Skip to content

Commit

Permalink
Rollup merge of #91150 - dtolnay:qpath, r=davidtwco
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
matthiaskrgr authored Jan 18, 2022
2 parents dd621a4 + 87a7def commit f372476
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 11 deletions.
44 changes: 34 additions & 10 deletions compiler/rustc_parse/src/parser/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,22 +139,46 @@ impl<'a> Parser<'a> {
style: PathStyle,
ty_generics: Option<&Generics>,
) -> PResult<'a, Path> {
maybe_whole!(self, NtPath, |path| {
let reject_generics_if_mod_style = |parser: &Parser<'_>, path: &Path| {
// Ensure generic arguments don't end up in attribute paths, such as:
//
// macro_rules! m {
// ($p:path) => { #[$p] struct S; }
// }
//
// m!(inline<u8>); //~ ERROR: unexpected generic arguments in path
//
if style == PathStyle::Mod && path.segments.iter().any(|segment| segment.args.is_some())
{
self.struct_span_err(
path.segments
.iter()
.filter_map(|segment| segment.args.as_ref())
.map(|arg| arg.span())
.collect::<Vec<_>>(),
"unexpected generic arguments in path",
)
.emit();
parser
.struct_span_err(
path.segments
.iter()
.filter_map(|segment| segment.args.as_ref())
.map(|arg| arg.span())
.collect::<Vec<_>>(),
"unexpected generic arguments in path",
)
.emit();
}
};

maybe_whole!(self, NtPath, |path| {
reject_generics_if_mod_style(self, &path);
path
});

if let token::Interpolated(nt) = &self.token.kind {
if let token::NtTy(ty) = &**nt {
if let ast::TyKind::Path(None, path) = &ty.kind {
let path = path.clone();
self.bump();
reject_generics_if_mod_style(self, &path);
return Ok(path);
}
}
}

let lo = self.token.span;
let mut segments = Vec::new();
let mod_sep_ctxt = self.token.span.ctxt();
Expand Down
14 changes: 13 additions & 1 deletion src/test/ui/macros/macro-interpolation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,20 @@ macro_rules! overly_complicated {

}

macro_rules! qpath {
(path, <$type:ty as $trait:path>::$name:ident) => {
<$type as $trait>::$name
};

(ty, <$type:ty as $trait:ty>::$name:ident) => {
<$type as $trait>::$name
};
}

pub fn main() {
let _: qpath!(path, <str as ToOwned>::Owned);
let _: qpath!(ty, <str as ToOwned>::Owned);

assert!(overly_complicated!(f, x, Option<usize>, { return Some(x); },
Some(8), Some(y), y) == 8)

}

0 comments on commit f372476

Please sign in to comment.