Skip to content

Commit 31c87c0

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

10 files changed

+194
-69
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 ident = ident.normalize_to_macros_2_0();
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(&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(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
@@ -1095,12 +1095,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
10951095
);
10961096
}
10971097
}
1098-
Scope::ExternPrelude => {
1098+
Scope::ExternPreludeItems => {
1099+
// Add idents from both item and flag scopes.
10991100
suggestions.extend(this.extern_prelude.keys().filter_map(|ident| {
11001101
let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
11011102
filter_fn(res).then_some(TypoSuggestion::typo_from_ident(*ident, res))
11021103
}));
11031104
}
1105+
Scope::ExternPreludeFlags => {}
11041106
Scope::ToolPrelude => {
11051107
let res = Res::NonMacroAttr(NonMacroAttrKind::Tool);
11061108
suggestions.extend(

compiler/rustc_resolve/src/ident.rs

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
9797
ScopeSet::All(ns)
9898
| ScopeSet::ModuleAndExternPrelude(ns, _)
9999
| ScopeSet::Late(ns, ..) => (ns, None),
100+
ScopeSet::ExternPrelude => (TypeNS, None),
100101
ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind)),
101102
};
102103
let module = match scope_set {
@@ -106,8 +107,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
106107
_ => parent_scope.module.nearest_item_scope(),
107108
};
108109
let module_and_extern_prelude = matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..));
110+
let extern_prelude = matches!(scope_set, ScopeSet::ExternPrelude);
109111
let mut scope = match ns {
110112
_ if module_and_extern_prelude => Scope::Module(module, None),
113+
_ if extern_prelude => Scope::ExternPreludeItems,
111114
TypeNS | ValueNS => Scope::Module(module, None),
112115
MacroNS => Scope::DeriveHelpers(parent_scope.expansion),
113116
};
@@ -138,7 +141,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
138141
Scope::Module(..) => true,
139142
Scope::MacroUsePrelude => use_prelude || rust_2015,
140143
Scope::BuiltinAttrs => true,
141-
Scope::ExternPrelude => use_prelude || module_and_extern_prelude,
144+
Scope::ExternPreludeItems | Scope::ExternPreludeFlags => {
145+
use_prelude || module_and_extern_prelude || extern_prelude
146+
}
142147
Scope::ToolPrelude => use_prelude,
143148
Scope::StdLibPrelude => use_prelude || ns == MacroNS,
144149
Scope::BuiltinTypes => true,
@@ -177,7 +182,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
177182
Scope::Module(..) if module_and_extern_prelude => match ns {
178183
TypeNS => {
179184
ctxt.adjust(ExpnId::root());
180-
Scope::ExternPrelude
185+
Scope::ExternPreludeItems
181186
}
182187
ValueNS | MacroNS => break,
183188
},
@@ -194,7 +199,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
194199
None => {
195200
ctxt.adjust(ExpnId::root());
196201
match ns {
197-
TypeNS => Scope::ExternPrelude,
202+
TypeNS => Scope::ExternPreludeItems,
198203
ValueNS => Scope::StdLibPrelude,
199204
MacroNS => Scope::MacroUsePrelude,
200205
}
@@ -203,8 +208,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
203208
}
204209
Scope::MacroUsePrelude => Scope::StdLibPrelude,
205210
Scope::BuiltinAttrs => break, // nowhere else to search
206-
Scope::ExternPrelude if module_and_extern_prelude => break,
207-
Scope::ExternPrelude => Scope::ToolPrelude,
211+
Scope::ExternPreludeItems => Scope::ExternPreludeFlags,
212+
Scope::ExternPreludeFlags if module_and_extern_prelude || extern_prelude => break,
213+
Scope::ExternPreludeFlags => Scope::ToolPrelude,
208214
Scope::ToolPrelude => Scope::StdLibPrelude,
209215
Scope::StdLibPrelude => match ns {
210216
TypeNS => Scope::BuiltinTypes,
@@ -407,6 +413,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
407413
ScopeSet::All(ns)
408414
| ScopeSet::ModuleAndExternPrelude(ns, _)
409415
| ScopeSet::Late(ns, ..) => (ns, None),
416+
ScopeSet::ExternPrelude => (TypeNS, None),
410417
ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind)),
411418
};
412419

