diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 88f057c3a6d6d..2b6c9e919d5dc 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -5,7 +5,6 @@ //! unexpanded macros in the fragment are visited and registered. //! Imports are also considered items and placed into modules here, but not resolved yet. -use std::cell::RefMut; use std::sync::Arc; use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind}; @@ -16,6 +15,7 @@ use rustc_ast::{ }; use rustc_attr_parsing::AttributeParser; use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::sync::WriteGuard; use rustc_expand::base::{ResolverExpand, SyntaxExtension, SyntaxExtensionKind}; use rustc_hir::Attribute; use rustc_hir::attrs::{AttributeKind, MacroUseArgs}; @@ -135,7 +135,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn get_extern_module_with_lock( &self, def_id: DefId, - map_lock: &mut RefMut<'_, FxIndexMap>>, + map_lock: &mut WriteGuard<'_, FxIndexMap>>, ) -> Option> { if let module @ Some(..) = map_lock.get(&def_id) { return module.copied(); diff --git a/compiler/rustc_resolve/src/diagnostics/impls.rs b/compiler/rustc_resolve/src/diagnostics/impls.rs index a005824e5dbfa..455900750cf2b 100644 --- a/compiler/rustc_resolve/src/diagnostics/impls.rs +++ b/compiler/rustc_resolve/src/diagnostics/impls.rs @@ -1522,7 +1522,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Never recommend deprecated helper attributes. } Scope::MacroRules(macro_rules_scope) => { - if let MacroRulesScope::Def(macro_rules_def) = macro_rules_scope.get() { + if let MacroRulesScope::Def(macro_rules_def) = *macro_rules_scope.read() { let res = macro_rules_def.decl.res(); if filter_fn(res) { suggestions.push(TypoSuggestion::new( diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 06cc2315851d8..85457bbba5da7 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -143,11 +143,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // used to avoid long scope chains, see the comments on `MacroRulesScopeRef`. // As another consequence of this optimization visitors never observe invocation // scopes for macros that were already expanded. - let mut scope = macro_rules_scope.get(); + // We need to lock this scope, such that the compression is always final. + let mut write_scope = macro_rules_scope.write(); + let mut scope = *write_scope; while let MacroRulesScope::Invocation(invoc_id) = scope { if let Some(next) = self.output_macro_rules_scopes.get(&invoc_id) { - scope = next.get(); - macro_rules_scope.set(scope); + scope = *next.borrow(); + *write_scope = scope; } else { break; } @@ -188,7 +190,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } Scope::DeriveHelpersCompat => Scope::MacroRules(parent_scope.macro_rules), - Scope::MacroRules(macro_rules_scope) => match macro_rules_scope.get() { + Scope::MacroRules(macro_rules_scope) => match *macro_rules_scope.read() { MacroRulesScope::Def(binding) => { Scope::MacroRules(binding.parent_macro_rules_scope) } @@ -593,7 +595,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } result } - Scope::MacroRules(macro_rules_scope) => match macro_rules_scope.get() { + Scope::MacroRules(macro_rules_scope) => match *macro_rules_scope.read() { MacroRulesScope::Def(macro_rules_def) if ident == macro_rules_def.ident => { Ok(macro_rules_def.decl) } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index baadbc644582b..f6a9c87a2daa9 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -46,7 +46,7 @@ use rustc_ast::{ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, default}; use rustc_data_structures::intern::Interned; use rustc_data_structures::steal::Steal; -use rustc_data_structures::sync::{FreezeReadGuard, FreezeWriteGuard, WorkerLocal}; +use rustc_data_structures::sync::{FreezeReadGuard, FreezeWriteGuard, Lock, RwLock, WorkerLocal}; use rustc_data_structures::unord::{UnordItems, UnordMap, UnordSet}; use rustc_errors::{Applicability, Diag, ErrCode, ErrorGuaranteed, LintBuffer}; use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind}; @@ -1284,7 +1284,7 @@ struct ExternPreludeEntry<'ra> { item_decl: Option<(Decl<'ra>, Span, /* introduced by item */ bool)>, /// Name declaration from an `--extern` flag, lazily populated on first use. flag_decl: Option< - CacheCell<( + Lock<( PendingDecl<'ra>, /* finalized */ bool, /* open flag (namespaced crate) */ bool, @@ -1300,14 +1300,14 @@ impl ExternPreludeEntry<'_> { fn flag() -> Self { ExternPreludeEntry { item_decl: None, - flag_decl: Some(CacheCell::new((PendingDecl::Pending, false, false))), + flag_decl: Some(Lock::new((PendingDecl::Pending, false, false))), } } fn open_flag() -> Self { ExternPreludeEntry { item_decl: None, - flag_decl: Some(CacheCell::new((PendingDecl::Pending, false, true))), + flag_decl: Some(Lock::new((PendingDecl::Pending, false, true))), } } @@ -1407,7 +1407,7 @@ pub struct Resolver<'ra, 'tcx> { /// Eagerly populated map of all local non-block modules. local_module_map: FxIndexMap>, /// Lazily populated cache of modules loaded from external crates. - extern_module_map: CacheRefCell>>, + extern_module_map: RwLock>>, /// Maps glob imports to the names of items actually imported. glob_map: FxIndexMap>, @@ -1439,7 +1439,7 @@ pub struct Resolver<'ra, 'tcx> { /// Eagerly populated map of all local macro definitions. local_macro_map: FxHashMap> = default::fx_hash_map(), /// Lazily populated cache of macro definitions loaded from external crates. - extern_macro_map: CacheRefCell>>, + extern_macro_map: RwLock>>, dummy_ext_bang: &'ra Arc, dummy_ext_derive: &'ra Arc, non_macro_attr: &'ra Arc, @@ -1613,7 +1613,7 @@ impl<'ra> ResolverArenas<'ra> { Interned::new_unchecked(self.name_resolutions.alloc(CmRefCell::new(resolution))) } fn alloc_macro_rules_scope(&'ra self, scope: MacroRulesScope<'ra>) -> MacroRulesScopeRef<'ra> { - self.dropless.alloc(CacheCell::new(scope)) + self.dropless.alloc(RwLock::new(scope)) } fn alloc_macro_rules_decl(&'ra self, decl: MacroRulesDecl<'ra>) -> &'ra MacroRulesDecl<'ra> { self.dropless.alloc(decl) @@ -2469,7 +2469,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> Option> { let entry = self.extern_prelude.get(&ident); entry.and_then(|entry| entry.flag_decl.as_ref()).and_then(|flag_decl| { - let (pending_decl, finalized, is_open) = flag_decl.get(); + let mut flag_decl = flag_decl.lock(); // Lock for this entire process + let (pending_decl, finalized, is_open) = *flag_decl; let decl = match pending_decl { PendingDecl::Ready(decl) => { if finalize && !finalized && !is_open { @@ -2504,7 +2505,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } }; - flag_decl.set((PendingDecl::Ready(decl), finalize || finalized, is_open)); + *flag_decl = (PendingDecl::Ready(decl), finalize || finalized, is_open); decl.or_else(|| finalize.then_some(self.dummy_decl)) }) } @@ -2844,11 +2845,6 @@ pub fn provide(providers: &mut Providers) { /// Prefer constructing it through `Resolver::cm(_mut)` to ensure correctness. type CmResolver<'r, 'ra, 'tcx> = ref_mut::RefOrMut<'r, Resolver<'ra, 'tcx>>; -// FIXME: These are cells for caches that can be populated even during speculative resolution, -// and should be replaced with mutexes, atomics, or other synchronized data when migrating to -// parallel name resolution. -use std::cell::{Cell as CacheCell, RefCell as CacheRefCell}; - mod ref_mut { use std::cell::{BorrowMutError, Cell, Ref, RefCell, RefMut}; use std::fmt; diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index d57f831f3d204..23dc8a1f7fef3 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -7,6 +7,7 @@ use std::sync::Arc; use rustc_ast::{self as ast, Crate, DelegationSuffixes, NodeId}; use rustc_ast_pretty::pprust; use rustc_attr_parsing::AttributeParser; +use rustc_data_structures::sync::RwLock; use rustc_errors::{Applicability, StashKey}; use rustc_expand::base::{ Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, @@ -41,7 +42,7 @@ use crate::diagnostics::{ use crate::hygiene::Macros20NormalizedSyntaxContext; use crate::imports::Import; use crate::{ - BindingKey, CacheCell, CmResolver, Decl, DeclKind, DeriveData, Determinacy, Finalize, IdentKey, + BindingKey, CmResolver, Decl, DeclKind, DeriveData, Determinacy, Finalize, IdentKey, InvocationParent, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, Res, ResolutionError, Resolver, ScopeSet, Segment, Used, }; @@ -79,7 +80,7 @@ pub(crate) enum MacroRulesScope<'ra> { /// This helps to avoid uncontrollable growth of `macro_rules!` scope chains, /// which usually grow linearly with the number of macro invocations /// in a module (including derives) and hurt performance. -pub(crate) type MacroRulesScopeRef<'ra> = &'ra CacheCell>; +pub(crate) type MacroRulesScopeRef<'ra> = &'ra RwLock>; /// Macro namespace is separated into two sub-namespaces, one for bang macros and /// one for attribute-like macros (attributes, derives).