diff options
Diffstat (limited to 'compiler/rustc_resolve/src')
| -rw-r--r-- | compiler/rustc_resolve/src/build_reduced_graph.rs | 36 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/def_collector.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/diagnostics.rs | 9 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/ident.rs | 261 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/late/diagnostics.rs | 19 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/lib.rs | 26 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/macros.rs | 11 |
7 files changed, 208 insertions, 156 deletions
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index f775cac149e..ef122deba4e 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -162,28 +162,30 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - pub(crate) fn get_macro(&mut self, res: Res) -> Option<&MacroData> { + pub(crate) fn get_macro(&self, res: Res) -> Option<&'ra MacroData> { match res { Res::Def(DefKind::Macro(..), def_id) => Some(self.get_macro_by_def_id(def_id)), - Res::NonMacroAttr(_) => Some(&self.non_macro_attr), + Res::NonMacroAttr(_) => Some(self.non_macro_attr), _ => None, } } - pub(crate) fn get_macro_by_def_id(&mut self, def_id: DefId) -> &MacroData { - if self.macro_map.contains_key(&def_id) { - return &self.macro_map[&def_id]; - } - - let loaded_macro = self.cstore().load_macro_untracked(def_id, self.tcx); - let macro_data = match loaded_macro { - LoadedMacro::MacroDef { def, ident, attrs, span, edition } => { - self.compile_macro(&def, ident, &attrs, span, ast::DUMMY_NODE_ID, edition) - } - LoadedMacro::ProcMacro(ext) => MacroData::new(Arc::new(ext)), - }; + pub(crate) fn get_macro_by_def_id(&self, def_id: DefId) -> &'ra MacroData { + // Local macros are always compiled. + match def_id.as_local() { + Some(local_def_id) => self.local_macro_map[&local_def_id], + None => *self.extern_macro_map.borrow_mut().entry(def_id).or_insert_with(|| { + let loaded_macro = self.cstore().load_macro_untracked(def_id, self.tcx); + let macro_data = match loaded_macro { + LoadedMacro::MacroDef { def, ident, attrs, span, edition } => { + self.compile_macro(&def, ident, &attrs, span, ast::DUMMY_NODE_ID, edition) + } + LoadedMacro::ProcMacro(ext) => MacroData::new(Arc::new(ext)), + }; - self.macro_map.entry(def_id).or_insert(macro_data) + self.arenas.alloc_macro(macro_data) + }), + } } pub(crate) fn build_reduced_graph( @@ -1203,7 +1205,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { fn insert_unused_macro(&mut self, ident: Ident, def_id: LocalDefId, node_id: NodeId) { if !ident.as_str().starts_with('_') { self.r.unused_macros.insert(def_id, (node_id, ident)); - let nrules = self.r.macro_map[&def_id.to_def_id()].nrules; + let nrules = self.r.local_macro_map[&def_id].nrules; self.r.unused_macro_rules.insert(node_id, DenseBitSet::new_filled(nrules)); } } @@ -1222,7 +1224,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { Some((macro_kind, ident, span)) => { let res = Res::Def(DefKind::Macro(macro_kind), def_id.to_def_id()); let macro_data = MacroData::new(self.r.dummy_ext(macro_kind)); - self.r.macro_map.insert(def_id.to_def_id(), macro_data); + self.r.new_local_macro(def_id, macro_data); self.r.proc_macro_stubs.insert(def_id); (res, ident, span, false) } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 1e345b11c14..e2caf632dd2 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -165,7 +165,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { self.create_def(i.id, i.kind.ident().map(|ident| ident.name), def_kind, i.span); if let Some(macro_data) = opt_macro_data { - self.resolver.macro_map.insert(def_id.to_def_id(), macro_data); + self.resolver.new_local_macro(def_id, macro_data); } self.with_parent(def_id, |this| { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index c99bc747fd2..c4ff5770e76 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1669,9 +1669,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut all_attrs: UnordMap<Symbol, Vec<_>> = UnordMap::default(); // We're collecting these in a hashmap, and handle ordering the output further down. #[allow(rustc::potential_query_instability)] - for (def_id, data) in &self.macro_map { + for (def_id, data) in self + .local_macro_map + .iter() + .map(|(local_id, data)| (local_id.to_def_id(), data)) + .chain(self.extern_macro_map.borrow().iter().map(|(id, d)| (*id, d))) + { for helper_attr in &data.ext.helper_attrs { - let item_name = self.tcx.item_name(*def_id); + let item_name = self.tcx.item_name(def_id); all_attrs.entry(*helper_attr).or_default().push(item_name); if helper_attr == &ident.name { derives.push(item_name); diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 68fbe48ebcb..558cbef0014 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -13,7 +13,7 @@ use rustc_span::{Ident, Span, kw, sym}; use tracing::{debug, instrument}; use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst}; -use crate::imports::Import; +use crate::imports::{Import, NameResolution}; use crate::late::{ConstantHasGenerics, NoConstantGenericsReason, PathSource, Rib, RibKind}; use crate::macros::{MacroRulesScope, sub_namespace_match}; use crate::{ @@ -37,7 +37,7 @@ impl From<UsePrelude> for bool { } } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Clone, Copy)] enum Shadowing { Restricted, Unrestricted, @@ -879,53 +879,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .into_iter() .find_map(|binding| if binding == ignore_binding { None } else { binding }); - if let Some(Finalize { path_span, report_private, used, root_span, .. }) = finalize { - let Some(binding) = binding else { - return Err((Determined, Weak::No)); - }; - - if !self.is_accessible_from(binding.vis, parent_scope.module) { - if report_private { - self.privacy_errors.push(PrivacyError { - ident, - binding, - dedup_span: path_span, - outermost_res: None, - parent_scope: *parent_scope, - single_nested: path_span != root_span, - }); - } else { - return Err((Determined, Weak::No)); - } - } - - // Forbid expanded shadowing to avoid time travel. - if let Some(shadowed_glob) = resolution.shadowed_glob - && shadowing == Shadowing::Restricted - && binding.expansion != LocalExpnId::ROOT - && binding.res() != shadowed_glob.res() - { - self.ambiguity_errors.push(AmbiguityError { - kind: AmbiguityKind::GlobVsExpanded, - ident, - b1: binding, - b2: shadowed_glob, - warning: false, - misc1: AmbiguityErrorMisc::None, - misc2: AmbiguityErrorMisc::None, - }); - } - - if shadowing == Shadowing::Unrestricted - && binding.expansion != LocalExpnId::ROOT - && let NameBindingKind::Import { import, .. } = binding.kind - && matches!(import.kind, ImportKind::MacroExport) - { - self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); - } - - self.record_use(ident, binding, used); - return Ok(binding); + if let Some(finalize) = finalize { + return self.finalize_module_binding( + ident, + binding, + resolution.shadowed_glob, + parent_scope, + finalize, + shadowing, + ); } let check_usable = |this: &mut Self, binding: NameBinding<'ra>| { @@ -944,75 +906,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Check if one of single imports can still define the name, // if it can then our result is not determined and can be invalidated. - for single_import in &resolution.single_imports { - if ignore_import == Some(*single_import) { - // This branch handles a cycle in single imports. - // - // For example: - // ``` - // use a::b; - // use b as a; - // ``` - // 1. Record `use a::b` as the `ignore_import` and attempt to locate `a` in the - // current module. - // 2. Encounter the import `use b as a`, which is a `single_import` for `a`, - // and try to find `b` in the current module. - // 3. Re-encounter the `use a::b` import since it's a `single_import` of `b`. - // This leads to entering this branch. - continue; - } - if !self.is_accessible_from(single_import.vis, parent_scope.module) { - continue; - } - if let Some(ignored) = ignore_binding - && let NameBindingKind::Import { import, .. } = ignored.kind - && import == *single_import - { - // Ignore not just the binding itself, but if it has a shadowed_glob, - // ignore that, too, because this loop is supposed to only process - // named imports. - continue; - } - - let Some(module) = single_import.imported_module.get() else { - return Err((Undetermined, Weak::No)); - }; - let ImportKind::Single { source, target, target_bindings, .. } = &single_import.kind - else { - unreachable!(); - }; - if source != target { - // This branch allows the binding to be defined or updated later if the target name - // can hide the source. - if target_bindings.iter().all(|binding| binding.get().is_none()) { - // None of the target bindings are available, so we can't determine - // if this binding is correct or not. - // See more details in #124840 - return Err((Undetermined, Weak::No)); - } else if target_bindings[ns].get().is_none() && binding.is_some() { - // `binding.is_some()` avoids the condition where the binding - // truly doesn't exist in this namespace and should return `Err(Determined)`. - return Err((Undetermined, Weak::No)); - } - } - - match self.resolve_ident_in_module( - module, - *source, - ns, - &single_import.parent_scope, - None, - ignore_binding, - ignore_import, - ) { - Err((Determined, _)) => continue, - Ok(binding) - if !self.is_accessible_from(binding.vis, single_import.parent_scope.module) => - { - continue; - } - Ok(_) | Err((Undetermined, _)) => return Err((Undetermined, Weak::No)), - } + if self.single_import_can_define_name( + &resolution, + binding, + ns, + ignore_import, + ignore_binding, + parent_scope, + ) { + return Err((Undetermined, Weak::No)); } // So we have a resolution that's from a glob import. This resolution is determined @@ -1101,6 +1003,129 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Err((Determined, Weak::No)) } + fn finalize_module_binding( + &mut self, + ident: Ident, + binding: Option<NameBinding<'ra>>, + shadowed_glob: Option<NameBinding<'ra>>, + parent_scope: &ParentScope<'ra>, + finalize: Finalize, + shadowing: Shadowing, + ) -> Result<NameBinding<'ra>, (Determinacy, Weak)> { + let Finalize { path_span, report_private, used, root_span, .. } = finalize; + + let Some(binding) = binding else { + return Err((Determined, Weak::No)); + }; + + if !self.is_accessible_from(binding.vis, parent_scope.module) { + if report_private { + self.privacy_errors.push(PrivacyError { + ident, + binding, + dedup_span: path_span, + outermost_res: None, + parent_scope: *parent_scope, + single_nested: path_span != root_span, + }); + } else { + return Err((Determined, Weak::No)); + } + } + + // Forbid expanded shadowing to avoid time travel. + if let Some(shadowed_glob) = shadowed_glob + && shadowing == Shadowing::Restricted + && binding.expansion != LocalExpnId::ROOT + && binding.res() != shadowed_glob.res() + { + self.ambiguity_errors.push(AmbiguityError { + kind: AmbiguityKind::GlobVsExpanded, + ident, + b1: binding, + b2: shadowed_glob, + warning: false, + misc1: AmbiguityErrorMisc::None, + misc2: AmbiguityErrorMisc::None, + }); + } + + if shadowing == Shadowing::Unrestricted + && binding.expansion != LocalExpnId::ROOT + && let NameBindingKind::Import { import, .. } = binding.kind + && matches!(import.kind, ImportKind::MacroExport) + { + self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); + } + + self.record_use(ident, binding, used); + return Ok(binding); + } + + // Checks if a single import can define the `Ident` corresponding to `binding`. + // This is used to check whether we can definitively accept a glob as a resolution. + fn single_import_can_define_name( + &mut self, + resolution: &NameResolution<'ra>, + binding: Option<NameBinding<'ra>>, + ns: Namespace, + ignore_import: Option<Import<'ra>>, + ignore_binding: Option<NameBinding<'ra>>, + parent_scope: &ParentScope<'ra>, + ) -> bool { + for single_import in &resolution.single_imports { + if ignore_import == Some(*single_import) { + continue; + } + if !self.is_accessible_from(single_import.vis, parent_scope.module) { + continue; + } + if let Some(ignored) = ignore_binding + && let NameBindingKind::Import { import, .. } = ignored.kind + && import == *single_import + { + continue; + } + + let Some(module) = single_import.imported_module.get() else { + return true; + }; + let ImportKind::Single { source, target, target_bindings, .. } = &single_import.kind + else { + unreachable!(); + }; + if source != target { + if target_bindings.iter().all(|binding| binding.get().is_none()) { + return true; + } else if target_bindings[ns].get().is_none() && binding.is_some() { + return true; + } + } + + match self.resolve_ident_in_module( + module, + *source, + ns, + &single_import.parent_scope, + None, + ignore_binding, + ignore_import, + ) { + Err((Determined, _)) => continue, + Ok(binding) + if !self.is_accessible_from(binding.vis, single_import.parent_scope.module) => + { + continue; + } + Ok(_) | Err((Undetermined, _)) => { + return true; + } + } + } + + false + } + /// Validate a local resolution (from ribs). #[instrument(level = "debug", skip(self, all_ribs))] fn validate_res_from_ribs( diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index fa04c8bc604..8114021510e 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -328,8 +328,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let module_did = mod_prefix.as_ref().and_then(Res::mod_def_id); let mod_prefix = - mod_prefix.map_or_else(String::new, |res| (format!("{} ", res.descr()))); - + mod_prefix.map_or_else(String::new, |res| format!("{} ", res.descr())); (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)), module_did, None) }; @@ -1183,15 +1182,23 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { _ => "`self` value is a keyword only available in methods with a `self` parameter", }, ); + + // using `let self` is wrong even if we're not in an associated method or if we're in a macro expansion. + // So, we should return early if we're in a pattern, see issue #143134. + if matches!(source, PathSource::Pat) { + return true; + } + let is_assoc_fn = self.self_type_is_available(); let self_from_macro = "a `self` parameter, but a macro invocation can only \ access identifiers it receives from parameters"; - if let Some((fn_kind, span)) = &self.diag_metadata.current_function { + if let Some((fn_kind, fn_span)) = &self.diag_metadata.current_function { // The current function has a `self` parameter, but we were unable to resolve // a reference to `self`. This can only happen if the `self` identifier we - // are resolving came from a different hygiene context. + // are resolving came from a different hygiene context or a variable binding. + // But variable binding error is returned early above. if fn_kind.decl().inputs.get(0).is_some_and(|p| p.is_self()) { - err.span_label(*span, format!("this function has {self_from_macro}")); + err.span_label(*fn_span, format!("this function has {self_from_macro}")); } else { let doesnt = if is_assoc_fn { let (span, sugg) = fn_kind @@ -1204,7 +1211,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // This avoids placing the suggestion into the visibility specifier. let span = fn_kind .ident() - .map_or(*span, |ident| span.with_lo(ident.span.hi())); + .map_or(*fn_span, |ident| fn_span.with_lo(ident.span.hi())); ( self.r .tcx diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index f8ca20c568f..6e4c5ef1909 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1128,10 +1128,12 @@ pub struct Resolver<'ra, 'tcx> { builtin_macros: FxHashMap<Symbol, SyntaxExtensionKind>, registered_tools: &'tcx RegisteredTools, macro_use_prelude: FxIndexMap<Symbol, NameBinding<'ra>>, - macro_map: FxHashMap<DefId, MacroData>, + local_macro_map: FxHashMap<LocalDefId, &'ra MacroData>, + /// Lazily populated cache of macros loaded from external crates. + extern_macro_map: RefCell<FxHashMap<DefId, &'ra MacroData>>, dummy_ext_bang: Arc<SyntaxExtension>, dummy_ext_derive: Arc<SyntaxExtension>, - non_macro_attr: MacroData, + non_macro_attr: &'ra MacroData, local_macro_def_scopes: FxHashMap<LocalDefId, Module<'ra>>, ast_transform_scopes: FxHashMap<LocalExpnId, Module<'ra>>, unused_macros: FxIndexMap<LocalDefId, (NodeId, Ident)>, @@ -1241,6 +1243,7 @@ pub struct ResolverArenas<'ra> { imports: TypedArena<ImportData<'ra>>, name_resolutions: TypedArena<RefCell<NameResolution<'ra>>>, ast_paths: TypedArena<ast::Path>, + macros: TypedArena<MacroData>, dropless: DroplessArena, } @@ -1287,7 +1290,7 @@ impl<'ra> ResolverArenas<'ra> { self.name_resolutions.alloc(Default::default()) } fn alloc_macro_rules_scope(&'ra self, scope: MacroRulesScope<'ra>) -> MacroRulesScopeRef<'ra> { - Interned::new_unchecked(self.dropless.alloc(Cell::new(scope))) + self.dropless.alloc(Cell::new(scope)) } fn alloc_macro_rules_binding( &'ra self, @@ -1298,6 +1301,9 @@ impl<'ra> ResolverArenas<'ra> { fn alloc_ast_paths(&'ra self, paths: &[ast::Path]) -> &'ra [ast::Path] { self.ast_paths.alloc_from_iter(paths.iter().cloned()) } + fn alloc_macro(&'ra self, macro_data: MacroData) -> &'ra MacroData { + self.macros.alloc(macro_data) + } fn alloc_pattern_spans(&'ra self, spans: impl Iterator<Item = Span>) -> &'ra [Span] { self.dropless.alloc_from_iter(spans) } @@ -1540,10 +1546,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { builtin_macros: Default::default(), registered_tools, macro_use_prelude: Default::default(), - macro_map: FxHashMap::default(), + local_macro_map: Default::default(), + extern_macro_map: Default::default(), dummy_ext_bang: Arc::new(SyntaxExtension::dummy_bang(edition)), dummy_ext_derive: Arc::new(SyntaxExtension::dummy_derive(edition)), - non_macro_attr: MacroData::new(Arc::new(SyntaxExtension::non_macro_attr(edition))), + non_macro_attr: arenas + .alloc_macro(MacroData::new(Arc::new(SyntaxExtension::non_macro_attr(edition)))), invocation_parent_scopes: Default::default(), output_macro_rules_scopes: Default::default(), macro_rules_scopes: Default::default(), @@ -1616,6 +1624,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) } + fn new_local_macro(&mut self, def_id: LocalDefId, macro_data: MacroData) -> &'ra MacroData { + let mac = self.arenas.alloc_macro(macro_data); + self.local_macro_map.insert(def_id, mac); + mac + } + fn next_node_id(&mut self) -> NodeId { let start = self.next_node_id; let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds"); @@ -1734,7 +1748,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { f(self, MacroNS); } - fn is_builtin_macro(&mut self, res: Res) -> bool { + fn is_builtin_macro(&self, res: Res) -> bool { self.get_macro(res).is_some_and(|macro_data| macro_data.ext.builtin_name.is_some()) } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index f878b26d4e8..5864b035f73 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -9,7 +9,6 @@ use rustc_ast::expand::StrippedCfgItem; use rustc_ast::{self as ast, Crate, NodeId, attr}; use rustc_ast_pretty::pprust; use rustc_attr_data_structures::StabilityLevel; -use rustc_data_structures::intern::Interned; use rustc_errors::{Applicability, DiagCtxtHandle, StashKey}; use rustc_expand::base::{ Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, @@ -80,7 +79,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> = Interned<'ra, Cell<MacroRulesScope<'ra>>>; +pub(crate) type MacroRulesScopeRef<'ra> = &'ra Cell<MacroRulesScope<'ra>>; /// Macro namespace is separated into two sub-namespaces, one for bang macros and /// one for attribute-like macros (attributes, derives). @@ -354,8 +353,8 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { if unused_arms.is_empty() { continue; } - let def_id = self.local_def_id(node_id).to_def_id(); - let m = &self.macro_map[&def_id]; + let def_id = self.local_def_id(node_id); + let m = &self.local_macro_map[&def_id]; let SyntaxExtensionKind::LegacyBang(ref ext) = m.ext.kind else { continue; }; @@ -1132,7 +1131,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - pub(crate) fn check_reserved_macro_name(&mut self, ident: Ident, res: Res) { + pub(crate) fn check_reserved_macro_name(&self, ident: Ident, res: Res) { // Reserve some names that are not quite covered by the general check // performed on `Resolver::builtin_attrs`. if ident.name == sym::cfg || ident.name == sym::cfg_attr { @@ -1148,7 +1147,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// /// Possibly replace its expander to a pre-defined one for built-in macros. pub(crate) fn compile_macro( - &mut self, + &self, macro_def: &ast::MacroDef, ident: Ident, attrs: &[rustc_hir::Attribute], |
