diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 7912345ec56ac..55d89b59ceb24 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -985,7 +985,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { return; } let entry = self.r.extern_prelude.entry(ident).or_insert(ExternPreludeEntry { - binding: Cell::new(None), + binding: Cell::new(crate::EpeBinding::OptPending), introduced_by_item: true, }); if orig_name.is_some() { @@ -994,7 +994,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // Binding from `extern crate` item in source code can replace // a binding from `--extern` on command line here. if !entry.is_import() { - entry.binding.set(Some(imported_binding)); + entry.binding.set(crate::EpeBinding::Item(imported_binding, false)); } else if ident.name != kw::Underscore { self.r.dcx().span_delayed_bug( item.span, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index a70ae4fd57a09..633c9ff2f97f6 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1007,15 +1007,24 @@ impl<'ra> NameBindingData<'ra> { } } +#[derive(Default, Clone, Copy, PartialEq)] +enum EpeBinding<'ra> { + #[default] + OptPending, + OptReadyOk(NameBinding<'ra>, bool), + OptReadyErr(bool), + Item(NameBinding<'ra>, bool), +} + #[derive(Default, Clone)] struct ExternPreludeEntry<'ra> { - binding: Cell>>, + binding: Cell>, introduced_by_item: bool, } impl ExternPreludeEntry<'_> { fn is_import(&self) -> bool { - self.binding.get().is_some_and(|binding| binding.is_import()) + matches!(self.binding.get(), EpeBinding::Item(..)) } } @@ -2011,7 +2020,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // 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(&ident.normalize_to_macros_2_0()) { - if !entry.introduced_by_item && entry.binding.get() == Some(used_binding) { + if !entry.introduced_by_item + && matches!(entry.binding.get(), EpeBinding::Item(b, _) if b == used_binding) + { return; } } @@ -2174,37 +2185,50 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let norm_ident = ident.normalize_to_macros_2_0(); - let binding = self.extern_prelude.get(&norm_ident).cloned().and_then(|entry| { - Some(if let Some(binding) = entry.binding.get() { - if finalize { - if !entry.is_import() { - self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span); - } else if entry.introduced_by_item { - self.record_use(ident, binding, Used::Other); - } + let entry = self.extern_prelude.get(&norm_ident).cloned(); + let binding = entry.map(|entry| match entry.binding.get() { + EpeBinding::Item(binding, finalized) => { + if finalize && !finalized && entry.introduced_by_item { + self.record_use(ident, binding, Used::Other); } - binding - } else { + EpeBinding::Item(binding, finalize) + } + EpeBinding::OptReadyOk(binding, finalized) => { + if finalize && !finalized { + self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span); + } + EpeBinding::OptReadyOk(binding, finalize) + } + EpeBinding::OptReadyErr(finalized) => { + if finalize && !finalized { + self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span); + } + EpeBinding::OptReadyErr(finalize) + } + EpeBinding::OptPending => { let crate_id = if finalize { - let Some(crate_id) = - self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span) - else { - return Some(self.dummy_binding); - }; - crate_id + self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span) } else { - self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name)? + self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name) }; - let res = Res::Def(DefKind::Mod, crate_id.as_def_id()); - self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT) - }) + let res = match crate_id { + Some(crate_id) => Res::Def(DefKind::Mod, crate_id.as_def_id()), + None => return EpeBinding::OptReadyErr(finalize), + }; + let binding = self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT); + EpeBinding::OptReadyOk(binding, finalize) + } }); - if let Some(entry) = self.extern_prelude.get(&norm_ident) { - entry.binding.set(binding); - } - - binding + binding.and_then(|binding| { + self.extern_prelude[&norm_ident].binding.set(binding); + match binding { + EpeBinding::Item(binding, _) | EpeBinding::OptReadyOk(binding, _) => Some(binding), + EpeBinding::OptReadyErr(_) if finalize => Some(self.dummy_binding), + EpeBinding::OptReadyErr(_) => None, + EpeBinding::OptPending => unreachable!(), + } + }) } /// Rustdoc uses this to resolve doc link paths in a recoverable way. `PathResult<'a>` diff --git a/tests/ui/crate-loading/invalid-rlib.rs b/tests/ui/crate-loading/invalid-rlib.rs index 6b46352624452..24293f88b1cd5 100644 --- a/tests/ui/crate-loading/invalid-rlib.rs +++ b/tests/ui/crate-loading/invalid-rlib.rs @@ -6,6 +6,3 @@ #![no_std] use ::foo; //~ ERROR invalid metadata files for crate `foo` //~| NOTE failed to mmap file -//~^^ ERROR invalid metadata files for crate `foo` -//~| NOTE failed to mmap file -//~| NOTE duplicate diagnostic diff --git a/tests/ui/crate-loading/invalid-rlib.stderr b/tests/ui/crate-loading/invalid-rlib.stderr index 63bb1b95cbb78..ad3ab729a5d21 100644 --- a/tests/ui/crate-loading/invalid-rlib.stderr +++ b/tests/ui/crate-loading/invalid-rlib.stderr @@ -6,15 +6,6 @@ LL | use ::foo; | = note: failed to mmap file 'auxiliary/libfoo.rlib' -error[E0786]: found invalid metadata files for crate `foo` - --> $DIR/invalid-rlib.rs:7:7 - | -LL | use ::foo; - | ^^^ - | - = note: failed to mmap file 'auxiliary/libfoo.rlib' - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0786`.