diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index ea464fc8ebbb5..1de452dcf3965 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 62723e385cf64..757450cc0685c 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 0000000000000..93015ee6c4942 --- /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);