Skip to content

Commit f8849ed

Browse files
committed
resolve: Split extern prelude into two scopes
One for `--extern` options and another for `extern crate` items.
1 parent 2886b36 commit f8849ed

10 files changed

+186
-71
lines changed

compiler/rustc_resolve/src/build_reduced_graph.rs

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -970,40 +970,35 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
970970
let imported_binding = self.r.import(binding, import);
971971
if ident.name != kw::Underscore && parent == self.r.graph_root {
972972
let norm_ident = Macros20NormalizedIdent::new(ident);
973+
// FIXME: this error is technically unnecessary now when extern prelude is split into
974+
// two scopes, remove it with lang team approval.
973975
if let Some(entry) = self.r.extern_prelude.get(&norm_ident)
974976
&& expansion != LocalExpnId::ROOT
975977
&& orig_name.is_some()
976-
&& !entry.is_import()
978+
&& entry.item_binding.is_none()
977979
{
978980
self.r.dcx().emit_err(
979981
errors::MacroExpandedExternCrateCannotShadowExternArguments { span: item.span },
980982
);
981-
// `return` is intended to discard this binding because it's an
982-
// unregistered ambiguity error which would result in a panic
983-
// caused by inconsistency `path_res`
984-
// more details: https://github.com/rust-lang/rust/pull/111761
985-
return;
986983
}
987984

988985
use indexmap::map::Entry;
989986
match self.r.extern_prelude.entry(norm_ident) {
990987
Entry::Occupied(mut occupied) => {
991988
let entry = occupied.get_mut();
992-
if let Some(old_binding) = entry.binding.get()
993-
&& old_binding.is_import()
994-
{
989+
if entry.item_binding.is_some() {
995990
let msg = format!("extern crate `{ident}` already in extern prelude");
996991
self.r.tcx.dcx().span_delayed_bug(item.span, msg);
997992
} else {
998-
// Binding from `extern crate` item in source code can replace
999-
// a binding from `--extern` on command line here.
1000-
entry.binding.set(Some(imported_binding));
993+
entry.item_binding = Some(imported_binding);
1001994
entry.introduced_by_item = orig_name.is_some();
1002995
}
1003996
entry
1004997
}
1005998
Entry::Vacant(vacant) => vacant.insert(ExternPreludeEntry {
1006-
binding: Cell::new(Some(imported_binding)),
999+
item_binding: Some(imported_binding),
1000+
flag_binding: Cell::new(None),
1001+
only_item: true,
10071002
introduced_by_item: true,
10081003
}),
10091004
};

compiler/rustc_resolve/src/diagnostics.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1097,12 +1097,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
10971097
);
10981098
}
10991099
}
1100-
Scope::ExternPrelude => {
1100+
Scope::ExternPreludeItems => {
1101+
// Add idents from both item and flag scopes.
11011102
suggestions.extend(this.extern_prelude.keys().filter_map(|ident| {
11021103
let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
11031104
filter_fn(res).then_some(TypoSuggestion::typo_from_ident(ident.0, res))
11041105
}));
11051106
}
1107+
Scope::ExternPreludeFlags => {}
11061108
Scope::ToolPrelude => {
11071109
let res = Res::NonMacroAttr(NonMacroAttrKind::Tool);
11081110
suggestions.extend(

compiler/rustc_resolve/src/ident.rs

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
102102
ScopeSet::All(ns)
103103
| ScopeSet::ModuleAndExternPrelude(ns, _)
104104
| ScopeSet::Late(ns, ..) => (ns, None),
105+
ScopeSet::ExternPrelude => (TypeNS, None),
105106
ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind)),
106107
};
107108
let module = match scope_set {
@@ -111,8 +112,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
111112
_ => parent_scope.module.nearest_item_scope(),
112113
};
113114
let module_and_extern_prelude = matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..));
115+
let extern_prelude = matches!(scope_set, ScopeSet::ExternPrelude);
114116
let mut scope = match ns {
115117
_ if module_and_extern_prelude => Scope::Module(module, None),
118+
_ if extern_prelude => Scope::ExternPreludeItems,
116119
TypeNS | ValueNS => Scope::Module(module, None),
117120
MacroNS => Scope::DeriveHelpers(parent_scope.expansion),
118121
};
@@ -143,7 +146,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
143146
Scope::Module(..) => true,
144147
Scope::MacroUsePrelude => use_prelude || rust_2015,
145148
Scope::BuiltinAttrs => true,
146-
Scope::ExternPrelude => use_prelude || module_and_extern_prelude,
149+
Scope::ExternPreludeItems | Scope::ExternPreludeFlags => {
150+
use_prelude || module_and_extern_prelude || extern_prelude
151+
}
147152
Scope::ToolPrelude => use_prelude,
148153
Scope::StdLibPrelude => use_prelude || ns == MacroNS,
149154
Scope::BuiltinTypes => true,
@@ -182,7 +187,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
182187
Scope::Module(..) if module_and_extern_prelude => match ns {
183188
TypeNS => {
184189
ctxt.adjust(ExpnId::root());
185-
Scope::ExternPrelude
190+
Scope::ExternPreludeItems
186191
}
187192
ValueNS | MacroNS => break,
188193
},
@@ -199,7 +204,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
199204
None => {
200205
ctxt.adjust(ExpnId::root());
201206
match ns {
202-
TypeNS => Scope::ExternPrelude,
207+
TypeNS => Scope::ExternPreludeItems,
203208
ValueNS => Scope::StdLibPrelude,
204209
MacroNS => Scope::MacroUsePrelude,
205210
}
@@ -208,8 +213,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
208213
}
209214
Scope::MacroUsePrelude => Scope::StdLibPrelude,
210215
Scope::BuiltinAttrs => break, // nowhere else to search
211-
Scope::ExternPrelude if module_and_extern_prelude => break,
212-
Scope::ExternPrelude => Scope::ToolPrelude,
216+
Scope::ExternPreludeItems => Scope::ExternPreludeFlags,
217+
Scope::ExternPreludeFlags if module_and_extern_prelude || extern_prelude => break,
218+
Scope::ExternPreludeFlags => Scope::ToolPrelude,
213219
Scope::ToolPrelude => Scope::StdLibPrelude,
214220
Scope::StdLibPrelude => match ns {
215221
TypeNS => Scope::BuiltinTypes,
@@ -413,6 +419,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
413419
ScopeSet::All(ns)
414420
| ScopeSet::ModuleAndExternPrelude(ns, _)
415421
| ScopeSet::Late(ns, ..) => (ns, None),
422+
ScopeSet::ExternPrelude => (TypeNS, None),
416423
ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind)),
417424
};
418425

