Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions compiler/rustc_resolve/src/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1008,16 +1008,13 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
let msg = format!("extern crate `{ident}` already in extern prelude");
self.r.tcx.dcx().span_delayed_bug(item.span, msg);
} else {
entry.item_binding = Some(imported_binding);
entry.introduced_by_item = orig_name.is_some();
entry.item_binding = Some((imported_binding, orig_name.is_some()));
}
entry
}
Entry::Vacant(vacant) => vacant.insert(ExternPreludeEntry {
item_binding: Some(imported_binding),
flag_binding: Cell::new(None),
only_item: true,
introduced_by_item: true,
item_binding: Some((imported_binding, true)),
flag_binding: None,
}),
};
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/check_unused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> {
.r
.extern_prelude
.get(&Macros20NormalizedIdent::new(extern_crate.ident))
.is_none_or(|entry| entry.introduced_by_item)
.is_none_or(|entry| entry.introduced_by_item())
{
continue;
}
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_resolve/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
let from_item = self
.extern_prelude
.get(&Macros20NormalizedIdent::new(ident))
.is_none_or(|entry| entry.introduced_by_item);
.is_none_or(|entry| entry.introduced_by_item());
// Only suggest removing an import if both bindings are to the same def, if both spans
// aren't dummy spans. Further, if both bindings are imports, then the ident must have
// been introduced by an item.
Expand Down Expand Up @@ -1845,7 +1845,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
let AmbiguityError { kind, ident, b1, b2, misc1, misc2, .. } = *ambiguity_error;
let extern_prelude_ambiguity = || {
self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)).is_some_and(|entry| {
entry.item_binding == Some(b1) && entry.flag_binding.get() == Some(b2)
entry.item_binding.map(|(b, _)| b) == Some(b1)
&& entry.flag_binding.as_ref().and_then(|pb| pb.get().binding()) == Some(b2)
})
};
let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() {
Expand Down
93 changes: 49 additions & 44 deletions compiler/rustc_resolve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use std::sync::Arc;
use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion};
use effective_visibilities::EffectiveVisibilitiesVisitor;
use errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst};
use imports::{Import, ImportData, ImportKind, NameResolution};
use imports::{Import, ImportData, ImportKind, NameResolution, PendingBinding};
use late::{
ForwardGenericParamBanReason, HasGenericParams, PathSource, PatternSource,
UnnecessaryQualification,
Expand Down Expand Up @@ -1025,18 +1025,26 @@ impl<'ra> NameBindingData<'ra> {
}
}

#[derive(Default, Clone)]
struct ExternPreludeEntry<'ra> {
/// Binding from an `extern crate` item.
item_binding: Option<NameBinding<'ra>>,
/// The boolean flag is true is `item_binding` is non-redundant, happens either when
/// `flag_binding` is `None`, or when `extern crate` introducing `item_binding` used renaming.
item_binding: Option<(NameBinding<'ra>, /* introduced by item */ bool)>,
/// Binding from an `--extern` flag, lazily populated on first use.
flag_binding: Cell<Option<NameBinding<'ra>>>,
/// There was no `--extern` flag introducing this name,
/// `flag_binding` doesn't need to be populated.
only_item: bool,
/// `item_binding` is non-redundant, happens either when `only_item` is true,
/// or when `extern crate` introducing `item_binding` used renaming.
introduced_by_item: bool,
flag_binding: Option<Cell<PendingBinding<'ra>>>,
}

impl ExternPreludeEntry<'_> {
fn introduced_by_item(&self) -> bool {
matches!(self.item_binding, Some((_, true)))
}

fn flag() -> Self {
ExternPreludeEntry {
item_binding: None,
flag_binding: Some(Cell::new(PendingBinding::Pending)),
}
}
}

struct DeriveData {
Expand Down Expand Up @@ -1528,19 +1536,20 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
&& let name = Symbol::intern(name)
&& name.can_be_raw()
{
Some((Macros20NormalizedIdent::with_dummy_span(name), Default::default()))
let ident = Macros20NormalizedIdent::with_dummy_span(name);
Some((ident, ExternPreludeEntry::flag()))
} else {
None
}
})
.collect();

if !attr::contains_name(attrs, sym::no_core) {
extern_prelude
.insert(Macros20NormalizedIdent::with_dummy_span(sym::core), Default::default());
let ident = Macros20NormalizedIdent::with_dummy_span(sym::core);
extern_prelude.insert(ident, ExternPreludeEntry::flag());
if !attr::contains_name(attrs, sym::no_std) {
extern_prelude
.insert(Macros20NormalizedIdent::with_dummy_span(sym::std), Default::default());
let ident = Macros20NormalizedIdent::with_dummy_span(sym::std);
extern_prelude.insert(ident, ExternPreludeEntry::flag());
}
}

Expand Down Expand Up @@ -2062,12 +2071,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
// Avoid marking `extern crate` items that refer to a name from extern prelude,
// but not introduce it, as used if they are accessed from lexical scope.
if used == Used::Scope {
if let Some(entry) = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)) {
if !entry.introduced_by_item && entry.item_binding == Some(used_binding) {
return;
}
}
if used == Used::Scope
&& let Some(entry) = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident))
&& entry.item_binding == Some((used_binding, false))
{
return;
}
let old_used = self.import_use_map.entry(import).or_insert(used);
if *old_used < used {
Expand Down Expand Up @@ -2226,7 +2234,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
finalize: bool,
) -> Option<NameBinding<'ra>> {
let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident));
entry.and_then(|entry| entry.item_binding).map(|binding| {
entry.and_then(|entry| entry.item_binding).map(|(binding, _)| {
if finalize {
self.get_mut().record_use(ident, binding, Used::Scope);
}
Expand All @@ -2236,31 +2244,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {

fn extern_prelude_get_flag(&self, ident: Ident, finalize: bool) -> Option<NameBinding<'ra>> {
let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident));
entry.and_then(|entry| match entry.flag_binding.get() {
Some(binding) => {
if finalize {
self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span);
entry.and_then(|entry| entry.flag_binding.as_ref()).and_then(|flag_binding| {
let binding = match flag_binding.get() {
PendingBinding::Ready(binding) => {
if finalize {
self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span);
}
binding
}
Some(binding)
}
None if entry.only_item => None,
None => {
let crate_id = if finalize {
self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span)
} else {
self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name)
};
match crate_id {
Some(crate_id) => {
PendingBinding::Pending => {
let crate_id = if finalize {
self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span)
} else {
self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name)
};
crate_id.map(|crate_id| {
let res = Res::Def(DefKind::Mod, crate_id.as_def_id());
let binding =
self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT);
entry.flag_binding.set(Some(binding));
Some(binding)
}
None => finalize.then_some(self.dummy_binding),
self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT)
})
}
}
};
flag_binding.set(PendingBinding::Ready(binding));
binding.or_else(|| finalize.then_some(self.dummy_binding))
})
}

Expand Down
Loading