From 9dd5340d3cbbd3acbe6cc9dfcbcea07e7eb4355e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 12 Mar 2025 16:14:32 +1100 Subject: [PATCH 1/5] Remove `is_any_keyword` methods. They're dodgy, covering all the keywords, including weak ones, and edition-specific ones without considering the edition. They have a single use in rustfmt. This commit changes that use to `is_reserved_ident`, which is a much more widely used alternative and is good enough, judging by the lack of effect on the test suite. --- compiler/rustc_ast/src/token.rs | 5 ----- compiler/rustc_span/src/symbol.rs | 24 +++++++---------------- src/tools/rustfmt/src/parse/macros/mod.rs | 2 +- 3 files changed, 8 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index f7cd63aaaf823..6e6f0f1b2660e 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -928,11 +928,6 @@ impl Token { self.is_non_raw_ident_where(Ident::is_path_segment_keyword) } - /// Don't use this unless you're doing something very loose and heuristic-y. - pub fn is_any_keyword(&self) -> bool { - self.is_non_raw_ident_where(Ident::is_any_keyword) - } - /// Returns true for reserved identifiers used internally for elided lifetimes, /// unnamed method parameters, crate root module, error recovery etc. pub fn is_special_ident(&self) -> bool { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 210966bed6277..5f81d36a74e79 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -32,7 +32,7 @@ symbols! { Keywords { // Special reserved identifiers used internally for elided lifetimes, // unnamed method parameters, crate root module, error recovery etc. - // Matching predicates: `is_any_keyword`, `is_special`/`is_reserved` + // Matching predicates: `is_special`/`is_reserved` // // Notes about `kw::Empty`: // - Its use can blur the lines between "empty symbol" and "no symbol". @@ -48,7 +48,7 @@ symbols! { Underscore: "_", // Keywords that are used in stable Rust. - // Matching predicates: `is_any_keyword`, `is_used_keyword_always`/`is_reserved` + // Matching predicates: `is_used_keyword_always`/`is_reserved` As: "as", Break: "break", Const: "const", @@ -86,7 +86,7 @@ symbols! { While: "while", // Keywords that are used in unstable Rust or reserved for future use. - // Matching predicates: `is_any_keyword`, `is_unused_keyword_always`/`is_reserved` + // Matching predicates: `is_unused_keyword_always`/`is_reserved` Abstract: "abstract", Become: "become", Box: "box", @@ -101,14 +101,14 @@ symbols! { Yield: "yield", // Edition-specific keywords that are used in stable Rust. - // Matching predicates: `is_any_keyword`, `is_used_keyword_conditional`/`is_reserved` (if + // Matching predicates: `is_used_keyword_conditional`/`is_reserved` (if // the edition suffices) Async: "async", // >= 2018 Edition only Await: "await", // >= 2018 Edition only Dyn: "dyn", // >= 2018 Edition only // Edition-specific keywords that are used in unstable Rust or reserved for future use. - // Matching predicates: `is_any_keyword`, `is_unused_keyword_conditional`/`is_reserved` (if + // Matching predicates: `is_unused_keyword_conditional`/`is_reserved` (if // the edition suffices) Gen: "gen", // >= 2024 Edition only Try: "try", // >= 2018 Edition only @@ -116,12 +116,12 @@ symbols! { // 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` + // Matching predicates: none UnderscoreLifetime: "'_", StaticLifetime: "'static", // Weak keywords, have special meaning only in specific contexts. - // Matching predicates: `is_any_keyword` + // Matching predicates: none Auto: "auto", Builtin: "builtin", Catch: "catch", @@ -2677,11 +2677,6 @@ pub mod sym { } impl Symbol { - /// Don't use this unless you're doing something very loose and heuristic-y. - pub fn is_any_keyword(self) -> bool { - self >= kw::As && self <= kw::Yeet - } - fn is_special(self) -> bool { self <= kw::Underscore } @@ -2738,11 +2733,6 @@ impl Symbol { } impl Ident { - /// Don't use this unless you're doing something very loose and heuristic-y. - pub fn is_any_keyword(self) -> bool { - self.name.is_any_keyword() - } - /// Returns `true` for reserved identifiers used internally for elided lifetimes, /// unnamed method parameters, crate root module, error recovery etc. pub fn is_special(self) -> bool { diff --git a/src/tools/rustfmt/src/parse/macros/mod.rs b/src/tools/rustfmt/src/parse/macros/mod.rs index 680a35f7e03ad..d7964484b261f 100644 --- a/src/tools/rustfmt/src/parse/macros/mod.rs +++ b/src/tools/rustfmt/src/parse/macros/mod.rs @@ -81,7 +81,7 @@ pub(crate) struct ParsedMacroArgs { } fn check_keyword<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option { - if parser.token.is_any_keyword() + if parser.token.is_reserved_ident() && parser.look_ahead(1, |t| *t == TokenKind::Eof || *t == TokenKind::Comma) { let keyword = parser.token.ident().unwrap().0.name; From a28d5092e9da9973fd56a4de5e85a632400c85f0 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 12 Mar 2025 16:18:20 +1100 Subject: [PATCH 2/5] Improve keyword comments a little. --- compiler/rustc_span/src/symbol.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 5f81d36a74e79..11f271af0b73d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -26,9 +26,10 @@ symbols! { // documents (such as the Rust Reference) about whether it is a keyword // (e.g. `_`). // - // If you modify this list, adjust any relevant `Symbol::{is,can_be}_*` predicates and - // `used_keywords`. - // But this should rarely be necessary if the keywords are kept in alphabetic order. + // If you modify this list, adjust any relevant `Symbol::{is,can_be}_*` + // predicates and `used_keywords`. (This should rarely be necessary if + // the keywords are kept in alphabetic order.) Also consider adding new + // keywords to the `ui/parser/raw/raw-idents.rs` test. Keywords { // Special reserved identifiers used internally for elided lifetimes, // unnamed method parameters, crate root module, error recovery etc. @@ -113,8 +114,6 @@ 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: none UnderscoreLifetime: "'_", From 3aaa12f622f294fd0d5f86a31415eb1fb4669bdd Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 12 Mar 2025 16:18:40 +1100 Subject: [PATCH 3/5] Fix some formatting. --- compiler/rustc_span/src/symbol.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 11f271af0b73d..394774b576461 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -128,8 +128,8 @@ symbols! { MacroRules: "macro_rules", Raw: "raw", Reuse: "reuse", - ContractEnsures: "contract_ensures", - ContractRequires: "contract_requires", + ContractEnsures: "contract_ensures", + ContractRequires: "contract_requires", Safe: "safe", Union: "union", Yeet: "yeet", From 10236fbe7bea988dd94509e437c63b855fd1ec00 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 12 Mar 2025 16:26:24 +1100 Subject: [PATCH 4/5] Alphabetize the keywords list. --- compiler/rustc_span/src/symbol.rs | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 394774b576461..33ffa00a3691c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -27,9 +27,8 @@ symbols! { // (e.g. `_`). // // If you modify this list, adjust any relevant `Symbol::{is,can_be}_*` - // predicates and `used_keywords`. (This should rarely be necessary if - // the keywords are kept in alphabetic order.) Also consider adding new - // keywords to the `ui/parser/raw/raw-idents.rs` test. + // predicates and `used_keywords`. Also consider adding new keywords to the + // `ui/parser/raw/raw-idents.rs` test. Keywords { // Special reserved identifiers used internally for elided lifetimes, // unnamed method parameters, crate root module, error recovery etc. @@ -43,13 +42,16 @@ symbols! { // present, it's better to use `sym::dummy` than `kw::Empty`, because // it's clearer that it's intended as a dummy value, and more likely // to be detected if it accidentally does get used. + // tidy-alphabetical-start + DollarCrate: "$crate", Empty: "", PathRoot: "{{root}}", - DollarCrate: "$crate", Underscore: "_", + // tidy-alphabetical-end // Keywords that are used in stable Rust. // Matching predicates: `is_used_keyword_always`/`is_reserved` + // tidy-alphabetical-start As: "as", Break: "break", Const: "const", @@ -85,9 +87,11 @@ symbols! { Use: "use", Where: "where", While: "while", + // tidy-alphabetical-end // Keywords that are used in unstable Rust or reserved for future use. // Matching predicates: `is_unused_keyword_always`/`is_reserved` + // tidy-alphabetical-start Abstract: "abstract", Become: "become", Box: "box", @@ -100,39 +104,48 @@ symbols! { Unsized: "unsized", Virtual: "virtual", Yield: "yield", + // tidy-alphabetical-end // Edition-specific keywords that are used in stable Rust. // Matching predicates: `is_used_keyword_conditional`/`is_reserved` (if // the edition suffices) + // tidy-alphabetical-start Async: "async", // >= 2018 Edition only Await: "await", // >= 2018 Edition only Dyn: "dyn", // >= 2018 Edition only + // tidy-alphabetical-end // Edition-specific keywords that are used in unstable Rust or reserved for future use. // Matching predicates: `is_unused_keyword_conditional`/`is_reserved` (if // the edition suffices) + // tidy-alphabetical-start Gen: "gen", // >= 2024 Edition only Try: "try", // >= 2018 Edition only + // tidy-alphabetical-end // "Lifetime keywords": regular keywords with a leading `'`. // Matching predicates: none - UnderscoreLifetime: "'_", + // tidy-alphabetical-start StaticLifetime: "'static", + UnderscoreLifetime: "'_", + // tidy-alphabetical-end // Weak keywords, have special meaning only in specific contexts. // Matching predicates: none + // tidy-alphabetical-start Auto: "auto", Builtin: "builtin", Catch: "catch", + ContractEnsures: "contract_ensures", + ContractRequires: "contract_requires", Default: "default", MacroRules: "macro_rules", Raw: "raw", Reuse: "reuse", - ContractEnsures: "contract_ensures", - ContractRequires: "contract_requires", Safe: "safe", Union: "union", Yeet: "yeet", + // tidy-alphabetical-end } // Pre-interned symbols that can be referred to with `rustc_span::sym::*`. @@ -2781,7 +2794,7 @@ impl Ident { /// *Note:* Please update this if a new keyword is added beyond the current /// range. pub fn used_keywords(edition: impl Copy + FnOnce() -> Edition) -> Vec { - (kw::Empty.as_u32()..kw::Yeet.as_u32()) + (kw::DollarCrate.as_u32()..kw::Yeet.as_u32()) .filter_map(|kw| { let kw = Symbol::new(kw); if kw.is_used_keyword_always() || kw.is_used_keyword_conditional(edition) { From a29e875b63542b1809ae6beb6fabbdacbb16971f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 12 Mar 2025 16:28:15 +1100 Subject: [PATCH 5/5] Move `is_used_keyword_conditional`. So the order of the `Symbol::is_*` predicates match the order of the keywords list. --- compiler/rustc_span/src/symbol.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 33ffa00a3691c..3e4742439655a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2697,14 +2697,14 @@ impl Symbol { self >= kw::As && self <= kw::While } - fn is_used_keyword_conditional(self, edition: impl FnOnce() -> Edition) -> bool { - (self >= kw::Async && self <= kw::Dyn) && edition() >= Edition::Edition2018 - } - fn is_unused_keyword_always(self) -> bool { self >= kw::Abstract && self <= kw::Yield } + fn is_used_keyword_conditional(self, edition: impl FnOnce() -> Edition) -> bool { + (self >= kw::Async && self <= kw::Dyn) && edition() >= Edition::Edition2018 + } + fn is_unused_keyword_conditional(self, edition: impl Copy + FnOnce() -> Edition) -> bool { self == kw::Gen && edition().at_least_rust_2024() || self == kw::Try && edition().at_least_rust_2018()