From 3d03332bdd84018e186929084699b5c446638a1c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 31 Jul 2025 15:33:48 +0300 Subject: [PATCH 1/2] [WIP] resolve: Better caching for unsuccessful crate resolutions --- .../rustc_resolve/src/build_reduced_graph.rs | 4 +- compiler/rustc_resolve/src/lib.rs | 78 ++++++++++++------- 2 files changed, 53 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 7912345ec56ac..c9f9dcfbb0109 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)); } 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..d18accdae04d4 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>), + OptReadyErr, + Item(NameBinding<'ra>), +} + #[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 + && entry.binding.get() == EpeBinding::Item(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() { + let entry = self.extern_prelude.get(&norm_ident).cloned(); + let binding = entry.map(|entry| match entry.binding.get() { + EpeBinding::Item(binding) => { + if finalize && entry.introduced_by_item { + self.record_use(ident, binding, Used::Other); + } + EpeBinding::Item(binding) + } + EpeBinding::OptReadyOk(binding) => { 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); - } + self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span); } - binding - } else { + EpeBinding::OptReadyOk(binding) + } + EpeBinding::OptReadyErr => { + if finalize { + self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span); + } + EpeBinding::OptReadyErr + } + 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, + }; + let binding = self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT); + EpeBinding::OptReadyOk(binding) + } }); - 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>` From 8f0d729d391e364481efa50fefd6a1f73d76991d Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 31 Jul 2025 17:36:10 +0300 Subject: [PATCH 2/2] resolve: Avoid finalizing extern prelude entries more than once --- .../rustc_resolve/src/build_reduced_graph.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 36 +++++++++---------- tests/ui/crate-loading/invalid-rlib.rs | 3 -- tests/ui/crate-loading/invalid-rlib.stderr | 11 +----- 4 files changed, 20 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index c9f9dcfbb0109..55d89b59ceb24 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -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(crate::EpeBinding::Item(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 d18accdae04d4..633c9ff2f97f6 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1011,9 +1011,9 @@ impl<'ra> NameBindingData<'ra> { enum EpeBinding<'ra> { #[default] OptPending, - OptReadyOk(NameBinding<'ra>), - OptReadyErr, - Item(NameBinding<'ra>), + OptReadyOk(NameBinding<'ra>, bool), + OptReadyErr(bool), + Item(NameBinding<'ra>, bool), } #[derive(Default, Clone)] @@ -2021,7 +2021,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { 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() == EpeBinding::Item(used_binding) + && matches!(entry.binding.get(), EpeBinding::Item(b, _) if b == used_binding) { return; } @@ -2187,23 +2187,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let norm_ident = ident.normalize_to_macros_2_0(); let entry = self.extern_prelude.get(&norm_ident).cloned(); let binding = entry.map(|entry| match entry.binding.get() { - EpeBinding::Item(binding) => { - if finalize && entry.introduced_by_item { + EpeBinding::Item(binding, finalized) => { + if finalize && !finalized && entry.introduced_by_item { self.record_use(ident, binding, Used::Other); } - EpeBinding::Item(binding) + EpeBinding::Item(binding, finalize) } - EpeBinding::OptReadyOk(binding) => { - if finalize { + EpeBinding::OptReadyOk(binding, finalized) => { + if finalize && !finalized { self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span); } - EpeBinding::OptReadyOk(binding) + EpeBinding::OptReadyOk(binding, finalize) } - EpeBinding::OptReadyErr => { - if finalize { + EpeBinding::OptReadyErr(finalized) => { + if finalize && !finalized { self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span); } - EpeBinding::OptReadyErr + EpeBinding::OptReadyErr(finalize) } EpeBinding::OptPending => { let crate_id = if finalize { @@ -2213,19 +2213,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; let res = match crate_id { Some(crate_id) => Res::Def(DefKind::Mod, crate_id.as_def_id()), - None => return EpeBinding::OptReadyErr, + None => return EpeBinding::OptReadyErr(finalize), }; let binding = self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT); - EpeBinding::OptReadyOk(binding) + EpeBinding::OptReadyOk(binding, finalize) } }); 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::Item(binding, _) | EpeBinding::OptReadyOk(binding, _) => Some(binding), + EpeBinding::OptReadyErr(_) if finalize => Some(self.dummy_binding), + EpeBinding::OptReadyErr(_) => None, EpeBinding::OptPending => unreachable!(), } }) 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`.