diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 4c5c591ad94e3..41573749abbe7 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -558,7 +558,7 @@ impl Resolver<'_, '_> { let unused_imports = visitor.unused_imports; let mut check_redundant_imports = FxIndexSet::default(); for module in &self.local_modules { - for (_key, resolution) in self.resolutions(module.to_module()).borrow().iter() { + for (_key, resolution) in self.resolutions(module.to_module()).iter() { if let Some(decl) = resolution.borrow().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 212629395c98b..cc2c72ad59906 100644 --- a/compiler/rustc_resolve/src/diagnostics/impls.rs +++ b/compiler/rustc_resolve/src/diagnostics/impls.rs @@ -1870,24 +1870,22 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // If so, we have to disambiguate the potential import suggestions by making // the paths *global* (i.e., by prefixing them with `::`). let needs_disambiguation = - self.resolutions(parent_scope.module).borrow().iter().any( - |(key, name_resolution)| { - if key.ns == TypeNS - && key.ident == *ident - && let Some(decl) = name_resolution.borrow().best_decl() - { - match decl.res() { - // No disambiguation needed if the identically named item we - // found in scope actually refers to the crate in question. - Res::Def(_, def_id) => def_id != crate_def_id, - Res::PrimTy(_) => true, - _ => false, - } - } else { - false + self.resolutions(parent_scope.module).iter().any(|(key, name_resolution)| { + if key.ns == TypeNS + && key.ident == *ident + && let Some(decl) = name_resolution.borrow().best_decl() + { + match decl.res() { + // No disambiguation needed if the identically named item we + // found in scope actually refers to the crate in question. + Res::Def(_, def_id) => def_id != crate_def_id, + Res::PrimTy(_) => true, + _ => false, } - }, - ); + } else { + false + } + }); let mut crate_path = ThinVec::new(); if needs_disambiguation { crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP)); diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 90927492195b0..ff976b080d40d 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -125,7 +125,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { /// including their whole reexport chains. fn set_bindings_effective_visibilities(&mut self, module_id: LocalDefId) { let module = self.r.expect_module(module_id.to_def_id()); - for (_, name_resolution) in self.r.resolutions(module).borrow().iter() { + for (_, name_resolution) in self.r.resolutions(module).iter() { let Some(decl) = name_resolution.borrow().best_decl() else { continue; }; @@ -309,7 +309,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { ) { if self.macro_reachable.insert((module_def_id, defining_mod)) { let module = self.r.expect_module(module_def_id.to_def_id()); - for (_, name_resolution) in self.r.resolutions(module).borrow().iter() { + for (_, name_resolution) in self.r.resolutions(module).iter() { let Some(decl) = name_resolution.borrow().best_decl() else { continue; }; diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index c00eb97f4c3d6..6e2ea9abf2de8 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1002,7 +1002,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()).borrow().iter() { + for (key, resolution) in self.resolutions(module.to_module()).iter() { let resolution = resolution.borrow(); let Some(binding) = resolution.best_decl() else { continue }; @@ -1481,7 +1481,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let names = match module { ModuleOrUniformRoot::Module(module) => { self.resolutions(module) - .borrow() .iter() .filter_map(|(BindingKey { ident: i, .. }, resolution)| { if i.name == ident.name { @@ -1799,7 +1798,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let import_bindings = match imported_module { ModuleOrUniformRoot::Module(module) if module != import.parent_scope.module => self .resolutions(module) - .borrow() .iter() .filter_map(|(key, resolution)| { let res = resolution.borrow(); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index f2ce21377acce..9550ac1446ec7 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -190,7 +190,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { assoc_name: Symbol, ) -> Option { let module = self.r.get_module(trait_def_id)?; - self.r.resolutions(module).borrow().iter().find_map(|(key, resolution)| { + self.r.resolutions(module).iter().find_map(|(key, resolution)| { if key.ident.name != assoc_name { return None; } @@ -648,7 +648,6 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { && self .r .resolutions(module) - .borrow() .iter() .any(|(key, _r)| key.ident.name == following_seg.ident.name) } else { @@ -1164,7 +1163,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn lookup_doc_alias_name(&mut self, path: &[Segment], ns: Namespace) -> Option<(DefId, Ident)> { let find_doc_alias_name = |r: &mut Resolver<'ra, '_>, m: Module<'ra>, item_name: Symbol| { - for resolution in r.resolutions(m).borrow().values() { + for resolution in r.resolutions(m).values() { let Some(did) = resolution.borrow().best_decl().and_then(|binding| binding.res().opt_def_id()) else { @@ -1904,7 +1903,6 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let targets: Vec<_> = self .r .resolutions(module) - .borrow() .iter() .filter_map(|(key, resolution)| { let resolution = resolution.borrow(); @@ -2767,7 +2765,6 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let targets = self .r .resolutions(*module) - .borrow() .iter() .filter_map(|(key, res)| res.borrow().best_decl().map(|binding| (key, binding.res()))) .filter(|(_, res)| match (kind, res) { @@ -2970,7 +2967,6 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let module = self.r.expect_module(def_id); self.r .resolutions(module) - .borrow() .iter() .any(|(key, _)| key.ident.name == following_seg.ident.name) } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index af62b136f60c5..a3c804e56ee22 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -21,7 +21,7 @@ #![recursion_limit = "256"] // tidy-alphabetical-end -use std::cell::Ref; +use std::cell::{Ref, RefMut}; use std::collections::BTreeSet; use std::ops::ControlFlow; use std::sync::{Arc, OnceLock}; @@ -81,7 +81,7 @@ use crate::diagnostics::impls::{ ImportSuggestion, LabelSuggestion, OnUnknownData, StructCtor, Suggestion, }; use crate::imports::{ImportResolution, NameResolutionRef}; -use crate::ref_mut::{CmCell, CmRefCell}; +use crate::ref_mut::{CmCell, CmRef, CmRefCell}; mod build_reduced_graph; mod check_unused; @@ -637,7 +637,7 @@ type ResolutionTable<'ra> = FxIndexMap>; enum Resolutions<'ra> { Local(CmRefCell>), - Extern(OnceLock>>), + Extern(OnceLock>), } impl<'ra> Resolutions<'ra> { @@ -792,7 +792,7 @@ impl<'ra> Module<'ra> { resolver: &R, mut f: impl FnMut(&R, IdentKey, Span, Namespace, Decl<'ra>), ) { - for (key, name_resolution) in resolver.as_ref().resolutions(self).borrow().iter() { + for (key, name_resolution) in resolver.as_ref().resolutions(self).iter() { let name_resolution = name_resolution.borrow(); if let Some(decl) = name_resolution.best_decl() { f(resolver, key.ident, name_resolution.orig_ident_span, key.ns, decl); @@ -805,7 +805,7 @@ impl<'ra> Module<'ra> { resolver: &mut R, mut f: impl FnMut(&mut R, IdentKey, Span, Namespace, Decl<'ra>), ) { - for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() { + for (key, name_resolution) in resolver.as_mut().resolutions(self).iter() { let name_resolution = name_resolution.borrow(); if let Some(decl) = name_resolution.best_decl() { f(resolver, key.ident, name_resolution.orig_ident_span, key.ns, decl); @@ -2152,7 +2152,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { match (trait_module, assoc_item) { (Some(trait_module), Some((name, ns))) => self .resolutions(trait_module) - .borrow() .iter() .any(|(key, _name_resolution)| key.ns == ns && key.ident.name == name), _ => true, @@ -2177,14 +2176,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.tcx.hir_arena.alloc_slice(&import_ids) } - fn resolutions(&self, module: Module<'ra>) -> &'ra CmRefCell> { + fn resolutions(&self, module: Module<'ra>) -> CmRef<'ra, ResolutionTable<'ra>> { match &module.0.0.lazy_resolutions { - Resolutions::Local(local_res) => local_res, + Resolutions::Local(local_res) => CmRef::Tracked(local_res.borrow()), Resolutions::Extern(extern_res) => { - // as long as 1 thread is building this external table, all other threads will wait - extern_res.get_or_init(|| { - CmRefCell::new(self.build_reduced_graph_external(module.expect_extern())) - }) + // It is fine to return a `CmRef::Untracked`, we never give out a `&mut` + // to an external table. + CmRef::Untracked( + // As long as 1 thread is building this external table, all other threads will wait. + extern_res + .get_or_init(|| self.build_reduced_graph_external(module.expect_extern())), + ) + } + } + } + + fn resolutions_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(_) => { + // We do not allow in place mutations of the external resolution table. In fact, + // we never attempt it. + unreachable!("Attempted to mutably borrow an extenral resolution table") } } } @@ -2194,7 +2207,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module: Module<'ra>, key: BindingKey, ) -> Option>> { - self.resolutions(module).borrow().get(&key).map(|resolution| resolution.0.borrow()) + self.resolutions(module).get(&key).map(|resolution| resolution.0.borrow()) } #[track_caller] @@ -2204,7 +2217,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { key: BindingKey, orig_ident_span: Span, ) -> NameResolutionRef<'ra> { - *self.resolutions(module).borrow_mut(self).entry(key).or_insert_with(|| { + *self.resolutions_mut(module).entry(key).or_insert_with(|| { self.arenas.alloc_name_resolution(NameResolution::new(orig_ident_span)) }) } @@ -2915,6 +2928,24 @@ mod ref_mut { } } + pub(crate) enum CmRef<'b, T> { + /// A tracked borrow of a [`CmRefCell`] + Tracked(Ref<'b, T>), + /// An untracked or normal reference (not dynamically borrow-checked by `RefCell`) + Untracked(&'b T), + } + + impl<'b, T> Deref for CmRef<'b, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + match self { + CmRef::Tracked(r) => r, + CmRef::Untracked(r) => r, + } + } + } + /// A wrapper around a [`RefCell`] that only allows writes (mutable borrows) based on a condition in the resolver. #[derive(Default)] pub(crate) struct CmRefCell(RefCell); @@ -2926,10 +2957,7 @@ mod ref_mut { #[track_caller] pub(crate) fn borrow_mut<'ra, 'tcx>(&self, r: &Resolver<'ra, 'tcx>) -> RefMut<'_, T> { - if r.assert_speculative { - panic!("not allowed to mutably borrow a `CmRefCell` during speculative resolution"); - } - self.0.borrow_mut() + self.try_borrow_mut(r).unwrap() } #[track_caller]