@@ -555,14 +562,20 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
555562
Some(binding) => Ok((*binding, Flags::empty())),
556563
None => Err(Determinacy::Determined),
557564
},
558-
Scope::ExternPrelude => {
559-
match this.extern_prelude_get(ident, finalize.is_some()) {
565+
Scope::ExternPreludeItems => {
566+
match this.extern_prelude_get_item(ident, finalize.is_some()) {
560567
Some(binding) => Ok((binding, Flags::empty())),
561568
None => Err(Determinacy::determined(
562569
this.graph_root.unexpanded_invocations.borrow().is_empty(),
563570
)),
564571
}
565572
}
573+
Scope::ExternPreludeFlags => {
574+
match this.extern_prelude_get_flag(ident, finalize.is_some()) {
575+
Some(binding) => Ok((binding, Flags::empty())),
576+
None => Err(Determinacy::Determined),
577+
}
578+
}
566579
Scope::ToolPrelude => match this.registered_tool_bindings.get(&ident) {
567580
Some(binding) => Ok((*binding, Flags::empty())),
568581
None => Err(Determinacy::Determined),
@@ -812,13 +825,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
812825
assert_eq!(shadowing, Shadowing::Unrestricted);
813826
return if ns != TypeNS {
814827
Err((Determined, Weak::No))
815-
} else if let Some(binding) = self.extern_prelude_get(ident, finalize.is_some()) {
816-
Ok(binding)
817-
} else if !self.graph_root.unexpanded_invocations.borrow().is_empty() {
818-
// Macro-expanded `extern crate` items can add names to extern prelude.
819-
Err((Undetermined, Weak::No))
820828
} else {
821-
Err((Determined, Weak::No))
829+
let binding = self.early_resolve_ident_in_lexical_scope(
830+
ident,
831+
ScopeSet::ExternPrelude,
832+
parent_scope,
833+
finalize,
834+
finalize.is_some(),
835+
ignore_binding,
836+
ignore_import,
837+
);
838+
return binding.map_err(|determinacy| (determinacy, Weak::No));
822839
};
823840
}
824841
ModuleOrUniformRoot::CurrentScope => {

compiler/rustc_resolve/src/lib.rs

Lines changed: 55 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -112,34 +112,46 @@ impl Determinacy {
112112
}
113113

114114
/// A specific scope in which a name can be looked up.
115-
/// This enum is currently used only for early resolution (imports and macros),
116-
/// but not for late resolution yet.
117115
#[derive(Clone, Copy, Debug)]
118116
enum Scope<'ra> {
117+
/// Inert attributes registered by derive macros.
119118
DeriveHelpers(LocalExpnId),
119+
/// Inert attributes registered by derive macros, but used before they are actually declared.
120+
/// This scope will exist until the compatibility lint `LEGACY_DERIVE_HELPERS`
121+
/// is turned into a hard error.
120122
DeriveHelpersCompat,
123+
/// Textual `let`-like scopes introduced by `macro_rules!` items.
121124
MacroRules(MacroRulesScopeRef<'ra>),
122-
// The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK`
123-
// lint if it should be reported.
125+
/// Names declared in the given module.
126+
/// The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK`
127+
/// lint if it should be reported.
124128
Module(Module<'ra>, Option<NodeId>),
129+
/// Names introduced by `#[macro_use]` attributes on `extern crate` items.
125130
MacroUsePrelude,
131+
/// Built-in attributes.
126132
BuiltinAttrs,
127-
ExternPrelude,
133+
/// Extern prelude names introduced by `extern crate` items.
134+
ExternPreludeItems,
135+
/// Extern prelude names introduced by `--extern` flags.
136+
ExternPreludeFlags,
137+
/// Tool modules introduced with `#![register_tool]`.
128138
ToolPrelude,
139+
/// Standard library prelude introduced with an internal `#[prelude_import]` import.
129140
StdLibPrelude,
141+
/// Built-in types.
130142
BuiltinTypes,
131143
}
132144

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

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

1016-
impl ExternPreludeEntry<'_> {
1017-
fn is_import(&self) -> bool {
1018-
self.binding.get().is_some_and(|binding| binding.is_import())
1019-
}
1020-
}
1021-
10221036
struct DeriveData {
10231037
resolutions: Vec<DeriveResolution>,
10241038
helper_attrs: Vec<(usize, Ident)>,
@@ -1859,7 +1873,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
18591873
this.traits_in_module(module, assoc_item, &mut found_traits);
18601874
}
18611875
}
1862-
Scope::ExternPrelude | Scope::ToolPrelude | Scope::BuiltinTypes => {}
1876+
Scope::ExternPreludeItems
1877+
| Scope::ExternPreludeFlags
1878+
| Scope::ToolPrelude
1879+
| Scope::BuiltinTypes => {}
18631880
_ => unreachable!(),
18641881
}
18651882
None::<()>
@@ -2021,7 +2038,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
20212038
// but not introduce it, as used if they are accessed from lexical scope.
20222039
if used == Used::Scope {
20232040
if let Some(entry) = self.extern_prelude.get(&ident.normalize_to_macros_2_0()) {
2024-
if !entry.introduced_by_item && entry.binding.get() == Some(used_binding) {
2041+
if !entry.introduced_by_item && entry.item_binding == Some(used_binding) {
20252042
return;
20262043
}
20272044
}
@@ -2177,22 +2194,34 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
21772194
}
21782195
}
21792196

2180-
fn extern_prelude_get(&mut self, ident: Ident, finalize: bool) -> Option<NameBinding<'ra>> {
2181-
let mut record_use = None;
2197+
fn extern_prelude_get_item(
2198+
&mut self,
2199+
ident: Ident,
2200+
finalize: bool,
2201+
) -> Option<NameBinding<'ra>> {
21822202
let entry = self.extern_prelude.get(&ident.normalize_to_macros_2_0());
2183-
let binding = entry.and_then(|entry| match entry.binding.get() {
2184-
Some(binding) if binding.is_import() => {
2185-
if finalize {
2186-
record_use = Some(binding);
2187-
}
2188-
Some(binding)
2203+
entry.and_then(|entry| entry.item_binding).map(|binding| {
2204+
if finalize {
2205+
self.record_use(ident, binding, Used::Scope);
21892206
}
2207+
binding
2208+
})
2209+
}
2210+
2211+
fn extern_prelude_get_flag(
2212+
&mut self,
2213+
ident: Ident,
2214+
finalize: bool,
2215+
) -> Option<NameBinding<'ra>> {
2216+
let entry = self.extern_prelude.get(&ident.normalize_to_macros_2_0());
2217+
entry.and_then(|entry| match entry.flag_binding.get() {
21902218
Some(binding) => {
21912219
if finalize {
21922220
self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span);
21932221
}
21942222
Some(binding)
21952223
}
2224+
None if entry.only_item => None,
21962225
None => {
21972226
let crate_id = if finalize {
21982227
self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span)
@@ -2204,19 +2233,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
22042233
let res = Res::Def(DefKind::Mod, crate_id.as_def_id());
22052234
let binding =
22062235
self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT);
2207-
entry.binding.set(Some(binding));
2236+
entry.flag_binding.set(Some(binding));
22082237
Some(binding)
22092238
}
22102239
None => finalize.then_some(self.dummy_binding),
22112240
}
22122241
}
2213-
});
2214-
2215-
if let Some(binding) = record_use {
2216-
self.record_use(ident, binding, Used::Scope);
2217-
}
2218-
2219-
binding
2242+
})
22202243
}
22212244

22222245
/// 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)