From 3f09a2054921708ac8288ac9912885dbe66682ec Mon Sep 17 00:00:00 2001 From: Jack Rickard Date: Mon, 3 Feb 2025 13:56:20 +0000 Subject: Do not allow attributes on struct field rest patterns This removes support for attributes on struct field rest patterns (the `..`) from the parser. Previously they were being parsed but dropped from the AST, so didn't work and were deleted by rustfmt. --- compiler/rustc_parse/src/parser/pat.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 64bcb1a5a36..8ce749ec814 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1472,17 +1472,6 @@ impl<'a> Parser<'a> { let mut last_non_comma_dotdot_span = None; while self.token != token::CloseDelim(Delimiter::Brace) { - let attrs = match self.parse_outer_attributes() { - Ok(attrs) => attrs, - Err(err) => { - if let Some(delayed) = delayed_err { - delayed.emit(); - } - return Err(err); - } - }; - let lo = self.token.span; - // check that a comma comes after every field if !ate_comma { let err = if self.token == token::At { @@ -1585,6 +1574,17 @@ impl<'a> Parser<'a> { } } + let attrs = match self.parse_outer_attributes() { + Ok(attrs) => attrs, + Err(err) => { + if let Some(delayed) = delayed_err { + delayed.emit(); + } + return Err(err); + } + }; + let lo = self.token.span; + let field = self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| { let field = match this.parse_pat_field(lo, attrs) { Ok(field) => Ok(field), -- cgit 1.4.1-3-g733a5 From 28164e3c047991294a3d4e7afd6b820c0c2f86ee Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 10 Feb 2025 19:47:00 +0000 Subject: Stop using span hack for contracts feature gating --- compiler/rustc_builtin_macros/src/contracts.rs | 21 ++++++++----------- compiler/rustc_parse/src/parser/generics.rs | 14 ++----------- compiler/rustc_session/src/parse.rs | 5 ----- .../internal-feature-gating.stderr | 8 ++++---- tests/ui/feature-gates/feature-gate-contracts.rs | 2 -- .../ui/feature-gates/feature-gate-contracts.stderr | 24 ++-------------------- 6 files changed, 17 insertions(+), 57 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_builtin_macros/src/contracts.rs b/compiler/rustc_builtin_macros/src/contracts.rs index 85a30f7bdc9..0cba29f2b31 100644 --- a/compiler/rustc_builtin_macros/src/contracts.rs +++ b/compiler/rustc_builtin_macros/src/contracts.rs @@ -4,8 +4,8 @@ use rustc_ast::token; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_errors::ErrorGuaranteed; use rustc_expand::base::{AttrProcMacro, ExtCtxt}; -use rustc_span::Span; use rustc_span::symbol::{Ident, Symbol, kw, sym}; +use rustc_span::{DesugaringKind, Span}; pub(crate) struct ExpandRequires; @@ -121,23 +121,19 @@ fn expand_contract_clause( } } - // Record the span as a contract attribute expansion. - // This is used later to stop users from using the extended syntax directly - // which is gated via `contracts_internals`. - ecx.psess().contract_attribute_spans.push(attr_span); - Ok(new_tts) } fn expand_requires_tts( - _ecx: &mut ExtCtxt<'_>, + ecx: &mut ExtCtxt<'_>, attr_span: Span, annotation: TokenStream, annotated: TokenStream, ) -> Result { - expand_contract_clause(_ecx, attr_span, annotated, |new_tts| { + let feature_span = ecx.with_def_site_ctxt(attr_span); + expand_contract_clause(ecx, attr_span, annotated, |new_tts| { new_tts.push_tree(TokenTree::Token( - token::Token::from_ast_ident(Ident::new(kw::ContractRequires, attr_span)), + token::Token::from_ast_ident(Ident::new(kw::ContractRequires, feature_span)), Spacing::Joint, )); new_tts.push_tree(TokenTree::Token( @@ -155,14 +151,15 @@ fn expand_requires_tts( } fn expand_ensures_tts( - _ecx: &mut ExtCtxt<'_>, + ecx: &mut ExtCtxt<'_>, attr_span: Span, annotation: TokenStream, annotated: TokenStream, ) -> Result { - expand_contract_clause(_ecx, attr_span, annotated, |new_tts| { + let feature_span = ecx.with_def_site_ctxt(attr_span); + expand_contract_clause(ecx, attr_span, annotated, |new_tts| { new_tts.push_tree(TokenTree::Token( - token::Token::from_ast_ident(Ident::new(kw::ContractEnsures, attr_span)), + token::Token::from_ast_ident(Ident::new(kw::ContractEnsures, feature_span)), Spacing::Joint, )); new_tts.push_tree(TokenTree::Delimited( diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 86816819be2..11f0e579de5 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -302,26 +302,16 @@ impl<'a> Parser<'a> { pub(super) fn parse_contract( &mut self, ) -> PResult<'a, Option>> { - let gate = |span| { - if self.psess.contract_attribute_spans.contains(span) { - // span was generated via a builtin contracts attribute, so gate as end-user visible - self.psess.gated_spans.gate(sym::contracts, span); - } else { - // span was not generated via a builtin contracts attribute, so gate as internal machinery - self.psess.gated_spans.gate(sym::contracts_internals, span); - } - }; - let requires = if self.eat_keyword_noexpect(exp!(ContractRequires).kw) { + self.psess.gated_spans.gate(sym::contracts_internals, self.prev_token.span); let precond = self.parse_expr()?; - gate(precond.span); Some(precond) } else { None }; let ensures = if self.eat_keyword_noexpect(exp!(ContractEnsures).kw) { + self.psess.gated_spans.gate(sym::contracts_internals, self.prev_token.span); let postcond = self.parse_expr()?; - gate(postcond.span); Some(postcond) } else { None diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index d4db05ce139..e0405a71f65 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -208,10 +208,6 @@ pub struct ParseSess { pub config: Cfg, pub check_config: CheckCfg, pub edition: Edition, - /// Places where contract attributes were expanded into unstable AST forms. - /// This is used to allowlist those spans (so that we only check them against the feature - /// gate for the externally visible interface, and not internal implmentation machinery). - pub contract_attribute_spans: AppendOnlyVec, /// Places where raw identifiers were used. This is used to avoid complaining about idents /// clashing with keywords in new editions. pub raw_identifier_spans: AppendOnlyVec, @@ -260,7 +256,6 @@ impl ParseSess { config: Cfg::default(), check_config: CheckCfg::default(), edition: ExpnId::root().expn_data().edition, - contract_attribute_spans: Default::default(), raw_identifier_spans: Default::default(), bad_unicode_identifiers: Lock::new(Default::default()), source_map, diff --git a/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr b/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr index c0e1522f54c..7302694a787 100644 --- a/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr +++ b/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr @@ -1,18 +1,18 @@ error[E0658]: contract internal machinery is for internal use only - --> $DIR/internal-feature-gating.rs:16:45 + --> $DIR/internal-feature-gating.rs:16:28 | LL | fn identity_1() -> i32 contract_requires(|| true) { 10 } - | ^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ | = note: see issue #128044 for more information = help: add `#![feature(contracts_internals)]` 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[E0658]: contract internal machinery is for internal use only - --> $DIR/internal-feature-gating.rs:18:44 + --> $DIR/internal-feature-gating.rs:18:28 | LL | fn identity_2() -> i32 contract_ensures(|_| true) { 10 } - | ^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = note: see issue #128044 for more information = help: add `#![feature(contracts_internals)]` to the crate attributes to enable diff --git a/tests/ui/feature-gates/feature-gate-contracts.rs b/tests/ui/feature-gates/feature-gate-contracts.rs index 5544f1d82ee..1759d23077b 100644 --- a/tests/ui/feature-gates/feature-gate-contracts.rs +++ b/tests/ui/feature-gates/feature-gate-contracts.rs @@ -3,9 +3,7 @@ #[core::contracts::requires(x > 0)] pub fn requires_needs_it(x: i32) { } //~^^ ERROR use of unstable library feature `contracts` -//~^^^ ERROR contracts are incomplete #[core::contracts::ensures(|ret| *ret > 0)] pub fn ensures_needs_it() -> i32 { 10 } //~^^ ERROR use of unstable library feature `contracts` -//~^^^ ERROR contracts are incomplete diff --git a/tests/ui/feature-gates/feature-gate-contracts.stderr b/tests/ui/feature-gates/feature-gate-contracts.stderr index 4403e7df50b..4b0f7150973 100644 --- a/tests/ui/feature-gates/feature-gate-contracts.stderr +++ b/tests/ui/feature-gates/feature-gate-contracts.stderr @@ -9,7 +9,7 @@ LL | #[core::contracts::requires(x > 0)] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `contracts` - --> $DIR/feature-gate-contracts.rs:8:3 + --> $DIR/feature-gate-contracts.rs:7:3 | LL | #[core::contracts::ensures(|ret| *ret > 0)] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -18,26 +18,6 @@ LL | #[core::contracts::ensures(|ret| *ret > 0)] = help: add `#![feature(contracts)]` 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[E0658]: contracts are incomplete - --> $DIR/feature-gate-contracts.rs:3:1 - | -LL | #[core::contracts::requires(x > 0)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #128044 for more information - = help: add `#![feature(contracts)]` 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[E0658]: contracts are incomplete - --> $DIR/feature-gate-contracts.rs:8:1 - | -LL | #[core::contracts::ensures(|ret| *ret > 0)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #128044 for more information - = help: add `#![feature(contracts)]` 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: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. -- cgit 1.4.1-3-g733a5 From 0aa2e6b606fdca2c0166b6033e3ea0cb8484eeb7 Mon Sep 17 00:00:00 2001 From: yukang Date: Tue, 11 Feb 2025 15:26:21 +0800 Subject: Try to recover from path sep error in parser --- compiler/rustc_parse/messages.ftl | 3 -- compiler/rustc_parse/src/errors.rs | 8 ---- compiler/rustc_parse/src/parser/item.rs | 3 -- compiler/rustc_parse/src/parser/path.rs | 15 ++++++- .../single-colon-path-not-const-generics.stderr | 4 +- .../argument-list-from-path-sep-error-129273.fixed | 15 +++++++ .../argument-list-from-path-sep-error-129273.rs | 15 +++++++ ...argument-list-from-path-sep-error-129273.stderr | 14 +++++++ .../struct-field-type-including-single-colon.rs | 8 ++-- ...struct-field-type-including-single-colon.stderr | 47 ++++++++++++++-------- 10 files changed, 92 insertions(+), 40 deletions(-) create mode 100644 tests/ui/suggestions/argument-list-from-path-sep-error-129273.fixed create mode 100644 tests/ui/suggestions/argument-list-from-path-sep-error-129273.rs create mode 100644 tests/ui/suggestions/argument-list-from-path-sep-error-129273.stderr (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index d50bd18a1d7..563081c7240 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -743,9 +743,6 @@ parse_single_colon_import_path = expected `::`, found `:` .suggestion = use double colon .note = import paths are delimited using `::` -parse_single_colon_struct_type = found single colon in a struct field type path - .suggestion = write a path separator here - parse_static_with_generics = static items may not have generic parameters parse_struct_literal_body_without_path = diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 8f0e29c2769..dc03d6f9521 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3071,14 +3071,6 @@ pub(crate) struct BadItemKind { pub help: bool, } -#[derive(Diagnostic)] -#[diag(parse_single_colon_struct_type)] -pub(crate) struct SingleColonStructType { - #[primary_span] - #[suggestion(code = "::", applicability = "maybe-incorrect", style = "verbose")] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(parse_macro_rules_missing_bang)] pub(crate) struct MacroRulesMissingBang { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 637ed2774a2..c923717ecaf 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2043,9 +2043,6 @@ impl<'a> Parser<'a> { } self.expect_field_ty_separator()?; let ty = self.parse_ty()?; - if self.token == token::Colon && self.look_ahead(1, |t| *t != token::Colon) { - self.dcx().emit_err(errors::SingleColonStructType { span: self.token.span }); - } let default = if self.token == token::Eq { self.bump(); let const_expr = self.parse_expr_anon_const()?; diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 576711e6677..b241aa892db 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -246,8 +246,19 @@ impl<'a> Parser<'a> { segments.push(segment); if self.is_import_coupler() || !self.eat_path_sep() { - if style == PathStyle::Expr - && self.may_recover() + let ok_for_recovery = self.may_recover() + && match style { + PathStyle::Expr => true, + PathStyle::Type if let Some((ident, _)) = self.prev_token.ident() => { + self.token == token::Colon + && ident.as_str().chars().all(|c| c.is_lowercase()) + && self.token.span.lo() == self.prev_token.span.hi() + && self + .look_ahead(1, |token| self.token.span.hi() == token.span.lo()) + } + _ => false, + }; + if ok_for_recovery && self.token == token::Colon && self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident()) { diff --git a/tests/ui/generics/single-colon-path-not-const-generics.stderr b/tests/ui/generics/single-colon-path-not-const-generics.stderr index 4e695b2dcd6..c14a5e62a0c 100644 --- a/tests/ui/generics/single-colon-path-not-const-generics.stderr +++ b/tests/ui/generics/single-colon-path-not-const-generics.stderr @@ -1,8 +1,6 @@ error: path separator must be a double colon --> $DIR/single-colon-path-not-const-generics.rs:8:18 | -LL | pub struct Foo { - | --- while parsing this struct LL | a: Vec, | ^ | @@ -10,7 +8,7 @@ LL | a: Vec, help: use a double colon instead | LL | a: Vec, - | + + | + error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/argument-list-from-path-sep-error-129273.fixed b/tests/ui/suggestions/argument-list-from-path-sep-error-129273.fixed new file mode 100644 index 00000000000..f5dbf0c8b6f --- /dev/null +++ b/tests/ui/suggestions/argument-list-from-path-sep-error-129273.fixed @@ -0,0 +1,15 @@ +//@ run-rustfix + +use std::fmt; + +struct Hello; + +impl fmt::Display for Hello { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { //~ ERROR path separator must be a double colon + write!(f, "hello") + } +} + +fn main() { + let _ = Hello; +} diff --git a/tests/ui/suggestions/argument-list-from-path-sep-error-129273.rs b/tests/ui/suggestions/argument-list-from-path-sep-error-129273.rs new file mode 100644 index 00000000000..c41880a26f6 --- /dev/null +++ b/tests/ui/suggestions/argument-list-from-path-sep-error-129273.rs @@ -0,0 +1,15 @@ +//@ run-rustfix + +use std::fmt; + +struct Hello; + +impl fmt::Display for Hello { + fn fmt(&self, f: &mut fmt:Formatter) -> fmt::Result { //~ ERROR path separator must be a double colon + write!(f, "hello") + } +} + +fn main() { + let _ = Hello; +} diff --git a/tests/ui/suggestions/argument-list-from-path-sep-error-129273.stderr b/tests/ui/suggestions/argument-list-from-path-sep-error-129273.stderr new file mode 100644 index 00000000000..92947e3b177 --- /dev/null +++ b/tests/ui/suggestions/argument-list-from-path-sep-error-129273.stderr @@ -0,0 +1,14 @@ +error: path separator must be a double colon + --> $DIR/argument-list-from-path-sep-error-129273.rs:8:30 + | +LL | fn fmt(&self, f: &mut fmt:Formatter) -> fmt::Result { + | ^ + | + = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 +help: use a double colon instead + | +LL | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + | + + +error: aborting due to 1 previous error + diff --git a/tests/ui/suggestions/struct-field-type-including-single-colon.rs b/tests/ui/suggestions/struct-field-type-including-single-colon.rs index b7ad6d996f1..a3111028895 100644 --- a/tests/ui/suggestions/struct-field-type-including-single-colon.rs +++ b/tests/ui/suggestions/struct-field-type-including-single-colon.rs @@ -7,14 +7,14 @@ mod foo { struct Foo { a: foo:A, - //~^ ERROR found single colon in a struct field type path - //~| expected `,`, or `}`, found `:` + //~^ ERROR path separator must be a double colon + //~| ERROR struct `A` is private } struct Bar { b: foo::bar:B, - //~^ ERROR found single colon in a struct field type path - //~| expected `,`, or `}`, found `:` + //~^ ERROR path separator must be a double colon + //~| ERROR module `bar` is private } fn main() {} diff --git a/tests/ui/suggestions/struct-field-type-including-single-colon.stderr b/tests/ui/suggestions/struct-field-type-including-single-colon.stderr index 5ffc5b40849..ce16aca1e14 100644 --- a/tests/ui/suggestions/struct-field-type-including-single-colon.stderr +++ b/tests/ui/suggestions/struct-field-type-including-single-colon.stderr @@ -1,40 +1,53 @@ -error: found single colon in a struct field type path +error: path separator must be a double colon --> $DIR/struct-field-type-including-single-colon.rs:9:11 | LL | a: foo:A, | ^ | -help: write a path separator here + = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 +help: use a double colon instead | LL | a: foo::A, | + -error: expected `,`, or `}`, found `:` - --> $DIR/struct-field-type-including-single-colon.rs:9:11 - | -LL | struct Foo { - | --- while parsing this struct -LL | a: foo:A, - | ^ - -error: found single colon in a struct field type path +error: path separator must be a double colon --> $DIR/struct-field-type-including-single-colon.rs:15:16 | LL | b: foo::bar:B, | ^ | -help: write a path separator here + = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 +help: use a double colon instead | LL | b: foo::bar::B, | + -error: expected `,`, or `}`, found `:` - --> $DIR/struct-field-type-including-single-colon.rs:15:16 +error[E0603]: struct `A` is private + --> $DIR/struct-field-type-including-single-colon.rs:9:12 + | +LL | a: foo:A, + | ^ private struct + | +note: the struct `A` is defined here + --> $DIR/struct-field-type-including-single-colon.rs:2:5 + | +LL | struct A; + | ^^^^^^^^^ + +error[E0603]: module `bar` is private + --> $DIR/struct-field-type-including-single-colon.rs:15:13 | -LL | struct Bar { - | --- while parsing this struct LL | b: foo::bar:B, - | ^ + | ^^^ - struct `B` is not publicly re-exported + | | + | private module + | +note: the module `bar` is defined here + --> $DIR/struct-field-type-including-single-colon.rs:3:5 + | +LL | mod bar { + | ^^^^^^^ error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0603`. -- cgit 1.4.1-3-g733a5 From 8a02724b9d0bf3a9e449a04c2d7efaa8a0521e1b Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Sun, 16 Feb 2025 16:20:53 +0100 Subject: Fix const items not being allowed to be called `r#move` or `r#static` Because of an ambiguity with const closures, the parser needs to ensure that for a const item, the `const` keyword isn't followed by a `move` or `static` keyword, as that would indicate a const closure: ```rust fn main() { const move // ... } ``` This check did not take raw identifiers into account, therefore being unable to distinguish between `const move` and `const r#move`. The latter is obviously not a const closure, so it should be allowed as a const item. This fixes the check in the parser to only treat `const ...` as a const closure if it's followed by the *proper keyword*, and not a raw identifier. Additionally, this adds a large test that tests for all raw identifiers in all kinds of positions, including `const`, to prevent issues like this one from occurring again. --- compiler/rustc_parse/src/parser/mod.rs | 6 +- compiler/rustc_span/src/symbol.rs | 2 + tests/ui/parser/raw/raw-idents.rs | 158 +++++++++++++++++++++++++++++++++ 3 files changed, 163 insertions(+), 3 deletions(-) create mode 100644 tests/ui/parser/raw/raw-idents.rs (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index ea464fc8ebb..1de452dcf39 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -754,9 +754,9 @@ impl<'a> Parser<'a> { self.is_keyword_ahead(0, &[kw::Const]) && self.look_ahead(1, |t| match &t.kind { // async closures do not work with const closures, so we do not parse that here. - token::Ident(kw::Move | kw::Static, _) | token::OrOr | token::BinOp(token::Or) => { - true - } + token::Ident(kw::Move | kw::Static, IdentIsRaw::No) + | token::OrOr + | token::BinOp(token::Or) => true, _ => false, }) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 62723e385cf..757450cc068 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -104,6 +104,8 @@ symbols! { Gen: "gen", // >= 2024 Edition only Try: "try", // >= 2018 Edition only + // NOTE: When adding new keywords, consider adding them to the ui/parser/raw/raw-idents.rs test. + // "Lifetime keywords": regular keywords with a leading `'`. // Matching predicates: `is_any_keyword` UnderscoreLifetime: "'_", diff --git a/tests/ui/parser/raw/raw-idents.rs b/tests/ui/parser/raw/raw-idents.rs new file mode 100644 index 00000000000..93015ee6c49 --- /dev/null +++ b/tests/ui/parser/raw/raw-idents.rs @@ -0,0 +1,158 @@ +//@ check-pass +//@ revisions:e2015 e2018 e2021 e2024 +//@[e2015] edition:2015 +//@[e2018] edition:2018 +//@[e2021] edition:2021 +//@[e2024] edition:2024 + +// Ensure that all (usable as identifier) keywords work as raw identifiers in all positions. +// This was motivated by issue #137128, where `r#move`/`r#static`` did not work as `const` names +// due to a parser check not acounting for raw identifiers. + +#![crate_type = "lib"] +#![allow(dead_code, nonstandard_style)] + +// NOTE: It is vital to only use a `tt` fragment to avoid confusing +// the parser with nonterminals that can mask bugs. + +macro_rules! tests { + ($kw:tt) => { + mod $kw { + mod const_item { + const $kw: () = (); + } + mod static_item { + static $kw: () = (); + } + mod fn_item { + fn $kw() {} + } + mod mod_and_use_item { + mod $kw { + use super::$kw; + } + } + mod ty_alias_item { + type $kw = (); + } + mod struct_item { + struct $kw { $kw: () } + } + mod enum_item { + enum $kw { $kw } + } + mod union_item { + union $kw { $kw: () } + } + mod trait_item { + trait $kw { + fn $kw() {} + } + } + mod generics_and_impl { + struct A<$kw>($kw); + enum B<$kw> { A($kw) } + trait Tr<$kw> { + type $kw; + } + + impl<$kw> Tr<$kw> for A<$kw> { + type $kw = (); + } + impl<$kw> B<$kw> {} + } + mod extern_crate { + #[cfg(any())] + extern crate $kw; + } + mod body { + fn expr() { + let $kw = 0; + let b = $kw; + assert_eq!($kw, b); + type $kw = (); + let $kw: $kw = (); + let _ = $kw as $kw; + } + fn pat_const() { + const $kw: u8 = 0; + + // Ensure that $kw actually matches the constant. + #[forbid(unreachable_patterns)] + match 1 { + $kw => {} + _ => {} + } + } + fn pat_binding() { + match 1 { + $kw => {} + _ => {} + } + } + } + } + }; +} + +tests!(r#break); +tests!(r#const); +tests!(r#continue); +tests!(r#else); +tests!(r#enum); +tests!(r#extern); +tests!(r#false); +tests!(r#fn); +tests!(r#for); +tests!(r#if); +tests!(r#impl); +tests!(r#in); +tests!(r#let); +tests!(r#loop); +tests!(r#match); +tests!(r#mod); +tests!(r#move); +tests!(r#mut); +tests!(r#pub); +tests!(r#ref); +tests!(r#return); +tests!(r#static); +tests!(r#struct); +tests!(r#trait); +tests!(r#true); +tests!(r#type); +tests!(r#unsafe); +tests!(r#use); +tests!(r#where); +tests!(r#while); +tests!(r#abstract); +tests!(r#become); +tests!(r#box); +tests!(r#do); +tests!(r#final); +tests!(r#macro); +tests!(r#override); +tests!(r#priv); +tests!(r#typeof); +tests!(r#unsized); +tests!(r#virtual); +tests!(r#yield); +tests!(r#async); +tests!(r#await); +tests!(r#dyn); +tests!(r#gen); +tests!(r#try); + +// Weak keywords: +tests!(auto); +tests!(builtin); +tests!(catch); +tests!(default); +tests!(macro_rules); +tests!(raw); +tests!(reuse); +tests!(contract_ensures); +tests!(contract_requires); +tests!(safe); +tests!(union); +tests!(yeet); -- cgit 1.4.1-3-g733a5