summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_resolve
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:20:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:20:29 +0000
commit631cd5845e8de329d0e227aaa707d7ea228b8f8f (patch)
treea1b87c8f8cad01cf18f7c5f57a08f102771ed303 /compiler/rustc_resolve
parentAdding debian version 1.69.0+dfsg1-1. (diff)
downloadrustc-631cd5845e8de329d0e227aaa707d7ea228b8f8f.tar.xz
rustc-631cd5845e8de329d0e227aaa707d7ea228b8f8f.zip
Merging upstream version 1.70.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
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.rs156
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs44
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs4
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs84
-rw-r--r--compiler/rustc_resolve/src/effective_visibilities.rs84
-rw-r--r--compiler/rustc_resolve/src/errors.rs36
-rw-r--r--compiler/rustc_resolve/src/ident.rs55
-rw-r--r--compiler/rustc_resolve/src/imports.rs133
-rw-r--r--compiler/rustc_resolve/src/late.rs76
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs204
-rw-r--r--compiler/rustc_resolve/src/lib.rs136
-rw-r--r--compiler/rustc_resolve/src/macros.rs52
-rw-r--r--compiler/rustc_resolve/src/rustdoc.rs36
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] = &param.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.