From 94f6e5a1de34cad8484807f2521a4c39b49c9c83 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 17 Apr 2024 17:08:58 +1000 Subject: [PATCH 01/18] Tweak `expand_incomplete_parse` warning. By using `token_descr`, as is done for many other errors, we can get slightly better descriptions in error messages, e.g. "macro expansion ignores token `let` and any following" becomes "macro expansion ignores keyword `let` and any tokens following". This will be more important once invisible delimiters start being mentioned in error messages -- without this commit, that leads to error messages such as "error at ``" because invisible delimiters are pretty printed as an empty string. --- compiler/rustc_expand/messages.ftl | 2 +- compiler/rustc_expand/src/errors.rs | 2 +- compiler/rustc_expand/src/expand.rs | 7 ++++--- compiler/rustc_parse/src/parser/mod.rs | 2 +- tests/ui/macros/issue-118786.rs | 2 +- tests/ui/macros/issue-118786.stderr | 2 +- tests/ui/macros/issue-30007.rs | 2 +- tests/ui/macros/issue-30007.stderr | 2 +- tests/ui/macros/issue-54441.rs | 2 +- tests/ui/macros/issue-54441.stderr | 2 +- tests/ui/macros/macro-context.rs | 6 +++--- tests/ui/macros/macro-context.stderr | 6 +++--- tests/ui/macros/macro-in-expression-context.fixed | 2 +- tests/ui/macros/macro-in-expression-context.rs | 2 +- tests/ui/macros/macro-in-expression-context.stderr | 2 +- tests/ui/macros/syntax-error-recovery.rs | 2 +- tests/ui/macros/syntax-error-recovery.stderr | 2 +- tests/ui/parser/macro/macro-expand-to-match-arm.rs | 2 +- tests/ui/parser/macro/macro-expand-to-match-arm.stderr | 2 +- tests/ui/parser/macro/macro-incomplete-parse.rs | 4 ++-- tests/ui/parser/macro/macro-incomplete-parse.stderr | 4 ++-- tests/ui/parser/macro/trait-non-item-macros.rs | 2 +- tests/ui/parser/macro/trait-non-item-macros.stderr | 2 +- tests/ui/proc-macro/attr-invalid-exprs.rs | 4 ++-- tests/ui/proc-macro/attr-invalid-exprs.stderr | 4 ++-- tests/ui/proc-macro/expand-expr.rs | 4 ++-- tests/ui/proc-macro/expand-expr.stderr | 4 ++-- 27 files changed, 40 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index 766d96e268f04..930694265f626 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -68,7 +68,7 @@ expand_helper_attribute_name_invalid = `{$name}` cannot be a name of derive helper attribute expand_incomplete_parse = - macro expansion ignores token `{$token}` and any following + macro expansion ignores {$descr} and any tokens following .label = caused by the macro expansion here .note = the usage of `{$macro_path}!` is likely invalid in {$kind_name} context .suggestion_add_semi = you might be missing a semicolon here diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index 0fdccb0891899..91d8d9e4adacc 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -275,7 +275,7 @@ pub(crate) struct UnsupportedKeyValue { pub(crate) struct IncompleteParse<'a> { #[primary_span] pub span: Span, - pub token: Cow<'a, str>, + pub descr: String, #[label] pub label_span: Span, pub macro_path: &'a ast::Path, diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 0d56a005f159e..b8433ef6fe363 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -20,7 +20,8 @@ use rustc_data_structures::sync::Lrc; use rustc_errors::PResult; use rustc_feature::Features; use rustc_parse::parser::{ - AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, RecoverColon, RecoverComma, + token_descr, AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, RecoverColon, + RecoverComma, }; use rustc_parse::validate_attr; use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS}; @@ -1011,7 +1012,7 @@ pub(crate) fn ensure_complete_parse<'a>( span: Span, ) { if parser.token != token::Eof { - let token = pprust::token_to_string(&parser.token); + let descr = token_descr(&parser.token); // Avoid emitting backtrace info twice. let def_site_span = parser.token.span.with_ctxt(SyntaxContext::root()); @@ -1027,7 +1028,7 @@ pub(crate) fn ensure_complete_parse<'a>( parser.dcx().emit_err(IncompleteParse { span: def_site_span, - token, + descr, label_span: span, macro_path, kind_name, diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 9d9265d5318db..c5b63e31aa5d5 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -420,7 +420,7 @@ impl TokenDescription { } } -pub(super) fn token_descr(token: &Token) -> String { +pub fn token_descr(token: &Token) -> String { let name = pprust::token_to_string(token).to_string(); let kind = match (TokenDescription::from_token(token), &token.kind) { diff --git a/tests/ui/macros/issue-118786.rs b/tests/ui/macros/issue-118786.rs index a41372e4ea840..a73b737fe07e4 100644 --- a/tests/ui/macros/issue-118786.rs +++ b/tests/ui/macros/issue-118786.rs @@ -5,7 +5,7 @@ macro_rules! make_macro { ($macro_name:tt) => { macro_rules! $macro_name { - //~^ ERROR macro expansion ignores token `{` and any following + //~^ ERROR macro expansion ignores `{` and any tokens following //~| ERROR cannot find macro `macro_rules` in this scope //~| put a macro name here () => {} diff --git a/tests/ui/macros/issue-118786.stderr b/tests/ui/macros/issue-118786.stderr index 256b742ee160b..7fa5c2b83ddd8 100644 --- a/tests/ui/macros/issue-118786.stderr +++ b/tests/ui/macros/issue-118786.stderr @@ -13,7 +13,7 @@ help: add a semicolon LL | macro_rules! $macro_name; { | + -error: macro expansion ignores token `{` and any following +error: macro expansion ignores `{` and any tokens following --> $DIR/issue-118786.rs:7:34 | LL | macro_rules! $macro_name { diff --git a/tests/ui/macros/issue-30007.rs b/tests/ui/macros/issue-30007.rs index 918a821bae925..e36e47a3e7c23 100644 --- a/tests/ui/macros/issue-30007.rs +++ b/tests/ui/macros/issue-30007.rs @@ -1,5 +1,5 @@ macro_rules! t { - () => ( String ; ); //~ ERROR macro expansion ignores token `;` + () => ( String ; ); //~ ERROR macro expansion ignores `;` } fn main() { diff --git a/tests/ui/macros/issue-30007.stderr b/tests/ui/macros/issue-30007.stderr index f303221cf8aa8..129733ed69aba 100644 --- a/tests/ui/macros/issue-30007.stderr +++ b/tests/ui/macros/issue-30007.stderr @@ -1,4 +1,4 @@ -error: macro expansion ignores token `;` and any following +error: macro expansion ignores `;` and any tokens following --> $DIR/issue-30007.rs:2:20 | LL | () => ( String ; ); diff --git a/tests/ui/macros/issue-54441.rs b/tests/ui/macros/issue-54441.rs index b24d7e1f6bee5..37ab4e636475b 100644 --- a/tests/ui/macros/issue-54441.rs +++ b/tests/ui/macros/issue-54441.rs @@ -1,6 +1,6 @@ macro_rules! m { () => { - let //~ ERROR macro expansion ignores token `let` and any following + let //~ ERROR macro expansion ignores keyword `let` and any tokens following }; } diff --git a/tests/ui/macros/issue-54441.stderr b/tests/ui/macros/issue-54441.stderr index fb2c103139b97..f5f8b8ca2b266 100644 --- a/tests/ui/macros/issue-54441.stderr +++ b/tests/ui/macros/issue-54441.stderr @@ -1,4 +1,4 @@ -error: macro expansion ignores token `let` and any following +error: macro expansion ignores keyword `let` and any tokens following --> $DIR/issue-54441.rs:3:9 | LL | let diff --git a/tests/ui/macros/macro-context.rs b/tests/ui/macros/macro-context.rs index d09fdf118e6f4..a31470263a0a5 100644 --- a/tests/ui/macros/macro-context.rs +++ b/tests/ui/macros/macro-context.rs @@ -1,9 +1,9 @@ // (typeof used because it's surprisingly hard to find an unparsed token after a stmt) macro_rules! m { () => ( i ; typeof ); //~ ERROR expected expression, found reserved keyword `typeof` - //~| ERROR macro expansion ignores token `typeof` - //~| ERROR macro expansion ignores token `;` - //~| ERROR macro expansion ignores token `;` + //~| ERROR macro expansion ignores reserved keyword `typeof` + //~| ERROR macro expansion ignores `;` + //~| ERROR macro expansion ignores `;` //~| ERROR cannot find type `i` in this scope //~| ERROR cannot find value `i` in this scope //~| WARN trailing semicolon in macro diff --git a/tests/ui/macros/macro-context.stderr b/tests/ui/macros/macro-context.stderr index 7785f41594627..4820a43f00c79 100644 --- a/tests/ui/macros/macro-context.stderr +++ b/tests/ui/macros/macro-context.stderr @@ -1,4 +1,4 @@ -error: macro expansion ignores token `;` and any following +error: macro expansion ignores `;` and any tokens following --> $DIR/macro-context.rs:3:15 | LL | () => ( i ; typeof ); @@ -9,7 +9,7 @@ LL | let a: m!(); | = note: the usage of `m!` is likely invalid in type context -error: macro expansion ignores token `typeof` and any following +error: macro expansion ignores reserved keyword `typeof` and any tokens following --> $DIR/macro-context.rs:3:17 | LL | () => ( i ; typeof ); @@ -20,7 +20,7 @@ LL | let i = m!(); | = note: the usage of `m!` is likely invalid in expression context -error: macro expansion ignores token `;` and any following +error: macro expansion ignores `;` and any tokens following --> $DIR/macro-context.rs:3:15 | LL | () => ( i ; typeof ); diff --git a/tests/ui/macros/macro-in-expression-context.fixed b/tests/ui/macros/macro-in-expression-context.fixed index f4d04ca37bf5b..7c830707ffd9d 100644 --- a/tests/ui/macros/macro-in-expression-context.fixed +++ b/tests/ui/macros/macro-in-expression-context.fixed @@ -11,7 +11,7 @@ macro_rules! foo { //~| NOTE `#[warn(semicolon_in_expressions_from_macros)]` on by default assert_eq!("B", "B"); } - //~^^ ERROR macro expansion ignores token `assert_eq` and any following + //~^^ ERROR macro expansion ignores `assert_eq` and any tokens following //~| NOTE the usage of `foo!` is likely invalid in expression context } diff --git a/tests/ui/macros/macro-in-expression-context.rs b/tests/ui/macros/macro-in-expression-context.rs index 8921a05637725..da95017aa5f74 100644 --- a/tests/ui/macros/macro-in-expression-context.rs +++ b/tests/ui/macros/macro-in-expression-context.rs @@ -11,7 +11,7 @@ macro_rules! foo { //~| NOTE `#[warn(semicolon_in_expressions_from_macros)]` on by default assert_eq!("B", "B"); } - //~^^ ERROR macro expansion ignores token `assert_eq` and any following + //~^^ ERROR macro expansion ignores `assert_eq` and any tokens following //~| NOTE the usage of `foo!` is likely invalid in expression context } diff --git a/tests/ui/macros/macro-in-expression-context.stderr b/tests/ui/macros/macro-in-expression-context.stderr index 2eee63f307af9..43419f2678c22 100644 --- a/tests/ui/macros/macro-in-expression-context.stderr +++ b/tests/ui/macros/macro-in-expression-context.stderr @@ -1,4 +1,4 @@ -error: macro expansion ignores token `assert_eq` and any following +error: macro expansion ignores `assert_eq` and any tokens following --> $DIR/macro-in-expression-context.rs:12:9 | LL | assert_eq!("B", "B"); diff --git a/tests/ui/macros/syntax-error-recovery.rs b/tests/ui/macros/syntax-error-recovery.rs index f6178c137db97..016e4def28497 100644 --- a/tests/ui/macros/syntax-error-recovery.rs +++ b/tests/ui/macros/syntax-error-recovery.rs @@ -10,7 +10,7 @@ macro_rules! values { }; } //~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found type `(String)` -//~| ERROR macro expansion ignores token `(String)` and any following +//~| ERROR macro expansion ignores type `(String)` and any tokens following values!(STRING(1) as (String) => cfg(test),); //~^ ERROR expected one of `!` or `::`, found `` diff --git a/tests/ui/macros/syntax-error-recovery.stderr b/tests/ui/macros/syntax-error-recovery.stderr index 6218bf43a1ef2..3cfbd8ce82b56 100644 --- a/tests/ui/macros/syntax-error-recovery.stderr +++ b/tests/ui/macros/syntax-error-recovery.stderr @@ -10,7 +10,7 @@ LL | values!(STRING(1) as (String) => cfg(test),); = help: enum variants can be `Variant`, `Variant = `, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` = note: this error originates in the macro `values` (in Nightly builds, run with -Z macro-backtrace for more info) -error: macro expansion ignores token `(String)` and any following +error: macro expansion ignores type `(String)` and any tokens following --> $DIR/syntax-error-recovery.rs:7:26 | LL | $token $($inner)? = $value, diff --git a/tests/ui/parser/macro/macro-expand-to-match-arm.rs b/tests/ui/parser/macro/macro-expand-to-match-arm.rs index db38fa0d7bc65..0e27836b718bc 100644 --- a/tests/ui/parser/macro/macro-expand-to-match-arm.rs +++ b/tests/ui/parser/macro/macro-expand-to-match-arm.rs @@ -1,7 +1,7 @@ macro_rules! arm { ($pattern:pat => $block:block) => { $pattern => $block - //~^ ERROR macro expansion ignores token `=>` and any following + //~^ ERROR macro expansion ignores `=>` and any tokens following //~| NOTE the usage of `arm!` is likely invalid in pattern context //~| NOTE macros cannot expand to match arms }; diff --git a/tests/ui/parser/macro/macro-expand-to-match-arm.stderr b/tests/ui/parser/macro/macro-expand-to-match-arm.stderr index e3e7ff89c8134..1927d80fd724c 100644 --- a/tests/ui/parser/macro/macro-expand-to-match-arm.stderr +++ b/tests/ui/parser/macro/macro-expand-to-match-arm.stderr @@ -1,4 +1,4 @@ -error: macro expansion ignores token `=>` and any following +error: macro expansion ignores `=>` and any tokens following --> $DIR/macro-expand-to-match-arm.rs:3:18 | LL | $pattern => $block diff --git a/tests/ui/parser/macro/macro-incomplete-parse.rs b/tests/ui/parser/macro/macro-incomplete-parse.rs index 544e4aa7b1b09..612196aa4b276 100644 --- a/tests/ui/parser/macro/macro-incomplete-parse.rs +++ b/tests/ui/parser/macro/macro-incomplete-parse.rs @@ -2,7 +2,7 @@ macro_rules! ignored_item { () => { fn foo() {} fn bar() {} - , //~ ERROR macro expansion ignores token `,` + , //~ ERROR macro expansion ignores `,` } } @@ -13,7 +13,7 @@ macro_rules! ignored_expr { } macro_rules! ignored_pat { - () => ( 1, 2 ) //~ ERROR macro expansion ignores token `,` + () => ( 1, 2 ) //~ ERROR macro expansion ignores `,` } ignored_item!(); diff --git a/tests/ui/parser/macro/macro-incomplete-parse.stderr b/tests/ui/parser/macro/macro-incomplete-parse.stderr index 707417b725e9f..096b5f718ae1c 100644 --- a/tests/ui/parser/macro/macro-incomplete-parse.stderr +++ b/tests/ui/parser/macro/macro-incomplete-parse.stderr @@ -1,4 +1,4 @@ -error: macro expansion ignores token `,` and any following +error: macro expansion ignores `,` and any tokens following --> $DIR/macro-incomplete-parse.rs:5:9 | LL | , @@ -20,7 +20,7 @@ LL | ignored_expr!(); | = note: this error originates in the macro `ignored_expr` (in Nightly builds, run with -Z macro-backtrace for more info) -error: macro expansion ignores token `,` and any following +error: macro expansion ignores `,` and any tokens following --> $DIR/macro-incomplete-parse.rs:16:14 | LL | () => ( 1, 2 ) diff --git a/tests/ui/parser/macro/trait-non-item-macros.rs b/tests/ui/parser/macro/trait-non-item-macros.rs index 97fb564bf6479..e93000193b6e3 100644 --- a/tests/ui/parser/macro/trait-non-item-macros.rs +++ b/tests/ui/parser/macro/trait-non-item-macros.rs @@ -1,7 +1,7 @@ macro_rules! bah { ($a:expr) => { $a - }; //~^ ERROR macro expansion ignores token `2` and any following + }; //~^ ERROR macro expansion ignores expression `2` and any tokens following } trait Bar { diff --git a/tests/ui/parser/macro/trait-non-item-macros.stderr b/tests/ui/parser/macro/trait-non-item-macros.stderr index db20e6b24aa03..1a82848377895 100644 --- a/tests/ui/parser/macro/trait-non-item-macros.stderr +++ b/tests/ui/parser/macro/trait-non-item-macros.stderr @@ -1,4 +1,4 @@ -error: macro expansion ignores token `2` and any following +error: macro expansion ignores expression `2` and any tokens following --> $DIR/trait-non-item-macros.rs:3:9 | LL | $a diff --git a/tests/ui/proc-macro/attr-invalid-exprs.rs b/tests/ui/proc-macro/attr-invalid-exprs.rs index 3d8806ee80030..ec0b79469a457 100644 --- a/tests/ui/proc-macro/attr-invalid-exprs.rs +++ b/tests/ui/proc-macro/attr-invalid-exprs.rs @@ -13,7 +13,7 @@ fn main() { //~^ ERROR expected expression, found end of macro arguments let _ = #[duplicate] "Hello, world!"; - //~^ ERROR macro expansion ignores token `,` and any following + //~^ ERROR macro expansion ignores `,` and any tokens following let _ = { #[no_output] @@ -22,7 +22,7 @@ fn main() { let _ = { #[duplicate] - //~^ ERROR macro expansion ignores token `,` and any following + //~^ ERROR macro expansion ignores `,` and any tokens following "Hello, world!" }; } diff --git a/tests/ui/proc-macro/attr-invalid-exprs.stderr b/tests/ui/proc-macro/attr-invalid-exprs.stderr index f96939bb6efce..0d500c871453f 100644 --- a/tests/ui/proc-macro/attr-invalid-exprs.stderr +++ b/tests/ui/proc-macro/attr-invalid-exprs.stderr @@ -4,7 +4,7 @@ error: expected expression, found end of macro arguments LL | let _ = #[no_output] "Hello, world!"; | ^^^^^^^^^^^^ -error: macro expansion ignores token `,` and any following +error: macro expansion ignores `,` and any tokens following --> $DIR/attr-invalid-exprs.rs:15:13 | LL | let _ = #[duplicate] "Hello, world!"; @@ -16,7 +16,7 @@ help: you might be missing a semicolon here LL | let _ = #[duplicate]; "Hello, world!"; | + -error: macro expansion ignores token `,` and any following +error: macro expansion ignores `,` and any tokens following --> $DIR/attr-invalid-exprs.rs:24:9 | LL | #[duplicate] diff --git a/tests/ui/proc-macro/expand-expr.rs b/tests/ui/proc-macro/expand-expr.rs index 5f7375d7450d6..e06ddc51a297e 100644 --- a/tests/ui/proc-macro/expand-expr.rs +++ b/tests/ui/proc-macro/expand-expr.rs @@ -114,8 +114,8 @@ expand_expr_fail!(echo_pm!($)); //~ ERROR: expected expression, found `$` // We get errors reported and recover during macro expansion if the macro // doesn't produce a valid expression. -expand_expr_is!("string", echo_tts!("string"; hello)); //~ ERROR: macro expansion ignores token `hello` and any following -expand_expr_is!("string", echo_pm!("string"; hello)); //~ ERROR: macro expansion ignores token `;` and any following +expand_expr_is!("string", echo_tts!("string"; hello)); //~ ERROR: macro expansion ignores `hello` and any tokens following +expand_expr_is!("string", echo_pm!("string"; hello)); //~ ERROR: macro expansion ignores `;` and any tokens following // For now, fail if a non-literal expression is expanded. expand_expr_fail!(arbitrary_expression() + "etc"); diff --git a/tests/ui/proc-macro/expand-expr.stderr b/tests/ui/proc-macro/expand-expr.stderr index 2b92472e5ab75..8b1df177cfa6d 100644 --- a/tests/ui/proc-macro/expand-expr.stderr +++ b/tests/ui/proc-macro/expand-expr.stderr @@ -22,7 +22,7 @@ error: expected expression, found `$` LL | expand_expr_fail!(echo_pm!($)); | ^ expected expression -error: macro expansion ignores token `hello` and any following +error: macro expansion ignores `hello` and any tokens following --> $DIR/expand-expr.rs:117:47 | LL | expand_expr_is!("string", echo_tts!("string"; hello)); @@ -34,7 +34,7 @@ help: you might be missing a semicolon here LL | expand_expr_is!("string", echo_tts!("string"; hello);); | + -error: macro expansion ignores token `;` and any following +error: macro expansion ignores `;` and any tokens following --> $DIR/expand-expr.rs:118:44 | LL | expand_expr_is!("string", echo_pm!("string"; hello)); From a2f39d06a210af0ba0607d3936fdc8864f19997b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 25 Jun 2024 12:52:15 +1000 Subject: [PATCH 02/18] Tweak more warnings. Much like the previous commit. I think the removal of "the token" in each message is fine here. There are many more error messages that mention tokens without saying "the token" than those that do say it. --- compiler/rustc_expand/src/mbe/diagnostics.rs | 13 +++---------- compiler/rustc_expand/src/mbe/macro_parser.rs | 5 ++--- .../array-slice-vec/vec-macro-with-comma-only.rs | 2 +- .../vec-macro-with-comma-only.stderr | 2 +- .../editions/edition-keywords-2015-2015-parsing.rs | 4 ++-- .../edition-keywords-2015-2015-parsing.stderr | 4 ++-- .../editions/edition-keywords-2015-2018-parsing.rs | 4 ++-- .../edition-keywords-2015-2018-parsing.stderr | 4 ++-- .../editions/edition-keywords-2018-2015-parsing.rs | 4 ++-- .../edition-keywords-2018-2015-parsing.stderr | 6 +++--- .../editions/edition-keywords-2018-2018-parsing.rs | 4 ++-- .../edition-keywords-2018-2018-parsing.stderr | 6 +++--- tests/ui/fail-simple.rs | 2 +- tests/ui/fail-simple.stderr | 2 +- .../assert-trailing-junk.with-generic-asset.stderr | 4 ++-- ...sert-trailing-junk.without-generic-asset.stderr | 4 ++-- tests/ui/macros/best-failure.rs | 2 +- tests/ui/macros/best-failure.stderr | 2 +- .../macros/expr_2021_inline_const.edi2021.stderr | 4 ++-- .../macros/expr_2021_inline_const.edi2024.stderr | 2 +- tests/ui/macros/expr_2021_inline_const.rs | 4 ++-- .../expr_2024_underscore_expr.edi2021.stderr | 4 ++-- .../expr_2024_underscore_expr.edi2024.stderr | 2 +- tests/ui/macros/expr_2024_underscore_expr.rs | 4 ++-- tests/ui/macros/macro-at-most-once-rep-2015.rs | 14 +++++++------- tests/ui/macros/macro-at-most-once-rep-2015.stderr | 14 +++++++------- tests/ui/macros/macro-at-most-once-rep-2018.rs | 14 +++++++------- tests/ui/macros/macro-at-most-once-rep-2018.stderr | 14 +++++++------- tests/ui/macros/macro-non-lifetime.rs | 2 +- tests/ui/macros/macro-non-lifetime.stderr | 2 +- tests/ui/macros/missing-comma.rs | 10 +++++----- tests/ui/macros/missing-comma.stderr | 10 +++++----- tests/ui/macros/nonterminal-matching.rs | 10 +++++----- tests/ui/macros/nonterminal-matching.stderr | 14 +++++++------- tests/ui/macros/trace_faulty_macros.stderr | 2 +- tests/ui/offset-of/offset-of-arg-count.rs | 2 +- tests/ui/offset-of/offset-of-arg-count.stderr | 2 +- tests/ui/offset-of/offset-of-tuple.stderr | 2 +- .../or-patterns/or-patterns-syntactic-fail-2018.rs | 4 ++-- .../or-patterns-syntactic-fail-2018.stderr | 4 ++-- tests/ui/parser/macro/macro-doc-comments-1.rs | 2 +- tests/ui/parser/macro/macro-doc-comments-1.stderr | 2 +- tests/ui/parser/macro/macro-doc-comments-2.rs | 2 +- tests/ui/parser/macro/macro-doc-comments-2.stderr | 2 +- .../ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs | 2 +- .../rfcs/rfc-2294-if-let-guard/feature-gate.stderr | 2 +- .../ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs | 2 +- .../rfc-2497-if-let-chains/feature-gate.stderr | 2 +- tests/ui/underscore-ident-matcher.rs | 2 +- tests/ui/underscore-ident-matcher.stderr | 2 +- 50 files changed, 113 insertions(+), 121 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 5778f6616227a..7083664f5b015 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -2,10 +2,9 @@ use std::borrow::Cow; use rustc_ast::token::{self, Token, TokenKind}; use rustc_ast::tokenstream::TokenStream; -use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage}; use rustc_macros::Subdiagnostic; -use rustc_parse::parser::{Parser, Recovery}; +use rustc_parse::parser::{token_descr, Parser, Recovery}; use rustc_session::parse::ParseSess; use rustc_span::source_map::SourceMap; use rustc_span::symbol::Ident; @@ -336,17 +335,11 @@ pub(super) fn annotate_doc_comment(err: &mut Diag<'_>, sm: &SourceMap, span: Spa /// other tokens, this is "unexpected token...". pub(super) fn parse_failure_msg(tok: &Token, expected_token: Option<&Token>) -> Cow<'static, str> { if let Some(expected_token) = expected_token { - Cow::from(format!( - "expected `{}`, found `{}`", - pprust::token_to_string(expected_token), - pprust::token_to_string(tok), - )) + Cow::from(format!("expected {}, found {}", token_descr(expected_token), token_descr(tok))) } else { match tok.kind { token::Eof => Cow::from("unexpected end of macro invocation"), - _ => { - Cow::from(format!("no rules expected the token `{}`", pprust::token_to_string(tok))) - } + _ => Cow::from(format!("no rules expected {}", token_descr(tok))), } } } diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 501a2417fcf31..9c4a5e63f17c1 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -76,11 +76,10 @@ use std::fmt::Display; use std::rc::Rc; use rustc_ast::token::{self, DocComment, NonterminalKind, Token}; -use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; use rustc_lint_defs::pluralize; -use rustc_parse::parser::{ParseNtResult, Parser}; +use rustc_parse::parser::{token_descr, ParseNtResult, Parser}; use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent}; use rustc_span::Span; pub(crate) use NamedMatch::*; @@ -150,7 +149,7 @@ impl Display for MatcherLoc { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { MatcherLoc::Token { token } | MatcherLoc::SequenceSep { separator: token } => { - write!(f, "`{}`", pprust::token_to_string(token)) + write!(f, "{}", token_descr(token)) } MatcherLoc::MetaVarDecl { bind, kind, .. } => { write!(f, "meta-variable `${bind}")?; diff --git a/tests/ui/array-slice-vec/vec-macro-with-comma-only.rs b/tests/ui/array-slice-vec/vec-macro-with-comma-only.rs index 574a53c58feac..0f99f6b1b1e07 100644 --- a/tests/ui/array-slice-vec/vec-macro-with-comma-only.rs +++ b/tests/ui/array-slice-vec/vec-macro-with-comma-only.rs @@ -1,3 +1,3 @@ pub fn main() { - vec![,]; //~ ERROR no rules expected the token `,` + vec![,]; //~ ERROR no rules expected `,` } diff --git a/tests/ui/array-slice-vec/vec-macro-with-comma-only.stderr b/tests/ui/array-slice-vec/vec-macro-with-comma-only.stderr index b3f953af6d278..d76d493eca839 100644 --- a/tests/ui/array-slice-vec/vec-macro-with-comma-only.stderr +++ b/tests/ui/array-slice-vec/vec-macro-with-comma-only.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `,` +error: no rules expected `,` --> $DIR/vec-macro-with-comma-only.rs:2:10 | LL | vec![,]; diff --git a/tests/ui/editions/edition-keywords-2015-2015-parsing.rs b/tests/ui/editions/edition-keywords-2015-2015-parsing.rs index 07104bdf217d0..4751d280467cb 100644 --- a/tests/ui/editions/edition-keywords-2015-2015-parsing.rs +++ b/tests/ui/editions/edition-keywords-2015-2015-parsing.rs @@ -13,8 +13,8 @@ pub fn check_async() { let mut r#async = 1; // OK r#async = consumes_async!(async); // OK - r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async` - r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async` + r#async = consumes_async!(r#async); //~ ERROR no rules expected `r#async` + r#async = consumes_async_raw!(async); //~ ERROR no rules expected `async` r#async = consumes_async_raw!(r#async); // OK if passes_ident!(async) == 1 {} // OK diff --git a/tests/ui/editions/edition-keywords-2015-2015-parsing.stderr b/tests/ui/editions/edition-keywords-2015-2015-parsing.stderr index 39944622d07b9..2519a9fded2ee 100644 --- a/tests/ui/editions/edition-keywords-2015-2015-parsing.stderr +++ b/tests/ui/editions/edition-keywords-2015-2015-parsing.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `r#async` +error: no rules expected `r#async` --> $DIR/edition-keywords-2015-2015-parsing.rs:16:31 | LL | r#async = consumes_async!(r#async); @@ -10,7 +10,7 @@ note: while trying to match `async` LL | (async) => (1) | ^^^^^ -error: no rules expected the token `async` +error: no rules expected `async` --> $DIR/edition-keywords-2015-2015-parsing.rs:17:35 | LL | r#async = consumes_async_raw!(async); diff --git a/tests/ui/editions/edition-keywords-2015-2018-parsing.rs b/tests/ui/editions/edition-keywords-2015-2018-parsing.rs index 3c294f95cd265..4404ea26fb30d 100644 --- a/tests/ui/editions/edition-keywords-2015-2018-parsing.rs +++ b/tests/ui/editions/edition-keywords-2015-2018-parsing.rs @@ -13,8 +13,8 @@ pub fn check_async() { let mut r#async = 1; // OK r#async = consumes_async!(async); // OK - r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async` - r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async` + r#async = consumes_async!(r#async); //~ ERROR no rules expected `r#async` + r#async = consumes_async_raw!(async); //~ ERROR no rules expected `async` r#async = consumes_async_raw!(r#async); // OK if passes_ident!(async) == 1 {} // OK diff --git a/tests/ui/editions/edition-keywords-2015-2018-parsing.stderr b/tests/ui/editions/edition-keywords-2015-2018-parsing.stderr index fa83908e6666e..0c0e573841519 100644 --- a/tests/ui/editions/edition-keywords-2015-2018-parsing.stderr +++ b/tests/ui/editions/edition-keywords-2015-2018-parsing.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `r#async` +error: no rules expected `r#async` --> $DIR/edition-keywords-2015-2018-parsing.rs:16:31 | LL | r#async = consumes_async!(r#async); @@ -10,7 +10,7 @@ note: while trying to match `async` LL | (async) => (1) | ^^^^^ -error: no rules expected the token `async` +error: no rules expected `async` --> $DIR/edition-keywords-2015-2018-parsing.rs:17:35 | LL | r#async = consumes_async_raw!(async); diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.rs b/tests/ui/editions/edition-keywords-2018-2015-parsing.rs index 5918454327409..c346be5085601 100644 --- a/tests/ui/editions/edition-keywords-2018-2015-parsing.rs +++ b/tests/ui/editions/edition-keywords-2018-2015-parsing.rs @@ -17,8 +17,8 @@ pub fn check_async() { let mut r#async = 1; // OK r#async = consumes_async!(async); // OK - r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async` - r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async` + r#async = consumes_async!(r#async); //~ ERROR no rules expected `r#async` + r#async = consumes_async_raw!(async); //~ ERROR no rules expected keyword `async` r#async = consumes_async_raw!(r#async); // OK if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr index 42db75f665973..aed5837abeafe 100644 --- a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr +++ b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr @@ -20,19 +20,19 @@ help: escape `async` to use it as an identifier LL | module::r#async(); | ++ -error: no rules expected the token `r#async` +error: no rules expected `r#async` --> $DIR/edition-keywords-2018-2015-parsing.rs:20:31 | LL | r#async = consumes_async!(r#async); | ^^^^^^^ no rules expected this token in macro call | -note: while trying to match `async` +note: while trying to match keyword `async` --> $DIR/auxiliary/edition-kw-macro-2015.rs:17:6 | LL | (async) => (1) | ^^^^^ -error: no rules expected the token `async` +error: no rules expected keyword `async` --> $DIR/edition-keywords-2018-2015-parsing.rs:21:35 | LL | r#async = consumes_async_raw!(async); diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.rs b/tests/ui/editions/edition-keywords-2018-2018-parsing.rs index 4975246fa9423..b75b68b3febbd 100644 --- a/tests/ui/editions/edition-keywords-2018-2018-parsing.rs +++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.rs @@ -24,8 +24,8 @@ pub fn check_async() { let mut r#async = 1; // OK r#async = consumes_async!(async); // OK - r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async` - r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async` + r#async = consumes_async!(r#async); //~ ERROR no rules expected `r#async` + r#async = consumes_async_raw!(async); //~ ERROR no rules expected keyword `async` r#async = consumes_async_raw!(r#async); // OK if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr index 4bbe1597233cf..6503e9cc73cf1 100644 --- a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr +++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr @@ -20,19 +20,19 @@ help: escape `async` to use it as an identifier LL | module::r#async(); | ++ -error: no rules expected the token `r#async` +error: no rules expected `r#async` --> $DIR/edition-keywords-2018-2018-parsing.rs:27:31 | LL | r#async = consumes_async!(r#async); | ^^^^^^^ no rules expected this token in macro call | -note: while trying to match `async` +note: while trying to match keyword `async` --> $DIR/auxiliary/edition-kw-macro-2018.rs:17:6 | LL | (async) => (1) | ^^^^^ -error: no rules expected the token `async` +error: no rules expected keyword `async` --> $DIR/edition-keywords-2018-2018-parsing.rs:28:35 | LL | r#async = consumes_async_raw!(async); diff --git a/tests/ui/fail-simple.rs b/tests/ui/fail-simple.rs index cd81a5d0a0fc6..55e547ee72b0f 100644 --- a/tests/ui/fail-simple.rs +++ b/tests/ui/fail-simple.rs @@ -1,3 +1,3 @@ fn main() { - panic!(@); //~ ERROR no rules expected the token `@` + panic!(@); //~ ERROR no rules expected `@` } diff --git a/tests/ui/fail-simple.stderr b/tests/ui/fail-simple.stderr index 39fec3e2517b2..50c350b3ef55e 100644 --- a/tests/ui/fail-simple.stderr +++ b/tests/ui/fail-simple.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `@` +error: no rules expected `@` --> $DIR/fail-simple.rs:2:12 | LL | panic!(@); diff --git a/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr b/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr index 1e73320e43912..7582c8e8659bc 100644 --- a/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr +++ b/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr @@ -10,7 +10,7 @@ error: expected one of `,`, `.`, `?`, or an operator, found `some` LL | assert!(true some extra junk); | ^^^^ expected one of `,`, `.`, `?`, or an operator -error: no rules expected the token `blah` +error: no rules expected `blah` --> $DIR/assert-trailing-junk.rs:15:30 | LL | assert!(true, "whatever" blah); @@ -28,7 +28,7 @@ LL | assert!(true "whatever" blah); | | | help: try adding a comma -error: no rules expected the token `blah` +error: no rules expected `blah` --> $DIR/assert-trailing-junk.rs:18:29 | LL | assert!(true "whatever" blah); diff --git a/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr b/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr index 1e73320e43912..7582c8e8659bc 100644 --- a/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr +++ b/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr @@ -10,7 +10,7 @@ error: expected one of `,`, `.`, `?`, or an operator, found `some` LL | assert!(true some extra junk); | ^^^^ expected one of `,`, `.`, `?`, or an operator -error: no rules expected the token `blah` +error: no rules expected `blah` --> $DIR/assert-trailing-junk.rs:15:30 | LL | assert!(true, "whatever" blah); @@ -28,7 +28,7 @@ LL | assert!(true "whatever" blah); | | | help: try adding a comma -error: no rules expected the token `blah` +error: no rules expected `blah` --> $DIR/assert-trailing-junk.rs:18:29 | LL | assert!(true "whatever" blah); diff --git a/tests/ui/macros/best-failure.rs b/tests/ui/macros/best-failure.rs index bbdd465d5ec96..1b73066c8749d 100644 --- a/tests/ui/macros/best-failure.rs +++ b/tests/ui/macros/best-failure.rs @@ -2,7 +2,7 @@ macro_rules! number { (neg false, $self:ident) => { $self }; ($signed:tt => $ty:ty;) => { number!(neg $signed, $self); - //~^ ERROR no rules expected the token `$` + //~^ ERROR no rules expected `$` }; } diff --git a/tests/ui/macros/best-failure.stderr b/tests/ui/macros/best-failure.stderr index c5f8b9abc19a1..914ff7fd8207f 100644 --- a/tests/ui/macros/best-failure.stderr +++ b/tests/ui/macros/best-failure.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `$` +error: no rules expected `$` --> $DIR/best-failure.rs:4:30 | LL | macro_rules! number { diff --git a/tests/ui/macros/expr_2021_inline_const.edi2021.stderr b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr index b55ae62030c56..82f11358c94a6 100644 --- a/tests/ui/macros/expr_2021_inline_const.edi2021.stderr +++ b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `const` +error: no rules expected keyword `const` --> $DIR/expr_2021_inline_const.rs:26:12 | LL | macro_rules! m2021 { @@ -13,7 +13,7 @@ note: while trying to match meta-variable `$e:expr_2021` LL | ($e:expr_2021) => { | ^^^^^^^^^^^^ -error: no rules expected the token `const` +error: no rules expected keyword `const` --> $DIR/expr_2021_inline_const.rs:27:12 | LL | macro_rules! m2024 { diff --git a/tests/ui/macros/expr_2021_inline_const.edi2024.stderr b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr index 285db53d6c834..5c7b672f025c7 100644 --- a/tests/ui/macros/expr_2021_inline_const.edi2024.stderr +++ b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `const` +error: no rules expected keyword `const` --> $DIR/expr_2021_inline_const.rs:26:12 | LL | macro_rules! m2021 { diff --git a/tests/ui/macros/expr_2021_inline_const.rs b/tests/ui/macros/expr_2021_inline_const.rs index 06b74a466d6e2..c8b05b5364a70 100644 --- a/tests/ui/macros/expr_2021_inline_const.rs +++ b/tests/ui/macros/expr_2021_inline_const.rs @@ -23,8 +23,8 @@ macro_rules! test { } fn main() { - m2021!(const { 1 }); //~ ERROR: no rules expected the token `const` - m2024!(const { 1 }); //[edi2021]~ ERROR: no rules expected the token `const` + m2021!(const { 1 }); //~ ERROR: no rules expected keyword `const` + m2024!(const { 1 }); //[edi2021]~ ERROR: no rules expected keyword `const` test!(expr); } diff --git a/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr b/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr index 335b3f613434b..32d3a310a1fea 100644 --- a/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr +++ b/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `_` +error: no rules expected reserved identifier `_` --> $DIR/expr_2024_underscore_expr.rs:22:12 | LL | macro_rules! m2021 { @@ -13,7 +13,7 @@ note: while trying to match meta-variable `$e:expr_2021` LL | ($e:expr_2021) => { | ^^^^^^^^^^^^ -error: no rules expected the token `_` +error: no rules expected reserved identifier `_` --> $DIR/expr_2024_underscore_expr.rs:23:12 | LL | macro_rules! m2024 { diff --git a/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr b/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr index 9e49f66a89ae8..9103974690201 100644 --- a/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr +++ b/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `_` +error: no rules expected reserved identifier `_` --> $DIR/expr_2024_underscore_expr.rs:22:12 | LL | macro_rules! m2021 { diff --git a/tests/ui/macros/expr_2024_underscore_expr.rs b/tests/ui/macros/expr_2024_underscore_expr.rs index b2129bf154f7e..d5ae86571af0b 100644 --- a/tests/ui/macros/expr_2024_underscore_expr.rs +++ b/tests/ui/macros/expr_2024_underscore_expr.rs @@ -19,6 +19,6 @@ macro_rules! m2024 { } fn main() { - m2021!(_); //~ ERROR: no rules expected the token `_` - m2024!(_); //[edi2021]~ ERROR: no rules expected the token `_` + m2021!(_); //~ ERROR: no rules expected reserved identifier `_` + m2024!(_); //[edi2021]~ ERROR: no rules expected reserved identifier `_` } diff --git a/tests/ui/macros/macro-at-most-once-rep-2015.rs b/tests/ui/macros/macro-at-most-once-rep-2015.rs index 8f2531a25aeaf..08967b82531c9 100644 --- a/tests/ui/macros/macro-at-most-once-rep-2015.rs +++ b/tests/ui/macros/macro-at-most-once-rep-2015.rs @@ -22,21 +22,21 @@ macro_rules! barstar { pub fn main() { foo!(); foo!(a); - foo!(a?); //~ ERROR no rules expected the token `?` - foo!(a?a); //~ ERROR no rules expected the token `?` - foo!(a?a?a); //~ ERROR no rules expected the token `?` + foo!(a?); //~ ERROR no rules expected `?` + foo!(a?a); //~ ERROR no rules expected `?` + foo!(a?a?a); //~ ERROR no rules expected `?` barplus!(); //~ERROR unexpected end of macro invocation barplus!(a); //~ERROR unexpected end of macro invocation - barplus!(a?); //~ ERROR no rules expected the token `?` - barplus!(a?a); //~ ERROR no rules expected the token `?` + barplus!(a?); //~ ERROR no rules expected `?` + barplus!(a?a); //~ ERROR no rules expected `?` barplus!(a+); barplus!(+); barstar!(); //~ERROR unexpected end of macro invocation barstar!(a); //~ERROR unexpected end of macro invocation - barstar!(a?); //~ ERROR no rules expected the token `?` - barstar!(a?a); //~ ERROR no rules expected the token `?` + barstar!(a?); //~ ERROR no rules expected `?` + barstar!(a?a); //~ ERROR no rules expected `?` barstar!(a*); barstar!(*); } diff --git a/tests/ui/macros/macro-at-most-once-rep-2015.stderr b/tests/ui/macros/macro-at-most-once-rep-2015.stderr index 7c45b85bc8d4e..7f161cdc8d0b4 100644 --- a/tests/ui/macros/macro-at-most-once-rep-2015.stderr +++ b/tests/ui/macros/macro-at-most-once-rep-2015.stderr @@ -4,7 +4,7 @@ error: the `?` macro repetition operator does not take a separator LL | ($(a),?) => {}; | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2015.rs:25:11 | LL | macro_rules! foo { @@ -15,7 +15,7 @@ LL | foo!(a?); | = note: while trying to match sequence end -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2015.rs:26:11 | LL | macro_rules! foo { @@ -26,7 +26,7 @@ LL | foo!(a?a); | = note: while trying to match sequence end -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2015.rs:27:11 | LL | macro_rules! foo { @@ -67,7 +67,7 @@ note: while trying to match `+` LL | ($(a)?+) => {}; // ok. matches "a+" and "+" | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2015.rs:31:15 | LL | macro_rules! barplus { @@ -82,7 +82,7 @@ note: while trying to match `+` LL | ($(a)?+) => {}; // ok. matches "a+" and "+" | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2015.rs:32:15 | LL | macro_rules! barplus { @@ -127,7 +127,7 @@ note: while trying to match `*` LL | ($(a)?*) => {}; // ok. matches "a*" and "*" | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2015.rs:38:15 | LL | macro_rules! barstar { @@ -142,7 +142,7 @@ note: while trying to match `*` LL | ($(a)?*) => {}; // ok. matches "a*" and "*" | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2015.rs:39:15 | LL | macro_rules! barstar { diff --git a/tests/ui/macros/macro-at-most-once-rep-2018.rs b/tests/ui/macros/macro-at-most-once-rep-2018.rs index 7f43055ded6f4..98fbb2ad20733 100644 --- a/tests/ui/macros/macro-at-most-once-rep-2018.rs +++ b/tests/ui/macros/macro-at-most-once-rep-2018.rs @@ -22,21 +22,21 @@ macro_rules! barstar { pub fn main() { foo!(); foo!(a); - foo!(a?); //~ ERROR no rules expected the token `?` - foo!(a?a); //~ ERROR no rules expected the token `?` - foo!(a?a?a); //~ ERROR no rules expected the token `?` + foo!(a?); //~ ERROR no rules expected `?` + foo!(a?a); //~ ERROR no rules expected `?` + foo!(a?a?a); //~ ERROR no rules expected `?` barplus!(); //~ERROR unexpected end of macro invocation barplus!(a); //~ERROR unexpected end of macro invocation - barplus!(a?); //~ ERROR no rules expected the token `?` - barplus!(a?a); //~ ERROR no rules expected the token `?` + barplus!(a?); //~ ERROR no rules expected `?` + barplus!(a?a); //~ ERROR no rules expected `?` barplus!(a+); barplus!(+); barstar!(); //~ERROR unexpected end of macro invocation barstar!(a); //~ERROR unexpected end of macro invocation - barstar!(a?); //~ ERROR no rules expected the token `?` - barstar!(a?a); //~ ERROR no rules expected the token `?` + barstar!(a?); //~ ERROR no rules expected `?` + barstar!(a?a); //~ ERROR no rules expected `?` barstar!(a*); barstar!(*); } diff --git a/tests/ui/macros/macro-at-most-once-rep-2018.stderr b/tests/ui/macros/macro-at-most-once-rep-2018.stderr index 696520b28268a..f165a199b10b9 100644 --- a/tests/ui/macros/macro-at-most-once-rep-2018.stderr +++ b/tests/ui/macros/macro-at-most-once-rep-2018.stderr @@ -4,7 +4,7 @@ error: the `?` macro repetition operator does not take a separator LL | ($(a),?) => {}; | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2018.rs:25:11 | LL | macro_rules! foo { @@ -15,7 +15,7 @@ LL | foo!(a?); | = note: while trying to match sequence end -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2018.rs:26:11 | LL | macro_rules! foo { @@ -26,7 +26,7 @@ LL | foo!(a?a); | = note: while trying to match sequence end -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2018.rs:27:11 | LL | macro_rules! foo { @@ -67,7 +67,7 @@ note: while trying to match `+` LL | ($(a)?+) => {}; // ok. matches "a+" and "+" | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2018.rs:31:15 | LL | macro_rules! barplus { @@ -82,7 +82,7 @@ note: while trying to match `+` LL | ($(a)?+) => {}; // ok. matches "a+" and "+" | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2018.rs:32:15 | LL | macro_rules! barplus { @@ -127,7 +127,7 @@ note: while trying to match `*` LL | ($(a)?*) => {}; // ok. matches "a*" and "*" | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2018.rs:38:15 | LL | macro_rules! barstar { @@ -142,7 +142,7 @@ note: while trying to match `*` LL | ($(a)?*) => {}; // ok. matches "a*" and "*" | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2018.rs:39:15 | LL | macro_rules! barstar { diff --git a/tests/ui/macros/macro-non-lifetime.rs b/tests/ui/macros/macro-non-lifetime.rs index 26e1f2afa91bb..3defffd29604a 100644 --- a/tests/ui/macros/macro-non-lifetime.rs +++ b/tests/ui/macros/macro-non-lifetime.rs @@ -4,5 +4,5 @@ macro_rules! m { ($x:lifetime) => { } } fn main() { m!(a); - //~^ ERROR no rules expected the token `a` + //~^ ERROR no rules expected `a` } diff --git a/tests/ui/macros/macro-non-lifetime.stderr b/tests/ui/macros/macro-non-lifetime.stderr index 9ff3d741c01d2..35040a2229bd3 100644 --- a/tests/ui/macros/macro-non-lifetime.stderr +++ b/tests/ui/macros/macro-non-lifetime.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `a` +error: no rules expected `a` --> $DIR/macro-non-lifetime.rs:6:8 | LL | macro_rules! m { ($x:lifetime) => { } } diff --git a/tests/ui/macros/missing-comma.rs b/tests/ui/macros/missing-comma.rs index 92f8a77950583..64cfb0db31a0b 100644 --- a/tests/ui/macros/missing-comma.rs +++ b/tests/ui/macros/missing-comma.rs @@ -19,16 +19,16 @@ fn main() { println!("{}" a); //~^ ERROR expected `,`, found `a` foo!(a b); - //~^ ERROR no rules expected the token `b` + //~^ ERROR no rules expected `b` foo!(a, b, c, d e); - //~^ ERROR no rules expected the token `e` + //~^ ERROR no rules expected `e` foo!(a, b, c d, e); - //~^ ERROR no rules expected the token `d` + //~^ ERROR no rules expected `d` foo!(a, b, c d e); - //~^ ERROR no rules expected the token `d` + //~^ ERROR no rules expected `d` bar!(Level::Error, ); //~^ ERROR unexpected end of macro invocation check!(::fmt, "fmt"); check!(::fmt, "fmt",); - //~^ ERROR no rules expected the token `,` + //~^ ERROR no rules expected `,` } diff --git a/tests/ui/macros/missing-comma.stderr b/tests/ui/macros/missing-comma.stderr index 81877a29ed8ae..9913ba3491927 100644 --- a/tests/ui/macros/missing-comma.stderr +++ b/tests/ui/macros/missing-comma.stderr @@ -4,7 +4,7 @@ error: expected `,`, found `a` LL | println!("{}" a); | ^ expected `,` -error: no rules expected the token `b` +error: no rules expected `b` --> $DIR/missing-comma.rs:21:12 | LL | macro_rules! foo { @@ -21,7 +21,7 @@ note: while trying to match meta-variable `$a:ident` LL | ($a:ident) => (); | ^^^^^^^^ -error: no rules expected the token `e` +error: no rules expected `e` --> $DIR/missing-comma.rs:23:21 | LL | macro_rules! foo { @@ -38,7 +38,7 @@ note: while trying to match meta-variable `$d:ident` LL | ($a:ident, $b:ident, $c:ident, $d:ident) => (); | ^^^^^^^^ -error: no rules expected the token `d` +error: no rules expected `d` --> $DIR/missing-comma.rs:25:18 | LL | macro_rules! foo { @@ -55,7 +55,7 @@ note: while trying to match meta-variable `$c:ident` LL | ($a:ident, $b:ident, $c:ident) => (); | ^^^^^^^^ -error: no rules expected the token `d` +error: no rules expected `d` --> $DIR/missing-comma.rs:27:18 | LL | macro_rules! foo { @@ -85,7 +85,7 @@ note: while trying to match meta-variable `$arg:tt` LL | ($lvl:expr, $($arg:tt)+) => {} | ^^^^^^^ -error: no rules expected the token `,` +error: no rules expected `,` --> $DIR/missing-comma.rs:32:38 | LL | macro_rules! check { diff --git a/tests/ui/macros/nonterminal-matching.rs b/tests/ui/macros/nonterminal-matching.rs index 5f0d6b2f90eee..a655b66510311 100644 --- a/tests/ui/macros/nonterminal-matching.rs +++ b/tests/ui/macros/nonterminal-matching.rs @@ -16,7 +16,7 @@ macro complex_nonterminal($nt_item: item) { struct S; } - n!(a $nt_item b); //~ ERROR no rules expected the token `enum E {}` + n!(a $nt_item b); //~ ERROR no rules expected item `enum E {}` } simple_nonterminal!(a, 'a, (x, y, z)); // OK @@ -29,10 +29,10 @@ 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` + (expr $x:expr) => { bar!(expr $x); }; //~ ERROR: no rules expected expression `3` + (literal $x:literal) => { bar!(literal $x); }; //~ ERROR: no rules expected literal `4` + (path $x:path) => { bar!(path $x); }; //~ ERROR: no rules expected path `a::b::c` + (stmt $x:stmt) => { bar!(stmt $x); }; //~ ERROR: no rules expected statement `let abc = 0` } macro_rules! bar { diff --git a/tests/ui/macros/nonterminal-matching.stderr b/tests/ui/macros/nonterminal-matching.stderr index 3ee88b5f52ef9..e283dfcb8fdc4 100644 --- a/tests/ui/macros/nonterminal-matching.stderr +++ b/tests/ui/macros/nonterminal-matching.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `enum E {}` +error: no rules expected item `enum E {}` --> $DIR/nonterminal-matching.rs:19:10 | LL | macro n(a $nt_item b) { @@ -10,7 +10,7 @@ LL | n!(a $nt_item b); LL | complex_nonterminal!(enum E {}); | ------------------------------- in this macro invocation | -note: while trying to match `enum E {}` +note: while trying to match item `enum E {}` --> $DIR/nonterminal-matching.rs:15:15 | LL | macro n(a $nt_item b) { @@ -23,7 +23,7 @@ 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: no rules expected the token `3` +error: no rules expected expression `3` --> $DIR/nonterminal-matching.rs:32:35 | LL | (expr $x:expr) => { bar!(expr $x); }; @@ -45,7 +45,7 @@ LL | (expr 3) => {}; = 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` +error: no rules expected literal `4` --> $DIR/nonterminal-matching.rs:33:44 | LL | (literal $x:literal) => { bar!(literal $x); }; @@ -67,7 +67,7 @@ LL | (literal 4) => {}; = 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` +error: no rules expected path `a::b::c` --> $DIR/nonterminal-matching.rs:34:35 | LL | (path $x:path) => { bar!(path $x); }; @@ -89,7 +89,7 @@ LL | (path a::b::c) => {}; = 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` +error: no rules expected statement `let abc = 0` --> $DIR/nonterminal-matching.rs:35:35 | LL | (stmt $x:stmt) => { bar!(stmt $x); }; @@ -101,7 +101,7 @@ LL | macro_rules! bar { LL | foo!(stmt let abc = 0); | ---------------------- in this macro invocation | -note: while trying to match `let` +note: while trying to match keyword `let` --> $DIR/nonterminal-matching.rs:45:11 | LL | (stmt let abc = 0) => {}; diff --git a/tests/ui/macros/trace_faulty_macros.stderr b/tests/ui/macros/trace_faulty_macros.stderr index 66d7b76bb0726..10ad3faab1612 100644 --- a/tests/ui/macros/trace_faulty_macros.stderr +++ b/tests/ui/macros/trace_faulty_macros.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `bcd` +error: no rules expected `bcd` --> $DIR/trace_faulty_macros.rs:7:26 | LL | macro_rules! my_faulty_macro { diff --git a/tests/ui/offset-of/offset-of-arg-count.rs b/tests/ui/offset-of/offset-of-arg-count.rs index c86e61a61a725..f4c8b91d7daee 100644 --- a/tests/ui/offset-of/offset-of-arg-count.rs +++ b/tests/ui/offset-of/offset-of-arg-count.rs @@ -3,7 +3,7 @@ use std::mem::offset_of; fn main() { offset_of!(NotEnoughArguments); //~ ERROR unexpected end of macro invocation offset_of!(NotEnoughArgumentsWithAComma, ); //~ ERROR unexpected end of macro invocation - offset_of!(Container, field, too many arguments); //~ ERROR no rules expected the token `too` + offset_of!(Container, field, too many arguments); //~ ERROR no rules expected `too` offset_of!(S, f); // compiles fine offset_of!(S, f,); // also compiles fine offset_of!(S, f.); //~ ERROR unexpected token: `)` diff --git a/tests/ui/offset-of/offset-of-arg-count.stderr b/tests/ui/offset-of/offset-of-arg-count.stderr index 4cb24b3d034b6..0772bb18e0c62 100644 --- a/tests/ui/offset-of/offset-of-arg-count.stderr +++ b/tests/ui/offset-of/offset-of-arg-count.stderr @@ -16,7 +16,7 @@ LL | offset_of!(NotEnoughArgumentsWithAComma, ); note: while trying to match meta-variable `$fields:expr` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL -error: no rules expected the token `too` +error: no rules expected `too` --> $DIR/offset-of-arg-count.rs:6:34 | LL | offset_of!(Container, field, too many arguments); diff --git a/tests/ui/offset-of/offset-of-tuple.stderr b/tests/ui/offset-of/offset-of-tuple.stderr index dd20859e04e1b..38ce49c9179ba 100644 --- a/tests/ui/offset-of/offset-of-tuple.stderr +++ b/tests/ui/offset-of/offset-of-tuple.stderr @@ -76,7 +76,7 @@ error: suffixes on a tuple index are invalid LL | offset_of!((u8, u8), 1_u8); | ^^^^ invalid suffix `u8` -error: no rules expected the token `+` +error: no rules expected `+` --> $DIR/offset-of-tuple.rs:11:26 | LL | offset_of!((u8, u8), +1); diff --git a/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.rs b/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.rs index 7a94c96b79d89..fb227bf0e915f 100644 --- a/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.rs +++ b/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.rs @@ -9,5 +9,5 @@ macro_rules! accept_pat { ($p:pat) => {}; } -accept_pat!(p | q); //~ ERROR no rules expected the token `|` -accept_pat!(|p| q); //~ ERROR no rules expected the token `|` +accept_pat!(p | q); //~ ERROR no rules expected `|` +accept_pat!(|p| q); //~ ERROR no rules expected `|` diff --git a/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr b/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr index acc2099bbc6a8..47dac84ee4947 100644 --- a/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr +++ b/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `|` +error: no rules expected `|` --> $DIR/or-patterns-syntactic-fail-2018.rs:12:15 | LL | macro_rules! accept_pat { @@ -13,7 +13,7 @@ note: while trying to match meta-variable `$p:pat` LL | ($p:pat) => {}; | ^^^^^^ -error: no rules expected the token `|` +error: no rules expected `|` --> $DIR/or-patterns-syntactic-fail-2018.rs:13:13 | LL | macro_rules! accept_pat { diff --git a/tests/ui/parser/macro/macro-doc-comments-1.rs b/tests/ui/parser/macro/macro-doc-comments-1.rs index 8d8103bb1e065..1aaa993e0721d 100644 --- a/tests/ui/parser/macro/macro-doc-comments-1.rs +++ b/tests/ui/parser/macro/macro-doc-comments-1.rs @@ -4,6 +4,6 @@ macro_rules! outer { outer! { //! Inner -} //~^ ERROR no rules expected the token `!` +} //~^ ERROR no rules expected `!` fn main() { } diff --git a/tests/ui/parser/macro/macro-doc-comments-1.stderr b/tests/ui/parser/macro/macro-doc-comments-1.stderr index 9d2d1bc00725a..6b7e758980c2b 100644 --- a/tests/ui/parser/macro/macro-doc-comments-1.stderr +++ b/tests/ui/parser/macro/macro-doc-comments-1.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `!` +error: no rules expected `!` --> $DIR/macro-doc-comments-1.rs:6:5 | LL | macro_rules! outer { diff --git a/tests/ui/parser/macro/macro-doc-comments-2.rs b/tests/ui/parser/macro/macro-doc-comments-2.rs index 8f33720ae80eb..2bee2435ef872 100644 --- a/tests/ui/parser/macro/macro-doc-comments-2.rs +++ b/tests/ui/parser/macro/macro-doc-comments-2.rs @@ -4,6 +4,6 @@ macro_rules! inner { inner! { /// Outer -} //~^ ERROR no rules expected the token `[` +} //~^ ERROR no rules expected `[` fn main() { } diff --git a/tests/ui/parser/macro/macro-doc-comments-2.stderr b/tests/ui/parser/macro/macro-doc-comments-2.stderr index 22efd995b463c..02c12bf959114 100644 --- a/tests/ui/parser/macro/macro-doc-comments-2.stderr +++ b/tests/ui/parser/macro/macro-doc-comments-2.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `[` +error: no rules expected `[` --> $DIR/macro-doc-comments-2.rs:6:5 | LL | macro_rules! inner { diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs index b8c0eb3e6d6d7..4b2fc4a03b620 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs @@ -68,7 +68,7 @@ fn _macros() { _ => {} } use_expr!(let 0 = 1); - //~^ ERROR no rules expected the token `let` + //~^ ERROR no rules expected keyword `let` } fn main() {} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr index 2341dbbbdbd00..1c710b04897cb 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr @@ -131,7 +131,7 @@ LL | use_expr!((let 0 = 1)); | = note: only supported directly in conditions of `if` and `while` expressions -error: no rules expected the token `let` +error: no rules expected keyword `let` --> $DIR/feature-gate.rs:70:15 | LL | macro_rules! use_expr { diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs index bca7564efd83f..2087fc42cf102 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs @@ -54,7 +54,7 @@ fn _macros() { #[cfg(FALSE)] (let 0 = 1); //~^ ERROR expected expression, found `let` statement use_expr!(let 0 = 1); - //~^ ERROR no rules expected the token `let` + //~^ ERROR no rules expected keyword `let` } fn main() {} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr index 2b1a49be3daa5..7c874ae78a8ad 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr @@ -14,7 +14,7 @@ LL | noop_expr!((let 0 = 1)); | = note: only supported directly in conditions of `if` and `while` expressions -error: no rules expected the token `let` +error: no rules expected keyword `let` --> $DIR/feature-gate.rs:56:15 | LL | macro_rules! use_expr { diff --git a/tests/ui/underscore-ident-matcher.rs b/tests/ui/underscore-ident-matcher.rs index bddc8c80a7b96..77ec70d43d54e 100644 --- a/tests/ui/underscore-ident-matcher.rs +++ b/tests/ui/underscore-ident-matcher.rs @@ -5,5 +5,5 @@ macro_rules! identity { } fn main() { - let identity!(_) = 10; //~ ERROR no rules expected the token `_` + let identity!(_) = 10; //~ ERROR no rules expected reserved identifier `_` } diff --git a/tests/ui/underscore-ident-matcher.stderr b/tests/ui/underscore-ident-matcher.stderr index a663f34cde1b1..0c3f980cf6c71 100644 --- a/tests/ui/underscore-ident-matcher.stderr +++ b/tests/ui/underscore-ident-matcher.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `_` +error: no rules expected reserved identifier `_` --> $DIR/underscore-ident-matcher.rs:8:19 | LL | macro_rules! identity { From ace58ea8d0121490648b5408ff778d38e43daa0e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 17 Apr 2024 09:59:27 +1000 Subject: [PATCH 03/18] Introduce `InvisibleOrigin` on invisible delimiters. It's not used meaningfully yet, but will be needed to get rid of interpolated tokens. --- compiler/rustc_ast/src/attr/mod.rs | 4 +- compiler/rustc_ast/src/token.rs | 114 +++++++++++++++++- compiler/rustc_ast/src/tokenstream.rs | 6 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 5 +- compiler/rustc_expand/src/mbe/macro_rules.rs | 2 +- compiler/rustc_expand/src/mbe/quoted.rs | 11 +- .../rustc_expand/src/proc_macro_server.rs | 4 +- .../rustc_parse/src/parser/attr_wrapper.rs | 4 +- compiler/rustc_parse/src/parser/mod.rs | 12 +- src/tools/rustfmt/src/macros.rs | 2 +- 10 files changed, 133 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 94a00ab1a047e..c74b518f2dbfb 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -411,7 +411,7 @@ impl MetaItemKind { tokens: &mut impl Iterator, ) -> Option { match tokens.next() { - Some(TokenTree::Delimited(.., Delimiter::Invisible, inner_tokens)) => { + Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => { MetaItemKind::name_value_from_tokens(&mut inner_tokens.trees()) } Some(TokenTree::Token(token, _)) => { @@ -549,7 +549,7 @@ impl NestedMetaItem { tokens.next(); return Some(NestedMetaItem::Lit(lit)); } - Some(TokenTree::Delimited(.., Delimiter::Invisible, inner_tokens)) => { + Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => { tokens.next(); return NestedMetaItem::from_tokens(&mut inner_tokens.trees().peekable()); } diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index a0082a41713be..9cc47ccb3c58a 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -42,11 +42,87 @@ pub enum BinOpToken { Shr, } +// This type must not implement `Hash` due to the unusual `PartialEq` impl below. +#[derive(Copy, Clone, Debug, Encodable, Decodable, HashStable_Generic)] +pub enum InvisibleOrigin { + // From the expansion of a metavariable in a declarative macro. + MetaVar(MetaVarKind), + + // Converted from `proc_macro::Delimiter` in + // `proc_macro::Delimiter::to_internal`, i.e. returned by a proc macro. + ProcMacro, + + // Converted from `TokenKind::Interpolated` in + // `TokenStream::flatten_token`. Treated similarly to `ProcMacro`. + FlattenToken, +} + +impl PartialEq for InvisibleOrigin { + #[inline] + fn eq(&self, _other: &InvisibleOrigin) -> bool { + // When we had AST-based nonterminals we couldn't compare them, and the + // old `Nonterminal` type had an `eq` that always returned false, + // resulting in this restriction: + // https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment + // This `eq` emulates that behaviour. We could consider lifting this + // restriction now but there are still cases involving invisible + // delimiters that make it harder than it first appears. + false + } +} + +/// Annoyingly similar to `NonterminalKind`, but the slight differences are important. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)] +pub enum MetaVarKind { + Item, + Block, + Stmt, + Pat(NtPatKind), + Expr { + kind: NtExprKind, + // This field is needed for `Token::can_begin_literal_maybe_minus`. + can_begin_literal_maybe_minus: bool, + // This field is needed for `Token::can_begin_string_literal`. + can_begin_string_literal: bool, + }, + Ty, + Ident, + Lifetime, + Literal, + Meta, + Path, + Vis, + TT, +} + +impl fmt::Display for MetaVarKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use MetaVarKind::*; + let sym = match self { + Item => sym::item, + Block => sym::block, + Stmt => sym::stmt, + Pat(PatParam { inferred: true } | PatWithOr) => sym::pat, + Pat(PatParam { inferred: false }) => sym::pat_param, + Expr { kind: Expr2021 { inferred: true } | Expr, .. } => sym::expr, + Expr { kind: Expr2021 { inferred: false }, .. } => sym::expr_2021, + Ty => sym::ty, + Ident => sym::ident, + Lifetime => sym::lifetime, + Literal => sym::literal, + Meta => sym::meta, + Path => sym::path, + Vis => sym::vis, + TT => sym::tt, + }; + write!(f, "{}", sym) + } +} + /// Describes how a sequence of token trees is delimited. /// Cannot use `proc_macro::Delimiter` directly because this /// structure should implement some additional traits. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[derive(Encodable, Decodable, Hash, HashStable_Generic)] +#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)] pub enum Delimiter { /// `( ... )` Parenthesis, @@ -59,7 +135,33 @@ pub enum Delimiter { /// "macro variable" `$var`. It is important to preserve operator priorities in cases like /// `$var * 3` where `$var` is `1 + 2`. /// Invisible delimiters might not survive roundtrip of a token stream through a string. - Invisible, + Invisible(InvisibleOrigin), +} + +impl Delimiter { + // Should the parser skip these delimiters? Only happens for certain kinds + // of invisible delimiters. Ideally this function will eventually disappear + // and no invisible delimiters will be skipped. + #[inline] + pub fn skip(&self) -> bool { + use InvisibleOrigin::*; + match self { + Delimiter::Parenthesis | Delimiter::Bracket | Delimiter::Brace => false, + Delimiter::Invisible(MetaVar(_)) => false, + Delimiter::Invisible(FlattenToken | ProcMacro) => true, + } + } + + // This exists because `InvisibleOrigin`s should be compared. It is only used for assertions. + pub fn eq_ignoring_invisible_origin(&self, other: &Delimiter) -> bool { + match (self, other) { + (Delimiter::Parenthesis, Delimiter::Parenthesis) => true, + (Delimiter::Brace, Delimiter::Brace) => true, + (Delimiter::Bracket, Delimiter::Bracket) => true, + (Delimiter::Invisible(_), Delimiter::Invisible(_)) => true, + _ => false, + } + } } // Note that the suffix is *not* considered when deciding the `LitKind` in this @@ -890,7 +992,7 @@ impl PartialEq for Token { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)] pub enum NtPatKind { // Matches or-patterns. Was written using `pat` in edition 2021 or later. PatWithOr, @@ -900,7 +1002,7 @@ pub enum NtPatKind { PatParam { inferred: bool }, } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)] pub enum NtExprKind { // Matches expressions using the post-edition 2024. Was written using // `expr` in edition 2024 or later. @@ -927,7 +1029,7 @@ pub enum Nonterminal { NtVis(P), } -#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)] pub enum NonterminalKind { Item, Block, diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index fc1dd2caf681a..5b2b09060240b 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -24,7 +24,7 @@ use rustc_span::{sym, Span, SpanDecoder, SpanEncoder, Symbol, DUMMY_SP}; use crate::ast::{AttrStyle, StmtKind}; use crate::ast_traits::{HasAttrs, HasTokens}; -use crate::token::{self, Delimiter, Nonterminal, Token, TokenKind}; +use crate::token::{self, Delimiter, InvisibleOrigin, Nonterminal, Token, TokenKind}; use crate::{AttrVec, Attribute}; /// Part of a `TokenStream`. @@ -485,13 +485,13 @@ impl TokenStream { token::NtLifetime(ident, is_raw) => TokenTree::Delimited( DelimSpan::from_single(token.span), DelimSpacing::new(Spacing::JointHidden, spacing), - Delimiter::Invisible, + Delimiter::Invisible(InvisibleOrigin::FlattenToken), TokenStream::token_alone(token::Lifetime(ident.name, is_raw), ident.span), ), token::Interpolated(ref nt) => TokenTree::Delimited( DelimSpan::from_single(token.span), DelimSpacing::new(Spacing::JointHidden, spacing), - Delimiter::Invisible, + Delimiter::Invisible(InvisibleOrigin::FlattenToken), TokenStream::from_nonterminal_ast(&nt).flattened(), ), _ => TokenTree::Token(token.clone(), spacing), diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 3b1449d9a9113..b45028fc2500b 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -931,9 +931,8 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere token::CloseDelim(Delimiter::Bracket) => "]".into(), token::OpenDelim(Delimiter::Brace) => "{".into(), token::CloseDelim(Delimiter::Brace) => "}".into(), - token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible) => { - "".into() - } + token::OpenDelim(Delimiter::Invisible(_)) + | token::CloseDelim(Delimiter::Invisible(_)) => "".into(), token::Pound => "#".into(), token::Dollar => "$".into(), token::Question => "?".into(), diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 256713ef73000..10a00d5578801 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -711,7 +711,7 @@ fn has_compile_error_macro(rhs: &mbe::TokenTree) -> bool { && let mbe::TokenTree::Token(bang) = bang && let TokenKind::Not = bang.kind && let mbe::TokenTree::Delimited(.., del) = args - && del.delim != Delimiter::Invisible + && !del.delim.skip() { true } else { diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 5df0aebfe57bd..c1e8a9c3096aa 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -195,11 +195,12 @@ fn parse_tree<'a>( // during parsing. let mut next = outer_trees.next(); let mut trees: Box>; - if let Some(tokenstream::TokenTree::Delimited(.., Delimiter::Invisible, tts)) = next { - trees = Box::new(tts.trees()); - next = trees.next(); - } else { - trees = Box::new(outer_trees); + match next { + Some(tokenstream::TokenTree::Delimited(.., delim, tts)) if delim.skip() => { + trees = Box::new(tts.trees()); + next = trees.next(); + } + _ => trees = Box::new(outer_trees), } match next { diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 5798bcedc2263..76bc7c057e2ea 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -38,7 +38,7 @@ impl FromInternal for Delimiter { token::Delimiter::Parenthesis => Delimiter::Parenthesis, token::Delimiter::Brace => Delimiter::Brace, token::Delimiter::Bracket => Delimiter::Bracket, - token::Delimiter::Invisible => Delimiter::None, + token::Delimiter::Invisible(_) => Delimiter::None, } } } @@ -49,7 +49,7 @@ impl ToInternal for Delimiter { Delimiter::Parenthesis => token::Delimiter::Parenthesis, Delimiter::Brace => token::Delimiter::Brace, Delimiter::Bracket => token::Delimiter::Bracket, - Delimiter::None => token::Delimiter::Invisible, + Delimiter::None => token::Delimiter::Invisible(token::InvisibleOrigin::ProcMacro), } } } diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 6a241be0a1560..9d73eb4cccf22 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -493,8 +493,8 @@ fn make_attr_token_stream( FlatToken::Token((Token { kind: TokenKind::CloseDelim(delim), span }, spacing)) => { let frame_data = mem::replace(&mut stack_top, stack_rest.pop().unwrap()); let (open_delim, open_sp, open_spacing) = frame_data.open_delim_sp.unwrap(); - assert_eq!( - open_delim, delim, + assert!( + open_delim.eq_ignoring_invisible_origin(&delim), "Mismatched open/close delims: open={open_delim:?} close={span:?}" ); let dspan = DelimSpan::from_pair(open_sp, span); diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index c5b63e31aa5d5..3e047b41a0487 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -313,7 +313,7 @@ impl TokenCursor { spacing, delim, )); - if delim != Delimiter::Invisible { + if !delim.skip() { return (Token::new(token::OpenDelim(delim), sp.open), spacing.open); } // No open delimiter to return; continue on to the next iteration. @@ -322,7 +322,7 @@ impl TokenCursor { } else if let Some((tree_cursor, span, spacing, delim)) = self.stack.pop() { // We have exhausted this token stream. Move back to its parent token stream. self.tree_cursor = tree_cursor; - if delim != Delimiter::Invisible { + if !delim.skip() { return (Token::new(token::CloseDelim(delim), span.close), spacing.close); } // No close delimiter to return; continue on to the next iteration. @@ -1159,7 +1159,7 @@ impl<'a> Parser<'a> { } debug_assert!(!matches!( next.0.kind, - token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible) + token::OpenDelim(delim) | token::CloseDelim(delim) if delim.skip() )); self.inlined_bump_with(next) } @@ -1183,7 +1183,7 @@ impl<'a> Parser<'a> { match tree { TokenTree::Token(token, _) => return looker(token), &TokenTree::Delimited(dspan, _, delim, _) => { - if delim != Delimiter::Invisible { + if !delim.skip() { return looker(&Token::new(token::OpenDelim(delim), dspan.open)); } } @@ -1193,7 +1193,7 @@ impl<'a> Parser<'a> { // The tree cursor lookahead went (one) past the end of the // current token tree. Try to return a close delimiter. if let Some(&(_, span, _, delim)) = self.token_cursor.stack.last() - && delim != Delimiter::Invisible + && !delim.skip() { // We are not in the outermost token stream, so we have // delimiters. Also, those delimiters are not skipped. @@ -1212,7 +1212,7 @@ impl<'a> Parser<'a> { token = cursor.next().0; if matches!( token.kind, - token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible) + token::OpenDelim(delim) | token::CloseDelim(delim) if delim.skip() ) { continue; } diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs index 524fc666faeef..e07871144bcb3 100644 --- a/src/tools/rustfmt/src/macros.rs +++ b/src/tools/rustfmt/src/macros.rs @@ -589,7 +589,7 @@ fn delim_token_to_str( ("{ ", " }") } } - Delimiter::Invisible => unreachable!(), + Delimiter::Invisible(_) => unreachable!(), }; if use_multiple_lines { let indent_str = shape.indent.to_string_with_newline(context.config); From 4ce695618850440fd4579a8b03add4fa783261dc Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 18 Apr 2024 08:58:06 +1000 Subject: [PATCH 04/18] Add metavariables to `TokenDescription`. Pasted metavariables are wrapped in invisible delimiters, which pretty-print as empty strings, and changing that can break some proc macros. But error messages saying "expected identifer, found ``" are bad. So this commit adds support for metavariables in `TokenDescription` so they print as "metavariable" in error messages, instead of "``". It's not used meaningfully yet, but will be needed to get rid of interpolated tokens. --- compiler/rustc_parse/messages.ftl | 7 +++++ compiler/rustc_parse/src/errors.rs | 28 +++++++++++++++-- compiler/rustc_parse/src/parser/mod.rs | 43 +++++++++++++++++--------- 3 files changed, 61 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index ec9a676ea3135..2db333af9824a 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -207,6 +207,9 @@ parse_expected_identifier_found_doc_comment = expected identifier, found doc com parse_expected_identifier_found_doc_comment_str = expected identifier, found doc comment `{$token}` parse_expected_identifier_found_keyword = expected identifier, found keyword parse_expected_identifier_found_keyword_str = expected identifier, found keyword `{$token}` +parse_expected_identifier_found_metavar = expected identifier, found metavariable +# This one deliberately doesn't print a token. +parse_expected_identifier_found_metavar_str = expected identifier, found metavariable parse_expected_identifier_found_reserved_identifier = expected identifier, found reserved identifier parse_expected_identifier_found_reserved_identifier_str = expected identifier, found reserved identifier `{$token}` parse_expected_identifier_found_reserved_keyword = expected identifier, found reserved keyword @@ -218,6 +221,8 @@ parse_expected_mut_or_const_in_raw_pointer_type = expected `mut` or `const` keyw parse_expected_semi_found_doc_comment_str = expected `;`, found doc comment `{$token}` parse_expected_semi_found_keyword_str = expected `;`, found keyword `{$token}` +# This one deliberately doesn't print a token. +parse_expected_semi_found_metavar_str = expected `;`, found metavariable parse_expected_semi_found_reserved_identifier_str = expected `;`, found reserved identifier `{$token}` parse_expected_semi_found_reserved_keyword_str = expected `;`, found reserved keyword `{$token}` parse_expected_semi_found_str = expected `;`, found `{$token}` @@ -845,6 +850,8 @@ parse_unexpected_token_after_not_logical = use `!` to perform logical negation parse_unexpected_token_after_struct_name = expected `where`, `{"{"}`, `(`, or `;` after struct name parse_unexpected_token_after_struct_name_found_doc_comment = expected `where`, `{"{"}`, `(`, or `;` after struct name, found doc comment `{$token}` parse_unexpected_token_after_struct_name_found_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found keyword `{$token}` +# This one deliberately doesn't print a token. +parse_unexpected_token_after_struct_name_found_metavar = expected `where`, `{"{"}`, `(`, or `;` after struct name, found metavar parse_unexpected_token_after_struct_name_found_other = expected `where`, `{"{"}`, `(`, or `;` after struct name, found `{$token}` parse_unexpected_token_after_struct_name_found_reserved_identifier = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved identifier `{$token}` diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index da1103a4fe5dc..f4780e507818e 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1083,6 +1083,8 @@ pub(crate) enum ExpectedIdentifierFound { ReservedKeyword(#[primary_span] Span), #[label(parse_expected_identifier_found_doc_comment)] DocComment(#[primary_span] Span), + #[label(parse_expected_identifier_found_metavar)] + MetaVar(#[primary_span] Span), #[label(parse_expected_identifier)] Other(#[primary_span] Span), } @@ -1096,6 +1098,7 @@ impl ExpectedIdentifierFound { Some(TokenDescription::Keyword) => ExpectedIdentifierFound::Keyword, Some(TokenDescription::ReservedKeyword) => ExpectedIdentifierFound::ReservedKeyword, Some(TokenDescription::DocComment) => ExpectedIdentifierFound::DocComment, + Some(TokenDescription::MetaVar(_)) => ExpectedIdentifierFound::MetaVar, None => ExpectedIdentifierFound::Other, })(span) } @@ -1114,6 +1117,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedIdentifier { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let token_descr = TokenDescription::from_token(&self.token); + let mut add_token = true; let mut diag = Diag::new( dcx, level, @@ -1130,11 +1134,17 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedIdentifier { Some(TokenDescription::DocComment) => { fluent::parse_expected_identifier_found_doc_comment_str } + Some(TokenDescription::MetaVar(_)) => { + add_token = false; + fluent::parse_expected_identifier_found_metavar_str + } None => fluent::parse_expected_identifier_found_str, }, ); diag.span(self.span); - diag.arg("token", self.token); + if add_token { + diag.arg("token", self.token); + } if let Some(sugg) = self.suggest_raw { sugg.add_to_diag(&mut diag); @@ -1174,6 +1184,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedSemi { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let token_descr = TokenDescription::from_token(&self.token); + let mut add_token = true; let mut diag = Diag::new( dcx, level, @@ -1188,11 +1199,17 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedSemi { Some(TokenDescription::DocComment) => { fluent::parse_expected_semi_found_doc_comment_str } + Some(TokenDescription::MetaVar(_)) => { + add_token = false; + fluent::parse_expected_semi_found_metavar_str + } None => fluent::parse_expected_semi_found_str, }, ); diag.span(self.span); - diag.arg("token", self.token); + if add_token { + diag.arg("token", self.token); + } if let Some(unexpected_token_label) = self.unexpected_token_label { diag.span_label(unexpected_token_label, fluent::parse_label_unexpected_token); @@ -1918,6 +1935,12 @@ pub(crate) enum UnexpectedTokenAfterStructName { span: Span, token: Token, }, + #[diag(parse_unexpected_token_after_struct_name_found_metavar)] + MetaVar { + #[primary_span] + #[label(parse_unexpected_token_after_struct_name)] + span: Span, + }, #[diag(parse_unexpected_token_after_struct_name_found_other)] Other { #[primary_span] @@ -1934,6 +1957,7 @@ impl UnexpectedTokenAfterStructName { Some(TokenDescription::Keyword) => Self::Keyword { span, token }, Some(TokenDescription::ReservedKeyword) => Self::ReservedKeyword { span, token }, Some(TokenDescription::DocComment) => Self::DocComment { span, token }, + Some(TokenDescription::MetaVar(_)) => Self::MetaVar { span }, None => Self::Other { span, token }, } } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 3e047b41a0487..5521e710d4539 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -21,7 +21,9 @@ pub(crate) use item::FnParseMode; pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; use path::PathStyle; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind}; +use rustc_ast::token::{ + self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, Nonterminal, Token, TokenKind, +}; use rustc_ast::tokenstream::{ AttrsTarget, DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree, TokenTreeCursor, }; @@ -406,6 +408,12 @@ pub(super) enum TokenDescription { Keyword, ReservedKeyword, DocComment, + + // Expanded metavariables are wrapped in invisible delimiters which aren't + // pretty-printed. In error messages we must handle these specially + // otherwise we get confusing things in messages like "expected `(`, found + // ``". It's better to say e.g. "expected `(`, found type metavariable". + MetaVar(MetaVarKind), } impl TokenDescription { @@ -415,26 +423,31 @@ impl TokenDescription { _ if token.is_used_keyword() => Some(TokenDescription::Keyword), _ if token.is_unused_keyword() => Some(TokenDescription::ReservedKeyword), token::DocComment(..) => Some(TokenDescription::DocComment), + token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => { + Some(TokenDescription::MetaVar(kind)) + } _ => None, } } } pub fn token_descr(token: &Token) -> String { - let name = pprust::token_to_string(token).to_string(); - - let kind = match (TokenDescription::from_token(token), &token.kind) { - (Some(TokenDescription::ReservedIdentifier), _) => Some("reserved identifier"), - (Some(TokenDescription::Keyword), _) => Some("keyword"), - (Some(TokenDescription::ReservedKeyword), _) => Some("reserved keyword"), - (Some(TokenDescription::DocComment), _) => Some("doc comment"), - (None, TokenKind::NtIdent(..)) => Some("identifier"), - (None, TokenKind::NtLifetime(..)) => Some("lifetime"), - (None, TokenKind::Interpolated(node)) => Some(node.descr()), - (None, _) => None, - }; - - if let Some(kind) = kind { format!("{kind} `{name}`") } else { format!("`{name}`") } + use TokenDescription::*; + + let s = pprust::token_to_string(token).to_string(); + + match (TokenDescription::from_token(token), &token.kind) { + (Some(ReservedIdentifier), _) => format!("reserved identifier `{s}`"), + (Some(Keyword), _) => format!("keyword `{s}`"), + (Some(ReservedKeyword), _) => format!("reserved keyword `{s}`"), + (Some(DocComment), _) => format!("doc comment `{s}`"), + // Deliberately doesn't print `s`, which is empty. + (Some(MetaVar(kind)), _) => format!("`{kind}` metavariable"), + (None, TokenKind::NtIdent(..)) => format!("identifier `{s}`"), + (None, TokenKind::NtLifetime(..)) => format!("lifetime `{s}`"), + (None, TokenKind::Interpolated(node)) => format!("{} `{s}`", node.descr()), + (None, _) => format!("`{s}`"), + } } impl<'a> Parser<'a> { From 9625b10e321acd85ce1977c8b6c57d0e7076d78f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 17 Apr 2024 09:37:00 +1000 Subject: [PATCH 05/18] Prepare for invisible delimiters. Current places where `Interpolated` is used are going to change to instead use invisible delimiters. This prepares for that. - It adds invisible delimiter cases to the `can_begin_*`/`may_be_*` methods and the `failed_to_match_macro` that are equivalent to the existing `Interpolated` cases. - It adds panics/asserts in some places where invisible delimiters should never occur. - In `Parser::parse_struct_fields` it excludes an ident + invisible delimiter from special consideration in an error message, because that's quite different to an ident + paren/brace/bracket. --- compiler/rustc_ast/src/token.rs | 38 +++++++++++++- compiler/rustc_expand/src/mbe/diagnostics.rs | 6 ++- compiler/rustc_parse/src/lexer/tokentrees.rs | 16 ++++-- compiler/rustc_parse/src/parser/expr.rs | 12 ++++- .../rustc_parse/src/parser/nonterminal.rs | 51 +++++++++++++++++-- 5 files changed, 109 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 9cc47ccb3c58a..2841cd19704ce 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -592,10 +592,11 @@ impl Token { /// **NB**: Take care when modifying this function, since it will change /// the stable set of tokens that are allowed to match an expr nonterminal. pub fn can_begin_expr(&self) -> bool { + use Delimiter::*; match self.uninterpolate().kind { Ident(name, is_raw) => ident_can_begin_expr(name, self.span, is_raw), // value name or keyword - OpenDelim(..) | // tuple, array or block + OpenDelim(Parenthesis | Brace | Bracket) | // tuple, array or block Literal(..) | // literal Not | // operator not BinOp(Minus) | // unary minus @@ -606,7 +607,7 @@ impl Token { // DotDotDot is no longer supported, but we need some way to display the error DotDot | DotDotDot | DotDotEq | // range notation Lt | BinOp(Shl) | // associated path - PathSep | // global path + PathSep | // global path Lifetime(..) | // labeled loop Pound => true, // expression attributes Interpolated(ref nt) => @@ -616,6 +617,12 @@ impl Token { NtLiteral(..) | NtPath(..) ), + OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( + MetaVarKind::Block | + MetaVarKind::Expr { .. } | + MetaVarKind::Literal | + MetaVarKind::Path + ))) => true, _ => false, } } @@ -649,6 +656,14 @@ impl Token { | NtPath(..) | NtTy(..) ), + OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( + MetaVarKind::Expr { .. } | + MetaVarKind::Literal | + MetaVarKind::Meta | + MetaVarKind::Pat(_) | + MetaVarKind::Path | + MetaVarKind::Ty + ))) => true, _ => false, } } @@ -669,6 +684,10 @@ impl Token { Lt | BinOp(Shl) | // associated path PathSep => true, // global path Interpolated(ref nt) => matches!(&**nt, NtTy(..) | NtPath(..)), + OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( + MetaVarKind::Ty | + MetaVarKind::Path + ))) => true, // For anonymous structs or unions, which only appear in specific positions // (type of struct fields or union fields), we don't consider them as regular types _ => false, @@ -681,6 +700,9 @@ impl Token { OpenDelim(Delimiter::Brace) | Literal(..) | BinOp(Minus) => true, Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true, Interpolated(ref nt) => matches!(&**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)), + OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( + MetaVarKind::Expr { .. } | MetaVarKind::Block | MetaVarKind::Literal, + ))) => true, _ => false, } } @@ -737,6 +759,13 @@ impl Token { }, _ => false, }, + OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind))) => match mv_kind { + MetaVarKind::Literal => true, + MetaVarKind::Expr { can_begin_literal_maybe_minus, .. } => { + can_begin_literal_maybe_minus + } + _ => false, + }, _ => false, } } @@ -752,6 +781,11 @@ impl Token { }, _ => false, }, + OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind))) => match mv_kind { + MetaVarKind::Literal => true, + MetaVarKind::Expr { can_begin_string_literal, .. } => can_begin_string_literal, + _ => false, + }, _ => false, } } diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 7083664f5b015..3b39968845193 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use rustc_ast::token::{self, Token, TokenKind}; +use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::TokenStream; use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage}; use rustc_macros::Subdiagnostic; @@ -68,7 +68,9 @@ pub(super) fn failed_to_match_macro( if let MatcherLoc::Token { token: expected_token } = &remaining_matcher && (matches!(expected_token.kind, TokenKind::Interpolated(_)) - || matches!(token.kind, TokenKind::Interpolated(_))) + || matches!(token.kind, TokenKind::Interpolated(_)) + || matches!(expected_token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_))) + || matches!(token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_)))) { err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens"); err.note("see for more information"); diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index c83d8bf4021ee..157a58f04dc61 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -43,11 +43,19 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { let mut buf = Vec::new(); loop { match self.token.kind { - token::OpenDelim(delim) => buf.push(match self.lex_token_tree_open_delim(delim) { - Ok(val) => val, - Err(errs) => return (open_spacing, TokenStream::new(buf), Err(errs)), - }), + token::OpenDelim(delim) => { + // Invisible delimiters cannot occur here because `TokenTreesReader` parses + // code directly from strings, with no macro expansion involved. + debug_assert!(!matches!(delim, Delimiter::Invisible(_))); + buf.push(match self.lex_token_tree_open_delim(delim) { + Ok(val) => val, + Err(errs) => return (open_spacing, TokenStream::new(buf), Err(errs)), + }) + } token::CloseDelim(delim) => { + // Invisible delimiters cannot occur here because `TokenTreesReader` parses + // code directly from strings, with no macro expansion involved. + debug_assert!(!matches!(delim, Delimiter::Invisible(_))); return ( open_spacing, TokenStream::new(buf), diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 2d5a1914fa68a..6343aae2697f7 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3582,11 +3582,19 @@ impl<'a> Parser<'a> { && !self.token.is_reserved_ident() && self.look_ahead(1, |t| { AssocOp::from_token(t).is_some() - || matches!(t.kind, token::OpenDelim(_)) + || matches!( + t.kind, + token::OpenDelim( + Delimiter::Parenthesis + | Delimiter::Bracket + | Delimiter::Brace + ) + ) || *t == token::Dot }) { - // Looks like they tried to write a shorthand, complex expression. + // Looks like they tried to write a shorthand, complex expression, + // E.g.: `n + m`, `f(a)`, `a[i]`, `S { x: 3 }`, or `x.y`. e.span_suggestion_verbose( self.token.span.shrink_to_lo(), "try naming a field", diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 44b169c881e12..3d0e2be688596 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -2,7 +2,9 @@ use rustc_ast::ptr::P; use rustc_ast::token::Nonterminal::*; use rustc_ast::token::NtExprKind::*; use rustc_ast::token::NtPatKind::*; -use rustc_ast::token::{self, Delimiter, NonterminalKind, Token}; +use rustc_ast::token::{ + self, Delimiter, InvisibleOrigin, MetaVarKind, Nonterminal, NonterminalKind, Token, +}; use rustc_ast::HasTokens; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; @@ -22,7 +24,29 @@ impl<'a> Parser<'a> { #[inline] pub fn nonterminal_may_begin_with(kind: NonterminalKind, token: &Token) -> bool { /// Checks whether the non-terminal may contain a single (non-keyword) identifier. - fn may_be_ident(nt: &token::Nonterminal) -> bool { + fn may_be_ident(kind: MetaVarKind) -> bool { + use MetaVarKind::*; + match kind { + Stmt + | Pat(_) + | Expr { .. } + | Ty + | Literal // `true`, `false` + | Meta + | Path => true, + + Item + | Block + | Vis => false, + + Ident + | Lifetime + | TT => unreachable!(), + } + } + + /// Old variant of `may_be_ident`. Being phased out. + fn nt_may_be_ident(nt: &Nonterminal) -> bool { match nt { NtStmt(_) | NtPat(_) @@ -69,7 +93,8 @@ impl<'a> Parser<'a> { | token::Ident(..) | token::NtIdent(..) | token::NtLifetime(..) - | token::Interpolated(_) => true, + | token::Interpolated(_) + | token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => true, _ => token.can_begin_type(), }, NonterminalKind::Block => match &token.kind { @@ -79,11 +104,29 @@ impl<'a> Parser<'a> { NtBlock(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true, NtItem(_) | NtPat(_) | NtTy(_) | NtMeta(_) | NtPath(_) | NtVis(_) => false, }, + token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k { + MetaVarKind::Block + | MetaVarKind::Stmt + | MetaVarKind::Expr { .. } + | MetaVarKind::Literal => true, + MetaVarKind::Item + | MetaVarKind::Pat(_) + | MetaVarKind::Ty + | MetaVarKind::Meta + | MetaVarKind::Path + | MetaVarKind::Vis => false, + MetaVarKind::Lifetime | MetaVarKind::Ident | MetaVarKind::TT => { + unreachable!() + } + }, _ => false, }, NonterminalKind::Path | NonterminalKind::Meta => match &token.kind { token::PathSep | token::Ident(..) | token::NtIdent(..) => true, - token::Interpolated(nt) => may_be_ident(nt), + token::Interpolated(nt) => nt_may_be_ident(nt), + token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => { + may_be_ident(*kind) + } _ => false, }, NonterminalKind::Pat(pat_kind) => token.can_begin_pattern(pat_kind), From 08af67f6340cf9dcf48e3928ad40dcc135e3c0fd Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 17 Apr 2024 12:17:09 +1000 Subject: [PATCH 06/18] Remove `NtVis`. We now use invisible delimiters for expanded `vis` fragments, instead of `Token::Interpolated`. --- compiler/rustc_ast/src/ast_traits.rs | 2 - compiler/rustc_ast/src/mut_visit.rs | 1 - compiler/rustc_ast/src/token.rs | 13 ++++-- compiler/rustc_ast/src/tokenstream.rs | 1 - compiler/rustc_expand/src/mbe/transcribe.rs | 22 ++++++++- compiler/rustc_parse/src/parser/mod.rs | 46 ++++++++++++++++++- .../rustc_parse/src/parser/nonterminal.rs | 13 +++--- 7 files changed, 79 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 60f8c6e10481b..a2923d6448ae9 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -206,7 +206,6 @@ impl HasTokens for Nonterminal { Nonterminal::NtTy(ty) => ty.tokens(), Nonterminal::NtMeta(attr_item) => attr_item.tokens(), Nonterminal::NtPath(path) => path.tokens(), - Nonterminal::NtVis(vis) => vis.tokens(), Nonterminal::NtBlock(block) => block.tokens(), } } @@ -219,7 +218,6 @@ impl HasTokens for Nonterminal { Nonterminal::NtTy(ty) => ty.tokens_mut(), Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(), Nonterminal::NtPath(path) => path.tokens_mut(), - Nonterminal::NtVis(vis) => vis.tokens_mut(), Nonterminal::NtBlock(block) => block.tokens_mut(), } } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 1bef51aa73f7b..8acc31a7e540c 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -824,7 +824,6 @@ fn visit_nonterminal(vis: &mut T, nt: &mut token::Nonterminal) { visit_lazy_tts(vis, tokens); } token::NtPath(path) => vis.visit_path(path), - token::NtVis(visib) => vis.visit_vis(visib), } } diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 2841cd19704ce..0244747039ada 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -957,6 +957,15 @@ impl Token { } } + /// Is this an invisible open delimiter at the start of a token sequence + /// from an expanded metavar? + pub fn is_metavar_seq(&self) -> Option { + match self.kind { + OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => Some(kind), + _ => None, + } + } + pub fn glue(&self, joint: &Token) -> Option { let kind = match self.kind { Eq => match joint.kind { @@ -1060,7 +1069,6 @@ pub enum Nonterminal { /// Stuff inside brackets for attributes NtMeta(P), NtPath(P), - NtVis(P), } #[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)] @@ -1157,7 +1165,6 @@ impl Nonterminal { NtTy(ty) => ty.span, NtMeta(attr_item) => attr_item.span(), NtPath(path) => path.span, - NtVis(vis) => vis.span, } } @@ -1172,7 +1179,6 @@ impl Nonterminal { NtTy(..) => "type", NtMeta(..) => "attribute", NtPath(..) => "path", - NtVis(..) => "visibility", } } } @@ -1199,7 +1205,6 @@ impl fmt::Debug for Nonterminal { NtLiteral(..) => f.pad("NtLiteral(..)"), NtMeta(..) => f.pad("NtMeta(..)"), NtPath(..) => f.pad("NtPath(..)"), - NtVis(..) => f.pad("NtVis(..)"), } } } diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 5b2b09060240b..c03c9557a3f4b 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -472,7 +472,6 @@ impl TokenStream { Nonterminal::NtTy(ty) => TokenStream::from_ast(ty), Nonterminal::NtMeta(attr) => TokenStream::from_ast(attr), Nonterminal::NtPath(path) => TokenStream::from_ast(path), - Nonterminal::NtVis(vis) => TokenStream::from_ast(vis), Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => TokenStream::from_ast(expr), } } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 2bd78d347368a..80e9841f1ffdf 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -1,7 +1,10 @@ use std::mem; use rustc_ast::mut_visit::{self, MutVisitor}; -use rustc_ast::token::{self, Delimiter, IdentIsRaw, Lit, LitKind, Nonterminal, Token, TokenKind}; +use rustc_ast::token::{ + self, Delimiter, IdentIsRaw, InvisibleOrigin, Lit, LitKind, MetaVarKind, Nonterminal, Token, + TokenKind, +}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_ast::ExprKind; use rustc_data_structures::fx::FxHashMap; @@ -252,7 +255,6 @@ pub(super) fn transcribe<'a>( } } - // Replace the meta-var with the matched token tree from the invocation. mbe::TokenTree::MetaVar(mut sp, mut original_ident) => { // Find the matched nonterminal from the macro invocation, and use it to replace // the meta-var. @@ -272,6 +274,19 @@ pub(super) fn transcribe<'a>( // some of the unnecessary whitespace. let ident = MacroRulesNormalizedIdent::new(original_ident); if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) { + let mut mk_delimited = |mv_kind, stream| { + // Emit as a token stream within `Delimiter::Invisible` to maintain parsing + // priorities. + marker.visit_span(&mut sp); + // Both the open delim and close delim get the same span, which covers the + // `$foo` in the decl macro RHS. + TokenTree::Delimited( + DelimSpan::from_single(sp), + DelimSpacing::new(Spacing::Alone, Spacing::Alone), + Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind)), + stream, + ) + }; let tt = match cur_matched { MatchedSingle(ParseNtResult::Tt(tt)) => { // `tt`s are emitted into the output stream directly as "raw tokens", @@ -288,6 +303,9 @@ pub(super) fn transcribe<'a>( let kind = token::NtLifetime(*ident, *is_raw); TokenTree::token_alone(kind, sp) } + MatchedSingle(ParseNtResult::Vis(vis)) => { + mk_delimited(MetaVarKind::Vis, TokenStream::from_ast(vis)) + } MatchedSingle(ParseNtResult::Nt(nt)) => { // Other variables are emitted into the output stream as groups with // `Delimiter::Invisible` to maintain parsing priorities. diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 5521e710d4539..abb7eb3c2febf 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -717,6 +717,43 @@ impl<'a> Parser<'a> { if !self.eat_keyword(kw) { self.unexpected() } else { Ok(()) } } + /// Consume a sequence produced by a metavar expansion, if present. + fn eat_metavar_seq( + &mut self, + mv_kind: MetaVarKind, + f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, + ) -> Option { + self.eat_metavar_seq_with_matcher(|mvk| mvk == mv_kind, f) + } + + /// A slightly more general form of `eat_metavar_seq`, for use with the + /// `MetaVarKind` variants that have parameters, where an exact match isn't + /// desired. + fn eat_metavar_seq_with_matcher( + &mut self, + match_mv_kind: impl Fn(MetaVarKind) -> bool, + mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, + ) -> Option { + if let token::OpenDelim(delim) = self.token.kind + && let Delimiter::Invisible(token::InvisibleOrigin::MetaVar(mv_kind)) = delim + && match_mv_kind(mv_kind) + { + self.bump(); + let res = f(self).expect("failed to reparse {mv_kind:?}"); + if let token::CloseDelim(delim) = self.token.kind + && let Delimiter::Invisible(token::InvisibleOrigin::MetaVar(mv_kind)) = delim + && match_mv_kind(mv_kind) + { + self.bump(); + Some(res) + } else { + panic!("no close delim when reparsing {mv_kind:?}"); + } + } else { + None + } + } + /// Is the given keyword `kw` followed by a non-reserved identifier? fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool { self.token.is_keyword(kw) && self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident()) @@ -1459,7 +1496,11 @@ impl<'a> Parser<'a> { /// so emit a proper diagnostic. // Public for rustfmt usage. pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibility> { - maybe_whole!(self, NtVis, |vis| vis.into_inner()); + if let Some(vis) = self + .eat_metavar_seq(MetaVarKind::Vis, |this| this.parse_visibility(FollowedByType::Yes)) + { + return Ok(vis); + } if !self.eat_keyword(kw::Pub) { // We need a span for our `Spanned`, but there's inherently no @@ -1684,7 +1725,8 @@ pub enum ParseNtResult { Tt(TokenTree), Ident(Ident, IdentIsRaw), Lifetime(Ident, IdentIsRaw), + Vis(P), - /// This case will eventually be removed, along with `Token::Interpolate`. + /// This variant will eventually be removed, along with `Token::Interpolate`. Nt(Lrc), } diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 3d0e2be688596..06b9a25e23a13 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -56,9 +56,7 @@ impl<'a> Parser<'a> { | NtMeta(_) | NtPath(_) => true, - NtItem(_) - | NtBlock(_) - | NtVis(_) => false, + NtItem(_) | NtBlock(_) => false, } } @@ -88,7 +86,7 @@ impl<'a> Parser<'a> { NonterminalKind::Ident => get_macro_ident(token).is_some(), NonterminalKind::Literal => token.can_begin_literal_maybe_minus(), NonterminalKind::Vis => match token.kind { - // The follow-set of :vis + "priv" keyword + interpolated + // The follow-set of :vis + "priv" keyword + interpolated/metavar-expansion. token::Comma | token::Ident(..) | token::NtIdent(..) @@ -102,7 +100,7 @@ impl<'a> Parser<'a> { token::NtLifetime(..) => true, token::Interpolated(nt) => match &**nt { NtBlock(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true, - NtItem(_) | NtPat(_) | NtTy(_) | NtMeta(_) | NtPath(_) | NtVis(_) => false, + NtItem(_) | NtPat(_) | NtTy(_) | NtMeta(_) | NtPath(_) => false, }, token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k { MetaVarKind::Block @@ -208,8 +206,9 @@ impl<'a> Parser<'a> { } NonterminalKind::Meta => NtMeta(P(self.parse_attr_item(ForceCollect::Yes)?)), NonterminalKind::Vis => { - NtVis(P(self - .collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?)) + return Ok(ParseNtResult::Vis(P(self.collect_tokens_no_attrs(|this| { + this.parse_visibility(FollowedByType::Yes) + })?))); } NonterminalKind::Lifetime => { // We want to keep `'keyword` parsing, just like `keyword` is still From 23bb0bf2ab21dcdfe0539e12b21fb25da15009a5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 17 Apr 2024 13:17:44 +1000 Subject: [PATCH 07/18] Remove `NtTy`. Notes about tests: - tests/ui/parser/macro/trait-object-macro-matcher.rs: the syntax error is duplicated, because it occurs now when parsing the decl macro input, and also when parsing the expanded decl macro. But this won't show up for normal users due to error de-duplication. - tests/ui/associated-consts/issue-93835.rs: ditto. - The changes to metavariable descriptions in this PR's earlier commits are now visible in error message for several tests. --- compiler/rustc_ast/src/ast_traits.rs | 2 -- compiler/rustc_ast/src/mut_visit.rs | 1 - compiler/rustc_ast/src/token.rs | 7 +--- compiler/rustc_ast/src/tokenstream.rs | 1 - compiler/rustc_expand/src/mbe/transcribe.rs | 3 ++ compiler/rustc_parse/src/parser/mod.rs | 33 ++++++++++++++++--- .../rustc_parse/src/parser/nonterminal.rs | 7 ++-- compiler/rustc_parse/src/parser/path.rs | 17 +++++----- compiler/rustc_parse/src/parser/ty.rs | 14 +++++--- tests/ui/associated-consts/issue-93835.rs | 1 + tests/ui/associated-consts/issue-93835.stderr | 13 +++++++- tests/ui/macros/macro-interpolation.rs | 2 +- tests/ui/macros/macro-interpolation.stderr | 4 +-- tests/ui/macros/syntax-error-recovery.rs | 4 +-- tests/ui/macros/syntax-error-recovery.stderr | 4 +-- tests/ui/parser/macro/issue-37113.rs | 2 +- tests/ui/parser/macro/issue-37113.stderr | 4 +-- .../macro/trait-object-macro-matcher.rs | 1 + .../macro/trait-object-macro-matcher.stderr | 10 +++++- 19 files changed, 88 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index a2923d6448ae9..346edc87c86bc 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -203,7 +203,6 @@ impl HasTokens for Nonterminal { Nonterminal::NtStmt(stmt) => stmt.tokens(), Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens(), Nonterminal::NtPat(pat) => pat.tokens(), - Nonterminal::NtTy(ty) => ty.tokens(), Nonterminal::NtMeta(attr_item) => attr_item.tokens(), Nonterminal::NtPath(path) => path.tokens(), Nonterminal::NtBlock(block) => block.tokens(), @@ -215,7 +214,6 @@ impl HasTokens for Nonterminal { Nonterminal::NtStmt(stmt) => stmt.tokens_mut(), Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(), Nonterminal::NtPat(pat) => pat.tokens_mut(), - Nonterminal::NtTy(ty) => ty.tokens_mut(), Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(), Nonterminal::NtPath(path) => path.tokens_mut(), Nonterminal::NtBlock(block) => block.tokens_mut(), diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 8acc31a7e540c..5195c48609193 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -815,7 +815,6 @@ fn visit_nonterminal(vis: &mut T, nt: &mut token::Nonterminal) { }), token::NtPat(pat) => vis.visit_pat(pat), token::NtExpr(expr) => vis.visit_expr(expr), - token::NtTy(ty) => vis.visit_ty(ty), token::NtLiteral(expr) => vis.visit_expr(expr), token::NtMeta(item) => { let AttrItem { unsafety: _, path, args, tokens } = item.deref_mut(); diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 0244747039ada..c283ba3f2e4f3 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -654,7 +654,6 @@ impl Token { | NtMeta(..) | NtPat(..) | NtPath(..) - | NtTy(..) ), OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( MetaVarKind::Expr { .. } | @@ -683,7 +682,7 @@ impl Token { Lifetime(..) | // lifetime bound in trait object Lt | BinOp(Shl) | // associated path PathSep => true, // global path - Interpolated(ref nt) => matches!(&**nt, NtTy(..) | NtPath(..)), + Interpolated(ref nt) => matches!(&**nt, NtPath(..)), OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( MetaVarKind::Ty | MetaVarKind::Path @@ -1064,7 +1063,6 @@ pub enum Nonterminal { NtStmt(P), NtPat(P), NtExpr(P), - NtTy(P), NtLiteral(P), /// Stuff inside brackets for attributes NtMeta(P), @@ -1162,7 +1160,6 @@ impl Nonterminal { NtStmt(stmt) => stmt.span, NtPat(pat) => pat.span, NtExpr(expr) | NtLiteral(expr) => expr.span, - NtTy(ty) => ty.span, NtMeta(attr_item) => attr_item.span(), NtPath(path) => path.span, } @@ -1176,7 +1173,6 @@ impl Nonterminal { NtPat(..) => "pattern", NtExpr(..) => "expression", NtLiteral(..) => "literal", - NtTy(..) => "type", NtMeta(..) => "attribute", NtPath(..) => "path", } @@ -1201,7 +1197,6 @@ impl fmt::Debug for Nonterminal { NtStmt(..) => f.pad("NtStmt(..)"), NtPat(..) => f.pad("NtPat(..)"), NtExpr(..) => f.pad("NtExpr(..)"), - NtTy(..) => f.pad("NtTy(..)"), NtLiteral(..) => f.pad("NtLiteral(..)"), NtMeta(..) => f.pad("NtMeta(..)"), NtPath(..) => f.pad("NtPath(..)"), diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index c03c9557a3f4b..fc371ca31e163 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -469,7 +469,6 @@ impl TokenStream { } Nonterminal::NtStmt(stmt) => TokenStream::from_ast(stmt), Nonterminal::NtPat(pat) => TokenStream::from_ast(pat), - Nonterminal::NtTy(ty) => TokenStream::from_ast(ty), Nonterminal::NtMeta(attr) => TokenStream::from_ast(attr), Nonterminal::NtPath(path) => TokenStream::from_ast(path), Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => TokenStream::from_ast(expr), diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 80e9841f1ffdf..525440a0a8c20 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -303,6 +303,9 @@ pub(super) fn transcribe<'a>( let kind = token::NtLifetime(*ident, *is_raw); TokenTree::token_alone(kind, sp) } + MatchedSingle(ParseNtResult::Ty(ty)) => { + mk_delimited(MetaVarKind::Ty, TokenStream::from_ast(ty)) + } MatchedSingle(ParseNtResult::Vis(vis)) => { mk_delimited(MetaVarKind::Vis, TokenStream::from_ast(vis)) } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index abb7eb3c2febf..f9b874b768a38 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -116,12 +116,16 @@ macro_rules! maybe_recover_from_interpolated_ty_qpath { ($self: expr, $allow_qpath_recovery: expr) => { if $allow_qpath_recovery && $self.may_recover() - && $self.look_ahead(1, |t| t == &token::PathSep) - && let token::Interpolated(nt) = &$self.token.kind - && let token::NtTy(ty) = &**nt + && let Some(token::MetaVarKind::Ty) = $self.token.is_metavar_seq() + && $self.check_noexpect_past_close_delim(&token::PathSep) { - let ty = ty.clone(); - $self.bump(); + // Reparse the type, then move to recovery. + let ty = $self + .eat_metavar_seq(token::MetaVarKind::Ty, |this| { + this.parse_ty_no_question_mark_recover() + }) + .expect("metavar seq ty"); + return $self.maybe_recover_from_bad_qpath_stage_2($self.prev_token.span, ty); } }; @@ -609,6 +613,24 @@ impl<'a> Parser<'a> { self.token == *tok } + // Check the first token after the delimiter that closes the current + // delimited sequence. (Panics if used in the outermost token stream, which + // has no delimiters.) It uses a clone of the relevant tree cursor to skip + // past the entire `TokenTree::Delimited` in a single step, avoiding the + // need for unbounded token lookahead. + // + // Primarily used when `self.token` matches + // `OpenDelim(Delimiter::Invisible(_))`, to look ahead through the current + // metavar expansion. + fn check_noexpect_past_close_delim(&self, tok: &TokenKind) -> bool { + let mut tree_cursor = self.token_cursor.stack.last().unwrap().0.clone(); + let tt = tree_cursor.next_ref(); + matches!( + tt, + Some(ast::tokenstream::TokenTree::Token(token::Token { kind, .. }, _)) if kind == tok + ) + } + /// Consumes a token 'tok' if it exists. Returns whether the given token was present. /// /// the main purpose of this function is to reduce the cluttering of the suggestions list @@ -1725,6 +1747,7 @@ pub enum ParseNtResult { Tt(TokenTree), Ident(Ident, IdentIsRaw), Lifetime(Ident, IdentIsRaw), + Ty(P), Vis(P), /// This variant will eventually be removed, along with `Token::Interpolate`. diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 06b9a25e23a13..62c28e3c6bf89 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -51,7 +51,6 @@ impl<'a> Parser<'a> { NtStmt(_) | NtPat(_) | NtExpr(_) - | NtTy(_) | NtLiteral(_) // `true`, `false` | NtMeta(_) | NtPath(_) => true, @@ -100,7 +99,7 @@ impl<'a> Parser<'a> { token::NtLifetime(..) => true, token::Interpolated(nt) => match &**nt { NtBlock(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true, - NtItem(_) | NtPat(_) | NtTy(_) | NtMeta(_) | NtPath(_) => false, + NtItem(_) | NtPat(_) | NtMeta(_) | NtPath(_) => false, }, token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k { MetaVarKind::Block @@ -187,7 +186,9 @@ impl<'a> Parser<'a> { NtLiteral(self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?) } NonterminalKind::Ty => { - NtTy(self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?) + return Ok(ParseNtResult::Ty( + self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?, + )); } // this could be handled like a token, since it is one NonterminalKind::Ident => { diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 42039c621d63c..07d2d16750613 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -2,7 +2,7 @@ use std::mem; use ast::token::IdentIsRaw; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, Token, TokenKind}; +use rustc_ast::token::{self, Delimiter, MetaVarKind, Token, TokenKind}; use rustc_ast::{ self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemConstraint, AssocItemConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs, @@ -197,13 +197,14 @@ impl<'a> Parser<'a> { maybe_whole!(self, NtPath, |path| reject_generics_if_mod_style(self, path.into_inner())); - 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(); - return Ok(reject_generics_if_mod_style(self, path)); - } + if let Some(MetaVarKind::Ty) = self.token.is_metavar_seq() { + let mut snapshot = self.create_snapshot_for_diagnostic(); + let ty = snapshot + .eat_metavar_seq(MetaVarKind::Ty, |this| this.parse_ty_no_question_mark_recover()) + .expect("metavar seq ty"); + if let ast::TyKind::Path(None, path) = ty.into_inner().kind { + self.restore_snapshot(snapshot); + return Ok(reject_generics_if_mod_style(self, path)); } } diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index dd1cc75c7fff9..9d1e2a9581320 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -1,5 +1,5 @@ use rustc_ast::ptr::P; -use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, Token, TokenKind}; +use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, MetaVarKind, Token, TokenKind}; use rustc_ast::util::case::Case; use rustc_ast::{ self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, FnRetTy, GenericBound, @@ -18,7 +18,7 @@ use crate::errors::{ HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, NestedCVariadicType, ReturnTypesUseThinArrow, }; -use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; +use crate::maybe_recover_from_interpolated_ty_qpath; /// Signals whether parsing a type should allow `+`. /// @@ -194,7 +194,8 @@ impl<'a> Parser<'a> { ) } - /// Parse a type without recovering `:` as `->` to avoid breaking code such as `where fn() : for<'a>` + /// Parse a type without recovering `:` as `->` to avoid breaking code such + /// as `where fn() : for<'a>`. pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, P> { self.parse_ty_common( AllowPlus::Yes, @@ -258,7 +259,12 @@ impl<'a> Parser<'a> { ) -> PResult<'a, P> { let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes; maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery); - maybe_whole!(self, NtTy, |ty| ty); + + if let Some(ty) = + self.eat_metavar_seq(MetaVarKind::Ty, |this| this.parse_ty_no_question_mark_recover()) + { + return Ok(ty); + } let lo = self.token.span; let mut impl_dyn_multi = false; diff --git a/tests/ui/associated-consts/issue-93835.rs b/tests/ui/associated-consts/issue-93835.rs index 9cc33d53f9cd5..c8b0990d0f0fa 100644 --- a/tests/ui/associated-consts/issue-93835.rs +++ b/tests/ui/associated-consts/issue-93835.rs @@ -5,6 +5,7 @@ fn e() { //~^ ERROR cannot find type `a` in this scope //~| ERROR cannot find value //~| ERROR associated const equality + //~| ERROR associated const equality //~| ERROR cannot find trait `p` in this scope } diff --git a/tests/ui/associated-consts/issue-93835.stderr b/tests/ui/associated-consts/issue-93835.stderr index dfe78b3d1f380..551b50d0eb6b5 100644 --- a/tests/ui/associated-consts/issue-93835.stderr +++ b/tests/ui/associated-consts/issue-93835.stderr @@ -26,7 +26,18 @@ LL | type_ascribe!(p, a>); = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 4 previous errors +error[E0658]: associated const equality is incomplete + --> $DIR/issue-93835.rs:4:28 + | +LL | type_ascribe!(p, a>); + | ^^^ + | + = note: see issue #92827 for more information + = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 5 previous errors Some errors have detailed explanations: E0405, E0412, E0425, E0658. For more information about an error, try `rustc --explain E0405`. diff --git a/tests/ui/macros/macro-interpolation.rs b/tests/ui/macros/macro-interpolation.rs index 48c1f19e777f7..b5d2322c8052c 100644 --- a/tests/ui/macros/macro-interpolation.rs +++ b/tests/ui/macros/macro-interpolation.rs @@ -19,7 +19,7 @@ macro_rules! qpath { (ty, <$type:ty as $trait:ty>::$name:ident) => { <$type as $trait>::$name - //~^ ERROR expected identifier, found `!` + //~^ ERROR expected identifier, found metavariable }; } diff --git a/tests/ui/macros/macro-interpolation.stderr b/tests/ui/macros/macro-interpolation.stderr index e6b39dfef8581..bc24a15861295 100644 --- a/tests/ui/macros/macro-interpolation.stderr +++ b/tests/ui/macros/macro-interpolation.stderr @@ -1,8 +1,8 @@ -error: expected identifier, found `!` +error: expected identifier, found metavariable --> $DIR/macro-interpolation.rs:21:19 | LL | <$type as $trait>::$name - | ^^^^^^ expected identifier + | ^^^^^^ expected identifier, found metavariable ... LL | let _: qpath!(ty, ::Owned); | ----------------------------- diff --git a/tests/ui/macros/syntax-error-recovery.rs b/tests/ui/macros/syntax-error-recovery.rs index 016e4def28497..6cf9d54e82636 100644 --- a/tests/ui/macros/syntax-error-recovery.rs +++ b/tests/ui/macros/syntax-error-recovery.rs @@ -9,8 +9,8 @@ macro_rules! values { } }; } -//~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found type `(String)` -//~| ERROR macro expansion ignores type `(String)` and any tokens following +//~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `ty` metavariable +//~| ERROR macro expansion ignores `ty` metavariable and any tokens following values!(STRING(1) as (String) => cfg(test),); //~^ ERROR expected one of `!` or `::`, found `` diff --git a/tests/ui/macros/syntax-error-recovery.stderr b/tests/ui/macros/syntax-error-recovery.stderr index 3cfbd8ce82b56..61758fb9d7dc6 100644 --- a/tests/ui/macros/syntax-error-recovery.stderr +++ b/tests/ui/macros/syntax-error-recovery.stderr @@ -1,4 +1,4 @@ -error: expected one of `(`, `,`, `=`, `{`, or `}`, found type `(String)` +error: expected one of `(`, `,`, `=`, `{`, or `}`, found `ty` metavariable --> $DIR/syntax-error-recovery.rs:7:26 | LL | $token $($inner)? = $value, @@ -10,7 +10,7 @@ LL | values!(STRING(1) as (String) => cfg(test),); = help: enum variants can be `Variant`, `Variant = `, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` = note: this error originates in the macro `values` (in Nightly builds, run with -Z macro-backtrace for more info) -error: macro expansion ignores type `(String)` and any tokens following +error: macro expansion ignores `ty` metavariable and any tokens following --> $DIR/syntax-error-recovery.rs:7:26 | LL | $token $($inner)? = $value, diff --git a/tests/ui/parser/macro/issue-37113.rs b/tests/ui/parser/macro/issue-37113.rs index 0044aa5610f5f..e0957542f8f19 100644 --- a/tests/ui/parser/macro/issue-37113.rs +++ b/tests/ui/parser/macro/issue-37113.rs @@ -1,7 +1,7 @@ macro_rules! test_macro { ( $( $t:ty ),* $(),*) => { enum SomeEnum { - $( $t, )* //~ ERROR expected identifier, found `String` + $( $t, )* //~ ERROR expected identifier, found metavariable }; }; } diff --git a/tests/ui/parser/macro/issue-37113.stderr b/tests/ui/parser/macro/issue-37113.stderr index 1f2fe23106ae3..560329df5ccbd 100644 --- a/tests/ui/parser/macro/issue-37113.stderr +++ b/tests/ui/parser/macro/issue-37113.stderr @@ -1,10 +1,10 @@ -error: expected identifier, found `String` +error: expected identifier, found metavariable --> $DIR/issue-37113.rs:4:16 | LL | enum SomeEnum { | -------- while parsing this enum LL | $( $t, )* - | ^^ expected identifier + | ^^ expected identifier, found metavariable ... LL | test_macro!(String,); | -------------------- in this macro invocation diff --git a/tests/ui/parser/macro/trait-object-macro-matcher.rs b/tests/ui/parser/macro/trait-object-macro-matcher.rs index 560195977d03a..d4ec199070e7c 100644 --- a/tests/ui/parser/macro/trait-object-macro-matcher.rs +++ b/tests/ui/parser/macro/trait-object-macro-matcher.rs @@ -10,5 +10,6 @@ macro_rules! m { fn main() { m!('static); //~^ ERROR lifetime in trait object type must be followed by `+` + //~| ERROR lifetime in trait object type must be followed by `+` //~| ERROR at least one trait is required for an object type } diff --git a/tests/ui/parser/macro/trait-object-macro-matcher.stderr b/tests/ui/parser/macro/trait-object-macro-matcher.stderr index 40082564bad4c..81dca6f71c436 100644 --- a/tests/ui/parser/macro/trait-object-macro-matcher.stderr +++ b/tests/ui/parser/macro/trait-object-macro-matcher.stderr @@ -4,12 +4,20 @@ error: lifetime in trait object type must be followed by `+` LL | m!('static); | ^^^^^^^ +error: lifetime in trait object type must be followed by `+` + --> $DIR/trait-object-macro-matcher.rs:11:8 + | +LL | m!('static); + | ^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error[E0224]: at least one trait is required for an object type --> $DIR/trait-object-macro-matcher.rs:11:8 | LL | m!('static); | ^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0224`. From e97c945f473fdef93ca5eef6f46fc4e3892c0fb1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 18 Apr 2024 12:44:11 +1000 Subject: [PATCH 08/18] Remove `NtPat`. The one notable test change is `tests/ui/macros/trace_faulty_macros.rs`. This commit removes the complicated `Interpolated` handling in `expected_expression_found` that results in a longer error message. But I think the new, shorter message is actually an improvement. The original complaint was in #71039, when the error message started with "error: expected expression, found `1 + 1`". That was confusing because `1 + 1` is an expression. Other than that, the reporter said "the whole error message is not too bad if you ignore the first line". Subsequently, extra complexity and wording was added to the error message. But I don't think the extra wording actually helps all that much. In particular, it still says of the `1+1` that "this is expected to be expression". This repeats the problem from the original complaint! This commit removes the extra complexity, reverting to a simpler error message. This is primarily because the traversal a pain without `Interpolated` tokens. Nonetheless, I think the error message is *improved*. It now starts with "expected expression, found `pat` metavariable", which is much clearer and the real problem. It also doesn't say anything specific about `1+1`, which is good, because the `1+1` isn't really relevant to the error -- it's the `$e:pat` that's important. --- compiler/rustc_ast/src/ast_traits.rs | 2 - compiler/rustc_ast/src/mut_visit.rs | 1 - compiler/rustc_ast/src/token.rs | 5 -- compiler/rustc_ast/src/tokenstream.rs | 1 - compiler/rustc_expand/src/mbe/transcribe.rs | 3 ++ .../rustc_parse/src/parser/diagnostics.rs | 51 +------------------ compiler/rustc_parse/src/parser/item.rs | 8 +-- compiler/rustc_parse/src/parser/mod.rs | 4 +- .../rustc_parse/src/parser/nonterminal.rs | 24 +++++---- compiler/rustc_parse/src/parser/pat.rs | 37 +++++++++++--- tests/ui/macros/trace_faulty_macros.rs | 2 +- tests/ui/macros/trace_faulty_macros.stderr | 13 ++--- .../issue-65122-mac-invoc-in-mut-patterns.rs | 2 +- ...sue-65122-mac-invoc-in-mut-patterns.stderr | 4 +- tests/ui/parser/mut-patterns.rs | 2 +- tests/ui/parser/mut-patterns.stderr | 4 +- 16 files changed, 66 insertions(+), 97 deletions(-) diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 346edc87c86bc..8b94d65c44ecb 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -202,7 +202,6 @@ impl HasTokens for Nonterminal { Nonterminal::NtItem(item) => item.tokens(), Nonterminal::NtStmt(stmt) => stmt.tokens(), Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens(), - Nonterminal::NtPat(pat) => pat.tokens(), Nonterminal::NtMeta(attr_item) => attr_item.tokens(), Nonterminal::NtPath(path) => path.tokens(), Nonterminal::NtBlock(block) => block.tokens(), @@ -213,7 +212,6 @@ impl HasTokens for Nonterminal { Nonterminal::NtItem(item) => item.tokens_mut(), Nonterminal::NtStmt(stmt) => stmt.tokens_mut(), Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(), - Nonterminal::NtPat(pat) => pat.tokens_mut(), Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(), Nonterminal::NtPath(path) => path.tokens_mut(), Nonterminal::NtBlock(block) => block.tokens_mut(), diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 5195c48609193..04b9931c0e8b2 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -813,7 +813,6 @@ fn visit_nonterminal(vis: &mut T, nt: &mut token::Nonterminal) { vis.flat_map_stmt(stmt).expect_one("expected visitor to produce exactly one item") }) }), - token::NtPat(pat) => vis.visit_pat(pat), token::NtExpr(expr) => vis.visit_expr(expr), token::NtLiteral(expr) => vis.visit_expr(expr), token::NtMeta(item) => { diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index c283ba3f2e4f3..47d72b9bd09d3 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -652,7 +652,6 @@ impl Token { | NtExpr(..) | NtLiteral(..) | NtMeta(..) - | NtPat(..) | NtPath(..) ), OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( @@ -1061,7 +1060,6 @@ pub enum Nonterminal { NtItem(P), NtBlock(P), NtStmt(P), - NtPat(P), NtExpr(P), NtLiteral(P), /// Stuff inside brackets for attributes @@ -1158,7 +1156,6 @@ impl Nonterminal { NtItem(item) => item.span, NtBlock(block) => block.span, NtStmt(stmt) => stmt.span, - NtPat(pat) => pat.span, NtExpr(expr) | NtLiteral(expr) => expr.span, NtMeta(attr_item) => attr_item.span(), NtPath(path) => path.span, @@ -1170,7 +1167,6 @@ impl Nonterminal { NtItem(..) => "item", NtBlock(..) => "block", NtStmt(..) => "statement", - NtPat(..) => "pattern", NtExpr(..) => "expression", NtLiteral(..) => "literal", NtMeta(..) => "attribute", @@ -1195,7 +1191,6 @@ impl fmt::Debug for Nonterminal { NtItem(..) => f.pad("NtItem(..)"), NtBlock(..) => f.pad("NtBlock(..)"), NtStmt(..) => f.pad("NtStmt(..)"), - NtPat(..) => f.pad("NtPat(..)"), NtExpr(..) => f.pad("NtExpr(..)"), NtLiteral(..) => f.pad("NtLiteral(..)"), NtMeta(..) => f.pad("NtMeta(..)"), diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index fc371ca31e163..fb3276cb3c053 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -468,7 +468,6 @@ impl TokenStream { TokenStream::token_alone(token::Semi, stmt.span) } Nonterminal::NtStmt(stmt) => TokenStream::from_ast(stmt), - Nonterminal::NtPat(pat) => TokenStream::from_ast(pat), Nonterminal::NtMeta(attr) => TokenStream::from_ast(attr), Nonterminal::NtPath(path) => TokenStream::from_ast(path), Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => TokenStream::from_ast(expr), diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 525440a0a8c20..82009a7fef535 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -303,6 +303,9 @@ pub(super) fn transcribe<'a>( let kind = token::NtLifetime(*ident, *is_raw); TokenTree::token_alone(kind, sp) } + MatchedSingle(ParseNtResult::Pat(pat, pat_kind)) => { + mk_delimited(MetaVarKind::Pat(*pat_kind), TokenStream::from_ast(pat)) + } MatchedSingle(ParseNtResult::Ty(ty)) => { mk_delimited(MetaVarKind::Ty, TokenStream::from_ast(ty)) } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index bee73c58cb794..ff904d9237d25 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -5,12 +5,11 @@ use ast::token::IdentIsRaw; use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Lit, LitKind, Token, TokenKind}; -use rustc_ast::tokenstream::AttrTokenTree; use rustc_ast::util::parser::AssocOp; use rustc_ast::{ AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block, - BlockCheckMode, Expr, ExprKind, GenericArg, Generics, HasTokens, Item, ItemKind, Param, Pat, - PatKind, Path, PathSegment, QSelf, Recovered, Ty, TyKind, + BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Param, Pat, PatKind, + Path, PathSegment, QSelf, Recovered, Ty, TyKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; @@ -2426,52 +2425,6 @@ impl<'a> Parser<'a> { err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); } err.span_label(span, "expected expression"); - - // Walk the chain of macro expansions for the current token to point at how the original - // code was interpreted. This helps the user realize when a macro argument of one type is - // later reinterpreted as a different type, like `$x:expr` being reinterpreted as `$x:pat` - // in a subsequent macro invocation (#71039). - let mut tok = self.token.clone(); - let mut labels = vec![]; - while let TokenKind::Interpolated(nt) = &tok.kind { - let tokens = nt.tokens(); - labels.push(nt.clone()); - if let Some(tokens) = tokens - && let tokens = tokens.to_attr_token_stream() - && let tokens = tokens.0.deref() - && let [AttrTokenTree::Token(token, _)] = &tokens[..] - { - tok = token.clone(); - } else { - break; - } - } - let mut iter = labels.into_iter().peekable(); - let mut show_link = false; - while let Some(nt) = iter.next() { - let descr = nt.descr(); - if let Some(next) = iter.peek() { - let next_descr = next.descr(); - if next_descr != descr { - err.span_label(next.use_span(), format!("this is expected to be {next_descr}")); - err.span_label( - nt.use_span(), - format!( - "this is interpreted as {}, but it is expected to be {}", - next_descr, descr, - ), - ); - show_link = true; - } - } - } - if show_link { - err.note( - "when forwarding a matched fragment to another macro-by-example, matchers in the \ - second macro will see an opaque AST of the fragment type, not the underlying \ - tokens", - ); - } err } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 104678e081c30..8b2fe72bfff80 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -4,7 +4,7 @@ use std::mem; use ast::token::IdentIsRaw; use rustc_ast::ast::*; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, TokenKind}; +use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast::util::case::Case; use rustc_ast::{self as ast}; @@ -2976,8 +2976,10 @@ impl<'a> Parser<'a> { fn is_named_param(&self) -> bool { let offset = match &self.token.kind { - token::Interpolated(nt) => match &**nt { - token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon), + token::OpenDelim(Delimiter::Invisible(origin)) => match origin { + InvisibleOrigin::MetaVar(MetaVarKind::Pat(_)) => { + return self.check_noexpect_past_close_delim(&token::Colon); + } _ => 0, }, token::BinOp(token::And) | token::AndAnd => 1, diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index f9b874b768a38..4231c517a868d 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -22,7 +22,8 @@ pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; use path::PathStyle; use rustc_ast::ptr::P; use rustc_ast::token::{ - self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, Nonterminal, Token, TokenKind, + self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, Nonterminal, NtPatKind, Token, + TokenKind, }; use rustc_ast::tokenstream::{ AttrsTarget, DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree, TokenTreeCursor, @@ -1747,6 +1748,7 @@ pub enum ParseNtResult { Tt(TokenTree), Ident(Ident, IdentIsRaw), Lifetime(Ident, IdentIsRaw), + Pat(P, NtPatKind), Ty(P), Vis(P), diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 62c28e3c6bf89..43f6d626f9e9d 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -49,7 +49,6 @@ impl<'a> Parser<'a> { fn nt_may_be_ident(nt: &Nonterminal) -> bool { match nt { NtStmt(_) - | NtPat(_) | NtExpr(_) | NtLiteral(_) // `true`, `false` | NtMeta(_) @@ -99,7 +98,7 @@ impl<'a> Parser<'a> { token::NtLifetime(..) => true, token::Interpolated(nt) => match &**nt { NtBlock(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true, - NtItem(_) | NtPat(_) | NtMeta(_) | NtPath(_) => false, + NtItem(_) | NtMeta(_) | NtPath(_) => false, }, token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k { MetaVarKind::Block @@ -170,15 +169,18 @@ impl<'a> Parser<'a> { } }, NonterminalKind::Pat(pat_kind) => { - NtPat(self.collect_tokens_no_attrs(|this| match pat_kind { - PatParam { .. } => this.parse_pat_no_top_alt(None, None), - PatWithOr => this.parse_pat_allow_top_alt( - None, - RecoverComma::No, - RecoverColon::No, - CommaRecoveryMode::EitherTupleOrPipe, - ), - })?) + return Ok(ParseNtResult::Pat( + self.collect_tokens_no_attrs(|this| match pat_kind { + PatParam { .. } => this.parse_pat_no_top_alt(None, None), + PatWithOr => this.parse_pat_allow_top_alt( + None, + RecoverComma::No, + RecoverColon::No, + CommaRecoveryMode::EitherTupleOrPipe, + ), + })?, + pat_kind, + )); } NonterminalKind::Expr(_) => NtExpr(self.parse_expr_force_collect()?), NonterminalKind::Literal => { diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index daced411b8fe2..018a230279c0e 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1,6 +1,7 @@ use rustc_ast::mut_visit::{walk_pat, MutVisitor}; use rustc_ast::ptr::P; -use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, Token}; +use rustc_ast::token::NtPatKind::*; +use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, MetaVarKind, Token}; use rustc_ast::{ self as ast, AttrVec, BindingMode, ByRef, Expr, ExprKind, MacCall, Mutability, Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, @@ -25,8 +26,8 @@ use crate::errors::{ UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, WrapInParens, }; +use crate::maybe_recover_from_interpolated_ty_qpath; use crate::parser::expr::could_be_unclosed_char_literal; -use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; #[derive(PartialEq, Copy, Clone)] pub enum Expected { @@ -431,6 +432,27 @@ impl<'a> Parser<'a> { None } + fn eat_metavar_pat(&mut self) -> Option> { + // Must try both kinds of pattern nonterminals. + if let Some(pat) = self.eat_metavar_seq_with_matcher( + |mv_kind| matches!(mv_kind, MetaVarKind::Pat(PatParam { .. })), + |this| this.parse_pat_no_top_alt(None, None), + ) { + Some(pat) + } else if let Some(pat) = self.eat_metavar_seq(MetaVarKind::Pat(PatWithOr), |this| { + this.parse_pat_allow_top_alt( + None, + RecoverComma::No, + RecoverColon::No, + CommaRecoveryMode::EitherTupleOrPipe, + ) + }) { + Some(pat) + } else { + None + } + } + /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are /// allowed). fn parse_pat_with_range_pat( @@ -440,7 +462,10 @@ impl<'a> Parser<'a> { syntax_loc: Option, ) -> PResult<'a, P> { maybe_recover_from_interpolated_ty_qpath!(self, true); - maybe_whole!(self, NtPat, |pat| pat); + + if let Some(pat) = self.eat_metavar_pat() { + return Ok(pat); + } let mut lo = self.token.span; @@ -776,10 +801,8 @@ impl<'a> Parser<'a> { self.recover_additional_muts(); // Make sure we don't allow e.g. `let mut $p;` where `$p:pat`. - if let token::Interpolated(nt) = &self.token.kind { - if let token::NtPat(..) = &**nt { - self.expected_ident_found_err().emit(); - } + if let Some(MetaVarKind::Pat(_)) = self.token.is_metavar_seq() { + self.expected_ident_found_err().emit(); } // Parse the pattern we hope to be an identifier. diff --git a/tests/ui/macros/trace_faulty_macros.rs b/tests/ui/macros/trace_faulty_macros.rs index 87036bb9c6f75..e0cbbd8f5c9e6 100644 --- a/tests/ui/macros/trace_faulty_macros.rs +++ b/tests/ui/macros/trace_faulty_macros.rs @@ -46,7 +46,7 @@ macro_rules! test { (let $p:pat = $e:expr) => {test!(($p,$e))}; // this should be expr // vvv - (($p:pat, $e:pat)) => {let $p = $e;}; //~ ERROR expected expression, found pattern `1+1` + (($p:pat, $e:pat)) => {let $p = $e;}; //~ ERROR expected expression, found `pat` metavariable } fn foo() { diff --git a/tests/ui/macros/trace_faulty_macros.stderr b/tests/ui/macros/trace_faulty_macros.stderr index 10ad3faab1612..73fed66e61906 100644 --- a/tests/ui/macros/trace_faulty_macros.stderr +++ b/tests/ui/macros/trace_faulty_macros.stderr @@ -50,7 +50,7 @@ LL | my_recursive_macro!(); = note: expanding `my_recursive_macro! { }` = note: to `my_recursive_macro! ();` -error: expected expression, found pattern `A { a : a, b : 0, c : _, .. }` +error: expected expression, found `pat` metavariable --> $DIR/trace_faulty_macros.rs:16:9 | LL | $a @@ -69,22 +69,15 @@ LL | #[derive(Debug)] LL | fn use_derive_macro_as_attr() {} | -------------------------------- not a `struct`, `enum` or `union` -error: expected expression, found pattern `1+1` +error: expected expression, found `pat` metavariable --> $DIR/trace_faulty_macros.rs:49:37 | -LL | (let $p:pat = $e:expr) => {test!(($p,$e))}; - | -- this is interpreted as expression, but it is expected to be pattern -... LL | (($p:pat, $e:pat)) => {let $p = $e;}; | ^^ expected expression ... LL | test!(let x = 1+1); - | ------------------ - | | | - | | this is expected to be expression - | in this macro invocation + | ------------------ in this macro invocation | - = note: when forwarding a matched fragment to another macro-by-example, matchers in the second macro will see an opaque AST of the fragment type, not the underlying tokens = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) note: trace_macro diff --git a/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.rs b/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.rs index 30f3781bf7743..1a0833ebb2f61 100644 --- a/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.rs +++ b/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.rs @@ -12,7 +12,7 @@ macro_rules! mac2 { ($eval:pat) => { let mut $eval = (); //~^ ERROR `mut` must be followed by a named binding - //~| ERROR expected identifier, found `does_not_exist!()` + //~| ERROR expected identifier, found metavariable }; } diff --git a/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr b/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr index 76259b40a9332..aec054c205c37 100644 --- a/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr +++ b/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr @@ -15,11 +15,11 @@ LL - let mut $eval = (); LL + let $eval = (); | -error: expected identifier, found `does_not_exist!()` +error: expected identifier, found metavariable --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:13:17 | LL | let mut $eval = (); - | ^^^^^ expected identifier + | ^^^^^ expected identifier, found metavariable ... LL | mac2! { does_not_exist!() } | --------------------------- in this macro invocation diff --git a/tests/ui/parser/mut-patterns.rs b/tests/ui/parser/mut-patterns.rs index b8610c4e19050..8b0a2d99ea96c 100644 --- a/tests/ui/parser/mut-patterns.rs +++ b/tests/ui/parser/mut-patterns.rs @@ -41,7 +41,7 @@ pub fn main() { // Make sure we don't accidentally allow `mut $p` where `$p:pat`. macro_rules! foo { ($p:pat) => { - let mut $p = 0; //~ ERROR expected identifier, found `x` + let mut $p = 0; //~ ERROR expected identifier, found metavariable } } foo!(x); diff --git a/tests/ui/parser/mut-patterns.stderr b/tests/ui/parser/mut-patterns.stderr index f4f11b88d3615..59cbe01c47894 100644 --- a/tests/ui/parser/mut-patterns.stderr +++ b/tests/ui/parser/mut-patterns.stderr @@ -142,11 +142,11 @@ help: add `mut` to each binding LL | let W(mut a, W(mut b, W(ref c, W(mut d, B { box mut f })))) | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -error: expected identifier, found `x` +error: expected identifier, found metavariable --> $DIR/mut-patterns.rs:44:21 | LL | let mut $p = 0; - | ^^ expected identifier + | ^^ expected identifier, found metavariable ... LL | foo!(x); | ------- in this macro invocation From 1317750d70e472f4bc271371ef90bb28425262b7 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 18 Apr 2024 14:53:52 +1000 Subject: [PATCH 09/18] Remove `NtItem` and `NtStmt`. This involves replacing `nt_pretty_printing_compatibility_hack` with `stream_pretty_printing_compatibility_hack`. The handling of statements in `transcribe` is slightly different to other nonterminal kinds, due to the lack of `from_ast` implementation for empty statements. Notable test changes: - `tests/ui/proc-macro/expand-to-derive.rs`: the diff looks large but the only difference is the insertion of a single invisible-delimited group around a metavar. --- compiler/rustc_ast/src/ast_traits.rs | 4 - compiler/rustc_ast/src/mut_visit.rs | 12 --- compiler/rustc_ast/src/token.rs | 8 -- compiler/rustc_ast/src/tokenstream.rs | 8 +- compiler/rustc_builtin_macros/src/cfg_eval.rs | 2 +- compiler/rustc_expand/src/base.rs | 49 ++++++++---- compiler/rustc_expand/src/mbe/transcribe.rs | 14 +++- compiler/rustc_expand/src/proc_macro.rs | 2 +- .../rustc_expand/src/proc_macro_server.rs | 31 ++++--- compiler/rustc_parse/src/parser/expr.rs | 2 +- compiler/rustc_parse/src/parser/item.rs | 14 ++-- compiler/rustc_parse/src/parser/mod.rs | 12 ++- .../rustc_parse/src/parser/nonterminal.rs | 13 ++- compiler/rustc_parse/src/parser/stmt.rs | 46 ++++++++--- tests/ui/macros/nonterminal-matching.rs | 4 +- tests/ui/macros/nonterminal-matching.stderr | 6 +- tests/ui/proc-macro/expand-to-derive.stdout | 80 ++++++++++--------- 17 files changed, 173 insertions(+), 134 deletions(-) diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 8b94d65c44ecb..26ae64a4b6886 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -199,8 +199,6 @@ impl HasTokens for Attribute { impl HasTokens for Nonterminal { fn tokens(&self) -> Option<&LazyAttrTokenStream> { match self { - Nonterminal::NtItem(item) => item.tokens(), - Nonterminal::NtStmt(stmt) => stmt.tokens(), Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens(), Nonterminal::NtMeta(attr_item) => attr_item.tokens(), Nonterminal::NtPath(path) => path.tokens(), @@ -209,8 +207,6 @@ impl HasTokens for Nonterminal { } fn tokens_mut(&mut self) -> Option<&mut Option> { match self { - Nonterminal::NtItem(item) => item.tokens_mut(), - Nonterminal::NtStmt(stmt) => stmt.tokens_mut(), Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(), Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(), Nonterminal::NtPath(path) => path.tokens_mut(), diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 04b9931c0e8b2..d3538dd77a0cc 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -800,19 +800,7 @@ pub fn visit_token(vis: &mut T, t: &mut Token) { // multiple items there.... fn visit_nonterminal(vis: &mut T, nt: &mut token::Nonterminal) { match nt { - token::NtItem(item) => visit_clobber(item, |item| { - // This is probably okay, because the only visitors likely to - // peek inside interpolated nodes will be renamings/markings, - // which map single items to single items. - vis.flat_map_item(item).expect_one("expected visitor to produce exactly one item") - }), token::NtBlock(block) => vis.visit_block(block), - token::NtStmt(stmt) => visit_clobber(stmt, |stmt| { - // See reasoning above. - stmt.map(|stmt| { - vis.flat_map_stmt(stmt).expect_one("expected visitor to produce exactly one item") - }) - }), token::NtExpr(expr) => vis.visit_expr(expr), token::NtLiteral(expr) => vis.visit_expr(expr), token::NtMeta(item) => { diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 47d72b9bd09d3..b612dad234d2c 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -1057,9 +1057,7 @@ pub enum NtExprKind { #[derive(Clone, Encodable, Decodable)] /// For interpolation during macro expansion. pub enum Nonterminal { - NtItem(P), NtBlock(P), - NtStmt(P), NtExpr(P), NtLiteral(P), /// Stuff inside brackets for attributes @@ -1153,9 +1151,7 @@ impl fmt::Display for NonterminalKind { impl Nonterminal { pub fn use_span(&self) -> Span { match self { - NtItem(item) => item.span, NtBlock(block) => block.span, - NtStmt(stmt) => stmt.span, NtExpr(expr) | NtLiteral(expr) => expr.span, NtMeta(attr_item) => attr_item.span(), NtPath(path) => path.span, @@ -1164,9 +1160,7 @@ impl Nonterminal { pub fn descr(&self) -> &'static str { match self { - NtItem(..) => "item", NtBlock(..) => "block", - NtStmt(..) => "statement", NtExpr(..) => "expression", NtLiteral(..) => "literal", NtMeta(..) => "attribute", @@ -1188,9 +1182,7 @@ impl PartialEq for Nonterminal { impl fmt::Debug for Nonterminal { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - NtItem(..) => f.pad("NtItem(..)"), NtBlock(..) => f.pad("NtBlock(..)"), - NtStmt(..) => f.pad("NtStmt(..)"), NtExpr(..) => f.pad("NtExpr(..)"), NtLiteral(..) => f.pad("NtLiteral(..)"), NtMeta(..) => f.pad("NtMeta(..)"), diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index fb3276cb3c053..f2da426b739ae 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -22,7 +22,7 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_serialize::{Decodable, Encodable}; use rustc_span::{sym, Span, SpanDecoder, SpanEncoder, Symbol, DUMMY_SP}; -use crate::ast::{AttrStyle, StmtKind}; +use crate::ast::AttrStyle; use crate::ast_traits::{HasAttrs, HasTokens}; use crate::token::{self, Delimiter, InvisibleOrigin, Nonterminal, Token, TokenKind}; use crate::{AttrVec, Attribute}; @@ -461,13 +461,7 @@ impl TokenStream { pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream { match nt { - Nonterminal::NtItem(item) => TokenStream::from_ast(item), Nonterminal::NtBlock(block) => TokenStream::from_ast(block), - Nonterminal::NtStmt(stmt) if let StmtKind::Empty = stmt.kind => { - // FIXME: Properly collect tokens for empty statements. - TokenStream::token_alone(token::Semi, stmt.span) - } - Nonterminal::NtStmt(stmt) => TokenStream::from_ast(stmt), Nonterminal::NtMeta(attr) => TokenStream::from_ast(attr), Nonterminal::NtPath(path) => TokenStream::from_ast(path), Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => TokenStream::from_ast(expr), diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 4b05c144d37d7..e7c492b59438f 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -164,7 +164,7 @@ impl CfgEval<'_> { }, Annotatable::Stmt(_) => |parser| { Ok(Annotatable::Stmt(P(parser - .parse_stmt_without_recovery(false, ForceCollect::Yes)? + .parse_stmt_without_recovery(false, ForceCollect::Yes, false)? .unwrap()))) }, Annotatable::Expr(_) => { diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 8f9104135cddd..291fe10191d15 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -5,7 +5,7 @@ use std::rc::Rc; use rustc_ast::attr::MarkedAttrs; use rustc_ast::ptr::P; -use rustc_ast::token::Nonterminal; +use rustc_ast::token::MetaVarKind; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind}; @@ -15,7 +15,7 @@ use rustc_data_structures::sync::{self, Lrc}; use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult}; use rustc_feature::Features; use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools}; -use rustc_parse::parser::Parser; +use rustc_parse::parser::{ForceCollect, Parser}; use rustc_parse::MACRO_ARGUMENTS; use rustc_session::config::CollapseMacroDebuginfo; use rustc_session::parse::ParseSess; @@ -1374,13 +1374,13 @@ pub fn parse_macro_name_and_helper_attrs( /// If this item looks like a specific enums from `rental`, emit a fatal error. /// See #73345 and #83125 for more details. /// FIXME(#73933): Remove this eventually. -fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) { +fn pretty_printing_compatibility_hack(item: &Item, psess: &ParseSess) { let name = item.ident.name; if name == sym::ProceduralMasqueradeDummyType && let ast::ItemKind::Enum(enum_def, _) = &item.kind && let [variant] = &*enum_def.variants && variant.ident.name == sym::Input - && let FileName::Real(real) = sess.source_map().span_to_filename(item.ident.span) + && let FileName::Real(real) = psess.source_map().span_to_filename(item.ident.span) && let Some(c) = real .local_path() .unwrap_or(Path::new("")) @@ -1398,7 +1398,7 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) { }; if crate_matches { - sess.dcx().emit_fatal(errors::ProcMacroBackCompat { + psess.dcx().emit_fatal(errors::ProcMacroBackCompat { crate_name: "rental".to_string(), fixed_version: "0.5.6".to_string(), }); @@ -1406,7 +1406,7 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) { } } -pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, sess: &Session) { +pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, psess: &ParseSess) { let item = match ann { Annotatable::Item(item) => item, Annotatable::Stmt(stmt) => match &stmt.kind { @@ -1415,17 +1415,36 @@ pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, sess: &S }, _ => return, }; - pretty_printing_compatibility_hack(item, sess) + pretty_printing_compatibility_hack(item, psess) } -pub(crate) fn nt_pretty_printing_compatibility_hack(nt: &Nonterminal, sess: &Session) { - let item = match nt { - Nonterminal::NtItem(item) => item, - Nonterminal::NtStmt(stmt) => match &stmt.kind { - ast::StmtKind::Item(item) => item, - _ => return, - }, +pub(crate) fn stream_pretty_printing_compatibility_hack( + kind: MetaVarKind, + stream: &TokenStream, + psess: &ParseSess, +) { + let item = match kind { + MetaVarKind::Item => { + let mut parser = Parser::new(psess, stream.clone(), None); + // No need to collect tokens for this simple check. + parser + .parse_item(ForceCollect::No) + .expect("failed to reparse item") + .expect("an actual item") + } + MetaVarKind::Stmt => { + let mut parser = Parser::new(psess, stream.clone(), None); + // No need to collect tokens for this simple check. + let stmt = parser + .parse_stmt(ForceCollect::No) + .expect("failed to reparse") + .expect("an actual stmt"); + match &stmt.kind { + ast::StmtKind::Item(item) => item.clone(), + _ => return, + } + } _ => return, }; - pretty_printing_compatibility_hack(item, sess) + pretty_printing_compatibility_hack(&item, psess) } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 82009a7fef535..187d9fbe34a7a 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -6,7 +6,7 @@ use rustc_ast::token::{ TokenKind, }; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; -use rustc_ast::ExprKind; +use rustc_ast::{ExprKind, StmtKind}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, Diag, DiagCtxtHandle, PResult}; use rustc_parse::lexer::nfc_normalize; @@ -303,6 +303,18 @@ pub(super) fn transcribe<'a>( let kind = token::NtLifetime(*ident, *is_raw); TokenTree::token_alone(kind, sp) } + MatchedSingle(ParseNtResult::Item(item)) => { + mk_delimited(MetaVarKind::Item, TokenStream::from_ast(item)) + } + MatchedSingle(ParseNtResult::Stmt(stmt)) => { + let stream = if let StmtKind::Empty = stmt.kind { + // FIXME: Properly collect tokens for empty statements. + TokenStream::token_alone(token::Semi, stmt.span) + } else { + TokenStream::from_ast(stmt) + }; + mk_delimited(MetaVarKind::Stmt, stream) + } MatchedSingle(ParseNtResult::Pat(pat, pat_kind)) => { mk_delimited(MetaVarKind::Pat(*pat_kind), TokenStream::from_ast(pat)) } diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index d1dcec0cc1574..85df541b3f808 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -122,7 +122,7 @@ impl MultiItemModifier for DeriveProcMacro { // We had a lint for a long time, but now we just emit a hard error. // Eventually we might remove the special case hard error check // altogether. See #73345. - crate::base::ann_pretty_printing_compatibility_hack(&item, &ecx.sess); + crate::base::ann_pretty_printing_compatibility_hack(&item, &ecx.sess.psess); let input = item.to_tokens(); let stream = { let _timer = diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 76bc7c057e2ea..db6293ff3e6af 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -116,11 +116,25 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec { - let delimiter = pm::Delimiter::from_internal(delim); + tokenstream::TokenTree::Delimited(span, _, delim, stream) => { + // We used to have an alternative behaviour for crates that + // needed it: a hack used to pass AST fragments to + // attribute and derive macros as a single nonterminal + // token instead of a token stream. Such token needs to be + // "unwrapped" and not represented as a delimited group. We + // had a lint for a long time, but now we just emit a hard + // error. Eventually we might remove the special case hard + // error check altogether. See #73345. + if let Delimiter::Invisible(InvisibleOrigin::MetaVar(kind)) = delim { + crate::base::stream_pretty_printing_compatibility_hack( + kind, + &stream, + rustc.psess(), + ); + } trees.push(TokenTree::Group(Group { - delimiter, - stream: Some(tts), + delimiter: pm::Delimiter::from_internal(delim), + stream: Some(stream), span: DelimSpan { open: span.open, close: span.close, @@ -280,15 +294,6 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec { let stream = TokenStream::from_nonterminal_ast(&nt); - // We used to have an alternative behaviour for crates that - // needed it: a hack used to pass AST fragments to - // attribute and derive macros as a single nonterminal - // token instead of a token stream. Such token needs to be - // "unwrapped" and not represented as a delimited group. We - // had a lint for a long time, but now we just emit a hard - // error. Eventually we might remove the special case hard - // error check altogether. See #73345. - crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.ecx.sess); trees.push(TokenTree::Group(Group { delimiter: pm::Delimiter::None, stream: Some(stream), diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 6343aae2697f7..d9aa3e4a3475d 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3063,7 +3063,7 @@ impl<'a> Parser<'a> { } self.restore_snapshot(pre_pat_snapshot); - match self.parse_stmt_without_recovery(true, ForceCollect::No) { + match self.parse_stmt_without_recovery(true, ForceCollect::No, false) { // Consume statements for as long as possible. Ok(Some(stmt)) => { stmts.push(stmt); diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 8b2fe72bfff80..4c53855a7fc4a 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -21,10 +21,11 @@ use tracing::debug; use super::diagnostics::{dummy_arg, ConsumeClosingDelim}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{ - AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, Trailing, UsePreAttrPos, + AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, Recovered, Trailing, + UsePreAttrPos, }; use crate::errors::{self, MacroExpandsToAdtField}; -use crate::{fluent_generated as fluent, maybe_whole}; +use crate::fluent_generated as fluent; impl<'a> Parser<'a> { /// Parses a source module as a crate. This is the main entry point for the parser. @@ -126,10 +127,13 @@ impl<'a> Parser<'a> { fn_parse_mode: FnParseMode, force_collect: ForceCollect, ) -> PResult<'a, Option> { - maybe_whole!(self, NtItem, |item| { + if let Some(item) = + self.eat_metavar_seq(MetaVarKind::Item, |this| this.parse_item(ForceCollect::Yes)) + { + let mut item = item.expect("an actual item"); attrs.prepend_to_nt_inner(&mut item.attrs); - Some(item.into_inner()) - }); + return Ok(Some(item.into_inner())); + } self.collect_tokens(None, attrs, force_collect, |this, mut attrs| { let lo = this.token.span; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 4231c517a868d..b7ea3b34f963f 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1078,10 +1078,12 @@ impl<'a> Parser<'a> { let initial_semicolon = self.token.span; while self.eat(&TokenKind::Semi) { - let _ = self.parse_stmt_without_recovery(false, ForceCollect::No).unwrap_or_else(|e| { - e.cancel(); - None - }); + let _ = self + .parse_stmt_without_recovery(false, ForceCollect::No, false) + .unwrap_or_else(|e| { + e.cancel(); + None + }); } expect_err @@ -1748,6 +1750,8 @@ pub enum ParseNtResult { Tt(TokenTree), Ident(Ident, IdentIsRaw), Lifetime(Ident, IdentIsRaw), + Item(P), + Stmt(P), Pat(P, NtPatKind), Ty(P), Vis(P), diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 43f6d626f9e9d..ab44d2d37f23e 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -48,13 +48,12 @@ impl<'a> Parser<'a> { /// Old variant of `may_be_ident`. Being phased out. fn nt_may_be_ident(nt: &Nonterminal) -> bool { match nt { - NtStmt(_) - | NtExpr(_) + NtExpr(_) | NtLiteral(_) // `true`, `false` | NtMeta(_) | NtPath(_) => true, - NtItem(_) | NtBlock(_) => false, + NtBlock(_) => false, } } @@ -97,8 +96,8 @@ impl<'a> Parser<'a> { token::OpenDelim(Delimiter::Brace) => true, token::NtLifetime(..) => true, token::Interpolated(nt) => match &**nt { - NtBlock(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true, - NtItem(_) | NtMeta(_) | NtPath(_) => false, + NtBlock(_) | NtExpr(_) | NtLiteral(_) => true, + NtMeta(_) | NtPath(_) => false, }, token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k { MetaVarKind::Block @@ -148,7 +147,7 @@ impl<'a> Parser<'a> { // Note that TT is treated differently to all the others. NonterminalKind::TT => return Ok(ParseNtResult::Tt(self.parse_token_tree())), NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? { - Some(item) => NtItem(item), + Some(item) => return Ok(ParseNtResult::Item(item)), None => { return Err(self .dcx() @@ -161,7 +160,7 @@ impl<'a> Parser<'a> { NtBlock(self.collect_tokens_no_attrs(|this| this.parse_block())?) } NonterminalKind::Stmt => match self.parse_stmt(ForceCollect::Yes)? { - Some(s) => NtStmt(P(s)), + Some(stmt) => return Ok(ParseNtResult::Stmt(P(stmt))), None => { return Err(self .dcx() diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 26ad39e06cde5..deb57c239105d 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -4,7 +4,7 @@ use std::mem; use ast::Label; use rustc_ast as ast; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, TokenKind}; +use rustc_ast::token::{self, Delimiter, MetaVarKind, TokenKind}; use rustc_ast::util::classify::{self, TrailingBrace}; use rustc_ast::{ AttrStyle, AttrVec, Block, BlockCheckMode, Expr, ExprKind, HasAttrs, Local, LocalKind, MacCall, @@ -30,8 +30,8 @@ impl<'a> Parser<'a> { /// Parses a statement. This stops just before trailing semicolons on everything but items. /// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed. // Public for rustfmt usage. - pub(super) fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option> { - Ok(self.parse_stmt_without_recovery(false, force_collect).unwrap_or_else(|e| { + pub fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option> { + Ok(self.parse_stmt_without_recovery(false, force_collect, false).unwrap_or_else(|e| { e.emit(); self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); None @@ -39,23 +39,27 @@ impl<'a> Parser<'a> { } /// If `force_collect` is [`ForceCollect::Yes`], forces collection of tokens regardless of - /// whether or not we have attributes. - // Public for `cfg_eval` macro expansion. + /// whether or not we have attributes. If `force_full_expr` is true, parses the stmt without + /// using `Restriction::STMT_EXPR`. Public for `cfg_eval` macro expansion. pub fn parse_stmt_without_recovery( &mut self, capture_semi: bool, force_collect: ForceCollect, + force_full_expr: bool, ) -> PResult<'a, Option> { let pre_attr_pos = self.collect_pos(); let attrs = self.parse_outer_attributes()?; let lo = self.token.span; - maybe_whole!(self, NtStmt, |stmt| { + if let Some(stmt) = self.eat_metavar_seq(MetaVarKind::Stmt, |this| { + this.parse_stmt_without_recovery(false, ForceCollect::Yes, false) + }) { + let mut stmt = stmt.expect("an actual statement"); stmt.visit_attrs(|stmt_attrs| { attrs.prepend_to_nt_inner(stmt_attrs); }); - Some(stmt.into_inner()) - }); + return Ok(Some(stmt)); + } if self.token.is_keyword(kw::Mut) && self.is_keyword_ahead(1, &[kw::Let]) { self.bump(); @@ -144,12 +148,14 @@ impl<'a> Parser<'a> { } else if self.token != token::CloseDelim(Delimiter::Brace) { // Remainder are line-expr stmts. This is similar to the `parse_stmt_path_start` case // above. + let restrictions = + if force_full_expr { Restrictions::empty() } else { Restrictions::STMT_EXPR }; let e = self.collect_tokens( Some(pre_attr_pos), AttrWrapper::empty(), force_collect, |this, _empty_attrs| { - let (expr, _) = this.parse_expr_res(Restrictions::STMT_EXPR, attrs)?; + let (expr, _) = this.parse_expr_res(restrictions, attrs)?; Ok((expr, Trailing::No, UsePreAttrPos::Yes)) }, )?; @@ -485,7 +491,7 @@ impl<'a> Parser<'a> { // bar; // // which is valid in other languages, but not Rust. - match self.parse_stmt_without_recovery(false, ForceCollect::No) { + match self.parse_stmt_without_recovery(false, ForceCollect::No, false) { // If the next token is an open brace, e.g., we have: // // if expr other_expr { @@ -655,10 +661,24 @@ impl<'a> Parser<'a> { &mut self, recover: AttemptLocalParseRecovery, ) -> PResult<'a, Option> { - // Skip looking for a trailing semicolon when we have an interpolated statement. - maybe_whole!(self, NtStmt, |stmt| Some(stmt.into_inner())); + // Skip looking for a trailing semicolon when we have a metavar seq. + if let Some(stmt) = self.eat_metavar_seq(MetaVarKind::Stmt, |this| { + // Why pass `true` for `force_full_expr`? Statement expressions are less expressive + // than "full" expressions, due to the `STMT_EXPR` restriction, and sometimes need + // parentheses. E.g. the "full" expression `match paren_around_match {} | true` when + // used in statement context must be written `(match paren_around_match {} | true)`. + // However, if the expression we are parsing in this statement context was pasted by a + // declarative macro, it may have come from a "full" expression context, and lack + // these parentheses. So we lift the `STMT_EXPR` restriction to ensure the statement + // will reparse successfully. + this.parse_stmt_without_recovery(false, ForceCollect::No, true) + }) { + let stmt = stmt.expect("an actual statement"); + return Ok(Some(stmt)); + } - let Some(mut stmt) = self.parse_stmt_without_recovery(true, ForceCollect::No)? else { + let Some(mut stmt) = self.parse_stmt_without_recovery(true, ForceCollect::No, false)? + else { return Ok(None); }; diff --git a/tests/ui/macros/nonterminal-matching.rs b/tests/ui/macros/nonterminal-matching.rs index a655b66510311..f71a1ae50cc19 100644 --- a/tests/ui/macros/nonterminal-matching.rs +++ b/tests/ui/macros/nonterminal-matching.rs @@ -16,7 +16,7 @@ macro complex_nonterminal($nt_item: item) { struct S; } - n!(a $nt_item b); //~ ERROR no rules expected item `enum E {}` + n!(a $nt_item b); //~ ERROR no rules expected `item` metavariable } simple_nonterminal!(a, 'a, (x, y, z)); // OK @@ -32,7 +32,7 @@ macro_rules! foo { (expr $x:expr) => { bar!(expr $x); }; //~ ERROR: no rules expected expression `3` (literal $x:literal) => { bar!(literal $x); }; //~ ERROR: no rules expected literal `4` (path $x:path) => { bar!(path $x); }; //~ ERROR: no rules expected path `a::b::c` - (stmt $x:stmt) => { bar!(stmt $x); }; //~ ERROR: no rules expected statement `let abc = 0` + (stmt $x:stmt) => { bar!(stmt $x); }; //~ ERROR: no rules expected `stmt` metavariable } macro_rules! bar { diff --git a/tests/ui/macros/nonterminal-matching.stderr b/tests/ui/macros/nonterminal-matching.stderr index e283dfcb8fdc4..6e057ac3317f0 100644 --- a/tests/ui/macros/nonterminal-matching.stderr +++ b/tests/ui/macros/nonterminal-matching.stderr @@ -1,4 +1,4 @@ -error: no rules expected item `enum E {}` +error: no rules expected `item` metavariable --> $DIR/nonterminal-matching.rs:19:10 | LL | macro n(a $nt_item b) { @@ -10,7 +10,7 @@ LL | n!(a $nt_item b); LL | complex_nonterminal!(enum E {}); | ------------------------------- in this macro invocation | -note: while trying to match item `enum E {}` +note: while trying to match `item` metavariable --> $DIR/nonterminal-matching.rs:15:15 | LL | macro n(a $nt_item b) { @@ -89,7 +89,7 @@ LL | (path a::b::c) => {}; = 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 statement `let abc = 0` +error: no rules expected `stmt` metavariable --> $DIR/nonterminal-matching.rs:35:35 | LL | (stmt $x:stmt) => { bar!(stmt $x); }; diff --git a/tests/ui/proc-macro/expand-to-derive.stdout b/tests/ui/proc-macro/expand-to-derive.stdout index 81fc52ea22d7b..3a16f23ecf23c 100644 --- a/tests/ui/proc-macro/expand-to-derive.stdout +++ b/tests/ui/proc-macro/expand-to-derive.stdout @@ -44,52 +44,58 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ Group { delimiter: Brace, stream: TokenStream [ - Punct { - ch: '#', - spacing: Alone, - span: $DIR/expand-to-derive.rs:27:5: 27:6 (#0), - }, - Group { - delimiter: Bracket, - stream: TokenStream [ - Ident { - ident: "rustc_dummy", - span: $DIR/expand-to-derive.rs:27:28: 27:39 (#0), - }, - ], - span: $DIR/expand-to-derive.rs:27:6: 27:41 (#0), - }, - Ident { - ident: "struct", - span: $DIR/expand-to-derive.rs:28:5: 28:11 (#0), - }, - Ident { - ident: "Inner", - span: $DIR/expand-to-derive.rs:28:12: 28:17 (#0), - }, Group { - delimiter: Brace, + delimiter: None, stream: TokenStream [ - Ident { - ident: "other_inner_field", - span: $DIR/expand-to-derive.rs:30:9: 30:26 (#0), - }, Punct { - ch: ':', + ch: '#', spacing: Alone, - span: $DIR/expand-to-derive.rs:30:26: 30:27 (#0), + span: $DIR/expand-to-derive.rs:27:5: 27:6 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "rustc_dummy", + span: $DIR/expand-to-derive.rs:27:28: 27:39 (#0), + }, + ], + span: $DIR/expand-to-derive.rs:27:6: 27:41 (#0), }, Ident { - ident: "u8", - span: $DIR/expand-to-derive.rs:30:28: 30:30 (#0), + ident: "struct", + span: $DIR/expand-to-derive.rs:28:5: 28:11 (#0), }, - Punct { - ch: ',', - spacing: Alone, - span: $DIR/expand-to-derive.rs:30:30: 30:31 (#0), + Ident { + ident: "Inner", + span: $DIR/expand-to-derive.rs:28:12: 28:17 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "other_inner_field", + span: $DIR/expand-to-derive.rs:30:9: 30:26 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/expand-to-derive.rs:30:26: 30:27 (#0), + }, + Ident { + ident: "u8", + span: $DIR/expand-to-derive.rs:30:28: 30:30 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/expand-to-derive.rs:30:30: 30:31 (#0), + }, + ], + span: $DIR/expand-to-derive.rs:28:18: 31:6 (#0), }, ], - span: $DIR/expand-to-derive.rs:28:18: 31:6 (#0), + span: $DIR/expand-to-derive.rs:19:17: 19:22 (#3), }, Literal { kind: Integer, From 353ccf503c880a52a17a2b2de61fb64af386f6e6 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 18 Apr 2024 16:22:02 +1000 Subject: [PATCH 10/18] Remove `NtMeta`. Note: there was an existing code path involving `Interpolated` in `MetaItem::from_tokens` that was dead. This commit transfers that to the new form, but puts an `unreachable!` call inside it. --- compiler/rustc_ast/src/ast_traits.rs | 2 -- compiler/rustc_ast/src/attr/mod.rs | 12 ++++++-- compiler/rustc_ast/src/mut_visit.rs | 6 ---- compiler/rustc_ast/src/token.rs | 7 +---- compiler/rustc_ast/src/tokenstream.rs | 1 - compiler/rustc_expand/src/mbe/transcribe.rs | 3 ++ compiler/rustc_parse/messages.ftl | 2 +- compiler/rustc_parse/src/errors.rs | 2 +- compiler/rustc_parse/src/parser/attr.rs | 30 +++++++++++-------- compiler/rustc_parse/src/parser/expr.rs | 1 - compiler/rustc_parse/src/parser/mod.rs | 1 + .../rustc_parse/src/parser/nonterminal.rs | 7 +++-- tests/ui/attributes/nonterminal-expansion.rs | 2 +- .../attributes/nonterminal-expansion.stderr | 2 +- .../cfg-attr-syntax-validation.rs | 4 +-- .../cfg-attr-syntax-validation.stderr | 4 +-- tests/ui/parser/attribute/attr-bad-meta-4.rs | 4 +-- .../parser/attribute/attr-bad-meta-4.stderr | 4 +-- .../parser/attribute/attr-unquoted-ident.rs | 2 +- .../attribute/attr-unquoted-ident.stderr | 2 +- 20 files changed, 50 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 26ae64a4b6886..dd04a6491b829 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -200,7 +200,6 @@ impl HasTokens for Nonterminal { fn tokens(&self) -> Option<&LazyAttrTokenStream> { match self { Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens(), - Nonterminal::NtMeta(attr_item) => attr_item.tokens(), Nonterminal::NtPath(path) => path.tokens(), Nonterminal::NtBlock(block) => block.tokens(), } @@ -208,7 +207,6 @@ impl HasTokens for Nonterminal { fn tokens_mut(&mut self) -> Option<&mut Option> { match self { Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(), - Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(), Nonterminal::NtPath(path) => path.tokens_mut(), Nonterminal::NtBlock(block) => block.tokens_mut(), } diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index c74b518f2dbfb..d4f9612628bd5 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -15,7 +15,7 @@ use crate::ast::{ PathSegment, Safety, DUMMY_NODE_ID, }; use crate::ptr::P; -use crate::token::{self, CommentKind, Delimiter, Token}; +use crate::token::{self, CommentKind, Delimiter, InvisibleOrigin, MetaVarKind, Token}; use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, Spacing, TokenStream, TokenTree}; use crate::util::comments; use crate::util::literal::escape_string_symbol; @@ -365,10 +365,18 @@ impl MetaItem { Path { span, segments, tokens: None } } Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. }, _)) => match &**nt { - token::Nonterminal::NtMeta(item) => return item.meta(item.path.span), token::Nonterminal::NtPath(path) => (**path).clone(), _ => return None, }, + Some(TokenTree::Delimited( + _span, + _spacing, + Delimiter::Invisible(InvisibleOrigin::MetaVar(MetaVarKind::Meta)), + _stream, + )) => { + // This path is currently unreachable in the test suite. + unreachable!() + } Some(TokenTree::Token( Token { kind: token::OpenDelim(_) | token::CloseDelim(_), .. }, _, diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index d3538dd77a0cc..4b8bf6f9b0dbc 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -803,12 +803,6 @@ fn visit_nonterminal(vis: &mut T, nt: &mut token::Nonterminal) { token::NtBlock(block) => vis.visit_block(block), token::NtExpr(expr) => vis.visit_expr(expr), token::NtLiteral(expr) => vis.visit_expr(expr), - token::NtMeta(item) => { - let AttrItem { unsafety: _, path, args, tokens } = item.deref_mut(); - vis.visit_path(path); - visit_attr_args(vis, args); - visit_lazy_tts(vis, tokens); - } token::NtPath(path) => vis.visit_path(path), } } diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index b612dad234d2c..2e3e8ee9f494c 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -651,7 +651,6 @@ impl Token { matches!(&**nt, | NtExpr(..) | NtLiteral(..) - | NtMeta(..) | NtPath(..) ), OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( @@ -854,6 +853,7 @@ impl Token { /// Is this a pre-parsed expression dropped into the token stream /// (which happens while parsing the result of macro expansion)? pub fn is_whole_expr(&self) -> bool { + #[allow(irrefutable_let_patterns)] // FIXME: temporary if let Interpolated(nt) = &self.kind && let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = &**nt { @@ -1060,8 +1060,6 @@ pub enum Nonterminal { NtBlock(P), NtExpr(P), NtLiteral(P), - /// Stuff inside brackets for attributes - NtMeta(P), NtPath(P), } @@ -1153,7 +1151,6 @@ impl Nonterminal { match self { NtBlock(block) => block.span, NtExpr(expr) | NtLiteral(expr) => expr.span, - NtMeta(attr_item) => attr_item.span(), NtPath(path) => path.span, } } @@ -1163,7 +1160,6 @@ impl Nonterminal { NtBlock(..) => "block", NtExpr(..) => "expression", NtLiteral(..) => "literal", - NtMeta(..) => "attribute", NtPath(..) => "path", } } @@ -1185,7 +1181,6 @@ impl fmt::Debug for Nonterminal { NtBlock(..) => f.pad("NtBlock(..)"), NtExpr(..) => f.pad("NtExpr(..)"), NtLiteral(..) => f.pad("NtLiteral(..)"), - NtMeta(..) => f.pad("NtMeta(..)"), NtPath(..) => f.pad("NtPath(..)"), } } diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index f2da426b739ae..2a57914288d27 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -462,7 +462,6 @@ impl TokenStream { pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream { match nt { Nonterminal::NtBlock(block) => TokenStream::from_ast(block), - Nonterminal::NtMeta(attr) => TokenStream::from_ast(attr), Nonterminal::NtPath(path) => TokenStream::from_ast(path), Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => TokenStream::from_ast(expr), } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 187d9fbe34a7a..e105b35cf0adb 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -321,6 +321,9 @@ pub(super) fn transcribe<'a>( MatchedSingle(ParseNtResult::Ty(ty)) => { mk_delimited(MetaVarKind::Ty, TokenStream::from_ast(ty)) } + MatchedSingle(ParseNtResult::Meta(meta)) => { + mk_delimited(MetaVarKind::Meta, TokenStream::from_ast(meta)) + } MatchedSingle(ParseNtResult::Vis(vis)) => { mk_delimited(MetaVarKind::Vis, TokenStream::from_ast(vis)) } diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 2db333af9824a..500167954eadc 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -415,7 +415,7 @@ parse_invalid_logical_operator = `{$incorrect}` is not a logical operator .use_amp_amp_for_conjunction = use `&&` to perform logical conjunction .use_pipe_pipe_for_disjunction = use `||` to perform logical disjunction -parse_invalid_meta_item = expected unsuffixed literal, found `{$token}` +parse_invalid_meta_item = expected unsuffixed literal, found {$descr} .quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal parse_invalid_offset_of = offset_of expects dot-separated field and variant names diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index f4780e507818e..9fae77fafa69f 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1022,7 +1022,7 @@ pub(crate) struct SuffixedLiteralInAttribute { pub(crate) struct InvalidMetaItem { #[primary_span] pub span: Span, - pub token: Token, + pub descr: String, #[subdiagnostic] pub quote_ident_sugg: Option, } diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index c65cf3f40f658..c26e905883b88 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -1,6 +1,6 @@ use rustc_ast as ast; use rustc_ast::attr; -use rustc_ast::token::{self, Delimiter}; +use rustc_ast::token::{self, Delimiter, MetaVarKind}; use rustc_errors::codes::*; use rustc_errors::{Diag, PResult}; use rustc_span::symbol::kw; @@ -12,7 +12,7 @@ use super::{ AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, ParserRange, PathStyle, Trailing, UsePreAttrPos, }; -use crate::{errors, fluent_generated as fluent, maybe_whole}; +use crate::{errors, fluent_generated as fluent}; // Public for rustfmt usage #[derive(Debug)] @@ -272,7 +272,11 @@ impl<'a> Parser<'a> { /// PATH `=` UNSUFFIXED_LIT /// The delimiters or `=` are still put into the resulting token stream. pub fn parse_attr_item(&mut self, force_collect: ForceCollect) -> PResult<'a, ast::AttrItem> { - maybe_whole!(self, NtMeta, |attr| attr.into_inner()); + if let Some(item) = + self.eat_metavar_seq(MetaVarKind::Meta, |this| this.parse_attr_item(force_collect)) + { + return Ok(item); + } // Attr items don't have attributes. self.collect_tokens(None, AttrWrapper::empty(), force_collect, |this, _empty_attrs| { @@ -397,18 +401,18 @@ impl<'a> Parser<'a> { &mut self, unsafe_allowed: AllowLeadingUnsafe, ) -> PResult<'a, ast::MetaItem> { - // We can't use `maybe_whole` here because it would bump in the `None` - // case, which we don't want. - if let token::Interpolated(nt) = &self.token.kind - && let token::NtMeta(attr_item) = &**nt + // Snapshot the parser so we can backtrack in the case where `attr_item.meta()` fails. + let mut snapshot = self.create_snapshot_for_diagnostic(); + if let Some(attr_item) = snapshot + .eat_metavar_seq(MetaVarKind::Meta, |this| this.parse_attr_item(ForceCollect::No)) { - match attr_item.meta(attr_item.path.span) { + return match attr_item.meta(attr_item.path.span) { Some(meta) => { - self.bump(); - return Ok(meta); + self.restore_snapshot(snapshot); + Ok(meta) } - None => self.unexpected()?, - } + None => self.unexpected_any(), + }; } let lo = self.token.span; @@ -465,7 +469,7 @@ impl<'a> Parser<'a> { let mut err = errors::InvalidMetaItem { span: self.token.span, - token: self.token.clone(), + descr: super::token_descr(&self.token), quote_ident_sugg: None, }; diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index d9aa3e4a3475d..f140aab0353ca 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1402,7 +1402,6 @@ impl<'a> Parser<'a> { self.bump(); return Ok(self.mk_expr(self.prev_token.span, ExprKind::Block(block, None))); } - _ => {} }; } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index b7ea3b34f963f..4cd7c65a42618 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1754,6 +1754,7 @@ pub enum ParseNtResult { Stmt(P), Pat(P, NtPatKind), Ty(P), + Meta(P), Vis(P), /// This variant will eventually be removed, along with `Token::Interpolate`. diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index ab44d2d37f23e..ef459c139d41a 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -50,7 +50,6 @@ impl<'a> Parser<'a> { match nt { NtExpr(_) | NtLiteral(_) // `true`, `false` - | NtMeta(_) | NtPath(_) => true, NtBlock(_) => false, @@ -97,7 +96,7 @@ impl<'a> Parser<'a> { token::NtLifetime(..) => true, token::Interpolated(nt) => match &**nt { NtBlock(_) | NtExpr(_) | NtLiteral(_) => true, - NtMeta(_) | NtPath(_) => false, + NtPath(_) => false, }, token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k { MetaVarKind::Block @@ -206,7 +205,9 @@ impl<'a> Parser<'a> { NonterminalKind::Path => { NtPath(P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?)) } - NonterminalKind::Meta => NtMeta(P(self.parse_attr_item(ForceCollect::Yes)?)), + NonterminalKind::Meta => { + return Ok(ParseNtResult::Meta(P(self.parse_attr_item(ForceCollect::Yes)?))); + } NonterminalKind::Vis => { return Ok(ParseNtResult::Vis(P(self.collect_tokens_no_attrs(|this| { this.parse_visibility(FollowedByType::Yes) diff --git a/tests/ui/attributes/nonterminal-expansion.rs b/tests/ui/attributes/nonterminal-expansion.rs index 1b2e92a31703c..796c81a5cdf29 100644 --- a/tests/ui/attributes/nonterminal-expansion.rs +++ b/tests/ui/attributes/nonterminal-expansion.rs @@ -5,7 +5,7 @@ macro_rules! pass_nonterminal { ($n:expr) => { #[repr(align($n))] - //~^ ERROR expected unsuffixed literal, found `n!()` + //~^ ERROR expected unsuffixed literal, found expression `n!()` struct S; }; } diff --git a/tests/ui/attributes/nonterminal-expansion.stderr b/tests/ui/attributes/nonterminal-expansion.stderr index b640575d17dc7..15a61a642609b 100644 --- a/tests/ui/attributes/nonterminal-expansion.stderr +++ b/tests/ui/attributes/nonterminal-expansion.stderr @@ -1,4 +1,4 @@ -error: expected unsuffixed literal, found `n!()` +error: expected unsuffixed literal, found expression `n!()` --> $DIR/nonterminal-expansion.rs:7:22 | LL | #[repr(align($n))] diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs index d885281249203..9a041557c7cc9 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs @@ -28,8 +28,8 @@ struct S9; macro_rules! generate_s10 { ($expr: expr) => { #[cfg(feature = $expr)] - //~^ ERROR expected unsuffixed literal, found `concat!("nonexistent")` - //~| ERROR expected unsuffixed literal, found `concat!("nonexistent")` + //~^ ERROR expected unsuffixed literal, found expression `concat!("nonexistent")` + //~| ERROR expected unsuffixed literal, found expression `concat!("nonexistent")` struct S10; } } diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr index 3dd0823389cde..21a3712d9391a 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr @@ -54,7 +54,7 @@ LL | #[cfg(a = b"hi")] | | | help: consider removing the prefix -error: expected unsuffixed literal, found `concat!("nonexistent")` +error: expected unsuffixed literal, found expression `concat!("nonexistent")` --> $DIR/cfg-attr-syntax-validation.rs:30:25 | LL | #[cfg(feature = $expr)] @@ -65,7 +65,7 @@ LL | generate_s10!(concat!("nonexistent")); | = note: this error originates in the macro `generate_s10` (in Nightly builds, run with -Z macro-backtrace for more info) -error: expected unsuffixed literal, found `concat!("nonexistent")` +error: expected unsuffixed literal, found expression `concat!("nonexistent")` --> $DIR/cfg-attr-syntax-validation.rs:30:25 | LL | #[cfg(feature = $expr)] diff --git a/tests/ui/parser/attribute/attr-bad-meta-4.rs b/tests/ui/parser/attribute/attr-bad-meta-4.rs index 2a69ae5ac0639..2d0c6dbb50ab8 100644 --- a/tests/ui/parser/attribute/attr-bad-meta-4.rs +++ b/tests/ui/parser/attribute/attr-bad-meta-4.rs @@ -1,8 +1,8 @@ macro_rules! mac { ($attr_item: meta) => { #[cfg($attr_item)] - //~^ ERROR expected unsuffixed literal, found `an(arbitrary token stream)` - //~| ERROR expected unsuffixed literal, found `an(arbitrary token stream)` + //~^ ERROR expected unsuffixed literal, found `meta` metavariable + //~| ERROR expected unsuffixed literal, found `meta` metavariable struct S; } } diff --git a/tests/ui/parser/attribute/attr-bad-meta-4.stderr b/tests/ui/parser/attribute/attr-bad-meta-4.stderr index 192be28db3fb8..dea574fd36d5b 100644 --- a/tests/ui/parser/attribute/attr-bad-meta-4.stderr +++ b/tests/ui/parser/attribute/attr-bad-meta-4.stderr @@ -4,7 +4,7 @@ error: expected unsuffixed literal, found `-` LL | #[cfg(feature = -1)] | ^ -error: expected unsuffixed literal, found `an(arbitrary token stream)` +error: expected unsuffixed literal, found `meta` metavariable --> $DIR/attr-bad-meta-4.rs:3:15 | LL | #[cfg($attr_item)] @@ -15,7 +15,7 @@ LL | mac!(an(arbitrary token stream)); | = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -error: expected unsuffixed literal, found `an(arbitrary token stream)` +error: expected unsuffixed literal, found `meta` metavariable --> $DIR/attr-bad-meta-4.rs:3:15 | LL | #[cfg($attr_item)] diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.rs b/tests/ui/parser/attribute/attr-unquoted-ident.rs index 5b15b8d69fcf8..396265f715e97 100644 --- a/tests/ui/parser/attribute/attr-unquoted-ident.rs +++ b/tests/ui/parser/attribute/attr-unquoted-ident.rs @@ -19,7 +19,7 @@ fn main() { macro_rules! make { ($name:ident) => { #[doc(alias = $name)] pub struct S; } - //~^ ERROR expected unsuffixed literal, found `nickname` + //~^ ERROR expected unsuffixed literal, found identifier `nickname` } make!(nickname); //~ NOTE in this expansion diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.stderr b/tests/ui/parser/attribute/attr-unquoted-ident.stderr index e0f99459c44e7..2d7997f1aea5a 100644 --- a/tests/ui/parser/attribute/attr-unquoted-ident.stderr +++ b/tests/ui/parser/attribute/attr-unquoted-ident.stderr @@ -20,7 +20,7 @@ help: surround the identifier with quotation marks to make it into a string lite LL | #[cfg(key="foo bar baz")] | + + -error: expected unsuffixed literal, found `nickname` +error: expected unsuffixed literal, found identifier `nickname` --> $DIR/attr-unquoted-ident.rs:21:38 | LL | ($name:ident) => { #[doc(alias = $name)] pub struct S; } From 1517eb7b7674ae3294738b77395b3e54b86fc955 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 18 Apr 2024 20:09:37 +1000 Subject: [PATCH 11/18] Remove `NtPath`. --- compiler/rustc_ast/src/ast_traits.rs | 2 -- compiler/rustc_ast/src/attr/mod.rs | 8 ++--- compiler/rustc_ast/src/mut_visit.rs | 1 - compiler/rustc_ast/src/token.rs | 32 +++++-------------- compiler/rustc_ast/src/tokenstream.rs | 1 - compiler/rustc_expand/src/mbe/transcribe.rs | 3 ++ compiler/rustc_parse/src/parser/expr.rs | 12 +++---- compiler/rustc_parse/src/parser/mod.rs | 1 + .../rustc_parse/src/parser/nonterminal.rs | 7 ++-- compiler/rustc_parse/src/parser/path.rs | 9 ++++-- tests/ui/imports/import-prefix-macro-2.rs | 2 +- tests/ui/imports/import-prefix-macro-2.stderr | 4 +-- tests/ui/macros/nonterminal-matching.rs | 2 +- tests/ui/macros/nonterminal-matching.stderr | 2 +- 14 files changed, 36 insertions(+), 50 deletions(-) diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index dd04a6491b829..044569e451253 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -200,14 +200,12 @@ impl HasTokens for Nonterminal { fn tokens(&self) -> Option<&LazyAttrTokenStream> { match self { Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens(), - Nonterminal::NtPath(path) => path.tokens(), Nonterminal::NtBlock(block) => block.tokens(), } } fn tokens_mut(&mut self) -> Option<&mut Option> { match self { Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(), - Nonterminal::NtPath(path) => path.tokens_mut(), Nonterminal::NtBlock(block) => block.tokens_mut(), } } diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index d4f9612628bd5..2f6142a800f5b 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -364,14 +364,12 @@ impl MetaItem { let span = span.with_hi(segments.last().unwrap().ident.span.hi()); Path { span, segments, tokens: None } } - Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. }, _)) => match &**nt { - token::Nonterminal::NtPath(path) => (**path).clone(), - _ => return None, - }, Some(TokenTree::Delimited( _span, _spacing, - Delimiter::Invisible(InvisibleOrigin::MetaVar(MetaVarKind::Meta)), + Delimiter::Invisible(InvisibleOrigin::MetaVar( + MetaVarKind::Meta | MetaVarKind::Path, + )), _stream, )) => { // This path is currently unreachable in the test suite. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 4b8bf6f9b0dbc..b2dddc3ad7e2d 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -803,7 +803,6 @@ fn visit_nonterminal(vis: &mut T, nt: &mut token::Nonterminal) { token::NtBlock(block) => vis.visit_block(block), token::NtExpr(expr) => vis.visit_expr(expr), token::NtLiteral(expr) => vis.visit_expr(expr), - token::NtPath(path) => vis.visit_path(path), } } diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 2e3e8ee9f494c..5f99d7b6fec47 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -614,8 +614,7 @@ impl Token { matches!(&**nt, NtBlock(..) | NtExpr(..) | - NtLiteral(..) | - NtPath(..) + NtLiteral(..) ), OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( MetaVarKind::Block | @@ -651,7 +650,6 @@ impl Token { matches!(&**nt, | NtExpr(..) | NtLiteral(..) - | NtPath(..) ), OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( MetaVarKind::Expr { .. } | @@ -680,7 +678,6 @@ impl Token { Lifetime(..) | // lifetime bound in trait object Lt | BinOp(Shl) | // associated path PathSep => true, // global path - Interpolated(ref nt) => matches!(&**nt, NtPath(..)), OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( MetaVarKind::Ty | MetaVarKind::Path @@ -839,28 +836,19 @@ impl Token { self.ident().is_some_and(|(ident, _)| ident.name == name) } - /// Returns `true` if the token is an interpolated path. - fn is_whole_path(&self) -> bool { - if let Interpolated(nt) = &self.kind - && let NtPath(..) = &**nt - { - return true; - } - - false - } - /// Is this a pre-parsed expression dropped into the token stream /// (which happens while parsing the result of macro expansion)? pub fn is_whole_expr(&self) -> bool { #[allow(irrefutable_let_patterns)] // FIXME: temporary if let Interpolated(nt) = &self.kind - && let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = &**nt + && let NtExpr(_) | NtLiteral(_) | NtBlock(_) = &**nt { - return true; + true + } else if matches!(self.is_metavar_seq(), Some(MetaVarKind::Path)) { + true + } else { + false } - - false } /// Is the token an interpolated block (`$b:block`)? @@ -886,7 +874,7 @@ impl Token { pub fn is_path_start(&self) -> bool { self == &PathSep || self.is_qpath_start() - || self.is_whole_path() + || matches!(self.is_metavar_seq(), Some(MetaVarKind::Path)) || self.is_path_segment_keyword() || self.is_ident() && !self.is_reserved_ident() } @@ -1060,7 +1048,6 @@ pub enum Nonterminal { NtBlock(P), NtExpr(P), NtLiteral(P), - NtPath(P), } #[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)] @@ -1151,7 +1138,6 @@ impl Nonterminal { match self { NtBlock(block) => block.span, NtExpr(expr) | NtLiteral(expr) => expr.span, - NtPath(path) => path.span, } } @@ -1160,7 +1146,6 @@ impl Nonterminal { NtBlock(..) => "block", NtExpr(..) => "expression", NtLiteral(..) => "literal", - NtPath(..) => "path", } } } @@ -1181,7 +1166,6 @@ impl fmt::Debug for Nonterminal { NtBlock(..) => f.pad("NtBlock(..)"), NtExpr(..) => f.pad("NtExpr(..)"), NtLiteral(..) => f.pad("NtLiteral(..)"), - NtPath(..) => f.pad("NtPath(..)"), } } } diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 2a57914288d27..3498816576895 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -462,7 +462,6 @@ impl TokenStream { pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream { match nt { Nonterminal::NtBlock(block) => TokenStream::from_ast(block), - Nonterminal::NtPath(path) => TokenStream::from_ast(path), Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => TokenStream::from_ast(expr), } } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index e105b35cf0adb..70a00fdfbebb9 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -324,6 +324,9 @@ pub(super) fn transcribe<'a>( MatchedSingle(ParseNtResult::Meta(meta)) => { mk_delimited(MetaVarKind::Meta, TokenStream::from_ast(meta)) } + MatchedSingle(ParseNtResult::Path(path)) => { + mk_delimited(MetaVarKind::Path, TokenStream::from_ast(path)) + } MatchedSingle(ParseNtResult::Vis(vis)) => { mk_delimited(MetaVarKind::Vis, TokenStream::from_ast(vis)) } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index f140aab0353ca..5a199409d7413 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -4,7 +4,7 @@ use core::mem; use core::ops::ControlFlow; use ast::mut_visit::{self, MutVisitor}; -use ast::token::IdentIsRaw; +use ast::token::{IdentIsRaw, MetaVarKind}; use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment, Recovered}; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; @@ -1385,6 +1385,7 @@ impl<'a> Parser<'a> { fn parse_expr_bottom(&mut self) -> PResult<'a, P> { maybe_recover_from_interpolated_ty_qpath!(self, true); + let span = self.token.span; if let token::Interpolated(nt) = &self.token.kind { match &**nt { token::NtExpr(e) | token::NtLiteral(e) => { @@ -1392,17 +1393,16 @@ impl<'a> Parser<'a> { self.bump(); return Ok(e); } - token::NtPath(path) => { - let path = (**path).clone(); - self.bump(); - return Ok(self.mk_expr(self.prev_token.span, ExprKind::Path(None, path))); - } token::NtBlock(block) => { let block = block.clone(); self.bump(); return Ok(self.mk_expr(self.prev_token.span, ExprKind::Block(block, None))); } }; + } else if let Some(path) = self.eat_metavar_seq(MetaVarKind::Path, |this| { + this.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type)) + }) { + return Ok(self.mk_expr(span, ExprKind::Path(None, path))); } // Outer attributes are already parsed and will be diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 4cd7c65a42618..9acf6ba85f68d 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1755,6 +1755,7 @@ pub enum ParseNtResult { Pat(P, NtPatKind), Ty(P), Meta(P), + Path(P), Vis(P), /// This variant will eventually be removed, along with `Token::Interpolate`. diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index ef459c139d41a..7460f2dfcfb24 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -50,7 +50,7 @@ impl<'a> Parser<'a> { match nt { NtExpr(_) | NtLiteral(_) // `true`, `false` - | NtPath(_) => true, + => true, NtBlock(_) => false, } @@ -96,7 +96,6 @@ impl<'a> Parser<'a> { token::NtLifetime(..) => true, token::Interpolated(nt) => match &**nt { NtBlock(_) | NtExpr(_) | NtLiteral(_) => true, - NtPath(_) => false, }, token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k { MetaVarKind::Block @@ -203,7 +202,9 @@ impl<'a> Parser<'a> { }; } NonterminalKind::Path => { - NtPath(P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?)) + return Ok(ParseNtResult::Path(P( + self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))? + ))); } NonterminalKind::Meta => { return Ok(ParseNtResult::Meta(P(self.parse_attr_item(ForceCollect::Yes)?))); diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 07d2d16750613..7dd203dcbfaa4 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -16,9 +16,8 @@ use tracing::debug; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{Parser, Restrictions, TokenType}; -use crate::errors::PathSingleColon; +use crate::errors::{self, PathSingleColon}; use crate::parser::{CommaRecoveryMode, RecoverColon, RecoverComma}; -use crate::{errors, maybe_whole}; /// Specifies how to parse a path. #[derive(Copy, Clone, PartialEq)] @@ -195,7 +194,11 @@ impl<'a> Parser<'a> { } }; - maybe_whole!(self, NtPath, |path| reject_generics_if_mod_style(self, path.into_inner())); + if let Some(path) = + self.eat_metavar_seq(MetaVarKind::Path, |this| this.parse_path(PathStyle::Type)) + { + return Ok(reject_generics_if_mod_style(self, path)); + } if let Some(MetaVarKind::Ty) = self.token.is_metavar_seq() { let mut snapshot = self.create_snapshot_for_diagnostic(); diff --git a/tests/ui/imports/import-prefix-macro-2.rs b/tests/ui/imports/import-prefix-macro-2.rs index 952d161e83fac..17898c0a67995 100644 --- a/tests/ui/imports/import-prefix-macro-2.rs +++ b/tests/ui/imports/import-prefix-macro-2.rs @@ -8,7 +8,7 @@ mod a { } macro_rules! import { - ($p: path) => (use ::$p {S, Z}); //~ERROR expected identifier, found `a::b::c` + ($p: path) => (use ::$p {S, Z}); //~ERROR expected identifier, found metavariable } import! { a::b::c } diff --git a/tests/ui/imports/import-prefix-macro-2.stderr b/tests/ui/imports/import-prefix-macro-2.stderr index 070186f2bf2fb..fbeca99b13800 100644 --- a/tests/ui/imports/import-prefix-macro-2.stderr +++ b/tests/ui/imports/import-prefix-macro-2.stderr @@ -1,8 +1,8 @@ -error: expected identifier, found `a::b::c` +error: expected identifier, found metavariable --> $DIR/import-prefix-macro-2.rs:11:26 | LL | ($p: path) => (use ::$p {S, Z}); - | ^^ expected identifier + | ^^ expected identifier, found metavariable ... LL | import! { a::b::c } | ------------------- in this macro invocation diff --git a/tests/ui/macros/nonterminal-matching.rs b/tests/ui/macros/nonterminal-matching.rs index f71a1ae50cc19..b0a7f3e4650fd 100644 --- a/tests/ui/macros/nonterminal-matching.rs +++ b/tests/ui/macros/nonterminal-matching.rs @@ -31,7 +31,7 @@ macro_rules! foo { (tt $x:tt) => { bar!(tt $x); }; (expr $x:expr) => { bar!(expr $x); }; //~ ERROR: no rules expected expression `3` (literal $x:literal) => { bar!(literal $x); }; //~ ERROR: no rules expected literal `4` - (path $x:path) => { bar!(path $x); }; //~ ERROR: no rules expected path `a::b::c` + (path $x:path) => { bar!(path $x); }; //~ ERROR: no rules expected `path` metavariable (stmt $x:stmt) => { bar!(stmt $x); }; //~ ERROR: no rules expected `stmt` metavariable } diff --git a/tests/ui/macros/nonterminal-matching.stderr b/tests/ui/macros/nonterminal-matching.stderr index 6e057ac3317f0..2d9252fbfc1fa 100644 --- a/tests/ui/macros/nonterminal-matching.stderr +++ b/tests/ui/macros/nonterminal-matching.stderr @@ -67,7 +67,7 @@ LL | (literal 4) => {}; = 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 path `a::b::c` +error: no rules expected `path` metavariable --> $DIR/nonterminal-matching.rs:34:35 | LL | (path $x:path) => { bar!(path $x); }; From f48b2a168d96beaee1024af2e42fd16d44529f95 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 18 Apr 2024 21:31:17 +1000 Subject: [PATCH 12/18] Remove `NtExpr` and `NtLiteral`. Notes about tests: - tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs: some messages are now duplicated due to repeated parsing. - tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions*.rs: ditto. - `tests/ui/proc-macro/macro-rules-derive-cfg.rs`: the diff looks large but the only difference is the insertion of a single invisible-delimited group around a metavar. --- compiler/rustc_ast/src/ast_traits.rs | 2 - compiler/rustc_ast/src/mut_visit.rs | 2 - compiler/rustc_ast/src/token.rs | 71 ++---- compiler/rustc_ast/src/tokenstream.rs | 1 - compiler/rustc_expand/src/mbe/transcribe.rs | 34 ++- compiler/rustc_parse/messages.ftl | 2 +- compiler/rustc_parse/src/errors.rs | 4 +- compiler/rustc_parse/src/parser/expr.rs | 172 ++++++++----- compiler/rustc_parse/src/parser/item.rs | 11 +- compiler/rustc_parse/src/parser/mod.rs | 28 ++- .../rustc_parse/src/parser/nonterminal.rs | 16 +- compiler/rustc_parse/src/parser/pat.rs | 2 +- tests/ui/attributes/nonterminal-expansion.rs | 2 +- .../attributes/nonterminal-expansion.stderr | 2 +- .../cfg-attr-syntax-validation.rs | 4 +- .../cfg-attr-syntax-validation.stderr | 4 +- tests/ui/macros/nonterminal-matching.rs | 4 +- tests/ui/macros/nonterminal-matching.stderr | 4 +- tests/ui/parser/float-field-interpolated.rs | 8 +- .../ui/parser/float-field-interpolated.stderr | 8 +- .../ui/parser/macro/trait-non-item-macros.rs | 2 +- .../parser/macro/trait-non-item-macros.stderr | 2 +- .../proc-macro/macro-rules-derive-cfg.stdout | 129 +++++----- .../rfc-2294-if-let-guard/feature-gate.rs | 2 + .../rfc-2294-if-let-guard/feature-gate.stderr | 26 +- ...sallowed-positions-without-feature-gate.rs | 4 + ...owed-positions-without-feature-gate.stderr | 232 ++++++++++-------- .../disallowed-positions.rs | 4 + .../disallowed-positions.stderr | 230 +++++++++-------- 29 files changed, 596 insertions(+), 416 deletions(-) diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 044569e451253..8c07c328eeba0 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -199,13 +199,11 @@ impl HasTokens for Attribute { impl HasTokens for Nonterminal { fn tokens(&self) -> Option<&LazyAttrTokenStream> { match self { - Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens(), Nonterminal::NtBlock(block) => block.tokens(), } } fn tokens_mut(&mut self) -> Option<&mut Option> { match self { - Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(), Nonterminal::NtBlock(block) => block.tokens_mut(), } } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index b2dddc3ad7e2d..2654ff5fb1b60 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -801,8 +801,6 @@ pub fn visit_token(vis: &mut T, t: &mut Token) { fn visit_nonterminal(vis: &mut T, nt: &mut token::Nonterminal) { match nt { token::NtBlock(block) => vis.visit_block(block), - token::NtExpr(expr) => vis.visit_expr(expr), - token::NtLiteral(expr) => vis.visit_expr(expr), } } diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 5f99d7b6fec47..067de16ec26f7 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -210,16 +210,17 @@ impl Lit { } } - /// Keep this in sync with `Token::can_begin_literal_maybe_minus` excluding unary negation. + /// Keep this in sync with `Token::can_begin_literal_maybe_minus` and + /// `Parser::eat_token_lit` (excluding unary negation). pub fn from_token(token: &Token) -> Option { match token.uninterpolate().kind { Ident(name, IdentIsRaw::No) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)), Literal(token_lit) => Some(token_lit), - Interpolated(ref nt) - if let NtExpr(expr) | NtLiteral(expr) = &**nt - && let ast::ExprKind::Lit(token_lit) = expr.kind => - { - Some(token_lit) + OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( + MetaVarKind::Literal | MetaVarKind::Expr { .. }, + ))) => { + // Unreachable with the current test suite. + panic!("from_token metavar"); } _ => None, } @@ -558,6 +559,9 @@ impl Token { /// for which spans affect name resolution and edition checks. /// Note that keywords are also identifiers, so they should use this /// if they keep spans or perform edition checks. + // + // Note: `Parser::uninterpolated_token_span` may give better information + // than this method does. pub fn uninterpolated_span(&self) -> Span { match self.kind { NtIdent(ident, _) | NtLifetime(ident, _) => ident.span, @@ -610,12 +614,7 @@ impl Token { PathSep | // global path Lifetime(..) | // labeled loop Pound => true, // expression attributes - Interpolated(ref nt) => - matches!(&**nt, - NtBlock(..) | - NtExpr(..) | - NtLiteral(..) - ), + Interpolated(ref nt) => matches!(&**nt, NtBlock(..)), OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( MetaVarKind::Block | MetaVarKind::Expr { .. } | @@ -646,11 +645,6 @@ impl Token { BinOp(Shl) => true, // path (double UFCS) // leading vert `|` or-pattern BinOp(Or) => matches!(pat_kind, PatWithOr), - Interpolated(nt) => - matches!(&**nt, - | NtExpr(..) - | NtLiteral(..) - ), OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( MetaVarKind::Expr { .. } | MetaVarKind::Literal | @@ -693,7 +687,7 @@ impl Token { match self.kind { OpenDelim(Delimiter::Brace) | Literal(..) | BinOp(Minus) => true, Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true, - Interpolated(ref nt) => matches!(&**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)), + Interpolated(ref nt) => matches!(&**nt, NtBlock(..)), OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( MetaVarKind::Expr { .. } | MetaVarKind::Block | MetaVarKind::Literal, ))) => true, @@ -737,22 +731,12 @@ impl Token { /// /// In other words, would this token be a valid start of `parse_literal_maybe_minus`? /// - /// Keep this in sync with and `Lit::from_token`, excluding unary negation. + /// Keep this in sync with `Lit::from_token` and `Parser::eat_token_lit` + /// (excluding unary negation). pub fn can_begin_literal_maybe_minus(&self) -> bool { match self.uninterpolate().kind { Literal(..) | BinOp(Minus) => true, Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true, - Interpolated(ref nt) => match &**nt { - NtLiteral(_) => true, - NtExpr(e) => match &e.kind { - ast::ExprKind::Lit(_) => true, - ast::ExprKind::Unary(ast::UnOp::Neg, e) => { - matches!(&e.kind, ast::ExprKind::Lit(_)) - } - _ => false, - }, - _ => false, - }, OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind))) => match mv_kind { MetaVarKind::Literal => true, MetaVarKind::Expr { can_begin_literal_maybe_minus, .. } => { @@ -767,14 +751,6 @@ impl Token { pub fn can_begin_string_literal(&self) -> bool { match self.uninterpolate().kind { Literal(..) => true, - Interpolated(ref nt) => match &**nt { - NtLiteral(_) => true, - NtExpr(e) => match &e.kind { - ast::ExprKind::Lit(_) => true, - _ => false, - }, - _ => false, - }, OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind))) => match mv_kind { MetaVarKind::Literal => true, MetaVarKind::Expr { can_begin_string_literal, .. } => can_begin_string_literal, @@ -838,13 +814,16 @@ impl Token { /// Is this a pre-parsed expression dropped into the token stream /// (which happens while parsing the result of macro expansion)? - pub fn is_whole_expr(&self) -> bool { + pub fn is_metavar_expr(&self) -> bool { #[allow(irrefutable_let_patterns)] // FIXME: temporary if let Interpolated(nt) = &self.kind - && let NtExpr(_) | NtLiteral(_) | NtBlock(_) = &**nt + && let NtBlock(_) = &**nt { true - } else if matches!(self.is_metavar_seq(), Some(MetaVarKind::Path)) { + } else if matches!( + self.is_metavar_seq(), + Some(MetaVarKind::Expr { .. } | MetaVarKind::Literal | MetaVarKind::Path) + ) { true } else { false @@ -853,6 +832,7 @@ impl Token { /// Is the token an interpolated block (`$b:block`)? pub fn is_whole_block(&self) -> bool { + #[allow(irrefutable_let_patterns)] // FIXME: temporary if let Interpolated(nt) = &self.kind && let NtBlock(..) = &**nt { @@ -1046,8 +1026,6 @@ pub enum NtExprKind { /// For interpolation during macro expansion. pub enum Nonterminal { NtBlock(P), - NtExpr(P), - NtLiteral(P), } #[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)] @@ -1137,15 +1115,12 @@ impl Nonterminal { pub fn use_span(&self) -> Span { match self { NtBlock(block) => block.span, - NtExpr(expr) | NtLiteral(expr) => expr.span, } } pub fn descr(&self) -> &'static str { match self { NtBlock(..) => "block", - NtExpr(..) => "expression", - NtLiteral(..) => "literal", } } } @@ -1164,8 +1139,6 @@ impl fmt::Debug for Nonterminal { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { NtBlock(..) => f.pad("NtBlock(..)"), - NtExpr(..) => f.pad("NtExpr(..)"), - NtLiteral(..) => f.pad("NtLiteral(..)"), } } } @@ -1188,7 +1161,7 @@ mod size_asserts { // tidy-alphabetical-start static_assert_size!(Lit, 12); static_assert_size!(LitKind, 2); - static_assert_size!(Nonterminal, 16); + static_assert_size!(Nonterminal, 8); static_assert_size!(Token, 24); static_assert_size!(TokenKind, 16); // tidy-alphabetical-end diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 3498816576895..e9cbdd53cbe2f 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -462,7 +462,6 @@ impl TokenStream { pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream { match nt { Nonterminal::NtBlock(block) => TokenStream::from_ast(block), - Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => TokenStream::from_ast(expr), } } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 70a00fdfbebb9..21e1f11e5dabf 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -2,11 +2,10 @@ use std::mem; use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::token::{ - self, Delimiter, IdentIsRaw, InvisibleOrigin, Lit, LitKind, MetaVarKind, Nonterminal, Token, - TokenKind, + self, Delimiter, IdentIsRaw, InvisibleOrigin, Lit, LitKind, MetaVarKind, Token, TokenKind, }; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; -use rustc_ast::{ExprKind, StmtKind}; +use rustc_ast::{ExprKind, StmtKind, UnOp}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, Diag, DiagCtxtHandle, PResult}; use rustc_parse::lexer::nfc_normalize; @@ -318,6 +317,29 @@ pub(super) fn transcribe<'a>( MatchedSingle(ParseNtResult::Pat(pat, pat_kind)) => { mk_delimited(MetaVarKind::Pat(*pat_kind), TokenStream::from_ast(pat)) } + MatchedSingle(ParseNtResult::Expr(expr, kind)) => { + let (can_begin_literal_maybe_minus, can_begin_string_literal) = + match &expr.kind { + ExprKind::Lit(_) => (true, true), + ExprKind::Unary(UnOp::Neg, e) + if matches!(&e.kind, ExprKind::Lit(_)) => + { + (true, false) + } + _ => (false, false), + }; + mk_delimited( + MetaVarKind::Expr { + kind: *kind, + can_begin_literal_maybe_minus, + can_begin_string_literal, + }, + TokenStream::from_ast(expr), + ) + } + MatchedSingle(ParseNtResult::Literal(lit)) => { + mk_delimited(MetaVarKind::Literal, TokenStream::from_ast(lit)) + } MatchedSingle(ParseNtResult::Ty(ty)) => { mk_delimited(MetaVarKind::Ty, TokenStream::from_ast(ty)) } @@ -837,10 +859,8 @@ fn extract_symbol_from_pnr<'a>( }, _, )) => Ok(*symbol), - ParseNtResult::Nt(nt) - if let Nonterminal::NtLiteral(expr) = &**nt - && let ExprKind::Lit(Lit { kind: LitKind::Str, symbol, suffix: None }) = - &expr.kind => + ParseNtResult::Literal(expr) + if let ExprKind::Lit(Lit { kind: LitKind::Str, symbol, suffix: None }) = &expr.kind => { Ok(*symbol) } diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 500167954eadc..613943058338c 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -836,7 +836,7 @@ parse_unexpected_parentheses_in_match_arm_pattern = unexpected parentheses surro parse_unexpected_self_in_generic_parameters = unexpected keyword `Self` in generic parameters .note = you cannot use `Self` as a generic parameter because it is reserved for associated items -parse_unexpected_token_after_dot = unexpected token: `{$actual}` +parse_unexpected_token_after_dot = unexpected token: {$actual} parse_unexpected_token_after_label = expected `while`, `for`, `loop` or `{"{"}` after a label .suggestion_remove_label = consider removing the label diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 9fae77fafa69f..577893f764a8a 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1676,10 +1676,10 @@ pub(crate) struct SelfArgumentPointer { #[derive(Diagnostic)] #[diag(parse_unexpected_token_after_dot)] -pub(crate) struct UnexpectedTokenAfterDot<'a> { +pub(crate) struct UnexpectedTokenAfterDot { #[primary_span] pub span: Span, - pub actual: Cow<'a, str>, + pub actual: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 5a199409d7413..fa87fb86de849 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -4,10 +4,10 @@ use core::mem; use core::ops::ControlFlow; use ast::mut_visit::{self, MutVisitor}; -use ast::token::{IdentIsRaw, MetaVarKind}; +use ast::token::IdentIsRaw; use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment, Recovered}; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, Token, TokenKind}; +use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, Token, TokenKind}; use rustc_ast::util::case::Case; use rustc_ast::util::classify; use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity}; @@ -17,7 +17,6 @@ use rustc_ast::{ ClosureBinder, Expr, ExprField, ExprKind, FnDecl, FnRetTy, Label, MacCall, MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind, UnOp, DUMMY_NODE_ID, }; -use rustc_ast_pretty::pprust; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic}; use rustc_lexer::unescape::unescape_char; @@ -644,7 +643,7 @@ impl<'a> Parser<'a> { // can't continue an expression after an ident token::Ident(name, is_raw) => token::ident_can_begin_expr(name, t.span, is_raw), token::Literal(..) | token::Pound => true, - _ => t.is_whole_expr(), + _ => t.is_metavar_expr(), }; self.token.is_ident_named(sym::not) && self.look_ahead(1, token_cannot_continue_expr) } @@ -680,6 +679,13 @@ impl<'a> Parser<'a> { TokenKind::NtIdent(..) | TokenKind::NtLifetime(..) | TokenKind::Interpolated(..) => { self.prev_token.span } + TokenKind::CloseDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => { + // `expr.span` is the interpolated span, because invisible open + // and close delims both get marked with the same span, one + // that covers the entire thing between them. (See + // `rustc_expand::mbe::transcribe::transcribe`.) + self.prev_token.span + } _ => expr.span, } } @@ -1019,12 +1025,16 @@ impl<'a> Parser<'a> { } fn error_unexpected_after_dot(&self) -> ErrorGuaranteed { - let actual = pprust::token_to_string(&self.token); + let actual = super::token_descr(&self.token); let span = self.token.span; let sm = self.psess.source_map(); let (span, actual) = match (&self.token.kind, self.subparser_name) { - (token::Eof, Some(_)) if let Ok(actual) = sm.span_to_snippet(sm.next_point(span)) => { - (span.shrink_to_hi(), actual.into()) + (token::Eof, Some(_)) if let Ok(snippet) = sm.span_to_snippet(sm.next_point(span)) => { + (span.shrink_to_hi(), format!("`{}`", snippet)) + } + (token::CloseDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))), _) => { + // Don't need to report an error in this case. + return; } _ => (span, actual), }; @@ -1388,17 +1398,31 @@ impl<'a> Parser<'a> { let span = self.token.span; if let token::Interpolated(nt) = &self.token.kind { match &**nt { - token::NtExpr(e) | token::NtLiteral(e) => { - let e = e.clone(); - self.bump(); - return Ok(e); - } token::NtBlock(block) => { let block = block.clone(); self.bump(); return Ok(self.mk_expr(self.prev_token.span, ExprKind::Block(block, None))); } }; + } else if let Some(expr) = self.eat_metavar_seq_with_matcher( + |mv_kind| matches!(mv_kind, MetaVarKind::Expr { .. }), + |this| { + let expr = this.parse_expr(); + // FIXME(nnethercote) Sometimes with expressions we get a trailing comma, possibly + // related to the FIXME in `collect_tokens_for_expr`. Examples are the multi-line + // `assert_eq!` calls involving arguments annotated with `#[rustfmt::skip]` in + // `compiler/rustc_index/src/bit_set/tests.rs`. + if this.token.kind == token::Comma { + this.bump(); + } + expr + }, + ) { + return Ok(expr); + } else if let Some(lit) = + self.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus()) + { + return Ok(lit); } else if let Some(path) = self.eat_metavar_seq(MetaVarKind::Path, |this| { this.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type)) }) { @@ -1410,7 +1434,8 @@ impl<'a> Parser<'a> { let restrictions = self.restrictions; self.with_res(restrictions - Restrictions::ALLOW_LET, |this| { - // Note: when adding new syntax here, don't forget to adjust `TokenKind::can_begin_expr()`. + // Note: when adding new syntax here, don't forget to adjust + // `TokenKind::can_begin_expr()`. let lo = this.token.span; if let token::Literal(_) = this.token.kind { // This match arm is a special-case of the `_` match arm below and @@ -2107,49 +2132,78 @@ impl<'a> Parser<'a> { recovered } + /// Keep this in sync with `Token::can_begin_literal_maybe_minus` and + /// `Lit::from_token` (excluding unary negation). + pub fn eat_token_lit(&mut self) -> Option { + match self.token.uninterpolate().kind { + token::Ident(name, IdentIsRaw::No) if name.is_bool_lit() => { + self.bump(); + Some(token::Lit::new(token::Bool, name, None)) + } + token::Literal(token_lit) => { + self.bump(); + Some(token_lit) + } + token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( + MetaVarKind::Literal, + ))) => { + let lit = self + .eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus()) + .expect("metavar seq literal"); + let ast::ExprKind::Lit(token_lit) = lit.kind else { + panic!("didn't reparse a literal"); + }; + Some(token_lit) + } + token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( + mv_kind @ MetaVarKind::Expr { can_begin_literal_maybe_minus: true, .. }, + ))) => { + let expr = self + .eat_metavar_seq(mv_kind, |this| this.parse_expr()) + .expect("metavar seq expr"); + let ast::ExprKind::Lit(token_lit) = expr.kind else { + panic!("didn't reparse an expr"); + }; + Some(token_lit) + } + _ => None, + } + } + /// Matches `lit = true | false | token_lit`. /// Returns `None` if the next token is not a literal. - pub(super) fn parse_opt_token_lit(&mut self) -> Option<(token::Lit, Span)> { - let recovered = self.recover_after_dot(); - let token = recovered.as_ref().unwrap_or(&self.token); - let span = token.span; - - token::Lit::from_token(token).map(|token_lit| { - self.bump(); - (token_lit, span) - }) + fn parse_opt_token_lit(&mut self) -> Option<(token::Lit, Span)> { + match self.recover_after_dot() { + Some(recovered) => self.token = recovered, + None => {} + } + let span = self.token.span; + self.eat_token_lit().map(|token_lit| (token_lit, span)) } /// Matches `lit = true | false | token_lit`. /// Returns `None` if the next token is not a literal. - pub(super) fn parse_opt_meta_item_lit(&mut self) -> Option { - let recovered = self.recover_after_dot(); - let token = recovered.as_ref().unwrap_or(&self.token); - match token::Lit::from_token(token) { - Some(lit) => { - match MetaItemLit::from_token_lit(lit, token.span) { - Ok(lit) => { - self.bump(); - Some(lit) - } - Err(err) => { - let span = token.uninterpolated_span(); - self.bump(); - let guar = report_lit_error(self.psess, err, lit, span); - // Pack possible quotes and prefixes from the original literal into - // the error literal's symbol so they can be pretty-printed faithfully. - let suffixless_lit = token::Lit::new(lit.kind, lit.symbol, None); - let symbol = Symbol::intern(&suffixless_lit.to_string()); - let lit = token::Lit::new(token::Err(guar), symbol, lit.suffix); - Some( - MetaItemLit::from_token_lit(lit, span) - .unwrap_or_else(|_| unreachable!()), - ) - } + fn parse_opt_meta_item_lit(&mut self) -> Option { + match self.recover_after_dot() { + Some(recovered) => self.token = recovered, + None => {} + } + let span = self.token.span; + let span2 = self.uninterpolated_token_span(); + self.eat_token_lit().map(|token_lit| { + match MetaItemLit::from_token_lit(token_lit, span) { + Ok(lit) => lit, + Err(err) => { + let guar = report_lit_error(&self.psess, err, token_lit, span2); + // Pack possible quotes and prefixes from the original literal into + // the error literal's symbol so they can be pretty-printed faithfully. + let suffixless_lit = token::Lit::new(token_lit.kind, token_lit.symbol, None); + let symbol = Symbol::intern(&suffixless_lit.to_string()); + let token_lit = token::Lit::new(token::Err(guar), symbol, token_lit.suffix); + MetaItemLit::from_token_lit(token_lit, span2).unwrap_or_else(|_| unreachable!()) } } - None => None, - } + }) } pub(super) fn expect_no_tuple_index_suffix(&self, span: Span, suffix: Symbol) { @@ -2173,9 +2227,10 @@ impl<'a> Parser<'a> { /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`). /// Keep this in sync with `Token::can_begin_literal_maybe_minus`. pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P> { - if let token::Interpolated(nt) = &self.token.kind { - match &**nt { - // FIXME(nnethercote) The `NtExpr` case should only match if + if let Some(expr) = self.eat_metavar_seq_with_matcher( + |mv_kind| matches!(mv_kind, MetaVarKind::Expr { .. }), + |this| { + // FIXME(nnethercote) The `expr` case should only match if // `e` is an `ExprKind::Lit` or an `ExprKind::Unary` containing // an `UnOp::Neg` and an `ExprKind::Lit`, like how // `can_begin_literal_maybe_minus` works. But this method has @@ -2185,13 +2240,14 @@ impl<'a> Parser<'a> { // `ExprKind::Path` must be accepted when parsing range // patterns. That requires some care. So for now, we continue // being less strict here than we should be. - token::NtExpr(e) | token::NtLiteral(e) => { - let e = e.clone(); - self.bump(); - return Ok(e); - } - _ => {} - }; + this.parse_expr() + }, + ) { + return Ok(expr); + } else if let Some(lit) = + self.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus()) + { + return Ok(lit); } let lo = self.token.span; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 4c53855a7fc4a..3e0e81f847532 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2525,12 +2525,17 @@ impl<'a> Parser<'a> { }) // `extern ABI fn` || self.check_keyword_case(kw::Extern, case) + // Use `tree_look_ahead` because `ABI` might be a metavariable, + // i.e. an invisible-delimited sequence, and `tree_look_ahead` + // will consider that a single element when looking ahead. && self.look_ahead(1, |t| t.can_begin_string_literal()) - && (self.look_ahead(2, |t| t.is_keyword_case(kw::Fn, case)) || + && (self.tree_look_ahead(2, |t| t.is_keyword_case(kw::Fn, case)) == Some(true) || // this branch is only for better diagnostics; `pub`, `unsafe`, etc. are not allowed here (self.may_recover() - && self.look_ahead(2, |t| ALL_QUALS.iter().any(|&kw| t.is_keyword(kw))) - && self.look_ahead(3, |t| t.is_keyword_case(kw::Fn, case)))) + && self.tree_look_ahead(2, |t| ALL_QUALS.iter().any(|&kw| t.is_keyword(kw))) == Some(true) + && self.tree_look_ahead(3, |t| t.is_keyword_case(kw::Fn, case)) == Some(true) + ) + ) } /// Parses all the "front matter" (or "qualifiers") for a `fn` declaration, diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 9acf6ba85f68d..3568184ee9b7b 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -22,8 +22,8 @@ pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; use path::PathStyle; use rustc_ast::ptr::P; use rustc_ast::token::{ - self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, Nonterminal, NtPatKind, Token, - TokenKind, + self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, Nonterminal, NtExprKind, NtPatKind, + Token, TokenKind, }; use rustc_ast::tokenstream::{ AttrsTarget, DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree, TokenTreeCursor, @@ -100,6 +100,7 @@ pub enum ForceCollect { #[macro_export] macro_rules! maybe_whole { ($p:expr, $constructor:ident, |$x:ident| $e:expr) => { + #[allow(irrefutable_let_patterns)] // FIXME: temporary if let token::Interpolated(nt) = &$p.token.kind && let token::$constructor(x) = &**nt { @@ -1296,6 +1297,17 @@ impl<'a> Parser<'a> { looker(&token) } + /// Like `lookahead`, but skips over token trees rather than tokens. Useful + /// when looking past possible metavariable pasting sites. + pub fn tree_look_ahead(&self, dist: usize, looker: impl FnOnce(&Token) -> R) -> Option { + assert_ne!(dist, 0); + + match self.token_cursor.tree_cursor.look_ahead(dist - 1) { + Some(TokenTree::Token(token, _)) => Some(looker(token)), + _ => None, + } + } + /// Returns whether any of the given keywords are `dist` tokens ahead of the current one. pub(crate) fn is_keyword_ahead(&self, dist: usize, kws: &[Symbol]) -> bool { self.look_ahead(dist, |t| kws.iter().any(|&kw| t.is_keyword(kw))) @@ -1701,6 +1713,16 @@ impl<'a> Parser<'a> { pub fn approx_token_stream_pos(&self) -> u32 { self.num_bump_calls } + + pub fn uninterpolated_token_span(&self) -> Span { + match &self.token.kind { + token::Interpolated(nt) => nt.use_span(), + token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => { + self.look_ahead(1, |t| t.span) + } + _ => self.token.span, + } + } } pub(crate) fn make_unclosed_delims_error( @@ -1753,6 +1775,8 @@ pub enum ParseNtResult { Item(P), Stmt(P), Pat(P, NtPatKind), + Expr(P, NtExprKind), + Literal(P), Ty(P), Meta(P), Path(P), diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 7460f2dfcfb24..897afa99103de 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -48,10 +48,6 @@ impl<'a> Parser<'a> { /// Old variant of `may_be_ident`. Being phased out. fn nt_may_be_ident(nt: &Nonterminal) -> bool { match nt { - NtExpr(_) - | NtLiteral(_) // `true`, `false` - => true, - NtBlock(_) => false, } } @@ -95,7 +91,7 @@ impl<'a> Parser<'a> { token::OpenDelim(Delimiter::Brace) => true, token::NtLifetime(..) => true, token::Interpolated(nt) => match &**nt { - NtBlock(_) | NtExpr(_) | NtLiteral(_) => true, + NtBlock(_) => true, }, token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k { MetaVarKind::Block @@ -179,10 +175,14 @@ impl<'a> Parser<'a> { pat_kind, )); } - NonterminalKind::Expr(_) => NtExpr(self.parse_expr_force_collect()?), + NonterminalKind::Expr(expr_kind) => { + return Ok(ParseNtResult::Expr(self.parse_expr_force_collect()?, expr_kind)); + } NonterminalKind::Literal => { - // The `:literal` matcher does not support attributes - NtLiteral(self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?) + // The `:literal` matcher does not support attributes. + return Ok(ParseNtResult::Literal( + self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?, + )); } NonterminalKind::Ty => { return Ok(ParseNtResult::Ty( diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 018a230279c0e..3379799d83591 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -988,7 +988,7 @@ impl<'a> Parser<'a> { || *t == token::Dot // e.g. `.5` for recovery; || matches!(t.kind, token::Literal(..) | token::BinOp(token::Minus)) || t.is_bool_lit() - || t.is_whole_expr() + || t.is_metavar_expr() || t.is_lifetime() // recover `'a` instead of `'a'` || (self.may_recover() // recover leading `(` && *t == token::OpenDelim(Delimiter::Parenthesis) diff --git a/tests/ui/attributes/nonterminal-expansion.rs b/tests/ui/attributes/nonterminal-expansion.rs index 796c81a5cdf29..004a8a23fd61f 100644 --- a/tests/ui/attributes/nonterminal-expansion.rs +++ b/tests/ui/attributes/nonterminal-expansion.rs @@ -5,7 +5,7 @@ macro_rules! pass_nonterminal { ($n:expr) => { #[repr(align($n))] - //~^ ERROR expected unsuffixed literal, found expression `n!()` + //~^ ERROR expected unsuffixed literal, found `expr` metavariable struct S; }; } diff --git a/tests/ui/attributes/nonterminal-expansion.stderr b/tests/ui/attributes/nonterminal-expansion.stderr index 15a61a642609b..9c6cb98f61965 100644 --- a/tests/ui/attributes/nonterminal-expansion.stderr +++ b/tests/ui/attributes/nonterminal-expansion.stderr @@ -1,4 +1,4 @@ -error: expected unsuffixed literal, found expression `n!()` +error: expected unsuffixed literal, found `expr` metavariable --> $DIR/nonterminal-expansion.rs:7:22 | LL | #[repr(align($n))] diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs index 9a041557c7cc9..59a95307a227c 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs @@ -28,8 +28,8 @@ struct S9; macro_rules! generate_s10 { ($expr: expr) => { #[cfg(feature = $expr)] - //~^ ERROR expected unsuffixed literal, found expression `concat!("nonexistent")` - //~| ERROR expected unsuffixed literal, found expression `concat!("nonexistent")` + //~^ ERROR expected unsuffixed literal, found `expr` metavariable + //~| ERROR expected unsuffixed literal, found `expr` metavariable struct S10; } } diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr index 21a3712d9391a..d073f2a7a3448 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr @@ -54,7 +54,7 @@ LL | #[cfg(a = b"hi")] | | | help: consider removing the prefix -error: expected unsuffixed literal, found expression `concat!("nonexistent")` +error: expected unsuffixed literal, found `expr` metavariable --> $DIR/cfg-attr-syntax-validation.rs:30:25 | LL | #[cfg(feature = $expr)] @@ -65,7 +65,7 @@ LL | generate_s10!(concat!("nonexistent")); | = note: this error originates in the macro `generate_s10` (in Nightly builds, run with -Z macro-backtrace for more info) -error: expected unsuffixed literal, found expression `concat!("nonexistent")` +error: expected unsuffixed literal, found `expr` metavariable --> $DIR/cfg-attr-syntax-validation.rs:30:25 | LL | #[cfg(feature = $expr)] diff --git a/tests/ui/macros/nonterminal-matching.rs b/tests/ui/macros/nonterminal-matching.rs index b0a7f3e4650fd..a03ede20c5499 100644 --- a/tests/ui/macros/nonterminal-matching.rs +++ b/tests/ui/macros/nonterminal-matching.rs @@ -29,8 +29,8 @@ 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 expression `3` - (literal $x:literal) => { bar!(literal $x); }; //~ ERROR: no rules expected literal `4` + (expr $x:expr) => { bar!(expr $x); }; //~ ERROR: no rules expected `expr` metavariable + (literal $x:literal) => { bar!(literal $x); }; //~ ERROR: no rules expected `literal` metavariable (path $x:path) => { bar!(path $x); }; //~ ERROR: no rules expected `path` metavariable (stmt $x:stmt) => { bar!(stmt $x); }; //~ ERROR: no rules expected `stmt` metavariable } diff --git a/tests/ui/macros/nonterminal-matching.stderr b/tests/ui/macros/nonterminal-matching.stderr index 2d9252fbfc1fa..d01561415664c 100644 --- a/tests/ui/macros/nonterminal-matching.stderr +++ b/tests/ui/macros/nonterminal-matching.stderr @@ -23,7 +23,7 @@ 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: no rules expected expression `3` +error: no rules expected `expr` metavariable --> $DIR/nonterminal-matching.rs:32:35 | LL | (expr $x:expr) => { bar!(expr $x); }; @@ -45,7 +45,7 @@ LL | (expr 3) => {}; = 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 literal `4` +error: no rules expected `literal` metavariable --> $DIR/nonterminal-matching.rs:33:44 | LL | (literal $x:literal) => { bar!(literal $x); }; diff --git a/tests/ui/parser/float-field-interpolated.rs b/tests/ui/parser/float-field-interpolated.rs index 990f2926dc861..bf7163039c420 100644 --- a/tests/ui/parser/float-field-interpolated.rs +++ b/tests/ui/parser/float-field-interpolated.rs @@ -5,10 +5,10 @@ macro_rules! generate_field_accesses { let s = S(0, (0, 0)); s.$a; // OK - { s.$b; } //~ ERROR unexpected token: `1.1` - //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found literal `1.1` - { s.$c; } //~ ERROR unexpected token: `1.1` - //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found expression `1.1` + { s.$b; } //~ ERROR unexpected token: `literal` metavariable + //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `literal` metavariable + { s.$c; } //~ ERROR unexpected token: `expr` metavariable + //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `expr` metavariable }; } diff --git a/tests/ui/parser/float-field-interpolated.stderr b/tests/ui/parser/float-field-interpolated.stderr index 2a1a4926cb3c6..e2b7e3a7dbe75 100644 --- a/tests/ui/parser/float-field-interpolated.stderr +++ b/tests/ui/parser/float-field-interpolated.stderr @@ -1,4 +1,4 @@ -error: unexpected token: `1.1` +error: unexpected token: `literal` metavariable --> $DIR/float-field-interpolated.rs:8:13 | LL | { s.$b; } @@ -9,7 +9,7 @@ LL | generate_field_accesses!(1.1, 1.1, 1.1); | = note: this error originates in the macro `generate_field_accesses` (in Nightly builds, run with -Z macro-backtrace for more info) -error: expected one of `.`, `;`, `?`, `}`, or an operator, found literal `1.1` +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `literal` metavariable --> $DIR/float-field-interpolated.rs:8:13 | LL | { s.$b; } @@ -20,7 +20,7 @@ LL | generate_field_accesses!(1.1, 1.1, 1.1); | = note: this error originates in the macro `generate_field_accesses` (in Nightly builds, run with -Z macro-backtrace for more info) -error: unexpected token: `1.1` +error: unexpected token: `expr` metavariable --> $DIR/float-field-interpolated.rs:10:13 | LL | { s.$c; } @@ -31,7 +31,7 @@ LL | generate_field_accesses!(1.1, 1.1, 1.1); | = note: this error originates in the macro `generate_field_accesses` (in Nightly builds, run with -Z macro-backtrace for more info) -error: expected one of `.`, `;`, `?`, `}`, or an operator, found expression `1.1` +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `expr` metavariable --> $DIR/float-field-interpolated.rs:10:13 | LL | { s.$c; } diff --git a/tests/ui/parser/macro/trait-non-item-macros.rs b/tests/ui/parser/macro/trait-non-item-macros.rs index e93000193b6e3..b4140613cbae7 100644 --- a/tests/ui/parser/macro/trait-non-item-macros.rs +++ b/tests/ui/parser/macro/trait-non-item-macros.rs @@ -1,7 +1,7 @@ macro_rules! bah { ($a:expr) => { $a - }; //~^ ERROR macro expansion ignores expression `2` and any tokens following + }; //~^ ERROR macro expansion ignores `expr` metavariable and any tokens following } trait Bar { diff --git a/tests/ui/parser/macro/trait-non-item-macros.stderr b/tests/ui/parser/macro/trait-non-item-macros.stderr index 1a82848377895..62b42fa8b8dd7 100644 --- a/tests/ui/parser/macro/trait-non-item-macros.stderr +++ b/tests/ui/parser/macro/trait-non-item-macros.stderr @@ -1,4 +1,4 @@ -error: macro expansion ignores expression `2` and any tokens following +error: macro expansion ignores `expr` metavariable and any tokens following --> $DIR/trait-non-item-macros.rs:3:9 | LL | $a diff --git a/tests/ui/proc-macro/macro-rules-derive-cfg.stdout b/tests/ui/proc-macro/macro-rules-derive-cfg.stdout index c1e46b50d40c2..9482b2784d222 100644 --- a/tests/ui/proc-macro/macro-rules-derive-cfg.stdout +++ b/tests/ui/proc-macro/macro-rules-derive-cfg.stdout @@ -1,8 +1,9 @@ PRINT-DERIVE INPUT (DISPLAY): struct -Foo([bool; #[rustc_dummy(first)] #[rustc_dummy(second)] -{ #![rustc_dummy(third)] #[rustc_dummy(fourth)] 30 }]); +Foo([bool; #[rustc_dummy(first)] +#[rustc_dummy(second)] { #![rustc_dummy(third)] #[rustc_dummy(fourth)] 30 }]); PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): struct -Foo([bool; #[rustc_dummy(first)] #[rustc_dummy(second)] +Foo([bool; #[rustc_dummy(first)] +#[rustc_dummy(second)] { #! [rustc_dummy(third)] #[rustc_dummy(fourth)] 30 }]); PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { @@ -53,97 +54,103 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ ], span: $DIR/macro-rules-derive-cfg.rs:18:21: 18:63 (#3), }, - Punct { - ch: '#', - spacing: Alone, - span: $DIR/macro-rules-derive-cfg.rs:23:13: 23:14 (#0), - }, Group { - delimiter: Bracket, - stream: TokenStream [ - Ident { - ident: "rustc_dummy", - span: $DIR/macro-rules-derive-cfg.rs:23:36: 23:47 (#0), - }, - Group { - delimiter: Parenthesis, - stream: TokenStream [ - Ident { - ident: "second", - span: $DIR/macro-rules-derive-cfg.rs:23:48: 23:54 (#0), - }, - ], - span: $DIR/macro-rules-derive-cfg.rs:23:47: 23:55 (#0), - }, - ], - span: $DIR/macro-rules-derive-cfg.rs:23:14: 23:57 (#0), - }, - Group { - delimiter: Brace, + delimiter: None, stream: TokenStream [ Punct { ch: '#', - spacing: Joint, - span: $DIR/macro-rules-derive-cfg.rs:24:5: 24:6 (#0), - }, - Punct { - ch: '!', spacing: Alone, - span: $DIR/macro-rules-derive-cfg.rs:24:6: 24:7 (#0), + span: $DIR/macro-rules-derive-cfg.rs:23:13: 23:14 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "rustc_dummy", - span: $DIR/macro-rules-derive-cfg.rs:24:29: 24:40 (#0), + span: $DIR/macro-rules-derive-cfg.rs:23:36: 23:47 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "third", - span: $DIR/macro-rules-derive-cfg.rs:24:41: 24:46 (#0), + ident: "second", + span: $DIR/macro-rules-derive-cfg.rs:23:48: 23:54 (#0), }, ], - span: $DIR/macro-rules-derive-cfg.rs:24:40: 24:47 (#0), + span: $DIR/macro-rules-derive-cfg.rs:23:47: 23:55 (#0), }, ], - span: $DIR/macro-rules-derive-cfg.rs:24:7: 24:49 (#0), - }, - Punct { - ch: '#', - spacing: Alone, - span: $DIR/macro-rules-derive-cfg.rs:25:5: 25:6 (#0), + span: $DIR/macro-rules-derive-cfg.rs:23:14: 23:57 (#0), }, Group { - delimiter: Bracket, + delimiter: Brace, stream: TokenStream [ - Ident { - ident: "rustc_dummy", - span: $DIR/macro-rules-derive-cfg.rs:25:28: 25:39 (#0), + Punct { + ch: '#', + spacing: Joint, + span: $DIR/macro-rules-derive-cfg.rs:24:5: 24:6 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/macro-rules-derive-cfg.rs:24:6: 24:7 (#0), }, Group { - delimiter: Parenthesis, + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "rustc_dummy", + span: $DIR/macro-rules-derive-cfg.rs:24:29: 24:40 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "third", + span: $DIR/macro-rules-derive-cfg.rs:24:41: 24:46 (#0), + }, + ], + span: $DIR/macro-rules-derive-cfg.rs:24:40: 24:47 (#0), + }, + ], + span: $DIR/macro-rules-derive-cfg.rs:24:7: 24:49 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/macro-rules-derive-cfg.rs:25:5: 25:6 (#0), + }, + Group { + delimiter: Bracket, stream: TokenStream [ Ident { - ident: "fourth", - span: $DIR/macro-rules-derive-cfg.rs:25:40: 25:46 (#0), + ident: "rustc_dummy", + span: $DIR/macro-rules-derive-cfg.rs:25:28: 25:39 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "fourth", + span: $DIR/macro-rules-derive-cfg.rs:25:40: 25:46 (#0), + }, + ], + span: $DIR/macro-rules-derive-cfg.rs:25:39: 25:47 (#0), }, ], - span: $DIR/macro-rules-derive-cfg.rs:25:39: 25:47 (#0), + span: $DIR/macro-rules-derive-cfg.rs:25:6: 25:49 (#0), + }, + Literal { + kind: Integer, + symbol: "30", + suffix: None, + span: $DIR/macro-rules-derive-cfg.rs:26:5: 26:7 (#0), }, ], - span: $DIR/macro-rules-derive-cfg.rs:25:6: 25:49 (#0), - }, - Literal { - kind: Integer, - symbol: "30", - suffix: None, - span: $DIR/macro-rules-derive-cfg.rs:26:5: 26:7 (#0), + span: $DIR/macro-rules-derive-cfg.rs:23:58: 27:2 (#0), }, ], - span: $DIR/macro-rules-derive-cfg.rs:23:58: 27:2 (#0), + span: $DIR/macro-rules-derive-cfg.rs:18:64: 18:69 (#3), }, ], span: $DIR/macro-rules-derive-cfg.rs:18:13: 18:70 (#3), diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs index 4b2fc4a03b620..110c03d0e5491 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs @@ -59,8 +59,10 @@ fn _macros() { } use_expr!((let 0 = 1 && 0 == 0)); //~^ ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement use_expr!((let 0 = 1)); //~^ ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement match () { #[cfg(FALSE)] () if let 0 = 1 => {} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr index 1c710b04897cb..0997f0c81a019 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr @@ -124,15 +124,33 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/feature-gate.rs:62:16 + --> $DIR/feature-gate.rs:60:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:63:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:63:16 | LL | use_expr!((let 0 = 1)); | ^^^ | = note: only supported directly in conditions of `if` and `while` expressions + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: no rules expected keyword `let` - --> $DIR/feature-gate.rs:70:15 + --> $DIR/feature-gate.rs:72:15 | LL | macro_rules! use_expr { | --------------------- when calling this macro @@ -202,7 +220,7 @@ LL | () if let Range { start: _, end: _ } = (true..true) && false => {} = help: you can write `if matches!(, )` instead of `if let = ` error[E0658]: `if let` guards are experimental - --> $DIR/feature-gate.rs:66:12 + --> $DIR/feature-gate.rs:68:12 | LL | () if let 0 = 1 => {} | ^^^^^^^^^^^^ @@ -262,6 +280,6 @@ LL | () if let Range { start: _, end: _ } = (true..true) && false => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 23 previous errors +error: aborting due to 25 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions-without-feature-gate.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions-without-feature-gate.rs index 096036bb1333a..c6aa5126c8285 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions-without-feature-gate.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions-without-feature-gate.rs @@ -62,8 +62,12 @@ fn _macros() { } use_expr!((let 0 = 1 && 0 == 0)); //~^ ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement use_expr!((let 0 = 1)); //~^ ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement } fn nested_within_if_expr() { diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions-without-feature-gate.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions-without-feature-gate.stderr index 31f389512edb4..9ba1e0162955f 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions-without-feature-gate.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions-without-feature-gate.stderr @@ -233,7 +233,7 @@ LL | while (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:70:9 + --> $DIR/disallowed-positions-without-feature-gate.rs:74:9 | LL | if &let 0 = 0 {} | ^^^^^^^^^ @@ -241,7 +241,7 @@ LL | if &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:73:9 + --> $DIR/disallowed-positions-without-feature-gate.rs:77:9 | LL | if !let 0 = 0 {} | ^^^^^^^^^ @@ -249,7 +249,7 @@ LL | if !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:75:9 + --> $DIR/disallowed-positions-without-feature-gate.rs:79:9 | LL | if *let 0 = 0 {} | ^^^^^^^^^ @@ -257,7 +257,7 @@ LL | if *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:77:9 + --> $DIR/disallowed-positions-without-feature-gate.rs:81:9 | LL | if -let 0 = 0 {} | ^^^^^^^^^ @@ -265,7 +265,7 @@ LL | if -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:85:9 + --> $DIR/disallowed-positions-without-feature-gate.rs:89:9 | LL | if (let 0 = 0)? {} | ^^^^^^^^^ @@ -273,20 +273,20 @@ LL | if (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:88:16 + --> $DIR/disallowed-positions-without-feature-gate.rs:92:16 | LL | if true || let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions-without-feature-gate.rs:88:13 + --> $DIR/disallowed-positions-without-feature-gate.rs:92:13 | LL | if true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:90:17 + --> $DIR/disallowed-positions-without-feature-gate.rs:94:17 | LL | if (true || let 0 = 0) {} | ^^^^^^^^^ @@ -294,7 +294,7 @@ LL | if (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:92:25 + --> $DIR/disallowed-positions-without-feature-gate.rs:96:25 | LL | if true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -302,7 +302,7 @@ LL | if true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:94:25 + --> $DIR/disallowed-positions-without-feature-gate.rs:98:25 | LL | if true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -310,7 +310,7 @@ LL | if true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:98:12 + --> $DIR/disallowed-positions-without-feature-gate.rs:102:12 | LL | if x = let 0 = 0 {} | ^^^ @@ -318,7 +318,7 @@ LL | if x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:101:15 + --> $DIR/disallowed-positions-without-feature-gate.rs:105:15 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^ @@ -326,7 +326,7 @@ LL | if true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:104:11 + --> $DIR/disallowed-positions-without-feature-gate.rs:108:11 | LL | if ..(let 0 = 0) {} | ^^^^^^^^^ @@ -334,7 +334,7 @@ LL | if ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:106:9 + --> $DIR/disallowed-positions-without-feature-gate.rs:110:9 | LL | if (let 0 = 0).. {} | ^^^^^^^^^ @@ -342,7 +342,7 @@ LL | if (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:110:8 + --> $DIR/disallowed-positions-without-feature-gate.rs:114:8 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -350,7 +350,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:113:8 + --> $DIR/disallowed-positions-without-feature-gate.rs:117:8 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -358,7 +358,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:119:8 + --> $DIR/disallowed-positions-without-feature-gate.rs:123:8 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -366,7 +366,7 @@ LL | if let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:125:8 + --> $DIR/disallowed-positions-without-feature-gate.rs:129:8 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -374,7 +374,7 @@ LL | if let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:129:19 + --> $DIR/disallowed-positions-without-feature-gate.rs:133:19 | LL | if let true = let true = true {} | ^^^ @@ -382,7 +382,7 @@ LL | if let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:134:12 + --> $DIR/disallowed-positions-without-feature-gate.rs:138:12 | LL | while &let 0 = 0 {} | ^^^^^^^^^ @@ -390,7 +390,7 @@ LL | while &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:137:12 + --> $DIR/disallowed-positions-without-feature-gate.rs:141:12 | LL | while !let 0 = 0 {} | ^^^^^^^^^ @@ -398,7 +398,7 @@ LL | while !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:139:12 + --> $DIR/disallowed-positions-without-feature-gate.rs:143:12 | LL | while *let 0 = 0 {} | ^^^^^^^^^ @@ -406,7 +406,7 @@ LL | while *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:141:12 + --> $DIR/disallowed-positions-without-feature-gate.rs:145:12 | LL | while -let 0 = 0 {} | ^^^^^^^^^ @@ -414,7 +414,7 @@ LL | while -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:149:12 + --> $DIR/disallowed-positions-without-feature-gate.rs:153:12 | LL | while (let 0 = 0)? {} | ^^^^^^^^^ @@ -422,20 +422,20 @@ LL | while (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:152:19 + --> $DIR/disallowed-positions-without-feature-gate.rs:156:19 | LL | while true || let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions-without-feature-gate.rs:152:16 + --> $DIR/disallowed-positions-without-feature-gate.rs:156:16 | LL | while true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:154:20 + --> $DIR/disallowed-positions-without-feature-gate.rs:158:20 | LL | while (true || let 0 = 0) {} | ^^^^^^^^^ @@ -443,7 +443,7 @@ LL | while (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:156:28 + --> $DIR/disallowed-positions-without-feature-gate.rs:160:28 | LL | while true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -451,7 +451,7 @@ LL | while true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:158:28 + --> $DIR/disallowed-positions-without-feature-gate.rs:162:28 | LL | while true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -459,7 +459,7 @@ LL | while true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:162:15 + --> $DIR/disallowed-positions-without-feature-gate.rs:166:15 | LL | while x = let 0 = 0 {} | ^^^ @@ -467,7 +467,7 @@ LL | while x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:165:18 + --> $DIR/disallowed-positions-without-feature-gate.rs:169:18 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^ @@ -475,7 +475,7 @@ LL | while true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:168:14 + --> $DIR/disallowed-positions-without-feature-gate.rs:172:14 | LL | while ..(let 0 = 0) {} | ^^^^^^^^^ @@ -483,7 +483,7 @@ LL | while ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:170:12 + --> $DIR/disallowed-positions-without-feature-gate.rs:174:12 | LL | while (let 0 = 0).. {} | ^^^^^^^^^ @@ -491,7 +491,7 @@ LL | while (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:174:11 + --> $DIR/disallowed-positions-without-feature-gate.rs:178:11 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -499,7 +499,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:177:11 + --> $DIR/disallowed-positions-without-feature-gate.rs:181:11 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -507,7 +507,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:183:11 + --> $DIR/disallowed-positions-without-feature-gate.rs:187:11 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -515,7 +515,7 @@ LL | while let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:189:11 + --> $DIR/disallowed-positions-without-feature-gate.rs:193:11 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -523,7 +523,7 @@ LL | while let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:193:22 + --> $DIR/disallowed-positions-without-feature-gate.rs:197:22 | LL | while let true = let true = true {} | ^^^ @@ -531,7 +531,7 @@ LL | while let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:208:6 + --> $DIR/disallowed-positions-without-feature-gate.rs:212:6 | LL | &let 0 = 0; | ^^^ @@ -539,7 +539,7 @@ LL | &let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:211:6 + --> $DIR/disallowed-positions-without-feature-gate.rs:215:6 | LL | !let 0 = 0; | ^^^ @@ -547,7 +547,7 @@ LL | !let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:213:6 + --> $DIR/disallowed-positions-without-feature-gate.rs:217:6 | LL | *let 0 = 0; | ^^^ @@ -555,7 +555,7 @@ LL | *let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:215:6 + --> $DIR/disallowed-positions-without-feature-gate.rs:219:6 | LL | -let 0 = 0; | ^^^ @@ -563,7 +563,7 @@ LL | -let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:217:13 + --> $DIR/disallowed-positions-without-feature-gate.rs:221:13 | LL | let _ = let _ = 3; | ^^^ @@ -571,7 +571,7 @@ LL | let _ = let _ = 3; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:225:6 + --> $DIR/disallowed-positions-without-feature-gate.rs:229:6 | LL | (let 0 = 0)?; | ^^^ @@ -579,7 +579,7 @@ LL | (let 0 = 0)?; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:228:13 + --> $DIR/disallowed-positions-without-feature-gate.rs:232:13 | LL | true || let 0 = 0; | ^^^ @@ -587,7 +587,7 @@ LL | true || let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:230:14 + --> $DIR/disallowed-positions-without-feature-gate.rs:234:14 | LL | (true || let 0 = 0); | ^^^ @@ -595,7 +595,7 @@ LL | (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:232:22 + --> $DIR/disallowed-positions-without-feature-gate.rs:236:22 | LL | true && (true || let 0 = 0); | ^^^ @@ -603,7 +603,7 @@ LL | true && (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:236:9 + --> $DIR/disallowed-positions-without-feature-gate.rs:240:9 | LL | x = let 0 = 0; | ^^^ @@ -611,7 +611,7 @@ LL | x = let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:239:12 + --> $DIR/disallowed-positions-without-feature-gate.rs:243:12 | LL | true..(let 0 = 0); | ^^^ @@ -619,7 +619,7 @@ LL | true..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:241:8 + --> $DIR/disallowed-positions-without-feature-gate.rs:245:8 | LL | ..(let 0 = 0); | ^^^ @@ -627,7 +627,7 @@ LL | ..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:243:6 + --> $DIR/disallowed-positions-without-feature-gate.rs:247:6 | LL | (let 0 = 0)..; | ^^^ @@ -635,7 +635,7 @@ LL | (let 0 = 0)..; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:246:6 + --> $DIR/disallowed-positions-without-feature-gate.rs:250:6 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^ @@ -643,7 +643,7 @@ LL | (let Range { start: _, end: _ } = true..true || false); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:250:6 + --> $DIR/disallowed-positions-without-feature-gate.rs:254:6 | LL | (let true = let true = true); | ^^^ @@ -651,7 +651,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:250:17 + --> $DIR/disallowed-positions-without-feature-gate.rs:254:17 | LL | (let true = let true = true); | ^^^ @@ -659,7 +659,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:256:25 + --> $DIR/disallowed-positions-without-feature-gate.rs:260:25 | LL | let x = true && let y = 1; | ^^^ @@ -667,7 +667,7 @@ LL | let x = true && let y = 1; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:262:19 + --> $DIR/disallowed-positions-without-feature-gate.rs:266:19 | LL | [1, 2, 3][let _ = ()] | ^^^ @@ -675,7 +675,7 @@ LL | [1, 2, 3][let _ = ()] = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:267:6 + --> $DIR/disallowed-positions-without-feature-gate.rs:271:6 | LL | &let 0 = 0 | ^^^ @@ -683,7 +683,7 @@ LL | &let 0 = 0 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:277:17 + --> $DIR/disallowed-positions-without-feature-gate.rs:281:17 | LL | true && let 1 = 1 | ^^^ @@ -691,7 +691,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:282:17 + --> $DIR/disallowed-positions-without-feature-gate.rs:286:17 | LL | true && let 1 = 1 | ^^^ @@ -699,7 +699,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:287:17 + --> $DIR/disallowed-positions-without-feature-gate.rs:291:17 | LL | true && let 1 = 1 | ^^^ @@ -707,7 +707,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:298:17 + --> $DIR/disallowed-positions-without-feature-gate.rs:302:17 | LL | true && let 1 = 1 | ^^^ @@ -715,7 +715,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/disallowed-positions-without-feature-gate.rs:298:9 + --> $DIR/disallowed-positions-without-feature-gate.rs:302:9 | LL | true && let 1 = 1 | ^^^^^^^^^^^^^^^^^ @@ -726,124 +726,124 @@ LL | { true && let 1 = 1 } | + + error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:307:9 + --> $DIR/disallowed-positions-without-feature-gate.rs:311:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:307:9 + --> $DIR/disallowed-positions-without-feature-gate.rs:311:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:311:9 + --> $DIR/disallowed-positions-without-feature-gate.rs:315:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:311:9 + --> $DIR/disallowed-positions-without-feature-gate.rs:315:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:314:9 + --> $DIR/disallowed-positions-without-feature-gate.rs:318:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:314:9 + --> $DIR/disallowed-positions-without-feature-gate.rs:318:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:314:32 + --> $DIR/disallowed-positions-without-feature-gate.rs:318:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:314:32 + --> $DIR/disallowed-positions-without-feature-gate.rs:318:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:319:9 + --> $DIR/disallowed-positions-without-feature-gate.rs:323:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:319:9 + --> $DIR/disallowed-positions-without-feature-gate.rs:323:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:319:31 + --> $DIR/disallowed-positions-without-feature-gate.rs:323:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:319:31 + --> $DIR/disallowed-positions-without-feature-gate.rs:323:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:323:9 + --> $DIR/disallowed-positions-without-feature-gate.rs:327:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:323:9 + --> $DIR/disallowed-positions-without-feature-gate.rs:327:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:323:31 + --> $DIR/disallowed-positions-without-feature-gate.rs:327:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:323:31 + --> $DIR/disallowed-positions-without-feature-gate.rs:327:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:327:9 + --> $DIR/disallowed-positions-without-feature-gate.rs:331:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:327:9 + --> $DIR/disallowed-positions-without-feature-gate.rs:331:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:332:22 + --> $DIR/disallowed-positions-without-feature-gate.rs:336:22 | LL | let x = (true && let y = 1); | ^^^ @@ -851,7 +851,7 @@ LL | let x = (true && let y = 1); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:337:20 + --> $DIR/disallowed-positions-without-feature-gate.rs:341:20 | LL | ([1, 2, 3][let _ = ()]) | ^^^ @@ -867,15 +867,51 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:65:16 + --> $DIR/disallowed-positions-without-feature-gate.rs:63:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions-without-feature-gate.rs:63:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions-without-feature-gate.rs:67:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions-without-feature-gate.rs:67:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions-without-feature-gate.rs:67:16 | LL | use_expr!((let 0 = 1)); | ^^^ | = note: only supported directly in conditions of `if` and `while` expressions + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0308]: mismatched types - --> $DIR/disallowed-positions-without-feature-gate.rs:101:8 + --> $DIR/disallowed-positions-without-feature-gate.rs:105:8 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range` @@ -884,7 +920,7 @@ LL | if true..(let 0 = 0) {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions-without-feature-gate.rs:110:12 + --> $DIR/disallowed-positions-without-feature-gate.rs:114:12 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -895,7 +931,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions-without-feature-gate.rs:113:12 + --> $DIR/disallowed-positions-without-feature-gate.rs:117:12 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -906,7 +942,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions-without-feature-gate.rs:119:12 + --> $DIR/disallowed-positions-without-feature-gate.rs:123:12 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -917,7 +953,7 @@ LL | if let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions-without-feature-gate.rs:125:12 + --> $DIR/disallowed-positions-without-feature-gate.rs:129:12 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -928,7 +964,7 @@ LL | if let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions-without-feature-gate.rs:81:20 + --> $DIR/disallowed-positions-without-feature-gate.rs:85:20 | LL | if let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -936,7 +972,7 @@ LL | if let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/disallowed-positions-without-feature-gate.rs:165:11 + --> $DIR/disallowed-positions-without-feature-gate.rs:169:11 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range` @@ -945,7 +981,7 @@ LL | while true..(let 0 = 0) {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions-without-feature-gate.rs:174:15 + --> $DIR/disallowed-positions-without-feature-gate.rs:178:15 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -956,7 +992,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions-without-feature-gate.rs:177:15 + --> $DIR/disallowed-positions-without-feature-gate.rs:181:15 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -967,7 +1003,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions-without-feature-gate.rs:183:15 + --> $DIR/disallowed-positions-without-feature-gate.rs:187:15 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -978,7 +1014,7 @@ LL | while let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions-without-feature-gate.rs:189:15 + --> $DIR/disallowed-positions-without-feature-gate.rs:193:15 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -989,7 +1025,7 @@ LL | while let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions-without-feature-gate.rs:145:23 + --> $DIR/disallowed-positions-without-feature-gate.rs:149:23 | LL | while let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -997,7 +1033,7 @@ LL | while let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/disallowed-positions-without-feature-gate.rs:246:10 + --> $DIR/disallowed-positions-without-feature-gate.rs:250:10 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1008,14 +1044,14 @@ LL | (let Range { start: _, end: _ } = true..true || false); found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions-without-feature-gate.rs:221:17 + --> $DIR/disallowed-positions-without-feature-gate.rs:225:17 | LL | let 0 = 0?; | ^^ the `?` operator cannot be applied to type `{integer}` | = help: the trait `Try` is not implemented for `{integer}` -error: aborting due to 105 previous errors +error: aborting due to 109 previous errors Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs index 4ac3ea53a08ab..dd05d16e0fdc0 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs @@ -80,8 +80,12 @@ fn _macros() { } use_expr!((let 0 = 1 && 0 == 0)); //~^ ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement use_expr!((let 0 = 1)); //~^ ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement } fn nested_within_if_expr() { diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.stderr index ab58abf4d4605..c40269f270360 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.stderr @@ -233,7 +233,7 @@ LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:88:9 + --> $DIR/disallowed-positions.rs:92:9 | LL | if &let 0 = 0 {} | ^^^^^^^^^ @@ -241,7 +241,7 @@ LL | if &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:91:9 + --> $DIR/disallowed-positions.rs:95:9 | LL | if !let 0 = 0 {} | ^^^^^^^^^ @@ -249,7 +249,7 @@ LL | if !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:93:9 + --> $DIR/disallowed-positions.rs:97:9 | LL | if *let 0 = 0 {} | ^^^^^^^^^ @@ -257,7 +257,7 @@ LL | if *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:95:9 + --> $DIR/disallowed-positions.rs:99:9 | LL | if -let 0 = 0 {} | ^^^^^^^^^ @@ -265,7 +265,7 @@ LL | if -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:103:9 + --> $DIR/disallowed-positions.rs:107:9 | LL | if (let 0 = 0)? {} | ^^^^^^^^^ @@ -273,20 +273,20 @@ LL | if (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:106:16 + --> $DIR/disallowed-positions.rs:110:16 | LL | if true || let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:106:13 + --> $DIR/disallowed-positions.rs:110:13 | LL | if true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:108:17 + --> $DIR/disallowed-positions.rs:112:17 | LL | if (true || let 0 = 0) {} | ^^^^^^^^^ @@ -294,7 +294,7 @@ LL | if (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:110:25 + --> $DIR/disallowed-positions.rs:114:25 | LL | if true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -302,7 +302,7 @@ LL | if true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:112:25 + --> $DIR/disallowed-positions.rs:116:25 | LL | if true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -310,7 +310,7 @@ LL | if true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:116:12 + --> $DIR/disallowed-positions.rs:120:12 | LL | if x = let 0 = 0 {} | ^^^ @@ -318,7 +318,7 @@ LL | if x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:119:15 + --> $DIR/disallowed-positions.rs:123:15 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^ @@ -326,7 +326,7 @@ LL | if true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:122:11 + --> $DIR/disallowed-positions.rs:126:11 | LL | if ..(let 0 = 0) {} | ^^^^^^^^^ @@ -334,7 +334,7 @@ LL | if ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:124:9 + --> $DIR/disallowed-positions.rs:128:9 | LL | if (let 0 = 0).. {} | ^^^^^^^^^ @@ -342,7 +342,7 @@ LL | if (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:128:8 + --> $DIR/disallowed-positions.rs:132:8 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -350,7 +350,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:131:8 + --> $DIR/disallowed-positions.rs:135:8 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -358,7 +358,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:137:8 + --> $DIR/disallowed-positions.rs:141:8 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -366,7 +366,7 @@ LL | if let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:143:8 + --> $DIR/disallowed-positions.rs:147:8 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -374,7 +374,7 @@ LL | if let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:147:19 + --> $DIR/disallowed-positions.rs:151:19 | LL | if let true = let true = true {} | ^^^ @@ -382,7 +382,7 @@ LL | if let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:152:12 + --> $DIR/disallowed-positions.rs:156:12 | LL | while &let 0 = 0 {} | ^^^^^^^^^ @@ -390,7 +390,7 @@ LL | while &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:155:12 + --> $DIR/disallowed-positions.rs:159:12 | LL | while !let 0 = 0 {} | ^^^^^^^^^ @@ -398,7 +398,7 @@ LL | while !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:157:12 + --> $DIR/disallowed-positions.rs:161:12 | LL | while *let 0 = 0 {} | ^^^^^^^^^ @@ -406,7 +406,7 @@ LL | while *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:159:12 + --> $DIR/disallowed-positions.rs:163:12 | LL | while -let 0 = 0 {} | ^^^^^^^^^ @@ -414,7 +414,7 @@ LL | while -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:167:12 + --> $DIR/disallowed-positions.rs:171:12 | LL | while (let 0 = 0)? {} | ^^^^^^^^^ @@ -422,20 +422,20 @@ LL | while (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:170:19 + --> $DIR/disallowed-positions.rs:174:19 | LL | while true || let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:170:16 + --> $DIR/disallowed-positions.rs:174:16 | LL | while true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:172:20 + --> $DIR/disallowed-positions.rs:176:20 | LL | while (true || let 0 = 0) {} | ^^^^^^^^^ @@ -443,7 +443,7 @@ LL | while (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:174:28 + --> $DIR/disallowed-positions.rs:178:28 | LL | while true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -451,7 +451,7 @@ LL | while true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:176:28 + --> $DIR/disallowed-positions.rs:180:28 | LL | while true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -459,7 +459,7 @@ LL | while true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:180:15 + --> $DIR/disallowed-positions.rs:184:15 | LL | while x = let 0 = 0 {} | ^^^ @@ -467,7 +467,7 @@ LL | while x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:183:18 + --> $DIR/disallowed-positions.rs:187:18 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^ @@ -475,7 +475,7 @@ LL | while true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:186:14 + --> $DIR/disallowed-positions.rs:190:14 | LL | while ..(let 0 = 0) {} | ^^^^^^^^^ @@ -483,7 +483,7 @@ LL | while ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:188:12 + --> $DIR/disallowed-positions.rs:192:12 | LL | while (let 0 = 0).. {} | ^^^^^^^^^ @@ -491,7 +491,7 @@ LL | while (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:192:11 + --> $DIR/disallowed-positions.rs:196:11 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -499,7 +499,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:195:11 + --> $DIR/disallowed-positions.rs:199:11 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -507,7 +507,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:201:11 + --> $DIR/disallowed-positions.rs:205:11 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -515,7 +515,7 @@ LL | while let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:207:11 + --> $DIR/disallowed-positions.rs:211:11 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -523,7 +523,7 @@ LL | while let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:211:22 + --> $DIR/disallowed-positions.rs:215:22 | LL | while let true = let true = true {} | ^^^ @@ -531,7 +531,7 @@ LL | while let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:226:6 + --> $DIR/disallowed-positions.rs:230:6 | LL | &let 0 = 0; | ^^^ @@ -539,7 +539,7 @@ LL | &let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:229:6 + --> $DIR/disallowed-positions.rs:233:6 | LL | !let 0 = 0; | ^^^ @@ -547,7 +547,7 @@ LL | !let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:231:6 + --> $DIR/disallowed-positions.rs:235:6 | LL | *let 0 = 0; | ^^^ @@ -555,7 +555,7 @@ LL | *let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:233:6 + --> $DIR/disallowed-positions.rs:237:6 | LL | -let 0 = 0; | ^^^ @@ -563,7 +563,7 @@ LL | -let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:241:6 + --> $DIR/disallowed-positions.rs:245:6 | LL | (let 0 = 0)?; | ^^^ @@ -571,7 +571,7 @@ LL | (let 0 = 0)?; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:244:13 + --> $DIR/disallowed-positions.rs:248:13 | LL | true || let 0 = 0; | ^^^ @@ -579,7 +579,7 @@ LL | true || let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:246:14 + --> $DIR/disallowed-positions.rs:250:14 | LL | (true || let 0 = 0); | ^^^ @@ -587,7 +587,7 @@ LL | (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:248:22 + --> $DIR/disallowed-positions.rs:252:22 | LL | true && (true || let 0 = 0); | ^^^ @@ -595,7 +595,7 @@ LL | true && (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:252:9 + --> $DIR/disallowed-positions.rs:256:9 | LL | x = let 0 = 0; | ^^^ @@ -603,7 +603,7 @@ LL | x = let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:255:12 + --> $DIR/disallowed-positions.rs:259:12 | LL | true..(let 0 = 0); | ^^^ @@ -611,7 +611,7 @@ LL | true..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:257:8 + --> $DIR/disallowed-positions.rs:261:8 | LL | ..(let 0 = 0); | ^^^ @@ -619,7 +619,7 @@ LL | ..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:259:6 + --> $DIR/disallowed-positions.rs:263:6 | LL | (let 0 = 0)..; | ^^^ @@ -627,7 +627,7 @@ LL | (let 0 = 0)..; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:262:6 + --> $DIR/disallowed-positions.rs:266:6 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^ @@ -635,7 +635,7 @@ LL | (let Range { start: _, end: _ } = true..true || false); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:266:6 + --> $DIR/disallowed-positions.rs:270:6 | LL | (let true = let true = true); | ^^^ @@ -643,7 +643,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:266:17 + --> $DIR/disallowed-positions.rs:270:17 | LL | (let true = let true = true); | ^^^ @@ -651,7 +651,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:272:25 + --> $DIR/disallowed-positions.rs:276:25 | LL | let x = true && let y = 1; | ^^^ @@ -659,7 +659,7 @@ LL | let x = true && let y = 1; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:278:19 + --> $DIR/disallowed-positions.rs:282:19 | LL | [1, 2, 3][let _ = ()] | ^^^ @@ -667,7 +667,7 @@ LL | [1, 2, 3][let _ = ()] = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:283:6 + --> $DIR/disallowed-positions.rs:287:6 | LL | &let 0 = 0 | ^^^ @@ -675,7 +675,7 @@ LL | &let 0 = 0 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:293:17 + --> $DIR/disallowed-positions.rs:297:17 | LL | true && let 1 = 1 | ^^^ @@ -683,7 +683,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:298:17 + --> $DIR/disallowed-positions.rs:302:17 | LL | true && let 1 = 1 | ^^^ @@ -691,7 +691,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:303:17 + --> $DIR/disallowed-positions.rs:307:17 | LL | true && let 1 = 1 | ^^^ @@ -699,7 +699,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:314:17 + --> $DIR/disallowed-positions.rs:318:17 | LL | true && let 1 = 1 | ^^^ @@ -707,7 +707,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/disallowed-positions.rs:314:9 + --> $DIR/disallowed-positions.rs:318:9 | LL | true && let 1 = 1 | ^^^^^^^^^^^^^^^^^ @@ -718,124 +718,124 @@ LL | { true && let 1 = 1 } | + + error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:323:9 + --> $DIR/disallowed-positions.rs:327:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:323:9 + --> $DIR/disallowed-positions.rs:327:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:327:9 + --> $DIR/disallowed-positions.rs:331:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:327:9 + --> $DIR/disallowed-positions.rs:331:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:330:9 + --> $DIR/disallowed-positions.rs:334:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:330:9 + --> $DIR/disallowed-positions.rs:334:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:330:32 + --> $DIR/disallowed-positions.rs:334:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:330:32 + --> $DIR/disallowed-positions.rs:334:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:337:9 + --> $DIR/disallowed-positions.rs:341:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:337:9 + --> $DIR/disallowed-positions.rs:341:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:337:31 + --> $DIR/disallowed-positions.rs:341:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:337:31 + --> $DIR/disallowed-positions.rs:341:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:341:9 + --> $DIR/disallowed-positions.rs:345:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:341:9 + --> $DIR/disallowed-positions.rs:345:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:341:31 + --> $DIR/disallowed-positions.rs:345:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:341:31 + --> $DIR/disallowed-positions.rs:345:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:345:9 + --> $DIR/disallowed-positions.rs:349:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:345:9 + --> $DIR/disallowed-positions.rs:349:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:361:22 + --> $DIR/disallowed-positions.rs:365:22 | LL | let x = (true && let y = 1); | ^^^ @@ -843,7 +843,7 @@ LL | let x = (true && let y = 1); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:366:20 + --> $DIR/disallowed-positions.rs:370:20 | LL | ([1, 2, 3][let _ = ()]) | ^^^ @@ -859,15 +859,51 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:83:16 + --> $DIR/disallowed-positions.rs:81:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:81:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:85:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:85:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:85:16 | LL | use_expr!((let 0 = 1)); | ^^^ | = note: only supported directly in conditions of `if` and `while` expressions + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:119:8 + --> $DIR/disallowed-positions.rs:123:8 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range` @@ -876,7 +912,7 @@ LL | if true..(let 0 = 0) {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:128:12 + --> $DIR/disallowed-positions.rs:132:12 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -887,7 +923,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:131:12 + --> $DIR/disallowed-positions.rs:135:12 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -898,7 +934,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:137:12 + --> $DIR/disallowed-positions.rs:141:12 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -909,7 +945,7 @@ LL | if let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:143:12 + --> $DIR/disallowed-positions.rs:147:12 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -920,7 +956,7 @@ LL | if let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:99:20 + --> $DIR/disallowed-positions.rs:103:20 | LL | if let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -928,7 +964,7 @@ LL | if let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:183:11 + --> $DIR/disallowed-positions.rs:187:11 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range` @@ -937,7 +973,7 @@ LL | while true..(let 0 = 0) {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:192:15 + --> $DIR/disallowed-positions.rs:196:15 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -948,7 +984,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:195:15 + --> $DIR/disallowed-positions.rs:199:15 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -959,7 +995,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:201:15 + --> $DIR/disallowed-positions.rs:205:15 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -970,7 +1006,7 @@ LL | while let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:207:15 + --> $DIR/disallowed-positions.rs:211:15 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -981,7 +1017,7 @@ LL | while let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:163:23 + --> $DIR/disallowed-positions.rs:167:23 | LL | while let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -989,7 +1025,7 @@ LL | while let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:262:10 + --> $DIR/disallowed-positions.rs:266:10 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1000,14 +1036,14 @@ LL | (let Range { start: _, end: _ } = true..true || false); found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:237:17 + --> $DIR/disallowed-positions.rs:241:17 | LL | let 0 = 0?; | ^^ the `?` operator cannot be applied to type `{integer}` | = help: the trait `Try` is not implemented for `{integer}` -error: aborting due to 104 previous errors +error: aborting due to 108 previous errors Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. From 48c952f14f75971edc0d364d5760a85922d6639d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 18 Apr 2024 20:18:13 +1000 Subject: [PATCH 13/18] Remove `NtBlock`, `Nonterminal`, and `TokenKind::Interpolated`. `NtBlock` is the last remaining variant of `Nonterminal`, so once it is gone then `Nonterminal` can be removed as well. --- compiler/rustc_ast/src/ast_traits.rs | 14 -- compiler/rustc_ast/src/mut_visit.rs | 40 +----- compiler/rustc_ast/src/token.rs | 131 +++--------------- compiler/rustc_ast/src/tokenstream.rs | 26 +--- compiler/rustc_ast_pretty/src/pprust/mod.rs | 6 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 14 +- compiler/rustc_builtin_macros/src/cfg_eval.rs | 6 +- compiler/rustc_expand/src/config.rs | 8 +- compiler/rustc_expand/src/mbe/diagnostics.rs | 4 +- compiler/rustc_expand/src/mbe/transcribe.rs | 14 +- .../rustc_expand/src/proc_macro_server.rs | 9 -- compiler/rustc_parse/src/parser/expr.rs | 36 ++--- compiler/rustc_parse/src/parser/item.rs | 2 +- compiler/rustc_parse/src/parser/mod.rs | 32 +---- .../rustc_parse/src/parser/nonterminal.rs | 117 +++++----------- compiler/rustc_parse/src/parser/stmt.rs | 9 +- tests/ui/macros/macro-as-fn-body.rs | 2 +- 17 files changed, 104 insertions(+), 366 deletions(-) diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 8c07c328eeba0..6a872fc23a04b 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -6,7 +6,6 @@ use std::fmt; use std::marker::PhantomData; use crate::ptr::P; -use crate::token::Nonterminal; use crate::tokenstream::LazyAttrTokenStream; use crate::{ Arm, AssocItem, AttrItem, AttrKind, AttrVec, Attribute, Block, Crate, Expr, ExprField, @@ -196,19 +195,6 @@ impl HasTokens for Attribute { } } -impl HasTokens for Nonterminal { - fn tokens(&self) -> Option<&LazyAttrTokenStream> { - match self { - Nonterminal::NtBlock(block) => block.tokens(), - } - } - fn tokens_mut(&mut self) -> Option<&mut Option> { - match self { - Nonterminal::NtBlock(block) => block.tokens_mut(), - } - } -} - /// A trait for AST nodes having (or not having) attributes. pub trait HasAttrs { /// This is `true` if this `HasAttrs` might support 'custom' (proc-macro) inner diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 2654ff5fb1b60..33ddff92f5b08 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -745,9 +745,9 @@ fn visit_lazy_tts(vis: &mut T, lazy_tts: &mut Option(vis: &mut T, t: &mut Token) { let Token { kind, span } = t; @@ -765,45 +765,11 @@ pub fn visit_token(vis: &mut T, t: &mut Token) { token::NtLifetime(ident, _is_raw) => { vis.visit_ident(ident); } - token::Interpolated(nt) => { - let nt = Lrc::make_mut(nt); - visit_nonterminal(vis, nt); - } _ => {} } vis.visit_span(span); } -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -/// Applies the visitor to elements of interpolated nodes. -// -// N.B., this can occur only when applying a visitor to partially expanded -// code, where parsed pieces have gotten implanted ito *other* macro -// invocations. This is relevant for macro hygiene, but possibly not elsewhere. -// -// One problem here occurs because the types for flat_map_item, flat_map_stmt, -// etc., allow the visitor to return *multiple* items; this is a problem for the -// nodes here, because they insist on having exactly one piece. One solution -// would be to mangle the MutVisitor trait to include one-to-many and -// one-to-one versions of these entry points, but that would probably confuse a -// lot of people and help very few. Instead, I'm just going to put in dynamic -// checks. I think the performance impact of this will be pretty much -// nonexistent. The danger is that someone will apply a `MutVisitor` to a -// partially expanded node, and will be confused by the fact that their -// `flat_map_item` or `flat_map_stmt` isn't getting called on `NtItem` or `NtStmt` -// nodes. Hopefully they'll wind up reading this comment, and doing something -// appropriate. -// -// BTW, design choice: I considered just changing the type of, e.g., `NtItem` to -// contain multiple items, but decided against it when I looked at -// `parse_item_or_view_item` and tried to figure out what I would do with -// multiple items there.... -fn visit_nonterminal(vis: &mut T, nt: &mut token::Nonterminal) { - match nt { - token::NtBlock(block) => vis.visit_block(block), - } -} - // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. fn visit_defaultness(vis: &mut T, defaultness: &mut Defaultness) { match defaultness { diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 067de16ec26f7..d1dcc34aa8068 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -1,8 +1,6 @@ use std::borrow::Cow; use std::fmt; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::Lrc; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::edition::Edition; use rustc_span::symbol::{kw, sym}; @@ -12,13 +10,11 @@ use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; pub use BinOpToken::*; pub use LitKind::*; -pub use Nonterminal::*; pub use NtExprKind::*; pub use NtPatKind::*; pub use TokenKind::*; use crate::ast; -use crate::ptr::P; use crate::util::case::Case; #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] @@ -52,8 +48,8 @@ pub enum InvisibleOrigin { // `proc_macro::Delimiter::to_internal`, i.e. returned by a proc macro. ProcMacro, - // Converted from `TokenKind::Interpolated` in - // `TokenStream::flatten_token`. Treated similarly to `ProcMacro`. + // Converted from `TokenKind::NtLifetime` in `TokenStream::flatten_token`. + // Treated similarly to `ProcMacro`. FlattenToken, } @@ -349,9 +345,7 @@ impl From for bool { } } -// SAFETY: due to the `Clone` impl below, all fields of all variants other than -// `Interpolated` must impl `Copy`. -#[derive(PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] +#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub enum TokenKind { /* Expression-operator symbols. */ /// `=` @@ -440,21 +434,6 @@ pub enum TokenKind { /// the `lifetime` metavariable in the macro's RHS. NtLifetime(Ident, IdentIsRaw), - /// An embedded AST node, as produced by a macro. This only exists for - /// historical reasons. We'd like to get rid of it, for multiple reasons. - /// - It's conceptually very strange. Saying a token can contain an AST - /// node is like saying, in natural language, that a word can contain a - /// sentence. - /// - It requires special handling in a bunch of places in the parser. - /// - It prevents `Token` from implementing `Copy`. - /// It adds complexity and likely slows things down. Please don't add new - /// occurrences of this token kind! - /// - /// The span in the surrounding `Token` is that of the metavariable in the - /// macro's RHS. The span within the Nonterminal is that of the fragment - /// passed to the macro at the call site. - Interpolated(Lrc), - /// A doc comment token. /// `Symbol` is the doc comment's data excluding its "quotes" (`///`, `/**`, etc) /// similarly to symbols in string literal tokens. @@ -464,19 +443,6 @@ pub enum TokenKind { Eof, } -impl Clone for TokenKind { - fn clone(&self) -> Self { - // `TokenKind` would impl `Copy` if it weren't for `Interpolated`. So - // for all other variants, this implementation of `clone` is just like - // a copy. This is faster than the `derive(Clone)` version which has a - // separate path for every variant. - match self { - Interpolated(nt) => Interpolated(nt.clone()), - _ => unsafe { std::ptr::read(self) }, - } - } -} - #[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub struct Token { pub kind: TokenKind, @@ -565,7 +531,6 @@ impl Token { pub fn uninterpolated_span(&self) -> Span { match self.kind { NtIdent(ident, _) | NtLifetime(ident, _) => ident.span, - Interpolated(ref nt) => nt.use_span(), _ => self.span, } } @@ -583,7 +548,7 @@ impl Token { } OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..) - | NtIdent(..) | Lifetime(..) | NtLifetime(..) | Interpolated(..) | Eof => false, + | NtIdent(..) | Lifetime(..) | NtLifetime(..) | Eof => false, } } @@ -614,7 +579,6 @@ impl Token { PathSep | // global path Lifetime(..) | // labeled loop Pound => true, // expression attributes - Interpolated(ref nt) => matches!(&**nt, NtBlock(..)), OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( MetaVarKind::Block | MetaVarKind::Expr { .. } | @@ -687,7 +651,6 @@ impl Token { match self.kind { OpenDelim(Delimiter::Brace) | Literal(..) | BinOp(Minus) => true, Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true, - Interpolated(ref nt) => matches!(&**nt, NtBlock(..)), OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( MetaVarKind::Expr { .. } | MetaVarKind::Block | MetaVarKind::Literal, ))) => true, @@ -815,31 +778,20 @@ impl Token { /// Is this a pre-parsed expression dropped into the token stream /// (which happens while parsing the result of macro expansion)? pub fn is_metavar_expr(&self) -> bool { - #[allow(irrefutable_let_patterns)] // FIXME: temporary - if let Interpolated(nt) = &self.kind - && let NtBlock(_) = &**nt - { - true - } else if matches!( + matches!( self.is_metavar_seq(), - Some(MetaVarKind::Expr { .. } | MetaVarKind::Literal | MetaVarKind::Path) - ) { - true - } else { - false - } + Some( + MetaVarKind::Expr { .. } + | MetaVarKind::Literal + | MetaVarKind::Path + | MetaVarKind::Block + ) + ) } - /// Is the token an interpolated block (`$b:block`)? - pub fn is_whole_block(&self) -> bool { - #[allow(irrefutable_let_patterns)] // FIXME: temporary - if let Interpolated(nt) = &self.kind - && let NtBlock(..) = &**nt - { - return true; - } - - false + /// Are we at a block from a metavar (`$b:block`)? + pub fn is_metavar_block(&self) -> bool { + matches!(self.is_metavar_seq(), Some(MetaVarKind::Block)) } /// Returns `true` if the token is either the `mut` or `const` keyword. @@ -864,7 +816,8 @@ impl Token { self.is_non_raw_ident_where(|id| id.name == kw) } - /// Returns `true` if the token is a given keyword, `kw` or if `case` is `Insensitive` and this token is an identifier equal to `kw` ignoring the case. + /// Returns `true` if the token is a given keyword, `kw` or if `case` is `Insensitive` and this + /// token is an identifier equal to `kw` ignoring the case. pub fn is_keyword_case(&self, kw: Symbol, case: Case) -> bool { self.is_keyword(kw) || (case == Case::Insensitive @@ -985,7 +938,7 @@ impl Token { Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | DotDotEq | Comma | Semi | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) | NtIdent(..) - | Lifetime(..) | NtLifetime(..) | Interpolated(..) | DocComment(..) | Eof => { + | Lifetime(..) | NtLifetime(..) | DocComment(..) | Eof => { return None; } }; @@ -1022,12 +975,6 @@ pub enum NtExprKind { Expr2021 { inferred: bool }, } -#[derive(Clone, Encodable, Decodable)] -/// For interpolation during macro expansion. -pub enum Nonterminal { - NtBlock(P), -} - #[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)] pub enum NonterminalKind { Item, @@ -1111,47 +1058,6 @@ impl fmt::Display for NonterminalKind { } } -impl Nonterminal { - pub fn use_span(&self) -> Span { - match self { - NtBlock(block) => block.span, - } - } - - pub fn descr(&self) -> &'static str { - match self { - NtBlock(..) => "block", - } - } -} - -impl PartialEq for Nonterminal { - fn eq(&self, _rhs: &Self) -> bool { - // FIXME: Assume that all nonterminals are not equal, we can't compare them - // correctly based on data from AST. This will prevent them from matching each other - // in macros. The comparison will become possible only when each nonterminal has an - // attached token stream from which it was parsed. - false - } -} - -impl fmt::Debug for Nonterminal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - NtBlock(..) => f.pad("NtBlock(..)"), - } - } -} - -impl HashStable for Nonterminal -where - CTX: crate::HashStableContext, -{ - fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) { - panic!("interpolated tokens should not be present in the HIR") - } -} - // Some types are used a lot. Make sure they don't unintentionally get bigger. #[cfg(target_pointer_width = "64")] mod size_asserts { @@ -1161,7 +1067,6 @@ mod size_asserts { // tidy-alphabetical-start static_assert_size!(Lit, 12); static_assert_size!(LitKind, 2); - static_assert_size!(Nonterminal, 8); static_assert_size!(Token, 24); static_assert_size!(TokenKind, 16); // tidy-alphabetical-end diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index e9cbdd53cbe2f..b9df9256393e5 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -24,7 +24,7 @@ use rustc_span::{sym, Span, SpanDecoder, SpanEncoder, Symbol, DUMMY_SP}; use crate::ast::AttrStyle; use crate::ast_traits::{HasAttrs, HasTokens}; -use crate::token::{self, Delimiter, InvisibleOrigin, Nonterminal, Token, TokenKind}; +use crate::token::{self, Delimiter, InvisibleOrigin, Token, TokenKind}; use crate::{AttrVec, Attribute}; /// Part of a `TokenStream`. @@ -288,11 +288,6 @@ pub struct AttrsTarget { } /// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s. -/// -/// The goal is for procedural macros to work with `TokenStream`s and `TokenTree`s -/// instead of a representation of the abstract syntax tree. -/// Today's `TokenTree`s can still contain AST via `token::Interpolated` for -/// backwards compatibility. #[derive(Clone, Debug, Default, Encodable, Decodable)] pub struct TokenStream(pub(crate) Lrc>); @@ -459,12 +454,6 @@ impl TokenStream { TokenStream::new(tts) } - pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream { - match nt { - Nonterminal::NtBlock(block) => TokenStream::from_ast(block), - } - } - fn flatten_token(token: &Token, spacing: Spacing) -> TokenTree { match token.kind { token::NtIdent(ident, is_raw) => { @@ -476,12 +465,6 @@ impl TokenStream { Delimiter::Invisible(InvisibleOrigin::FlattenToken), TokenStream::token_alone(token::Lifetime(ident.name, is_raw), ident.span), ), - token::Interpolated(ref nt) => TokenTree::Delimited( - DelimSpan::from_single(token.span), - DelimSpacing::new(Spacing::JointHidden, spacing), - Delimiter::Invisible(InvisibleOrigin::FlattenToken), - TokenStream::from_nonterminal_ast(&nt).flattened(), - ), _ => TokenTree::Token(token.clone(), spacing), } } @@ -499,10 +482,9 @@ impl TokenStream { pub fn flattened(&self) -> TokenStream { fn can_skip(stream: &TokenStream) -> bool { stream.trees().all(|tree| match tree { - TokenTree::Token(token, _) => !matches!( - token.kind, - token::NtIdent(..) | token::NtLifetime(..) | token::Interpolated(..) - ), + TokenTree::Token(token, _) => { + !matches!(token.kind, token::NtIdent(..) | token::NtLifetime(..)) + } TokenTree::Delimited(.., inner) => can_skip(inner), }) } diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs index cfcc28ba76fdd..136106952cfc1 100644 --- a/compiler/rustc_ast_pretty/src/pprust/mod.rs +++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs @@ -5,14 +5,10 @@ pub mod state; use std::borrow::Cow; use rustc_ast as ast; -use rustc_ast::token::{Nonterminal, Token, TokenKind}; +use rustc_ast::token::{Token, TokenKind}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; pub use state::{print_crate, AnnNode, Comments, PpAnn, PrintState, State}; -pub fn nonterminal_to_string(nt: &Nonterminal) -> String { - State::new().nonterminal_to_string(nt) -} - /// Print the token kind precisely, without converting `$crate` into its respective crate name. pub fn token_kind_to_string(tok: &TokenKind) -> Cow<'static, str> { State::new().token_kind_to_string(tok) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index b45028fc2500b..7ede2522e8f3b 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -11,9 +11,7 @@ use std::borrow::Cow; use ast::TraitBoundModifiers; use rustc_ast::attr::AttrIdGenerator; use rustc_ast::ptr::P; -use rustc_ast::token::{ - self, BinOpToken, CommentKind, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind, -}; +use rustc_ast::token::{self, BinOpToken, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind}; use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree}; use rustc_ast::util::classify; use rustc_ast::util::comments::{Comment, CommentStyle}; @@ -879,14 +877,6 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere } } - fn nonterminal_to_string(&self, nt: &Nonterminal) -> String { - // We extract the token stream from the AST fragment and pretty print - // it, rather than using AST pretty printing, because `Nonterminal` is - // slated for removal in #124141. (This method will also then be - // removed.) - self.tts_to_string(&TokenStream::from_nonterminal_ast(nt)) - } - /// Print the token kind precisely, without converting `$crate` into its respective crate name. fn token_kind_to_string(&self, tok: &TokenKind) -> Cow<'static, str> { self.token_kind_to_string_ext(tok, None) @@ -961,8 +951,6 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere doc_comment_to_string(comment_kind, attr_style, data).into() } token::Eof => "".into(), - - token::Interpolated(ref nt) => self.nonterminal_to_string(&nt).into(), } } diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index e7c492b59438f..364e987dad993 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -173,11 +173,11 @@ impl CfgEval<'_> { _ => unreachable!(), }; - // 'Flatten' all nonterminals (i.e. `TokenKind::Interpolated`) + // 'Flatten' all nonterminals (i.e. `TokenKind::Nt{Ident,Lifetime}`) // to `None`-delimited groups containing the corresponding tokens. This // is normally delayed until the proc-macro server actually needs to - // provide a `TokenKind::Interpolated` to a proc-macro. We do this earlier, - // so that we can handle cases like: + // provide tokens to a proc-macro. We do this earlier, so that we can + // handle cases like: // // ```rust // #[cfg_eval] #[cfg] $item diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index b0d3fecbb479b..f769fee9555ff 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -214,13 +214,7 @@ impl<'a> StripUnconfigured<'a> { Some(AttrTokenTree::Delimited(sp, spacing, delim, inner)) } AttrTokenTree::Token( - Token { - kind: - TokenKind::NtIdent(..) - | TokenKind::NtLifetime(..) - | TokenKind::Interpolated(..), - .. - }, + Token { kind: TokenKind::NtIdent(..) | TokenKind::NtLifetime(..), .. }, _, ) => { panic!("Nonterminal should have been flattened: {:?}", tree); diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 3b39968845193..15927681695f0 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -67,9 +67,7 @@ pub(super) fn failed_to_match_macro( } if let MatcherLoc::Token { token: expected_token } = &remaining_matcher - && (matches!(expected_token.kind, TokenKind::Interpolated(_)) - || matches!(token.kind, TokenKind::Interpolated(_)) - || matches!(expected_token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_))) + && (matches!(expected_token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_))) || matches!(token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_)))) { err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens"); diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 21e1f11e5dabf..398248ff53da2 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -289,7 +289,9 @@ pub(super) fn transcribe<'a>( let tt = match cur_matched { MatchedSingle(ParseNtResult::Tt(tt)) => { // `tt`s are emitted into the output stream directly as "raw tokens", - // without wrapping them into groups. + // without wrapping them into groups. Other variables are emitted into + // the output stream as groups with `Delimiter::Invisible` to maintain + // parsing priorities. maybe_use_metavar_location(psess, &stack, sp, tt, &mut marker) } MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => { @@ -305,6 +307,9 @@ pub(super) fn transcribe<'a>( MatchedSingle(ParseNtResult::Item(item)) => { mk_delimited(MetaVarKind::Item, TokenStream::from_ast(item)) } + MatchedSingle(ParseNtResult::Block(block)) => { + mk_delimited(MetaVarKind::Block, TokenStream::from_ast(block)) + } MatchedSingle(ParseNtResult::Stmt(stmt)) => { let stream = if let StmtKind::Empty = stmt.kind { // FIXME: Properly collect tokens for empty statements. @@ -352,13 +357,6 @@ pub(super) fn transcribe<'a>( MatchedSingle(ParseNtResult::Vis(vis)) => { mk_delimited(MetaVarKind::Vis, TokenStream::from_ast(vis)) } - MatchedSingle(ParseNtResult::Nt(nt)) => { - // Other variables are emitted into the output stream as groups with - // `Delimiter::Invisible` to maintain parsing priorities. - // `Interpolated` is currently used for such groups in rustc parser. - marker.visit_span(&mut sp); - TokenTree::token_alone(token::Interpolated(nt.clone()), sp) - } MatchedSeq(..) => { // We were unable to descend far enough. This is an error. return Err(dcx.create_err(VarStillRepeating { span: sp, ident })); diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index db6293ff3e6af..6b80705be91a3 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -292,15 +292,6 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec { - let stream = TokenStream::from_nonterminal_ast(&nt); - trees.push(TokenTree::Group(Group { - delimiter: pm::Delimiter::None, - stream: Some(stream), - span: DelimSpan::from_single(span), - })) - } - OpenDelim(..) | CloseDelim(..) => unreachable!(), Eof => unreachable!(), } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index fa87fb86de849..9a02a3167fc71 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -676,9 +676,7 @@ impl<'a> Parser<'a> { /// Returns the span of expr if it was not interpolated, or the span of the interpolated token. fn interpolated_or_expr_span(&self, expr: &Expr) -> Span { match self.prev_token.kind { - TokenKind::NtIdent(..) | TokenKind::NtLifetime(..) | TokenKind::Interpolated(..) => { - self.prev_token.span - } + TokenKind::NtIdent(..) | TokenKind::NtLifetime(..) => self.prev_token.span, TokenKind::CloseDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => { // `expr.span` is the interpolated span, because invisible open // and close delims both get marked with the same span, one @@ -1396,15 +1394,7 @@ impl<'a> Parser<'a> { maybe_recover_from_interpolated_ty_qpath!(self, true); let span = self.token.span; - if let token::Interpolated(nt) = &self.token.kind { - match &**nt { - token::NtBlock(block) => { - let block = block.clone(); - self.bump(); - return Ok(self.mk_expr(self.prev_token.span, ExprKind::Block(block, None))); - } - }; - } else if let Some(expr) = self.eat_metavar_seq_with_matcher( + if let Some(expr) = self.eat_metavar_seq_with_matcher( |mv_kind| matches!(mv_kind, MetaVarKind::Expr { .. }), |this| { let expr = this.parse_expr(); @@ -1423,9 +1413,13 @@ impl<'a> Parser<'a> { self.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus()) { return Ok(lit); - } else if let Some(path) = self.eat_metavar_seq(MetaVarKind::Path, |this| { - this.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type)) - }) { + } else if let Some(block) = + self.eat_metavar_seq(MetaVarKind::Block, |this| this.parse_block()) + { + return Ok(self.mk_expr(span, ExprKind::Block(block, None))); + } else if let Some(path) = + self.eat_metavar_seq(MetaVarKind::Path, |this| this.parse_path(PathStyle::Type)) + { return Ok(self.mk_expr(span, ExprKind::Path(None, path))); } @@ -1678,7 +1672,7 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(kw::Loop) { self.parse_expr_loop(label, lo) } else if self.check_noexpect(&token::OpenDelim(Delimiter::Brace)) - || self.token.is_whole_block() + || self.token.is_metavar_block() { self.parse_expr_block(label, lo, BlockCheckMode::Default) } else if !ate_colon @@ -2348,7 +2342,7 @@ impl<'a> Parser<'a> { } } - if self.token.is_whole_block() { + if self.token.is_metavar_block() { self.dcx().emit_err(errors::InvalidBlockMacroSegment { span: self.token.span, context: lo.to(self.token.span), @@ -3454,7 +3448,7 @@ impl<'a> Parser<'a> { self.token.is_keyword(kw::Do) && self.is_keyword_ahead(1, &[kw::Catch]) && self - .look_ahead(2, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block()) + .look_ahead(2, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block()) && !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) } @@ -3465,7 +3459,7 @@ impl<'a> Parser<'a> { fn is_try_block(&self) -> bool { self.token.is_keyword(kw::Try) && self - .look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block()) + .look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block()) && self.token.uninterpolated_span().at_least_rust_2018() } @@ -3499,12 +3493,12 @@ impl<'a> Parser<'a> { // `async move {` self.is_keyword_ahead(lookahead + 1, &[kw::Move]) && self.look_ahead(lookahead + 2, |t| { - *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block() + *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block() }) ) || ( // `async {` self.look_ahead(lookahead + 1, |t| { - *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block() + *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block() }) )) } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 3e0e81f847532..1ae38cba17419 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2461,7 +2461,7 @@ impl<'a> Parser<'a> { self.expect_semi()?; *sig_hi = self.prev_token.span; (AttrVec::new(), None) - } else if self.check(&token::OpenDelim(Delimiter::Brace)) || self.token.is_whole_block() { + } else if self.check(&token::OpenDelim(Delimiter::Brace)) || self.token.is_metavar_block() { self.parse_block_common(self.token.span, BlockCheckMode::Default, false) .map(|(attrs, body)| (attrs, Some(body)))? } else if self.token == token::Eq { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 3568184ee9b7b..74d88a59a19aa 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -22,8 +22,8 @@ pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; use path::PathStyle; use rustc_ast::ptr::P; use rustc_ast::token::{ - self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, Nonterminal, NtExprKind, NtPatKind, - Token, TokenKind, + self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, NtExprKind, NtPatKind, Token, + TokenKind, }; use rustc_ast::tokenstream::{ AttrsTarget, DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree, TokenTreeCursor, @@ -36,7 +36,6 @@ use rustc_ast::{ }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, Diag, FatalError, MultiSpan, PResult}; use rustc_index::interval::IntervalSet; use rustc_session::parse::ParseSess; @@ -97,21 +96,6 @@ pub enum ForceCollect { No, } -#[macro_export] -macro_rules! maybe_whole { - ($p:expr, $constructor:ident, |$x:ident| $e:expr) => { - #[allow(irrefutable_let_patterns)] // FIXME: temporary - if let token::Interpolated(nt) = &$p.token.kind - && let token::$constructor(x) = &**nt - { - #[allow(unused_mut)] - let mut $x = x.clone(); - $p.bump(); - return Ok($e); - } - }; -} - /// If the next tokens are ill-formed `$ty::` recover them as `<$ty>::`. #[macro_export] macro_rules! maybe_recover_from_interpolated_ty_qpath { @@ -451,7 +435,6 @@ pub fn token_descr(token: &Token) -> String { (Some(MetaVar(kind)), _) => format!("`{kind}` metavariable"), (None, TokenKind::NtIdent(..)) => format!("identifier `{s}`"), (None, TokenKind::NtLifetime(..)) => format!("lifetime `{s}`"), - (None, TokenKind::Interpolated(node)) => format!("{} `{s}`", node.descr()), (None, _) => format!("`{s}`"), } } @@ -823,8 +806,10 @@ impl<'a> Parser<'a> { fn check_inline_const(&self, dist: usize) -> bool { self.is_keyword_ahead(dist, &[kw::Const]) && self.look_ahead(dist + 1, |t| match &t.kind { - token::Interpolated(nt) => matches!(&**nt, token::NtBlock(..)), token::OpenDelim(Delimiter::Brace) => true, + token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( + MetaVarKind::Block, + ))) => true, _ => false, }) } @@ -1377,7 +1362,7 @@ impl<'a> Parser<'a> { // Avoid const blocks and const closures to be parsed as const items if (self.check_const_closure() == is_closure) && !self - .look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block()) + .look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block()) && self.eat_keyword_case(kw::Const, case) { Const::Yes(self.prev_token.uninterpolated_span()) @@ -1716,7 +1701,6 @@ impl<'a> Parser<'a> { pub fn uninterpolated_token_span(&self) -> Span { match &self.token.kind { - token::Interpolated(nt) => nt.use_span(), token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => { self.look_ahead(1, |t| t.span) } @@ -1773,6 +1757,7 @@ pub enum ParseNtResult { Ident(Ident, IdentIsRaw), Lifetime(Ident, IdentIsRaw), Item(P), + Block(P), Stmt(P), Pat(P, NtPatKind), Expr(P, NtExprKind), @@ -1781,7 +1766,4 @@ pub enum ParseNtResult { Meta(P), Path(P), Vis(P), - - /// This variant will eventually be removed, along with `Token::Interpolate`. - Nt(Lrc), } diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 897afa99103de..ca8932ebaf468 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -1,13 +1,7 @@ use rustc_ast::ptr::P; -use rustc_ast::token::Nonterminal::*; use rustc_ast::token::NtExprKind::*; use rustc_ast::token::NtPatKind::*; -use rustc_ast::token::{ - self, Delimiter, InvisibleOrigin, MetaVarKind, Nonterminal, NonterminalKind, Token, -}; -use rustc_ast::HasTokens; -use rustc_ast_pretty::pprust; -use rustc_data_structures::sync::Lrc; +use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, NonterminalKind, Token}; use rustc_errors::PResult; use rustc_span::symbol::{kw, Ident}; @@ -45,13 +39,6 @@ impl<'a> Parser<'a> { } } - /// Old variant of `may_be_ident`. Being phased out. - fn nt_may_be_ident(nt: &Nonterminal) -> bool { - match nt { - NtBlock(_) => false, - } - } - match kind { // `expr_2021` and earlier NonterminalKind::Expr(Expr2021 { .. }) => { @@ -83,16 +70,12 @@ impl<'a> Parser<'a> { | token::Ident(..) | token::NtIdent(..) | token::NtLifetime(..) - | token::Interpolated(_) | token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => true, _ => token.can_begin_type(), }, NonterminalKind::Block => match &token.kind { token::OpenDelim(Delimiter::Brace) => true, token::NtLifetime(..) => true, - token::Interpolated(nt) => match &**nt { - NtBlock(_) => true, - }, token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k { MetaVarKind::Block | MetaVarKind::Stmt @@ -112,7 +95,6 @@ impl<'a> Parser<'a> { }, NonterminalKind::Path | NonterminalKind::Meta => match &token.kind { token::PathSep | token::Ident(..) | token::NtIdent(..) => true, - token::Interpolated(nt) => nt_may_be_ident(nt), token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => { may_be_ident(*kind) } @@ -137,61 +119,51 @@ impl<'a> Parser<'a> { // which requires having captured tokens available. Since we cannot determine // in advance whether or not a proc-macro will be (transitively) invoked, // we always capture tokens for any `Nonterminal` which needs them. - let mut nt = match kind { + match kind { // Note that TT is treated differently to all the others. - NonterminalKind::TT => return Ok(ParseNtResult::Tt(self.parse_token_tree())), + NonterminalKind::TT => Ok(ParseNtResult::Tt(self.parse_token_tree())), NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? { - Some(item) => return Ok(ParseNtResult::Item(item)), - None => { - return Err(self - .dcx() - .create_err(UnexpectedNonterminal::Item(self.token.span))); - } + Some(item) => Ok(ParseNtResult::Item(item)), + None => Err(self.dcx().create_err(UnexpectedNonterminal::Item(self.token.span))), }, NonterminalKind::Block => { // While a block *expression* may have attributes (e.g. `#[my_attr] { ... }`), // the ':block' matcher does not support them - NtBlock(self.collect_tokens_no_attrs(|this| this.parse_block())?) + Ok(ParseNtResult::Block(self.collect_tokens_no_attrs(|this| this.parse_block())?)) } NonterminalKind::Stmt => match self.parse_stmt(ForceCollect::Yes)? { - Some(stmt) => return Ok(ParseNtResult::Stmt(P(stmt))), + Some(stmt) => Ok(ParseNtResult::Stmt(P(stmt))), None => { - return Err(self - .dcx() - .create_err(UnexpectedNonterminal::Statement(self.token.span))); + Err(self.dcx().create_err(UnexpectedNonterminal::Statement(self.token.span))) } }, - NonterminalKind::Pat(pat_kind) => { - return Ok(ParseNtResult::Pat( - self.collect_tokens_no_attrs(|this| match pat_kind { - PatParam { .. } => this.parse_pat_no_top_alt(None, None), - PatWithOr => this.parse_pat_allow_top_alt( - None, - RecoverComma::No, - RecoverColon::No, - CommaRecoveryMode::EitherTupleOrPipe, - ), - })?, - pat_kind, - )); - } + NonterminalKind::Pat(pat_kind) => Ok(ParseNtResult::Pat( + self.collect_tokens_no_attrs(|this| match pat_kind { + PatParam { .. } => this.parse_pat_no_top_alt(None, None), + PatWithOr => this.parse_pat_allow_top_alt( + None, + RecoverComma::No, + RecoverColon::No, + CommaRecoveryMode::EitherTupleOrPipe, + ), + })?, + pat_kind, + )), NonterminalKind::Expr(expr_kind) => { - return Ok(ParseNtResult::Expr(self.parse_expr_force_collect()?, expr_kind)); + Ok(ParseNtResult::Expr(self.parse_expr_force_collect()?, expr_kind)) } NonterminalKind::Literal => { // The `:literal` matcher does not support attributes. - return Ok(ParseNtResult::Literal( + Ok(ParseNtResult::Literal( self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?, - )); - } - NonterminalKind::Ty => { - return Ok(ParseNtResult::Ty( - self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?, - )); + )) } - // this could be handled like a token, since it is one + NonterminalKind::Ty => Ok(ParseNtResult::Ty( + self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?, + )), + // This could be handled like a token, since it is one. NonterminalKind::Ident => { - return if let Some((ident, is_raw)) = get_macro_ident(&self.token) { + if let Some((ident, is_raw)) = get_macro_ident(&self.token) { self.bump(); Ok(ParseNtResult::Ident(ident, is_raw)) } else { @@ -199,25 +171,22 @@ impl<'a> Parser<'a> { span: self.token.span, token: self.token.clone(), })) - }; - } - NonterminalKind::Path => { - return Ok(ParseNtResult::Path(P( - self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))? - ))); + } } + NonterminalKind::Path => Ok(ParseNtResult::Path(P( + self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))? + ))), NonterminalKind::Meta => { - return Ok(ParseNtResult::Meta(P(self.parse_attr_item(ForceCollect::Yes)?))); + Ok(ParseNtResult::Meta(P(self.parse_attr_item(ForceCollect::Yes)?))) } NonterminalKind::Vis => { - return Ok(ParseNtResult::Vis(P(self.collect_tokens_no_attrs(|this| { - this.parse_visibility(FollowedByType::Yes) - })?))); + Ok(ParseNtResult::Vis(P(self + .collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?))) } NonterminalKind::Lifetime => { // We want to keep `'keyword` parsing, just like `keyword` is still // an ident for nonterminal purposes. - return if let Some((ident, is_raw)) = self.token.lifetime() { + if let Some((ident, is_raw)) = self.token.lifetime() { self.bump(); Ok(ParseNtResult::Lifetime(ident, is_raw)) } else { @@ -225,21 +194,9 @@ impl<'a> Parser<'a> { span: self.token.span, token: self.token.clone(), })) - }; + } } - }; - - // If tokens are supported at all, they should be collected. - if matches!(nt.tokens_mut(), Some(None)) { - panic!( - "Missing tokens for nt {:?} at {:?}: {:?}", - nt, - nt.use_span(), - pprust::nonterminal_to_string(&nt) - ); } - - Ok(ParseNtResult::Nt(Lrc::new(nt))) } } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index deb57c239105d..b9ea4f454528b 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -23,8 +23,7 @@ use super::{ AttrWrapper, BlockMode, FnParseMode, ForceCollect, Parser, Restrictions, SemiColonMode, Trailing, UsePreAttrPos, }; -use crate::errors::MalformedLoopLabel; -use crate::{errors, maybe_whole}; +use crate::errors::{self, MalformedLoopLabel}; impl<'a> Parser<'a> { /// Parses a statement. This stops just before trailing semicolons on everything but items. @@ -558,7 +557,9 @@ impl<'a> Parser<'a> { blk_mode: BlockCheckMode, can_be_struct_literal: bool, ) -> PResult<'a, (AttrVec, P)> { - maybe_whole!(self, NtBlock, |block| (AttrVec::new(), block)); + if let Some(block) = self.eat_metavar_seq(MetaVarKind::Block, |this| this.parse_block()) { + return Ok((AttrVec::new(), block)); + } let maybe_ident = self.prev_token.clone(); self.maybe_recover_unexpected_block_label(); @@ -734,7 +735,7 @@ impl<'a> Parser<'a> { { if self.token == token::Colon && self.look_ahead(1, |token| { - token.is_whole_block() + token.is_metavar_block() || matches!( token.kind, token::Ident( diff --git a/tests/ui/macros/macro-as-fn-body.rs b/tests/ui/macros/macro-as-fn-body.rs index e0542edc2a521..188c7f7f728c9 100644 --- a/tests/ui/macros/macro-as-fn-body.rs +++ b/tests/ui/macros/macro-as-fn-body.rs @@ -1,7 +1,7 @@ // //@ run-pass // -// Description - ensure Interpolated blocks can act as valid function bodies +// Description - ensure block metavariables can act as valid function bodies // Covered cases: free functions, struct methods, and default trait functions macro_rules! def_fn { From 4f585b9972d66a7f7eda4aa4edb54890b0f74dfc Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 16 May 2024 09:22:37 +1000 Subject: [PATCH 14/18] Impl `Copy` for `Token` and `TokenKind`. --- compiler/rustc_ast/src/token.rs | 4 ++-- compiler/rustc_ast/src/tokenstream.rs | 2 +- compiler/rustc_expand/src/mbe/diagnostics.rs | 2 +- compiler/rustc_expand/src/mbe/macro_parser.rs | 4 ++-- compiler/rustc_expand/src/mbe/macro_rules.rs | 8 ++++---- compiler/rustc_expand/src/mbe/quoted.rs | 4 ++-- compiler/rustc_expand/src/mbe/transcribe.rs | 4 ++-- .../rustc_parse/src/lexer/unicode_chars.rs | 2 +- .../rustc_parse/src/parser/attr_wrapper.rs | 4 ++-- .../rustc_parse/src/parser/diagnostics.rs | 12 +++++------ compiler/rustc_parse/src/parser/expr.rs | 20 +++++++++---------- compiler/rustc_parse/src/parser/item.rs | 5 ++--- compiler/rustc_parse/src/parser/mod.rs | 10 +++++----- .../rustc_parse/src/parser/nonterminal.rs | 4 ++-- compiler/rustc_parse/src/parser/pat.rs | 6 +++--- compiler/rustc_parse/src/parser/path.rs | 4 ++-- compiler/rustc_parse/src/parser/stmt.rs | 2 +- compiler/rustc_parse/src/parser/ty.rs | 4 ++-- src/tools/rustfmt/src/macros.rs | 14 ++++++------- 19 files changed, 57 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index d1dcc34aa8068..3626723889494 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -345,7 +345,7 @@ impl From for bool { } } -#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] +#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub enum TokenKind { /* Expression-operator symbols. */ /// `=` @@ -443,7 +443,7 @@ pub enum TokenKind { Eof, } -#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] +#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub struct Token { pub kind: TokenKind, pub span: Span, diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index b9df9256393e5..99198c75480de 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -465,7 +465,7 @@ impl TokenStream { Delimiter::Invisible(InvisibleOrigin::FlattenToken), TokenStream::token_alone(token::Lifetime(ident.name, is_raw), ident.span), ), - _ => TokenTree::Token(token.clone(), spacing), + _ => TokenTree::Token(*token, spacing), } } diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 15927681695f0..f25e943f11931 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -161,7 +161,7 @@ impl<'dcx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'dcx, 'match .map_or(true, |failure| failure.is_better_position(*approx_position)) { self.best_failure = Some(BestFailure { - token: token.clone(), + token: *token, position_in_tokenstream: *approx_position, msg, remaining_matcher: self diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 9c4a5e63f17c1..bf626ded2755e 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -180,7 +180,7 @@ pub(super) fn compute_locs(matcher: &[TokenTree]) -> Vec { for tt in tts { match tt { TokenTree::Token(token) => { - locs.push(MatcherLoc::Token { token: token.clone() }); + locs.push(MatcherLoc::Token { token: *token }); } TokenTree::Delimited(span, _, delimited) => { let open_token = Token::new(token::OpenDelim(delimited.delim), span.open); @@ -649,7 +649,7 @@ impl TtParser { // There are no possible next positions AND we aren't waiting for the black-box // parser: syntax error. return Failure(T::build_failure( - parser.token.clone(), + parser.token, parser.approx_token_stream_pos(), "no rules expected this token in macro call", )); diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 10a00d5578801..cf67db59fc4d0 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -796,7 +796,7 @@ impl<'tt> FirstSets<'tt> { // token could be the separator token itself. if let (Some(sep), true) = (&seq_rep.separator, subfirst.maybe_empty) { - first.add_one_maybe(TtHandle::from_token(sep.clone())); + first.add_one_maybe(TtHandle::from_token(*sep)); } // Reverse scan: Sequence comes before `first`. @@ -859,7 +859,7 @@ impl<'tt> FirstSets<'tt> { // If the sequence contents can be empty, then the first // token could be the separator token itself. if let (Some(sep), true) = (&seq_rep.separator, subfirst.maybe_empty) { - first.add_one_maybe(TtHandle::from_token(sep.clone())); + first.add_one_maybe(TtHandle::from_token(*sep)); } assert!(first.maybe_empty); @@ -935,7 +935,7 @@ impl<'tt> Clone for TtHandle<'tt> { // This variant *must* contain a `mbe::TokenTree::Token`, and not // any other variant of `mbe::TokenTree`. TtHandle::Token(mbe::TokenTree::Token(tok)) => { - TtHandle::Token(mbe::TokenTree::Token(tok.clone())) + TtHandle::Token(mbe::TokenTree::Token(*tok)) } _ => unreachable!(), @@ -1111,7 +1111,7 @@ fn check_matcher_core<'tt>( let mut new; let my_suffix = if let Some(sep) = &seq_rep.separator { new = suffix_first.clone(); - new.add_one_maybe(TtHandle::from_token(sep.clone())); + new.add_one_maybe(TtHandle::from_token(*sep)); &new } else { &suffix_first diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index c1e8a9c3096aa..4d5fbb4a23bb8 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -312,7 +312,7 @@ fn parse_tree<'a>( } // `tree` is an arbitrary token. Keep it. - tokenstream::TokenTree::Token(token, _) => TokenTree::Token(token.clone()), + tokenstream::TokenTree::Token(token, _) => TokenTree::Token(*token), // `tree` is the beginning of a delimited set of tokens (e.g., `(` or `{`). We need to // descend into the delimited set and further parse it. @@ -350,7 +350,7 @@ fn parse_kleene_op<'a>( match input.next() { Some(tokenstream::TokenTree::Token(token, _)) => match kleene_op(token) { Some(op) => Ok(Ok((op, token.span))), - None => Ok(Err(token.clone())), + None => Ok(Err(*token)), }, tree => Err(tree.map_or(span, tokenstream::TokenTree::span)), } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 398248ff53da2..f71a9e63fbf23 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -163,7 +163,7 @@ pub(super) fn transcribe<'a>( if repeat_idx < repeat_len { frame.idx = 0; if let Some(sep) = sep { - result.push(TokenTree::Token(sep.clone(), Spacing::Alone)); + result.push(TokenTree::Token(*sep, Spacing::Alone)); } continue; } @@ -404,7 +404,7 @@ pub(super) fn transcribe<'a>( // Nothing much to do here. Just push the token to the result, being careful to // preserve syntax context. mbe::TokenTree::Token(token) => { - let mut token = token.clone(); + let mut token = *token; mut_visit::visit_token(&mut marker, &mut token); let tt = TokenTree::Token(token, Spacing::Alone); result.push(tt); diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index d78b3664b1ee8..0d1ea767ea7ee 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -377,7 +377,7 @@ pub(super) fn check_for_substitution( ascii_name, }) }; - (token.clone(), sugg) + (*token, sugg) } /// Extract string if found at current position with given delimiters diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 9d73eb4cccf22..066bf48b9f794 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -120,7 +120,7 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { // produce an empty `TokenStream` if no calls were made, and omit the // final token otherwise. let mut cursor_snapshot = self.cursor_snapshot.clone(); - let tokens = iter::once(FlatToken::Token(self.start_token.clone())) + let tokens = iter::once(FlatToken::Token(self.start_token)) .chain(iter::repeat_with(|| FlatToken::Token(cursor_snapshot.next()))) .take(self.num_calls as usize); @@ -173,7 +173,7 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { impl<'a> Parser<'a> { pub(super) fn collect_pos(&self) -> CollectPos { CollectPos { - start_token: (self.token.clone(), self.token_spacing), + start_token: (self.token, self.token_spacing), cursor_snapshot: self.token_cursor.clone(), start_pos: self.num_bump_calls, } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index ff904d9237d25..9ac65fb23fea3 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -320,7 +320,7 @@ impl<'a> Parser<'a> { let mut recovered_ident = None; // we take this here so that the correct original token is retained in // the diagnostic, regardless of eager recovery. - let bad_token = self.token.clone(); + let bad_token = self.token; // suggest prepending a keyword in identifier position with `r#` let suggest_raw = if let Some((ident, IdentIsRaw::No)) = self.token.ident() @@ -380,7 +380,7 @@ impl<'a> Parser<'a> { // if the previous token is a valid keyword // that might use a generic, then suggest a correct // generic placement (later on) - let maybe_keyword = self.prev_token.clone(); + let maybe_keyword = self.prev_token; if valid_prev_keywords.into_iter().any(|x| maybe_keyword.is_keyword(x)) { // if we have a valid keyword, attempt to parse generics // also obtain the keywords symbol @@ -496,7 +496,7 @@ impl<'a> Parser<'a> { false } - if **token != parser::TokenType::Token(self.token.kind.clone()) { + if **token != parser::TokenType::Token(self.token.kind) { let eq = is_ident_eq_keyword(&self.token.kind, &token); // If the suggestion is a keyword and the found token is an ident, // the content of which are equal to the suggestion's content, @@ -560,7 +560,7 @@ impl<'a> Parser<'a> { // let y = 42; let guar = self.dcx().emit_err(ExpectedSemi { span: self.token.span, - token: self.token.clone(), + token: self.token, unexpected_token_label: None, sugg: ExpectedSemiSugg::ChangeToSemi(self.token.span), }); @@ -585,7 +585,7 @@ impl<'a> Parser<'a> { let span = self.prev_token.span.shrink_to_hi(); let guar = self.dcx().emit_err(ExpectedSemi { span, - token: self.token.clone(), + token: self.token, unexpected_token_label: Some(self.token.span), sugg: ExpectedSemiSugg::AddSemi(span), }); @@ -827,7 +827,7 @@ impl<'a> Parser<'a> { let span = self.prev_token.span.shrink_to_hi(); let mut err = self.dcx().create_err(ExpectedSemi { span, - token: self.token.clone(), + token: self.token, unexpected_token_label: Some(self.token.span), sugg: ExpectedSemiSugg::AddSemi(span), }); diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 9a02a3167fc71..3d38c1aed2972 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -381,7 +381,7 @@ impl<'a> Parser<'a> { fn error_found_expr_would_be_stmt(&self, lhs: &Expr) { self.dcx().emit_err(errors::FoundExprWouldBeStmt { span: self.token.span, - token: self.token.clone(), + token: self.token, suggestion: ExprParenthesesNeeded::surrounding(lhs.span), }); } @@ -456,7 +456,7 @@ impl<'a> Parser<'a> { cur_op_span: Span, ) -> PResult<'a, P> { let rhs = if self.is_at_start_of_range_notation_rhs() { - let maybe_lt = self.token.clone(); + let maybe_lt = self.token; let attrs = self.parse_outer_attributes()?; Some( self.parse_expr_assoc_with(prec + 1, attrs) @@ -650,7 +650,7 @@ impl<'a> Parser<'a> { /// Recover on `not expr` in favor of `!expr`. fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> { - let negated_token = self.look_ahead(1, |t| t.clone()); + let negated_token = self.look_ahead(1, |t| *t); let sub_diag = if negated_token.is_numeric_lit() { errors::NotAsNegationOperatorSub::SuggestNotBitwise @@ -1613,7 +1613,7 @@ impl<'a> Parser<'a> { } fn parse_expr_path_start(&mut self) -> PResult<'a, P> { - let maybe_eq_tok = self.prev_token.clone(); + let maybe_eq_tok = self.prev_token; let (qself, path) = if self.eat_lt() { let lt_span = self.prev_token.span; let (qself, path) = self.parse_qpath(PathStyle::Expr).map_err(|mut err| { @@ -2059,7 +2059,7 @@ impl<'a> Parser<'a> { &mut self, mk_lit_char: impl FnOnce(Symbol, Span) -> L, ) -> PResult<'a, L> { - let token = self.token.clone(); + let token = self.token; let err = |self_: &Self| { let msg = format!("unexpected token: {}", super::token_descr(&token)); self_.dcx().struct_span_err(token.span, msg) @@ -2367,7 +2367,7 @@ impl<'a> Parser<'a> { fn parse_expr_closure(&mut self) -> PResult<'a, P> { let lo = self.token.span; - let before = self.prev_token.clone(); + let before = self.prev_token; let binder = if self.check_keyword(kw::For) { let lo = self.token.span; let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?; @@ -2398,8 +2398,8 @@ impl<'a> Parser<'a> { FnRetTy::Default(_) => { let restrictions = self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET; - let prev = self.prev_token.clone(); - let token = self.token.clone(); + let prev = self.prev_token; + let token = self.token; let attrs = self.parse_outer_attributes()?; match self.parse_expr_res(restrictions, attrs) { Ok((expr, _)) => expr, @@ -2598,7 +2598,7 @@ impl<'a> Parser<'a> { } } else { let attrs = self.parse_outer_attributes()?; // For recovery. - let maybe_fatarrow = self.token.clone(); + let maybe_fatarrow = self.token; let block = if self.check(&token::OpenDelim(Delimiter::Brace)) { self.parse_block()? } else if let Some(block) = recover_block_from_condition(self) { @@ -3803,7 +3803,7 @@ impl<'a> Parser<'a> { return Err(this.dcx().create_err(errors::ExpectedStructField { span: this.look_ahead(1, |t| t.span), ident_span: this.token.span, - token: this.look_ahead(1, |t| t.clone()), + token: this.look_ahead(1, |t| *t), })); } let (ident, expr) = if is_shorthand { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 1ae38cba17419..4dc253f32d33b 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1696,8 +1696,7 @@ impl<'a> Parser<'a> { self.expect_semi()?; body } else { - let err = - errors::UnexpectedTokenAfterStructName::new(self.token.span, self.token.clone()); + let err = errors::UnexpectedTokenAfterStructName::new(self.token.span, self.token); return Err(self.dcx().create_err(err)); }; @@ -2227,7 +2226,7 @@ impl<'a> Parser<'a> { || self.token.is_keyword(kw::Union)) && self.look_ahead(1, |t| t.is_ident()) { - let kw_token = self.token.clone(); + let kw_token = self.token; let kw_str = pprust::token_to_string(&kw_token); let item = self.parse_item(ForceCollect::No)?; let mut item = item.unwrap().span; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 74d88a59a19aa..5164fb39291df 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -290,12 +290,12 @@ impl TokenCursor { // below can be removed. if let Some(tree) = self.tree_cursor.next_ref() { match tree { - &TokenTree::Token(ref token, spacing) => { + &TokenTree::Token(token, spacing) => { debug_assert!(!matches!( token.kind, token::OpenDelim(_) | token::CloseDelim(_) )); - return (token.clone(), spacing); + return (token, spacing); } &TokenTree::Delimited(sp, spacing, delim, ref tts) => { let trees = tts.clone().into_trees(); @@ -587,7 +587,7 @@ impl<'a> Parser<'a> { fn check(&mut self, tok: &TokenKind) -> bool { let is_present = self.token == *tok; if !is_present { - self.expected_tokens.push(TokenType::Token(tok.clone())); + self.expected_tokens.push(TokenType::Token(*tok)); } is_present } @@ -1484,7 +1484,7 @@ impl<'a> Parser<'a> { _ => { let prev_spacing = self.token_spacing; self.bump(); - TokenTree::Token(self.prev_token.clone(), prev_spacing) + TokenTree::Token(self.prev_token, prev_spacing) } } } @@ -1664,7 +1664,7 @@ impl<'a> Parser<'a> { dbg_fmt.field("prev_token", &parser.prev_token); let mut tokens = vec![]; for i in 0..*lookahead { - let tok = parser.look_ahead(i, |tok| tok.kind.clone()); + let tok = parser.look_ahead(i, |tok| tok.kind); let is_eof = tok == TokenKind::Eof; tokens.push(tok); if is_eof { diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index ca8932ebaf468..7bd586179d5ca 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -169,7 +169,7 @@ impl<'a> Parser<'a> { } else { Err(self.dcx().create_err(UnexpectedNonterminal::Ident { span: self.token.span, - token: self.token.clone(), + token: self.token, })) } } @@ -192,7 +192,7 @@ impl<'a> Parser<'a> { } else { Err(self.dcx().create_err(UnexpectedNonterminal::Lifetime { span: self.token.span, - token: self.token.clone(), + token: self.token, })) } } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 3379799d83591..ff223066e84aa 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -333,7 +333,7 @@ impl<'a> Parser<'a> { self.dcx().emit_err(TrailingVertNotAllowed { span: self.token.span, start: lo, - token: self.token.clone(), + token: self.token, note_double_vert: matches!(self.token.kind, token::OrOr), }); self.bump(); @@ -1256,8 +1256,8 @@ impl<'a> Parser<'a> { etc = PatFieldsRest::Rest; let mut etc_sp = self.token.span; if first_etc_and_maybe_comma_span.is_none() { - if let Some(comma_tok) = self - .look_ahead(1, |t| if *t == token::Comma { Some(t.clone()) } else { None }) + if let Some(comma_tok) = + self.look_ahead(1, |&t| if t == token::Comma { Some(t) } else { None }) { let nw_span = self .psess diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 7dd203dcbfaa4..1851430ab6324 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -376,8 +376,8 @@ impl<'a> Parser<'a> { } else { // `(T, U) -> R` - let prev_token_before_parsing = self.prev_token.clone(); - let token_before_parsing = self.token.clone(); + let prev_token_before_parsing = self.prev_token; + let token_before_parsing = self.token; let mut snapshot = None; if self.may_recover() && prev_token_before_parsing == token::PathSep diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index b9ea4f454528b..c4f58cd97bccb 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -561,7 +561,7 @@ impl<'a> Parser<'a> { return Ok((AttrVec::new(), block)); } - let maybe_ident = self.prev_token.clone(); + let maybe_ident = self.prev_token; self.maybe_recover_unexpected_block_label(); if !self.eat(&token::OpenDelim(Delimiter::Brace)) { return self.error_block_no_opening_brace(); diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 9d1e2a9581320..c97480d879e49 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -566,7 +566,7 @@ impl<'a> Parser<'a> { // Recovery mutbl = Mutability::Mut; - let (dyn_tok, dyn_tok_sp) = (self.token.clone(), self.token_spacing); + let (dyn_tok, dyn_tok_sp) = (self.token, self.token_spacing); self.bump(); self.bump_with((dyn_tok, dyn_tok_sp)); } @@ -847,7 +847,7 @@ impl<'a> Parser<'a> { /// ``` fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> { let lo = self.token.span; - let leading_token = self.prev_token.clone(); + let leading_token = self.prev_token; let has_parens = self.eat(&token::OpenDelim(Delimiter::Parenthesis)); let bound = if self.token.is_lifetime() { diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs index e07871144bcb3..d7127cb32af9f 100644 --- a/src/tools/rustfmt/src/macros.rs +++ b/src/tools/rustfmt/src/macros.rs @@ -847,18 +847,18 @@ impl MacroArgParser { }; self.result.push(ParsedMacroArg { - kind: MacroArgKind::Repeat(delim, inner, another, self.last_tok.clone()), + kind: MacroArgKind::Repeat(delim, inner, another, self.last_tok), }); Some(()) } - fn update_buffer(&mut self, t: &Token) { + fn update_buffer(&mut self, t: Token) { if self.buf.is_empty() { - self.start_tok = t.clone(); + self.start_tok = t; } else { let needs_space = match next_space(&self.last_tok.kind) { - SpaceState::Ident => ident_like(t), - SpaceState::Punctuation => !ident_like(t), + SpaceState::Ident => ident_like(&t), + SpaceState::Punctuation => !ident_like(&t), SpaceState::Always => true, SpaceState::Never => false, }; @@ -867,7 +867,7 @@ impl MacroArgParser { } } - self.buf.push_str(&pprust::token_to_string(t)); + self.buf.push_str(&pprust::token_to_string(&t)); } fn need_space_prefix(&self) -> bool { @@ -926,7 +926,7 @@ impl MacroArgParser { ) if self.is_meta_var => { self.add_meta_variable(&mut iter)?; } - TokenTree::Token(ref t, _) => self.update_buffer(t), + &TokenTree::Token(t, _) => self.update_buffer(t), &TokenTree::Delimited(_dspan, _spacing, delimited, ref tts) => { if !self.buf.is_empty() { if next_space(&self.last_tok.kind) == SpaceState::Always { From d56a04692be38b31ab1804037804141c3611c76b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 4 Jul 2024 10:16:51 +1000 Subject: [PATCH 15/18] Remove `TokenStream::flattened`. It's no longer needed. This does slightly worsen the error message for a single test, but that test contains code that is so badly broken that I'm not worried about it. --- compiler/rustc_ast/src/tokenstream.rs | 44 +------------------ compiler/rustc_ast_lowering/src/lib.rs | 2 +- compiler/rustc_builtin_macros/src/cfg_eval.rs | 10 ++--- compiler/rustc_expand/src/config.rs | 6 --- tests/ui/macros/syntax-error-recovery.rs | 4 +- tests/ui/macros/syntax-error-recovery.stderr | 6 +-- 6 files changed, 10 insertions(+), 62 deletions(-) diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 99198c75480de..7fb1faa6fe878 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -24,7 +24,7 @@ use rustc_span::{sym, Span, SpanDecoder, SpanEncoder, Symbol, DUMMY_SP}; use crate::ast::AttrStyle; use crate::ast_traits::{HasAttrs, HasTokens}; -use crate::token::{self, Delimiter, InvisibleOrigin, Token, TokenKind}; +use crate::token::{self, Delimiter, Token, TokenKind}; use crate::{AttrVec, Attribute}; /// Part of a `TokenStream`. @@ -454,48 +454,6 @@ impl TokenStream { TokenStream::new(tts) } - fn flatten_token(token: &Token, spacing: Spacing) -> TokenTree { - match token.kind { - token::NtIdent(ident, is_raw) => { - TokenTree::Token(Token::new(token::Ident(ident.name, is_raw), ident.span), spacing) - } - token::NtLifetime(ident, is_raw) => TokenTree::Delimited( - DelimSpan::from_single(token.span), - DelimSpacing::new(Spacing::JointHidden, spacing), - Delimiter::Invisible(InvisibleOrigin::FlattenToken), - TokenStream::token_alone(token::Lifetime(ident.name, is_raw), ident.span), - ), - _ => TokenTree::Token(*token, spacing), - } - } - - fn flatten_token_tree(tree: &TokenTree) -> TokenTree { - match tree { - TokenTree::Token(token, spacing) => TokenStream::flatten_token(token, *spacing), - TokenTree::Delimited(span, spacing, delim, tts) => { - TokenTree::Delimited(*span, *spacing, *delim, tts.flattened()) - } - } - } - - #[must_use] - pub fn flattened(&self) -> TokenStream { - fn can_skip(stream: &TokenStream) -> bool { - stream.trees().all(|tree| match tree { - TokenTree::Token(token, _) => { - !matches!(token.kind, token::NtIdent(..) | token::NtLifetime(..)) - } - TokenTree::Delimited(.., inner) => can_skip(inner), - }) - } - - if can_skip(self) { - return self.clone(); - } - - self.trees().map(|tree| TokenStream::flatten_token_tree(tree)).collect() - } - // If `vec` is not empty, try to glue `tt` onto its last token. The return // value indicates if gluing took place. fn try_glue_to_last(vec: &mut Vec, tt: &TokenTree) -> bool { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index efd3ae336afb8..3dc31ec9329e7 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -987,7 +987,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn lower_delim_args(&self, args: &DelimArgs) -> DelimArgs { - DelimArgs { dspan: args.dspan, delim: args.delim, tokens: args.tokens.flattened() } + DelimArgs { dspan: args.dspan, delim: args.delim, tokens: args.tokens.clone() } } /// Lower an associated item constraint. diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 364e987dad993..e97fc9ff30a72 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -173,11 +173,7 @@ impl CfgEval<'_> { _ => unreachable!(), }; - // 'Flatten' all nonterminals (i.e. `TokenKind::Nt{Ident,Lifetime}`) - // to `None`-delimited groups containing the corresponding tokens. This - // is normally delayed until the proc-macro server actually needs to - // provide tokens to a proc-macro. We do this earlier, so that we can - // handle cases like: + // Interesting cases: // // ```rust // #[cfg_eval] #[cfg] $item @@ -185,8 +181,8 @@ impl CfgEval<'_> { // // where `$item` is `#[cfg_attr] struct Foo {}`. We want to make // sure to evaluate *all* `#[cfg]` and `#[cfg_attr]` attributes - the simplest - // way to do this is to do a single parse of a stream without any nonterminals. - let orig_tokens = annotatable.to_tokens().flattened(); + // way to do this is to do a single parse of the token stream. + let orig_tokens = annotatable.to_tokens(); // Re-parse the tokens, setting the `capture_cfg` flag to save extra information // to the captured `AttrTokenStream` (specifically, we capture diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index f769fee9555ff..40dd9da772da6 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -213,12 +213,6 @@ impl<'a> StripUnconfigured<'a> { inner = self.configure_tokens(&inner); Some(AttrTokenTree::Delimited(sp, spacing, delim, inner)) } - AttrTokenTree::Token( - Token { kind: TokenKind::NtIdent(..) | TokenKind::NtLifetime(..), .. }, - _, - ) => { - panic!("Nonterminal should have been flattened: {:?}", tree); - } AttrTokenTree::Token( Token { kind: TokenKind::OpenDelim(_) | TokenKind::CloseDelim(_), .. }, _, diff --git a/tests/ui/macros/syntax-error-recovery.rs b/tests/ui/macros/syntax-error-recovery.rs index 6cf9d54e82636..e1681ea32a2ee 100644 --- a/tests/ui/macros/syntax-error-recovery.rs +++ b/tests/ui/macros/syntax-error-recovery.rs @@ -5,14 +5,14 @@ macro_rules! values { $( #[$attr] $token $($inner)? = $value, + //~^ ERROR expected one of `!` or `::`, found `` )* } }; } -//~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `ty` metavariable +//~^^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `ty` metavariable //~| ERROR macro expansion ignores `ty` metavariable and any tokens following values!(STRING(1) as (String) => cfg(test),); -//~^ ERROR expected one of `!` or `::`, found `` fn main() {} diff --git a/tests/ui/macros/syntax-error-recovery.stderr b/tests/ui/macros/syntax-error-recovery.stderr index 61758fb9d7dc6..a2059aa1aa802 100644 --- a/tests/ui/macros/syntax-error-recovery.stderr +++ b/tests/ui/macros/syntax-error-recovery.stderr @@ -22,10 +22,10 @@ LL | values!(STRING(1) as (String) => cfg(test),); = note: the usage of `values!` is likely invalid in item context error: expected one of `!` or `::`, found `` - --> $DIR/syntax-error-recovery.rs:15:9 + --> $DIR/syntax-error-recovery.rs:7:17 | -LL | values!(STRING(1) as (String) => cfg(test),); - | ^^^^^^ expected one of `!` or `::` +LL | $token $($inner)? = $value, + | ^^^^^^ expected one of `!` or `::` error: aborting due to 3 previous errors From c05df1b55694e631fd0d6a2cdad377b7337654dc Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 12 Sep 2024 13:01:34 -0700 Subject: [PATCH 16/18] Enable doctest merging on all editions --- src/librustdoc/doctest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 05ef72892012d..a4cb75baacfa7 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -789,7 +789,7 @@ struct CreateRunnableDocTests { impl CreateRunnableDocTests { fn new(rustdoc_options: RustdocOptions, opts: GlobalTestOptions) -> CreateRunnableDocTests { - let can_merge_doctests = rustdoc_options.edition >= Edition::Edition2024; + let can_merge_doctests = true; CreateRunnableDocTests { standalone_tests: Vec::new(), mergeable_tests: FxHashMap::default(), From 04f521ec9afd563b512ecd52b7a76d7562d077e2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 14 Sep 2024 15:43:03 -0400 Subject: [PATCH 17/18] Check elaborated projections from dyn don't mention unconstrained late bound lifetimes --- .../src/hir_ty_lowering/object_safety.rs | 50 +++++++++++++++++++ ...ted-predicates-unconstrained-late-bound.rs | 24 +++++++++ ...predicates-unconstrained-late-bound.stderr | 9 ++++ tests/ui/traits/object/pretty.rs | 4 +- tests/ui/traits/object/pretty.stderr | 13 +---- 5 files changed, 86 insertions(+), 14 deletions(-) create mode 100644 tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.rs create mode 100644 tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs index 8853886371033..bc3744c5c52ad 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs @@ -174,6 +174,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Include projections defined on supertraits. projection_bounds.push((pred, span)); } + + self.check_elaborated_projection_mentions_input_lifetimes(pred, span); } _ => (), } @@ -358,6 +360,54 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Ty::new_dynamic(tcx, existential_predicates, region_bound, representation) } + + /// Check that elaborating the principal of a trait ref doesn't lead to projections + /// that are unconstrained. This can happen because an otherwise unconstrained + /// *type variable* can be substituted with a type that has late-bound regions. See + /// `elaborated-predicates-unconstrained-late-bound.rs` for a test. + fn check_elaborated_projection_mentions_input_lifetimes( + &self, + pred: ty::PolyProjectionPredicate<'tcx>, + span: Span, + ) { + let tcx = self.tcx(); + + // Find any late-bound regions declared in `ty` that are not + // declared in the trait-ref or assoc_item. These are not well-formed. + // + // Example: + // + // for<'a> ::Item = &'a str // <-- 'a is bad + // for<'a> >::Output = &'a str // <-- 'a is ok + let late_bound_in_projection_term = + tcx.collect_constrained_late_bound_regions(pred.map_bound(|pred| pred.projection_term)); + let late_bound_in_term = + tcx.collect_referenced_late_bound_regions(pred.map_bound(|pred| pred.term)); + debug!(?late_bound_in_projection_term); + debug!(?late_bound_in_term); + + // FIXME: point at the type params that don't have appropriate lifetimes: + // struct S1 Fn(&i32, &i32) -> &'a i32>(F); + // ---- ---- ^^^^^^^ + // NOTE(associated_const_equality): This error should be impossible to trigger + // with associated const equality constraints. + self.validate_late_bound_regions( + late_bound_in_projection_term, + late_bound_in_term, + |br_name| { + let item_name = tcx.item_name(pred.projection_def_id()); + struct_span_code_err!( + self.dcx(), + span, + E0582, + "binding for associated type `{}` references {}, \ + which does not appear in the trait input types", + item_name, + br_name + ) + }, + ); + } } fn replace_dummy_self_with_error<'tcx, T: TypeFoldable>>( diff --git a/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.rs b/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.rs new file mode 100644 index 0000000000000..b174776c596ee --- /dev/null +++ b/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.rs @@ -0,0 +1,24 @@ +// Make sure that when elaborating the principal of a dyn trait for projection predicates +// we don't end up in a situation where we have an unconstrained late-bound lifetime in +// the output of a projection. + +// Fix for . + +trait A: B {} + +trait B { + type T; +} + +struct Erase(T::T); + +fn main() { + let x = { + let x = String::from("hello"); + + Erase:: A<&'a _>>(x.as_str()) + //~^ ERROR binding for associated type `T` references lifetime `'a`, which does not appear in the trait input types + }; + + dbg!(x.0); +} diff --git a/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.stderr b/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.stderr new file mode 100644 index 0000000000000..bb3cc4b3fd786 --- /dev/null +++ b/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.stderr @@ -0,0 +1,9 @@ +error[E0582]: binding for associated type `T` references lifetime `'a`, which does not appear in the trait input types + --> $DIR/elaborated-predicates-unconstrained-late-bound.rs:19:21 + | +LL | Erase:: A<&'a _>>(x.as_str()) + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0582`. diff --git a/tests/ui/traits/object/pretty.rs b/tests/ui/traits/object/pretty.rs index 6660ff040f753..603d7af526002 100644 --- a/tests/ui/traits/object/pretty.rs +++ b/tests/ui/traits/object/pretty.rs @@ -13,7 +13,7 @@ trait SuperGeneric<'a> { } trait AnyGeneric<'a>: SuperGeneric<'a> {} trait FixedGeneric1<'a>: SuperGeneric<'a, Assoc2 = &'a u8> {} -trait FixedGeneric2<'a>: Super {} +// trait FixedGeneric2<'a>: Super {} // Unsound! trait FixedHrtb: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> {} trait AnyDifferentBinders: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> + Super {} trait FixedDifferentBinders: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> + Super {} @@ -32,7 +32,7 @@ fn dyn_fixed_static(x: &dyn FixedStatic) { x } //~ERROR mismatched types fn dyn_super_generic(x: &dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>) { x } //~ERROR mismatched types fn dyn_any_generic(x: &dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>) { x } //~ERROR mismatched types fn dyn_fixed_generic1(x: &dyn for<'a> FixedGeneric1<'a>) { x } //~ERROR mismatched types -fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x } //~ERROR mismatched types +// fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x } // Unsound! fn dyn_fixed_generic_multi(x: &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>) { x } //~ERROR mismatched types fn dyn_fixed_hrtb(x: &dyn FixedHrtb) { x } //~ERROR mismatched types fn dyn_any_different_binders(x: &dyn AnyDifferentBinders) { x } //~ERROR mismatched types diff --git a/tests/ui/traits/object/pretty.stderr b/tests/ui/traits/object/pretty.stderr index 6964d97c08ed8..e0a4347524f13 100644 --- a/tests/ui/traits/object/pretty.stderr +++ b/tests/ui/traits/object/pretty.stderr @@ -106,17 +106,6 @@ LL | fn dyn_fixed_generic1(x: &dyn for<'a> FixedGeneric1<'a>) { x } = note: expected unit type `()` found reference `&dyn for<'a> FixedGeneric1<'a>` -error[E0308]: mismatched types - --> $DIR/pretty.rs:35:60 - | -LL | fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x } - | - ^ expected `()`, found `&dyn FixedGeneric2<'a>` - | | - | help: try adding a return type: `-> &dyn for<'a> FixedGeneric2<'a>` - | - = note: expected unit type `()` - found reference `&dyn for<'a> FixedGeneric2<'a>` - error[E0308]: mismatched types --> $DIR/pretty.rs:36:79 | @@ -172,6 +161,6 @@ LL | fn dyn_has_gat(x: &dyn HasGat = ()>) { x } = note: expected unit type `()` found reference `&dyn HasGat = ()>` -error: aborting due to 15 previous errors; 1 warning emitted +error: aborting due to 14 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0308`. From 29ed87319b1946439e72f4183abcfcd40c69964f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 14 Sep 2024 15:55:16 -0400 Subject: [PATCH 18/18] Elaborate supertrait span correctly to label the error better --- .../src/hir_ty_lowering/object_safety.rs | 20 +++++++--- compiler/rustc_middle/src/ty/predicate.rs | 4 ++ compiler/rustc_type_ir/src/elaborate.rs | 40 +++++++++++++++++++ compiler/rustc_type_ir/src/inherent.rs | 2 + ...predicates-unconstrained-late-bound.stderr | 3 ++ 5 files changed, 64 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs index bc3744c5c52ad..bdb363f43ce03 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs @@ -13,6 +13,7 @@ use rustc_middle::ty::{ use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::error_reporting::traits::report_object_safety_error; use rustc_trait_selection::traits::{self, hir_ty_lowering_object_safety_violations}; +use rustc_type_ir::elaborate::ClauseWithSupertraitSpan; use smallvec::{smallvec, SmallVec}; use tracing::{debug, instrument}; @@ -124,16 +125,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .into_iter() .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id())); - for (base_trait_ref, span) in regular_traits_refs_spans { + for (base_trait_ref, original_span) in regular_traits_refs_spans { let base_pred: ty::Predicate<'tcx> = base_trait_ref.upcast(tcx); - for pred in traits::elaborate(tcx, [base_pred]).filter_only_self() { + for ClauseWithSupertraitSpan { pred, original_span, supertrait_span } in + traits::elaborate(tcx, [ClauseWithSupertraitSpan::new(base_pred, original_span)]) + .filter_only_self() + { debug!("observing object predicate `{pred:?}`"); let bound_predicate = pred.kind(); match bound_predicate.skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { let pred = bound_predicate.rebind(pred); - associated_types.entry(span).or_default().extend( + associated_types.entry(original_span).or_default().extend( tcx.associated_items(pred.def_id()) .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Type) @@ -172,10 +176,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // the discussion in #56288 for alternatives. if !references_self { // Include projections defined on supertraits. - projection_bounds.push((pred, span)); + projection_bounds.push((pred, original_span)); } - self.check_elaborated_projection_mentions_input_lifetimes(pred, span); + self.check_elaborated_projection_mentions_input_lifetimes( + pred, + original_span, + supertrait_span, + ); } _ => (), } @@ -369,6 +377,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, pred: ty::PolyProjectionPredicate<'tcx>, span: Span, + supertrait_span: Span, ) { let tcx = self.tcx(); @@ -405,6 +414,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { item_name, br_name ) + .with_span_label(supertrait_span, "due to this supertrait") }, ); } diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index 8e72505b86200..bddcd233f5072 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -179,6 +179,10 @@ pub struct Clause<'tcx>( ); impl<'tcx> rustc_type_ir::inherent::Clause> for Clause<'tcx> { + fn as_predicate(self) -> Predicate<'tcx> { + self.as_predicate() + } + fn instantiate_supertrait(self, tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> Self { self.instantiate_supertrait(tcx, trait_ref) } diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index f30419c801f18..03464d18e4637 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -43,6 +43,46 @@ pub trait Elaboratable { ) -> Self; } +pub struct ClauseWithSupertraitSpan { + pub pred: I::Predicate, + // Span of the original elaborated predicate. + pub original_span: I::Span, + // Span of the supertrait predicatae that lead to this clause. + pub supertrait_span: I::Span, +} +impl ClauseWithSupertraitSpan { + pub fn new(pred: I::Predicate, span: I::Span) -> Self { + ClauseWithSupertraitSpan { pred, original_span: span, supertrait_span: span } + } +} +impl Elaboratable for ClauseWithSupertraitSpan { + fn predicate(&self) -> ::Predicate { + self.pred + } + + fn child(&self, clause: ::Clause) -> Self { + ClauseWithSupertraitSpan { + pred: clause.as_predicate(), + original_span: self.original_span, + supertrait_span: self.supertrait_span, + } + } + + fn child_with_derived_cause( + &self, + clause: ::Clause, + supertrait_span: ::Span, + _parent_trait_pred: crate::Binder>, + _index: usize, + ) -> Self { + ClauseWithSupertraitSpan { + pred: clause.as_predicate(), + original_span: self.original_span, + supertrait_span: supertrait_span, + } + } +} + pub fn elaborate>( cx: I, obligations: impl IntoIterator, diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 59a83ea5412d5..69665df4bfc26 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -460,6 +460,8 @@ pub trait Clause>: + IntoKind>> + Elaboratable { + fn as_predicate(self) -> I::Predicate; + fn as_trait_clause(self) -> Option>> { self.kind() .map_bound(|clause| if let ty::ClauseKind::Trait(t) = clause { Some(t) } else { None }) diff --git a/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.stderr b/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.stderr index bb3cc4b3fd786..067eaf5e7f30f 100644 --- a/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.stderr +++ b/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.stderr @@ -1,6 +1,9 @@ error[E0582]: binding for associated type `T` references lifetime `'a`, which does not appear in the trait input types --> $DIR/elaborated-predicates-unconstrained-late-bound.rs:19:21 | +LL | trait A: B {} + | ----- due to this supertrait +... LL | Erase:: A<&'a _>>(x.as_str()) | ^^^^^^^^^^^^^^^^