Skip to content

Commit 868ecfb

Browse files
committed
Introduce ModernIdent type to unify macro 2.0 hygiene handling
Signed-off-by: xizheyin <[email protected]>
1 parent 8708f3c commit 868ecfb

File tree

9 files changed

+107
-39
lines changed

9 files changed

+107
-39
lines changed

compiler/rustc_resolve/src/build_reduced_graph.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use rustc_middle::bug;
2727
use rustc_middle::metadata::ModChild;
2828
use rustc_middle::ty::{Feed, Visibility};
2929
use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind};
30-
use rustc_span::{Ident, Span, Symbol, kw, sym};
30+
use rustc_span::{Ident, Macros20NormalizedIdent, Span, Symbol, kw, sym};
3131
use thin_vec::ThinVec;
3232
use tracing::debug;
3333

@@ -938,7 +938,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
938938
self.r.potentially_unused_imports.push(import);
939939
let imported_binding = self.r.import(binding, import);
940940
if parent == self.r.graph_root {
941-
let ident = ident.normalize_to_macros_2_0();
941+
let ident = Macros20NormalizedIdent::new(ident);
942942
if let Some(entry) = self.r.extern_prelude.get(&ident)
943943
&& expansion != LocalExpnId::ROOT
944944
&& orig_name.is_some()

compiler/rustc_resolve/src/check_unused.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use rustc_session::lint::BuiltinLintDiag;
3333
use rustc_session::lint::builtin::{
3434
MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES, UNUSED_IMPORTS, UNUSED_QUALIFICATIONS,
3535
};
36-
use rustc_span::{DUMMY_SP, Ident, Span, kw};
36+
use rustc_span::{DUMMY_SP, Ident, Macros20NormalizedIdent, Span, kw};
3737

3838
use crate::imports::{Import, ImportKind};
3939
use crate::{LexicalScopeBinding, NameBindingKind, Resolver, module_to_string};
@@ -203,7 +203,7 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> {
203203
if self
204204
.r
205205
.extern_prelude
206-
.get(&extern_crate.ident)
206+
.get(&unsafe { Macros20NormalizedIdent::new_without_normalize(extern_crate.ident) })
207207
.is_none_or(|entry| entry.introduced_by_item)
208208
{
209209
continue;

compiler/rustc_resolve/src/diagnostics.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
3232
use rustc_span::edition::Edition;
3333
use rustc_span::hygiene::MacroKind;
3434
use rustc_span::source_map::SourceMap;
35-
use rustc_span::{BytePos, Ident, Span, Symbol, SyntaxContext, kw, sym};
35+
use rustc_span::{BytePos, Ident, Macros20NormalizedIdent, Span, Symbol, SyntaxContext, kw, sym};
3636
use thin_vec::{ThinVec, thin_vec};
3737
use tracing::{debug, instrument};
3838

@@ -322,8 +322,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
322322
// Check if the target of the use for both bindings is the same.
323323
let duplicate = new_binding.res().opt_def_id() == old_binding.res().opt_def_id();
324324
let has_dummy_span = new_binding.span.is_dummy() || old_binding.span.is_dummy();
325-
let from_item =
326-
self.extern_prelude.get(&ident).is_none_or(|entry| entry.introduced_by_item);
325+
let from_item = self
326+
.extern_prelude
327+
.get(&unsafe { Macros20NormalizedIdent::new_without_normalize(ident) })
328+
.is_none_or(|entry| entry.introduced_by_item);
327329
// Only suggest removing an import if both bindings are to the same def, if both spans
328330
// aren't dummy spans. Further, if both bindings are imports, then the ident must have
329331
// been introduced by an item.
@@ -532,7 +534,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
532534
module.for_each_child(self, |_this, ident, _ns, binding| {
533535
let res = binding.res();
534536
if filter_fn(res) && ctxt.is_none_or(|ctxt| ctxt == ident.span.ctxt()) {
535-
names.push(TypoSuggestion::typo_from_ident(ident, res));
537+
names.push(TypoSuggestion::typo_from_ident(ident.0, res));
536538
}
537539
});
538540
}
@@ -1100,7 +1102,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
11001102
Scope::ExternPrelude => {
11011103
suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
11021104
let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
1103-
filter_fn(res).then_some(TypoSuggestion::typo_from_ident(*ident, res))
1105+
filter_fn(res).then_some(TypoSuggestion::typo_from_ident(ident.0, res))
11041106
}));
11051107
}
11061108
Scope::ToolPrelude => {
@@ -1246,7 +1248,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
12461248
};
12471249
segms.append(&mut path_segments.clone());
12481250

