From ca891364fdb911148dfc59d6387a6f375e97f098 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Sat, 1 Aug 2026 17:01:52 +0200 Subject: [PATCH] Split methods of `Cm(Ref)Cell` into `name` and `name_checked`. With `*_checked` requiring a `&Resolver` to check the speculative flag. The normal ones require a `&mut Resolver` thus not needing to check the speculative flag. Mostly to minimize per "penalty" of always checking it, even if we definitely know that we are not in speculative resolution (due to `&mut Resolver`). --- .../rustc_resolve/src/build_reduced_graph.rs | 2 +- compiler/rustc_resolve/src/check_unused.rs | 2 +- .../rustc_resolve/src/diagnostics/impls.rs | 4 +- compiler/rustc_resolve/src/ident.rs | 2 +- compiler/rustc_resolve/src/imports.rs | 18 ++--- compiler/rustc_resolve/src/lib.rs | 68 +++++++++++++------ compiler/rustc_resolve/src/macros.rs | 4 +- 7 files changed, 63 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index ad00003af9482..8ce95f80633b0 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -567,7 +567,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { // Don't add underscore imports to `single_imports` // because they cannot define any usable names. if target.name != kw::Underscore { - self.r.per_ns(|this, ns| { + self.r.per_ns_mut(|this, ns| { let key = BindingKey::new(IdentKey::new(target), ns); this.resolution_or_default(current_module.to_module(), key, target.span) .borrow_mut(this) diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index dcbda2f96323e..52e46bb21a9f3 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -559,7 +559,7 @@ impl Resolver<'_, '_> { let mut check_redundant_imports = FxIndexSet::default(); for module in &self.local_modules { for (_key, resolution) in self.resolutions(module.to_module()).iter() { - if let Some(decl) = resolution.borrow(self).best_decl() + if let Some(decl) = resolution.borrow_checked(self).best_decl() && let DeclKind::Import { import, .. } = decl.kind && let ImportKind::Single { id, .. } = import.kind { diff --git a/compiler/rustc_resolve/src/diagnostics/impls.rs b/compiler/rustc_resolve/src/diagnostics/impls.rs index 97c2c2f327ccf..00b1c9ca0c5f3 100644 --- a/compiler/rustc_resolve/src/diagnostics/impls.rs +++ b/compiler/rustc_resolve/src/diagnostics/impls.rs @@ -1873,7 +1873,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.resolutions(parent_scope.module).iter().any(|(key, name_resolution)| { if key.ns == TypeNS && key.ident == *ident - && let Some(decl) = name_resolution.borrow(self).best_decl() + && let Some(decl) = name_resolution.borrow_checked(self).best_decl() { match decl.res() { // No disambiguation needed if the identically named item we @@ -3634,7 +3634,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut res = false; let m = r.expect_module(parent_module); if m.is_local() { - for importer in m.glob_importers.borrow(r).iter() { + for importer in m.glob_importers.borrow_checked(r).iter() { if let Some(next_parent_module) = importer.parent_scope.module.opt_def_id() { if next_parent_module == module diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 2a1b208f94c34..000af0f38534a 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1290,7 +1290,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Check if one of glob imports can still define the name, // if it can then our "no resolution" result is not determined and can be invalidated. - for glob_import in module.globs.borrow(&self).iter() { + for glob_import in module.globs.borrow_checked(&self).iter() { if ignore_import == Some(*glob_import) { continue; } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 499f9ea297362..749e414d2ba9e 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -468,7 +468,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { || max_vis.get().is_none_or(|max_vis| vis.greater_than(max_vis, self.tcx))) { // `set` can't fail because this can only happen during "write_import_resolutions" - max_vis.set(Some(vis), self) + max_vis.set_checked(Some(vis), self) } self.arenas.alloc_decl(DeclData { @@ -585,7 +585,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && glob_decl.ambiguity.get().is_none() { // Do not lose glob ambiguities when re-fetching the glob. - glob_decl.ambiguity.set(Some((old_ambig, true)), self); + glob_decl.ambiguity.set_checked(Some((old_ambig, true)), self); } glob_decl } else if glob_decl.res() != old_glob_decl.res() { @@ -593,7 +593,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { || self.is_rustybuzz_0_4_0(old_glob_decl, glob_decl) || self.is_pdf_0_9_0(old_glob_decl, glob_decl) || self.is_net2_0_2_39(old_glob_decl, glob_decl); - old_glob_decl.ambiguity.set(Some((glob_decl, warning)), self); + old_glob_decl.ambiguity.set_checked(Some((glob_decl, warning)), self); old_glob_decl } else if let old_vis = old_glob_decl.vis() && let vis = glob_decl.vis() @@ -602,17 +602,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // We are glob-importing the same item but with a different visibility. // All visibilities here are ordered because all of them are ancestors of `module`. if vis.greater_than(old_vis, self.tcx) { - old_glob_decl.ambiguity_vis_max.set(Some(glob_decl), self); + old_glob_decl.ambiguity_vis_max.set_checked(Some(glob_decl), self); } else if let old_min_vis = old_glob_decl.min_vis() && old_min_vis != vis && old_min_vis.greater_than(vis, self.tcx) { - old_glob_decl.ambiguity_vis_min.set(Some(glob_decl), self); + old_glob_decl.ambiguity_vis_min.set_checked(Some(glob_decl), self); } old_glob_decl } else if glob_decl.is_ambiguity_recursive() && !old_glob_decl.is_ambiguity_recursive() { // Overwriting a non-ambiguous glob import with an ambiguous glob import. - old_glob_decl.ambiguity.set(Some((glob_decl, true)), self); + old_glob_decl.ambiguity.set_checked(Some((glob_decl, true)), self); old_glob_decl } else { old_glob_decl @@ -1011,7 +1011,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn lint_reexports(&mut self, exported_ambiguities: FxHashSet>) { for module in &self.local_modules { for (key, resolution) in self.resolutions(module.to_module()).iter() { - let resolution = resolution.borrow(self); + let resolution = resolution.borrow_checked(self); let Some(binding) = resolution.best_decl() else { continue }; // Report "cannot reexport" errors for exotic cases involving macros 2.0 @@ -1808,7 +1808,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .resolutions(module) .iter() .filter_map(|(key, resolution)| { - let res = resolution.borrow(self); + let res = resolution.borrow_checked(self); let decl = res.determined_decl()?; let mut key = *key; let scope = match key.ident.ctxt.update_unchecked(|ctxt| { @@ -1874,7 +1874,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ambig_module_children: &mut LocalDefIdMap>, ) { // Since import resolution is finished, globs will not define any more names. - *module.globs.borrow_mut(self) = Vec::new(); + *module.globs.borrow_mut_checked(self) = Vec::new(); let Some(def_id) = module.opt_def_id() else { return }; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index b7e57ad8ec37e..2b02fe136f2ad 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -769,7 +769,7 @@ impl<'ra> ModuleData<'ra> { } fn has_unexpanded_invocations<'tcx>(&self, r: &Resolver<'ra, 'tcx>) -> bool { - !self.unexpanded_invocations.borrow(r).is_empty() + !self.unexpanded_invocations.borrow_checked(r).is_empty() } fn res(&self) -> Option { @@ -794,7 +794,7 @@ impl<'ra> Module<'ra> { mut f: impl FnMut(&R, IdentKey, Span, Namespace, Decl<'ra>), ) { for (key, name_resolution) in resolver.as_ref().resolutions(self).iter() { - let name_resolution = name_resolution.borrow(resolver.as_ref()); + let name_resolution = name_resolution.borrow_checked(resolver.as_ref()); if let Some(decl) = name_resolution.best_decl() { f(resolver, key.ident, name_resolution.orig_ident_span, key.ns, decl); } @@ -816,7 +816,7 @@ impl<'ra> Module<'ra> { /// This modifies `self` in place. The traits will be stored in `self.traits`. fn ensure_traits<'tcx>(self, resolver: &Resolver<'ra, 'tcx>) { - let mut traits = self.traits.borrow_mut(resolver.as_ref()); + let mut traits = self.traits.borrow_mut_checked(resolver); if traits.is_none() { let mut collected_traits = Vec::new(); self.for_each_child(resolver, |r, ident, _, ns, mut decl| { @@ -2184,7 +2184,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn resolutions(&self, module: Module<'ra>) -> CmRef<'ra, ResolutionTable<'ra>> { match &module.0.0.lazy_resolutions { - Resolutions::Local(local_res) => local_res.borrow(self), + Resolutions::Local(local_res) => local_res.borrow_checked(self), Resolutions::Extern(extern_res) => { // It is fine to return a `CmRef::Untracked`, we never give out a `&mut` // to an external table. @@ -2197,7 +2197,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - fn resolutions_mut(&self, module: Module<'ra>) -> RefMut<'ra, ResolutionTable<'ra>> { + fn resolutions_mut(&mut self, module: Module<'ra>) -> RefMut<'ra, ResolutionTable<'ra>> { match &module.0.0.lazy_resolutions { Resolutions::Local(local_res) => local_res.borrow_mut(self), Resolutions::Extern(_) => { @@ -2213,12 +2213,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module: Module<'ra>, key: BindingKey, ) -> Option>> { - self.resolutions(module).get(&key).map(|resolution| resolution.0.borrow(self)) + self.resolutions(module).get(&key).map(|resolution| resolution.0.borrow_checked(self)) } #[track_caller] fn resolution_or_default( - &self, + &mut self, module: Module<'ra>, key: BindingKey, orig_ident_span: Span, @@ -2908,10 +2908,11 @@ mod ref_mut { self.0.get() } - pub(crate) fn update<'ra, 'tcx>(&self, r: &Resolver<'ra, 'tcx>, f: impl FnOnce(T) -> T) - where - T: Copy, - { + pub(crate) fn update<'ra, 'tcx>( + &self, + r: &mut Resolver<'ra, 'tcx>, + f: impl FnOnce(T) -> T, + ) { let old = self.get(); self.set(f(old), r); } @@ -2922,10 +2923,15 @@ mod ref_mut { CmCell(Cell::new(value)) } - pub(crate) fn set<'ra, 'tcx>(&self, val: T, r: &Resolver<'ra, 'tcx>) { - if r.speculative_flag.is_speculative() { - panic!("not allowed to mutate a `CmCell` during speculative resolution") - } + pub(crate) fn set<'ra, 'tcx>(&self, val: T, _: &mut Resolver<'ra, 'tcx>) { + self.0.set(val); + } + + pub(crate) fn set_checked<'ra, 'tcx>(&self, val: T, r: &Resolver<'ra, 'tcx>) { + assert!( + !r.speculative_flag.is_speculative(), + "Cannot mutate `CmCell` during speculative resolution" + ); self.0.set(val); } @@ -2983,23 +2989,43 @@ mod ref_mut { } #[track_caller] - pub(crate) fn borrow_mut<'ra, 'tcx>(&self, r: &Resolver<'ra, 'tcx>) -> RefMut<'_, T> { + pub(crate) fn borrow_mut<'ra, 'tcx>(&self, r: &mut Resolver<'ra, 'tcx>) -> RefMut<'_, T> { self.try_borrow_mut(r).unwrap() } #[track_caller] - pub(crate) fn try_borrow_mut<'ra, 'tcx>( + pub(crate) fn borrow_mut_checked<'ra, 'tcx>( + &self, + r: &Resolver<'ra, 'tcx>, + ) -> RefMut<'_, T> { + self.try_borrow_mut_checked(r).unwrap() + } + + #[track_caller] + pub(crate) fn try_borrow_mut_checked<'ra, 'tcx>( &self, r: &Resolver<'ra, 'tcx>, ) -> Result, BorrowMutError> { - if r.speculative_flag.is_speculative() { - panic!("not allowed to mutably borrow a `CmRefCell` during speculative resolution"); - } + assert!( + !r.speculative_flag.is_speculative(), + "Cannot mutate `CmRefCell` state/value during speculative resolution" + ); self.0.try_borrow_mut() } #[track_caller] - pub(crate) fn borrow<'ra, 'tcx>(&self, r: &Resolver<'ra, 'tcx>) -> CmRef<'_, T> { + pub(crate) fn try_borrow_mut<'ra, 'tcx>( + &self, + _: &mut Resolver<'ra, 'tcx>, + ) -> Result, BorrowMutError> { + self.0.try_borrow_mut() + } + + pub(crate) fn borrow<'ra, 'tcx>(&self, _: &mut Resolver<'ra, 'tcx>) -> Ref<'_, T> { + self.0.borrow() + } + + pub(crate) fn borrow_checked<'ra, 'tcx>(&self, r: &Resolver<'ra, 'tcx>) -> CmRef<'_, T> { if r.speculative_flag.is_speculative() { // `try_borrow_unguarded` is unsafe because it returns a `&T` instead // of `Ref<'_, T>`. It does provides an extra check to make sure no live diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 6921d0ed595fe..ebff3e29e6b19 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -861,7 +861,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { PathResult::Module(..) => unreachable!(), }; - self.multi_segment_macro_resolutions.borrow_mut(&self).push(( + self.multi_segment_macro_resolutions.borrow_mut_checked(&self).push(( path, path_span, kind, @@ -888,7 +888,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return Err(Determinacy::Undetermined); } - self.single_segment_macro_resolutions.borrow_mut(&self).push(( + self.single_segment_macro_resolutions.borrow_mut_checked(&self).push(( path[0].ident, kind, *parent_scope,