diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index f5b38e750a544..d5babe2e94a90 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1148,10 +1148,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ignore_import: Option>, ) -> Result, ControlFlow> { let key = BindingKey::new(ident, ns); - let resolution_ref = self.resolution_or_default(module.to_module(), key, orig_ident_span); - let resolution = resolution_ref.borrow(); + let resolution = self.resolution(module.to_module(), key); - let binding = resolution.non_glob_decl.filter(|b| Some(*b) != ignore_decl); + let binding = + resolution.as_ref().and_then(|r| r.non_glob_decl).filter(|b| Some(*b) != ignore_decl); if let Some(finalize) = finalize { return self.get_mut().finalize_module_binding( @@ -1170,21 +1170,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return if accessible { Ok(binding) } else { Err(ControlFlow::Break(Determined)) }; } - // We need to detect resolution cycles to avoid infinite recursion. The guard ensures - // the resolution is removed when this resolve call ends. - let _cycle_guard = cycle_detection::enter_cycle_detector(resolution_ref) - .map_err(|_| ControlFlow::Continue(Determined))?; + if let Some(resolution) = resolution { + // We need to detect resolution cycles to avoid infinite recursion. The guard ensures + // the resolution is removed when this resolve call ends. + let _cycle_guard = cycle_detection::enter_cycle_detector(module, key) + .map_err(|_| ControlFlow::Continue(Determined))?; - // Check if one of single imports can still define the name, block if it can. - if self.reborrow().single_import_can_define_name( - &resolution, - None, - ns, - ignore_import, - ignore_decl, - parent_scope, - ) { - return Err(ControlFlow::Break(Undetermined)); + // Check if one of single imports can still define the name, block if it can. + if self.reborrow().single_import_can_define_name( + &resolution, + None, + ns, + ignore_import, + ignore_decl, + parent_scope, + ) { + return Err(ControlFlow::Break(Undetermined)); + } } // Check if one of unexpanded macros can still define the name. @@ -1210,10 +1212,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ignore_import: Option>, ) -> Result, ControlFlow> { let key = BindingKey::new(ident, ns); - let resolution_ref = self.resolution_or_default(module.to_module(), key, orig_ident_span); - let resolution = resolution_ref.borrow(); + let resolution = self.resolution(module.to_module(), key); - let binding = resolution.glob_decl.filter(|b| Some(*b) != ignore_decl); + let binding = + resolution.as_ref().and_then(|r| r.glob_decl).filter(|b| Some(*b) != ignore_decl); if let Some(finalize) = finalize { return self.get_mut().finalize_module_binding( @@ -1228,20 +1230,22 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // We need to detect resolution cycles to avoid infinite recursion. The guard ensures // the resolution is removed when this resolve call ends. - let _cycle_guard = cycle_detection::enter_cycle_detector(resolution_ref) + let _cycle_guard = cycle_detection::enter_cycle_detector(module, key) .map_err(|_| ControlFlow::Continue(Determined))?; // Check if one of single imports can still define the name, // if it can then our result is not determined and can be invalidated. - if self.reborrow().single_import_can_define_name( - &resolution, - binding, - ns, - ignore_import, - ignore_decl, - parent_scope, - ) { - return Err(ControlFlow::Break(Undetermined)); + if let Some(resolution) = resolution { + if self.reborrow().single_import_can_define_name( + &resolution, + binding, + ns, + ignore_import, + ignore_decl, + parent_scope, + ) { + return Err(ControlFlow::Break(Undetermined)); + } } // So we have a resolution that's from a glob import. This resolution is determined diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 08807616d5097..371c4ce0cb9d9 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -326,23 +326,23 @@ impl<'ra> NameResolution<'ra> { pub(crate) mod cycle_detection { use std::ptr; - use crate::CacheRefCell; - use crate::imports::NameResolutionRef; + use crate::{BindingKey, CacheRefCell, LocalModule}; thread_local!( /// During import resolution, recursive imports can form cycles. /// This set stores the active resolution stack for the current thread. - /// So it's essentially a recursion stack. + /// By keeping track of the module and `BindingKey` pair that identifies + /// the specific resolution. /// - /// The key is the interned address of a `RefCell>` allocated + /// The pointer is the interned address of a `Interned<'ra, ModuleData>` allocated /// in the `Resolver Arenas` (lifetime `'ra`), it is thus stable and allows casting /// to a `*const ()` for comparison. This is done because we can't use lifetimes /// other than `'static` in thread local storage. - static ACTIVE_RESOLUTIONS: CacheRefCell> = Default::default(); + static ACTIVE_RESOLUTIONS: CacheRefCell> = Default::default(); ); pub(crate) struct ActiveResolutionGuard { - key: *const (), + key: (*const (), BindingKey), } impl Drop for ActiveResolutionGuard { @@ -360,9 +360,11 @@ pub(crate) mod cycle_detection { /// Returns `Err(())` if a cycle is detected, otherwise this returns a /// guard that will remove the resolution when dropped. pub(crate) fn enter_cycle_detector<'ra>( - resolution: NameResolutionRef<'ra>, + module: LocalModule<'ra>, + binding_key: BindingKey, ) -> Result { - let key = ptr::from_ref(resolution.0).cast::<()>(); + let module_key = ptr::from_ref(module.0.0).cast(); + let key = (module_key, binding_key); ACTIVE_RESOLUTIONS.with_borrow_mut(|ar| { if ar.contains(&key) { return Err(());