From 83f35c0bf435fc743abb54a94ee10de9701c417b Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 27 Dec 2023 16:04:30 +0000 Subject: [PATCH 1/3] Treat `k#ident` keywords as valid tokens --- compiler/rustc_ast/src/token.rs | 8 ++++++-- compiler/rustc_ast_pretty/src/pprust/state.rs | 1 + compiler/rustc_expand/src/proc_macro_server.rs | 5 +++++ compiler/rustc_lexer/src/lib.rs | 17 +++++++++++++++++ compiler/rustc_parse/src/lexer/mod.rs | 12 ++++++++++++ compiler/rustc_span/src/symbol.rs | 1 + src/librustdoc/html/highlight.rs | 1 + .../crates/parser/src/lexed_str.rs | 1 + 8 files changed, 44 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index d62462b1ae33b..8e5bb8297be4e 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -299,6 +299,10 @@ pub enum TokenKind { /// It's recommended to use `Token::(ident,uninterpolate,uninterpolated_span)` to /// treat regular and interpolated identifiers in the same way. Ident(Symbol, /* is_raw */ bool), + + /// A `k#ident` keyword + Keyword(Symbol), + /// Lifetime identifier token. /// Do not forget about `NtLifetime` when you want to match on lifetime identifiers. /// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to @@ -438,7 +442,7 @@ impl Token { | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question | SingleQuote => true, OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..) - | Lifetime(..) | Interpolated(..) | Eof => false, + | Keyword(..) | Lifetime(..) | Interpolated(..) | Eof => false, } } @@ -812,7 +816,7 @@ impl Token { Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar - | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) + | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) | Keyword(..) | Lifetime(..) | Interpolated(..) | DocComment(..) | Eof => return None, }; diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index f4b424259deef..95c6093a9cbef 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -781,6 +781,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere token::Ident(s, is_raw) => { IdentPrinter::new(s, is_raw, convert_dollar_crate).to_string().into() } + token::Keyword(s) => format!("k#{s}").into(), token::Lifetime(s) => s.to_string().into(), /* Other */ diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 5eb6aed72534d..b7ab825d49033 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -203,6 +203,11 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec op("'"), Ident(sym, is_raw) => trees.push(TokenTree::Ident(Ident { sym, is_raw, span })), + Keyword(sym) => trees.extend([ + TokenTree::Ident(Ident { sym: sym::k, is_raw: false, span }), + TokenTree::Punct(Punct { ch: b'#', joint: true, span }), + TokenTree::Ident(Ident { sym, is_raw: false, span }), + ]), Lifetime(name) => { let ident = symbol::Ident::new(name, span).without_first_quote(); trees.extend([ diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 43dfd34a6ff74..13fbdda904ca8 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -78,6 +78,9 @@ pub enum TokenKind { /// "r#ident" RawIdent, + /// "k#ident" + KeywordIdent, + /// An unknown prefix, like `foo#`, `foo'`, `foo"`. /// /// Note that only the @@ -375,6 +378,11 @@ impl Cursor<'_> { None, ), + 'k' => match (self.first(), self.second()) { + ('#', c1) if is_id_start(c1) => self.keyword_ident(), + _ => self.ident_or_unknown_prefix(), + }, + // Identifier (this should be checked after other variant that can // start as identifier). c if is_id_start(c) => self.ident_or_unknown_prefix(), @@ -505,6 +513,15 @@ impl Cursor<'_> { RawIdent } + fn keyword_ident(&mut self) -> TokenKind { + debug_assert!(self.prev() == 'k' && self.first() == '#' && is_id_start(self.second())); + // Eat "#" symbol. + self.bump(); + // Eat the identifier part of KeywordIdent. + self.eat_identifier(); + KeywordIdent + } + fn ident_or_unknown_prefix(&mut self) -> TokenKind { debug_assert!(is_id_start(self.prev())); // Start is already eaten, eat the rest of identifier. diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 083d1984e0031..fcd5c96fffb65 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -185,6 +185,18 @@ impl<'a> StringReader<'a> { self.sess.raw_identifier_spans.push(span); token::Ident(sym, true) } + // Treat `k#ident` as a normal identifier token before 2021. + rustc_lexer::TokenKind::KeywordIdent if !self.mk_sp(start, self.pos).edition().at_least_rust_2021() => { + // FIXME: what should we do when this is a _known_ prefix? + self.report_unknown_prefix(start); + self.ident(start) + } + rustc_lexer::TokenKind::KeywordIdent => { + let sym = nfc_normalize(self.str_from(start)); + let span = self.mk_sp(start, self.pos); + self.sess.symbol_gallery.insert(sym, span); + token::Keyword(sym) + } rustc_lexer::TokenKind::UnknownPrefix => { self.report_unknown_prefix(start); self.ident(start) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 0b44071496ea8..ad8b1f88263eb 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -918,6 +918,7 @@ symbols! { iter_repeat, iterator, iterator_collect_fn, + k, kcfi, keyword, kind, diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 1cdc792a819a8..32528d2dfe3bf 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -878,6 +878,7 @@ impl<'src> Classifier<'src> { TokenKind::RawIdent | TokenKind::UnknownPrefix | TokenKind::InvalidIdent => { Class::Ident(self.new_span(before, text)) } + TokenKind::KeywordIdent => Class::KeyWord, TokenKind::Lifetime { .. } => Class::Lifetime, TokenKind::Eof => panic!("Eof in advance"), }; diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs index b9e7566fdf9bc..c6a9a3ee8f54c 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs @@ -224,6 +224,7 @@ impl<'a> Converter<'a> { rustc_lexer::TokenKind::Slash => T![/], rustc_lexer::TokenKind::Caret => T![^], rustc_lexer::TokenKind::Percent => T![%], + rustc_lexer::TokenKind::KeywordIdent => ERROR, rustc_lexer::TokenKind::Unknown => ERROR, rustc_lexer::TokenKind::UnknownPrefix if token_text == "builtin" => IDENT, rustc_lexer::TokenKind::UnknownPrefix => { From 52f3cd5c232ac5161ddb9981ac8bc56b816e47f7 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Thu, 28 Dec 2023 10:24:45 +0000 Subject: [PATCH 2/3] Change `token::Ident` to use `IdentKind` --- compiler/rustc_ast/src/token.rs | 81 ++++++++++++------- compiler/rustc_ast/src/tokenstream.rs | 4 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 11 +-- compiler/rustc_builtin_macros/src/asm.rs | 4 +- .../src/assert/context.rs | 7 +- compiler/rustc_expand/src/mbe/macro_check.rs | 7 +- compiler/rustc_expand/src/mbe/macro_rules.rs | 23 ++++-- compiler/rustc_expand/src/mbe/metavar_expr.rs | 4 +- compiler/rustc_expand/src/mbe/quoted.rs | 8 +- compiler/rustc_expand/src/parse/tests.rs | 41 +++++++--- .../rustc_expand/src/proc_macro_server.rs | 26 ++++-- .../rustc_expand/src/tokenstream/tests.rs | 7 +- compiler/rustc_lint/src/builtin.rs | 3 +- compiler/rustc_parse/src/lexer/mod.rs | 14 ++-- .../rustc_parse/src/lexer/unicode_chars.rs | 3 +- .../rustc_parse/src/parser/diagnostics.rs | 14 ++-- compiler/rustc_parse/src/parser/expr.rs | 56 ++++++++----- compiler/rustc_parse/src/parser/item.rs | 17 ++-- compiler/rustc_parse/src/parser/mod.rs | 12 +-- .../rustc_parse/src/parser/nonterminal.rs | 4 +- compiler/rustc_parse/src/parser/pat.rs | 4 +- compiler/rustc_parse/src/parser/path.rs | 6 +- compiler/rustc_parse/src/parser/stmt.rs | 4 +- compiler/rustc_span/src/symbol.rs | 21 +++-- src/librustdoc/clean/render_macro_matchers.rs | 4 +- 25 files changed, 246 insertions(+), 139 deletions(-) diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 8e5bb8297be4e..a1c2db2dfde7e 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -107,7 +107,9 @@ impl Lit { /// Keep this in sync with `Token::can_begin_literal_or_bool` excluding unary negation. pub fn from_token(token: &Token) -> Option { match token.uninterpolate().kind { - Ident(name, false) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)), + Ident(name, IdentKind::Default) 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.0 @@ -183,8 +185,8 @@ impl LitKind { } } -pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool { - let ident_token = Token::new(Ident(name, is_raw), span); +pub fn ident_can_begin_expr(name: Symbol, span: Span, kind: IdentKind) -> bool { + let ident_token = Token::new(Ident(name, kind), span); !ident_token.is_reserved_ident() || ident_token.is_path_segment_keyword() @@ -212,15 +214,37 @@ pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool { kw::Static, ] .contains(&name) + || kind == IdentKind::Keyword } -fn ident_can_begin_type(name: Symbol, span: Span, is_raw: bool) -> bool { - let ident_token = Token::new(Ident(name, is_raw), span); +fn ident_can_begin_type(name: Symbol, span: Span, kind: IdentKind) -> bool { + let ident_token = Token::new(Ident(name, kind), span); !ident_token.is_reserved_ident() || ident_token.is_path_segment_keyword() || [kw::Underscore, kw::For, kw::Impl, kw::Fn, kw::Unsafe, kw::Extern, kw::Typeof, kw::Dyn] .contains(&name) + || kind == IdentKind::Keyword +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable_Generic, Encodable, Decodable)] +pub enum IdentKind { + /// The usual identifiers (or, depending on the context, keywords): `v`, `union`, `await`, `loop`. + Default, + /// Raw identifiers: `r#just_an_ident`, `r#loop`. + Raw, + /// Forced keywords: `k#break`, `k#await`, `k#some_new_experimental_keyword`. + Keyword, +} + +impl IdentKind { + pub fn prefix(self) -> Option<&'static str> { + match self { + IdentKind::Default => None, + IdentKind::Raw => Some("r#"), + IdentKind::Keyword => Some("k#"), + } + } } // SAFETY: due to the `Clone` impl below, all fields of all variants other than @@ -298,10 +322,7 @@ pub enum TokenKind { /// Do not forget about `NtIdent` when you want to match on identifiers. /// It's recommended to use `Token::(ident,uninterpolate,uninterpolated_span)` to /// treat regular and interpolated identifiers in the same way. - Ident(Symbol, /* is_raw */ bool), - - /// A `k#ident` keyword - Keyword(Symbol), + Ident(Symbol, IdentKind), /// Lifetime identifier token. /// Do not forget about `NtLifetime` when you want to match on lifetime identifiers. @@ -415,7 +436,13 @@ impl Token { /// Recovers a `Token` from an `Ident`. This creates a raw identifier if necessary. pub fn from_ast_ident(ident: Ident) -> Self { - Token::new(Ident(ident.name, ident.is_raw_guess()), ident.span) + Token::new( + Ident( + ident.name, + if ident.is_raw_guess() { IdentKind::Raw } else { IdentKind::Default }, + ), + ident.span, + ) } /// For interpolated tokens, returns a span of the fragment to which the interpolated @@ -442,7 +469,7 @@ impl Token { | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question | SingleQuote => true, OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..) - | Keyword(..) | Lifetime(..) | Interpolated(..) | Eof => false, + | Lifetime(..) | Interpolated(..) | Eof => false, } } @@ -571,7 +598,7 @@ impl Token { pub fn can_begin_literal_maybe_minus(&self) -> bool { match self.uninterpolate().kind { Literal(..) | BinOp(Minus) => true, - Ident(name, false) if name.is_bool_lit() => true, + Ident(name, IdentKind::Default) if name.is_bool_lit() => true, Interpolated(ref nt) => match &nt.0 { NtLiteral(_) => true, NtExpr(e) => match &e.kind { @@ -606,10 +633,10 @@ impl Token { /// Returns an identifier if this token is an identifier. #[inline] - pub fn ident(&self) -> Option<(Ident, /* is_raw */ bool)> { + pub fn ident(&self) -> Option<(Ident, IdentKind)> { // We avoid using `Token::uninterpolate` here because it's slow. match &self.kind { - &Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)), + &Ident(name, kind) => Some((Ident::new(name, self.span), kind)), Interpolated(nt) => match &nt.0 { NtIdent(ident, is_raw) => Some((*ident, *is_raw)), _ => None, @@ -702,46 +729,46 @@ impl Token { /// Returns `true` if the token is a given keyword, `kw`. pub fn is_keyword(&self, kw: Symbol) -> bool { - self.is_non_raw_ident_where(|id| id.name == kw) + self.is_keywordable_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. pub fn is_keyword_case(&self, kw: Symbol, case: Case) -> bool { self.is_keyword(kw) || (case == Case::Insensitive - && self.is_non_raw_ident_where(|id| { + && self.is_keywordable_ident_where(|id| { id.name.as_str().to_lowercase() == kw.as_str().to_lowercase() })) } pub fn is_path_segment_keyword(&self) -> bool { - self.is_non_raw_ident_where(Ident::is_path_segment_keyword) + self.is_keywordable_ident_where(Ident::is_path_segment_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 { - self.is_non_raw_ident_where(Ident::is_special) + self.is_keywordable_ident_where(Ident::is_special) } /// Returns `true` if the token is a keyword used in the language. pub fn is_used_keyword(&self) -> bool { - self.is_non_raw_ident_where(Ident::is_used_keyword) + self.is_keywordable_ident_where(Ident::is_used_keyword) } /// Returns `true` if the token is a keyword reserved for possible future use. pub fn is_unused_keyword(&self) -> bool { - self.is_non_raw_ident_where(Ident::is_unused_keyword) + self.is_keywordable_ident_where(Ident::is_unused_keyword) } /// Returns `true` if the token is either a special identifier or a keyword. pub fn is_reserved_ident(&self) -> bool { - self.is_non_raw_ident_where(Ident::is_reserved) + self.is_keywordable_ident_where(Ident::is_reserved) } /// Returns `true` if the token is the identifier `true` or `false`. pub fn is_bool_lit(&self) -> bool { - self.is_non_raw_ident_where(|id| id.name.is_bool_lit()) + self.is_keywordable_ident_where(|id| id.name.is_bool_lit()) } pub fn is_numeric_lit(&self) -> bool { @@ -757,9 +784,9 @@ impl Token { } /// Returns `true` if the token is a non-raw identifier for which `pred` holds. - pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(Ident) -> bool) -> bool { + pub fn is_keywordable_ident_where(&self, pred: impl FnOnce(Ident) -> bool) -> bool { match self.ident() { - Some((id, false)) => pred(id), + Some((id, IdentKind::Default | IdentKind::Keyword)) => pred(id), _ => false, } } @@ -810,13 +837,13 @@ impl Token { _ => return None, }, SingleQuote => match joint.kind { - Ident(name, false) => Lifetime(Symbol::intern(&format!("'{name}"))), + Ident(name, IdentKind::Default) => Lifetime(Symbol::intern(&format!("'{name}"))), _ => return None, }, Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar - | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) | Keyword(..) + | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) | Lifetime(..) | Interpolated(..) | DocComment(..) | Eof => return None, }; @@ -840,7 +867,7 @@ pub enum Nonterminal { NtPat(P), NtExpr(P), NtTy(P), - NtIdent(Ident, /* is_raw */ bool), + NtIdent(Ident, IdentKind), NtLifetime(Ident), NtLiteral(P), /// Stuff inside brackets for attributes diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 4c0c496584eb8..147eea31bb366 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -15,7 +15,7 @@ use crate::ast::{AttrStyle, StmtKind}; use crate::ast_traits::{HasAttrs, HasSpan, HasTokens}; -use crate::token::{self, Delimiter, Nonterminal, Token, TokenKind}; +use crate::token::{self, Delimiter, IdentKind, Nonterminal, Token, TokenKind}; use crate::AttrVec; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -677,7 +677,7 @@ impl TokenStream { DelimSpacing::new(Spacing::JointHidden, Spacing::Alone), Delimiter::Bracket, [ - TokenTree::token_alone(token::Ident(sym::doc, false), span), + TokenTree::token_alone(token::Ident(sym::doc, IdentKind::Default), span), TokenTree::token_alone(token::Eq, span), TokenTree::token_alone( TokenKind::lit(token::StrRaw(num_of_hashes), data, None), diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 95c6093a9cbef..b5dea9ce87b46 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -268,7 +268,9 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool); fn print_ident(&mut self, ident: Ident) { - self.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string()); + self.word( + IdentPrinter::for_ast_ident(ident, ident.is_raw_guess().then(|| "r#")).to_string(), + ); self.ann_post(ident) } @@ -715,7 +717,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere token::NtBlock(e) => self.block_to_string(e), token::NtStmt(e) => self.stmt_to_string(e), token::NtPat(e) => self.pat_to_string(e), - token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(*e, *is_raw).to_string(), + &token::NtIdent(e, kind) => IdentPrinter::for_ast_ident(e, kind.prefix()).to_string(), token::NtLifetime(e) => e.to_string(), token::NtLiteral(e) => self.expr_to_string(e), token::NtVis(e) => self.vis_to_string(e), @@ -778,10 +780,9 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere token::Literal(lit) => literal_to_string(lit).into(), /* Name components */ - token::Ident(s, is_raw) => { - IdentPrinter::new(s, is_raw, convert_dollar_crate).to_string().into() + token::Ident(s, kind) => { + IdentPrinter::new(s, kind.prefix(), convert_dollar_crate).to_string().into() } - token::Keyword(s) => format!("k#{s}").into(), token::Lifetime(s) => s.to_string().into(), /* Other */ diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index b5801c1b0f168..938324787f3df 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -1,6 +1,6 @@ use rustc_ast as ast; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter}; +use rustc_ast::token::{self, Delimiter, IdentKind}; use rustc_ast::tokenstream::TokenStream; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::PResult; @@ -416,7 +416,7 @@ fn parse_reg<'a>( ) -> PResult<'a, ast::InlineAsmRegOrRegClass> { p.expect(&token::OpenDelim(Delimiter::Parenthesis))?; let result = match p.token.uninterpolate().kind { - token::Ident(name, false) => ast::InlineAsmRegOrRegClass::RegClass(name), + token::Ident(name, IdentKind::Default) => ast::InlineAsmRegOrRegClass::RegClass(name), token::Literal(token::Lit { kind: token::LitKind::Str, symbol, suffix: _ }) => { *explicit_reg = true; ast::InlineAsmRegOrRegClass::Reg(symbol) diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index d244897f8a5de..6941e19d2de2e 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -1,7 +1,7 @@ use rustc_ast::{ ptr::P, token, - token::Delimiter, + token::{Delimiter, IdentKind}, tokenstream::{DelimSpan, TokenStream, TokenTree}, BinOpKind, BorrowKind, DelimArgs, Expr, ExprKind, ItemKind, MacCall, MethodCall, Mutability, Path, PathSegment, Stmt, StructRest, UnOp, UseTree, UseTreeKind, DUMMY_NODE_ID, @@ -170,7 +170,10 @@ impl<'cx, 'a> Context<'cx, 'a> { ]; let captures = self.capture_decls.iter().flat_map(|cap| { [ - TokenTree::token_joint_hidden(token::Ident(cap.ident.name, false), cap.ident.span), + TokenTree::token_joint_hidden( + token::Ident(cap.ident.name, IdentKind::Default), + cap.ident.span, + ), TokenTree::token_alone(token::Comma, self.span), ] }); diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index e66cfbe6fb689..576ca342c649d 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -107,7 +107,7 @@ use crate::errors; use crate::mbe::{KleeneToken, TokenTree}; -use rustc_ast::token::{Delimiter, Token, TokenKind}; +use rustc_ast::token::{Delimiter, IdentKind, Token, TokenKind}; use rustc_ast::{NodeId, DUMMY_NODE_ID}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{DiagnosticMessage, MultiSpan}; @@ -409,7 +409,10 @@ fn check_nested_occurrences( match (state, tt) { ( NestedMacroState::Empty, - &TokenTree::Token(Token { kind: TokenKind::Ident(name, false), .. }), + &TokenTree::Token(Token { + kind: TokenKind::Ident(name, IdentKind::Default | IdentKind::Keyword), + .. + }), ) => { if name == kw::MacroRules { state = NestedMacroState::MacroRules; diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index e9736d6f2c8ae..0eb25d4ea19fc 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -9,7 +9,8 @@ use crate::mbe::macro_parser::{MatchedSeq, MatchedTokenTree, MatcherLoc}; use crate::mbe::transcribe::transcribe; use rustc_ast as ast; -use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind, TokenKind::*}; +use rustc_ast::token::TokenKind::*; +use rustc_ast::token::{self, Delimiter, IdentKind, NonterminalKind, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast::{NodeId, DUMMY_NODE_ID}; use rustc_ast_pretty::pprust; @@ -1323,7 +1324,11 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { match tok { TokenTree::Token(token) => match token.kind { FatArrow | Comma | Eq | BinOp(token::Or) => IsInFollow::Yes, - Ident(name, false) if name == kw::If || name == kw::In => IsInFollow::Yes, + Ident(name, IdentKind::Default | IdentKind::Keyword) + if name == kw::If || name == kw::In => + { + IsInFollow::Yes + } _ => IsInFollow::No(TOKENS), }, _ => IsInFollow::No(TOKENS), @@ -1334,7 +1339,11 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { match tok { TokenTree::Token(token) => match token.kind { FatArrow | Comma | Eq => IsInFollow::Yes, - Ident(name, false) if name == kw::If || name == kw::In => IsInFollow::Yes, + Ident(name, IdentKind::Default | IdentKind::Keyword) + if name == kw::If || name == kw::In => + { + IsInFollow::Yes + } _ => IsInFollow::No(TOKENS), }, _ => IsInFollow::No(TOKENS), @@ -1357,7 +1366,9 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { | BinOp(token::Shr) | Semi | BinOp(token::Or) => IsInFollow::Yes, - Ident(name, false) if name == kw::As || name == kw::Where => { + Ident(name, IdentKind::Default | IdentKind::Keyword) + if name == kw::As || name == kw::Where => + { IsInFollow::Yes } _ => IsInFollow::No(TOKENS), @@ -1385,7 +1396,9 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { match tok { TokenTree::Token(token) => match token.kind { Comma => IsInFollow::Yes, - Ident(name, is_raw) if is_raw || name != kw::Priv => IsInFollow::Yes, + Ident(name, kind) if kind == IdentKind::Raw || name != kw::Priv => { + IsInFollow::Yes + } _ => { if token.can_begin_type() { IsInFollow::Yes diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs index e3dc73d0d851f..4a0a9c861d277 100644 --- a/compiler/rustc_expand/src/mbe/metavar_expr.rs +++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs @@ -1,4 +1,4 @@ -use rustc_ast::token::{self, Delimiter}; +use rustc_ast::token::{self, Delimiter, IdentKind}; use rustc_ast::tokenstream::{RefTokenTreeCursor, TokenStream, TokenTree}; use rustc_ast::{LitIntType, LitKind}; use rustc_ast_pretty::pprust; @@ -142,7 +142,7 @@ fn parse_ident<'sess>( if let Some(tt) = iter.next() && let TokenTree::Token(token, _) = tt { - if let Some((elem, false)) = token.ident() { + if let Some((elem, IdentKind::Default)) = token.ident() { return Ok(elem); } let token_str = pprust::token_to_string(token); diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 445be01bc97c3..fb883ca20bd9e 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -1,7 +1,7 @@ use crate::mbe::macro_parser::count_metavar_decls; use crate::mbe::{Delimited, KleeneOp, KleeneToken, MetaVarExpr, SequenceRepetition, TokenTree}; -use rustc_ast::token::{self, Delimiter, Token}; +use rustc_ast::token::{self, Delimiter, IdentKind, Token}; use rustc_ast::{tokenstream, NodeId}; use rustc_ast_pretty::pprust; use rustc_feature::Features; @@ -218,10 +218,10 @@ fn parse_tree<'a>( // `tree` is followed by an `ident`. This could be `$meta_var` or the `$crate` // special metavariable that names the crate of the invocation. Some(tokenstream::TokenTree::Token(token, _)) if token.is_ident() => { - let (ident, is_raw) = token.ident().unwrap(); + let (ident, kind) = token.ident().unwrap(); let span = ident.span.with_lo(span.lo()); - if ident.name == kw::Crate && !is_raw { - TokenTree::token(token::Ident(kw::DollarCrate, is_raw), span) + if ident.name == kw::Crate && kind == IdentKind::Default { + TokenTree::token(token::Ident(kw::DollarCrate, kind), span) } else { TokenTree::MetaVar(span, ident) } diff --git a/compiler/rustc_expand/src/parse/tests.rs b/compiler/rustc_expand/src/parse/tests.rs index 7a888250ca161..2b903d744a36b 100644 --- a/compiler/rustc_expand/src/parse/tests.rs +++ b/compiler/rustc_expand/src/parse/tests.rs @@ -3,7 +3,7 @@ use crate::tests::{ }; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, Token}; +use rustc_ast::token::{self, Delimiter, IdentKind, Token}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_ast::visit; use rustc_ast::{self as ast, PatKind}; @@ -74,9 +74,12 @@ fn string_to_tts_macro() { match tts { [ - TokenTree::Token(Token { kind: token::Ident(name_macro_rules, false), .. }, _), + TokenTree::Token( + Token { kind: token::Ident(name_macro_rules, IdentKind::Default), .. }, + _, + ), TokenTree::Token(Token { kind: token::Not, .. }, _), - TokenTree::Token(Token { kind: token::Ident(name_zip, false), .. }, _), + TokenTree::Token(Token { kind: token::Ident(name_zip, IdentKind::Default), .. }, _), TokenTree::Delimited(.., macro_delim, macro_tts), ] if name_macro_rules == &kw::MacroRules && name_zip.as_str() == "zip" => { let tts = ¯o_tts.trees().collect::>(); @@ -90,7 +93,10 @@ fn string_to_tts_macro() { match &tts[..] { [ TokenTree::Token(Token { kind: token::Dollar, .. }, _), - TokenTree::Token(Token { kind: token::Ident(name, false), .. }, _), + TokenTree::Token( + Token { kind: token::Ident(name, IdentKind::Default), .. }, + _, + ), ] if first_delim == &Delimiter::Parenthesis && name.as_str() == "a" => { } _ => panic!("value 3: {:?} {:?}", first_delim, first_tts), @@ -99,7 +105,10 @@ fn string_to_tts_macro() { match &tts[..] { [ TokenTree::Token(Token { kind: token::Dollar, .. }, _), - TokenTree::Token(Token { kind: token::Ident(name, false), .. }, _), + TokenTree::Token( + Token { kind: token::Ident(name, IdentKind::Default), .. }, + _, + ), ] if second_delim == &Delimiter::Parenthesis && name.as_str() == "a" => {} _ => panic!("value 4: {:?} {:?}", second_delim, second_tts), @@ -119,8 +128,11 @@ fn string_to_tts_1() { let tts = string_to_stream("fn a(b: i32) { b; }".to_string()); let expected = TokenStream::new(vec![ - TokenTree::token_alone(token::Ident(kw::Fn, false), sp(0, 2)), - TokenTree::token_joint_hidden(token::Ident(Symbol::intern("a"), false), sp(3, 4)), + TokenTree::token_alone(token::Ident(kw::Fn, IdentKind::Default), sp(0, 2)), + TokenTree::token_joint_hidden( + token::Ident(Symbol::intern("a"), IdentKind::Default), + sp(3, 4), + ), TokenTree::Delimited( DelimSpan::from_pair(sp(4, 5), sp(11, 12)), // `JointHidden` because the `(` is followed immediately by @@ -128,10 +140,16 @@ fn string_to_tts_1() { DelimSpacing::new(Spacing::JointHidden, Spacing::Alone), Delimiter::Parenthesis, TokenStream::new(vec![ - TokenTree::token_joint(token::Ident(Symbol::intern("b"), false), sp(5, 6)), + TokenTree::token_joint( + token::Ident(Symbol::intern("b"), IdentKind::Default), + sp(5, 6), + ), TokenTree::token_alone(token::Colon, sp(6, 7)), // `JointHidden` because the `i32` is immediately followed by the `)`. - TokenTree::token_joint_hidden(token::Ident(sym::i32, false), sp(8, 11)), + TokenTree::token_joint_hidden( + token::Ident(sym::i32, IdentKind::Default), + sp(8, 11), + ), ]) .into(), ), @@ -143,7 +161,10 @@ fn string_to_tts_1() { DelimSpacing::new(Spacing::Alone, Spacing::Alone), Delimiter::Brace, TokenStream::new(vec![ - TokenTree::token_joint(token::Ident(Symbol::intern("b"), false), sp(15, 16)), + TokenTree::token_joint( + token::Ident(Symbol::intern("b"), IdentKind::Default), + sp(15, 16), + ), // `Alone` because the `;` is followed by whitespace. TokenTree::token_alone(token::Semi, sp(16, 17)), ]) diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index b7ab825d49033..35007f50ac1b3 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -4,7 +4,7 @@ use pm::bridge::{ }; use pm::{Delimiter, Level}; use rustc_ast as ast; -use rustc_ast::token; +use rustc_ast::token::{self, IdentKind}; use rustc_ast::tokenstream::{self, DelimSpacing, Spacing, TokenStream}; use rustc_ast::util::literal::escape_byte_str_symbol; use rustc_ast_pretty::pprust; @@ -202,8 +202,9 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec op("?"), SingleQuote => op("'"), - Ident(sym, is_raw) => trees.push(TokenTree::Ident(Ident { sym, is_raw, span })), - Keyword(sym) => trees.extend([ + Ident(sym, kind @ (IdentKind::Default | IdentKind::Raw)) => trees + .push(TokenTree::Ident(Ident { sym, is_raw: kind == IdentKind::Raw, span })), + Ident(sym, IdentKind::Keyword) => trees.extend([ TokenTree::Ident(Ident { sym: sym::k, is_raw: false, span }), TokenTree::Punct(Punct { ch: b'#', joint: true, span }), TokenTree::Ident(Ident { sym, is_raw: false, span }), @@ -229,7 +230,7 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec)> for Vec { + Interpolated(ref nt) if let NtIdent(ident, IdentKind::Keyword) = nt.0 => trees + .extend([ + TokenTree::Ident(Ident { sym: sym::k, is_raw: false, span }), + TokenTree::Punct(Punct { ch: b'#', joint: true, span }), + TokenTree::Ident(Ident { sym: ident.name, is_raw: false, span }), + ]), + Interpolated(ref nt) if let NtIdent(ident, kind) = nt.0 => { trees.push(TokenTree::Ident(Ident { sym: ident.name, - is_raw: *is_raw, + is_raw: kind == IdentKind::Raw, span: ident.span, })) } @@ -343,7 +350,10 @@ impl ToInternal> } TokenTree::Ident(self::Ident { sym, is_raw, span }) => { rustc.sess().symbol_gallery.insert(sym, span); - smallvec![tokenstream::TokenTree::token_alone(Ident(sym, is_raw), span)] + smallvec![tokenstream::TokenTree::token_alone( + Ident(sym, if is_raw { IdentKind::Raw } else { IdentKind::Default }), + span + )] } TokenTree::Literal(self::Literal { kind: self::LitKind::Integer, @@ -560,7 +570,7 @@ impl server::TokenStream for Rustc<'_, '_> { match &expr.kind { ast::ExprKind::Lit(token_lit) if token_lit.kind == token::Bool => { Ok(tokenstream::TokenStream::token_alone( - token::Ident(token_lit.symbol, false), + token::Ident(token_lit.symbol, IdentKind::Default), expr.span, )) } diff --git a/compiler/rustc_expand/src/tokenstream/tests.rs b/compiler/rustc_expand/src/tokenstream/tests.rs index 91c4dd732e3a5..495383626a583 100644 --- a/compiler/rustc_expand/src/tokenstream/tests.rs +++ b/compiler/rustc_expand/src/tokenstream/tests.rs @@ -1,6 +1,6 @@ use crate::tests::string_to_stream; -use rustc_ast::token; +use rustc_ast::token::{self, IdentKind}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_span::create_default_session_globals_then; use rustc_span::{BytePos, Span, Symbol}; @@ -86,7 +86,10 @@ fn test_diseq_1() { fn test_is_empty() { create_default_session_globals_then(|| { let test0 = TokenStream::default(); - let test1 = TokenStream::token_alone(token::Ident(Symbol::intern("a"), false), sp(0, 1)); + let test1 = TokenStream::token_alone( + token::Ident(Symbol::intern("a"), IdentKind::Default), + sp(0, 1), + ); let test2 = string_to_ts("foo(bar::baz)"); assert_eq!(test0.is_empty(), true); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 8afb5f2d32ebf..d8de1baac5f1a 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -40,6 +40,7 @@ use crate::{ }, EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext, }; +use ast::token::IdentKind; use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::visit::{FnCtxt, FnKind}; use rustc_ast::{self as ast, *}; @@ -1831,7 +1832,7 @@ impl KeywordIdents { match tt { // Only report non-raw idents. TokenTree::Token(token, _) => { - if let Some((ident, false)) = token.ident() { + if let Some((ident, IdentKind::Default)) = token.ident() { self.check_ident_token(cx, UnderMacro(true), ident); } } diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index fcd5c96fffb65..ee1342be4e2bc 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -4,7 +4,7 @@ use crate::errors; use crate::lexer::unicode_chars::UNICODE_ARRAY; use crate::make_unclosed_delims_error; use rustc_ast::ast::{self, AttrStyle}; -use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind}; +use rustc_ast::token::{self, CommentKind, Delimiter, IdentKind, Token, TokenKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::unicode::contains_text_flow_control_chars; use rustc_errors::{ @@ -183,10 +183,10 @@ impl<'a> StringReader<'a> { self.dcx().emit_err(errors::CannotBeRawIdent { span, ident: sym }); } self.sess.raw_identifier_spans.push(span); - token::Ident(sym, true) + token::Ident(sym, IdentKind::Raw) } - // Treat `k#ident` as a normal identifier token before 2021. - rustc_lexer::TokenKind::KeywordIdent if !self.mk_sp(start, self.pos).edition().at_least_rust_2021() => { + // Treat `k#ident` as a normal identifier token before edition 2021. + rustc_lexer::TokenKind::KeywordIdent if self.mk_sp(start, self.pos).edition() < Edition::Edition2021 => { // FIXME: what should we do when this is a _known_ prefix? self.report_unknown_prefix(start); self.ident(start) @@ -195,7 +195,7 @@ impl<'a> StringReader<'a> { let sym = nfc_normalize(self.str_from(start)); let span = self.mk_sp(start, self.pos); self.sess.symbol_gallery.insert(sym, span); - token::Keyword(sym) + token::Ident(sym, IdentKind::Keyword) } rustc_lexer::TokenKind::UnknownPrefix => { self.report_unknown_prefix(start); @@ -215,7 +215,7 @@ impl<'a> StringReader<'a> { let span = self.mk_sp(start, self.pos); self.sess.bad_unicode_identifiers.borrow_mut().entry(sym).or_default() .push(span); - token::Ident(sym, false) + token::Ident(sym, IdentKind::Default) } // split up (raw) c string literals to an ident and a string literal when edition < 2021. rustc_lexer::TokenKind::Literal { @@ -353,7 +353,7 @@ impl<'a> StringReader<'a> { let sym = nfc_normalize(self.str_from(start)); let span = self.mk_sp(start, self.pos); self.sess.symbol_gallery.insert(sym, span); - token::Ident(sym, false) + token::Ident(sym, IdentKind::Default) } fn struct_fatal_span_char( diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index dac7569e385e7..4fbb3c844f46d 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -6,6 +6,7 @@ use crate::{ errors::TokenSubstitution, token::{self, Delimiter}, }; +use rustc_ast::token::IdentKind; use rustc_span::{symbol::kw, BytePos, Pos, Span}; #[rustfmt::skip] // for line breaks @@ -307,7 +308,7 @@ pub(crate) const UNICODE_ARRAY: &[(char, &str, &str)] = &[ // fancier error recovery to it, as there will be less overall work to do this way. const ASCII_ARRAY: &[(&str, &str, Option)] = &[ (" ", "Space", None), - ("_", "Underscore", Some(token::Ident(kw::Underscore, false))), + ("_", "Underscore", Some(token::Ident(kw::Underscore, IdentKind::Default))), ("-", "Minus/Hyphen", Some(token::BinOp(token::Minus))), (",", "Comma", Some(token::Comma)), (";", "Semicolon", Some(token::Semi)), diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 77bca2f138a9d..7c07776c8f95e 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -23,7 +23,7 @@ use crate::parser; use crate::parser::attr::InnerAttrPolicy; use rustc_ast as ast; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, Lit, LitKind, TokenKind}; +use rustc_ast::token::{self, Delimiter, IdentKind, Lit, LitKind, TokenKind}; use rustc_ast::tokenstream::AttrTokenTree; use rustc_ast::util::parser::AssocOp; use rustc_ast::{ @@ -264,7 +264,7 @@ impl<'a> Parser<'a> { pub(super) fn expected_ident_found( &mut self, recover: bool, - ) -> PResult<'a, (Ident, /* is_raw */ bool)> { + ) -> PResult<'a, (Ident, IdentKind)> { if let TokenKind::DocComment(..) = self.prev_token.kind { return Err(self.dcx().create_err(DocCommentDoesNotDocumentAnything { span: self.prev_token.span, @@ -290,11 +290,11 @@ impl<'a> Parser<'a> { let bad_token = self.token.clone(); // suggest prepending a keyword in identifier position with `r#` - let suggest_raw = if let Some((ident, false)) = self.token.ident() + let suggest_raw = if let Some((ident, IdentKind::Default)) = self.token.ident() && ident.is_raw_guess() && self.look_ahead(1, |t| valid_follow.contains(&t.kind)) { - recovered_ident = Some((ident, true)); + recovered_ident = Some((ident, IdentKind::Raw)); // `Symbol::to_string()` is different from `Symbol::into_diagnostic_arg()`, // which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#` @@ -320,7 +320,7 @@ impl<'a> Parser<'a> { let help_cannot_start_number = self.is_lit_bad_ident().map(|(len, valid_portion)| { let (invalid, valid) = self.token.span.split_at(len as u32); - recovered_ident = Some((Ident::new(valid_portion, valid), false)); + recovered_ident = Some((Ident::new(valid_portion, valid), IdentKind::Default)); HelpIdentifierStartsWithNumber { num_span: invalid } }); @@ -654,9 +654,9 @@ impl<'a> Parser<'a> { // positive for a `cr#` that wasn't intended to start a c-string literal, but identifying // that in the parser requires unbounded lookahead, so we only add a hint to the existing // error rather than replacing it entirely. - if ((self.prev_token.kind == TokenKind::Ident(sym::c, false) + if ((self.prev_token.kind == TokenKind::Ident(sym::c, IdentKind::Default) && matches!(&self.token.kind, TokenKind::Literal(token::Lit { kind: token::Str, .. }))) - || (self.prev_token.kind == TokenKind::Ident(sym::cr, false) + || (self.prev_token.kind == TokenKind::Ident(sym::cr, IdentKind::Default) && matches!( &self.token.kind, TokenKind::Literal(token::Lit { kind: token::Str, .. }) | token::Pound diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index bf6151b64d3f1..be98a3105cc4f 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -9,20 +9,21 @@ use super::{ use crate::errors; use crate::maybe_recover_from_interpolated_ty_qpath; -use ast::mut_visit::{noop_visit_expr, MutVisitor}; -use ast::{CoroutineKind, ForLoopKind, GenBlockKind, Pat, Path, PathSegment}; use core::mem; +use rustc_ast::mut_visit::{noop_visit_expr, MutVisitor}; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, Token, TokenKind}; +use rustc_ast::token::{self, Delimiter, IdentKind, Token, TokenKind}; use rustc_ast::tokenstream::Spacing; use rustc_ast::util::case::Case; use rustc_ast::util::classify; use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity}; use rustc_ast::visit::Visitor; -use rustc_ast::{self as ast, AttrStyle, AttrVec, CaptureBy, ExprField, UnOp, DUMMY_NODE_ID}; -use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty, TyKind}; -use rustc_ast::{Arm, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits}; -use rustc_ast::{ClosureBinder, MetaItemLit, StmtKind}; +use rustc_ast::{ + self as ast, AnonConst, Arm, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy, + ClosureBinder, CoroutineKind, Expr, ExprField, ExprKind, FnDecl, FnRetTy, ForLoopKind, + GenBlockKind, Label, MacCall, MetaItemLit, Movability, Param, Pat, Path, PathSegment, + RangeLimits, StmtKind, Ty, TyKind, UnOp, DUMMY_NODE_ID, +}; use rustc_ast_pretty::pprust; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ @@ -128,7 +129,7 @@ impl<'a> Parser<'a> { match self.parse_expr_res(restrictions, None) { Ok(expr) => Ok(expr), Err(mut err) => match self.token.ident() { - Some((Ident { name: kw::Underscore, .. }, false)) + Some((Ident { name: kw::Underscore, .. }, IdentKind::Default)) if self.may_recover() && self.look_ahead(1, |t| t == &token::Comma) => { // Special-case handling of `foo(_, _, _)` @@ -446,7 +447,9 @@ impl<'a> Parser<'a> { return None; } (Some(op), _) => (op, self.token.span), - (None, Some((Ident { name: sym::and, span }, false))) if self.may_recover() => { + (None, Some((Ident { name: sym::and, span }, IdentKind::Default))) + if self.may_recover() => + { self.dcx().emit_err(errors::InvalidLogicalOperator { span: self.token.span, incorrect: "and".into(), @@ -454,7 +457,9 @@ impl<'a> Parser<'a> { }); (AssocOp::LAnd, span) } - (None, Some((Ident { name: sym::or, span }, false))) if self.may_recover() => { + (None, Some((Ident { name: sym::or, span }, IdentKind::Default))) + if self.may_recover() => + { self.dcx().emit_err(errors::InvalidLogicalOperator { span: self.token.span, incorrect: "or".into(), @@ -738,7 +743,10 @@ impl<'a> Parser<'a> { ( // `foo: ` ExprKind::Path(None, ast::Path { segments, .. }), - token::Ident(kw::For | kw::Loop | kw::While, false), + token::Ident( + kw::For | kw::Loop | kw::While, + IdentKind::Default | IdentKind::Keyword, + ), ) if segments.len() == 1 => { let snapshot = self.create_snapshot_for_diagnostic(); let label = Label { @@ -951,7 +959,10 @@ impl<'a> Parser<'a> { fn parse_expr_dot_or_call_with_(&mut self, mut e: P, lo: Span) -> PResult<'a, P> { loop { - let has_question = if self.prev_token.kind == TokenKind::Ident(kw::Return, false) { + let has_question = if matches!( + self.prev_token.kind, + TokenKind::Ident(kw::Return, IdentKind::Default | IdentKind::Keyword) + ) { // we are using noexpect here because we don't expect a `?` directly after a `return` // which could be suggested otherwise self.eat_noexpect(&token::Question) @@ -963,7 +974,10 @@ impl<'a> Parser<'a> { e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e)); continue; } - let has_dot = if self.prev_token.kind == TokenKind::Ident(kw::Return, false) { + let has_dot = if matches!( + self.prev_token.kind, + TokenKind::Ident(kw::Return, IdentKind::Default | IdentKind::Keyword) + ) { // we are using noexpect here because we don't expect a `.` directly after a `return` // which could be suggested otherwise self.eat_noexpect(&token::Dot) @@ -1123,19 +1137,20 @@ impl<'a> Parser<'a> { // 1. DestructuredFloat::TrailingDot(sym, ident_span, dot_span) => { assert!(suffix.is_none()); - self.token = Token::new(token::Ident(sym, false), ident_span); + self.token = Token::new(token::Ident(sym, IdentKind::Default), ident_span); let next_token = (Token::new(token::Dot, dot_span), self.token_spacing); self.parse_expr_tuple_field_access(lo, base, sym, None, Some(next_token)) } // 1.2 | 1.2e3 DestructuredFloat::MiddleDot(symbol1, ident1_span, dot_span, symbol2, ident2_span) => { - self.token = Token::new(token::Ident(symbol1, false), ident1_span); + self.token = Token::new(token::Ident(symbol1, IdentKind::Default), ident1_span); // This needs to be `Spacing::Alone` to prevent regressions. // See issue #76399 and PR #76285 for more details let next_token1 = (Token::new(token::Dot, dot_span), Spacing::Alone); let base1 = self.parse_expr_tuple_field_access(lo, base, symbol1, None, Some(next_token1)); - let next_token2 = Token::new(token::Ident(symbol2, false), ident2_span); + let next_token2 = + Token::new(token::Ident(symbol2, IdentKind::Default), ident2_span); self.bump_with((next_token2, self.token_spacing)); // `.` self.parse_expr_tuple_field_access(lo, base1, symbol2, suffix, None) } @@ -1163,7 +1178,7 @@ impl<'a> Parser<'a> { // in cases like `offset_of!(Ty, 1.)`. It depends on what comes // after the float-like token, and therefore we have to make // the other parts of the parser think that there is a dot literal. - self.token = Token::new(token::Ident(sym, false), sym_span); + self.token = Token::new(token::Ident(sym, IdentKind::Default), sym_span); self.bump_with((Token::new(token::Dot, dot_span), self.token_spacing)); thin_vec![Ident::new(sym, sym_span)] } @@ -1881,7 +1896,7 @@ impl<'a> Parser<'a> { self.bump(); // `builtin` self.bump(); // `#` - let Some((ident, false)) = self.token.ident() else { + let Some((ident, IdentKind::Default)) = self.token.ident() else { let err = self.dcx().create_err(errors::ExpectedBuiltinIdent { span: self.token.span }); return Err(err); }; @@ -3481,8 +3496,9 @@ impl<'a> Parser<'a> { /// Use in case of error after field-looking code: `S { foo: () with a }`. fn find_struct_error_after_field_looking_code(&self) -> Option { match self.token.ident() { - Some((ident, is_raw)) - if (is_raw || !ident.is_reserved()) + Some((ident, kind)) + if (kind == IdentKind::Raw || !ident.is_reserved()) + && kind != IdentKind::Keyword && self.look_ahead(1, |t| *t == token::Colon) => { Some(ast::ExprField { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 0ac0b678abace..ef11b1da235c9 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -5,7 +5,7 @@ use crate::errors::{self, MacroExpandsToAdtField}; use crate::fluent_generated as fluent; use rustc_ast::ast::*; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, TokenKind}; +use rustc_ast::token::{self, Delimiter, IdentKind, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast::util::case::Case; use rustc_ast::{self as ast}; @@ -781,7 +781,7 @@ impl<'a> Parser<'a> { // However, we must avoid keywords that occur as binary operators. // Currently, the only applicable keyword is `as` (`default as Ty`). if self.check_keyword(kw::Default) - && self.look_ahead(1, |t| t.is_non_raw_ident_where(|i| i.name != kw::As)) + && self.look_ahead(1, |t| t.is_keywordable_ident_where(|i| i.name != kw::As)) { self.bump(); // `default` Defaultness::Default(self.prev_token.uninterpolated_span()) @@ -1024,7 +1024,7 @@ impl<'a> Parser<'a> { fn parse_ident_or_underscore(&mut self) -> PResult<'a, Ident> { match self.token.ident() { - Some((ident @ Ident { name: kw::Underscore, .. }, false)) => { + Some((ident @ Ident { name: kw::Underscore, .. }, IdentKind::Default)) => { self.bump(); Ok(ident) } @@ -1917,10 +1917,11 @@ impl<'a> Parser<'a> { /// Parses a field identifier. Specialized version of `parse_ident_common` /// for better diagnostics and suggestions. fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> { - let (ident, is_raw) = self.ident_or_err(true)?; + let (ident, kind) = self.ident_or_err(true)?; if ident.name == kw::Underscore { self.sess.gated_spans.gate(sym::unnamed_fields, lo); - } else if !is_raw && ident.is_reserved() { + } else if (kind == IdentKind::Default && ident.is_reserved()) || kind == IdentKind::Keyword + { let snapshot = self.create_snapshot_for_diagnostic(); let err = if self.check_fn_front_matter(false, Case::Sensitive) { let inherited_vis = Visibility { @@ -2344,13 +2345,13 @@ impl<'a> Parser<'a> { // Two qualifiers `$qual $qual` is enough, e.g. `async unsafe`. || ( ( - t.is_non_raw_ident_where(|i| + t.is_keywordable_ident_where(|i| quals.contains(&i.name) // Rule out 2015 `const async: T = val`. && i.is_reserved() ) || case == Case::Insensitive - && t.is_non_raw_ident_where(|i| quals.iter().any(|qual| qual.as_str() == i.name.as_str().to_lowercase())) + && t.is_keywordable_ident_where(|i| quals.iter().any(|qual| qual.as_str() == i.name.as_str().to_lowercase())) ) // Rule out `unsafe extern {`. && !self.is_unsafe_foreign_mod() @@ -2695,7 +2696,7 @@ impl<'a> Parser<'a> { fn parse_self_param(&mut self) -> PResult<'a, Option> { // Extract an identifier *after* having confirmed that the token is one. let expect_self_ident = |this: &mut Self| match this.token.ident() { - Some((ident, false)) => { + Some((ident, IdentKind::Default | IdentKind::Keyword)) => { this.bump(); ident } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 19226f37abec1..fae2d48b2fe42 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -19,7 +19,7 @@ pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; pub use path::PathStyle; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, Nonterminal, Token, TokenKind}; +use rustc_ast::token::{self, Delimiter, IdentKind, Nonterminal, Token, TokenKind}; use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing}; use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor}; use rustc_ast::util::case::Case; @@ -495,9 +495,9 @@ impl<'a> Parser<'a> { } fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, Ident> { - let (ident, is_raw) = self.ident_or_err(recover)?; + let (ident, kind) = self.ident_or_err(recover)?; - if !is_raw && ident.is_reserved() { + if (kind == IdentKind::Default && ident.is_reserved()) || kind == IdentKind::Keyword { let mut err = self.expected_ident_found_err(); if recover { err.emit(); @@ -509,7 +509,7 @@ impl<'a> Parser<'a> { Ok(ident) } - fn ident_or_err(&mut self, recover: bool) -> PResult<'a, (Ident, /* is_raw */ bool)> { + fn ident_or_err(&mut self, recover: bool) -> PResult<'a, (Ident, IdentKind)> { match self.token.ident() { Some(ident) => Ok(ident), None => self.expected_ident_found(recover), @@ -566,7 +566,7 @@ impl<'a> Parser<'a> { } if case == Case::Insensitive - && let Some((ident, /* is_raw */ false)) = self.token.ident() + && let Some((ident, IdentKind::Default | IdentKind::Keyword)) = self.token.ident() && ident.as_str().to_lowercase() == kw.as_str().to_lowercase() { true @@ -596,7 +596,7 @@ impl<'a> Parser<'a> { } if case == Case::Insensitive - && let Some((ident, /* is_raw */ false)) = self.token.ident() + && let Some((ident, IdentKind::Default | IdentKind::Keyword)) = self.token.ident() && ident.as_str().to_lowercase() == kw.as_str().to_lowercase() { self.dcx().emit_err(errors::KwBadCase { span: ident.span, kw: kw.as_str() }); diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 071d6b72f3b96..ddb96d24b7911 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -1,5 +1,5 @@ use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, Nonterminal::*, NonterminalKind, Token}; +use rustc_ast::token::{self, Delimiter, IdentKind, Nonterminal::*, NonterminalKind, Token}; use rustc_ast::HasTokens; use rustc_ast_pretty::pprust; use rustc_errors::PResult; @@ -201,6 +201,6 @@ impl<'a> Parser<'a> { /// The token is an identifier, but not `_`. /// We prohibit passing `_` to macros expecting `ident` for now. -fn get_macro_ident(token: &Token) -> Option<(Ident, bool)> { +fn get_macro_ident(token: &Token) -> Option<(Ident, IdentKind)> { token.ident().filter(|(ident, _)| ident.name != kw::Underscore) } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index afbc253757816..3fe11dccd4a32 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -12,7 +12,7 @@ use crate::errors::{ use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor}; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter}; +use rustc_ast::token::{self, Delimiter, IdentKind}; use rustc_ast::{ self as ast, AttrVec, BindingAnnotation, ByRef, Expr, ExprKind, MacCall, Mutability, Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, @@ -308,7 +308,7 @@ impl<'a> Parser<'a> { matches!( &token.uninterpolate().kind, token::FatArrow // e.g. `a | => 0,`. - | token::Ident(kw::If, false) // e.g. `a | if expr`. + | token::Ident(kw::If, IdentKind::Default | IdentKind::Keyword) // e.g. `a | if expr`. | token::Eq // e.g. `let a | = 0`. | token::Semi // e.g. `let a |;`. | token::Colon // e.g. `let a | :`. diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 4253c0ae421a6..955df2381808c 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -3,7 +3,7 @@ use super::{Parser, Restrictions, TokenType}; use crate::errors::PathSingleColon; use crate::{errors, maybe_whole}; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, Token, TokenKind}; +use rustc_ast::token::{self, Delimiter, IdentKind, Token, TokenKind}; use rustc_ast::{ self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocConstraint, AssocConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs, @@ -390,7 +390,9 @@ impl<'a> Parser<'a> { pub(super) fn parse_path_segment_ident(&mut self) -> PResult<'a, Ident> { match self.token.ident() { - Some((ident, false)) if ident.is_path_segment_keyword() => { + Some((ident, IdentKind::Default | IdentKind::Keyword)) + if ident.is_path_segment_keyword() => + { self.bump(); Ok(ident) } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 831edcd88c11b..5f0961b9e7fdc 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -14,7 +14,7 @@ use crate::errors::MalformedLoopLabel; 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, IdentKind, TokenKind}; use rustc_ast::util::classify; use rustc_ast::{AttrStyle, AttrVec, LocalKind, MacCall, MacCallStmt, MacStmtStyle}; use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, HasAttrs, Local, Stmt}; @@ -684,7 +684,7 @@ impl<'a> Parser<'a> { token.kind, token::Ident( kw::For | kw::Loop | kw::While, - false + IdentKind::Default | IdentKind::Keyword ) | token::OpenDelim(Delimiter::Brace) ) }) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ad8b1f88263eb..775da8bf36e78 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1913,7 +1913,7 @@ impl fmt::Debug for Ident { /// except that AST identifiers don't keep the rawness flag, so we have to guess it. impl fmt::Display for Ident { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&IdentPrinter::new(self.name, self.is_raw_guess(), None), f) + fmt::Display::fmt(&IdentPrinter::new(self.name, self.is_raw_guess().then(|| "r#"), None), f) } } @@ -1932,7 +1932,8 @@ impl fmt::Display for Ident { /// done for a token stream or a single token. pub struct IdentPrinter { symbol: Symbol, - is_raw: bool, + /// `Some("r#")` for a raw ident, `Some("k#")` for a forced keyword, `None` for a default ident. + prefix: Option<&'static str>, /// Span used for retrieving the crate name to which `$crate` refers to, /// if this field is `None` then the `$crate` conversion doesn't happen. convert_dollar_crate: Option, @@ -1940,22 +1941,26 @@ pub struct IdentPrinter { impl IdentPrinter { /// The most general `IdentPrinter` constructor. Do not use this. - pub fn new(symbol: Symbol, is_raw: bool, convert_dollar_crate: Option) -> IdentPrinter { - IdentPrinter { symbol, is_raw, convert_dollar_crate } + pub fn new( + symbol: Symbol, + prefix: Option<&'static str>, + convert_dollar_crate: Option, + ) -> IdentPrinter { + IdentPrinter { symbol, prefix, convert_dollar_crate } } /// This implementation is supposed to be used when printing identifiers /// as a part of pretty-printing for larger AST pieces. /// Do not use this either. - pub fn for_ast_ident(ident: Ident, is_raw: bool) -> IdentPrinter { - IdentPrinter::new(ident.name, is_raw, Some(ident.span)) + pub fn for_ast_ident(ident: Ident, prefix: Option<&'static str>) -> IdentPrinter { + IdentPrinter::new(ident.name, prefix, Some(ident.span)) } } impl fmt::Display for IdentPrinter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.is_raw { - f.write_str("r#")?; + if let Some(prefix) = self.prefix { + f.write_str(prefix)?; } else if self.symbol == kw::DollarCrate { if let Some(span) = self.convert_dollar_crate { let converted = span.ctxt().dollar_crate_name(); diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs index 605f9e496c769..a69e0a537ff1a 100644 --- a/src/librustdoc/clean/render_macro_matchers.rs +++ b/src/librustdoc/clean/render_macro_matchers.rs @@ -1,4 +1,4 @@ -use rustc_ast::token::{self, BinOpToken, Delimiter}; +use rustc_ast::token::{self, BinOpToken, Delimiter, IdentKind}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast_pretty::pprust::state::State as Printer; use rustc_ast_pretty::pprust::PrintState; @@ -148,7 +148,7 @@ fn print_tts(printer: &mut Printer<'_>, tts: &TokenStream) { (false, Other) } (Pound, token::Not) => (false, PoundBang), - (_, token::Ident(symbol, /* is_raw */ false)) + (_, token::Ident(symbol, IdentKind::Default | IdentKind::Keyword)) if !usually_needs_space_between_keyword_and_open_delim(*symbol, tt.span) => { (true, Ident) From c2de4837e6627542848ba09374435f6a7c07c4a1 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sat, 30 Dec 2023 06:48:17 +0000 Subject: [PATCH 3/3] feature gate --- compiler/rustc_ast_passes/src/feature_gate.rs | 1 + compiler/rustc_feature/src/unstable.rs | 2 ++ compiler/rustc_parse/src/lexer/mod.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + 4 files changed, 5 insertions(+) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 2b746789a769f..2a35f9b5a480e 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -516,6 +516,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { } }; } + gate_all!(forced_keywords, "`k#ident` syntax is experimental",); gate_all!( if_let_guard, "`if let` guards are experimental", diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 763bd4fc3916b..b9a164d50571b 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -473,6 +473,8 @@ declare_features! ( (unstable, fn_align, "1.53.0", Some(82232)), /// Support delegating implementation of functions to other already implemented functions. (incomplete, fn_delegation, "1.76.0", Some(118212)), + /// Support forcing an ident to be recognized as a keyword through `k#ident`. + (unstable, forced_keywords, "CURRENT_RUSTC_VERSION", None), /// Allows defining gen blocks and `gen fn`. (unstable, gen_blocks, "1.75.0", Some(117078)), /// Infer generic args for both consts and types. diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index ee1342be4e2bc..09ea45ebbfee5 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -194,6 +194,7 @@ impl<'a> StringReader<'a> { rustc_lexer::TokenKind::KeywordIdent => { let sym = nfc_normalize(self.str_from(start)); let span = self.mk_sp(start, self.pos); + self.sess.gated_spans.gate(sym::forced_keywords, span); self.sess.symbol_gallery.insert(sym, span); token::Ident(sym, IdentKind::Keyword) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 775da8bf36e78..e8b4a4ec64602 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -787,6 +787,7 @@ symbols! { fn_ptr_addr, fn_ptr_trait, forbid, + forced_keywords, forget, format, format_alignment,