diff options
Diffstat (limited to 'compiler/rustc_resolve/src')
| -rw-r--r-- | compiler/rustc_resolve/src/build_reduced_graph.rs | 225 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/check_unused.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/def_collector.rs | 21 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/diagnostics.rs | 166 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/errors.rs | 16 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/ident.rs | 281 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/imports.rs | 383 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/late.rs | 63 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/late/diagnostics.rs | 66 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/lib.rs | 188 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/macros.rs | 71 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/rustdoc.rs | 116 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/rustdoc/tests.rs | 6 | 
13 files changed, 873 insertions, 731 deletions
| diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 650a827ba56..5a1be618cee 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -18,10 +18,11 @@ use rustc_expand::base::ResolverExpand; use rustc_expand::expand::AstFragment; use rustc_hir::def::{self, *}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; +use rustc_index::bit_set::DenseBitSet; use rustc_metadata::creader::LoadedMacro; +use rustc_middle::bug; use rustc_middle::metadata::ModChild; -use rustc_middle::ty::Feed; -use rustc_middle::{bug, ty}; +use rustc_middle::ty::{Feed, Visibility}; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind}; use rustc_span::{Ident, Span, Symbol, kw, sym}; use tracing::debug; @@ -31,56 +32,43 @@ use crate::def_collector::collect_definitions; use crate::imports::{ImportData, ImportKind}; use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use crate::{ - BindingKey, Determinacy, ExternPreludeEntry, Finalize, MacroData, Module, ModuleKind, - ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult, - ResolutionError, Resolver, ResolverArenas, Segment, ToNameBinding, Used, VisResolutionError, - errors, + BindingKey, ExternPreludeEntry, Finalize, MacroData, Module, ModuleKind, ModuleOrUniformRoot, + NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, Used, + VisResolutionError, errors, }; type Res = def::Res<NodeId>; -impl<'ra, Id: Into<DefId>> ToNameBinding<'ra> - for (Module<'ra>, ty::Visibility<Id>, Span, LocalExpnId) -{ - fn to_name_binding(self, arenas: &'ra ResolverArenas<'ra>) -> NameBinding<'ra> { - arenas.alloc_name_binding(NameBindingData { - kind: NameBindingKind::Module(self.0), - ambiguity: None, - warn_ambiguity: false, - vis: self.1.to_def_id(), - span: self.2, - expansion: self.3, - }) - } -} - -impl<'ra, Id: Into<DefId>> ToNameBinding<'ra> for (Res, ty::Visibility<Id>, Span, LocalExpnId) { - fn to_name_binding(self, arenas: &'ra ResolverArenas<'ra>) -> NameBinding<'ra> { - arenas.alloc_name_binding(NameBindingData { - kind: NameBindingKind::Res(self.0), - ambiguity: None, - warn_ambiguity: false, - vis: self.1.to_def_id(), - span: self.2, - expansion: self.3, - }) - } -} - impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined; /// otherwise, reports an error. - pub(crate) fn define<T>(&mut self, parent: Module<'ra>, ident: Ident, ns: Namespace, def: T) - where - T: ToNameBinding<'ra>, - { - let binding = def.to_name_binding(self.arenas); + pub(crate) fn define_binding( + &mut self, + parent: Module<'ra>, + ident: Ident, + ns: Namespace, + binding: NameBinding<'ra>, + ) { let key = self.new_disambiguated_key(ident, ns); if let Err(old_binding) = self.try_define(parent, key, binding, false) { self.report_conflict(parent, ident, ns, old_binding, binding); } } + fn define( + &mut self, + parent: Module<'ra>, + ident: Ident, + ns: Namespace, + res: Res, + vis: Visibility<impl Into<DefId>>, + span: Span, + expn_id: LocalExpnId, + ) { + let binding = self.arenas.new_res_binding(res, vis.to_def_id(), span, expn_id); + self.define_binding(parent, ident, ns, binding) + } + /// Walks up the tree of definitions starting at `def_id`, /// stopping at the first encountered module. /// Parent block modules for arbitrary def-ids are not recorded for the local crate, @@ -121,7 +109,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if !def_id.is_local() { // Query `def_kind` is not used because query system overhead is too expensive here. let def_kind = self.cstore().def_kind_untracked(def_id); - if let DefKind::Mod | DefKind::Enum | DefKind::Trait = def_kind { + if def_kind.is_module_like() { let parent = self .tcx .opt_parent(def_id) @@ -161,28 +149,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( @@ -221,12 +211,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let expansion = parent_scope.expansion; // Record primary definitions. match res { - Res::Def(DefKind::Mod | DefKind::Enum | DefKind::Trait, def_id) => { - let module = self.expect_module(def_id); - self.define(parent, ident, TypeNS, (module, vis, span, expansion)); - } Res::Def( - DefKind::Struct + DefKind::Mod + | DefKind::Enum + | DefKind::Trait + | DefKind::Struct | DefKind::Union | DefKind::Variant | DefKind::TyAlias @@ -237,7 +226,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _, ) | Res::PrimTy(..) - | Res::ToolMod => self.define(parent, ident, TypeNS, (res, vis, span, expansion)), + | Res::ToolMod => self.define(parent, ident, TypeNS, res, vis, span, expansion), Res::Def( DefKind::Fn | DefKind::AssocFn @@ -246,9 +235,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { | DefKind::AssocConst | DefKind::Ctor(..), _, - ) => self.define(parent, ident, ValueNS, (res, vis, span, expansion)), + ) => self.define(parent, ident, ValueNS, res, vis, span, expansion), Res::Def(DefKind::Macro(..), _) | Res::NonMacroAttr(..) => { - self.define(parent, ident, MacroNS, (res, vis, span, expansion)) + self.define(parent, ident, MacroNS, res, vis, span, expansion) } Res::Def( DefKind::TyParam @@ -292,10 +281,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { Res::Def(self.r.tcx.def_kind(def_id), def_id) } - fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility { + fn resolve_visibility(&mut self, vis: &ast::Visibility) -> Visibility { self.try_resolve_visibility(vis, true).unwrap_or_else(|err| { self.r.report_vis_error(err); - ty::Visibility::Public + Visibility::Public }) } @@ -303,10 +292,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { &mut self, vis: &'ast ast::Visibility, finalize: bool, - ) -> Result<ty::Visibility, VisResolutionError<'ast>> { + ) -> Result<Visibility, VisResolutionError<'ast>> { let parent_scope = &self.parent_scope; match vis.kind { - ast::VisibilityKind::Public => Ok(ty::Visibility::Public), + ast::VisibilityKind::Public => Ok(Visibility::Public), ast::VisibilityKind::Inherited => { Ok(match self.parent_scope.module.kind { // Any inherited visibility resolved directly inside an enum or trait @@ -316,7 +305,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.tcx.visibility(def_id).expect_local() } // Otherwise, the visibility is restricted to the nearest parent `mod` item. - _ => ty::Visibility::Restricted( + _ => Visibility::Restricted( self.parent_scope.module.nearest_parent_mod().expect_local(), ), }) @@ -364,9 +353,9 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } if module.is_normal() { match res { - Res::Err => Ok(ty::Visibility::Public), + Res::Err => Ok(Visibility::Public), _ => { - let vis = ty::Visibility::Restricted(res.def_id()); + let vis = Visibility::Restricted(res.def_id()); if self.r.is_accessible_from(vis, parent_scope.module) { Ok(vis.expect_local()) } else { @@ -431,7 +420,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { item: &ast::Item, root_span: Span, root_id: NodeId, - vis: ty::Visibility, + vis: Visibility, ) { let current_module = self.parent_scope.module; let import = self.r.arenas.alloc_import(ImportData { @@ -479,7 +468,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { list_stem: bool, // The whole `use` item item: &Item, - vis: ty::Visibility, + vis: Visibility, root_span: Span, ) { debug!( @@ -617,16 +606,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let kind = ImportKind::Single { source: source.ident, target: ident, - source_bindings: PerNS { - type_ns: Cell::new(Err(Determinacy::Undetermined)), - value_ns: Cell::new(Err(Determinacy::Undetermined)), - macro_ns: Cell::new(Err(Determinacy::Undetermined)), - }, - target_bindings: PerNS { - type_ns: Cell::new(None), - value_ns: Cell::new(None), - macro_ns: Cell::new(None), - }, + bindings: Default::default(), type_ns_only, nested, id, @@ -697,7 +677,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { true, // The whole `use` item item, - ty::Visibility::Restricted( + Visibility::Restricted( self.parent_scope.module.nearest_parent_mod().expect_local(), ), root_span, @@ -713,7 +693,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ident: Ident, feed: Feed<'tcx, LocalDefId>, adt_res: Res, - adt_vis: ty::Visibility, + adt_vis: Visibility, adt_span: Span, ) { let parent_scope = &self.parent_scope; @@ -721,7 +701,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let expansion = parent_scope.expansion; // Define a name in the type namespace if it is not anonymous. - self.r.define(parent, ident, TypeNS, (adt_res, adt_vis, adt_span, expansion)); + self.r.define(parent, ident, TypeNS, adt_res, adt_vis, adt_span, expansion); self.r.feed_visibility(feed, adt_vis); let def_id = feed.key(); @@ -773,7 +753,12 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } ItemKind::Mod(_, ident, ref mod_kind) => { - let module = self.r.new_module( + self.r.define(parent, ident, TypeNS, res, vis, sp, expansion); + + if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind { + self.r.mods_with_parse_errors.insert(def_id); + } + self.parent_scope.module = self.r.new_module( Some(parent), ModuleKind::Def(def_kind, def_id, Some(ident.name)), expansion.to_expn_id(), @@ -781,24 +766,16 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { parent.no_implicit_prelude || ast::attr::contains_name(&item.attrs, sym::no_implicit_prelude), ); - self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); - - if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind { - self.r.mods_with_parse_errors.insert(def_id); - } - - // Descend into the module. - self.parent_scope.module = module; } // These items live in the value namespace. ItemKind::Const(box ConstItem { ident, .. }) | ItemKind::Delegation(box Delegation { ident, .. }) | ItemKind::Static(box StaticItem { ident, .. }) => { - self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion)); + self.r.define(parent, ident, ValueNS, res, vis, sp, expansion); } ItemKind::Fn(box Fn { ident, .. }) => { - self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion)); + self.r.define(parent, ident, ValueNS, res, vis, sp, expansion); // Functions introducing procedural macros reserve a slot // in the macro namespace as well (see #52225). @@ -807,19 +784,19 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // These items live in the type namespace. ItemKind::TyAlias(box TyAlias { ident, .. }) | ItemKind::TraitAlias(ident, ..) => { - self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); + self.r.define(parent, ident, TypeNS, res, vis, sp, expansion); } ItemKind::Enum(ident, _, _) | ItemKind::Trait(box ast::Trait { ident, .. }) => { - let module = self.r.new_module( + self.r.define(parent, ident, TypeNS, res, vis, sp, expansion); + + self.parent_scope.module = self.r.new_module( Some(parent), ModuleKind::Def(def_kind, def_id, Some(ident.name)), expansion.to_expn_id(), item.span, parent.no_implicit_prelude, ); - self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); - self.parent_scope.module = module; } // These items live in both the type and value namespaces. @@ -841,7 +818,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let mut ctor_vis = if vis.is_public() && ast::attr::contains_name(&item.attrs, sym::non_exhaustive) { - ty::Visibility::Restricted(CRATE_DEF_ID) + Visibility::Restricted(CRATE_DEF_ID) } else { vis }; @@ -854,7 +831,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // constructor visibility should still be determined correctly. let field_vis = self .try_resolve_visibility(&field.vis, false) - .unwrap_or(ty::Visibility::Public); + .unwrap_or(Visibility::Public); if ctor_vis.is_at_least(field_vis, self.r.tcx) { ctor_vis = field_vis; } @@ -863,7 +840,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let feed = self.r.feed(ctor_node_id); let ctor_def_id = feed.key(); let ctor_res = self.res(ctor_def_id); - self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion)); + self.r.define(parent, ident, ValueNS, ctor_res, ctor_vis, sp, expansion); self.r.feed_visibility(feed, ctor_vis); // We need the field visibility spans also for the constructor for E0603. self.insert_field_visibilities_local(ctor_def_id.to_def_id(), vdata.fields()); @@ -903,7 +880,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { item: &Item, ident: Ident, local_def_id: LocalDefId, - vis: ty::Visibility, + vis: Visibility, parent: Module<'ra>, ) { let sp = item.span; @@ -927,8 +904,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } .map(|module| { let used = self.process_macro_use_imports(item, module); - let vis = ty::Visibility::<LocalDefId>::Public; - let binding = (module, vis, sp, expansion).to_name_binding(self.r.arenas); + let binding = self.r.arenas.new_pub_res_binding(module.res().unwrap(), sp, expansion); (used, Some(ModuleOrUniformRoot::Module(module)), binding) }) .unwrap_or((true, None, self.r.dummy_binding)); @@ -985,7 +961,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ); } } - self.r.define(parent, ident, TypeNS, imported_binding); + self.r.define_binding(parent, ident, TypeNS, imported_binding); } /// Constructs the reduced graph for one foreign item. @@ -1002,7 +978,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let parent = self.parent_scope.module; let expansion = self.parent_scope.expansion; let vis = self.resolve_visibility(&item.vis); - self.r.define(parent, ident, ns, (self.res(def_id), vis, item.span, expansion)); + self.r.define(parent, ident, ns, self.res(def_id), vis, item.span, expansion); self.r.feed_visibility(feed, vis); } @@ -1088,7 +1064,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { root_span: span, span, module_path: Vec::new(), - vis: ty::Visibility::Restricted(CRATE_DEF_ID), + vis: Visibility::Restricted(CRATE_DEF_ID), }) }; @@ -1202,13 +1178,8 @@ 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)); - for (rule_i, rule_span) in &self.r.macro_map[&def_id.to_def_id()].rule_spans { - self.r - .unused_macro_rules - .entry(node_id) - .or_default() - .insert(*rule_i, (ident, *rule_span)); - } + let nrules = self.r.local_macro_map[&def_id].nrules; + self.r.unused_macro_rules.insert(node_id, DenseBitSet::new_filled(nrules)); } } @@ -1226,7 +1197,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) } @@ -1243,11 +1214,11 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.macro_names.insert(ident); let is_macro_export = ast::attr::contains_name(&item.attrs, sym::macro_export); let vis = if is_macro_export { - ty::Visibility::Public + Visibility::Public } else { - ty::Visibility::Restricted(CRATE_DEF_ID) + Visibility::Restricted(CRATE_DEF_ID) }; - let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas); + let binding = self.r.arenas.new_res_binding(res, vis.to_def_id(), span, expansion); self.r.set_binding_parent_module(binding, parent_scope.module); self.r.all_macro_rules.insert(ident.name); if is_macro_export { @@ -1266,7 +1237,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { }); self.r.import_use_map.insert(import, Used::Other); let import_binding = self.r.import(binding, import); - self.r.define(self.r.graph_root, ident, MacroNS, import_binding); + self.r.define_binding(self.r.graph_root, ident, MacroNS, import_binding); } else { self.r.check_reserved_macro_name(ident, res); self.insert_unused_macro(ident, def_id, item.id); @@ -1287,14 +1258,14 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // Visibilities must not be resolved non-speculatively twice // and we already resolved this one as a `fn` item visibility. ItemKind::Fn(..) => { - self.try_resolve_visibility(&item.vis, false).unwrap_or(ty::Visibility::Public) + self.try_resolve_visibility(&item.vis, false).unwrap_or(Visibility::Public) } _ => self.resolve_visibility(&item.vis), }; if !vis.is_public() { self.insert_unused_macro(ident, def_id, item.id); } - self.r.define(module, ident, MacroNS, (res, vis, span, expansion)); + self.r.define(module, ident, MacroNS, res, vis, span, expansion); self.r.feed_visibility(feed, vis); self.parent_scope.macro_rules } @@ -1430,7 +1401,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { if ctxt == AssocCtxt::Trait { let parent = self.parent_scope.module; let expansion = self.parent_scope.expansion; - self.r.define(parent, ident, ns, (self.res(def_id), vis, item.span, expansion)); + self.r.define(parent, ident, ns, self.res(def_id), vis, item.span, expansion); } else if !matches!(&item.kind, AssocItemKind::Delegation(deleg) if deleg.from_glob) { let impl_def_id = self.r.tcx.local_parent(local_def_id); let key = BindingKey::new(ident.normalize_to_macros_2_0(), ns); @@ -1515,13 +1486,13 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let feed = self.r.feed(variant.id); let def_id = feed.key(); let vis = self.resolve_visibility(&variant.vis); - self.r.define(parent, ident, TypeNS, (self.res(def_id), vis, variant.span, expn_id)); + self.r.define(parent, ident, TypeNS, self.res(def_id), vis, variant.span, expn_id); self.r.feed_visibility(feed, vis); // If the variant is marked as non_exhaustive then lower the visibility to within the crate. let ctor_vis = if vis.is_public() && ast::attr::contains_name(&variant.attrs, sym::non_exhaustive) { - ty::Visibility::Restricted(CRATE_DEF_ID) + Visibility::Restricted(CRATE_DEF_ID) } else { vis }; @@ -1531,7 +1502,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let feed = self.r.feed(ctor_node_id); let ctor_def_id = feed.key(); let ctor_res = self.res(ctor_def_id); - self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id)); + self.r.define(parent, ident, ValueNS, ctor_res, ctor_vis, variant.span, expn_id); self.r.feed_visibility(feed, ctor_vis); } diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 2e870c47f8e..81ee02ac3c7 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -511,7 +511,7 @@ impl Resolver<'_, '_> { for (_key, resolution) in self.resolutions(*module).borrow().iter() { let resolution = resolution.borrow(); - if let Some(binding) = resolution.binding + if let Some(binding) = resolution.best_binding() && let NameBindingKind::Import { import, .. } = binding.kind && let ImportKind::Single { id, .. } = import.kind { diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 16852d1661e..781e2ce9704 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -2,12 +2,12 @@ use std::mem; use rustc_ast::visit::FnKind; use rustc_ast::*; -use rustc_ast_pretty::pprust; use rustc_attr_parsing::{AttributeParser, Early, OmitDoc}; use rustc_expand::expand::AstFragment; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::def_id::LocalDefId; +use rustc_middle::span_bug; use rustc_span::hygiene::LocalExpnId; use rustc_span::{Span, Symbol, sym}; use tracing::debug; @@ -132,6 +132,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { &self.resolver.tcx.sess, self.resolver.tcx.features(), Vec::new(), + Early { emit_errors: false }, ); let attrs = parser.parse_attribute_list( &i.attrs, @@ -165,7 +166,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| { @@ -380,20 +381,20 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } fn visit_ty(&mut self, ty: &'a Ty) { - match &ty.kind { + match ty.kind { TyKind::MacCall(..) => self.visit_macro_invoc(ty.id), - TyKind::ImplTrait(id, _) => { - // HACK: pprust breaks strings with newlines when the type - // gets too long. We don't want these to show up in compiler - // output or built artifacts, so replace them here... - // Perhaps we should instead format APITs more robustly. - let name = Symbol::intern(&pprust::ty_to_string(ty).replace('\n', " ")); + TyKind::ImplTrait(opaque_id, _) => { + let name = *self + .resolver + .impl_trait_names + .get(&ty.id) + .unwrap_or_else(|| span_bug!(ty.span, "expected this opaque to be named")); let kind = match self.invocation_parent.impl_trait_context { ImplTraitContext::Universal => DefKind::TyParam, ImplTraitContext::Existential => DefKind::OpaqueTy, ImplTraitContext::InBinding => return visit::walk_ty(self, ty), }; - let id = self.create_def(*id, Some(name), kind, ty.span); + let id = self.create_def(opaque_id, Some(name), kind, ty.span); match self.invocation_parent.impl_trait_context { // Do not nest APIT, as we desugar them as `impl_trait: bounds`, // so the `impl_trait` node is not a parent to `bounds`. diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 9149974a617..5a162b5d2b9 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1,11 +1,12 @@ -use rustc_ast::expand::StrippedCfgItem; use rustc_ast::ptr::P; use rustc_ast::visit::{self, Visitor}; use rustc_ast::{ - self as ast, CRATE_NODE_ID, Crate, ItemKind, MetaItemInner, MetaItemKind, ModKind, NodeId, Path, + self as ast, CRATE_NODE_ID, Crate, ItemKind, ModKind, NodeId, Path, join_path_idents, }; use rustc_ast_pretty::pprust; -use rustc_attr_data_structures::{self as attr, Stability}; +use rustc_attr_data_structures::{ + self as attr, AttributeKind, CfgEntry, Stability, StrippedCfgItem, find_attr, +}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::codes::*; @@ -233,12 +234,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return; } - let old_kind = match (ns, old_binding.module()) { + let old_kind = match (ns, old_binding.res()) { (ValueNS, _) => "value", (MacroNS, _) => "macro", (TypeNS, _) if old_binding.is_extern_crate() => "extern crate", - (TypeNS, Some(module)) if module.is_normal() => "module", - (TypeNS, Some(module)) if module.is_trait() => "trait", + (TypeNS, Res::Def(DefKind::Mod, _)) => "module", + (TypeNS, Res::Def(DefKind::Trait, _)) => "trait", (TypeNS, _) => "type", }; @@ -256,22 +257,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; let label = match new_binding.is_import_user_facing() { - true => errors::NameDefinedMultipleTimeLabel::Reimported { span, name }, - false => errors::NameDefinedMultipleTimeLabel::Redefined { span, name }, + true => errors::NameDefinedMultipleTimeLabel::Reimported { span }, + false => errors::NameDefinedMultipleTimeLabel::Redefined { span }, }; let old_binding_label = (!old_binding.span.is_dummy() && old_binding.span != span).then(|| { let span = self.tcx.sess.source_map().guess_head_span(old_binding.span); match old_binding.is_import_user_facing() { - true => errors::NameDefinedMultipleTimeOldBindingLabel::Import { - span, - name, - old_kind, - }, + true => { + errors::NameDefinedMultipleTimeOldBindingLabel::Import { span, old_kind } + } false => errors::NameDefinedMultipleTimeOldBindingLabel::Definition { span, - name, old_kind, }, } @@ -281,6 +279,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .dcx() .create_err(errors::NameDefinedMultipleTime { span, + name, descr: ns.descr(), container, label, @@ -1322,7 +1321,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // collect submodules to explore - if let Some(module) = name_binding.module() { + if let Some(def_id) = name_binding.res().module_like_def_id() { // form the path let mut path_segments = path_segments.clone(); path_segments.push(ast::PathSegment::from_ident(ident)); @@ -1342,14 +1341,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if !is_extern_crate_that_also_appears_in_prelude || alias_import { // add the module to the lookup - if seen_modules.insert(module.def_id()) { + if seen_modules.insert(def_id) { if via_import { &mut worklist_via_import } else { &mut worklist }.push( ( - module, + this.expect_module(def_id), path_segments, child_accessible, child_doc_visible, - is_stable && this.is_stable(module.def_id(), name_binding.span), + is_stable && this.is_stable(def_id, name_binding.span), ), ); } @@ -1442,7 +1441,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { |(key, name_resolution)| { if key.ns == TypeNS && key.ident == ident - && let Some(binding) = name_resolution.borrow().binding + && let Some(binding) = name_resolution.borrow().best_binding() { match binding.res() { // No disambiguation needed if the identically named item we @@ -1496,7 +1495,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return None; }; for (_, resolution) in this.resolutions(m).borrow().iter() { - let Some(binding) = resolution.borrow().binding else { + let Some(binding) = resolution.borrow().best_binding() else { continue; }; let Res::Def(DefKind::Macro(MacroKind::Derive | MacroKind::Attr), def_id) = @@ -1671,9 +1670,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); @@ -2000,9 +2004,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Otherwise, point out if the struct has any private fields. if let Some(def_id) = res.opt_def_id() && !def_id.is_local() - && let Some(attr) = self.tcx.get_attr(def_id, sym::non_exhaustive) + && let Some(attr_span) = find_attr!(self.tcx.get_all_attrs(def_id), AttributeKind::NonExhaustive(span) => *span) { - non_exhaustive = Some(attr.span()); + non_exhaustive = Some(attr_span); } else if let Some(span) = ctor_fields_span { let label = errors::ConstructorPrivateIfAnyFieldPrivate { span }; err.subdiagnostic(label); @@ -2016,7 +2020,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - let mut sugg_paths = vec![]; + let mut sugg_paths: Vec<(Vec<Ident>, bool)> = vec![]; if let Some(mut def_id) = res.opt_def_id() { // We can't use `def_path_str` in resolve. let mut path = vec![def_id]; @@ -2029,16 +2033,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } // We will only suggest importing directly if it is accessible through that path. - let path_names: Option<Vec<String>> = path + let path_names: Option<Vec<Ident>> = path .iter() .rev() .map(|def_id| { - self.tcx.opt_item_name(*def_id).map(|n| { - if def_id.is_top_level_module() { - "crate".to_string() + self.tcx.opt_item_name(*def_id).map(|name| { + Ident::with_dummy_span(if def_id.is_top_level_module() { + kw::Crate } else { - n.to_string() - } + name + }) }) }) .collect(); @@ -2082,17 +2086,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { match binding.kind { NameBindingKind::Import { import, .. } => { for segment in import.module_path.iter().skip(1) { - path.push(segment.ident.to_string()); + path.push(segment.ident); } sugg_paths.push(( - path.iter() - .cloned() - .chain(vec![ident.to_string()].into_iter()) - .collect::<Vec<_>>(), + path.iter().cloned().chain(std::iter::once(ident)).collect::<Vec<_>>(), true, // re-export )); } - NameBindingKind::Res(_) | NameBindingKind::Module(_) => {} + NameBindingKind::Res(_) => {} } let first = binding == first_binding; let def_span = self.tcx.sess.source_map().guess_head_span(binding.span); @@ -2124,7 +2125,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { err.subdiagnostic(note); } // We prioritize shorter paths, non-core imports and direct imports over the alternatives. - sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0] == "core", *reexport)); + sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0].name == sym::core, *reexport)); for (sugg, reexport) in sugg_paths { if not_publicly_reexported { break; @@ -2134,7 +2135,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // `tests/ui/imports/issue-55884-2.rs` continue; } - let path = sugg.join("::"); + let path = join_path_idents(sugg); let sugg = if reexport { errors::ImportIdent::ThroughReExport { span: dedup_span, ident, path } } else { @@ -2304,25 +2305,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .ok() }; if let Some(binding) = binding { - let mut found = |what| { - msg = format!( - "expected {}, found {} `{}` in {}", - ns.descr(), - what, - ident, - parent - ) - }; - if binding.module().is_some() { - found("module") - } else { - match binding.res() { - // Avoid using TyCtxt::def_kind_descr in the resolver, because it - // indirectly *calls* the resolver, and would cause a query cycle. - Res::Def(kind, id) => found(kind.descr(id)), - _ => found(ns_to_try.descr()), - } - } + msg = format!( + "expected {}, found {} `{ident}` in {parent}", + ns.descr(), + binding.res().descr(), + ); }; } (msg, None) @@ -2423,6 +2410,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } else { let suggestion = if suggestion.is_some() { suggestion + } else if let Some(m) = self.undeclared_module_exists(ident) { + self.undeclared_module_suggest_declare(ident, m) } else if was_invoked_from_cargo() { Some(( vec![], @@ -2444,6 +2433,55 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } + fn undeclared_module_suggest_declare( + &mut self, + ident: Ident, + path: std::path::PathBuf, + ) -> Option<(Vec<(Span, String)>, String, Applicability)> { + Some(( + vec![(self.current_crate_outer_attr_insert_span, format!("mod {ident};\n"))], + format!( + "to make use of source file {}, use `mod {ident}` \ + in this file to declare the module", + path.display() + ), + Applicability::MaybeIncorrect, + )) + } + + fn undeclared_module_exists(&mut self, ident: Ident) -> Option<std::path::PathBuf> { + let map = self.tcx.sess.source_map(); + + let src = map.span_to_filename(ident.span).into_local_path()?; + let i = ident.as_str(); + // FIXME: add case where non parent using undeclared module (hard?) + let dir = src.parent()?; + let src = src.file_stem()?.to_str()?; + for file in [ + // …/x.rs + dir.join(i).with_extension("rs"), + // …/x/mod.rs + dir.join(i).join("mod.rs"), + ] { + if file.exists() { + return Some(file); + } + } + if !matches!(src, "main" | "lib" | "mod") { + for file in [ + // …/x/y.rs + dir.join(src).join(i).with_extension("rs"), + // …/x/y/mod.rs + dir.join(src).join(i).join("mod.rs"), + ] { + if file.exists() { + return Some(file); + } + } + } + None + } + /// Adds suggestions for a path that cannot be resolved. #[instrument(level = "debug", skip(self, parent_scope))] pub(crate) fn make_path_suggestion( @@ -2806,17 +2844,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let note = errors::FoundItemConfigureOut { span: ident.span }; err.subdiagnostic(note); - if let MetaItemKind::List(nested) = &cfg.kind - && let MetaItemInner::MetaItem(meta_item) = &nested[0] - && let MetaItemKind::NameValue(feature_name) = &meta_item.kind - { - let note = errors::ItemWasBehindFeature { - feature: feature_name.symbol, - span: meta_item.span, - }; + if let CfgEntry::NameValue { value: Some((feature, _)), .. } = cfg.0 { + let note = errors::ItemWasBehindFeature { feature, span: cfg.1 }; err.subdiagnostic(note); } else { - let note = errors::ItemWasCfgOut { span: cfg.span }; + let note = errors::ItemWasCfgOut { span: cfg.1 }; err.subdiagnostic(note); } } diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 7fe74378b67..b34bcb38f84 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -878,12 +878,12 @@ pub(crate) struct MacroExpandedExternCrateCannotShadowExternArguments { #[derive(Diagnostic)] #[diag(resolve_elided_anonymous_lifetime_report_error, code = E0637)] -pub(crate) struct ElidedAnonymousLivetimeReportError { +pub(crate) struct ElidedAnonymousLifetimeReportError { #[primary_span] #[label] pub(crate) span: Span, #[subdiagnostic] - pub(crate) suggestion: Option<ElidedAnonymousLivetimeReportErrorSuggestion>, + pub(crate) suggestion: Option<ElidedAnonymousLifetimeReportErrorSuggestion>, } #[derive(Diagnostic)] @@ -897,7 +897,7 @@ pub(crate) struct LendingIteratorReportError { #[derive(Diagnostic)] #[diag(resolve_anonymous_lifetime_non_gat_report_error)] -pub(crate) struct AnonymousLivetimeNonGatReportError { +pub(crate) struct AnonymousLifetimeNonGatReportError { #[primary_span] #[label] pub(crate) lifetime: Span, @@ -908,7 +908,7 @@ pub(crate) struct AnonymousLivetimeNonGatReportError { resolve_elided_anonymous_lifetime_report_error_suggestion, applicability = "machine-applicable" )] -pub(crate) struct ElidedAnonymousLivetimeReportErrorSuggestion { +pub(crate) struct ElidedAnonymousLifetimeReportErrorSuggestion { #[suggestion_part(code = "for<'a> ")] pub(crate) lo: Span, #[suggestion_part(code = "'a ")] @@ -917,7 +917,7 @@ pub(crate) struct ElidedAnonymousLivetimeReportErrorSuggestion { #[derive(Diagnostic)] #[diag(resolve_explicit_anonymous_lifetime_report_error, code = E0637)] -pub(crate) struct ExplicitAnonymousLivetimeReportError { +pub(crate) struct ExplicitAnonymousLifetimeReportError { #[primary_span] #[label] pub(crate) span: Span, @@ -934,6 +934,7 @@ pub(crate) struct ImplicitElidedLifetimeNotAllowedHere { #[derive(Diagnostic)] #[diag(resolve_underscore_lifetime_is_reserved, code = E0637)] +#[help] pub(crate) struct UnderscoreLifetimeIsReserved { #[primary_span] #[label] @@ -978,6 +979,7 @@ pub(crate) struct VariableNotInAllPatterns { pub(crate) struct NameDefinedMultipleTime { #[primary_span] pub(crate) span: Span, + pub(crate) name: Symbol, pub(crate) descr: &'static str, pub(crate) container: &'static str, #[subdiagnostic] @@ -992,13 +994,11 @@ pub(crate) enum NameDefinedMultipleTimeLabel { Reimported { #[primary_span] span: Span, - name: Symbol, }, #[label(resolve_name_defined_multiple_time_redefined)] Redefined { #[primary_span] span: Span, - name: Symbol, }, } @@ -1008,14 +1008,12 @@ pub(crate) enum NameDefinedMultipleTimeOldBindingLabel { Import { #[primary_span] span: Span, - name: Symbol, old_kind: &'static str, }, #[label(resolve_name_defined_multiple_time_old_binding_definition)] Definition { #[primary_span] span: Span, - name: Symbol, old_kind: &'static str, }, } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 68fbe48ebcb..84d66c15f00 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -3,28 +3,25 @@ use Namespace::*; use rustc_ast::{self as ast, NodeId}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{DefKind, Namespace, NonMacroAttrKind, PartialRes, PerNS}; -use rustc_middle::{bug, ty}; +use rustc_middle::bug; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK; use rustc_session::parse::feature_err; -use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext}; 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::{ AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingKey, Determinacy, Finalize, ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope, - ScopeSet, Segment, ToNameBinding, Used, Weak, errors, + ScopeSet, Segment, Used, Weak, errors, }; -type Visibility = ty::Visibility<LocalDefId>; - #[derive(Copy, Clone)] pub enum UsePrelude { No, @@ -37,7 +34,7 @@ impl From<UsePrelude> for bool { } } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Clone, Copy)] enum Shadowing { Restricted, Unrestricted, @@ -464,13 +461,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { Ok((Some(ext), _)) => { if ext.helper_attrs.contains(&ident.name) { - let binding = ( + let binding = this.arenas.new_pub_res_binding( Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat), - Visibility::Public, derive.span, LocalExpnId::ROOT, - ) - .to_name_binding(this.arenas); + ); result = Ok((binding, Flags::empty())); break; } @@ -875,57 +870,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // binding if it exists. What we really want here is having two separate scopes in // a module - one for non-globs and one for globs, but until that's done use this // hack to avoid inconsistent resolution ICEs during import validation. - let binding = [resolution.binding, resolution.shadowed_glob] + let binding = [resolution.non_glob_binding, resolution.glob_binding] .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, + if resolution.non_glob_binding.is_some() { resolution.glob_binding } else { None }, + parent_scope, + finalize, + shadowing, + ); } let check_usable = |this: &mut Self, binding: NameBinding<'ra>| { @@ -944,75 +901,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 +998,128 @@ 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, bindings, .. } = &single_import.kind else { + unreachable!(); + }; + if source != target { + if bindings.iter().all(|binding| binding.get().binding().is_none()) { + return true; + } else if bindings[ns].get().binding().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( @@ -1613,11 +1632,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res); - if let Some(next_module) = binding.module() { - if self.mods_with_parse_errors.contains(&next_module.def_id()) { + if let Some(def_id) = binding.res().module_like_def_id() { + if self.mods_with_parse_errors.contains(&def_id) { module_had_parse_errors = true; } - module = Some(ModuleOrUniformRoot::Module(next_module)); + module = Some(ModuleOrUniformRoot::Module(self.expect_module(def_id))); record_segment_res(self, res); } else if res == Res::ToolMod && !is_last && opt_ns.is_some() { if binding.is_import() { diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index e989209e177..c3e39d2071b 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -11,11 +11,12 @@ use rustc_errors::{Applicability, MultiSpan, pluralize, struct_span_code_err}; use rustc_hir::def::{self, DefKind, PartialRes}; use rustc_hir::def_id::DefId; use rustc_middle::metadata::{ModChild, Reexport}; -use rustc_middle::{span_bug, ty}; +use rustc_middle::span_bug; +use rustc_middle::ty::Visibility; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ - AMBIGUOUS_GLOB_REEXPORTS, HIDDEN_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, - REDUNDANT_IMPORTS, UNUSED_IMPORTS, + AMBIGUOUS_GLOB_REEXPORTS, EXPORTED_PRIVATE_DEPENDENCIES, HIDDEN_GLOB_REEXPORTS, + PUB_USE_OF_PRIVATE_EXTERN_CRATE, REDUNDANT_IMPORTS, UNUSED_IMPORTS, }; use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; @@ -24,7 +25,6 @@ use rustc_span::{Ident, Span, Symbol, kw, sym}; use smallvec::SmallVec; use tracing::debug; -use crate::Determinacy::{self, *}; use crate::Namespace::*; use crate::diagnostics::{DiagMode, Suggestion, import_candidates}; use crate::errors::{ @@ -33,13 +33,30 @@ use crate::errors::{ ConsiderAddingMacroExport, ConsiderMarkingAsPub, }; use crate::{ - AmbiguityError, AmbiguityKind, BindingKey, Finalize, ImportSuggestion, Module, + AmbiguityError, AmbiguityKind, BindingKey, Determinacy, Finalize, ImportSuggestion, Module, ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult, PerNS, ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string, names_to_string, }; type Res = def::Res<NodeId>; +/// A [`NameBinding`] in the process of being resolved. +#[derive(Clone, Copy, Default, PartialEq)] +pub(crate) enum PendingBinding<'ra> { + Ready(Option<NameBinding<'ra>>), + #[default] + Pending, +} + +impl<'ra> PendingBinding<'ra> { + pub(crate) fn binding(self) -> Option<NameBinding<'ra>> { + match self { + PendingBinding::Ready(binding) => binding, + PendingBinding::Pending => None, + } + } +} + /// Contains data for specific kinds of imports. #[derive(Clone)] pub(crate) enum ImportKind<'ra> { @@ -49,10 +66,8 @@ pub(crate) enum ImportKind<'ra> { /// `target` in `use prefix::source as target`. /// It will directly use `source` when the format is `use prefix::source`. target: Ident, - /// Bindings to which `source` refers to. - source_bindings: PerNS<Cell<Result<NameBinding<'ra>, Determinacy>>>, - /// Bindings introduced by `target`. - target_bindings: PerNS<Cell<Option<NameBinding<'ra>>>>, + /// Bindings introduced by the import. + bindings: PerNS<Cell<PendingBinding<'ra>>>, /// `true` for `...::{self [as target]}` imports, `false` otherwise. type_ns_only: bool, /// Did this import result from a nested import? ie. `use foo::{bar, baz};` @@ -74,7 +89,7 @@ pub(crate) enum ImportKind<'ra> { is_prelude: bool, // The visibility of the greatest re-export. // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors. - max_vis: Cell<Option<ty::Visibility>>, + max_vis: Cell<Option<Visibility>>, id: NodeId, }, ExternCrate { @@ -96,26 +111,14 @@ impl<'ra> std::fmt::Debug for ImportKind<'ra> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { use ImportKind::*; match self { - Single { - source, - target, - source_bindings, - target_bindings, - type_ns_only, - nested, - id, - } => f + Single { source, target, bindings, type_ns_only, nested, id, .. } => f .debug_struct("Single") .field("source", source) .field("target", target) // Ignore the nested bindings to avoid an infinite loop while printing. .field( - "source_bindings", - &source_bindings.clone().map(|b| b.into_inner().map(|_| format_args!(".."))), - ) - .field( - "target_bindings", - &target_bindings.clone().map(|b| b.into_inner().map(|_| format_args!(".."))), + "bindings", + &bindings.clone().map(|b| b.into_inner().binding().map(|_| format_args!(".."))), ) .field("type_ns_only", type_ns_only) .field("nested", nested) @@ -174,9 +177,16 @@ pub(crate) struct ImportData<'ra> { pub parent_scope: ParentScope<'ra>, pub module_path: Vec<Segment>, - /// The resolution of `module_path`. + /// The resolution of `module_path`: + /// + /// | `module_path` | `imported_module` | remark | + /// |-|-|-| + /// |`use prefix::foo`| `ModuleOrUniformRoot::Module(prefix)` | - | + /// |`use ::foo` | `ModuleOrUniformRoot::ExternPrelude` | 2018+ editions | + /// |`use ::foo` | `ModuleOrUniformRoot::CrateRootAndExternPrelude` | a special case in 2015 edition | + /// |`use foo` | `ModuleOrUniformRoot::CurrentScope` | - | pub imported_module: Cell<Option<ModuleOrUniformRoot<'ra>>>, - pub vis: ty::Visibility, + pub vis: Visibility, } /// All imports are unique and allocated on a same arena, @@ -235,15 +245,16 @@ pub(crate) struct NameResolution<'ra> { /// Single imports that may define the name in the namespace. /// Imports are arena-allocated, so it's ok to use pointers as keys. pub single_imports: FxIndexSet<Import<'ra>>, - /// The least shadowable known binding for this name, or None if there are no known bindings. - pub binding: Option<NameBinding<'ra>>, - pub shadowed_glob: Option<NameBinding<'ra>>, + /// The non-glob binding for this name, if it is known to exist. + pub non_glob_binding: Option<NameBinding<'ra>>, + /// The glob binding for this name, if it is known to exist. + pub glob_binding: Option<NameBinding<'ra>>, } impl<'ra> NameResolution<'ra> { /// Returns the binding for the name if it is known or None if it not known. pub(crate) fn binding(&self) -> Option<NameBinding<'ra>> { - self.binding.and_then(|binding| { + self.best_binding().and_then(|binding| { if !binding.is_glob_import() || self.single_imports.is_empty() { Some(binding) } else { @@ -251,6 +262,10 @@ impl<'ra> NameResolution<'ra> { } }) } + + pub(crate) fn best_binding(&self) -> Option<NameBinding<'ra>> { + self.non_glob_binding.or(self.glob_binding) + } } /// An error that may be transformed into a diagnostic later. Used to combine multiple unresolved @@ -331,69 +346,71 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.check_reserved_macro_name(key.ident, res); self.set_binding_parent_module(binding, module); self.update_resolution(module, key, warn_ambiguity, |this, resolution| { - if let Some(old_binding) = resolution.binding { + if let Some(old_binding) = resolution.best_binding() { if res == Res::Err && old_binding.res() != Res::Err { // Do not override real bindings with `Res::Err`s from error recovery. return Ok(()); } match (old_binding.is_glob_import(), binding.is_glob_import()) { (true, true) => { + let (glob_binding, old_glob_binding) = (binding, old_binding); // FIXME: remove `!binding.is_ambiguity_recursive()` after delete the warning ambiguity. if !binding.is_ambiguity_recursive() && let NameBindingKind::Import { import: old_import, .. } = - old_binding.kind - && let NameBindingKind::Import { import, .. } = binding.kind + old_glob_binding.kind + && let NameBindingKind::Import { import, .. } = glob_binding.kind && old_import == import { - // We should replace the `old_binding` with `binding` regardless - // of whether they has same resolution or not when they are - // imported from the same glob-import statement. - resolution.binding = Some(binding); - } else if res != old_binding.res() { - resolution.binding = Some(this.new_ambiguity_binding( + // When imported from the same glob-import statement, we should replace + // `old_glob_binding` with `glob_binding`, regardless of whether + // they have the same resolution or not. + resolution.glob_binding = Some(glob_binding); + } else if res != old_glob_binding.res() { + resolution.glob_binding = Some(this.new_ambiguity_binding( AmbiguityKind::GlobVsGlob, - old_binding, - binding, + old_glob_binding, + glob_binding, warn_ambiguity, )); } else if !old_binding.vis.is_at_least(binding.vis, this.tcx) { // We are glob-importing the same item but with greater visibility. - resolution.binding = Some(binding); + resolution.glob_binding = Some(glob_binding); } else if binding.is_ambiguity_recursive() { - resolution.binding = Some(this.new_warn_ambiguity_binding(binding)); + resolution.glob_binding = + Some(this.new_warn_ambiguity_binding(glob_binding)); } } (old_glob @ true, false) | (old_glob @ false, true) => { - let (glob_binding, nonglob_binding) = + let (glob_binding, non_glob_binding) = if old_glob { (old_binding, binding) } else { (binding, old_binding) }; if key.ns == MacroNS - && nonglob_binding.expansion != LocalExpnId::ROOT - && glob_binding.res() != nonglob_binding.res() + && non_glob_binding.expansion != LocalExpnId::ROOT + && glob_binding.res() != non_glob_binding.res() { - resolution.binding = Some(this.new_ambiguity_binding( + resolution.non_glob_binding = Some(this.new_ambiguity_binding( AmbiguityKind::GlobVsExpanded, - nonglob_binding, + non_glob_binding, glob_binding, false, )); } else { - resolution.binding = Some(nonglob_binding); + resolution.non_glob_binding = Some(non_glob_binding); } - if let Some(old_shadowed_glob) = resolution.shadowed_glob { - assert!(old_shadowed_glob.is_glob_import()); - if glob_binding.res() != old_shadowed_glob.res() { - resolution.shadowed_glob = Some(this.new_ambiguity_binding( + if let Some(old_glob_binding) = resolution.glob_binding { + assert!(old_glob_binding.is_glob_import()); + if glob_binding.res() != old_glob_binding.res() { + resolution.glob_binding = Some(this.new_ambiguity_binding( AmbiguityKind::GlobVsGlob, - old_shadowed_glob, + old_glob_binding, glob_binding, false, )); - } else if !old_shadowed_glob.vis.is_at_least(binding.vis, this.tcx) { - resolution.shadowed_glob = Some(glob_binding); + } else if !old_glob_binding.vis.is_at_least(binding.vis, this.tcx) { + resolution.glob_binding = Some(glob_binding); } } else { - resolution.shadowed_glob = Some(glob_binding); + resolution.glob_binding = Some(glob_binding); } } (false, false) => { @@ -401,7 +418,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } } else { - resolution.binding = Some(binding); + if binding.is_glob_import() { + resolution.glob_binding = Some(binding); + } else { + resolution.non_glob_binding = Some(binding); + } } Ok(()) @@ -484,8 +505,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Define a dummy resolution containing a `Res::Err` as a placeholder for a failed // or indeterminate resolution, also mark such failed imports as used to avoid duplicate diagnostics. fn import_dummy_binding(&mut self, import: Import<'ra>, is_indeterminate: bool) { - if let ImportKind::Single { target, ref target_bindings, .. } = import.kind { - if !(is_indeterminate || target_bindings.iter().all(|binding| binding.get().is_none())) + if let ImportKind::Single { target, ref bindings, .. } = import.kind { + if !(is_indeterminate + || bindings.iter().all(|binding| binding.get().binding().is_none())) { return; // Has resolution, do not create the dummy binding } @@ -560,10 +582,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { glob_error |= import.is_glob(); - if let ImportKind::Single { source, ref source_bindings, .. } = import.kind + if let ImportKind::Single { source, ref bindings, .. } = import.kind && source.name == kw::SelfLower // Silence `unresolved import` error if E0429 is already emitted - && let Err(Determined) = source_bindings.value_ns.get() + && let PendingBinding::Ready(None) = bindings.value_ns.get() { continue; } @@ -608,18 +630,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - self.throw_unresolved_import_error(errors, glob_error); + if !errors.is_empty() { + self.throw_unresolved_import_error(errors, glob_error); + } } - pub(crate) fn check_hidden_glob_reexports( - &mut self, - exported_ambiguities: FxHashSet<NameBinding<'ra>>, - ) { + pub(crate) fn lint_reexports(&mut self, exported_ambiguities: FxHashSet<NameBinding<'ra>>) { for module in self.arenas.local_modules().iter() { for (key, resolution) in self.resolutions(*module).borrow().iter() { let resolution = resolution.borrow(); - let Some(binding) = resolution.binding else { continue }; + let Some(binding) = resolution.best_binding() else { continue }; if let NameBindingKind::Import { import, .. } = binding.kind && let Some((amb_binding, _)) = binding.ambiguity @@ -639,7 +660,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ); } - if let Some(glob_binding) = resolution.shadowed_glob { + if let Some(glob_binding) = resolution.glob_binding + && resolution.non_glob_binding.is_some() + { if binding.res() != Res::Err && glob_binding.res() != Res::Err && let NameBindingKind::Import { import: glob_import, .. } = @@ -654,9 +677,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { NameBindingKind::Res(res) => { Some(self.def_id_to_node_id(res.def_id().expect_local())) } - NameBindingKind::Module(module) => { - Some(self.def_id_to_node_id(module.def_id().expect_local())) - } NameBindingKind::Import { import, .. } => import.id(), }; if let Some(binding_id) = binding_id { @@ -674,6 +694,27 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } } + + if let NameBindingKind::Import { import, .. } = binding.kind + && let Some(binding_id) = import.id() + && let import_def_id = self.local_def_id(binding_id) + && self.effective_visibilities.is_exported(import_def_id) + && let Res::Def(reexported_kind, reexported_def_id) = binding.res() + && !matches!(reexported_kind, DefKind::Ctor(..)) + && !reexported_def_id.is_local() + && self.tcx.is_private_dep(reexported_def_id.krate) + { + self.lint_buffer.buffer_lint( + EXPORTED_PRIVATE_DEPENDENCIES, + binding_id, + binding.span, + BuiltinLintDiag::ReexportPrivateDependency { + kind: binding.res().descr().to_string(), + name: key.ident.name.to_string(), + krate: self.tcx.crate_name(reexported_def_id.krate), + }, + ); + } } } } @@ -688,14 +729,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(def_id) if self.mods_with_parse_errors.contains(&def_id) => false, _ => true, }); + errors.retain(|(_import, err)| { + // If we've encountered something like `use _;`, we've already emitted an error stating + // that `_` is not a valid identifier, so we ignore that resolve error. + err.segment != Some(kw::Underscore) + }); + if errors.is_empty() { + self.tcx.dcx().delayed_bug("expected a parse or \"`_` can't be an identifier\" error"); return; } - /// Upper limit on the number of `span_label` messages. - const MAX_LABEL_COUNT: usize = 10; - let span = MultiSpan::from_spans(errors.iter().map(|(_, err)| err.span).collect()); + let paths = errors .iter() .map(|(import, err)| { @@ -715,6 +761,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { diag.note(note.clone()); } + /// Upper limit on the number of `span_label` messages. + const MAX_LABEL_COUNT: usize = 10; + for (import, err) in errors.into_iter().take(MAX_LABEL_COUNT) { if let Some(label) = err.label { diag.span_label(err.span, label); @@ -802,15 +851,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; import.imported_module.set(Some(module)); - let (source, target, source_bindings, target_bindings, type_ns_only) = match import.kind { - ImportKind::Single { - source, - target, - ref source_bindings, - ref target_bindings, - type_ns_only, - .. - } => (source, target, source_bindings, target_bindings, type_ns_only), + let (source, target, bindings, type_ns_only) = match import.kind { + ImportKind::Single { source, target, ref bindings, type_ns_only, .. } => { + (source, target, bindings, type_ns_only) + } ImportKind::Glob { .. } => { self.resolve_glob_import(import); return 0; @@ -821,21 +865,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut indeterminate_count = 0; self.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { - if let Err(Undetermined) = source_bindings[ns].get() { - let binding = this.maybe_resolve_ident_in_module( - module, - source, - ns, - &import.parent_scope, - Some(import), - ); - source_bindings[ns].set(binding); - } else { + if bindings[ns].get() != PendingBinding::Pending { return; }; - + let binding_result = this.maybe_resolve_ident_in_module( + module, + source, + ns, + &import.parent_scope, + Some(import), + ); let parent = import.parent_scope.module; - match source_bindings[ns].get() { + let binding = match binding_result { Ok(binding) => { if binding.is_assoc_item() && !this.tcx.features().import_trait_associated_functions() @@ -848,12 +889,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) .emit(); } - + // We need the `target`, `source` can be extracted. let imported_binding = this.import(binding, import); - target_bindings[ns].set(Some(imported_binding)); - this.define(parent, target, ns, imported_binding); + this.define_binding(parent, target, ns, imported_binding); + PendingBinding::Ready(Some(imported_binding)) } - Err(Determined) => { + Err(Determinacy::Determined) => { // Don't update the resolution for underscores, because it was never added. if target.name != kw::Underscore { let key = BindingKey::new(target, ns); @@ -861,9 +902,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { resolution.single_imports.swap_remove(&import); }); } + PendingBinding::Ready(None) } - Err(Undetermined) => indeterminate_count += 1, - } + Err(Determinacy::Undetermined) => { + indeterminate_count += 1; + PendingBinding::Pending + } + }; + bindings[ns].set(binding); } }); @@ -876,7 +922,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// consolidate multiple unresolved import errors into a single diagnostic. fn finalize_import(&mut self, import: Import<'ra>) -> Option<UnresolvedImportError> { let ignore_binding = match &import.kind { - ImportKind::Single { target_bindings, .. } => target_bindings[TypeNS].get(), + ImportKind::Single { bindings, .. } => bindings[TypeNS].get().binding(), _ => None, }; let ambiguity_errors_len = @@ -994,60 +1040,53 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { PathResult::Indeterminate => unreachable!(), }; - let (ident, target, source_bindings, target_bindings, type_ns_only, import_id) = - match import.kind { - ImportKind::Single { - source, - target, - ref source_bindings, - ref target_bindings, - type_ns_only, - id, - .. - } => (source, target, source_bindings, target_bindings, type_ns_only, id), - ImportKind::Glob { is_prelude, ref max_vis, id } => { - if import.module_path.len() <= 1 { - // HACK(eddyb) `lint_if_path_starts_with_module` needs at least - // 2 segments, so the `resolve_path` above won't trigger it. - let mut full_path = import.module_path.clone(); - full_path.push(Segment::from_ident(Ident::dummy())); - self.lint_if_path_starts_with_module(Some(finalize), &full_path, None); - } + let (ident, target, bindings, type_ns_only, import_id) = match import.kind { + ImportKind::Single { source, target, ref bindings, type_ns_only, id, .. } => { + (source, target, bindings, type_ns_only, id) + } + ImportKind::Glob { is_prelude, ref max_vis, id } => { + if import.module_path.len() <= 1 { + // HACK(eddyb) `lint_if_path_starts_with_module` needs at least + // 2 segments, so the `resolve_path` above won't trigger it. + let mut full_path = import.module_path.clone(); + full_path.push(Segment::from_ident(Ident::dummy())); + self.lint_if_path_starts_with_module(Some(finalize), &full_path, None); + } - if let ModuleOrUniformRoot::Module(module) = module - && module == import.parent_scope.module - { - // Importing a module into itself is not allowed. - return Some(UnresolvedImportError { + if let ModuleOrUniformRoot::Module(module) = module + && module == import.parent_scope.module + { + // Importing a module into itself is not allowed. + return Some(UnresolvedImportError { + span: import.span, + label: Some(String::from("cannot glob-import a module into itself")), + note: None, + suggestion: None, + candidates: None, + segment: None, + module: None, + }); + } + if !is_prelude + && let Some(max_vis) = max_vis.get() + && !max_vis.is_at_least(import.vis, self.tcx) + { + let def_id = self.local_def_id(id); + self.lint_buffer.buffer_lint( + UNUSED_IMPORTS, + id, + import.span, + BuiltinLintDiag::RedundantImportVisibility { + max_vis: max_vis.to_string(def_id, self.tcx), + import_vis: import.vis.to_string(def_id, self.tcx), span: import.span, - label: Some(String::from("cannot glob-import a module into itself")), - note: None, - suggestion: None, - candidates: None, - segment: None, - module: None, - }); - } - if !is_prelude - && let Some(max_vis) = max_vis.get() - && !max_vis.is_at_least(import.vis, self.tcx) - { - let def_id = self.local_def_id(id); - self.lint_buffer.buffer_lint( - UNUSED_IMPORTS, - id, - import.span, - BuiltinLintDiag::RedundantImportVisibility { - max_vis: max_vis.to_string(def_id, self.tcx), - import_vis: import.vis.to_string(def_id, self.tcx), - span: import.span, - }, - ); - } - return None; + }, + ); } - _ => unreachable!(), - }; + return None; + } + _ => unreachable!(), + }; if self.privacy_errors.len() != privacy_errors_len { // Get the Res for the last element, so that we can point to alternative ways of @@ -1078,17 +1117,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns, &import.parent_scope, Some(Finalize { report_private: false, ..finalize }), - target_bindings[ns].get(), + bindings[ns].get().binding(), Some(import), ); match binding { Ok(binding) => { // Consistency checks, analogous to `finalize_macro_resolutions`. - let initial_res = source_bindings[ns].get().map(|initial_binding| { + let initial_res = bindings[ns].get().binding().map(|binding| { + let initial_binding = binding.import_source(); all_ns_err = false; - if let Some(target_binding) = target_bindings[ns].get() - && target.name == kw::Underscore + if target.name == kw::Underscore && initial_binding.is_extern_crate() && !initial_binding.is_import() { @@ -1097,7 +1136,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } else { Used::Other }; - this.record_use(ident, target_binding, used); + this.record_use(ident, binding, used); } initial_binding.res() }); @@ -1109,7 +1148,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .span_delayed_bug(import.span, "some error happened for an import"); return; } - if let Ok(initial_res) = initial_res { + if let Some(initial_res) = initial_res { if res != initial_res { span_bug!(import.span, "inconsistent resolution for an import"); } @@ -1162,7 +1201,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return None; } // Never suggest the same name match *resolution.borrow() { - NameResolution { binding: Some(name_binding), .. } => { + ref resolution + if let Some(name_binding) = resolution.best_binding() => + { match name_binding.kind { NameBindingKind::Import { binding, .. } => { match binding.kind { @@ -1252,13 +1293,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut any_successful_reexport = false; let mut crate_private_reexport = false; self.per_ns(|this, ns| { - let Ok(binding) = source_bindings[ns].get() else { + let Some(binding) = bindings[ns].get().binding().map(|b| b.import_source()) else { return; }; if !binding.vis.is_at_least(import.vis, this.tcx) { reexport_error = Some((ns, binding)); - if let ty::Visibility::Restricted(binding_def_id) = binding.vis + if let Visibility::Restricted(binding_def_id) = binding.vis && binding_def_id.is_top_level_module() { crate_private_reexport = true; @@ -1323,7 +1364,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut full_path = import.module_path.clone(); full_path.push(Segment::from_ident(ident)); self.per_ns(|this, ns| { - if let Ok(binding) = source_bindings[ns].get() { + if let Some(binding) = bindings[ns].get().binding().map(|b| b.import_source()) { this.lint_if_path_starts_with_module(Some(finalize), &full_path, Some(binding)); } }); @@ -1333,7 +1374,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // this may resolve to either a value or a type, but for documentation // purposes it's good enough to just favor one over the other. self.per_ns(|this, ns| { - if let Ok(binding) = source_bindings[ns].get() { + if let Some(binding) = bindings[ns].get().binding().map(|b| b.import_source()) { this.import_res_map.entry(import_id).or_default()[ns] = Some(binding.res()); } }); @@ -1344,10 +1385,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn check_for_redundant_imports(&mut self, import: Import<'ra>) -> bool { // This function is only called for single imports. - let ImportKind::Single { - source, target, ref source_bindings, ref target_bindings, id, .. - } = import.kind - else { + let ImportKind::Single { source, target, ref bindings, id, .. } = import.kind else { unreachable!() }; @@ -1374,7 +1412,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut is_redundant = true; let mut redundant_span = PerNS { value_ns: None, type_ns: None, macro_ns: None }; self.per_ns(|this, ns| { - if is_redundant && let Ok(binding) = source_bindings[ns].get() { + let binding = bindings[ns].get().binding().map(|b| b.import_source()); + if is_redundant && let Some(binding) = binding { if binding.res() == Res::Err { return; } @@ -1385,7 +1424,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &import.parent_scope, None, false, - target_bindings[ns].get(), + bindings[ns].get().binding(), None, ) { Ok(other_binding) => { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 67dd87b0ae9..3ef98100d09 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -28,7 +28,7 @@ use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, Par use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::{MissingLifetimeKind, PrimTy, TraitCandidate}; use rustc_middle::middle::resolve_bound_vars::Set1; -use rustc_middle::ty::DelegationFnSig; +use rustc_middle::ty::{DelegationFnSig, Visibility}; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, ResolveDocLinks}; use rustc_session::lint::{self, BuiltinLintDiag}; @@ -370,7 +370,7 @@ enum LifetimeRibKind { #[derive(Copy, Clone, Debug)] enum LifetimeBinderKind { - BareFnType, + FnPtrType, PolyTrait, WhereBound, Item, @@ -384,7 +384,7 @@ impl LifetimeBinderKind { fn descr(self) -> &'static str { use LifetimeBinderKind::*; match self { - BareFnType => "type", + FnPtrType => "type", PolyTrait => "bound", WhereBound => "bound", Item | ConstItem => "item", @@ -638,8 +638,8 @@ impl PathSource<'_, '_, '_> { enum MaybeExported<'a> { Ok(NodeId), Impl(Option<DefId>), - ImplItem(Result<DefId, &'a Visibility>), - NestedUse(&'a Visibility), + ImplItem(Result<DefId, &'a ast::Visibility>), + NestedUse(&'a ast::Visibility), } impl MaybeExported<'_> { @@ -900,16 +900,16 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc self.diag_metadata.current_trait_object = Some(&bounds[..]); visit::walk_ty(self, ty) } - TyKind::BareFn(bare_fn) => { - let span = ty.span.shrink_to_lo().to(bare_fn.decl_span.shrink_to_lo()); + TyKind::FnPtr(fn_ptr) => { + let span = ty.span.shrink_to_lo().to(fn_ptr.decl_span.shrink_to_lo()); self.with_generic_param_rib( - &bare_fn.generic_params, + &fn_ptr.generic_params, RibKind::Normal, ty.id, - LifetimeBinderKind::BareFnType, + LifetimeBinderKind::FnPtrType, span, |this| { - this.visit_generic_params(&bare_fn.generic_params, false); + this.visit_generic_params(&fn_ptr.generic_params, false); this.with_lifetime_rib( LifetimeRibKind::AnonymousCreateParameter { binder: ty.id, @@ -921,12 +921,8 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc false, // We don't need to deal with patterns in parameters, because // they are not possible for foreign or bodiless functions. - bare_fn - .decl - .inputs - .iter() - .map(|Param { ty, .. }| (None, &**ty)), - &bare_fn.decl.output, + fn_ptr.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)), + &fn_ptr.decl.output, ) }, ); @@ -939,7 +935,7 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc &unsafe_binder.generic_params, RibKind::Normal, ty.id, - LifetimeBinderKind::BareFnType, + LifetimeBinderKind::FnPtrType, span, |this| { this.visit_generic_params(&unsafe_binder.generic_params, false); @@ -1418,11 +1414,14 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc fn visit_variant(&mut self, v: &'ast Variant) { self.resolve_doc_links(&v.attrs, MaybeExported::Ok(v.id)); - visit::walk_variant(self, v) - } - - fn visit_variant_discr(&mut self, discr: &'ast AnonConst) { - self.resolve_anon_const(discr, AnonConstKind::EnumDiscriminant); + self.visit_id(v.id); + walk_list!(self, visit_attribute, &v.attrs); + self.visit_vis(&v.vis); + self.visit_ident(&v.ident); + self.visit_variant_data(&v.data); + if let Some(discr) = &v.disr_expr { + self.resolve_anon_const(discr, AnonConstKind::EnumDiscriminant); + } } fn visit_field_def(&mut self, f: &'ast FieldDef) { @@ -1653,7 +1652,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { forward_ty_ban_rib.bindings.swap_remove(i); forward_ty_ban_rib_const_param_ty.bindings.swap_remove(i); } - GenericParamKind::Const { ref ty, kw_span: _, ref default } => { + GenericParamKind::Const { ref ty, span: _, ref default } => { // Const parameters can't have param bounds. assert!(param.bounds.is_empty()); @@ -1889,7 +1888,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { .. } = rib.kind { - Some(errors::ElidedAnonymousLivetimeReportErrorSuggestion { + Some(errors::ElidedAnonymousLifetimeReportErrorSuggestion { lo: span.shrink_to_lo(), hi: lifetime.ident.span.shrink_to_hi(), }) @@ -1915,18 +1914,18 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ty: ty.span, }); } else { - self.r.dcx().emit_err(errors::AnonymousLivetimeNonGatReportError { + self.r.dcx().emit_err(errors::AnonymousLifetimeNonGatReportError { lifetime: lifetime.ident.span, }); } } else { - self.r.dcx().emit_err(errors::ElidedAnonymousLivetimeReportError { + self.r.dcx().emit_err(errors::ElidedAnonymousLifetimeReportError { span: lifetime.ident.span, suggestion, }); } } else { - self.r.dcx().emit_err(errors::ExplicitAnonymousLivetimeReportError { + self.r.dcx().emit_err(errors::ExplicitAnonymousLifetimeReportError { span: lifetime.ident.span, }); }; @@ -2973,7 +2972,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } } - if let LifetimeBinderKind::BareFnType + if let LifetimeBinderKind::FnPtrType | LifetimeBinderKind::WhereBound | LifetimeBinderKind::Function | LifetimeBinderKind::ImplBlock = generics_kind @@ -3438,7 +3437,8 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }; ident.span.normalize_to_macros_2_0_and_adjust(module.expansion); let key = BindingKey::new(ident, ns); - let mut binding = self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.binding); + let mut binding = + self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.best_binding()); debug!(?binding); if binding.is_none() { // We could not find the trait item in the correct namespace. @@ -3449,7 +3449,8 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { _ => ns, }; let key = BindingKey::new(ident, ns); - binding = self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.binding); + binding = + self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.best_binding()); debug!(?binding); } @@ -3462,7 +3463,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { span, "error should be emitted when an unexpected trait item is used", ); - rustc_middle::ty::Visibility::Public + Visibility::Public }; this.r.feed_visibility(this.r.feed(id), vis); }; diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index d5dd3bdb6cd..a4601cb44eb 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) }; @@ -881,8 +880,10 @@ 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() { - let Some(did) = - resolution.borrow().binding.and_then(|binding| binding.res().opt_def_id()) + let Some(did) = resolution + .borrow() + .best_binding() + .and_then(|binding| binding.res().opt_def_id()) else { continue; }; @@ -1183,15 +1184,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 +1213,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 @@ -1457,15 +1466,16 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { self.resolve_path(mod_path, None, None) { let resolutions = self.r.resolutions(module).borrow(); - let targets: Vec<_> = - resolutions - .iter() - .filter_map(|(key, resolution)| { - resolution.borrow().binding.map(|binding| binding.res()).and_then( - |res| if filter_fn(res) { Some((key, res)) } else { None }, - ) - }) - .collect(); + let targets: Vec<_> = resolutions + .iter() + .filter_map(|(key, resolution)| { + resolution + .borrow() + .best_binding() + .map(|binding| binding.res()) + .and_then(|res| if filter_fn(res) { Some((key, res)) } else { None }) + }) + .collect(); if let [target] = targets.as_slice() { return Some(TypoSuggestion::single_item_from_ident(target.0.ident, target.1)); } @@ -2298,7 +2308,9 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let targets = resolutions .borrow() .iter() - .filter_map(|(key, res)| res.borrow().binding.map(|binding| (key, binding.res()))) + .filter_map(|(key, res)| { + res.borrow().best_binding().map(|binding| (key, binding.res())) + }) .filter(|(_, res)| match (kind, res) { (AssocItemKind::Const(..), Res::Def(DefKind::AssocConst, _)) => true, (AssocItemKind::Fn(_), Res::Def(DefKind::AssocFn, _)) => true, @@ -2644,18 +2656,17 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if result.is_some() || !name_binding.vis.is_visible_locally() { return; } - if let Some(module) = name_binding.module() { + if let Some(module_def_id) = name_binding.res().module_like_def_id() { // form the path let mut path_segments = path_segments.clone(); path_segments.push(ast::PathSegment::from_ident(ident)); - let module_def_id = module.def_id(); let doc_visible = doc_visible && (module_def_id.is_local() || !r.tcx.is_doc_hidden(module_def_id)); if module_def_id == def_id { let path = Path { span: name_binding.span, segments: path_segments, tokens: None }; result = Some(( - module, + r.expect_module(module_def_id), ImportSuggestion { did: Some(def_id), descr: "module", @@ -2670,6 +2681,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } else { // add the module to the lookup if seen_modules.insert(module_def_id) { + let module = r.expect_module(module_def_id); worklist.push((module, path_segments, doc_visible)); } } @@ -2940,7 +2952,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let span = if let [.., bound] = ¶m.bounds[..] { bound.span() } else if let GenericParam { - kind: GenericParamKind::Const { ty, kw_span: _, default }, .. + kind: GenericParamKind::Const { ty, span: _, default }, .. } = param { default.as_ref().map(|def| def.value.span).unwrap_or(ty.span) } else { @@ -3122,15 +3134,10 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { &mut err, Some(lifetime_ref.ident.name.as_str()), |err, _, span, message, suggestion, span_suggs| { - err.multipart_suggestion_with_style( + err.multipart_suggestion_verbose( message, std::iter::once((span, suggestion)).chain(span_suggs.clone()).collect(), Applicability::MaybeIncorrect, - if span_suggs.is_empty() { - SuggestionStyle::ShowCode - } else { - SuggestionStyle::ShowAlways - }, ); true }, @@ -3182,7 +3189,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let higher_ranked = matches!( kind, - LifetimeBinderKind::BareFnType + LifetimeBinderKind::FnPtrType | LifetimeBinderKind::PolyTrait | LifetimeBinderKind::WhereBound ); @@ -3837,6 +3844,7 @@ fn mk_where_bound_predicate( ref_id: DUMMY_NODE_ID, }, span: DUMMY_SP, + parens: ast::Parens::No, })], }; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index f0540725416..f904f326296 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -36,17 +36,17 @@ use late::{ }; use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use rustc_arena::{DroplessArena, TypedArena}; -use rustc_ast::expand::StrippedCfgItem; use rustc_ast::node_id::NodeMap; use rustc_ast::{ self as ast, AngleBracketedArg, CRATE_NODE_ID, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, NodeId, Path, attr, }; +use rustc_attr_data_structures::StrippedCfgItem; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::FreezeReadGuard; -use rustc_data_structures::unord::UnordMap; +use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::{Applicability, Diag, ErrCode, ErrorGuaranteed}; use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind}; use rustc_feature::BUILTIN_ATTRIBUTES; @@ -57,6 +57,7 @@ use rustc_hir::def::{ use rustc_hir::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalDefIdMap}; use rustc_hir::definitions::DisambiguatorState; use rustc_hir::{PrimTy, TraitCandidate}; +use rustc_index::bit_set::DenseBitSet; use rustc_metadata::creader::{CStore, CrateLoader}; use rustc_middle::metadata::ModChild; use rustc_middle::middle::privacy::EffectiveVisibilities; @@ -64,7 +65,7 @@ use rustc_middle::query::Providers; use rustc_middle::span_bug; use rustc_middle::ty::{ self, DelegationFnSig, Feed, MainDefinition, RegisteredTools, ResolverGlobalCtxt, - ResolverOutputs, TyCtxt, TyCtxtFeed, + ResolverOutputs, TyCtxt, TyCtxtFeed, Visibility, }; use rustc_query_system::ich::StableHashingContext; use rustc_session::lint::builtin::PRIVATE_MACRO_USE; @@ -578,7 +579,7 @@ struct ModuleData<'ra> { globs: RefCell<Vec<Import<'ra>>>, /// Used to memoize the traits in this module for faster searches through all traits in scope. - traits: RefCell<Option<Box<[(Ident, NameBinding<'ra>)]>>>, + traits: RefCell<Option<Box<[(Ident, NameBinding<'ra>, Option<Module<'ra>>)]>>>, /// Span of the module itself. Used for error reporting. span: Span, @@ -640,7 +641,7 @@ impl<'ra> Module<'ra> { F: FnMut(&mut R, Ident, Namespace, NameBinding<'ra>), { for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() { - if let Some(binding) = name_resolution.borrow().binding { + if let Some(binding) = name_resolution.borrow().best_binding() { f(resolver, key.ident, key.ns, binding); } } @@ -654,12 +655,12 @@ impl<'ra> Module<'ra> { let mut traits = self.traits.borrow_mut(); if traits.is_none() { let mut collected_traits = Vec::new(); - self.for_each_child(resolver, |_, name, ns, binding| { + self.for_each_child(resolver, |r, name, ns, binding| { if ns != TypeNS { return; } - if let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = binding.res() { - collected_traits.push((name, binding)) + if let Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) = binding.res() { + collected_traits.push((name, binding, r.as_mut().get_module(def_id))) } }); *traits = Some(collected_traits.into_boxed_slice()); @@ -673,7 +674,6 @@ impl<'ra> Module<'ra> { } } - // Public for rustdoc. fn def_id(self) -> DefId { self.opt_def_id().expect("`ModuleData::def_id` is called on a block module") } @@ -748,7 +748,7 @@ struct NameBindingData<'ra> { warn_ambiguity: bool, expansion: LocalExpnId, span: Span, - vis: ty::Visibility<DefId>, + vis: Visibility<DefId>, } /// All name bindings are unique and allocated on a same arena, @@ -768,20 +768,9 @@ impl std::hash::Hash for NameBindingData<'_> { } } -trait ToNameBinding<'ra> { - fn to_name_binding(self, arenas: &'ra ResolverArenas<'ra>) -> NameBinding<'ra>; -} - -impl<'ra> ToNameBinding<'ra> for NameBinding<'ra> { - fn to_name_binding(self, _: &'ra ResolverArenas<'ra>) -> NameBinding<'ra> { - self - } -} - #[derive(Clone, Copy, Debug)] enum NameBindingKind<'ra> { Res(Res), - Module(Module<'ra>), Import { binding: NameBinding<'ra>, import: Import<'ra> }, } @@ -874,19 +863,17 @@ struct AmbiguityError<'ra> { } impl<'ra> NameBindingData<'ra> { - fn module(&self) -> Option<Module<'ra>> { + fn res(&self) -> Res { match self.kind { - NameBindingKind::Module(module) => Some(module), - NameBindingKind::Import { binding, .. } => binding.module(), - _ => None, + NameBindingKind::Res(res) => res, + NameBindingKind::Import { binding, .. } => binding.res(), } } - fn res(&self) -> Res { + fn import_source(&self) -> NameBinding<'ra> { match self.kind { - NameBindingKind::Res(res) => res, - NameBindingKind::Module(module) => module.res().unwrap(), - NameBindingKind::Import { binding, .. } => binding.res(), + NameBindingKind::Import { binding, .. } => binding, + _ => unreachable!(), } } @@ -913,7 +900,7 @@ impl<'ra> NameBindingData<'ra> { DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), _, )) => true, - NameBindingKind::Res(..) | NameBindingKind::Module(..) => false, + NameBindingKind::Res(..) => false, } } @@ -922,11 +909,7 @@ impl<'ra> NameBindingData<'ra> { NameBindingKind::Import { import, .. } => { matches!(import.kind, ImportKind::ExternCrate { .. }) } - NameBindingKind::Module(module) - if let ModuleKind::Def(DefKind::Mod, def_id, _) = module.kind => - { - def_id.is_crate_root() - } + NameBindingKind::Res(Res::Def(_, def_id)) => def_id.is_crate_root(), _ => false, } } @@ -1014,13 +997,13 @@ struct DeriveData { struct MacroData { ext: Arc<SyntaxExtension>, - rule_spans: Vec<(usize, Span)>, + nrules: usize, macro_rules: bool, } impl MacroData { fn new(ext: Arc<SyntaxExtension>) -> MacroData { - MacroData { ext, rule_spans: Vec::new(), macro_rules: false } + MacroData { ext, nrules: 0, macro_rules: false } } } @@ -1031,7 +1014,7 @@ pub struct Resolver<'ra, 'tcx> { tcx: TyCtxt<'tcx>, /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`. - expn_that_defined: FxHashMap<LocalDefId, ExpnId>, + expn_that_defined: UnordMap<LocalDefId, ExpnId>, graph_root: Module<'ra>, @@ -1100,7 +1083,7 @@ pub struct Resolver<'ra, 'tcx> { /// Maps glob imports to the names of items actually imported. glob_map: FxIndexMap<LocalDefId, FxIndexSet<Symbol>>, glob_error: Option<ErrorGuaranteed>, - visibilities_for_hashing: Vec<(LocalDefId, ty::Visibility)>, + visibilities_for_hashing: Vec<(LocalDefId, Visibility)>, used_imports: FxHashSet<NodeId>, maybe_unused_trait_imports: FxIndexSet<LocalDefId>, @@ -1127,15 +1110,17 @@ 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)>, /// A map from the macro to all its potentially unused arms. - unused_macro_rules: FxIndexMap<NodeId, UnordMap<usize, (Ident, Span)>>, + unused_macro_rules: FxIndexMap<NodeId, DenseBitSet<usize>>, proc_macro_stubs: FxHashSet<LocalDefId>, /// Traces collected during macro resolution and validated when it's complete. single_segment_macro_resolutions: @@ -1171,7 +1156,7 @@ pub struct Resolver<'ra, 'tcx> { /// Table for mapping struct IDs into struct constructor IDs, /// it's not used during normal resolution, only for better error reporting. /// Also includes of list of each fields visibility - struct_constructors: LocalDefIdMap<(Res, ty::Visibility<DefId>, Vec<ty::Visibility<DefId>>)>, + struct_constructors: LocalDefIdMap<(Res, Visibility<DefId>, Vec<Visibility<DefId>>)>, lint_buffer: LintBuffer, @@ -1208,7 +1193,7 @@ pub struct Resolver<'ra, 'tcx> { effective_visibilities: EffectiveVisibilities, doc_link_resolutions: FxIndexMap<LocalDefId, DocLinkResMap>, doc_link_traits_in_scope: FxIndexMap<LocalDefId, Vec<DefId>>, - all_macro_rules: FxHashSet<Symbol>, + all_macro_rules: UnordSet<Symbol>, /// Invocation ids of all glob delegations. glob_delegation_invoc_ids: FxHashSet<LocalExpnId>, @@ -1224,6 +1209,11 @@ pub struct Resolver<'ra, 'tcx> { current_crate_outer_attr_insert_span: Span, mods_with_parse_errors: FxHashSet<DefId>, + + // Stores pre-expansion and pre-placeholder-fragment-insertion names for `impl Trait` types + // that were encountered during resolution. These names are used to generate item names + // for APITs, so we don't want to leak details of resolution into these names. + impl_trait_names: FxHashMap<NodeId, Symbol>, } /// This provides memory for the rest of the crate. The `'ra` lifetime that is @@ -1235,10 +1225,37 @@ pub struct ResolverArenas<'ra> { imports: TypedArena<ImportData<'ra>>, name_resolutions: TypedArena<RefCell<NameResolution<'ra>>>, ast_paths: TypedArena<ast::Path>, + macros: TypedArena<MacroData>, dropless: DroplessArena, } impl<'ra> ResolverArenas<'ra> { + fn new_res_binding( + &'ra self, + res: Res, + vis: Visibility<DefId>, + span: Span, + expansion: LocalExpnId, + ) -> NameBinding<'ra> { + self.alloc_name_binding(NameBindingData { + kind: NameBindingKind::Res(res), + ambiguity: None, + warn_ambiguity: false, + vis, + span, + expansion, + }) + } + + fn new_pub_res_binding( + &'ra self, + res: Res, + span: Span, + expn_id: LocalExpnId, + ) -> NameBinding<'ra> { + self.new_res_binding(res, Visibility::Public, span, expn_id) + } + fn new_module( &'ra self, parent: Option<Module<'ra>>, @@ -1262,8 +1279,8 @@ impl<'ra> ResolverArenas<'ra> { } if let Some(def_id) = def_id { module_map.insert(def_id, module); - let vis = ty::Visibility::<DefId>::Public; - let binding = (module, vis, module.span, LocalExpnId::ROOT).to_name_binding(self); + let res = module.res().unwrap(); + let binding = self.new_pub_res_binding(res, module.span, LocalExpnId::ROOT); module_self_bindings.insert(module, binding); } module @@ -1281,7 +1298,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, @@ -1292,6 +1309,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) } @@ -1451,8 +1471,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let registered_tools = tcx.registered_tools(()); - - let pub_vis = ty::Visibility::<DefId>::Public; let edition = tcx.sess.edition(); let mut resolver = Resolver { @@ -1501,12 +1519,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { macro_expanded_macro_export_errors: BTreeSet::new(), arenas, - dummy_binding: (Res::Err, pub_vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(arenas), + dummy_binding: arenas.new_pub_res_binding(Res::Err, DUMMY_SP, LocalExpnId::ROOT), builtin_types_bindings: PrimTy::ALL .iter() .map(|prim_ty| { - let binding = (Res::PrimTy(*prim_ty), pub_vis, DUMMY_SP, LocalExpnId::ROOT) - .to_name_binding(arenas); + let res = Res::PrimTy(*prim_ty); + let binding = arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT); (prim_ty.name(), binding) }) .collect(), @@ -1514,16 +1532,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .iter() .map(|builtin_attr| { let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin(builtin_attr.name)); - let binding = - (res, pub_vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(arenas); + let binding = arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT); (builtin_attr.name, binding) }) .collect(), registered_tool_bindings: registered_tools .iter() .map(|ident| { - let binding = (Res::ToolMod, pub_vis, ident.span, LocalExpnId::ROOT) - .to_name_binding(arenas); + let res = Res::ToolMod; + let binding = arenas.new_pub_res_binding(res, ident.span, LocalExpnId::ROOT); (*ident, binding) }) .collect(), @@ -1534,10 +1551,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(), @@ -1579,11 +1598,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { impl_binding_keys: Default::default(), current_crate_outer_attr_insert_span, mods_with_parse_errors: Default::default(), + impl_trait_names: Default::default(), }; let root_parent_scope = ParentScope::module(graph_root, &resolver); resolver.invocation_parent_scopes.insert(LocalExpnId::ROOT, root_parent_scope); - resolver.feed_visibility(crate_feed, ty::Visibility::Public); + resolver.feed_visibility(crate_feed, Visibility::Public); resolver } @@ -1609,6 +1629,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"); @@ -1631,7 +1657,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Default::default() } - fn feed_visibility(&mut self, feed: Feed<'tcx, LocalDefId>, vis: ty::Visibility) { + fn feed_visibility(&mut self, feed: Feed<'tcx, LocalDefId>, vis: Visibility) { let feed = feed.upgrade(self.tcx); feed.visibility(vis.to_def_id()); self.visibilities_for_hashing.push((feed.def_id(), vis)); @@ -1647,16 +1673,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let confused_type_with_std_module = self.confused_type_with_std_module; let effective_visibilities = self.effective_visibilities; - let stripped_cfg_items = Steal::new( - self.stripped_cfg_items - .into_iter() - .filter_map(|item| { - let parent_module = - self.node_id_to_def_id.get(&item.parent_module)?.key().to_def_id(); - Some(StrippedCfgItem { parent_module, ident: item.ident, cfg: item.cfg }) - }) - .collect(), - ); + let stripped_cfg_items = self + .stripped_cfg_items + .into_iter() + .filter_map(|item| { + let parent_module = + self.node_id_to_def_id.get(&item.parent_module)?.key().to_def_id(); + Some(StrippedCfgItem { parent_module, ident: item.ident, cfg: item.cfg }) + }) + .collect(); let global_ctxt = ResolverGlobalCtxt { expn_that_defined, @@ -1728,7 +1753,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()) } @@ -1748,9 +1773,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let exported_ambiguities = self.tcx.sess.time("compute_effective_visibilities", || { EffectiveVisibilitiesVisitor::compute_effective_visibilities(self, krate) }); - self.tcx.sess.time("check_hidden_glob_reexports", || { - self.check_hidden_glob_reexports(exported_ambiguities) - }); + self.tcx.sess.time("lint_reexports", || self.lint_reexports(exported_ambiguities)); self.tcx .sess .time("finalize_macro_resolutions", || self.finalize_macro_resolutions(krate)); @@ -1810,10 +1833,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { module.ensure_traits(self); let traits = module.traits.borrow(); - for (trait_name, trait_binding) in traits.as_ref().unwrap().iter() { - if self.trait_may_have_item(trait_binding.module(), assoc_item) { + for &(trait_name, trait_binding, trait_module) in traits.as_ref().unwrap().iter() { + if self.trait_may_have_item(trait_module, assoc_item) { let def_id = trait_binding.res().def_id(); - let import_ids = self.find_transitive_imports(&trait_binding.kind, *trait_name); + let import_ids = self.find_transitive_imports(&trait_binding.kind, trait_name); found_traits.push(TraitCandidate { def_id, import_ids }); } } @@ -2083,11 +2106,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.pat_span_map.insert(node, span); } - fn is_accessible_from( - &self, - vis: ty::Visibility<impl Into<DefId>>, - module: Module<'ra>, - ) -> bool { + fn is_accessible_from(&self, vis: Visibility<impl Into<DefId>>, module: Module<'ra>) -> bool { vis.is_accessible_from(module.nearest_parent_mod(), self.tcx) } @@ -2147,9 +2166,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } else { self.crate_loader(|c| c.maybe_process_path_extern(ident.name))? }; - let crate_root = self.expect_module(crate_id.as_def_id()); - let vis = ty::Visibility::<DefId>::Public; - (crate_root, vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(self.arenas) + let res = Res::Def(DefKind::Mod, crate_id.as_def_id()); + self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT) }) }); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 1b82e9c9799..c17d74659db 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -5,11 +5,9 @@ use std::cell::Cell; use std::mem; use std::sync::Arc; -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_attr_data_structures::{CfgEntry, StabilityLevel, StrippedCfgItem}; use rustc_errors::{Applicability, DiagCtxtHandle, StashKey}; use rustc_expand::base::{ Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, @@ -22,10 +20,10 @@ use rustc_expand::expand::{ use rustc_hir::def::{self, DefKind, Namespace, NonMacroAttrKind}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_middle::middle::stability; -use rustc_middle::ty::{RegisteredTools, TyCtxt, Visibility}; +use rustc_middle::ty::{RegisteredTools, TyCtxt}; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ - LEGACY_DERIVE_HELPERS, OUT_OF_SCOPE_MACRO_CALLS, UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + LEGACY_DERIVE_HELPERS, OUT_OF_SCOPE_MACRO_CALLS, UNKNOWN_DIAGNOSTIC_ATTRIBUTES, UNUSED_MACRO_RULES, UNUSED_MACROS, }; use rustc_session::parse::feature_err; @@ -43,7 +41,7 @@ use crate::imports::Import; use crate::{ BindingKey, DeriveData, Determinacy, Finalize, InvocationParent, MacroData, ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, ResolutionError, - Resolver, ScopeSet, Segment, ToNameBinding, Used, + Resolver, ScopeSet, Segment, Used, }; type Res = def::Res<NodeId>; @@ -80,7 +78,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). @@ -334,7 +332,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { fn record_macro_rule_usage(&mut self, id: NodeId, rule_i: usize) { if let Some(rules) = self.unused_macro_rules.get_mut(&id) { - rules.remove(&rule_i); + rules.remove(rule_i); } } @@ -351,13 +349,23 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { } for (&node_id, unused_arms) in self.unused_macro_rules.iter() { - for (&arm_i, &(ident, rule_span)) in unused_arms.to_sorted_stable_ord() { - self.lint_buffer.buffer_lint( - UNUSED_MACRO_RULES, - node_id, - rule_span, - BuiltinLintDiag::MacroRuleNeverUsed(arm_i, ident.name), - ); + if unused_arms.is_empty() { + continue; + } + 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; + }; + for arm_i in unused_arms.iter() { + if let Some((ident, rule_span)) = ext.get_unused_rule(arm_i) { + self.lint_buffer.buffer_lint( + UNUSED_MACRO_RULES, + node_id, + rule_span, + BuiltinLintDiag::MacroRuleNeverUsed(arm_i, ident.name), + ); + } } } } @@ -428,8 +436,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { .iter() .map(|(_, ident)| { let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper); - let binding = (res, Visibility::<DefId>::Public, ident.span, expn_id) - .to_name_binding(self.arenas); + let binding = self.arenas.new_pub_res_binding(res, ident.span, expn_id); (*ident, binding) }) .collect(); @@ -476,8 +483,18 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { self.proc_macros.push(self.local_def_id(id)) } - fn append_stripped_cfg_item(&mut self, parent_node: NodeId, ident: Ident, cfg: ast::MetaItem) { - self.stripped_cfg_items.push(StrippedCfgItem { parent_module: parent_node, ident, cfg }); + fn append_stripped_cfg_item( + &mut self, + parent_node: NodeId, + ident: Ident, + cfg: CfgEntry, + cfg_span: Span, + ) { + self.stripped_cfg_items.push(StrippedCfgItem { + parent_module: parent_node, + ident, + cfg: (cfg, cfg_span), + }); } fn registered_tools(&self) -> &RegisteredTools { @@ -522,6 +539,10 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { }); Ok(idents) } + + fn insert_impl_trait_name(&mut self, id: NodeId, name: Symbol) { + self.impl_trait_names.insert(id, name); + } } impl<'ra, 'tcx> Resolver<'ra, 'tcx> { @@ -676,7 +697,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ); self.tcx.sess.psess.buffer_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + UNKNOWN_DIAGNOSTIC_ATTRIBUTES, attribute.span(), node_id, BuiltinLintDiag::UnknownDiagnosticAttribute { span: attribute.span(), typo_name }, @@ -1118,7 +1139,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 { @@ -1134,7 +1155,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], @@ -1142,7 +1163,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { node_id: NodeId, edition: Edition, ) -> MacroData { - let (mut ext, mut rule_spans) = compile_declarative_macro( + let (mut ext, mut nrules) = compile_declarative_macro( self.tcx.sess, self.tcx.features(), macro_def, @@ -1159,13 +1180,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // The macro is a built-in, replace its expander function // while still taking everything else from the source code. ext.kind = builtin_ext_kind.clone(); - rule_spans = Vec::new(); + nrules = 0; } else { self.dcx().emit_err(errors::CannotFindBuiltinMacroWithName { span, ident }); } } - MacroData { ext: Arc::new(ext), rule_spans, macro_rules: macro_def.macro_rules } + MacroData { ext: Arc::new(ext), nrules, macro_rules: macro_def.macro_rules } } fn path_accessible( diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index fa839d2748d..24e15ded94f 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -7,6 +7,7 @@ use pulldown_cmark::{ }; use rustc_ast as ast; use rustc_ast::attr::AttributeExt; +use rustc_ast::join_path_syms; use rustc_ast::util::comments::beautify_doc_string; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::UnordSet; @@ -49,6 +50,9 @@ pub struct DocFragment { pub doc: Symbol, pub kind: DocFragmentKind, pub indent: usize, + /// Because we tamper with the spans context, this information cannot be correctly retrieved + /// later on. So instead, we compute it and store it here. + pub from_expansion: bool, } #[derive(Clone, Copy, Debug)] @@ -208,17 +212,18 @@ pub fn attrs_to_doc_fragments<'a, A: AttributeExt + Clone + 'a>( for (attr, item_id) in attrs { if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() { let doc = beautify_doc_string(doc_str, comment_kind); - let (span, kind) = if attr.is_doc_comment() { - (attr.span(), DocFragmentKind::SugaredDoc) + let (span, kind, from_expansion) = if attr.is_doc_comment() { + let span = attr.span(); + (span, DocFragmentKind::SugaredDoc, span.from_expansion()) } else { - ( - attr.value_span() - .map(|i| i.with_ctxt(attr.span().ctxt())) - .unwrap_or(attr.span()), - DocFragmentKind::RawDoc, - ) + let attr_span = attr.span(); + let (span, from_expansion) = match attr.value_span() { + Some(sp) => (sp.with_ctxt(attr_span.ctxt()), sp.from_expansion()), + None => (attr_span, attr_span.from_expansion()), + }; + (span, DocFragmentKind::RawDoc, from_expansion) }; - let fragment = DocFragment { span, doc, kind, item_id, indent: 0 }; + let fragment = DocFragment { span, doc, kind, item_id, indent: 0, from_expansion }; doc_fragments.push(fragment); } else if !doc_only { other_attrs.push(attr.clone()); @@ -255,7 +260,7 @@ pub fn main_body_opts() -> Options { | Options::ENABLE_SMART_PUNCTUATION } -fn strip_generics_from_path_segment(segment: Vec<char>) -> Result<String, MalformedGenerics> { +fn strip_generics_from_path_segment(segment: Vec<char>) -> Result<Symbol, MalformedGenerics> { let mut stripped_segment = String::new(); let mut param_depth = 0; @@ -280,7 +285,7 @@ fn strip_generics_from_path_segment(segment: Vec<char>) -> Result<String, Malfor } if param_depth == 0 { - Ok(stripped_segment) + Ok(Symbol::intern(&stripped_segment)) } else { // The segment has unbalanced angle brackets, e.g. `Vec<T` or `Vec<T>>` Err(MalformedGenerics::UnbalancedAngleBrackets) @@ -342,9 +347,8 @@ pub fn strip_generics_from_path(path_str: &str) -> Result<Box<str>, MalformedGen debug!("path_str: {path_str:?}\nstripped segments: {stripped_segments:?}"); - let stripped_path = stripped_segments.join("::"); - - if !stripped_path.is_empty() { + if !stripped_segments.is_empty() { + let stripped_path = join_path_syms(stripped_segments); Ok(stripped_path.into()) } else { Err(MalformedGenerics::MissingType) @@ -356,7 +360,12 @@ pub fn strip_generics_from_path(path_str: &str) -> Result<Box<str>, MalformedGen /// If there are no doc-comments, return true. /// FIXME(#78591): Support both inner and outer attributes on the same item. pub fn inner_docs(attrs: &[impl AttributeExt]) -> bool { - attrs.iter().find(|a| a.doc_str().is_some()).is_none_or(|a| a.style() == ast::AttrStyle::Inner) + for attr in attrs { + if let Some(attr_style) = attr.doc_resolution_scope() { + return attr_style == ast::AttrStyle::Inner; + } + } + true } /// Has `#[rustc_doc_primitive]` or `#[doc(keyword)]`. @@ -500,17 +509,26 @@ fn collect_link_data<'input, F: BrokenLinkCallback<'input>>( display_text.map(String::into_boxed_str) } -/// Returns a span encompassing all the document fragments. -pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> { - if fragments.is_empty() { - return None; - } - let start = fragments[0].span; - if start == DUMMY_SP { +/// Returns a tuple containing a span encompassing all the document fragments and a boolean that is +/// `true` if any of the fragments are from a macro expansion. +pub fn span_of_fragments_with_expansion(fragments: &[DocFragment]) -> Option<(Span, bool)> { + let (first_fragment, last_fragment) = match fragments { + [] => return None, + [first, .., last] => (first, last), + [first] => (first, first), + }; + if first_fragment.span == DUMMY_SP { return None; } - let end = fragments.last().expect("no doc strings provided").span; - Some(start.to(end)) + Some(( + first_fragment.span.to(last_fragment.span), + fragments.iter().any(|frag| frag.from_expansion), + )) +} + +/// Returns a span encompassing all the document fragments. +pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> { + span_of_fragments_with_expansion(fragments).map(|(sp, _)| sp) } /// Attempts to match a range of bytes from parsed markdown to a `Span` in the source code. @@ -524,18 +542,22 @@ pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> { /// This method will return `Some` only if one of the following is true: /// /// - The doc is made entirely from sugared doc comments, which cannot contain escapes -/// - The doc is entirely from a single doc fragment with a string literal exactly equal to `markdown`. +/// - The doc is entirely from a single doc fragment with a string literal exactly equal to +/// `markdown`. /// - The doc comes from `include_str!` -/// - The doc includes exactly one substring matching `markdown[md_range]` which is contained in a single doc fragment. +/// - The doc includes exactly one substring matching `markdown[md_range]` which is contained in a +/// single doc fragment. +/// +/// This function is defined in the compiler so it can be used by both `rustdoc` and `clippy`. /// -/// This function is defined in the compiler so it can be used by -/// both `rustdoc` and `clippy`. +/// It returns a tuple containing a span encompassing all the document fragments and a boolean that +/// is `true` if any of the *matched* fragments are from a macro expansion. pub fn source_span_for_markdown_range( tcx: TyCtxt<'_>, markdown: &str, md_range: &Range<usize>, fragments: &[DocFragment], -) -> Option<Span> { +) -> Option<(Span, bool)> { let map = tcx.sess.source_map(); source_span_for_markdown_range_inner(map, markdown, md_range, fragments) } @@ -546,7 +568,7 @@ pub fn source_span_for_markdown_range_inner( markdown: &str, md_range: &Range<usize>, fragments: &[DocFragment], -) -> Option<Span> { +) -> Option<(Span, bool)> { use rustc_span::BytePos; if let &[fragment] = &fragments @@ -557,11 +579,14 @@ pub fn source_span_for_markdown_range_inner( && let Ok(md_range_hi) = u32::try_from(md_range.end) { // Single fragment with string that contains same bytes as doc. - return Some(Span::new( - fragment.span.lo() + rustc_span::BytePos(md_range_lo), - fragment.span.lo() + rustc_span::BytePos(md_range_hi), - fragment.span.ctxt(), - fragment.span.parent(), + return Some(( + Span::new( + fragment.span.lo() + rustc_span::BytePos(md_range_lo), + fragment.span.lo() + rustc_span::BytePos(md_range_hi), + fragment.span.ctxt(), + fragment.span.parent(), + ), + fragment.from_expansion, )); } @@ -593,19 +618,21 @@ pub fn source_span_for_markdown_range_inner( { match_data = Some((i, match_start)); } else { - // Heirustic produced ambiguity, return nothing. + // Heuristic produced ambiguity, return nothing. return None; } } } if let Some((i, match_start)) = match_data { - let sp = fragments[i].span; + let fragment = &fragments[i]; + let sp = fragment.span; // we need to calculate the span start, - // then use that in our calulations for the span end + // then use that in our calculations for the span end let lo = sp.lo() + BytePos(match_start as u32); - return Some( + return Some(( sp.with_lo(lo).with_hi(lo + BytePos((md_range.end - md_range.start) as u32)), - ); + fragment.from_expansion, + )); } return None; } @@ -659,8 +686,13 @@ pub fn source_span_for_markdown_range_inner( } } - Some(span_of_fragments(fragments)?.from_inner(InnerSpan::new( + let (span, _) = span_of_fragments_with_expansion(fragments)?; + let src_span = span.from_inner(InnerSpan::new( md_range.start + start_bytes, md_range.end + start_bytes + end_bytes, - ))) + )); + Some(( + src_span, + fragments.iter().any(|frag| frag.span.overlaps(src_span) && frag.from_expansion), + )) } diff --git a/compiler/rustc_resolve/src/rustdoc/tests.rs b/compiler/rustc_resolve/src/rustdoc/tests.rs index 221ac907e7c..6a98ae06630 100644 --- a/compiler/rustc_resolve/src/rustdoc/tests.rs +++ b/compiler/rustc_resolve/src/rustdoc/tests.rs @@ -10,7 +10,7 @@ use super::{DocFragment, DocFragmentKind, source_span_for_markdown_range_inner}; fn single_backtick() { let sm = SourceMap::new(FilePathMapping::empty()); sm.new_source_file(PathBuf::from("foo.rs").into(), r#"#[doc = "`"] fn foo() {}"#.to_string()); - let span = source_span_for_markdown_range_inner( + let (span, _) = source_span_for_markdown_range_inner( &sm, "`", &(0..1), @@ -20,6 +20,7 @@ fn single_backtick() { kind: DocFragmentKind::RawDoc, doc: sym::empty, // unused placeholder indent: 0, + from_expansion: false, }], ) .unwrap(); @@ -32,7 +33,7 @@ fn utf8() { // regression test for https://github.com/rust-lang/rust/issues/141665 let sm = SourceMap::new(FilePathMapping::empty()); sm.new_source_file(PathBuf::from("foo.rs").into(), r#"#[doc = "⚠"] fn foo() {}"#.to_string()); - let span = source_span_for_markdown_range_inner( + let (span, _) = source_span_for_markdown_range_inner( &sm, "⚠", &(0..3), @@ -42,6 +43,7 @@ fn utf8() { kind: DocFragmentKind::RawDoc, doc: sym::empty, // unused placeholder indent: 0, + from_expansion: false, }], ) .unwrap(); | 
