diff options
Diffstat (limited to 'compiler/rustc_resolve')
-rw-r--r-- | compiler/rustc_resolve/messages.ftl (renamed from compiler/rustc_resolve/locales/en-US.ftl) | 16 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/build_reduced_graph.rs | 156 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/check_unused.rs | 44 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/def_collector.rs | 4 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/diagnostics.rs | 84 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/effective_visibilities.rs | 84 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/errors.rs | 36 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/ident.rs | 55 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/imports.rs | 133 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/late.rs | 76 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/late/diagnostics.rs | 204 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/lib.rs | 136 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/macros.rs | 52 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/rustdoc.rs | 36 |
14 files changed, 687 insertions, 429 deletions
diff --git a/compiler/rustc_resolve/locales/en-US.ftl b/compiler/rustc_resolve/messages.ftl index 817bb83ed..01f002c94 100644 --- a/compiler/rustc_resolve/locales/en-US.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -42,7 +42,7 @@ resolve_try_adding_local_generic_param_on_method = try adding a local generic parameter in this method instead resolve_help_try_using_local_generic_param = - try using a local generic paramter instead + try using a local generic parameter instead resolve_name_is_already_used_as_generic_parameter = the name `{$name}` is already used for a generic parameter in this item's generic parameters @@ -207,5 +207,19 @@ resolve_expected_found = resolve_indeterminate = cannot determine resolution for the visibility +resolve_tool_module_imported = + cannot use a tool module through an import + .note = the tool module imported here + resolve_module_only = visibility must resolve to a module + +resolve_macro_expected_found = + expected {$expected}, found {$found} `{$macro_path}` + +resolve_remove_surrounding_derive = + remove from the surrounding `derive()` + +resolve_add_as_non_derive = + add as non-Derive macro + `#[{$macro_path}]` diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index b1e023f2c..ff0f1f559 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -25,12 +25,9 @@ use rustc_expand::expand::AstFragment; use rustc_hir::def::{self, *}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_metadata::creader::LoadedMacro; -use rustc_middle::bug; use rustc_middle::metadata::ModChild; -use rustc_middle::ty::{self, DefIdTree}; -use rustc_session::cstore::CrateStore; +use rustc_middle::{bug, ty}; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind}; -use rustc_span::source_map::respan; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; @@ -99,7 +96,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { loop { match self.get_module(def_id) { Some(module) => return module, - None => def_id = self.parent(def_id), + None => def_id = self.tcx.parent(def_id), } } } @@ -117,35 +114,28 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } if !def_id.is_local() { - let def_kind = self.cstore().def_kind(def_id); - match def_kind { - DefKind::Mod | DefKind::Enum | DefKind::Trait => { - let def_key = self.cstore().def_key(def_id); - let parent = def_key.parent.map(|index| { - self.get_nearest_non_block_module(DefId { index, krate: def_id.krate }) - }); - let name = if let Some(cnum) = def_id.as_crate_root() { - self.cstore().crate_name(cnum) - } else { - def_key.disambiguated_data.data.get_opt_name().expect("module without name") - }; - - let expn_id = self.cstore().module_expansion_untracked(def_id, &self.tcx.sess); - let span = self.cstore().get_span_untracked(def_id, &self.tcx.sess); - Some(self.new_module( - parent, - ModuleKind::Def(def_kind, def_id, name), - expn_id, - span, - // FIXME: Account for `#[no_implicit_prelude]` attributes. - parent.map_or(false, |module| module.no_implicit_prelude), - )) - } - _ => None, + // 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 { + let parent = self + .tcx + .opt_parent(def_id) + .map(|parent_id| self.get_nearest_non_block_module(parent_id)); + // Query `expn_that_defined` is not used because + // hashing spans in its result is expensive. + let expn_id = self.cstore().expn_that_defined_untracked(def_id, &self.tcx.sess); + return Some(self.new_module( + parent, + ModuleKind::Def(def_kind, def_id, self.tcx.item_name(def_id)), + expn_id, + self.def_span(def_id), + // FIXME: Account for `#[no_implicit_prelude]` attributes. + parent.map_or(false, |module| module.no_implicit_prelude), + )); } - } else { - None } + + None } pub(crate) fn expn_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> { @@ -207,6 +197,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } pub(crate) fn build_reduced_graph_external(&mut self, module: Module<'a>) { + // Query `module_children` is not used because hashing spans in its result is expensive. let children = Vec::from_iter(self.cstore().module_children_untracked(module.def_id(), self.tcx.sess)); for child in children { @@ -329,13 +320,13 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } } - fn insert_field_names_local(&mut self, def_id: DefId, vdata: &ast::VariantData) { - let field_names = vdata - .fields() - .iter() - .map(|field| respan(field.span, field.ident.map_or(kw::Empty, |ident| ident.name))) - .collect(); - self.r.field_names.insert(def_id, field_names); + fn insert_field_def_ids(&mut self, def_id: LocalDefId, vdata: &ast::VariantData) { + if vdata.fields().iter().any(|field| field.is_placeholder) { + // The fields are not expanded yet. + return; + } + let def_ids = vdata.fields().iter().map(|field| self.r.local_def_id(field.id).to_def_id()); + self.r.field_def_ids.insert(def_id, self.r.tcx.arena.alloc_from_iter(def_ids)); } fn insert_field_visibilities_local(&mut self, def_id: DefId, vdata: &ast::VariantData) { @@ -347,12 +338,6 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.r.field_visibility_spans.insert(def_id, field_vis); } - fn insert_field_names_extern(&mut self, def_id: DefId) { - let field_names = - self.r.cstore().struct_field_names_untracked(def_id, self.r.tcx.sess).collect(); - self.r.field_names.insert(def_id, field_names); - } - fn block_needs_anonymous_module(&mut self, block: &Block) -> bool { // If any statements are items, we need to create an anonymous module block @@ -579,7 +564,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } ast::UseTreeKind::Glob => { let kind = ImportKind::Glob { - is_prelude: self.r.tcx.sess.contains_name(&item.attrs, sym::prelude_import), + is_prelude: attr::contains_name(&item.attrs, sym::prelude_import), max_vis: Cell::new(None), id, }; @@ -694,7 +679,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { expansion.to_expn_id(), item.span, parent.no_implicit_prelude - || self.r.tcx.sess.contains_name(&item.attrs, sym::no_implicit_prelude), + || attr::contains_name(&item.attrs, sym::no_implicit_prelude), ); self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); @@ -703,8 +688,8 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } // These items live in the value namespace. - ItemKind::Static(_, mt, _) => { - let res = Res::Def(DefKind::Static(mt), def_id); + ItemKind::Static(box ast::StaticItem { mutability, .. }) => { + let res = Res::Def(DefKind::Static(mutability), def_id); self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion)); } ItemKind::Const(..) => { @@ -750,7 +735,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); // Record field names for error reporting. - self.insert_field_names_local(def_id, vdata); + self.insert_field_def_ids(local_def_id, vdata); self.insert_field_visibilities_local(def_id, vdata); // If this is a tuple or unit struct, define a name @@ -759,7 +744,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { // If the structure is marked as non_exhaustive then lower the visibility // to within the crate. let mut ctor_vis = if vis.is_public() - && self.r.tcx.sess.contains_name(&item.attrs, sym::non_exhaustive) + && attr::contains_name(&item.attrs, sym::non_exhaustive) { ty::Visibility::Restricted(CRATE_DEF_ID) } else { @@ -775,7 +760,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { let field_vis = self .try_resolve_visibility(&field.vis, false) .unwrap_or(ty::Visibility::Public); - if ctor_vis.is_at_least(field_vis, &*self.r) { + if ctor_vis.is_at_least(field_vis, self.r.tcx) { ctor_vis = field_vis; } ret_fields.push(field_vis.to_def_id()); @@ -790,7 +775,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.r .struct_constructors - .insert(def_id, (ctor_res, ctor_vis.to_def_id(), ret_fields)); + .insert(local_def_id, (ctor_res, ctor_vis.to_def_id(), ret_fields)); } } @@ -799,7 +784,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); // Record field names for error reporting. - self.insert_field_names_local(def_id, vdata); + self.insert_field_def_ids(local_def_id, vdata); self.insert_field_visibilities_local(def_id, vdata); } @@ -946,7 +931,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { /// Builds the reduced graph for a single item in an external crate. fn build_reduced_graph_for_external_crate_res(&mut self, child: ModChild) { let parent = self.parent_scope.module; - let ModChild { ident, res, vis, span, macro_rules } = child; + let ModChild { ident, res, vis, span, .. } = child; let res = res.expect_non_local(); let expansion = self.parent_scope.expansion; // Record primary definitions. @@ -979,9 +964,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { _, ) => self.r.define(parent, ident, ValueNS, (res, vis, span, expansion)), Res::Def(DefKind::Macro(..), _) | Res::NonMacroAttr(..) => { - if !macro_rules { - self.r.define(parent, ident, MacroNS, (res, vis, span, expansion)) - } + self.r.define(parent, ident, MacroNS, (res, vis, span, expansion)) } Res::Def( DefKind::TyParam @@ -1005,32 +988,6 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { | Res::SelfCtor(..) | Res::Err => bug!("unexpected resolution: {:?}", res), } - // Record some extra data for better diagnostics. - match res { - Res::Def(DefKind::Struct, def_id) => { - let cstore = self.r.cstore(); - if let Some((ctor_kind, ctor_def_id)) = cstore.ctor_untracked(def_id) { - let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id); - let ctor_vis = cstore.visibility_untracked(ctor_def_id); - let field_visibilities = - cstore.struct_field_visibilities_untracked(def_id).collect(); - drop(cstore); - self.r - .struct_constructors - .insert(def_id, (ctor_res, ctor_vis, field_visibilities)); - } else { - drop(cstore); - } - self.insert_field_names_extern(def_id) - } - Res::Def(DefKind::Union, def_id) => self.insert_field_names_extern(def_id), - Res::Def(DefKind::AssocFn, def_id) => { - if self.r.cstore().fn_has_self_parameter_untracked(def_id, self.r.tcx.sess) { - self.r.has_self.insert(def_id); - } - } - _ => {} - } } fn add_macro_use_binding( @@ -1203,12 +1160,11 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } fn proc_macro_stub(&self, item: &ast::Item) -> Option<(MacroKind, Ident, Span)> { - if self.r.tcx.sess.contains_name(&item.attrs, sym::proc_macro) { + if attr::contains_name(&item.attrs, sym::proc_macro) { return Some((MacroKind::Bang, item.ident, item.span)); - } else if self.r.tcx.sess.contains_name(&item.attrs, sym::proc_macro_attribute) { + } else if attr::contains_name(&item.attrs, sym::proc_macro_attribute) { return Some((MacroKind::Attr, item.ident, item.span)); - } else if let Some(attr) = self.r.tcx.sess.find_by_name(&item.attrs, sym::proc_macro_derive) - { + } else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) { if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) { if let Some(ident) = nested_meta.ident() { return Some((MacroKind::Derive, ident, ident.span)); @@ -1263,7 +1219,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { if macro_rules { let ident = ident.normalize_to_macros_2_0(); self.r.macro_names.insert(ident); - let is_macro_export = self.r.tcx.sess.contains_name(&item.attrs, sym::macro_export); + let is_macro_export = attr::contains_name(&item.attrs, sym::macro_export); let vis = if is_macro_export { ty::Visibility::Public } else { @@ -1414,10 +1370,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { if !(ctxt == AssocCtxt::Impl && matches!(item.vis.kind, ast::VisibilityKind::Inherited) - && self - .r - .trait_impl_items - .contains(&ty::DefIdTree::local_parent(&*self.r, local_def_id))) + && self.r.trait_impl_items.contains(&self.r.tcx.local_parent(local_def_id))) { // Trait impl item visibility is inherited from its trait when not specified // explicitly. In that case we cannot determine it here in early resolve, @@ -1430,7 +1383,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { AssocItemKind::Const(..) => (DefKind::AssocConst, ValueNS), AssocItemKind::Fn(box Fn { ref sig, .. }) => { if sig.decl.has_self() { - self.r.has_self.insert(def_id); + self.r.has_self.insert(local_def_id); } (DefKind::AssocFn, ValueNS) } @@ -1526,13 +1479,12 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.r.visibilities.insert(def_id, vis); // If the variant is marked as non_exhaustive then lower the visibility to within the crate. - let ctor_vis = if vis.is_public() - && self.r.tcx.sess.contains_name(&variant.attrs, sym::non_exhaustive) - { - ty::Visibility::Restricted(CRATE_DEF_ID) - } else { - vis - }; + let ctor_vis = + if vis.is_public() && attr::contains_name(&variant.attrs, sym::non_exhaustive) { + ty::Visibility::Restricted(CRATE_DEF_ID) + } else { + vis + }; // Define a constructor name in the value namespace. if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(&variant.data) { @@ -1544,7 +1496,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { } // Record field names for error reporting. - self.insert_field_names_local(def_id.to_def_id(), &variant.data); + self.insert_field_def_ids(def_id, &variant.data); self.insert_field_visibilities_local(def_id.to_def_id(), &variant.data); visit::walk_variant(self, variant); diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index b2578e4c4..ae3fd0ede 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -32,9 +32,10 @@ use rustc_ast::visit::{self, Visitor}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::unord::UnordSet; use rustc_errors::{pluralize, MultiSpan}; +use rustc_hir::def::{DefKind, Res}; use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES, UNUSED_IMPORTS}; use rustc_session::lint::BuiltinLintDiagnostics; -use rustc_span::symbol::Ident; +use rustc_span::symbol::{kw, Ident}; use rustc_span::{Span, DUMMY_SP}; struct UnusedImport<'a> { @@ -58,6 +59,7 @@ struct UnusedImportCheckVisitor<'a, 'b, 'tcx> { base_use_tree: Option<&'a ast::UseTree>, base_id: ast::NodeId, item_span: Span, + base_use_is_pub: bool, } struct ExternCrateToLint { @@ -110,6 +112,35 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> { unused: Default::default(), }) } + + fn check_import_as_underscore(&mut self, item: &ast::UseTree, id: ast::NodeId) { + match item.kind { + ast::UseTreeKind::Simple(Some(ident)) => { + if ident.name == kw::Underscore + && !self + .r + .import_res_map + .get(&id) + .map(|per_ns| { + per_ns.iter().filter_map(|res| res.as_ref()).any(|res| { + matches!(res, Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) + }) + }) + .unwrap_or(false) + { + self.unused_import(self.base_id).add(id); + } + } + ast::UseTreeKind::Nested(ref items) => self.check_imports_as_underscore(items), + _ => {} + } + } + + fn check_imports_as_underscore(&mut self, items: &[(ast::UseTree, ast::NodeId)]) { + for (item, id) in items { + self.check_import_as_underscore(item, *id); + } + } } impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> { @@ -119,7 +150,8 @@ impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> { // whether they're used or not. Also ignore imports with a dummy span // because this means that they were generated in some fashion by the // compiler and we don't need to consider them. - ast::ItemKind::Use(..) if item.vis.kind.is_pub() || item.span.is_dummy() => return, + ast::ItemKind::Use(..) if item.span.is_dummy() => return, + ast::ItemKind::Use(..) => self.base_use_is_pub = item.vis.kind.is_pub(), ast::ItemKind::ExternCrate(orig_name) => { self.extern_crate_items.push(ExternCrateToLint { id: item.id, @@ -146,6 +178,11 @@ impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> { self.base_use_tree = Some(use_tree); } + if self.base_use_is_pub { + self.check_import_as_underscore(use_tree, id); + return; + } + if let ast::UseTreeKind::Nested(ref items) = use_tree.kind { if items.is_empty() { self.unused_import(self.base_id).add(id); @@ -300,6 +337,7 @@ impl Resolver<'_, '_> { base_use_tree: None, base_id: ast::DUMMY_NODE_ID, item_span: DUMMY_SP, + base_use_is_pub: false, }; visit::walk_crate(&mut visitor, krate); @@ -355,7 +393,7 @@ impl Resolver<'_, '_> { // If we are in the `--test` mode, suppress a help that adds the `#[cfg(test)]` // attribute; however, if not, suggest adding the attribute. There is no way to // retrieve attributes here because we do not have a `TyCtxt` yet. - let test_module_span = if tcx.sess.opts.test { + let test_module_span = if tcx.sess.is_test_crate() { None } else { let parent_module = visitor.r.get_nearest_non_block_module( diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index e7ff236f8..356d7f365 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -260,9 +260,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { Async::No => closure_def, } } - ExprKind::Async(_, async_id, _) => { - self.create_def(async_id, DefPathData::ClosureExpr, expr.span) - } + ExprKind::Async(_, _) => self.create_def(expr.id, DefPathData::ClosureExpr, expr.span), _ => self.parent_def, }; diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 7add59ac6..0c9d30608 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -12,10 +12,10 @@ use rustc_errors::{struct_span_err, SuggestionStyle}; use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS}; -use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; use rustc_hir::PrimTy; use rustc_middle::bug; -use rustc_middle::ty::{DefIdTree, TyCtxt}; +use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE; use rustc_session::lint::builtin::MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS; use rustc_session::lint::BuiltinLintDiagnostics; @@ -555,25 +555,22 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { return err; } Res::SelfTyAlias { alias_to: def_id, .. } => { - if let Some(impl_span) = self.opt_span(def_id) { - err.span_label( - reduce_impl_span_to_impl_keyword(sm, impl_span), - "`Self` type implicitly declared here, by this `impl`", - ); - } + err.span_label( + reduce_impl_span_to_impl_keyword(sm, self.def_span(def_id)), + "`Self` type implicitly declared here, by this `impl`", + ); err.span_label(span, "use a type here instead"); return err; } Res::Def(DefKind::TyParam, def_id) => { - if let Some(span) = self.opt_span(def_id) { - err.span_label(span, "type parameter from outer function"); - } + err.span_label(self.def_span(def_id), "type parameter from outer function"); def_id } Res::Def(DefKind::ConstParam, def_id) => { - if let Some(span) = self.opt_span(def_id) { - err.span_label(span, "const parameter from outer function"); - } + err.span_label( + self.def_span(def_id), + "const parameter from outer function", + ); def_id } _ => { @@ -589,7 +586,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Try to retrieve the span of the function signature and generate a new // message with a local type or const parameter. let sugg_msg = "try using a local generic parameter instead"; - let name = self.opt_name(def_id).unwrap_or(sym::T); + let name = self.tcx.item_name(def_id); let (span, snippet) = if span.is_empty() { let snippet = format!("<{}>", name); (span, snippet) @@ -1197,7 +1194,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { segms.push(ast::PathSegment::from_ident(ident)); let path = Path { span: name_binding.span, segments: segms, tokens: None }; let did = match res { - Res::Def(DefKind::Ctor(..), did) => this.opt_parent(did), + Res::Def(DefKind::Ctor(..), did) => this.tcx.opt_parent(did), _ => res.opt_def_id(), }; @@ -1216,15 +1213,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // a note about editions let note = if let Some(did) = did { let requires_note = !did.is_local() - && this.cstore().item_attrs_untracked(did, this.tcx.sess).any( + && this.tcx.get_attrs(did, sym::rustc_diagnostic_item).any( |attr| { - if attr.has_name(sym::rustc_diagnostic_item) { - [sym::TryInto, sym::TryFrom, sym::FromIterator] - .map(|x| Some(x)) - .contains(&attr.value_str()) - } else { - false - } + [sym::TryInto, sym::TryFrom, sym::FromIterator] + .map(|x| Some(x)) + .contains(&attr.value_str()) }, ); @@ -1373,8 +1366,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } if ident.name == kw::Default && let ModuleKind::Def(DefKind::Enum, def_id, _) = parent_scope.module.kind - && let Some(span) = self.opt_span(def_id) { + let span = self.def_span(def_id); let source_map = self.tcx.sess.source_map(); let head_span = source_map.guess_head_span(span); if let Ok(head) = source_map.span_to_snippet(head_span) { @@ -1450,11 +1443,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Some(suggestion) if suggestion.candidate == kw::Underscore => return false, Some(suggestion) => suggestion, }; - let def_span = suggestion.res.opt_def_id().and_then(|def_id| match def_id.krate { - LOCAL_CRATE => self.opt_span(def_id), - _ => Some(self.cstore().get_span_untracked(def_id, self.tcx.sess)), - }); - if let Some(def_span) = def_span { + if let Some(def_span) = suggestion.res.opt_def_id().map(|def_id| self.def_span(def_id)) { if span.overlaps(def_span) { // Don't suggest typo suggestion for itself like in the following: // error[E0423]: expected function, tuple struct or tuple variant, found struct `X` @@ -1591,9 +1580,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ctor_def_id, )) = binding.kind { - let def_id = self.parent(ctor_def_id); - let fields = self.field_names.get(&def_id)?; - return fields.iter().map(|name| name.span).reduce(Span::to); // None for `struct Foo()` + let def_id = self.tcx.parent(ctor_def_id); + return self + .field_def_ids(def_id)? + .iter() + .map(|&field_id| self.def_span(field_id)) + .reduce(Span::to); // None for `struct Foo()` } None } @@ -1615,7 +1607,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let mut err = struct_span_err!(self.tcx.sess, ident.span, E0603, "{} `{}` is private", descr, ident); err.span_label(ident.span, &format!("private {}", descr)); - if let Some(span) = ctor_fields_span { + + let mut non_exhaustive = None; + // If an ADT is foreign and marked as `non_exhaustive`, then that's + // probably why we have the privacy error. + // 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) + { + non_exhaustive = Some(attr.span); + } else if let Some(span) = ctor_fields_span { err.span_label(span, "a constructor is private if any of the fields is private"); if let Res::Def(_, d) = res && let Some(fields) = self.field_visibility_spans.get(&d) { err.multipart_suggestion_verbose( @@ -1664,6 +1666,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if !first && binding.vis.is_public() { note_span.push_span_label(def_span, "consider importing it directly"); } + // Final step in the import chain, point out if the ADT is `non_exhaustive` + // which is probably why this privacy violation occurred. + if next_binding.is_none() && let Some(span) = non_exhaustive { + note_span.push_span_label( + span, + format!("cannot be constructed because it is `#[non_exhaustive]`"), + ); + } err.span_note(note_span, &msg); } @@ -1677,8 +1687,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ) -> Option<Symbol> { let mut candidates = self .extern_prelude - .iter() - .map(|(ident, _)| ident.name) + .keys() + .map(|ident| ident.name) .chain( self.module_map .iter() @@ -2015,7 +2025,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // 1) some consistent ordering for emitted diagnostics, and // 2) `std` suggestions before `core` suggestions. let mut extern_crate_names = - self.extern_prelude.iter().map(|(ident, _)| ident.name).collect::<Vec<_>>(); + self.extern_prelude.keys().map(|ident| ident.name).collect::<Vec<_>>(); extern_crate_names.sort_by(|a, b| b.as_str().partial_cmp(a.as_str()).unwrap()); for name in extern_crate_names.into_iter() { diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 7bd90d7e3..bed579f6b 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -4,12 +4,13 @@ use rustc_ast::visit; use rustc_ast::visit::Visitor; use rustc_ast::Crate; use rustc_ast::EnumDef; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::intern::Interned; use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_middle::middle::privacy::Level; use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility}; -use rustc_middle::ty::{DefIdTree, Visibility}; +use rustc_middle::ty::Visibility; use std::mem; type ImportId<'a> = Interned<'a, NameBinding<'a>>; @@ -60,7 +61,7 @@ impl Resolver<'_, '_> { // For mod items `nearest_normal_mod` returns its argument, but we actually need its parent. let normal_mod_id = self.nearest_normal_mod(def_id); if normal_mod_id == def_id { - self.opt_local_parent(def_id).map_or(Visibility::Public, Visibility::Restricted) + Visibility::Restricted(self.tcx.local_parent(def_id)) } else { Visibility::Restricted(normal_mod_id) } @@ -70,21 +71,20 @@ impl Resolver<'_, '_> { impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { /// Fills the `Resolver::effective_visibilities` table with public & exported items /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we - /// need access to a TyCtxt for that. + /// need access to a TyCtxt for that. Returns the set of ambiguous re-exports. pub(crate) fn compute_effective_visibilities<'c>( r: &'r mut Resolver<'a, 'tcx>, krate: &'c Crate, - ) { + ) -> FxHashSet<Interned<'a, NameBinding<'a>>> { let mut visitor = EffectiveVisibilitiesVisitor { r, def_effective_visibilities: Default::default(), import_effective_visibilities: Default::default(), - current_private_vis: Visibility::Public, + current_private_vis: Visibility::Restricted(CRATE_DEF_ID), changed: false, }; - visitor.update(CRATE_DEF_ID, CRATE_DEF_ID); - visitor.current_private_vis = Visibility::Restricted(CRATE_DEF_ID); + visitor.def_effective_visibilities.update_root(); visitor.set_bindings_effective_visibilities(CRATE_DEF_ID); while visitor.changed { @@ -93,18 +93,26 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { } visitor.r.effective_visibilities = visitor.def_effective_visibilities; + let mut exported_ambiguities = FxHashSet::default(); + // Update visibilities for import def ids. These are not used during the // `EffectiveVisibilitiesVisitor` pass, because we have more detailed binding-based // information, but are used by later passes. Effective visibility of an import def id // is the maximum value among visibilities of bindings corresponding to that def id. for (binding, eff_vis) in visitor.import_effective_visibilities.iter() { let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() }; - if let Some(node_id) = import.id() { - r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx) + if !binding.is_ambiguity() { + if let Some(node_id) = import.id() { + r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx) + } + } else if binding.ambiguity.is_some() && eff_vis.is_public_at_level(Level::Reexported) { + exported_ambiguities.insert(*binding); } } info!("resolve::effective_visibilities: {:#?}", r.effective_visibilities); + + exported_ambiguities } /// Update effective visibilities of bindings in the given module, @@ -115,30 +123,38 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { let resolutions = self.r.resolutions(module); for (_, name_resolution) in resolutions.borrow().iter() { - if let Some(mut binding) = name_resolution.borrow().binding() && !binding.is_ambiguity() { + if let Some(mut binding) = name_resolution.borrow().binding() { // Set the given effective visibility level to `Level::Direct` and // sets the rest of the `use` chain to `Level::Reexported` until // we hit the actual exported item. + // + // If the binding is ambiguous, put the root ambiguity binding and all reexports + // leading to it into the table. They are used by the `ambiguous_glob_reexports` + // lint. For all bindings added to the table this way `is_ambiguity` returns true. let mut parent_id = ParentId::Def(module_id); while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind { let binding_id = ImportId::new_unchecked(binding); self.update_import(binding_id, parent_id); + if binding.ambiguity.is_some() { + // Stop at the root ambiguity, further bindings in the chain should not + // be reexported because the root ambiguity blocks any access to them. + // (Those further bindings are most likely not ambiguities themselves.) + break; + } + parent_id = ParentId::Import(binding_id); binding = nested_binding; } - if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) { + if binding.ambiguity.is_none() + && let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) { self.update_def(def_id, binding.vis.expect_local(), parent_id); } } } } - fn cheap_private_vis(&self, parent_id: ParentId<'_>) -> Option<Visibility> { - matches!(parent_id, ParentId::Def(_)).then_some(self.current_private_vis) - } - fn effective_vis_or_private(&mut self, parent_id: ParentId<'a>) -> EffectiveVisibility { // Private nodes are only added to the table for caching, they could be added or removed at // any moment without consequences, so we don't set `changed` to true when adding them. @@ -152,15 +168,39 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { } } + /// All effective visibilities for a node are larger or equal than private visibility + /// for that node (see `check_invariants` in middle/privacy.rs). + /// So if either parent or nominal visibility is the same as private visibility, then + /// `min(parent_vis, nominal_vis) <= private_vis`, and the update logic is guaranteed + /// to not update anything and we can skip it. + /// + /// We are checking this condition only if the correct value of private visibility is + /// cheaply available, otherwise it does't make sense performance-wise. + /// + /// `None` is returned if the update can be skipped, + /// and cheap private visibility is returned otherwise. + fn may_update( + &self, + nominal_vis: Visibility, + parent_id: ParentId<'_>, + ) -> Option<Option<Visibility>> { + match parent_id { + ParentId::Def(def_id) => (nominal_vis != self.current_private_vis + && self.r.visibilities[&def_id] != self.current_private_vis) + .then_some(Some(self.current_private_vis)), + ParentId::Import(_) => Some(None), + } + } + fn update_import(&mut self, binding: ImportId<'a>, parent_id: ParentId<'a>) { let nominal_vis = binding.vis.expect_local(); - let private_vis = self.cheap_private_vis(parent_id); + let Some(cheap_private_vis) = self.may_update(nominal_vis, parent_id) else { return }; let inherited_eff_vis = self.effective_vis_or_private(parent_id); let tcx = self.r.tcx; self.changed |= self.import_effective_visibilities.update( binding, nominal_vis, - || private_vis.unwrap_or_else(|| self.r.private_vis_import(binding)), + || cheap_private_vis.unwrap_or_else(|| self.r.private_vis_import(binding)), inherited_eff_vis, parent_id.level(), tcx, @@ -168,20 +208,20 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { } fn update_def(&mut self, def_id: LocalDefId, nominal_vis: Visibility, parent_id: ParentId<'a>) { - let private_vis = self.cheap_private_vis(parent_id); + let Some(cheap_private_vis) = self.may_update(nominal_vis, parent_id) else { return }; let inherited_eff_vis = self.effective_vis_or_private(parent_id); let tcx = self.r.tcx; self.changed |= self.def_effective_visibilities.update( def_id, nominal_vis, - || private_vis.unwrap_or_else(|| self.r.private_vis_def(def_id)), + || cheap_private_vis.unwrap_or_else(|| self.r.private_vis_def(def_id)), inherited_eff_vis, parent_id.level(), tcx, ); } - fn update(&mut self, def_id: LocalDefId, parent_id: LocalDefId) { + fn update_field(&mut self, def_id: LocalDefId, parent_id: LocalDefId) { self.update_def(def_id, self.r.visibilities[&def_id], ParentId::Def(parent_id)); } } @@ -213,14 +253,14 @@ impl<'r, 'ast, 'tcx> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r, 't for variant in variants { let variant_def_id = self.r.local_def_id(variant.id); for field in variant.data.fields() { - self.update(self.r.local_def_id(field.id), variant_def_id); + self.update_field(self.r.local_def_id(field.id), variant_def_id); } } } ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => { for field in def.fields() { - self.update(self.r.local_def_id(field.id), def_id); + self.update_field(self.r.local_def_id(field.id), def_id); } } diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 867363f42..afa796cb6 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -470,5 +470,41 @@ pub(crate) struct ExpectedFound { pub(crate) struct Indeterminate(#[primary_span] pub(crate) Span); #[derive(Diagnostic)] +#[diag(resolve_tool_module_imported)] +pub(crate) struct ToolModuleImported { + #[primary_span] + pub(crate) span: Span, + #[note] + pub(crate) import: Span, +} + +#[derive(Diagnostic)] #[diag(resolve_module_only)] pub(crate) struct ModuleOnly(#[primary_span] pub(crate) Span); + +#[derive(Diagnostic, Default)] +#[diag(resolve_macro_expected_found)] +pub(crate) struct MacroExpectedFound<'a> { + #[primary_span] + pub(crate) span: Span, + pub(crate) found: &'a str, + pub(crate) expected: &'a str, + pub(crate) macro_path: &'a str, + #[subdiagnostic] + pub(crate) remove_surrounding_derive: Option<RemoveSurroundingDerive>, + #[subdiagnostic] + pub(crate) add_as_non_derive: Option<AddAsNonDerive<'a>>, +} + +#[derive(Subdiagnostic)] +#[help(resolve_remove_surrounding_derive)] +pub(crate) struct RemoveSurroundingDerive { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Subdiagnostic)] +#[help(resolve_add_as_non_derive)] +pub(crate) struct AddAsNonDerive<'a> { + pub(crate) macro_path: &'a str, +} diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 52f0b65fa..5a56d7b99 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -17,7 +17,7 @@ use crate::late::{ ConstantHasGenerics, ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind, }; use crate::macros::{sub_namespace_match, MacroRulesScope}; -use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize}; +use crate::{errors, AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize}; use crate::{Import, ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot}; use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res}; use crate::{ResolutionError, Resolver, Scope, ScopeSet, Segment, ToNameBinding, Weak}; @@ -389,7 +389,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - assert!(force || !finalize.is_some()); // `finalize` implies `force` + assert!(force || finalize.is_none()); // `finalize` implies `force` // Make sure `self`, `super` etc produce an error when passed to here. if orig_ident.is_path_segment_keyword() { @@ -869,17 +869,19 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let resolution = self.resolution(module, key).try_borrow_mut().map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports. - if let Some(Finalize { path_span, report_private, .. }) = finalize { - // If the primary binding is unusable, search further and return the shadowed glob - // 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].into_iter().find_map( - |binding| match (binding, ignore_binding) { + // If the primary binding is unusable, search further and return the shadowed glob + // 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].into_iter().find_map(|binding| { + match (binding, ignore_binding) { (Some(binding), Some(ignored)) if ptr::eq(binding, ignored) => None, _ => binding, - }, - ); + } + }); + + if let Some(Finalize { path_span, report_private, .. }) = finalize { let Some(binding) = binding else { return Err((Determined, Weak::No)); }; @@ -927,15 +929,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| { - if let Some(ignored) = ignore_binding && ptr::eq(binding, ignored) { - return Err((Determined, Weak::No)); - } let usable = this.is_accessible_from(binding.vis, parent_scope.module); if usable { Ok(binding) } else { Err((Determined, Weak::No)) } }; // Items and single imports are not shadowable, if we have one, then it's determined. - if let Some(binding) = resolution.binding { + if let Some(binding) = binding { if !binding.is_glob_import() { return check_usable(self, binding); } @@ -952,6 +951,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if !self.is_accessible_from(import_vis, parent_scope.module) { continue; } + if let Some(ignored) = ignore_binding && + let NameBindingKind::Import { import, .. } = ignored.kind && + ptr::eq(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)); }; @@ -989,7 +996,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // and prohibit access to macro-expanded `macro_export` macros instead (unless restricted // shadowing is enabled, see `macro_expanded_macro_export_errors`). let unexpanded_macros = !module.unexpanded_invocations.borrow().is_empty(); - if let Some(binding) = resolution.binding { + if let Some(binding) = binding { if !unexpanded_macros || ns == MacroNS || restricted_shadowing { return check_usable(self, binding); } else { @@ -1357,7 +1364,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } }; - let is_last = i == path.len() - 1; + let is_last = i + 1 == path.len(); let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS }; let name = ident.name; @@ -1494,16 +1501,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if let Some(next_module) = binding.module() { module = Some(ModuleOrUniformRoot::Module(next_module)); record_segment_res(self, res); - } else if res == Res::ToolMod && i + 1 != path.len() { + } else if res == Res::ToolMod && !is_last && opt_ns.is_some() { if binding.is_import() { - self.tcx - .sess - .struct_span_err( - ident.span, - "cannot use a tool module through an import", - ) - .span_note(binding.span, "the tool module imported here") - .emit(); + self.tcx.sess.emit_err(errors::ToolModuleImported { + span: ident.span, + import: binding.span, + }); } let res = Res::NonMacroAttr(NonMacroAttrKind::Tool); return PathResult::NonModule(PartialRes::new(res)); diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 4dab0836d..3c22d51c3 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -17,14 +17,18 @@ use rustc_data_structures::intern::Interned; use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan}; use rustc_hir::def::{self, DefKind, PartialRes}; use rustc_middle::metadata::ModChild; +use rustc_middle::metadata::Reexport; use rustc_middle::span_bug; use rustc_middle::ty; -use rustc_session::lint::builtin::{PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS}; +use rustc_session::lint::builtin::{ + AMBIGUOUS_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS, +}; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::LocalExpnId; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::Span; +use smallvec::SmallVec; use std::cell::Cell; use std::{mem, ptr}; @@ -85,20 +89,28 @@ impl<'a> std::fmt::Debug for ImportKind<'a> { Single { ref source, ref target, + ref source_bindings, + ref target_bindings, ref type_ns_only, ref nested, ref id, - // Ignore the following to avoid an infinite loop while printing. - source_bindings: _, - target_bindings: _, } => 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!(".."))), + ) .field("type_ns_only", type_ns_only) .field("nested", nested) .field("id", id) - .finish_non_exhaustive(), + .finish(), Glob { ref is_prelude, ref max_vis, ref id } => f .debug_struct("Glob") .field("is_prelude", is_prelude) @@ -180,6 +192,17 @@ impl<'a> Import<'a> { ImportKind::MacroUse | ImportKind::MacroExport => None, } } + + fn simplify(&self, r: &Resolver<'_, '_>) -> Reexport { + let to_def_id = |id| r.local_def_id(id).to_def_id(); + match self.kind { + ImportKind::Single { id, .. } => Reexport::Single(to_def_id(id)), + ImportKind::Glob { id, .. } => Reexport::Glob(to_def_id(id)), + ImportKind::ExternCrate { id, .. } => Reexport::ExternCrate(to_def_id(id)), + ImportKind::MacroUse => Reexport::MacroUse, + ImportKind::MacroExport => Reexport::MacroExport, + } + } } /// Records information about the resolution of a name in a namespace of a module. @@ -245,7 +268,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { import: &'a Import<'a>, ) -> &'a NameBinding<'a> { let import_vis = import.expect_vis().to_def_id(); - let vis = if binding.vis.is_at_least(import_vis, self) + let vis = if binding.vis.is_at_least(import_vis, self.tcx) || pub_use_of_private_extern_crate_hack(import, binding) { import_vis @@ -255,7 +278,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if let ImportKind::Glob { ref max_vis, .. } = import.kind { if vis == import_vis - || max_vis.get().map_or(true, |max_vis| vis.is_at_least(max_vis, self)) + || max_vis.get().map_or(true, |max_vis| vis.is_at_least(max_vis, self.tcx)) { max_vis.set(Some(vis.expect_local())) } @@ -294,7 +317,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { old_binding, binding, )); - } else if !old_binding.vis.is_at_least(binding.vis, &*this) { + } 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); } @@ -415,13 +438,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// Resolves all imports for the crate. This method performs the fixed- /// point iteration. pub(crate) fn resolve_imports(&mut self) { - let mut prev_num_indeterminates = self.indeterminate_imports.len() + 1; - while self.indeterminate_imports.len() < prev_num_indeterminates { - prev_num_indeterminates = self.indeterminate_imports.len(); + let mut prev_indeterminate_count = usize::MAX; + let mut indeterminate_count = self.indeterminate_imports.len() * 3; + while indeterminate_count < prev_indeterminate_count { + prev_indeterminate_count = indeterminate_count; + indeterminate_count = 0; for import in mem::take(&mut self.indeterminate_imports) { - match self.resolve_import(&import) { - true => self.determined_imports.push(import), - false => self.indeterminate_imports.push(import), + let import_indeterminate_count = self.resolve_import(&import); + indeterminate_count += import_indeterminate_count; + match import_indeterminate_count { + 0 => self.determined_imports.push(import), + _ => self.indeterminate_imports.push(import), } } } @@ -498,6 +525,34 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } + pub(crate) fn check_reexport_ambiguities( + &mut self, + exported_ambiguities: FxHashSet<Interned<'a, NameBinding<'a>>>, + ) { + for module in self.arenas.local_modules().iter() { + module.for_each_child(self, |this, ident, ns, binding| { + if let NameBindingKind::Import { import, .. } = binding.kind + && let Some((amb_binding, _)) = binding.ambiguity + && binding.res() != Res::Err + && exported_ambiguities.contains(&Interned::new_unchecked(binding)) + { + this.lint_buffer.buffer_lint_with_diagnostic( + AMBIGUOUS_GLOB_REEXPORTS, + import.root_id, + import.root_span, + "ambiguous glob re-exports", + BuiltinLintDiagnostics::AmbiguousGlobReexports { + name: ident.to_string(), + namespace: ns.descr().to_string(), + first_reexport_span: import.root_span, + duplicate_reexport_span: amb_binding.span, + }, + ); + } + }); + } + } + fn throw_unresolved_import_error(&self, errors: Vec<(&Import<'_>, UnresolvedImportError)>) { if errors.is_empty() { return; @@ -573,9 +628,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { diag.emit(); } - /// Attempts to resolve the given import, returning true if its resolution is determined. - /// If successful, the resolved bindings are written into the module. - fn resolve_import(&mut self, import: &'a Import<'a>) -> bool { + /// Attempts to resolve the given import, returning: + /// - `0` means its resolution is determined. + /// - Other values mean that indeterminate exists under certain namespaces. + /// + /// Meanwhile, if resolve successful, the resolved bindings are written + /// into the module. + fn resolve_import(&mut self, import: &'a Import<'a>) -> usize { debug!( "(resolving import for module) resolving import `{}::...` in `{}`", Segment::names_to_string(&import.module_path), @@ -593,8 +652,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match path_res { PathResult::Module(module) => module, - PathResult::Indeterminate => return false, - PathResult::NonModule(..) | PathResult::Failed { .. } => return true, + PathResult::Indeterminate => return 3, + PathResult::NonModule(..) | PathResult::Failed { .. } => return 0, } }; @@ -610,12 +669,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } => (source, target, source_bindings, target_bindings, type_ns_only), ImportKind::Glob { .. } => { self.resolve_glob_import(import); - return true; + return 0; } _ => unreachable!(), }; - let mut indeterminate = false; + let mut indeterminate_count = 0; self.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { if let Err(Undetermined) = source_bindings[ns].get() { @@ -638,7 +697,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let parent = import.parent_scope.module; match source_bindings[ns].get() { - Err(Undetermined) => indeterminate = true, + Err(Undetermined) => indeterminate_count += 1, // Don't update the resolution, because it was never added. Err(Determined) if target.name == kw::Underscore => {} Ok(binding) if binding.is_importable() => { @@ -662,7 +721,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } }); - !indeterminate + indeterminate_count } /// Performs final import resolution, consistency checks and error reporting. @@ -786,7 +845,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } if !is_prelude && let Some(max_vis) = max_vis.get() - && !max_vis.is_at_least(import.expect_vis(), &*self) + && !max_vis.is_at_least(import.expect_vis(), self.tcx) { let msg = "glob import doesn't reexport anything because no candidate is public enough"; self.lint_buffer.buffer_lint(UNUSED_IMPORTS, id, import.span, msg); @@ -977,7 +1036,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let mut crate_private_reexport = false; self.per_ns(|this, ns| { if let Ok(binding) = source_bindings[ns].get() { - if !binding.vis.is_at_least(import.expect_vis(), &*this) { + if !binding.vis.is_at_least(import.expect_vis(), this.tcx) { reexport_error = Some((ns, binding)); if let ty::Visibility::Restricted(binding_def_id) = binding.vis { if binding_def_id.is_top_level_module() { @@ -1202,24 +1261,38 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { *module.globs.borrow_mut() = Vec::new(); if let Some(def_id) = module.opt_def_id() { + let mut non_reexports = Vec::new(); let mut reexports = Vec::new(); module.for_each_child(self, |this, ident, _, binding| { - if let Some(res) = this.is_reexport(binding) { + let res = binding.res().expect_non_local(); + if !binding.is_import() { + non_reexports.push(res.def_id().expect_local()); + } else if res != def::Res::Err && !binding.is_ambiguity() { + let mut reexport_chain = SmallVec::new(); + let mut next_binding = binding; + while let NameBindingKind::Import { binding, import, .. } = next_binding.kind { + reexport_chain.push(import.simplify(this)); + next_binding = binding; + } + reexports.push(ModChild { ident, res, vis: binding.vis, span: binding.span, - macro_rules: false, + reexport_chain, }); } }); + // Should be fine because this code is only called for local modules. + let def_id = def_id.expect_local(); + if !non_reexports.is_empty() { + self.module_children_non_reexports.insert(def_id, non_reexports); + } if !reexports.is_empty() { - // Call to `expect_local` should be fine because current - // code is only called for local modules. - self.reexport_map.insert(def_id.expect_local(), reexports); + self.module_children_reexports.insert(def_id, reexports); } } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 7df17376b..90a2fa89c 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -22,7 +22,6 @@ use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::{BindingAnnotation, PrimTy, TraitCandidate}; use rustc_middle::middle::resolve_bound_vars::Set1; -use rustc_middle::ty::DefIdTree; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, ResolveDocLinks}; use rustc_session::lint; @@ -123,6 +122,12 @@ pub(crate) enum ConstantItemKind { Static, } +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +enum RecordPartialRes { + Yes, + No, +} + /// The rib kind restricts certain accesses, /// e.g. to a `Res::Local` of an outer item. #[derive(Copy, Clone, Debug)] @@ -591,10 +596,9 @@ struct LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { parent_scope: ParentScope<'a>, /// The current set of local scopes for types and values. - /// FIXME #4948: Reuse ribs to avoid allocation. ribs: PerNS<Vec<Rib<'a>>>, - /// Previous poped `rib`, only used for diagnostic. + /// Previous popped `rib`, only used for diagnostic. last_block_rib: Option<Rib<'a>>, /// The current set of local scopes, for labels. @@ -1219,7 +1223,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { lifetime_ribs: Vec::new(), lifetime_elision_candidates: None, current_trait_ref: None, - diagnostic_metadata: Box::new(DiagnosticMetadata::default()), + diagnostic_metadata: Default::default(), // errors at module scope should always be reported in_func_body: false, lifetime_uses: Default::default(), @@ -1479,8 +1483,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } else { LifetimeUseSet::Many }), - LifetimeRibKind::Generics { .. } => None, - LifetimeRibKind::ConstGeneric | LifetimeRibKind::AnonConst => { + LifetimeRibKind::Generics { .. } + | LifetimeRibKind::ConstGeneric => None, + LifetimeRibKind::AnonConst => { span_bug!(ident.span, "unexpected rib kind: {:?}", rib.kind) } }) @@ -1671,8 +1676,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // Figure out if this is a type/trait segment, // which may need lifetime elision performed. let type_def_id = match partial_res.base_res() { - Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => self.r.parent(def_id), - Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => self.r.parent(def_id), + Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => { + self.r.tcx.parent(def_id) + } + Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => { + self.r.tcx.parent(def_id) + } Res::Def(DefKind::Struct, def_id) | Res::Def(DefKind::Union, def_id) | Res::Def(DefKind::Enum, def_id) @@ -2342,7 +2351,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { }); } - ItemKind::Static(ref ty, _, ref expr) | ItemKind::Const(_, ref ty, ref expr) => { + ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. }) + | ItemKind::Const(box ast::ConstItem { ref ty, ref expr, .. }) => { self.with_static_rib(|this| { this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| { this.visit_ty(ty); @@ -2417,8 +2427,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { .iter() .rfind(|r| matches!(r.kind, ItemRibKind(_))) .expect("associated item outside of an item"); - seen_bindings - .extend(parent_rib.bindings.iter().map(|(ident, _)| (*ident, ident.span))); + seen_bindings.extend(parent_rib.bindings.keys().map(|ident| (*ident, ident.span))); }; add_bindings_for_ns(ValueNS); add_bindings_for_ns(TypeNS); @@ -2621,11 +2630,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { for item in trait_items { self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id)); match &item.kind { - AssocItemKind::Const(_, ty, default) => { + AssocItemKind::Const(box ast::ConstItem { ty, expr, .. }) => { self.visit_ty(ty); // Only impose the restrictions of `ConstRibKind` for an // actual constant expression in a provided default. - if let Some(expr) = default { + if let Some(expr) = expr { // We allow arbitrary const expressions inside of associated consts, // even if they are potentially not const evaluatable. // @@ -2678,6 +2687,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { &path, PathSource::Trait(AliasPossibility::No), Finalize::new(trait_ref.ref_id, trait_ref.path.span), + RecordPartialRes::Yes, ); self.diagnostic_metadata.currently_processing_impl_trait = None; if let Some(def_id) = res.expect_full_res().opt_def_id() { @@ -2796,7 +2806,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { use crate::ResolutionError::*; self.resolve_doc_links(&item.attrs, MaybeExported::ImplItem(trait_id.ok_or(&item.vis))); match &item.kind { - AssocItemKind::Const(_, ty, default) => { + AssocItemKind::Const(box ast::ConstItem { ty, expr, .. }) => { debug!("resolve_implementation AssocItemKind::Const"); // If this is a trait impl, ensure the const // exists in trait @@ -2811,7 +2821,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ); self.visit_ty(ty); - if let Some(expr) = default { + if let Some(expr) = expr { // We allow arbitrary const expressions inside of associated consts, // even if they are potentially not const evaluatable. // @@ -3373,7 +3383,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { participle: "defined", article: res.article(), shadowed_binding: res, - shadowed_binding_span: self.r.opt_span(def_id).expect("const parameter defined outside of local crate"), + shadowed_binding_span: self.r.def_span(def_id), } ); None @@ -3416,6 +3426,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { &Segment::from_path(path), source, Finalize::new(id, path.span), + RecordPartialRes::Yes, ); } @@ -3426,6 +3437,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { path: &[Segment], source: PathSource<'ast>, finalize: Finalize, + record_partial_res: RecordPartialRes, ) -> PartialRes { let ns = source.namespace(); @@ -3454,8 +3466,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { sugg.to_string(), Applicability::MaybeIncorrect, )) - } else if res.is_none() && matches!(source, PathSource::Type) { - this.report_missing_type_error(path) + } else if res.is_none() && let PathSource::Type | PathSource::Expr(_) = source { + this.suggest_adding_generic_parameter(path, source) } else { None }; @@ -3632,7 +3644,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { _ => report_errors(self, None), }; - if !matches!(source, PathSource::TraitItem(..)) { + if record_partial_res == RecordPartialRes::Yes { // Avoid recording definition of `A::B` in `<T as A>::B::C`. self.r.record_partial_res(node_id, partial_res); self.resolve_elided_lifetimes_in_path(node_id, partial_res, path, source, path_span); @@ -3736,7 +3748,25 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ))); } - // Make sure `A::B` in `<T as A::B>::C` is a trait item. + let num_privacy_errors = self.r.privacy_errors.len(); + // Make sure that `A` in `<T as A>::B::C` is a trait. + let trait_res = self.smart_resolve_path_fragment( + &None, + &path[..qself.position], + PathSource::Trait(AliasPossibility::No), + Finalize::new(finalize.node_id, qself.path_span), + RecordPartialRes::No, + ); + + if trait_res.expect_full_res() == Res::Err { + return Ok(Some(trait_res)); + } + + // Truncate additional privacy errors reported above, + // because they'll be recomputed below. + self.r.privacy_errors.truncate(num_privacy_errors); + + // Make sure `A::B` in `<T as A>::B::C` is a trait item. // // Currently, `path` names the full item (`A::B::C`, in // our example). so we extract the prefix of that that is @@ -3749,6 +3779,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { &path[..=qself.position], PathSource::TraitItem(ns), Finalize::with_root_span(finalize.node_id, finalize.path_span, qself.path_span), + RecordPartialRes::No, ); // The remaining segments (the `C` in our example) will @@ -4233,7 +4264,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { { return; } - ResolveDocLinks::Exported if !maybe_exported.eval(self.r) => { + ResolveDocLinks::Exported + if !maybe_exported.eval(self.r) + && !rustdoc::has_primitive_or_keyword_docs(attrs) => + { return; } ResolveDocLinks::ExportedMetadata diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index b8ddc4552..37fbfad2d 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -19,9 +19,8 @@ use rustc_errors::{ use rustc_hir as hir; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind}; -use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; use rustc_hir::PrimTy; -use rustc_middle::ty::DefIdTree; use rustc_session::lint; use rustc_session::parse::feature_err; use rustc_session::Session; @@ -167,13 +166,6 @@ impl TypoCandidate { } impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { - fn def_span(&self, def_id: DefId) -> Option<Span> { - match def_id.krate { - LOCAL_CRATE => self.r.opt_span(def_id), - _ => Some(self.r.cstore().get_span_untracked(def_id, self.r.tcx.sess)), - } - } - fn make_base_error( &mut self, path: &[Segment], @@ -192,7 +184,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { span, span_label: match res { Res::Def(kind, def_id) if kind == DefKind::TyParam => { - self.def_span(def_id).map(|span| (span, "found this type parameter")) + Some((self.r.def_span(def_id), "found this type parameter")) } _ => None, }, @@ -1296,28 +1288,46 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => { let span = find_span(&source, err); - if let Some(span) = self.def_span(def_id) { - err.span_label(span, &format!("`{}` defined here", path_str)); - } - let (tail, descr, applicability) = match source { - PathSource::Pat | PathSource::TupleStruct(..) => { - ("", "pattern", Applicability::MachineApplicable) - } - _ => (": val", "literal", Applicability::HasPlaceholders), - }; - let (fields, applicability) = match self.r.field_names.get(&def_id) { - Some(fields) => ( - fields - .iter() - .map(|f| format!("{}{}", f.node, tail)) - .collect::<Vec<String>>() - .join(", "), - applicability, + err.span_label(self.r.def_span(def_id), &format!("`{path_str}` defined here")); + + let (tail, descr, applicability, old_fields) = match source { + PathSource::Pat => ("", "pattern", Applicability::MachineApplicable, None), + PathSource::TupleStruct(_, args) => ( + "", + "pattern", + Applicability::MachineApplicable, + Some( + args.iter() + .map(|a| self.r.tcx.sess.source_map().span_to_snippet(*a).ok()) + .collect::<Vec<Option<String>>>(), + ), ), + _ => (": val", "literal", Applicability::HasPlaceholders, None), + }; + let field_ids = self.r.field_def_ids(def_id); + let (fields, applicability) = match field_ids { + Some(field_ids) => { + let fields = field_ids.iter().map(|&id| self.r.tcx.item_name(id)); + + let fields = if let Some(old_fields) = old_fields { + fields + .enumerate() + .map(|(idx, new)| (new, old_fields.get(idx))) + .map(|(new, old)| { + let new = new.to_ident_string(); + if let Some(Some(old)) = old && new != *old { format!("{}: {}", new, old) } else { new } + }) + .collect::<Vec<String>>() + } else { + fields.map(|f| format!("{f}{tail}")).collect::<Vec<String>>() + }; + + (fields.join(", "), applicability) + } None => ("/* fields */".to_string(), Applicability::HasPlaceholders), }; - let pad = match self.r.field_names.get(&def_id) { - Some(fields) if fields.is_empty() => "", + let pad = match field_ids { + Some(field_ids) if field_ids.is_empty() => "", _ => " ", }; err.span_suggestion( @@ -1360,17 +1370,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { if self.r.tcx.sess.is_nightly_build() { let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \ `type` alias"; - if let Some(span) = self.def_span(def_id) { - if let Ok(snip) = self.r.tcx.sess.source_map().span_to_snippet(span) { - // The span contains a type alias so we should be able to - // replace `type` with `trait`. - let snip = snip.replacen("type", "trait", 1); - err.span_suggestion(span, msg, snip, Applicability::MaybeIncorrect); - } else { - err.span_help(span, msg); - } + let span = self.r.def_span(def_id); + if let Ok(snip) = self.r.tcx.sess.source_map().span_to_snippet(span) { + // The span contains a type alias so we should be able to + // replace `type` with `trait`. + let snip = snip.replacen("type", "trait", 1); + err.span_suggestion(span, msg, snip, Applicability::MaybeIncorrect); } else { - err.help(msg); + err.span_help(span, msg); } } } @@ -1409,19 +1416,38 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { self.suggest_using_enum_variant(err, source, def_id, span); } (Res::Def(DefKind::Struct, def_id), source) if ns == ValueNS => { - let (ctor_def, ctor_vis, fields) = - if let Some(struct_ctor) = self.r.struct_constructors.get(&def_id).cloned() { - if let PathSource::Expr(Some(parent)) = source { - if let ExprKind::Field(..) | ExprKind::MethodCall(..) = parent.kind { - bad_struct_syntax_suggestion(def_id); - return true; - } + let struct_ctor = match def_id.as_local() { + Some(def_id) => self.r.struct_constructors.get(&def_id).cloned(), + None => { + let ctor = self.r.cstore().ctor_untracked(def_id); + ctor.map(|(ctor_kind, ctor_def_id)| { + let ctor_res = + Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id); + let ctor_vis = self.r.tcx.visibility(ctor_def_id); + let field_visibilities = self + .r + .tcx + .associated_item_def_ids(def_id) + .iter() + .map(|field_id| self.r.tcx.visibility(field_id)) + .collect(); + (ctor_res, ctor_vis, field_visibilities) + }) + } + }; + + let (ctor_def, ctor_vis, fields) = if let Some(struct_ctor) = struct_ctor { + if let PathSource::Expr(Some(parent)) = source { + if let ExprKind::Field(..) | ExprKind::MethodCall(..) = parent.kind { + bad_struct_syntax_suggestion(def_id); + return true; } - struct_ctor - } else { - bad_struct_syntax_suggestion(def_id); - return true; - }; + } + struct_ctor + } else { + bad_struct_syntax_suggestion(def_id); + return true; + }; let is_accessible = self.r.is_accessible_from(ctor_vis, self.parent_scope.module); if !is_expected(ctor_def) || is_accessible { @@ -1445,10 +1471,12 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { ); // Use spans of the tuple struct definition. - self.r - .field_names - .get(&def_id) - .map(|fields| fields.iter().map(|f| f.span).collect::<Vec<_>>()) + self.r.field_def_ids(def_id).map(|field_ids| { + field_ids + .iter() + .map(|&field_id| self.r.def_span(field_id)) + .collect::<Vec<_>>() + }) } _ => None, }; @@ -1494,9 +1522,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { match source { PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => { let span = find_span(&source, err); - if let Some(span) = self.def_span(def_id) { - err.span_label(span, &format!("`{}` defined here", path_str)); - } + err.span_label( + self.r.def_span(def_id), + &format!("`{path_str}` defined here"), + ); err.span_suggestion( span, "use this syntax instead", @@ -1508,13 +1537,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } } (Res::Def(DefKind::Ctor(_, CtorKind::Fn), ctor_def_id), _) if ns == ValueNS => { - let def_id = self.r.parent(ctor_def_id); - if let Some(span) = self.def_span(def_id) { - err.span_label(span, &format!("`{}` defined here", path_str)); - } - let fields = self.r.field_names.get(&def_id).map_or_else( + let def_id = self.r.tcx.parent(ctor_def_id); + err.span_label(self.r.def_span(def_id), &format!("`{path_str}` defined here")); + let fields = self.r.field_def_ids(def_id).map_or_else( || "/* fields */".to_string(), - |fields| vec!["_"; fields.len()].join(", "), + |field_ids| vec!["_"; field_ids.len()].join(", "), ); err.span_suggestion( span, @@ -1595,8 +1622,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { if let Some(Res::Def(DefKind::Struct | DefKind::Union, did)) = resolution.full_res() { - if let Some(field_names) = self.r.field_names.get(&did) { - if field_names.iter().any(|&field_name| ident.name == field_name.node) { + if let Some(field_ids) = self.r.field_def_ids(did) { + if field_ids + .iter() + .any(|&field_id| ident.name == self.r.tcx.item_name(field_id)) + { return Some(AssocSuggestion::Field); } } @@ -1631,7 +1661,17 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { ) { let res = binding.res(); if filter_fn(res) { - if self.r.has_self.contains(&res.def_id()) { + let def_id = res.def_id(); + let has_self = match def_id.as_local() { + Some(def_id) => self.r.has_self.contains(&def_id), + None => self + .r + .tcx + .fn_arg_names(def_id) + .first() + .map_or(false, |ident| ident.name == kw::SelfLower), + }; + if has_self { return Some(AssocSuggestion::MethodWithSelf { called }); } else { match res { @@ -1737,7 +1777,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { let name = path[path.len() - 1].ident.name; // Make sure error reporting is deterministic. - names.sort_by(|a, b| a.candidate.as_str().partial_cmp(b.candidate.as_str()).unwrap()); + names.sort_by(|a, b| a.candidate.as_str().cmp(b.candidate.as_str())); match find_best_match_for_name( &names.iter().map(|suggestion| suggestion.candidate).collect::<Vec<Symbol>>(), @@ -1999,12 +2039,13 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } } else { let needs_placeholder = |ctor_def_id: DefId, kind: CtorKind| { - let def_id = self.r.parent(ctor_def_id); - let has_no_fields = self.r.field_names.get(&def_id).map_or(false, |f| f.is_empty()); + let def_id = self.r.tcx.parent(ctor_def_id); match kind { CtorKind::Const => false, - CtorKind::Fn if has_no_fields => false, - _ => true, + CtorKind::Fn => !self + .r + .field_def_ids(def_id) + .map_or(false, |field_ids| field_ids.is_empty()), } }; @@ -2065,15 +2106,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { }; if def_id.is_local() { - if let Some(span) = self.def_span(def_id) { - err.span_note(span, "the enum is defined here"); - } + err.span_note(self.r.def_span(def_id), "the enum is defined here"); } } - pub(crate) fn report_missing_type_error( + pub(crate) fn suggest_adding_generic_parameter( &self, path: &[Segment], + source: PathSource<'_>, ) -> Option<(Span, &'static str, String, Applicability)> { let (ident, span) = match path { [segment] @@ -2109,7 +2149,6 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { // Without the 2nd `true`, we'd suggest `impl <T>` for `impl T` when a type `T` isn't found | (Some(Item { kind: kind @ ItemKind::Impl(..), .. }), true, true) | (Some(Item { kind, .. }), false, _) => { - // Likely missing type parameter. if let Some(generics) = kind.generics() { if span.overlaps(generics.span) { // Avoid the following: @@ -2122,7 +2161,12 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { // | not found in this scope return None; } - let msg = "you might be missing a type parameter"; + + let (msg, sugg) = match source { + PathSource::Type => ("you might be missing a type parameter", ident), + PathSource::Expr(_) => ("you might be missing a const parameter", format!("const {ident}: /* Type */")), + _ => return None, + }; let (span, sugg) = if let [.., param] = &generics.params[..] { let span = if let [.., bound] = ¶m.bounds[..] { bound.span() @@ -2133,9 +2177,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } else { param.ident.span }; - (span, format!(", {}", ident)) + (span, format!(", {sugg}")) } else { - (generics.span, format!("<{}>", ident)) + (generics.span, format!("<{sugg}>")) }; // Do not suggest if this is coming from macro expansion. if span.can_be_used_for_suggestions() { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 1fdfb1a53..b820d56b8 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -23,10 +23,11 @@ extern crate tracing; use rustc_arena::{DroplessArena, TypedArena}; use rustc_ast::node_id::NodeMap; -use rustc_ast::{self as ast, NodeId, CRATE_NODE_ID}; +use rustc_ast::{self as ast, attr, NodeId, CRATE_NODE_ID}; use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path}; 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::{Lrc, MappedReadGuard}; use rustc_errors::{ Applicability, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, SubdiagnosticMessage, @@ -34,7 +35,7 @@ use rustc_errors::{ use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind}; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, PartialRes, PerNS}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId}; +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, LocalDefIdSet}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::DefPathData; use rustc_hir::TraitCandidate; @@ -44,13 +45,11 @@ use rustc_metadata::creader::{CStore, CrateLoader}; use rustc_middle::metadata::ModChild; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::span_bug; -use rustc_middle::ty::{self, DefIdTree, MainDefinition, RegisteredTools, TyCtxt}; +use rustc_middle::ty::{self, MainDefinition, RegisteredTools, TyCtxt}; use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs}; use rustc_query_system::ich::StableHashingContext; -use rustc_session::cstore::CrateStore; use rustc_session::lint::LintBuffer; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency}; -use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; @@ -80,7 +79,7 @@ mod late; mod macros; pub mod rustdoc; -fluent_messages! { "../locales/en-US.ftl" } +fluent_messages! { "../messages.ftl" } enum Weak { Yes, @@ -880,11 +879,8 @@ pub struct Resolver<'a, 'tcx> { extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'a>>, /// N.B., this is used only for better diagnostics, not name resolution itself. - has_self: FxHashSet<DefId>, - - /// Names of fields of an item `DefId` accessible with dot syntax. - /// Used for hints during error reporting. - field_names: FxHashMap<DefId, Vec<Spanned<Symbol>>>, + has_self: LocalDefIdSet, + field_def_ids: LocalDefIdMap<&'tcx [DefId]>, /// Span of the privacy modifier in fields of an item `DefId` accessible with dot syntax. /// Used for hints during error reporting. @@ -913,7 +909,8 @@ pub struct Resolver<'a, 'tcx> { /// `CrateNum` resolutions of `extern crate` items. extern_crate_map: FxHashMap<LocalDefId, CrateNum>, - reexport_map: FxHashMap<LocalDefId, Vec<ModChild>>, + module_children_non_reexports: LocalDefIdMap<Vec<LocalDefId>>, + module_children_reexports: LocalDefIdMap<Vec<ModChild>>, trait_map: NodeMap<Vec<TraitCandidate>>, /// A map from nodes to anonymous modules. @@ -965,7 +962,7 @@ pub struct Resolver<'a, 'tcx> { /// A small map keeping true kinds of built-in macros that appear to be fn-like on /// the surface (`macro` items in libcore), but are actually attributes or derives. builtin_macro_kinds: FxHashMap<LocalDefId, MacroKind>, - registered_tools: RegisteredTools, + registered_tools: &'tcx RegisteredTools, macro_use_prelude: FxHashMap<Symbol, &'a NameBinding<'a>>, macro_map: FxHashMap<DefId, MacroData>, dummy_ext_bang: Lrc<SyntaxExtension>, @@ -1008,7 +1005,7 @@ pub struct Resolver<'a, '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: DefIdMap<(Res, ty::Visibility<DefId>, Vec<ty::Visibility<DefId>>)>, + struct_constructors: LocalDefIdMap<(Res, ty::Visibility<DefId>, Vec<ty::Visibility<DefId>>)>, /// Features enabled for this crate. active_features: FxHashSet<Symbol>, @@ -1117,13 +1114,6 @@ impl<'a, 'tcx> AsMut<Resolver<'a, 'tcx>> for Resolver<'a, 'tcx> { } } -impl<'a, 'b, 'tcx> DefIdTree for &'a Resolver<'b, 'tcx> { - #[inline] - fn opt_parent(self, id: DefId) -> Option<DefId> { - self.tcx.opt_parent(id) - } -} - impl<'tcx> Resolver<'_, 'tcx> { fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> { self.node_id_to_def_id.get(&node).copied() @@ -1179,7 +1169,7 @@ impl<'tcx> Resolver<'_, 'tcx> { if let Some(def_id) = def_id.as_local() { self.item_generics_num_lifetimes[&def_id] } else { - self.cstore().item_generics_num_lifetimes(def_id, self.tcx.sess) + self.tcx.generics_of(def_id).own_counts().lifetimes } } @@ -1191,7 +1181,8 @@ impl<'tcx> Resolver<'_, 'tcx> { impl<'a, 'tcx> Resolver<'a, 'tcx> { pub fn new( tcx: TyCtxt<'tcx>, - krate: &Crate, + attrs: &[ast::Attribute], + crate_span: Span, arenas: &'a ResolverArenas<'a>, ) -> Resolver<'a, 'tcx> { let root_def_id = CRATE_DEF_ID.to_def_id(); @@ -1200,8 +1191,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { None, ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty), ExpnId::root(), - krate.spans.inner_span, - tcx.sess.contains_name(&krate.attrs, sym::no_implicit_prelude), + crate_span, + attr::contains_name(attrs, sym::no_implicit_prelude), &mut module_map, ); let empty_module = arenas.new_module( @@ -1233,14 +1224,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { .map(|(name, _)| (Ident::from_str(name), Default::default())) .collect(); - if !tcx.sess.contains_name(&krate.attrs, sym::no_core) { + if !attr::contains_name(attrs, sym::no_core) { extern_prelude.insert(Ident::with_dummy_span(sym::core), Default::default()); - if !tcx.sess.contains_name(&krate.attrs, sym::no_std) { + if !attr::contains_name(attrs, sym::no_std) { extern_prelude.insert(Ident::with_dummy_span(sym::std), Default::default()); } } - let registered_tools = macros::registered_tools(tcx.sess, &krate.attrs); + let registered_tools = tcx.registered_tools(()); let features = tcx.sess.features_untracked(); @@ -1255,8 +1246,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { prelude: None, extern_prelude, - has_self: FxHashSet::default(), - field_names: FxHashMap::default(), + has_self: Default::default(), + field_def_ids: Default::default(), field_visibility_spans: FxHashMap::default(), determined_imports: Vec::new(), @@ -1269,7 +1260,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { lifetimes_res_map: Default::default(), extra_lifetime_params_map: Default::default(), extern_crate_map: Default::default(), - reexport_map: FxHashMap::default(), + module_children_non_reexports: Default::default(), + module_children_reexports: Default::default(), trait_map: NodeMap::default(), underscore_disambiguator: 0, empty_module, @@ -1396,7 +1388,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let visibilities = self.visibilities; let has_pub_restricted = self.has_pub_restricted; let extern_crate_map = self.extern_crate_map; - let reexport_map = self.reexport_map; let maybe_unused_trait_imports = self.maybe_unused_trait_imports; let glob_map = self.glob_map; let main_def = self.main_def; @@ -1408,14 +1399,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { has_pub_restricted, effective_visibilities, extern_crate_map, - reexport_map, + module_children_non_reexports: self.module_children_non_reexports, + module_children_reexports: self.module_children_reexports, glob_map, maybe_unused_trait_imports, main_def, trait_impls: self.trait_impls, proc_macros, confused_type_with_std_module, - registered_tools: self.registered_tools, doc_link_resolutions: self.doc_link_resolutions, doc_link_traits_in_scope: self.doc_link_traits_in_scope, all_macro_rules: self.all_macro_rules, @@ -1433,6 +1424,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { trait_map: self.trait_map, builtin_macro_kinds: self.builtin_macro_kinds, lifetime_elision_allowed: self.lifetime_elision_allowed, + lint_buffer: Steal::new(self.lint_buffer), }; ResolverOutputs { global_ctxt, ast_lowering } } @@ -1442,9 +1434,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } fn crate_loader<T>(&mut self, f: impl FnOnce(&mut CrateLoader<'_, '_>) -> T) -> T { - let mut cstore = self.tcx.untracked().cstore.write(); - let cstore = cstore.untracked_as_any().downcast_mut().unwrap(); - f(&mut CrateLoader::new(self.tcx, &mut *cstore, &mut self.used_extern_options)) + f(&mut CrateLoader::new( + self.tcx, + &mut CStore::from_tcx_mut(self.tcx), + &mut self.used_extern_options, + )) } fn cstore(&self) -> MappedReadGuard<'_, CStore> { @@ -1483,9 +1477,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { pub fn resolve_crate(&mut self, krate: &Crate) { self.tcx.sess.time("resolve_crate", || { self.tcx.sess.time("finalize_imports", || self.finalize_imports()); - self.tcx.sess.time("compute_effective_visibilities", || { + let exported_ambiguities = self.tcx.sess.time("compute_effective_visibilities", || { EffectiveVisibilitiesVisitor::compute_effective_visibilities(self, krate) }); + self.tcx.sess.time("check_reexport_ambiguities", || { + self.check_reexport_ambiguities(exported_ambiguities) + }); self.tcx.sess.time("finalize_macro_resolutions", || self.finalize_macro_resolutions()); self.tcx.sess.time("late_resolve_crate", || self.late_resolve_crate(krate)); self.tcx.sess.time("resolve_main", || self.resolve_main()); @@ -1656,7 +1653,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { misc2: AmbiguityErrorMisc::None, }; if !self.matches_previous_ambiguity_error(&ambiguity_error) { - // avoid dumplicated span information to be emitt out + // avoid duplicated span information to be emitt out self.ambiguity_errors.push(ambiguity_error); } } @@ -1789,7 +1786,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { vis: ty::Visibility<impl Into<DefId>>, module: Module<'a>, ) -> bool { - vis.is_accessible_from(module.nearest_parent_mod(), self) + vis.is_accessible_from(module.nearest_parent_mod(), self.tcx) } fn set_binding_parent_module(&mut self, binding: &'a NameBinding<'a>, module: Module<'a>) { @@ -1856,20 +1853,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { &mut self, path_str: &str, ns: Namespace, - mut parent_scope: ParentScope<'a>, + parent_scope: ParentScope<'a>, ) -> Option<Res> { let mut segments = Vec::from_iter(path_str.split("::").map(Ident::from_str).map(Segment::from_ident)); if let Some(segment) = segments.first_mut() { - if segment.ident.name == kw::Crate { - // FIXME: `resolve_path` always resolves `crate` to the current crate root, but - // rustdoc wants it to resolve to the `parent_scope`'s crate root. This trick of - // replacing `crate` with `self` and changing the current module should achieve - // the same effect. - segment.ident.name = kw::SelfLower; - parent_scope.module = - self.expect_module(parent_scope.module.def_id().krate.as_def_id()); - } else if segment.ident.name == kw::Empty { + if segment.ident.name == kw::Empty { segment.ident.name = kw::PathRoot; } } @@ -1884,20 +1873,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - /// Retrieves the span of the given `DefId` if `DefId` is in the local crate. - #[inline] - fn opt_span(&self, def_id: DefId) -> Option<Span> { - def_id.as_local().map(|def_id| self.tcx.source_span(def_id)) + /// Retrieves definition span of the given `DefId`. + fn def_span(&self, def_id: DefId) -> Span { + match def_id.as_local() { + Some(def_id) => self.tcx.source_span(def_id), + // Query `def_span` is not used because hashing its result span is expensive. + None => self.cstore().def_span_untracked(def_id, self.tcx.sess), + } } - /// Retrieves the name of the given `DefId`. - #[inline] - fn opt_name(&self, def_id: DefId) -> Option<Symbol> { - let def_key = match def_id.as_local() { - Some(def_id) => self.tcx.definitions_untracked().def_key(def_id), - None => self.cstore().def_key(def_id), - }; - def_key.get_opt_name() + fn field_def_ids(&self, def_id: DefId) -> Option<&'tcx [DefId]> { + match def_id.as_local() { + Some(def_id) => self.field_def_ids.get(&def_id).copied(), + None => Some(self.tcx.associated_item_def_ids(def_id)), + } } /// Checks if an expression refers to a function marked with @@ -1924,10 +1913,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { return v.clone(); } - let attr = self - .cstore() - .item_attrs_untracked(def_id, self.tcx.sess) - .find(|a| a.has_name(sym::rustc_legacy_const_generics))?; + let attr = self.tcx.get_attr(def_id, sym::rustc_legacy_const_generics)?; let mut ret = Vec::new(); for meta in attr.meta_item_list()? { match meta.lit()?.kind { @@ -1965,20 +1951,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } self.main_def = Some(MainDefinition { res, is_import, span }); } - - // Items that go to reexport table encoded to metadata and visible through it to other crates. - fn is_reexport(&self, binding: &NameBinding<'a>) -> Option<def::Res<!>> { - if binding.is_import() { - let res = binding.res().expect_non_local(); - // Ambiguous imports are treated as errors at this point and are - // not exposed to other crates (see #36837 for more details). - if res != def::Res::Err && !binding.is_ambiguity() { - return Some(res); - } - } - - return None; - } } fn names_to_string(names: &[Symbol]) -> String { @@ -2047,3 +2019,7 @@ impl Finalize { Finalize { node_id, path_span, root_span, report_private: true } } } + +pub fn provide(providers: &mut ty::query::Providers) { + providers.registered_tools = macros::registered_tools; +} diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index b38c11e8b..22b014c06 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -1,14 +1,14 @@ //! A bunch of methods and structures more or less related to resolving macros and //! interface provided by `Resolver` to macro expander. +use crate::errors::{AddAsNonDerive, MacroExpectedFound, RemoveSurroundingDerive}; use crate::Namespace::*; use crate::{BuiltinMacroState, Determinacy}; use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet}; use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment}; -use rustc_ast::{self as ast, Inline, ItemKind, ModKind, NodeId}; +use rustc_ast::{self as ast, attr, Inline, ItemKind, ModKind, NodeId}; use rustc_ast_pretty::pprust; use rustc_attr::StabilityLevel; -use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::Lrc; use rustc_errors::{struct_span_err, Applicability}; @@ -20,11 +20,11 @@ use rustc_hir::def::{self, DefKind, NonMacroAttrKind}; use rustc_hir::def_id::{CrateNum, LocalDefId}; use rustc_middle::middle::stability; use rustc_middle::ty::RegisteredTools; +use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE}; use rustc_session::lint::builtin::{UNUSED_MACROS, UNUSED_MACRO_RULES}; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::feature_err; -use rustc_session::Session; use rustc_span::edition::Edition; use rustc_span::hygiene::{self, ExpnData, ExpnKind, LocalExpnId}; use rustc_span::hygiene::{AstPass, MacroKind}; @@ -111,15 +111,17 @@ fn fast_print_path(path: &ast::Path) -> Symbol { } } -pub(crate) fn registered_tools(sess: &Session, attrs: &[ast::Attribute]) -> FxHashSet<Ident> { - let mut registered_tools = FxHashSet::default(); - for attr in sess.filter_by_name(attrs, sym::register_tool) { +pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { + let mut registered_tools = RegisteredTools::default(); + let (_, pre_configured_attrs) = &*tcx.crate_for_resolver(()).borrow(); + for attr in attr::filter_by_name(pre_configured_attrs, sym::register_tool) { for nested_meta in attr.meta_item_list().unwrap_or_default() { match nested_meta.ident() { Some(ident) => { if let Some(old_ident) = registered_tools.replace(ident) { let msg = format!("{} `{}` was already registered", "tool", ident); - sess.struct_span_err(ident.span, &msg) + tcx.sess + .struct_span_err(ident.span, &msg) .span_label(old_ident.span, "already registered here") .emit(); } @@ -127,7 +129,10 @@ pub(crate) fn registered_tools(sess: &Session, attrs: &[ast::Attribute]) -> FxHa None => { let msg = format!("`{}` only accepts identifiers", sym::register_tool); let span = nested_meta.span(); - sess.struct_span_err(span, &msg).span_label(span, "not an identifier").emit(); + tcx.sess + .struct_span_err(span, &msg) + .span_label(span, "not an identifier") + .emit(); } } } @@ -539,12 +544,29 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }; if let Some((article, expected)) = unexpected_res { let path_str = pprust::path_to_string(path); - let msg = format!("expected {}, found {} `{}`", expected, res.descr(), path_str); - self.tcx - .sess - .struct_span_err(path.span, &msg) - .span_label(path.span, format!("not {} {}", article, expected)) - .emit(); + + let mut err = MacroExpectedFound { + span: path.span, + expected, + found: res.descr(), + macro_path: &path_str, + ..Default::default() // Subdiagnostics default to None + }; + + // Suggest moving the macro out of the derive() if the macro isn't Derive + if !path.span.from_expansion() + && kind == MacroKind::Derive + && ext.macro_kind() != MacroKind::Derive + { + err.remove_surrounding_derive = Some(RemoveSurroundingDerive { span: path.span }); + err.add_as_non_derive = Some(AddAsNonDerive { macro_path: &path_str }); + } + + let mut err = self.tcx.sess.create_err(err); + err.span_label(path.span, format!("not {} {}", article, expected)); + + err.emit(); + return Ok((self.dummy_ext(kind), Res::Err)); } @@ -699,7 +721,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => { check_consistency(self, &path, path_span, kind, initial_res, res) } - path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed { .. } => { + path_res @ (PathResult::NonModule(..) | PathResult::Failed { .. }) => { let mut suggestion = None; let (span, label) = if let PathResult::Failed { span, label, .. } = path_res { // try to suggest if it's not a macro, maybe a function diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index b8853c174..9eae99be2 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -3,7 +3,7 @@ use rustc_ast as ast; use rustc_ast::util::comments::beautify_doc_string; use rustc_data_structures::fx::FxHashMap; use rustc_span::def_id::DefId; -use rustc_span::symbol::{kw, Symbol}; +use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; use std::{cmp, mem}; @@ -26,11 +26,13 @@ pub enum DocFragmentKind { #[derive(Clone, PartialEq, Eq, Debug)] pub struct DocFragment { pub span: Span, - /// The module this doc-comment came from. - /// - /// This allows distinguishing between the original documentation and a pub re-export. - /// If it is `None`, the item was not re-exported. - pub parent_module: Option<DefId>, + /// The item this doc-comment came from. + /// Used to determine the scope in which doc links in this fragment are resolved. + /// Typically filled for reexport docs when they are merged into the docs of the + /// original reexported item. + /// If the id is not filled, which happens for the original reexported item, then + /// it has to be taken from somewhere else during doc link resolution. + pub item_id: Option<DefId>, pub doc: Symbol, pub kind: DocFragmentKind, pub indent: usize, @@ -186,7 +188,7 @@ pub fn attrs_to_doc_fragments<'a>( ) -> (Vec<DocFragment>, ast::AttrVec) { let mut doc_fragments = Vec::new(); let mut other_attrs = ast::AttrVec::new(); - for (attr, parent_module) in attrs { + 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 kind = if attr.is_doc_comment() { @@ -194,7 +196,7 @@ pub fn attrs_to_doc_fragments<'a>( } else { DocFragmentKind::RawDoc }; - let fragment = DocFragment { span: attr.span, doc, kind, parent_module, indent: 0 }; + let fragment = DocFragment { span: attr.span, doc, kind, item_id, indent: 0 }; doc_fragments.push(fragment); } else if !doc_only { other_attrs.push(attr.clone()); @@ -216,7 +218,7 @@ pub fn prepare_to_doc_link_resolution( ) -> FxHashMap<Option<DefId>, String> { let mut res = FxHashMap::default(); for fragment in doc_fragments { - let out_str = res.entry(fragment.parent_module).or_default(); + let out_str = res.entry(fragment.item_id).or_default(); add_doc_fragment(out_str, fragment); } res @@ -337,6 +339,22 @@ pub fn inner_docs(attrs: &[ast::Attribute]) -> bool { attrs.iter().find(|a| a.doc_str().is_some()).map_or(true, |a| a.style == ast::AttrStyle::Inner) } +/// Has `#[rustc_doc_primitive]` or `#[doc(keyword)]`. +pub fn has_primitive_or_keyword_docs(attrs: &[ast::Attribute]) -> bool { + for attr in attrs { + if attr.has_name(sym::rustc_doc_primitive) { + return true; + } else if attr.has_name(sym::doc) && let Some(items) = attr.meta_item_list() { + for item in items { + if item.has_name(sym::keyword) { + return true; + } + } + } + } + false +} + /// Simplified version of the corresponding function in rustdoc. /// If the rustdoc version returns a successful result, this function must return the same result. /// Otherwise this function may return anything. |