@@ -561,14 +568,20 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
561568
Some(binding) => Ok((*binding, Flags::empty())),
562569
None => Err(Determinacy::Determined),
563570
},
564-
Scope::ExternPrelude => {
565-
match this.reborrow().extern_prelude_get(ident, finalize.is_some()) {
571+
Scope::ExternPreludeItems => {
572+
match this.reborrow().extern_prelude_get_item(ident, finalize.is_some()) {
566573
Some(binding) => Ok((binding, Flags::empty())),
567574
None => Err(Determinacy::determined(
568575
this.graph_root.unexpanded_invocations.borrow().is_empty(),
569576
)),
570577
}
571578
}
579+
Scope::ExternPreludeFlags => {
580+
match this.extern_prelude_get_flag(ident, finalize.is_some()) {
581+
Some(binding) => Ok((binding, Flags::empty())),
582+
None => Err(Determinacy::Determined),
583+
}
584+
}
572585
Scope::ToolPrelude => match this.registered_tool_bindings.get(&ident) {
573586
Some(binding) => Ok((*binding, Flags::empty())),
574587
None => Err(Determinacy::Determined),
@@ -817,15 +830,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
817830
assert_eq!(shadowing, Shadowing::Unrestricted);
818831
return if ns != TypeNS {
819832
Err((Determined, Weak::No))
820-
} else if let Some(binding) =
821-
self.reborrow().extern_prelude_get(ident, finalize.is_some())
822-
{
823-
Ok(binding)
824-
} else if !self.graph_root.unexpanded_invocations.borrow().is_empty() {
825-
// Macro-expanded `extern crate` items can add names to extern prelude.
826-
Err((Undetermined, Weak::No))
827833
} else {
828-
Err((Determined, Weak::No))
834+
let binding = self.early_resolve_ident_in_lexical_scope(
835+
ident,
836+
ScopeSet::ExternPrelude,
837+
parent_scope,
838+
finalize,
839+
finalize.is_some(),
840+
ignore_binding,
841+
ignore_import,
842+
);
843+
return binding.map_err(|determinacy| (determinacy, Weak::No));
829844
};
830845
}
831846
ModuleOrUniformRoot::CurrentScope => {

compiler/rustc_resolve/src/lib.rs

Lines changed: 47 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -113,34 +113,46 @@ impl Determinacy {
113113
}
114114

115115
/// A specific scope in which a name can be looked up.
116-
/// This enum is currently used only for early resolution (imports and macros),
117-
/// but not for late resolution yet.
118116
#[derive(Clone, Copy, Debug)]
119117
enum Scope<'ra> {
118+
/// Inert attributes registered by derive macros.
120119
DeriveHelpers(LocalExpnId),
120+
/// Inert attributes registered by derive macros, but used before they are actually declared.
121+
/// This scope will exist until the compatibility lint `LEGACY_DERIVE_HELPERS`
122+
/// is turned into a hard error.
121123
DeriveHelpersCompat,
124+
/// Textual `let`-like scopes introduced by `macro_rules!` items.
122125
MacroRules(MacroRulesScopeRef<'ra>),
123-
// The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK`
124-
// lint if it should be reported.
126+
/// Names declared in the given module.
127+
/// The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK`
128+
/// lint if it should be reported.
125129
Module(Module<'ra>, Option<NodeId>),
130+
/// Names introduced by `#[macro_use]` attributes on `extern crate` items.
126131
MacroUsePrelude,
132+
/// Built-in attributes.
127133
BuiltinAttrs,
128-
ExternPrelude,
134+
/// Extern prelude names introduced by `extern crate` items.
135+
ExternPreludeItems,
136+
/// Extern prelude names introduced by `--extern` flags.
137+
ExternPreludeFlags,
138+
/// Tool modules introduced with `#![register_tool]`.
129139
ToolPrelude,
140+
/// Standard library prelude introduced with an internal `#[prelude_import]` import.
130141
StdLibPrelude,
142+
/// Built-in types.
131143
BuiltinTypes,
132144
}
133145

134146
/// Names from different contexts may want to visit different subsets of all specific scopes
135147
/// with different restrictions when looking up the resolution.
136-
/// This enum is currently used only for early resolution (imports and macros),
137-
/// but not for late resolution yet.
138148
#[derive(Clone, Copy, Debug)]
139149
enum ScopeSet<'ra> {
140150
/// All scopes with the given namespace.
141151
All(Namespace),
142152
/// A module, then extern prelude (used for mixed 2015-2018 mode in macros).
143153
ModuleAndExternPrelude(Namespace, Module<'ra>),
154+
/// Just two extern prelude scopes.
155+
ExternPrelude,
144156
/// All scopes with macro namespace and the given macro kind restriction.
145157
Macro(MacroKind),
146158
/// All scopes with the given namespace, used for partially performing late resolution.
@@ -1011,16 +1023,18 @@ impl<'ra> NameBindingData<'ra> {
10111023

10121024
#[derive(Default, Clone)]
10131025
struct ExternPreludeEntry<'ra> {
1014-
binding: Cell<Option<NameBinding<'ra>>>,
1026+
/// Binding from an `extern crate` item.
1027+
item_binding: Option<NameBinding<'ra>>,
1028+
/// Binding from an `--extern` flag, lazily populated on first use.
1029+
flag_binding: Cell<Option<NameBinding<'ra>>>,
1030+
/// There was no `--extern` flag introducing this name,
1031+
/// `flag_binding` doesn't need to be populated.
1032+
only_item: bool,
1033+
/// `item_binding` is non-redundant, happens either when `only_item` is true,
1034+
/// or when `extern crate` introducing `item_binding` used renaming.
10151035
introduced_by_item: bool,
10161036
}
10171037

1018-
impl ExternPreludeEntry<'_> {
1019-
fn is_import(&self) -> bool {
1020-
self.binding.get().is_some_and(|binding| binding.is_import())
1021-
}
1022-
}
1023-
10241038
struct DeriveData {
10251039
resolutions: Vec<DeriveResolution>,
10261040
helper_attrs: Vec<(usize, Ident)>,
@@ -1885,7 +1899,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
18851899
this.get_mut().traits_in_module(module, assoc_item, &mut found_traits);
18861900
}
18871901
}
1888-
Scope::ExternPrelude | Scope::ToolPrelude | Scope::BuiltinTypes => {}
1902+
Scope::ExternPreludeItems
1903+
| Scope::ExternPreludeFlags
1904+
| Scope::ToolPrelude
1905+
| Scope::BuiltinTypes => {}
18891906
_ => unreachable!(),
18901907
}
18911908
None::<()>
@@ -2050,7 +2067,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
20502067
// but not introduce it, as used if they are accessed from lexical scope.
20512068
if used == Used::Scope {
20522069
if let Some(entry) = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)) {
2053-
if !entry.introduced_by_item && entry.binding.get() == Some(used_binding) {
2070+
if !entry.introduced_by_item && entry.item_binding == Some(used_binding) {
20542071
return;
20552072
}
20562073
}
@@ -2206,26 +2223,30 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
22062223
}
22072224
}
22082225

