Skip to content

Commit f372476

Browse files
authored
Rollup merge of #91150 - dtolnay:qpath, r=davidtwco
Let qpath contain NtTy: `<$:ty as $:ty>::…` Example: ```rust macro_rules! m { (<$type:ty as $trait:ty>::$name:ident) => { <$type as $trait>::$name }; } fn main() { let _: m!(<str as ToOwned>::Owned); } ``` Previous behavior: ```console error: expected identifier, found `ToOwned` --> src/main.rs:3:19 | 3 | <$type as $trait>::$name | ^^^^^^ expected identifier ... 8 | let _: m!(<str as ToOwned>::Owned); | --------------------------- | | | this macro call doesn't expand to a type | in this macro invocation ``` The <code>expected identifier, found \`ToOwned\`</code> error is particularly silly. I think it should be fine to accept this code as long as $trait is of the form `TyKind::Path(None, path)`; if it is any other kind of `NtTy`, we'll keep the same behavior as before.
2 parents dd621a4 + 87a7def commit f372476

File tree

2 files changed

+47
-11
lines changed

2 files changed

+47
-11
lines changed

compiler/rustc_parse/src/parser/path.rs

+34-10
Original file line numberDiff line numberDiff line change
@@ -139,22 +139,46 @@ impl<'a> Parser<'a> {
139139
style: PathStyle,
140140
ty_generics: Option<&Generics>,
141141
) -> PResult<'a, Path> {
142-
maybe_whole!(self, NtPath, |path| {
142+
let reject_generics_if_mod_style = |parser: &Parser<'_>, path: &Path| {
143+
// Ensure generic arguments don't end up in attribute paths, such as:
144+
//
145+
// macro_rules! m {
146+
// ($p:path) => { #[$p] struct S; }
147+
// }
148+
//
149+
// m!(inline<u8>); //~ ERROR: unexpected generic arguments in path
150+
//
143151
if style == PathStyle::Mod && path.segments.iter().any(|segment| segment.args.is_some())
144152
{
145-
self.struct_span_err(
146-
path.segments
147-
.iter()
148-
.filter_map(|segment| segment.args.as_ref())
149-
.map(|arg| arg.span())
150-
.collect::<Vec<_>>(),
151-
"unexpected generic arguments in path",
152-
)
153-
.emit();
153+
parser
154+
.struct_span_err(
155+
path.segments
156+
.iter()
157+
.filter_map(|segment| segment.args.as_ref())
158+
.map(|arg| arg.span())
159+
.collect::<Vec<_>>(),
160+
"unexpected generic arguments in path",
161+
)
162+
.emit();
154163
}
164+
};
165+
166+
maybe_whole!(self, NtPath, |path| {
167+
reject_generics_if_mod_style(self, &path);
155168
path
156169
});
157170

171+
if let token::Interpolated(nt) = &self.token.kind {
172+
if let token::NtTy(ty) = &**nt {
173+
if let ast::TyKind::Path(None, path) = &ty.kind {
174+
let path = path.clone();
175+
self.bump();
176+
reject_generics_if_mod_style(self, &path);
177+
return Ok(path);
178+
}
179+
}
180+
}
181+
158182
let lo = self.token.span;
159183
let mut segments = Vec::new();
160184
let mod_sep_ctxt = self.token.span.ctxt();

src/test/ui/macros/macro-interpolation.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,20 @@ macro_rules! overly_complicated {
1414

1515
}
1616

17+
macro_rules! qpath {
18+
(path, <$type:ty as $trait:path>::$name:ident) => {
19+
<$type as $trait>::$name
20+
};
21+
22+
(ty, <$type:ty as $trait:ty>::$name:ident) => {
23+
<$type as $trait>::$name
24+
};
25+
}
26+
1727
pub fn main() {
28+
let _: qpath!(path, <str as ToOwned>::Owned);
29+
let _: qpath!(ty, <str as ToOwned>::Owned);
30+
1831
assert!(overly_complicated!(f, x, Option<usize>, { return Some(x); },
1932
Some(8), Some(y), y) == 8)
20-
2133
}

0 commit comments

Comments
 (0)