1249-
segms.push(ast::PathSegment::from_ident(ident));
1251+
segms.push(ast::PathSegment::from_ident(ident.0));
12501252
let path = Path { span: name_binding.span, segments: segms, tokens: None };
12511253

12521254
if child_accessible
@@ -1319,7 +1321,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
13191321
if let Some(def_id) = name_binding.res().module_like_def_id() {
13201322
// form the path
13211323
let mut path_segments = path_segments.clone();
1322-
path_segments.push(ast::PathSegment::from_ident(ident));
1324+
path_segments.push(ast::PathSegment::from_ident(ident.0));
13231325

13241326
let alias_import = if let NameBindingKind::Import { import, .. } =
13251327
name_binding.kind
@@ -1455,7 +1457,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
14551457
if needs_disambiguation {
14561458
crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP));
14571459
}
1458-
crate_path.push(ast::PathSegment::from_ident(ident));
1460+
crate_path.push(ast::PathSegment::from_ident(ident.0));
14591461

14601462
suggestions.extend(self.lookup_import_candidates_from_module(
14611463
lookup_ident,

compiler/rustc_resolve/src/imports.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
499499
let imported_binding = self.import(binding, *import);
500500
let _ = self.try_define(
501501
import.parent_scope.module,
502-
ident,
502+
ident.0,
503503
key.ns,
504504
imported_binding,
505505
warn_ambiguity,
@@ -1522,7 +1522,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
15221522
.is_some_and(|binding| binding.warn_ambiguity_recursive());
15231523
let _ = self.try_define(
15241524
import.parent_scope.module,
1525-
key.ident,
1525+
key.ident.0,
15261526
key.ns,
15271527
imported_binding,
15281528
warn_ambiguity,
@@ -1555,7 +1555,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
15551555
next_binding = binding;
15561556
}
15571557

1558-
children.push(ModChild { ident, res, vis: binding.vis, reexport_chain });
1558+
children.push(ModChild { ident: ident.0, res, vis: binding.vis, reexport_chain });
15591559
}
15601560
});
15611561

compiler/rustc_resolve/src/late/diagnostics.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,7 +1473,10 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
14731473
})
14741474
.collect();
14751475
if let [target] = targets.as_slice() {
1476-
return Some(TypoSuggestion::single_item_from_ident(target.0.ident, target.1));
1476+
return Some(TypoSuggestion::single_item_from_ident(
1477+
target.0.ident.0,
1478+
target.1,
1479+
));
14771480
}
14781481
}
14791482
}
@@ -2492,7 +2495,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
24922495
Res::Def(DefKind::Mod, crate_id.as_def_id());
24932496