2209-
fn extern_prelude_get<'r>(
2226+
fn extern_prelude_get_item<'r>(
22102227
mut self: CmResolver<'r, 'ra, 'tcx>,
22112228
ident: Ident,
22122229
finalize: bool,
22132230
) -> Option<NameBinding<'ra>> {
2214-
let mut record_use = None;
22152231
let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident));
2216-
let binding = entry.and_then(|entry| match entry.binding.get() {
2217-
Some(binding) if binding.is_import() => {
2218-
if finalize {
2219-
record_use = Some(binding);
2220-
}
2221-
Some(binding)
2232+
entry.and_then(|entry| entry.item_binding).map(|binding| {
2233+
if finalize {
2234+
self.get_mut().record_use(ident, binding, Used::Scope);
22222235
}
2236+
binding
2237+
})
2238+
}
2239+
2240+
fn extern_prelude_get_flag(&self, ident: Ident, finalize: bool) -> Option<NameBinding<'ra>> {
2241+
let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident));
2242+
entry.and_then(|entry| match entry.flag_binding.get() {
22232243
Some(binding) => {
22242244
if finalize {
22252245
self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span);
22262246
}
22272247
Some(binding)
22282248
}
2249+
None if entry.only_item => None,
22292250
None => {
22302251
let crate_id = if finalize {
22312252
self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span)
@@ -2237,19 +2258,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
22372258
let res = Res::Def(DefKind::Mod, crate_id.as_def_id());
22382259
let binding =
22392260
self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT);
2240-
entry.binding.set(Some(binding));
2261+
entry.flag_binding.set(Some(binding));
22412262
Some(binding)
22422263
}
22432264
None => finalize.then_some(self.dummy_binding),
22442265
}
22452266
}
2246-
});
2247-
2248-
if let Some(binding) = record_use {
2249-
self.get_mut().record_use(ident, binding, Used::Scope);
2250-
}
2251-
2252-
binding
2267+
})
22532268
}
22542269

22552270
/// Rustdoc uses this to resolve doc link paths in a recoverable way. `PathResult<'a>`

tests/ui/imports/issue-109148.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ macro_rules! m {
1010

1111
m!();
1212

13-
use std::mem;
13+
use std::mem; //~ ERROR `std` is ambiguous
14+
use ::std::mem as _; //~ ERROR `std` is ambiguous
1415

1516
fn main() {}

0 commit comments

Comments
 (0)