From 763db5dcd9b95179915e13533af280ad5f6db403 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 5 Mar 2025 17:11:46 +1100 Subject: [PATCH 1/4] Convert a delayed bug to a bug. This is never hit in the test suite. At some point the check should be removed entirely. There are a million places in the compiler where an empty symbol doesn't make sense, so a check of this nature has almost zero value. But I'll leave it in place for now just in case it gets hit by fuzzing or in the wild. --- compiler/rustc_hir_typeck/src/expr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 786e8b876a613..7e4026db738d7 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2933,7 +2933,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let guar = if field.name == kw::Empty { - self.dcx().span_delayed_bug(field.span, "field name with no name") + self.dcx().span_bug(field.span, "field name with no name") } else if self.method_exists_for_diagnostic( field, base_ty, From fe04460f6fdc32c0783ca7cab6a0fb73ed254100 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 7 Mar 2025 07:29:41 +1100 Subject: [PATCH 2/4] Remove an unnecessary `kw::Empty` check. Replace it with an assert for now, just in case it is reachable. --- compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index c46a42c5de1e3..61b6f21596e44 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -825,15 +825,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let trait_missing_method = matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait(); - if item_name.name != kw::Empty { - self.report_method_error( - hir_id, - ty.normalized, - error, - Expectation::NoExpectation, - trait_missing_method && span.edition().at_least_rust_2021(), // emits missing method for trait only after edition 2021 - ); - } + assert_ne!(item_name.name, kw::Empty); + self.report_method_error( + hir_id, + ty.normalized, + error, + Expectation::NoExpectation, + trait_missing_method && span.edition().at_least_rust_2021(), // emits missing method for trait only after edition 2021 + ); result }); From 0b2d7062c47fa385ff83e20dc53b13c8c5ba4616 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 4 Mar 2025 17:10:55 +1100 Subject: [PATCH 3/4] Introduce `sym::dummy` and `Ident::dummy`. The idea is to identify cases of symbols/identifiers that are not expected to be used. There isn't a perfectly sharp line between "dummy" and "not dummy", but I think it's useful nonetheless. --- compiler/rustc_ast/src/mut_visit.rs | 2 +- compiler/rustc_attr_parsing/src/context.rs | 3 +-- compiler/rustc_attr_parsing/src/parser.rs | 4 ++-- compiler/rustc_expand/src/mbe/quoted.rs | 2 +- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_resolve/src/diagnostics.rs | 2 +- compiler/rustc_span/src/symbol.rs | 22 ++++++++++++++++++++++ 7 files changed, 29 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index e4396a50a15eb..fc31912283a7e 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1948,7 +1948,7 @@ impl DummyAstNode for Item { span: Default::default(), tokens: Default::default(), }, - ident: Ident::empty(), + ident: Ident::dummy(), kind: ItemKind::ExternCrate(None), tokens: Default::default(), } diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 0e6b0bab082e9..35541bb04bd7b 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -9,7 +9,6 @@ use rustc_errors::{DiagCtxtHandle, Diagnostic}; use rustc_feature::Features; use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId}; use rustc_session::Session; -use rustc_span::symbol::kw; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; @@ -338,7 +337,7 @@ impl<'sess> AttributeParser<'sess> { "expr in place where literal is expected (builtin attr parsing)", ); ast::MetaItemLit { - symbol: kw::Empty, + symbol: sym::dummy, suffix: None, kind: ast::LitKind::Err(guar), span: DUMMY_SP, diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index f0cce26f4e248..a8a1460591cf3 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -12,7 +12,7 @@ use rustc_ast::{AttrArgs, DelimArgs, Expr, ExprKind, LitKind, MetaItemLit, Norma use rustc_ast_pretty::pprust; use rustc_errors::DiagCtxtHandle; use rustc_hir::{self as hir, AttrPath}; -use rustc_span::symbol::{Ident, kw}; +use rustc_span::symbol::{Ident, kw, sym}; use rustc_span::{ErrorGuaranteed, Span, Symbol}; pub struct SegmentIterator<'a> { @@ -360,7 +360,7 @@ fn expr_to_lit(dcx: DiagCtxtHandle<'_>, expr: &Expr, span: Span) -> MetaItemLit span, "expr in place where literal is expected (builtin attr parsing)", ); - MetaItemLit { symbol: kw::Empty, suffix: None, kind: LitKind::Err(guar), span } + MetaItemLit { symbol: sym::dummy, suffix: None, kind: LitKind::Err(guar), span } } } diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 8cb001391c529..0ea53627fe786 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -274,7 +274,7 @@ fn parse_tree<'a>( let msg = format!("expected identifier, found `{}`", pprust::token_to_string(token),); sess.dcx().span_err(token.span, msg); - TokenTree::MetaVar(token.span, Ident::empty()) + TokenTree::MetaVar(token.span, Ident::dummy()) } // There are no more tokens. Just return the `$` we already have. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 53f0194091cdc..4ec7aff72862a 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -243,7 +243,7 @@ impl<'hir> PathSegment<'hir> { } pub fn invalid() -> Self { - Self::new(Ident::empty(), HirId::INVALID, Res::Err) + Self::new(Ident::dummy(), HirId::INVALID, Res::Err) } pub fn args(&self) -> &GenericArgs<'hir> { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index e3405c89b79ab..88d1126de1aea 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2266,7 +2266,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && !first.ident.is_path_segment_keyword() => { // Insert a placeholder that's later replaced by `self`/`super`/etc. - path.insert(0, Segment::from_ident(Ident::empty())); + path.insert(0, Segment::from_ident(Ident::dummy())); } _ => return None, } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 718f23d761f07..8a8bec35d8194 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -33,6 +33,15 @@ symbols! { // 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` + // + // Notes about `kw::Empty`: + // - Its use can blur the lines between "empty symbol" and "no symbol". + // Using `Option` is preferable, where possible, because that + // is unambiguous. + // - For dummy symbols that are never used and absolutely must be + // 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. Empty: "", PathRoot: "{{root}}", DollarCrate: "$crate", @@ -834,6 +843,7 @@ symbols! { drop_types_in_const, dropck_eyepatch, dropck_parametricity, + dummy: "", // use this instead of `kw::Empty` for symbols that won't be used dummy_cgu_name, dylib, dyn_compatible_for_dispatch, @@ -2305,11 +2315,23 @@ impl Ident { Ident::new(name, DUMMY_SP) } + /// This is best avoided, because it blurs the lines between "empty + /// identifier" and "no identifier". Using `Option` is preferable, + /// where possible, because that is unambiguous. #[inline] pub fn empty() -> Ident { Ident::with_dummy_span(kw::Empty) } + // For dummy identifiers that are never used and absolutely must be + // present, it's better to use `Ident::dummy` than `Ident::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. + #[inline] + pub fn dummy() -> Ident { + Ident::with_dummy_span(sym::dummy) + } + /// Maps a string to an identifier with a dummy span. pub fn from_str(string: &str) -> Ident { Ident::with_dummy_span(Symbol::intern(string)) From 4eadaff1844a0bfc7f8f69bbd1c137538b92b9dc Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 11 Mar 2025 14:14:08 +1100 Subject: [PATCH 4/4] Convert a `kw::Empty` occurrence to `sym::dummy`. `adjust_ident_and_get_scope` returns the symbol it receives unchanged, and the call site ignores the returned symbol, so this symbol is unused. --- compiler/rustc_privacy/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 5271d03a6f617..ff203b2938e06 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -40,7 +40,7 @@ use rustc_middle::ty::{ use rustc_middle::{bug, span_bug}; use rustc_session::lint; use rustc_span::hygiene::Transparency; -use rustc_span::{Ident, Span, Symbol, kw, sym}; +use rustc_span::{Ident, Span, Symbol, sym}; use tracing::debug; use {rustc_attr_parsing as attr, rustc_hir as hir}; @@ -935,8 +935,8 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { } // definition of the field - let ident = Ident::new(kw::Empty, use_ctxt); - let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id).1; + let ident = Ident::new(sym::dummy, use_ctxt); + let (_, def_id) = self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id); !field.vis.is_accessible_from(def_id, self.tcx) }