From aa30dd444b00248065d9c286527bf9168c9cfb4b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 15 May 2024 15:23:49 +1000 Subject: [PATCH 1/3] Fix a typo in a comment. --- compiler/rustc_ast/src/tokenstream.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 3d46415507def..b4ddbe20689e2 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -224,7 +224,7 @@ impl AttrTokenStream { // Inner attributes are only supported on extern blocks, functions, // impls, and modules. All of these have their inner attributes // placed at the beginning of the rightmost outermost braced group: - // e.g. fn foo() { #![my_attr} } + // e.g. fn foo() { #![my_attr] } // // Therefore, we can insert them back into the right location // without needing to do any extra position tracking. From bca5cd3a9dccc166e936b21eb86e6a58d3f4b84e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 25 Jun 2024 14:14:58 +1000 Subject: [PATCH 2/3] Extend `tests/ui/macros/nonterminal-matching.rs`. To involve `macro_rules!` macros, and also a mix of fragment specifiers, some of which feature the forwaring limitation and some of which don't. --- tests/ui/macros/nonterminal-matching.rs | 30 +++++++ tests/ui/macros/nonterminal-matching.stderr | 90 ++++++++++++++++++++- 2 files changed, 119 insertions(+), 1 deletion(-) diff --git a/tests/ui/macros/nonterminal-matching.rs b/tests/ui/macros/nonterminal-matching.rs index 84fffe44d6a55..5f0d6b2f90eee 100644 --- a/tests/ui/macros/nonterminal-matching.rs +++ b/tests/ui/macros/nonterminal-matching.rs @@ -23,4 +23,34 @@ simple_nonterminal!(a, 'a, (x, y, z)); // OK complex_nonterminal!(enum E {}); +// `ident`, `lifetime`, and `tt` all work. Other fragments do not. See +// https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment +macro_rules! foo { + (ident $x:ident) => { bar!(ident $x); }; + (lifetime $x:lifetime) => { bar!(lifetime $x); }; + (tt $x:tt) => { bar!(tt $x); }; + (expr $x:expr) => { bar!(expr $x); }; //~ ERROR: no rules expected the token `3` + (literal $x:literal) => { bar!(literal $x); }; //~ ERROR: no rules expected the token `4` + (path $x:path) => { bar!(path $x); }; //~ ERROR: no rules expected the token `a::b::c` + (stmt $x:stmt) => { bar!(stmt $x); }; //~ ERROR: no rules expected the token `let abc = 0` +} + +macro_rules! bar { + (ident abc) => {}; + (lifetime 'abc) => {}; + (tt 2) => {}; + (expr 3) => {}; + (literal 4) => {}; + (path a::b::c) => {}; + (stmt let abc = 0) => {}; +} + +foo!(ident abc); +foo!(lifetime 'abc); +foo!(tt 2); +foo!(expr 3); +foo!(literal 4); +foo!(path a::b::c); +foo!(stmt let abc = 0); + fn main() {} diff --git a/tests/ui/macros/nonterminal-matching.stderr b/tests/ui/macros/nonterminal-matching.stderr index d19141145fa19..3ee88b5f52ef9 100644 --- a/tests/ui/macros/nonterminal-matching.stderr +++ b/tests/ui/macros/nonterminal-matching.stderr @@ -23,5 +23,93 @@ LL | complex_nonterminal!(enum E {}); = help: try using `:tt` instead in the macro definition = note: this error originates in the macro `complex_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 1 previous error +error: no rules expected the token `3` + --> $DIR/nonterminal-matching.rs:32:35 + | +LL | (expr $x:expr) => { bar!(expr $x); }; + | ^^ no rules expected this token in macro call +... +LL | macro_rules! bar { + | ---------------- when calling this macro +... +LL | foo!(expr 3); + | ------------ in this macro invocation + | +note: while trying to match `3` + --> $DIR/nonterminal-matching.rs:42:11 + | +LL | (expr 3) => {}; + | ^ + = note: captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens + = note: see for more information + = help: try using `:tt` instead in the macro definition + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: no rules expected the token `4` + --> $DIR/nonterminal-matching.rs:33:44 + | +LL | (literal $x:literal) => { bar!(literal $x); }; + | ^^ no rules expected this token in macro call +... +LL | macro_rules! bar { + | ---------------- when calling this macro +... +LL | foo!(literal 4); + | --------------- in this macro invocation + | +note: while trying to match `4` + --> $DIR/nonterminal-matching.rs:43:14 + | +LL | (literal 4) => {}; + | ^ + = note: captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens + = note: see for more information + = help: try using `:tt` instead in the macro definition + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: no rules expected the token `a::b::c` + --> $DIR/nonterminal-matching.rs:34:35 + | +LL | (path $x:path) => { bar!(path $x); }; + | ^^ no rules expected this token in macro call +... +LL | macro_rules! bar { + | ---------------- when calling this macro +... +LL | foo!(path a::b::c); + | ------------------ in this macro invocation + | +note: while trying to match `a` + --> $DIR/nonterminal-matching.rs:44:11 + | +LL | (path a::b::c) => {}; + | ^ + = note: captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens + = note: see for more information + = help: try using `:tt` instead in the macro definition + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: no rules expected the token `let abc = 0` + --> $DIR/nonterminal-matching.rs:35:35 + | +LL | (stmt $x:stmt) => { bar!(stmt $x); }; + | ^^ no rules expected this token in macro call +... +LL | macro_rules! bar { + | ---------------- when calling this macro +... +LL | foo!(stmt let abc = 0); + | ---------------------- in this macro invocation + | +note: while trying to match `let` + --> $DIR/nonterminal-matching.rs:45:11 + | +LL | (stmt let abc = 0) => {}; + | ^^^ + = note: captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens + = note: see for more information + = help: try using `:tt` instead in the macro definition + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 5 previous errors From 2e4d547d4a862aafd9b9b8382a1bbcde1a4c0d32 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 15 May 2024 09:29:11 +1000 Subject: [PATCH 3/3] Extra panic cases. Just some extra sanity checking, making explicit some values not possible in code working with token trees -- we shouldn't be seeing explicit delimiter tokens, because they should be represented as `TokenTree::Delimited`. --- compiler/rustc_ast/src/attr/mod.rs | 9 ++++++++- compiler/rustc_expand/src/config.rs | 6 ++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 676a2377c3b35..593c78df3cdb8 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -327,7 +327,8 @@ impl MetaItem { I: Iterator, { // FIXME: Share code with `parse_path`. - let path = match tokens.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref() { + let tt = tokens.next().map(|tt| TokenTree::uninterpolate(tt)); + let path = match tt.as_deref() { Some(&TokenTree::Token( Token { kind: ref kind @ (token::Ident(..) | token::PathSep), span }, _, @@ -368,6 +369,12 @@ impl MetaItem { token::Nonterminal::NtPath(path) => (**path).clone(), _ => return None, }, + Some(TokenTree::Token( + Token { kind: token::OpenDelim(_) | token::CloseDelim(_), .. }, + _, + )) => { + panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tt); + } _ => return None, }; let list_closing_paren_pos = tokens.peek().map(|tt| tt.span().hi()); diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index badfa6d3aa323..56cbb54fcecf7 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -214,6 +214,12 @@ impl<'a> StripUnconfigured<'a> { ) => { panic!("Nonterminal should have been flattened: {:?}", tree); } + AttrTokenTree::Token( + Token { kind: TokenKind::OpenDelim(_) | TokenKind::CloseDelim(_), .. }, + _, + ) => { + panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tree); + } AttrTokenTree::Token(token, spacing) => { Some(AttrTokenTree::Token(token, spacing)).into_iter() }