24942497
filter_fn(crate_mod).then(|| {
2495-
TypoSuggestion::typo_from_ident(*ident, crate_mod)
2498+
TypoSuggestion::typo_from_ident(ident.0, crate_mod)
24962499
})
24972500
})
24982501
}));
@@ -2654,7 +2657,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
26542657
if let Some(module_def_id) = name_binding.res().module_like_def_id() {
26552658
// form the path
26562659
let mut path_segments = path_segments.clone();
2657-
path_segments.push(ast::PathSegment::from_ident(ident));
2660+
path_segments.push(ast::PathSegment::from_ident(ident.0));
26582661
let doc_visible = doc_visible
26592662
&& (module_def_id.is_local() || !r.tcx.is_doc_hidden(module_def_id));
26602663
if module_def_id == def_id {
@@ -2693,7 +2696,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
26932696
enum_module.for_each_child(self.r, |_, ident, _, name_binding| {
26942697
if let Res::Def(DefKind::Ctor(CtorOf::Variant, kind), def_id) = name_binding.res() {
26952698
let mut segms = enum_import_suggestion.path.segments.clone();
2696-
segms.push(ast::PathSegment::from_ident(ident));
2699+
segms.push(ast::PathSegment::from_ident(ident.0));
26972700
let path = Path { span: name_binding.span, segments: segms, tokens: None };
26982701
variants.push((path, def_id, kind));
26992702
}

compiler/rustc_resolve/src/lib.rs

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ use rustc_query_system::ich::StableHashingContext;
7171
use rustc_session::lint::builtin::PRIVATE_MACRO_USE;
7272
use rustc_session::lint::{BuiltinLintDiag, LintBuffer};
7373
use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency};
74-
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
74+
use rustc_span::{DUMMY_SP, Ident, Macros20NormalizedIdent, Span, Symbol, kw, sym};
7575
use smallvec::{SmallVec, smallvec};
7676
use tracing::debug;
7777

@@ -531,7 +531,7 @@ impl ModuleKind {
531531
struct BindingKey {
532532
/// The identifier for the binding, always the `normalize_to_macros_2_0` version of the
533533
/// identifier.
534-
ident: Ident,
534+
ident: Macros20NormalizedIdent,
535535
ns: Namespace,
536536
/// When we add an underscore binding (with ident `_`) to some module, this field has
537537
/// a non-zero value that uniquely identifies this binding in that module.
@@ -543,7 +543,7 @@ struct BindingKey {
543543

544544
impl BindingKey {
545545
fn new(ident: Ident, ns: Namespace) -> Self {
546-
BindingKey { ident: ident.normalize_to_macros_2_0(), ns, disambiguator: 0 }
546+
BindingKey { ident: Macros20NormalizedIdent::new(ident), ns, disambiguator: 0 }
547547
}
548548

549549
fn new_disambiguated(
@@ -552,7 +552,7 @@ impl BindingKey {
552552
disambiguator: impl FnOnce() -> u32,
553553
) -> BindingKey {
554554
let disambiguator = if ident.name == kw::Underscore { disambiguator() } else { 0 };
555-
BindingKey { ident: ident.normalize_to_macros_2_0(), ns, disambiguator }
555+
BindingKey { ident: Macros20NormalizedIdent::new(ident), ns, disambiguator }
556556
}
557557
}
558558

@@ -659,7 +659,7 @@ impl<'ra> Module<'ra> {
659659
fn for_each_child<'tcx, R, F>(self, resolver: &mut R, mut f: F)
660660
where
661661
R: AsMut<Resolver<'ra, 'tcx>>,
662-
F: FnMut(&mut R, Ident, Namespace, NameBinding<'ra>),
662+
F: FnMut(&mut R, Macros20NormalizedIdent, Namespace, NameBinding<'ra>),
663663
{
664664
for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() {
665665
if let Some(binding) = name_resolution.borrow().best_binding() {
@@ -681,7 +681,7 @@ impl<'ra> Module<'ra> {
681681
return;
682682
}
683683
if let Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) = binding.res() {
684-
collected_traits.push((name, binding, r.as_mut().get_module(def_id)))
684+
collected_traits.push((name.0, binding, r.as_mut().get_module(def_id)))
685685
}
686686
});
687687
*traits = Some(collected_traits.into_boxed_slice());
@@ -1040,7 +1040,7 @@ pub struct Resolver<'ra, 'tcx> {
10401040
graph_root: Module<'ra>,
10411041

10421042
prelude: Option<Module<'ra>>,
1043-
extern_prelude: FxIndexMap<Ident, ExternPreludeEntry<'ra>>,
1043+
extern_prelude: FxIndexMap<Macros20NormalizedIdent, ExternPreludeEntry<'ra>>,
10441044

10451045
/// N.B., this is used only for better diagnostics, not name resolution itself.
10461046
field_names: LocalDefIdMap<Vec<Ident>>,
@@ -1467,19 +1467,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
14671467
let mut invocation_parents = FxHashMap::default();
14681468
invocation_parents.insert(LocalExpnId::ROOT, InvocationParent::ROOT);
14691469

1470-
let mut extern_prelude: FxIndexMap<Ident, ExternPreludeEntry<'_>> = tcx
1470+
let mut extern_prelude: FxIndexMap<Macros20NormalizedIdent, ExternPreludeEntry<'_>> = tcx
14711471
.sess
14721472
.opts
14731473
.externs
14741474
.iter()
14751475
.filter(|(_, entry)| entry.add_prelude)
1476-
.map(|(name, _)| (Ident::from_str(name), Default::default()))
1476+
.map(|(name, _)| {
1477+
(
1478+
unsafe {
1479+
Macros20NormalizedIdent::new_without_normalize(Ident::from_str(name))
1480+
},
1481+
Default::default(),
1482+
)
1483+
})
14771484
.collect();
14781485

14791486
if !attr::contains_name(attrs, sym::no_core) {
1480-
extern_prelude.insert(Ident::with_dummy_span(sym::core), Default::default());
1487+
extern_prelude
1488+
.insert(Macros20NormalizedIdent::with_dummy_span(sym::core), Default::default());
14811489
if !attr::contains_name(attrs, sym::no_std) {
1482-
extern_prelude.insert(Ident::with_dummy_span(sym::std), Default::default());
1490+
extern_prelude
1491+
.insert(Macros20NormalizedIdent::with_dummy_span(sym::std), Default::default());
14831492
}
14841493
}
14851494

@@ -1983,7 +1992,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
19831992
// Avoid marking `extern crate` items that refer to a name from extern prelude,
19841993
// but not introduce it, as used if they are accessed from lexical scope.
19851994
if used == Used::Scope {
1986-
if let Some(entry) = self.extern_prelude.get(&ident.normalize_to_macros_2_0()) {
1995+
if let Some(entry) = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)) {
19871996
if !entry.introduced_by_item && entry.binding == Some(used_binding) {
19881997
return;
19891998
}
@@ -2146,7 +2155,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
21462155
return None;
21472156
}
21482157

2149-
let norm_ident = ident.normalize_to_macros_2_0();
2158+
let norm_ident = Macros20NormalizedIdent::new(ident);
21502159
let binding = self.extern_prelude.get(&norm_ident).cloned().and_then(|entry| {
21512160
Some(if let Some(binding) = entry.binding {
21522161
if finalize {

compiler/rustc_resolve/src/macros.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -535,11 +535,11 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
535535
target_trait.for_each_child(self, |this, ident, ns, _binding| {
536536
// FIXME: Adjust hygiene for idents from globs, like for glob imports.
537537
if let Some(overriding_keys) = this.impl_binding_keys.get(&impl_def_id)
538-
&& overriding_keys.contains(&BindingKey::new(ident, ns))
538+
&& overriding_keys.contains(&BindingKey::new(ident.0, ns))
539539
{
540540
// The name is overridden, do not produce it from the glob delegation.
541541
} else {
542-
idents.push((ident, None));
542+
idents.push((ident.0, None));
543543
}
544544
});
545545
Ok(idents)

compiler/rustc_span/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ pub use span_encoding::{DUMMY_SP, Span};
6666

6767
pub mod symbol;
6868
pub use symbol::{
69-
ByteSymbol, Ident, MacroRulesNormalizedIdent, STDLIB_STABLE_CRATES, Symbol, kw, sym,
69+
ByteSymbol, Ident, MacroRulesNormalizedIdent, Macros20NormalizedIdent, STDLIB_STABLE_CRATES,
70+
Symbol, kw, sym,
7071
};
7172

7273
mod analyze_source_file;

compiler/rustc_span/src/symbol.rs

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//! type, and vice versa.
44
55
use std::hash::{Hash, Hasher};
6+
use std::ops::{Deref, DerefMut};
67
use std::{fmt, str};
78

89
use rustc_arena::DroplessArena;
@@ -2562,16 +2563,17 @@ impl fmt::Display for IdentPrinter {
25622563
}
25632564

25642565
/// An newtype around `Ident` that calls [Ident::normalize_to_macro_rules] on
2565-
/// construction.
2566-
// FIXME(matthewj, petrochenkov) Use this more often, add a similar
2567-
// `ModernIdent` struct and use that as well.
2566+
/// construction for "local variable hygiene" comparisons.
2567+
///
2568+
/// Use this type when you need to compare identifiers according to macro_rules hygiene.
2569+
/// This ensures compile-time safety and avoids manual normalization calls.
25682570
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
25692571
pub struct MacroRulesNormalizedIdent(Ident);
25702572

25712573
impl MacroRulesNormalizedIdent {
25722574
#[inline]
25732575
pub fn new(ident: Ident) -> Self {
2574-
Self(ident.normalize_to_macro_rules())
2576+
MacroRulesNormalizedIdent(ident.normalize_to_macro_rules())
25752577
}
25762578
}
25772579

@@ -2587,6 +2589,57 @@ impl fmt::Display for MacroRulesNormalizedIdent {
25872589
}
25882590
}
25892591

2592+
/// An newtype around `Ident` that calls [Ident::normalize_to_macros_2_0] on
2593+
/// construction for "item hygiene" comparisons.
2594+
///
2595+
/// Identifiers with same string value become same if they came from the same macro 2.0 macro
2596+
/// (e.g., `macro` item, but not `macro_rules` item) and stay different if they came from
2597+
/// different macro 2.0 macros.
2598+
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
2599+
pub struct Macros20NormalizedIdent(pub Ident);
2600+
2601+
impl Macros20NormalizedIdent {
2602+
#[inline]
2603+
pub fn new(ident: Ident) -> Self {
2604+
Macros20NormalizedIdent(ident.normalize_to_macros_2_0())
2605+
}
2606+
2607+
// For search in index map for `Ident` as a index key
2608+
pub unsafe fn new_without_normalize(ident: Ident) -> Self {
2609+
Macros20NormalizedIdent(ident)
2610+
}
2611+
2612+
// dummy_span does not need to be normalized, so we can use `Ident` directly
2613+
pub fn with_dummy_span(name: Symbol) -> Self {
2614+
Macros20NormalizedIdent(Ident::with_dummy_span(name))
2615+
}
2616+
}
2617+
2618+
impl fmt::Debug for Macros20NormalizedIdent {
2619+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2620+
fmt::Debug::fmt(&self.0, f)
2621+
}
2622+
}
2623+
2624+
impl fmt::Display for Macros20NormalizedIdent {
2625+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2626+
fmt::Display::fmt(&self.0, f)
2627+
}
2628+
}
2629+
2630+
impl Deref for Macros20NormalizedIdent {
2631+
type Target = Ident;
2632+
fn deref(&self) -> &Self::Target {
2633+
&self.0
2634+
}
2635+
}
2636+
2637+
impl DerefMut for Macros20NormalizedIdent {
2638+
fn deref_mut(&mut self) -> &mut Self::Target {
2639+
&mut self.0
2640+
}
2641+
}
2642+
25902643
/// An interned UTF-8 string.
25912644
///
25922645
/// Internally, a `Symbol` is implemented as an index, and all operations

0 commit comments

Comments
 (0)