summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_resolve
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
commitc23a457e72abe608715ac76f076f47dc42af07a5 (patch)
tree2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /compiler/rustc_resolve
parentReleasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz
rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_resolve')
-rw-r--r--compiler/rustc_resolve/messages.ftl33
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs28
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs61
-rw-r--r--compiler/rustc_resolve/src/errors.rs44
-rw-r--r--compiler/rustc_resolve/src/ident.rs81
-rw-r--r--compiler/rustc_resolve/src/imports.rs15
-rw-r--r--compiler/rustc_resolve/src/late.rs130
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs142
-rw-r--r--compiler/rustc_resolve/src/lib.rs137
-rw-r--r--compiler/rustc_resolve/src/macros.rs39
-rw-r--r--compiler/rustc_resolve/src/rustdoc.rs89
11 files changed, 541 insertions, 258 deletions
diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index f98918cba..9a970f5db 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -58,15 +58,16 @@ resolve_cannot_determine_import_resolution =
cannot determine resolution for the import
.note = import resolution is stuck, try simplifying other imports
+resolve_cannot_determine_macro_resolution =
+ cannot determine resolution for the {$kind} `{$path}`
+ .note = import resolution is stuck, try simplifying macro imports
+
resolve_cannot_find_ident_in_this_scope =
cannot find {$expected} `{$ident}` in this scope
resolve_cannot_glob_import_possible_crates =
cannot glob-import all possible crates
-resolve_cannot_use_self_type_here =
- can't use `Self` here
-
resolve_change_import_binding =
you can use `as` to change the binding name of the import
@@ -86,9 +87,6 @@ resolve_const_not_member_of_trait =
const `{$const_}` is not a member of trait `{$trait_}`
.label = not a member of trait `{$trait_}`
-resolve_const_param_from_outer_fn =
- const parameter from outer function
-
resolve_const_param_in_enum_discriminant =
const parameters may not be used in enum discriminant values
@@ -115,10 +113,19 @@ resolve_forward_declared_generic_param =
generic parameters with a default cannot use forward declared identifiers
.label = defaulted generic parameters cannot be forward declared
-resolve_generic_params_from_outer_function =
- can't use generic parameters from outer function
- .label = use of generic parameter from outer function
- .suggestion = try using a local generic parameter instead
+resolve_generic_params_from_outer_item =
+ can't use generic parameters from outer item
+ .label = use of generic parameter from outer item
+ .refer_to_type_directly = refer to the type directly here instead
+ .suggestion = try introducing a local generic parameter here
+
+resolve_generic_params_from_outer_item_const_param = const parameter from outer item
+
+resolve_generic_params_from_outer_item_self_ty_alias = `Self` type implicitly declared here, by this `impl`
+
+resolve_generic_params_from_outer_item_self_ty_param = can't use `Self` here
+
+resolve_generic_params_from_outer_item_ty_param = type parameter from outer item
resolve_glob_import_doesnt_reexport =
glob import doesn't reexport anything because no candidate is public enough
@@ -273,9 +280,6 @@ resolve_type_not_member_of_trait =
type `{$type_}` is not a member of trait `{$trait_}`
.label = not a member of trait `{$trait_}`
-resolve_type_param_from_outer_fn =
- type parameter from outer function
-
resolve_type_param_in_enum_discriminant =
type parameters may not be used in enum discriminant values
@@ -311,9 +315,6 @@ resolve_unreachable_label_suggestion_use_similarly_named =
resolve_unreachable_label_with_similar_name_exists =
a label with a similar name exists but is unreachable
-resolve_use_a_type_here_instead =
- use a type here instead
-
resolve_variable_bound_with_different_mode =
variable `{$variable_name}` is bound inconsistently across alternatives separated by `|`
.label = bound in different ways
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 127bec22c..a18109574 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -247,8 +247,6 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
})
}
ast::VisibilityKind::Restricted { ref path, id, .. } => {
- // Make `PRIVATE_IN_PUBLIC` lint a hard error.
- self.r.has_pub_restricted = true;
// For visibilities we are not ready to provide correct implementation of "uniform
// paths" right now, so on 2018 edition we only allow module-relative paths for now.
// On 2015 edition visibilities are resolved as crate-relative by default,
@@ -700,10 +698,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
// These items live in the type namespace.
ItemKind::TyAlias(..) => {
- let res = Res::Def(
- DefKind::TyAlias { lazy: self.r.tcx.features().lazy_type_alias },
- def_id,
- );
+ let res = Res::Def(DefKind::TyAlias, def_id);
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
}
@@ -870,10 +865,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
let imported_binding = self.r.import(binding, import);
if parent == self.r.graph_root {
if let Some(entry) = self.r.extern_prelude.get(&ident.normalize_to_macros_2_0()) {
- if expansion != LocalExpnId::ROOT
- && orig_name.is_some()
- && entry.extern_crate_item.is_none()
- {
+ if expansion != LocalExpnId::ROOT && orig_name.is_some() && !entry.is_import() {
let msg = "macro-expanded `extern crate` items cannot \
shadow names passed with `--extern`";
self.r.tcx.sess.span_err(item.span, msg);
@@ -884,10 +876,14 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
return;
}
}
- let entry = self.r.extern_prelude.entry(ident.normalize_to_macros_2_0()).or_insert(
- ExternPreludeEntry { extern_crate_item: None, introduced_by_item: true },
- );
- entry.extern_crate_item = Some(imported_binding);
+ let entry = self
+ .r
+ .extern_prelude
+ .entry(ident.normalize_to_macros_2_0())
+ .or_insert(ExternPreludeEntry { binding: None, introduced_by_item: true });
+ // Binding from `extern crate` item in source code can replace
+ // a binding from `--extern` on command line here.
+ entry.binding = Some(imported_binding);
if orig_name.is_some() {
entry.introduced_by_item = true;
}
@@ -951,7 +947,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
DefKind::Struct
| DefKind::Union
| DefKind::Variant
- | DefKind::TyAlias { .. }
+ | DefKind::TyAlias
| DefKind::ForeignTy
| DefKind::OpaqueTy
| DefKind::TraitAlias
@@ -1240,7 +1236,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
use_span_with_attributes: span,
use_span: span,
root_span: span,
- span: span,
+ span,
module_path: Vec::new(),
vis: Cell::new(Some(vis)),
used: Cell::new(true),
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index cd1a9b934..907a6b1c4 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -553,43 +553,40 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
resolution_error: ResolutionError<'a>,
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
match resolution_error {
- ResolutionError::GenericParamsFromOuterFunction(outer_res, has_generic_params) => {
- let mut err = struct_span_err!(
- self.tcx.sess,
+ ResolutionError::GenericParamsFromOuterItem(outer_res, has_generic_params) => {
+ use errs::GenericParamsFromOuterItemLabel as Label;
+ let mut err = errs::GenericParamsFromOuterItem {
span,
- E0401,
- "can't use generic parameters from outer function",
- );
- err.span_label(span, "use of generic parameter from outer function");
+ label: None,
+ refer_to_type_directly: None,
+ sugg: None,
+ };
let sm = self.tcx.sess.source_map();
let def_id = match outer_res {
Res::SelfTyParam { .. } => {
- err.span_label(span, "can't use `Self` here");
- return err;
+ err.label = Some(Label::SelfTyParam(span));
+ return self.tcx.sess.create_err(err);
}
Res::SelfTyAlias { alias_to: def_id, .. } => {
- 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;
+ err.label = Some(Label::SelfTyAlias(reduce_impl_span_to_impl_keyword(
+ sm,
+ self.def_span(def_id),
+ )));
+ err.refer_to_type_directly = Some(span);
+ return self.tcx.sess.create_err(err);
}
Res::Def(DefKind::TyParam, def_id) => {
- err.span_label(self.def_span(def_id), "type parameter from outer function");
+ err.label = Some(Label::TyParam(self.def_span(def_id)));
def_id
}
Res::Def(DefKind::ConstParam, def_id) => {
- err.span_label(
- self.def_span(def_id),
- "const parameter from outer function",
- );
+ err.label = Some(Label::ConstParam(self.def_span(def_id)));
def_id
}
_ => {
bug!(
- "GenericParamsFromOuterFunction should only be used with \
+ "GenericParamsFromOuterItem should only be used with \
Res::SelfTyParam, Res::SelfTyAlias, DefKind::TyParam or \
DefKind::ConstParam"
);
@@ -597,9 +594,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
};
if let HasGenericParams::Yes(span) = has_generic_params {
- // 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.tcx.item_name(def_id);
let (span, snippet) = if span.is_empty() {
let snippet = format!("<{name}>");
@@ -609,11 +603,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let snippet = format!("{name}, ");
(span, snippet)
};
- // Suggest the modification to the user
- err.span_suggestion(span, sugg_msg, snippet, Applicability::MaybeIncorrect);
+ err.sugg = Some(errs::GenericParamsFromOuterItemSugg { span, snippet });
}
- err
+ self.tcx.sess.create_err(err)
}
ResolutionError::NameAlreadyUsedInParameterList(name, first_use_span) => self
.tcx
@@ -1032,7 +1025,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
.get(&expn_id)
.into_iter()
.flatten()
- .map(|ident| TypoSuggestion::typo_from_ident(*ident, res)),
+ .map(|(ident, _)| TypoSuggestion::typo_from_ident(*ident, res)),
);
}
}
@@ -2603,7 +2596,9 @@ fn show_candidates(
);
if let [first, .., last] = &path[..] {
let sp = first.ident.span.until(last.ident.span);
- if sp.can_be_used_for_suggestions() {
+ // Our suggestion is empty, so make sure the span is not empty (or we'd ICE).
+ // Can happen for derive-generated spans.
+ if sp.can_be_used_for_suggestions() && !sp.is_empty() {
err.span_suggestion_verbose(
sp,
format!("if you import `{}`, refer to it directly", last.ident),
@@ -2753,7 +2748,13 @@ fn search_for_any_use_in_items(items: &[P<ast::Item>]) -> Option<Span> {
for item in items {
if let ItemKind::Use(..) = item.kind {
if is_span_suitable_for_use_injection(item.span) {
- return Some(item.span.shrink_to_lo());
+ let mut lo = item.span.lo();
+ for attr in &item.attrs {
+ if attr.span.eq_ctxt(item.span) {
+ lo = std::cmp::min(lo, attr.span.lo());
+ }
+ }
+ return Some(Span::new(lo, lo, item.span.ctxt(), item.span.parent()));
}
}
}
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index e4b89c658..72ff959bb 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -33,6 +33,40 @@ pub(crate) struct CrateRootNamesMustBeNamedExplicitly(#[primary_span] pub(crate)
pub(crate) struct ResolutionError(#[primary_span] pub(crate) Span);
#[derive(Diagnostic)]
+#[diag(resolve_generic_params_from_outer_item, code = "E0401")]
+pub(crate) struct GenericParamsFromOuterItem {
+ #[primary_span]
+ #[label]
+ pub(crate) span: Span,
+ #[subdiagnostic]
+ pub(crate) label: Option<GenericParamsFromOuterItemLabel>,
+ #[label(resolve_refer_to_type_directly)]
+ pub(crate) refer_to_type_directly: Option<Span>,
+ #[subdiagnostic]
+ pub(crate) sugg: Option<GenericParamsFromOuterItemSugg>,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum GenericParamsFromOuterItemLabel {
+ #[label(resolve_generic_params_from_outer_item_self_ty_param)]
+ SelfTyParam(#[primary_span] Span),
+ #[label(resolve_generic_params_from_outer_item_self_ty_alias)]
+ SelfTyAlias(#[primary_span] Span),
+ #[label(resolve_generic_params_from_outer_item_ty_param)]
+ TyParam(#[primary_span] Span),
+ #[label(resolve_generic_params_from_outer_item_const_param)]
+ ConstParam(#[primary_span] Span),
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(resolve_suggestion, code = "{snippet}", applicability = "maybe-incorrect")]
+pub(crate) struct GenericParamsFromOuterItemSugg {
+ #[primary_span]
+ pub(crate) span: Span,
+ pub(crate) snippet: String,
+}
+
+#[derive(Diagnostic)]
#[diag(resolve_name_is_already_used_as_generic_parameter, code = "E0403")]
pub(crate) struct NameAlreadyUsedInParameterList {
#[primary_span]
@@ -655,6 +689,16 @@ pub(crate) struct CannotDetermineImportResolution {
}
#[derive(Diagnostic)]
+#[diag(resolve_cannot_determine_macro_resolution)]
+#[note]
+pub(crate) struct CannotDetermineMacroResolution {
+ #[primary_span]
+ pub(crate) span: Span,
+ pub(crate) kind: &'static str,
+ pub(crate) path: String,
+}
+
+#[derive(Diagnostic)]
#[diag(resolve_cannot_be_reexported_private, code = "E0364")]
pub(crate) struct CannotBeReexportedPrivate {
#[primary_span]
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 3bd9cea27..54388f80f 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -1,7 +1,5 @@
use rustc_ast::{self as ast, NodeId};
-use rustc_feature::is_builtin_attr_name;
use rustc_hir::def::{DefKind, Namespace, NonMacroAttrKind, PartialRes, PerNS};
-use rustc_hir::PrimTy;
use rustc_middle::bug;
use rustc_middle::ty;
use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK;
@@ -9,7 +7,7 @@ use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_span::def_id::LocalDefId;
use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext};
use rustc_span::symbol::{kw, Ident};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::Span;
use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst};
use crate::late::{
@@ -423,32 +421,22 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
orig_ident.span.ctxt(),
|this, scope, use_prelude, ctxt| {
let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt));
- let ok = |res, span, arenas| {
- Ok((
- (res, Visibility::Public, span, LocalExpnId::ROOT).to_name_binding(arenas),
- Flags::empty(),
- ))
- };
let result = match scope {
Scope::DeriveHelpers(expn_id) => {
- if let Some(attr) = this
- .helper_attrs
- .get(&expn_id)
- .and_then(|attrs| attrs.iter().rfind(|i| ident == **i))
- {
- let binding = (
- Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
- Visibility::Public,
- attr.span,
- expn_id,
- )
- .to_name_binding(this.arenas);
+ if let Some(binding) = this.helper_attrs.get(&expn_id).and_then(|attrs| {
+ attrs.iter().rfind(|(i, _)| ident == *i).map(|(_, binding)| *binding)
+ }) {
Ok((binding, Flags::empty()))
} else {
Err(Determinacy::Determined)
}
}
Scope::DeriveHelpersCompat => {
+ // FIXME: Try running this logic eariler, to allocate name bindings for
+ // legacy derive helpers when creating an attribute invocation with
+ // following derives. Legacy derive helpers are not common, so it shouldn't
+ // affect performance. It should also allow to remove the `derives`
+ // component from `ParentScope`.
let mut result = Err(Determinacy::Determined);
for derive in parent_scope.derives {
let parent_scope = &ParentScope { derives: &[], ..*parent_scope };
@@ -461,11 +449,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
) {
Ok((Some(ext), _)) => {
if ext.helper_attrs.contains(&ident.name) {
- result = ok(
+ let binding = (
Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat),
+ Visibility::Public,
derive.span,
- this.arenas,
- );
+ LocalExpnId::ROOT,
+ )
+ .to_name_binding(this.arenas);
+ result = Ok((binding, Flags::empty()));
break;
}
}
@@ -562,17 +553,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
)),
}
}
- Scope::BuiltinAttrs => {
- if is_builtin_attr_name(ident.name) {
- ok(
- Res::NonMacroAttr(NonMacroAttrKind::Builtin(ident.name)),
- DUMMY_SP,
- this.arenas,
- )
- } else {
- Err(Determinacy::Determined)
- }
- }
+ Scope::BuiltinAttrs => match this.builtin_attrs_bindings.get(&ident.name) {
+ Some(binding) => Ok((*binding, Flags::empty())),
+ None => Err(Determinacy::Determined),
+ },
Scope::ExternPrelude => {
match this.extern_prelude_get(ident, finalize.is_some()) {
Some(binding) => Ok((binding, Flags::empty())),
@@ -581,8 +565,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
)),
}
}
- Scope::ToolPrelude => match this.registered_tools.get(&ident).cloned() {
- Some(ident) => ok(Res::ToolMod, ident.span, this.arenas),
+ Scope::ToolPrelude => match this.registered_tool_bindings.get(&ident) {
+ Some(binding) => Ok((*binding, Flags::empty())),
None => Err(Determinacy::Determined),
},
Scope::StdLibPrelude => {
@@ -603,8 +587,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
result
}
- Scope::BuiltinTypes => match PrimTy::from_name(ident.name) {
- Some(prim_ty) => ok(Res::PrimTy(prim_ty), DUMMY_SP, this.arenas),
+ Scope::BuiltinTypes => match this.builtin_types_bindings.get(&ident.name) {
+ Some(binding) => Ok((*binding, Flags::empty())),
None => Err(Determinacy::Determined),
},
};
@@ -842,9 +826,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if ns == TypeNS {
if ident.name == kw::Crate || ident.name == kw::DollarCrate {
let module = self.resolve_crate_root(ident);
- let binding = (module, Visibility::Public, module.span, LocalExpnId::ROOT)
- .to_name_binding(self.arenas);
- return Ok(binding);
+ return Ok(self.module_self_bindings[&module]);
} else if ident.name == kw::Super || ident.name == kw::SelfLower {
// FIXME: Implement these with renaming requirements so that e.g.
// `use super;` doesn't work, but `use super as name;` does.
@@ -990,9 +972,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// progress, we have to ignore those potential unresolved invocations from other modules
// 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) = binding {
- if !unexpanded_macros || ns == MacroNS || restricted_shadowing {
+ if binding.determined() || ns == MacroNS || restricted_shadowing {
return check_usable(self, binding);
} else {
return Err((Undetermined, Weak::No));
@@ -1009,7 +990,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// Check if one of unexpanded macros can still define the name,
// if it can then our "no resolution" result is not determined and can be invalidated.
- if unexpanded_macros {
+ if !module.unexpanded_invocations.borrow().is_empty() {
return Err((Undetermined, Weak::Yes));
}
@@ -1247,10 +1228,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if let Some(span) = finalize {
self.report_error(
span,
- ResolutionError::GenericParamsFromOuterFunction(
- res,
- has_generic_params,
- ),
+ ResolutionError::GenericParamsFromOuterItem(res, has_generic_params),
);
}
return Res::Err;
@@ -1314,10 +1292,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if let Some(span) = finalize {
self.report_error(
span,
- ResolutionError::GenericParamsFromOuterFunction(
- res,
- has_generic_params,
- ),
+ ResolutionError::GenericParamsFromOuterItem(res, has_generic_params),
);
}
return Res::Err;
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index a175d9f6c..d271519a8 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -319,10 +319,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// We should replace the `old_binding` with `binding` regardless
// of whether they has same resolution or not when they are
// imported from the same glob-import statement.
- // However we currently using `Some(old_binding)` for back compact
- // purposes.
- // This case can be removed after once `Undetermined` is prepared
- // for glob-imports.
+ resolution.binding = Some(binding);
} else if res != old_binding.res() {
let binding = if warn_ambiguity {
this.warn_ambiguity(
@@ -805,13 +802,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// For better failure detection, pretend that the import will
// not define any names while resolving its module path.
let orig_vis = import.vis.take();
- let binding = this.resolve_ident_in_module(
+ let binding = this.maybe_resolve_ident_in_module(
module,
source,
ns,
&import.parent_scope,
- None,
- None,
);
import.vis.set(orig_vis);
source_bindings[ns].set(binding);
@@ -996,9 +991,9 @@ 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.tcx)
- {
- self.lint_buffer.buffer_lint(UNUSED_IMPORTS, id, import.span, fluent::resolve_glob_import_doesnt_reexport);
- }
+ {
+ self.lint_buffer.buffer_lint(UNUSED_IMPORTS, id, import.span, fluent::resolve_glob_import_doesnt_reexport);
+ }
return None;
}
_ => unreachable!(),
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index c87db96a5..15ec727e4 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -311,6 +311,10 @@ enum LifetimeRibKind {
/// error on default object bounds (e.g., `Box<dyn Foo>`).
AnonymousReportError,
+ /// Resolves elided lifetimes to `'static`, but gives a warning that this behavior
+ /// is a bug and will be reverted soon.
+ AnonymousWarn(NodeId),
+
/// Signal we cannot find which should be the anonymous lifetime.
ElisionFailure,
@@ -470,7 +474,7 @@ impl<'a> PathSource<'a> {
| DefKind::Enum
| DefKind::Trait
| DefKind::TraitAlias
- | DefKind::TyAlias { .. }
+ | DefKind::TyAlias
| DefKind::AssocTy
| DefKind::TyParam
| DefKind::OpaqueTy
@@ -509,7 +513,7 @@ impl<'a> PathSource<'a> {
DefKind::Struct
| DefKind::Union
| DefKind::Variant
- | DefKind::TyAlias { .. }
+ | DefKind::TyAlias
| DefKind::AssocTy,
_,
) | Res::SelfTyParam { .. }
@@ -768,9 +772,10 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
self.r.record_partial_res(ty.id, PartialRes::new(res));
visit::walk_ty(self, ty)
}
- TyKind::ImplTrait(..) => {
+ TyKind::ImplTrait(node_id, _) => {
let candidates = self.lifetime_elision_candidates.take();
visit::walk_ty(self, ty);
+ self.record_lifetime_params_for_impl_trait(*node_id);
self.lifetime_elision_candidates = candidates;
}
TyKind::TraitObject(bounds, ..) => {
@@ -905,8 +910,8 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
&sig.decl.output,
);
- if let Some((async_node_id, span)) = sig.header.asyncness.opt_return_id() {
- this.record_lifetime_params_for_impl_trait(async_node_id, span);
+ if let Some((async_node_id, _)) = sig.header.asyncness.opt_return_id() {
+ this.record_lifetime_params_for_impl_trait(async_node_id);
}
},
);
@@ -947,8 +952,8 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
&declaration.output,
);
- if let Some((async_node_id, span)) = async_node_id {
- this.record_lifetime_params_for_impl_trait(async_node_id, span);
+ if let Some((async_node_id, _)) = async_node_id {
+ this.record_lifetime_params_for_impl_trait(async_node_id);
}
},
);
@@ -1104,6 +1109,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
}
},
AssocConstraintKind::Bound { ref bounds } => {
+ self.record_lifetime_params_for_impl_trait(constraint.id);
walk_list!(self, visit_param_bound, bounds, BoundKind::Bound);
}
}
@@ -1148,6 +1154,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
}
LifetimeRibKind::AnonymousCreateParameter { .. }
| LifetimeRibKind::AnonymousReportError
+ | LifetimeRibKind::AnonymousWarn(_)
| LifetimeRibKind::Elided(_)
| LifetimeRibKind::ElisionFailure
| LifetimeRibKind::ConcreteAnonConst(_)
@@ -1515,6 +1522,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
// lifetime would be illegal.
LifetimeRibKind::Item
| LifetimeRibKind::AnonymousReportError
+ | LifetimeRibKind::AnonymousWarn(_)
| LifetimeRibKind::ElisionFailure => Some(LifetimeUseSet::Many),
// An anonymous lifetime is legal here, and bound to the right
// place, go ahead.
@@ -1576,7 +1584,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
| LifetimeRibKind::Elided(_)
| LifetimeRibKind::Generics { .. }
| LifetimeRibKind::ElisionFailure
- | LifetimeRibKind::AnonymousReportError => {}
+ | LifetimeRibKind::AnonymousReportError
+ | LifetimeRibKind::AnonymousWarn(_) => {}
}
}
@@ -1616,6 +1625,23 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
self.record_lifetime_res(lifetime.id, res, elision_candidate);
return;
}
+ LifetimeRibKind::AnonymousWarn(node_id) => {
+ let msg = if elided {
+ "`&` without an explicit lifetime name cannot be used here"
+ } else {
+ "`'_` cannot be used here"
+ };
+ self.r.lint_buffer.buffer_lint_with_diagnostic(
+ lint::builtin::ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
+ node_id,
+ lifetime.ident.span,
+ msg,
+ lint::BuiltinLintDiagnostics::AssociatedConstElidedLifetime {
+ elided,
+ span: lifetime.ident.span,
+ },
+ );
+ }
LifetimeRibKind::AnonymousReportError => {
let (msg, note) = if elided {
(
@@ -1740,7 +1766,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
Res::Def(DefKind::Struct, def_id)
| Res::Def(DefKind::Union, def_id)
| Res::Def(DefKind::Enum, def_id)
- | Res::Def(DefKind::TyAlias { .. }, def_id)
+ | Res::Def(DefKind::TyAlias, def_id)
| Res::Def(DefKind::Trait, def_id)
if i + 1 == proj_start =>
{
@@ -1811,7 +1837,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
//
// impl Foo for std::cell::Ref<u32> // note lack of '_
// async fn foo(_: std::cell::Ref<u32>) { ... }
- LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. } => {
+ LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. }
+ | LifetimeRibKind::AnonymousWarn(_) => {
let sess = self.r.tcx.sess;
let mut err = rustc_errors::struct_span_err!(
sess,
@@ -2423,7 +2450,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
ItemKind::Const(box ast::ConstItem { ref generics, ref ty, ref expr, .. }) => {
self.with_generic_param_rib(
&generics.params,
- RibKind::Item(HasGenericParams::Yes(generics.span)),
+ RibKind::Item(if self.r.tcx.features().generic_const_items {
+ HasGenericParams::Yes(generics.span)
+ } else {
+ HasGenericParams::No
+ }),
LifetimeRibKind::Generics {
binder: item.id,
kind: LifetimeBinderKind::ConstItem,
@@ -2898,7 +2929,6 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
match &item.kind {
AssocItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => {
debug!("resolve_implementation AssocItemKind::Const");
-
self.with_generic_param_rib(
&generics.params,
RibKind::AssocItem,
@@ -2908,28 +2938,30 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
kind: LifetimeBinderKind::ConstItem,
},
|this| {
- // If this is a trait impl, ensure the const
- // exists in trait
- this.check_trait_item(
- item.id,
- item.ident,
- &item.kind,
- ValueNS,
- item.span,
- seen_trait_items,
- |i, s, c| ConstNotMemberOfTrait(i, s, c),
- );
+ this.with_lifetime_rib(LifetimeRibKind::AnonymousWarn(item.id), |this| {
+ // If this is a trait impl, ensure the const
+ // exists in trait
+ this.check_trait_item(
+ item.id,
+ item.ident,
+ &item.kind,
+ ValueNS,
+ item.span,
+ seen_trait_items,
+ |i, s, c| ConstNotMemberOfTrait(i, s, c),
+ );
- this.visit_generics(generics);
- this.visit_ty(ty);
- if let Some(expr) = expr {
- // We allow arbitrary const expressions inside of associated consts,
- // even if they are potentially not const evaluatable.
- //
- // Type parameters can already be used and as associated consts are
- // not used as part of the type system, this is far less surprising.
- this.resolve_const_body(expr, None);
- }
+ this.visit_generics(generics);
+ this.visit_ty(ty);
+ if let Some(expr) = expr {
+ // We allow arbitrary const expressions inside of associated consts,
+ // even if they are potentially not const evaluatable.
+ //
+ // Type parameters can already be used and as associated consts are
+ // not used as part of the type system, this is far less surprising.
+ this.resolve_const_body(expr, None);
+ }
+ });
},
);
}
@@ -4108,6 +4140,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
});
}
+ fn resolve_expr_field(&mut self, f: &'ast ExprField, e: &'ast Expr) {
+ self.resolve_expr(&f.expr, Some(e));
+ self.visit_ident(f.ident);
+ walk_list!(self, visit_attribute, f.attrs.iter());
+ }
+
fn resolve_expr(&mut self, expr: &'ast Expr, parent: Option<&'ast Expr>) {
// First, record candidate traits for this expression if it could
// result in the invocation of a method call.
@@ -4123,7 +4161,19 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
ExprKind::Struct(ref se) => {
self.smart_resolve_path(expr.id, &se.qself, &se.path, PathSource::Struct);
- visit::walk_expr(self, expr);
+ // This is the same as `visit::walk_expr(self, expr);`, but we want to pass the
+ // parent in for accurate suggestions when encountering `Foo { bar }` that should
+ // have been `Foo { bar: self.bar }`.
+ if let Some(qself) = &se.qself {
+ self.visit_ty(&qself.ty);
+ }
+ self.visit_path(&se.path, expr.id);
+ walk_list!(self, resolve_expr_field, &se.fields, expr);
+ match &se.rest {
+ StructRest::Base(expr) => self.visit_expr(expr),
+ StructRest::Rest(_span) => {}
+ StructRest::None => {}
+ }
}
ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => {
@@ -4148,7 +4198,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
self.resolve_expr(e, Some(&expr));
}
- ExprKind::Let(ref pat, ref scrutinee, _) => {
+ ExprKind::Let(ref pat, ref scrutinee, _, _) => {
self.visit_expr(scrutinee);
self.resolve_pattern_top(pat, PatternSource::Let);
}
@@ -4336,7 +4386,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
/// We include all lifetime parameters, either named or "Fresh".
/// The order of those parameters does not matter, as long as it is
/// deterministic.
- fn record_lifetime_params_for_impl_trait(&mut self, impl_trait_node_id: NodeId, span: Span) {
+ fn record_lifetime_params_for_impl_trait(&mut self, impl_trait_node_id: NodeId) {
let mut extra_lifetime_params = vec![];
for rib in self.lifetime_ribs.iter().rev() {
@@ -4349,14 +4399,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
extra_lifetime_params.extend(earlier_fresh);
}
}
- LifetimeRibKind::Generics { .. } => {}
- _ => {
- // We are in a function definition. We should only find `Generics`
- // and `AnonymousCreateParameter` inside the innermost `Item`.
- span_bug!(span, "unexpected rib kind: {:?}", rib.kind)
- }
+ _ => {}
}
}
+
self.r.extra_lifetime_params_map.insert(impl_trait_node_id, extra_lifetime_params);
}
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index c34b7df9b..bc5f8a37b 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -41,7 +41,7 @@ type Res = def::Res<ast::NodeId>;
/// A field or associated item from self type suggested in case of resolution failure.
enum AssocSuggestion {
- Field,
+ Field(Span),
MethodWithSelf { called: bool },
AssocFn { called: bool },
AssocType,
@@ -51,7 +51,7 @@ enum AssocSuggestion {
impl AssocSuggestion {
fn action(&self) -> &'static str {
match self {
- AssocSuggestion::Field => "use the available field",
+ AssocSuggestion::Field(_) => "use the available field",
AssocSuggestion::MethodWithSelf { called: true } => {
"call the method with the fully-qualified path"
}
@@ -186,7 +186,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
fallback_label: format!("not a {expected}"),
span,
span_label: match res {
- Res::Def(kind, def_id) if kind == DefKind::TyParam => {
+ Res::Def(DefKind::TyParam, def_id) => {
Some((self.r.def_span(def_id), "found this type parameter"))
}
_ => None,
@@ -214,7 +214,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
module: None,
}
} else {
- let item_span = path.last().unwrap().ident.span;
+ let mut span_label = None;
+ let item_ident = path.last().unwrap().ident;
+ let item_span = item_ident.span;
let (mod_prefix, mod_str, module, suggestion) = if path.len() == 1 {
debug!(?self.diagnostic_metadata.current_impl_items);
debug!(?self.diagnostic_metadata.current_function);
@@ -224,32 +226,75 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
&& let FnKind::Fn(_, _, sig, ..) = fn_kind
&& let Some(items) = self.diagnostic_metadata.current_impl_items
&& let Some(item) = items.iter().find(|i| {
- if let AssocItemKind::Fn(..) | AssocItemKind::Const(..) = &i.kind
- && i.ident.name == item_str.name
- // don't suggest if the item is in Fn signature arguments
- // issue #112590
+ i.ident.name == item_str.name
+ // Don't suggest if the item is in Fn signature arguments (#112590).
&& !sig.span.contains(item_span)
- {
- debug!(?item_str.name);
- return true
- }
- false
})
{
- let self_sugg = match &item.kind {
- AssocItemKind::Fn(fn_) if fn_.sig.decl.has_self() => "self.",
- _ => "Self::",
+ let sp = item_span.shrink_to_lo();
+
+ // Account for `Foo { field }` when suggesting `self.field` so we result on
+ // `Foo { field: self.field }`.
+ let field = match source {
+ PathSource::Expr(Some(Expr { kind: ExprKind::Struct(expr), .. })) => {
+ expr.fields.iter().find(|f| f.ident == item_ident)
+ }
+ _ => None,
+ };
+ let pre = if let Some(field) = field && field.is_shorthand {
+ format!("{item_ident}: ")
+ } else {
+ String::new()
+ };
+ // Ensure we provide a structured suggestion for an assoc fn only for
+ // expressions that are actually a fn call.
+ let is_call = match field {
+ Some(ast::ExprField { expr, .. }) => {
+ matches!(expr.kind, ExprKind::Call(..))
+ }
+ _ => matches!(
+ source,
+ PathSource::Expr(Some(Expr { kind: ExprKind::Call(..), ..})),
+ ),
};
- Some((
- item_span.shrink_to_lo(),
- match &item.kind {
- AssocItemKind::Fn(..) => "consider using the associated function",
- AssocItemKind::Const(..) => "consider using the associated constant",
- _ => unreachable!("item kind was filtered above"),
- },
- self_sugg.to_string()
- ))
+ match &item.kind {
+ AssocItemKind::Fn(fn_)
+ if (!sig.decl.has_self() || !is_call) && fn_.sig.decl.has_self() => {
+ // Ensure that we only suggest `self.` if `self` is available,
+ // you can't call `fn foo(&self)` from `fn bar()` (#115992).
+ // We also want to mention that the method exists.
+ span_label = Some((
+ item.ident.span,
+ "a method by that name is available on `Self` here",
+ ));
+ None
+ }
+ AssocItemKind::Fn(fn_)
+ if !fn_.sig.decl.has_self() && !is_call => {
+ span_label = Some((
+ item.ident.span,
+ "an associated function by that name is available on `Self` here",
+ ));
+ None
+ }
+ AssocItemKind::Fn(fn_) if fn_.sig.decl.has_self() => Some((
+ sp,
+ "consider using the method on `Self`",
+ format!("{pre}self."),
+ )),
+ AssocItemKind::Fn(_) => Some((
+ sp,
+ "consider using the associated function on `Self`",
+ format!("{pre}Self::"),
+ )),
+ AssocItemKind::Const(..) => Some((
+ sp,
+ "consider using the associated constant on `Self`",
+ format!("{pre}Self::"),
+ )),
+ _ => None
+ }
} else {
None
};
@@ -314,7 +359,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
msg: format!("cannot find {expected} `{item_str}` in {mod_prefix}{mod_str}"),
fallback_label,
span: item_span,
- span_label: None,
+ span_label,
could_be_expr: false,
suggestion,
module,
@@ -611,17 +656,30 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call())
{
let self_is_available = self.self_value_is_available(path[0].ident.span);
+ // Account for `Foo { field }` when suggesting `self.field` so we result on
+ // `Foo { field: self.field }`.
+ let pre = match source {
+ PathSource::Expr(Some(Expr { kind: ExprKind::Struct(expr), .. }))
+ if expr
+ .fields
+ .iter()
+ .any(|f| f.ident == path[0].ident && f.is_shorthand) =>
+ {
+ format!("{path_str}: ")
+ }
+ _ => String::new(),
+ };
match candidate {
- AssocSuggestion::Field => {
+ AssocSuggestion::Field(field_span) => {
if self_is_available {
- err.span_suggestion(
- span,
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
"you might have meant to use the available field",
- format!("self.{path_str}"),
+ format!("{pre}self."),
Applicability::MachineApplicable,
);
} else {
- err.span_label(span, "a field by this name exists in `Self`");
+ err.span_label(field_span, "a field by that name exists in `Self`");
}
}
AssocSuggestion::MethodWithSelf { called } if self_is_available => {
@@ -630,10 +688,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
} else {
"you might have meant to refer to the method"
};
- err.span_suggestion(
- span,
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
msg,
- format!("self.{path_str}"),
+ "self.".to_string(),
Applicability::MachineApplicable,
);
}
@@ -641,10 +699,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
| AssocSuggestion::AssocFn { .. }
| AssocSuggestion::AssocConst
| AssocSuggestion::AssocType => {
- err.span_suggestion(
- span,
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
format!("you might have meant to {}", candidate.action()),
- format!("Self::{path_str}"),
+ "Self::".to_string(),
Applicability::MachineApplicable,
);
}
@@ -1419,7 +1477,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
(Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => {
err.span_label(span, fallback_label.to_string());
}
- (Res::Def(DefKind::TyAlias { .. }, def_id), PathSource::Trait(_)) => {
+ (Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => {
err.span_label(span, "type aliases cannot be used as traits");
if self.r.tcx.sess.is_nightly_build() {
let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \
@@ -1588,7 +1646,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
err.span_label(span, fallback_label.to_string());
err.note("can't use `Self` as a constructor, you must use the implemented struct");
}
- (Res::Def(DefKind::TyAlias { .. } | DefKind::AssocTy, _), _) if ns == ValueNS => {
+ (Res::Def(DefKind::TyAlias | DefKind::AssocTy, _), _) if ns == ValueNS => {
err.note("can't use a type alias as a constructor");
}
_ => return false,
@@ -1657,11 +1715,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
resolution.full_res()
{
if let Some(field_ids) = self.r.field_def_ids(did) {
- if field_ids
+ if let Some(field_id) = field_ids
.iter()
- .any(|&field_id| ident.name == self.r.tcx.item_name(field_id))
+ .find(|&&field_id| ident.name == self.r.tcx.item_name(field_id))
{
- return Some(AssocSuggestion::Field);
+ return Some(AssocSuggestion::Field(self.r.def_span(*field_id)));
}
}
}
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 76e54e60d..949c6ab5a 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -18,7 +18,7 @@
#![recursion_limit = "256"]
#![allow(rustdoc::private_intra_doc_links)]
#![allow(rustc::potential_query_instability)]
-#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![allow(internal_features)]
#[macro_use]
extern crate tracing;
@@ -34,18 +34,20 @@ use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArg
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_data_structures::sync::{FreezeReadGuard, Lrc};
use rustc_errors::{
Applicability, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, SubdiagnosticMessage,
};
use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind};
+use rustc_feature::BUILTIN_ATTRIBUTES;
use rustc_fluent_macro::fluent_messages;
use rustc_hir::def::Namespace::{self, *};
+use rustc_hir::def::NonMacroAttrKind;
use rustc_hir::def::{self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, PartialRes, PerNS};
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;
+use rustc_hir::{PrimTy, TraitCandidate};
use rustc_index::IndexVec;
use rustc_metadata::creader::{CStore, CrateLoader};
use rustc_middle::metadata::ModChild;
@@ -184,8 +186,8 @@ struct BindingError {
#[derive(Debug)]
enum ResolutionError<'a> {
- /// Error E0401: can't use type or const parameters from outer function.
- GenericParamsFromOuterFunction(Res, HasGenericParams),
+ /// Error E0401: can't use type or const parameters from outer item.
+ GenericParamsFromOuterItem(Res, HasGenericParams),
/// Error E0403: the name is already used for a type or const parameter in this generic
/// parameter list.
NameAlreadyUsedInParameterList(Symbol, Span),
@@ -517,7 +519,7 @@ struct ModuleData<'a> {
/// All modules are unique and allocated on a same arena,
/// so we can use referential equality to compare them.
-#[derive(Clone, Copy, PartialEq)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[rustc_pass_by_value]
struct Module<'a>(Interned<'a, ModuleData<'a>>);
@@ -879,14 +881,33 @@ impl<'a> NameBindingData<'a> {
invoc_parent_expansion.is_descendant_of(self_parent_expansion);
!(certainly_before_other_or_simultaneously || certainly_before_invoc_or_simultaneously)
}
+
+ // Its purpose is to postpone the determination of a single binding because
+ // we can't predict whether it will be overwritten by recently expanded macros.
+ // FIXME: How can we integrate it with the `update_resolution`?
+ fn determined(&self) -> bool {
+ match &self.kind {
+ NameBindingKind::Import { binding, import, .. } if import.is_glob() => {
+ import.parent_scope.module.unexpanded_invocations.borrow().is_empty()
+ && binding.determined()
+ }
+ _ => true,
+ }
+ }
}
#[derive(Default, Clone)]
struct ExternPreludeEntry<'a> {
- extern_crate_item: Option<NameBinding<'a>>,
+ binding: Option<NameBinding<'a>>,
introduced_by_item: bool,
}
+impl ExternPreludeEntry<'_> {
+ fn is_import(&self) -> bool {
+ self.binding.is_some_and(|binding| binding.is_import())
+ }
+}
+
/// Used for better errors for E0773
enum BuiltinMacroState {
NotYetSeen(SyntaxExtensionKind),
@@ -981,7 +1002,6 @@ pub struct Resolver<'a, 'tcx> {
glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
/// Visibilities in "lowered" form, for all entities that have them.
visibilities: FxHashMap<LocalDefId, ty::Visibility>,
- has_pub_restricted: bool,
used_imports: FxHashSet<NodeId>,
maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
@@ -996,6 +1016,12 @@ pub struct Resolver<'a, 'tcx> {
arenas: &'a ResolverArenas<'a>,
dummy_binding: NameBinding<'a>,
+ builtin_types_bindings: FxHashMap<Symbol, NameBinding<'a>>,
+ builtin_attrs_bindings: FxHashMap<Symbol, NameBinding<'a>>,
+ registered_tool_bindings: FxHashMap<Ident, NameBinding<'a>>,
+ /// Binding for implicitly declared names that come with a module,
+ /// like `self` (not yet used), or `crate`/`$crate` (for root modules).
+ module_self_bindings: FxHashMap<Module<'a>, NameBinding<'a>>,
used_extern_options: FxHashSet<Symbol>,
macro_names: FxHashSet<Ident>,
@@ -1033,7 +1059,7 @@ pub struct Resolver<'a, 'tcx> {
/// `macro_rules` scopes produced by `macro_rules` item definitions.
macro_rules_scopes: FxHashMap<LocalDefId, MacroRulesScopeRef<'a>>,
/// Helper attributes that are in scope for the given expansion.
- helper_attrs: FxHashMap<LocalExpnId, Vec<Ident>>,
+ helper_attrs: FxHashMap<LocalExpnId, Vec<(Ident, NameBinding<'a>)>>,
/// Ready or in-progress results of resolving paths inside the `#[derive(...)]` attribute
/// with the given `ExpnId`.
derive_data: FxHashMap<LocalExpnId, DeriveData>,
@@ -1111,6 +1137,7 @@ impl<'a> ResolverArenas<'a> {
span: Span,
no_implicit_prelude: bool,
module_map: &mut FxHashMap<DefId, Module<'a>>,
+ module_self_bindings: &mut FxHashMap<Module<'a>, NameBinding<'a>>,
) -> Module<'a> {
let module = Module(Interned::new_unchecked(self.modules.alloc(ModuleData::new(
parent,
@@ -1125,6 +1152,9 @@ impl<'a> ResolverArenas<'a> {
}
if let Some(def_id) = def_id {
module_map.insert(def_id, module);
+ let vis = ty::Visibility::<DefId>::Public;
+ let binding = (module, vis, module.span, LocalExpnId::ROOT).to_name_binding(self);
+ module_self_bindings.insert(module, binding);
}
module
}
@@ -1236,6 +1266,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
) -> Resolver<'a, 'tcx> {
let root_def_id = CRATE_DEF_ID.to_def_id();
let mut module_map = FxHashMap::default();
+ let mut module_self_bindings = FxHashMap::default();
let graph_root = arenas.new_module(
None,
ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty),
@@ -1243,6 +1274,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
crate_span,
attr::contains_name(attrs, sym::no_implicit_prelude),
&mut module_map,
+ &mut module_self_bindings,
);
let empty_module = arenas.new_module(
None,
@@ -1251,6 +1283,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
DUMMY_SP,
true,
&mut FxHashMap::default(),
+ &mut FxHashMap::default(),
);
let mut visibilities = FxHashMap::default();
@@ -1283,6 +1316,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let registered_tools = tcx.registered_tools(());
let features = tcx.features();
+ let pub_vis = ty::Visibility::<DefId>::Public;
let mut resolver = Resolver {
tcx,
@@ -1320,7 +1354,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
glob_map: Default::default(),
visibilities,
- has_pub_restricted: false,
used_imports: FxHashSet::default(),
maybe_unused_trait_imports: Default::default(),
@@ -1330,14 +1363,33 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
macro_expanded_macro_export_errors: BTreeSet::new(),
arenas,
- dummy_binding: arenas.alloc_name_binding(NameBindingData {
- kind: NameBindingKind::Res(Res::Err),
- ambiguity: None,
- warn_ambiguity: false,
- expansion: LocalExpnId::ROOT,
- span: DUMMY_SP,
- vis: ty::Visibility::Public,
- }),
+ dummy_binding: (Res::Err, pub_vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(arenas),
+ builtin_types_bindings: PrimTy::ALL
+ .iter()
+ .map(|prim_ty| {
+ let binding = (Res::PrimTy(*prim_ty), pub_vis, DUMMY_SP, LocalExpnId::ROOT)
+ .to_name_binding(arenas);
+ (prim_ty.name(), binding)
+ })
+ .collect(),
+ builtin_attrs_bindings: BUILTIN_ATTRIBUTES
+ .iter()
+ .map(|builtin_attr| {
+ let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin(builtin_attr.name));
+ let binding =
+ (res, pub_vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(arenas);
+ (builtin_attr.name, binding)
+ })
+ .collect(),
+ registered_tool_bindings: registered_tools
+ .iter()
+ .map(|ident| {
+ let binding = (Res::ToolMod, pub_vis, ident.span, LocalExpnId::ROOT)
+ .to_name_binding(arenas);
+ (*ident, binding)
+ })
+ .collect(),
+ module_self_bindings,
used_extern_options: Default::default(),
macro_names: FxHashSet::default(),
@@ -1407,7 +1459,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
no_implicit_prelude: bool,
) -> Module<'a> {
let module_map = &mut self.module_map;
- self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude, module_map)
+ let module_self_bindings = &mut self.module_self_bindings;
+ self.arenas.new_module(
+ parent,
+ kind,
+ expn_id,
+ span,
+ no_implicit_prelude,
+ module_map,
+ module_self_bindings,
+ )
}
fn next_node_id(&mut self) -> NodeId {
@@ -1436,7 +1497,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect();
let expn_that_defined = self.expn_that_defined;
let visibilities = self.visibilities;
- let has_pub_restricted = self.has_pub_restricted;
let extern_crate_map = self.extern_crate_map;
let maybe_unused_trait_imports = self.maybe_unused_trait_imports;
let glob_map = self.glob_map;
@@ -1454,7 +1514,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let global_ctxt = ResolverGlobalCtxt {
expn_that_defined,
visibilities,
- has_pub_restricted,
effective_visibilities,
extern_crate_map,
module_children: self.module_children,
@@ -1498,7 +1557,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
))
}
- fn cstore(&self) -> MappedReadGuard<'_, CStore> {
+ fn cstore(&self) -> FreezeReadGuard<'_, CStore> {
CStore::from_tcx(self.tcx)
}
@@ -1553,7 +1612,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
});
// Make sure we don't mutate the cstore from here on.
- self.tcx.untracked().cstore.leak();
+ self.tcx.untracked().cstore.freeze();
}
fn traits_in_scope(
@@ -1727,7 +1786,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// but not introduce it, as used if they are accessed from lexical scope.
if is_lexical_scope {
if let Some(entry) = self.extern_prelude.get(&ident.normalize_to_macros_2_0()) {
- if !entry.introduced_by_item && entry.extern_crate_item == Some(used_binding) {
+ if !entry.introduced_by_item && entry.binding == Some(used_binding) {
return;
}
}
@@ -1885,12 +1944,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// Make sure `self`, `super` etc produce an error when passed to here.
return None;
}
- self.extern_prelude.get(&ident.normalize_to_macros_2_0()).cloned().and_then(|entry| {
- if let Some(binding) = entry.extern_crate_item {
- if finalize && entry.introduced_by_item {
- self.record_use(ident, binding, false);
+
+ let norm_ident = ident.normalize_to_macros_2_0();
+ let binding = self.extern_prelude.get(&norm_ident).cloned().and_then(|entry| {
+ Some(if let Some(binding) = entry.binding {
+ if finalize {
+ if !entry.is_import() {
+ self.crate_loader(|c| c.process_path_extern(ident.name, ident.span));
+ } else if entry.introduced_by_item {
+ self.record_use(ident, binding, false);
+ }
}
- Some(binding)
+ binding
} else {
let crate_id = if finalize {
let Some(crate_id) =
@@ -1903,10 +1968,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
self.crate_loader(|c| c.maybe_process_path_extern(ident.name))?
};
let crate_root = self.expect_module(crate_id.as_def_id());
- let vis = ty::Visibility::<LocalDefId>::Public;
- Some((crate_root, vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(self.arenas))
- }
- })
+ let vis = ty::Visibility::<DefId>::Public;
+ (crate_root, vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(self.arenas)
+ })
+ });
+
+ if let Some(entry) = self.extern_prelude.get_mut(&norm_ident) {
+ entry.binding = binding;
+ }
+
+ binding
}
/// Rustdoc uses this to resolve doc link paths in a recoverable way. `PathResult<'a>`
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 6a5b675b4..90ae08ce3 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -2,12 +2,13 @@
//! interface provided by `Resolver` to macro expander.
use crate::errors::{
- self, AddAsNonDerive, CannotFindIdentInThisScope, MacroExpectedFound, RemoveSurroundingDerive,
+ self, AddAsNonDerive, CannotDetermineMacroResolution, CannotFindIdentInThisScope,
+ 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 crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
use rustc_ast::expand::StrippedCfgItem;
use rustc_ast::{self as ast, attr, Crate, Inline, ItemKind, ModKind, NodeId};
use rustc_ast_pretty::pprust;
@@ -20,12 +21,12 @@ use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
use rustc_expand::compile_declarative_macro;
use rustc_expand::expand::{AstFragment, Invocation, InvocationKind, SupportsMacroExpansion};
use rustc_hir::def::{self, DefKind, NonMacroAttrKind};
-use rustc_hir::def_id::{CrateNum, LocalDefId};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
use rustc_middle::middle::stability;
use rustc_middle::ty::RegisteredTools;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{TyCtxt, Visibility};
use rustc_session::lint::builtin::{
- LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE, UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
+ LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE, UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
};
use rustc_session::lint::builtin::{UNUSED_MACROS, UNUSED_MACRO_RULES};
use rustc_session::lint::BuiltinLintDiagnostics;
@@ -401,8 +402,17 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
}
// Sort helpers in a stable way independent from the derive resolution order.
entry.helper_attrs.sort_by_key(|(i, _)| *i);
- self.helper_attrs
- .insert(expn_id, entry.helper_attrs.iter().map(|(_, ident)| *ident).collect());
+ let helper_attrs = entry
+ .helper_attrs
+ .iter()
+ .map(|(_, ident)| {
+ let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
+ let binding = (res, Visibility::<DefId>::Public, ident.span, expn_id)
+ .to_name_binding(self.arenas);
+ (*ident, binding)
+ })
+ .collect();
+ self.helper_attrs.insert(expn_id, helper_attrs);
// Mark this derive as having `Copy` either if it has `Copy` itself or if its parent derive
// has `Copy`, to support cases like `#[derive(Clone, Copy)] #[derive(Debug)]`.
if entry.has_derive_copy || self.has_derive_copy(parent_scope.expansion) {
@@ -600,9 +610,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if res == Res::NonMacroAttr(NonMacroAttrKind::Tool)
&& path.segments.len() >= 2
&& path.segments[0].ident.name == sym::diagnostic
+ && path.segments[1].ident.name != sym::on_unimplemented
{
self.tcx.sess.parse_sess.buffer_lint(
- UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
+ UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
path.segments[1].span(),
node_id,
"unknown diagnostic attribute",
@@ -710,13 +721,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// even if speculative `resolve_path` returned nothing previously, so we skip this
// less informative error if the privacy error is reported elsewhere.
if this.privacy_errors.is_empty() {
- let msg = format!(
- "cannot determine resolution for the {} `{}`",
- kind.descr(),
- Segment::names_to_string(path)
- );
- let msg_note = "import resolution is stuck, try simplifying macro imports";
- this.tcx.sess.struct_span_err(span, msg).note(msg_note).emit();
+ this.tcx.sess.emit_err(CannotDetermineMacroResolution {
+ span,
+ kind: kind.descr(),
+ path: Segment::names_to_string(path),
+ });
}
}
};
diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs
index ba7417b6d..7c41c32d0 100644
--- a/compiler/rustc_resolve/src/rustdoc.rs
+++ b/compiler/rustc_resolve/src/rustdoc.rs
@@ -2,9 +2,11 @@ use pulldown_cmark::{BrokenLink, CowStr, Event, LinkType, Options, Parser, Tag};
use rustc_ast as ast;
use rustc_ast::util::comments::beautify_doc_string;
use rustc_data_structures::fx::FxHashMap;
+use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::DefId;
use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::Span;
+use rustc_span::{InnerSpan, Span, DUMMY_SP};
+use std::ops::Range;
use std::{cmp, mem};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
@@ -462,3 +464,88 @@ fn collect_link_data<'input, 'callback>(
display_text.map(String::into_boxed_str)
}
+
+/// Returns a span encompassing all the document fragments.
+pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> {
+ if fragments.is_empty() {
+ return None;
+ }
+ let start = fragments[0].span;
+ if start == DUMMY_SP {
+ return None;
+ }
+ let end = fragments.last().expect("no doc strings provided").span;
+ Some(start.to(end))
+}
+
+/// Attempts to match a range of bytes from parsed markdown to a `Span` in the source code.
+///
+/// This method will return `None` if we cannot construct a span from the source map or if the
+/// fragments are not all sugared doc comments. It's difficult to calculate the correct span in
+/// that case due to escaping and other source features.
+pub fn source_span_for_markdown_range(
+ tcx: TyCtxt<'_>,
+ markdown: &str,
+ md_range: &Range<usize>,
+ fragments: &[DocFragment],
+) -> Option<Span> {
+ let is_all_sugared_doc = fragments.iter().all(|frag| frag.kind == DocFragmentKind::SugaredDoc);
+
+ if !is_all_sugared_doc {
+ return None;
+ }
+
+ let snippet = tcx.sess.source_map().span_to_snippet(span_of_fragments(fragments)?).ok()?;
+
+ let starting_line = markdown[..md_range.start].matches('\n').count();
+ let ending_line = starting_line + markdown[md_range.start..md_range.end].matches('\n').count();
+
+ // We use `split_terminator('\n')` instead of `lines()` when counting bytes so that we treat
+ // CRLF and LF line endings the same way.
+ let mut src_lines = snippet.split_terminator('\n');
+ let md_lines = markdown.split_terminator('\n');
+
+ // The number of bytes from the source span to the markdown span that are not part
+ // of the markdown, like comment markers.
+ let mut start_bytes = 0;
+ let mut end_bytes = 0;
+
+ 'outer: for (line_no, md_line) in md_lines.enumerate() {
+ loop {
+ let source_line = src_lines.next()?;
+ match source_line.find(md_line) {
+ Some(offset) => {
+ if line_no == starting_line {
+ start_bytes += offset;
+
+ if starting_line == ending_line {
+ break 'outer;
+ }
+ } else if line_no == ending_line {
+ end_bytes += offset;
+ break 'outer;
+ } else if line_no < starting_line {
+ start_bytes += source_line.len() - md_line.len();
+ } else {
+ end_bytes += source_line.len() - md_line.len();
+ }
+ break;
+ }
+ None => {
+ // Since this is a source line that doesn't include a markdown line,
+ // we have to count the newline that we split from earlier.
+ if line_no <= starting_line {
+ start_bytes += source_line.len() + 1;
+ } else {
+ end_bytes += source_line.len() + 1;
+ }
+ }
+ }
+ }
+ }
+
+ Some(span_of_fragments(fragments)?.from_inner(InnerSpan::new(
+ md_range.start + start_bytes,
+ md_range.end + start_bytes + end_bytes,
+ )))
+}