diff options
Diffstat (limited to 'compiler/rustc_resolve')
| -rw-r--r-- | compiler/rustc_resolve/src/build_reduced_graph.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/check_unused.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/diagnostics.rs | 137 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/ident.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/imports.rs | 140 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/late.rs | 193 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/late/diagnostics.rs | 70 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/lib.rs | 30 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/macros.rs | 31 |
9 files changed, 397 insertions, 220 deletions
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index ff63e4e33cb..2f432799022 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -41,6 +41,7 @@ impl<'a, Id: Into<DefId>> ToNameBinding<'a> arenas.alloc_name_binding(NameBindingData { kind: NameBindingKind::Module(self.0), ambiguity: None, + warn_ambiguity: false, vis: self.1.to_def_id(), span: self.2, expansion: self.3, @@ -53,6 +54,7 @@ impl<'a, Id: Into<DefId>> ToNameBinding<'a> for (Res, ty::Visibility<Id>, Span, arenas.alloc_name_binding(NameBindingData { kind: NameBindingKind::Res(self.0), ambiguity: None, + warn_ambiguity: false, vis: self.1.to_def_id(), span: self.2, expansion: self.3, @@ -69,7 +71,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { { let binding = def.to_name_binding(self.arenas); let key = self.new_disambiguated_key(ident, ns); - if let Err(old_binding) = self.try_define(parent, key, binding) { + if let Err(old_binding) = self.try_define(parent, key, binding, false) { self.report_conflict(parent, ident, ns, old_binding, binding); } } @@ -999,7 +1001,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { allow_shadowing: bool, ) { if self.r.macro_use_prelude.insert(name, binding).is_some() && !allow_shadowing { - let msg = format!("`{}` is already in scope", name); + let msg = format!("`{name}` is already in scope"); let note = "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)"; self.r.tcx.sess.struct_span_err(span, msg).note(note).emit(); diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 3228e8d52f0..7dbbd4c34ea 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -362,7 +362,7 @@ impl Resolver<'_, '_> { let mut span_snippets = spans .iter() .filter_map(|s| match tcx.sess.source_map().span_to_snippet(*s) { - Ok(s) => Some(format!("`{}`", s)), + Ok(s) => Some(format!("`{s}`")), _ => None, }) .collect::<Vec<String>>(); diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 2cfde2f62d8..cd1a9b934cf 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -5,10 +5,8 @@ use rustc_ast::{self as ast, Crate, ItemKind, ModKind, NodeId, Path, CRATE_NODE_ use rustc_ast::{MetaItemKind, NestedMetaItem}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{ - pluralize, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, -}; -use rustc_errors::{struct_span_err, SuggestionStyle}; +use rustc_errors::{pluralize, report_ambiguity_error, struct_span_err, SuggestionStyle}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS}; @@ -17,8 +15,9 @@ use rustc_hir::PrimTy; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE; +use rustc_session::lint::builtin::AMBIGUOUS_GLOB_IMPORTS; use rustc_session::lint::builtin::MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS; -use rustc_session::lint::BuiltinLintDiagnostics; +use rustc_session::lint::{AmbiguityErrorDiag, BuiltinLintDiagnostics}; use rustc_session::Session; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; @@ -135,7 +134,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } for ambiguity_error in &self.ambiguity_errors { - self.report_ambiguity_error(ambiguity_error); + let diag = self.ambiguity_diagnostics(ambiguity_error); + if ambiguity_error.warning { + let NameBindingKind::Import { import, .. } = ambiguity_error.b1.0.kind else { + unreachable!() + }; + self.lint_buffer.buffer_lint_with_diagnostic( + AMBIGUOUS_GLOB_IMPORTS, + import.root_id, + ambiguity_error.ident.span, + diag.msg.to_string(), + BuiltinLintDiagnostics::AmbiguousGlobImports { diag }, + ); + } else { + let mut err = struct_span_err!(self.tcx.sess, diag.span, E0659, "{}", &diag.msg); + report_ambiguity_error(&mut err, diag); + err.emit(); + } } let mut reported_spans = FxHashSet::default(); @@ -228,7 +243,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { (TypeNS, _) => "type", }; - let msg = format!("the name `{}` is defined multiple times", name); + let msg = format!("the name `{name}` is defined multiple times"); let mut err = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) { (true, true) => struct_span_err!(self.tcx.sess, span, E0259, "{}", msg), @@ -250,11 +265,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { container )); - err.span_label(span, format!("`{}` re{} here", name, new_participle)); + err.span_label(span, format!("`{name}` re{new_participle} here")); if !old_binding.span.is_dummy() && old_binding.span != span { err.span_label( self.tcx.sess.source_map().guess_head_span(old_binding.span), - format!("previous {} of the {} `{}` here", old_noun, old_kind, name), + format!("previous {old_noun} of the {old_kind} `{name}` here"), ); } @@ -343,15 +358,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { binding_span: Span, ) { let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() { - format!("Other{}", name) + format!("Other{name}") } else { - format!("other_{}", name) + format!("other_{name}") }; let mut suggestion = None; match import.kind { ImportKind::Single { type_ns_only: true, .. } => { - suggestion = Some(format!("self as {}", suggested_name)) + suggestion = Some(format!("self as {suggested_name}")) } ImportKind::Single { source, .. } => { if let Some(pos) = @@ -587,11 +602,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { 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); + let snippet = format!("<{name}>"); (span, snippet) } else { let span = sm.span_through_char(span, '<').shrink_to_hi(); - let snippet = format!("{}, ", name); + let snippet = format!("{name}, "); (span, snippet) }; // Suggest the modification to the user @@ -652,7 +667,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { name, ); for sp in target_sp { - err.span_label(sp, format!("pattern doesn't bind `{}`", name)); + err.span_label(sp, format!("pattern doesn't bind `{name}`")); } for sp in origin_sp { err.span_label(sp, "variable not in all patterns"); @@ -679,8 +694,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if import_suggestions.is_empty() { let help_msg = format!( "if you meant to match on a variant or a `const` item, consider \ - making the path in the pattern qualified: `path::to::ModOrType::{}`", - name, + making the path in the pattern qualified: `path::to::ModOrType::{name}`", ); err.span_help(span, help_msg); } @@ -938,8 +952,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let mut err = self.tcx.sess.struct_span_err_with_code( span, format!( - "item `{}` is an associated {}, which doesn't match its trait `{}`", - name, kind, trait_path, + "item `{name}` is an associated {kind}, which doesn't match its trait `{trait_path}`", ), code, ); @@ -1395,7 +1408,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let head_span = source_map.guess_head_span(span); err.subdiagnostic(ConsiderAddingADerive { span: head_span.shrink_to_lo(), - suggestion: format!("#[derive(Default)]\n") + suggestion: "#[derive(Default)]\n".to_string(), }); } for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] { @@ -1412,10 +1425,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { "a function-like macro".to_string() } Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => { - format!("an attribute: `#[{}]`", ident) + format!("an attribute: `#[{ident}]`") } Res::Def(DefKind::Macro(MacroKind::Derive), _) => { - format!("a derive macro: `#[derive({})]`", ident) + format!("a derive macro: `#[derive({ident})]`") } Res::ToolMod => { // Don't confuse the user with tool modules. @@ -1436,7 +1449,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if !import.span.is_dummy() { err.span_note( import.span, - format!("`{}` is imported here, but it is {}", ident, desc), + format!("`{ident}` is imported here, but it is {desc}"), ); // Silence the 'unused import' warning we might get, // since this diagnostic already covers that import. @@ -1444,7 +1457,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { return; } } - err.note(format!("`{}` is in scope, but it is {}", ident, desc)); + err.note(format!("`{ident}` is in scope, but it is {desc}")); return; } } @@ -1540,20 +1553,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - fn report_ambiguity_error(&self, ambiguity_error: &AmbiguityError<'_>) { - let AmbiguityError { kind, ident, b1, b2, misc1, misc2 } = *ambiguity_error; + fn ambiguity_diagnostics(&self, ambiguity_error: &AmbiguityError<'_>) -> AmbiguityErrorDiag { + let AmbiguityError { kind, ident, b1, b2, misc1, misc2, .. } = *ambiguity_error; let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() { // We have to print the span-less alternative first, otherwise formatting looks bad. (b2, b1, misc2, misc1, true) } else { (b1, b2, misc1, misc2, false) }; - - let mut err = struct_span_err!(self.tcx.sess, ident.span, E0659, "`{ident}` is ambiguous"); - err.span_label(ident.span, "ambiguous name"); - err.note(format!("ambiguous because of {}", kind.descr())); - - let mut could_refer_to = |b: NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| { + let could_refer_to = |b: NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| { let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude); let note_msg = format!("`{ident}` could{also} refer to {what}"); @@ -1579,16 +1587,35 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { AmbiguityErrorMisc::FromPrelude | AmbiguityErrorMisc::None => {} } - err.span_note(b.span, note_msg); - for (i, help_msg) in help_msgs.iter().enumerate() { - let or = if i == 0 { "" } else { "or " }; - err.help(format!("{}{}", or, help_msg)); - } + ( + b.span, + note_msg, + help_msgs + .iter() + .enumerate() + .map(|(i, help_msg)| { + let or = if i == 0 { "" } else { "or " }; + format!("{or}{help_msg}") + }) + .collect::<Vec<_>>(), + ) }; - - could_refer_to(b1, misc1, ""); - could_refer_to(b2, misc2, " also"); - err.emit(); + let (b1_span, b1_note_msg, b1_help_msgs) = could_refer_to(b1, misc1, ""); + let (b2_span, b2_note_msg, b2_help_msgs) = could_refer_to(b2, misc2, " also"); + + AmbiguityErrorDiag { + msg: format!("`{ident}` is ambiguous"), + span: ident.span, + label_span: ident.span, + label_msg: "ambiguous name".to_string(), + note_msg: format!("ambiguous because of {}", kind.descr()), + b1_span, + b1_note_msg, + b1_help_msgs, + b2_span, + b2_note_msg, + b2_help_msgs, + } } /// If the binding refers to a tuple struct constructor with fields, @@ -1626,7 +1653,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let descr = get_descr(binding); let mut err = struct_span_err!(self.tcx.sess, ident.span, E0603, "{} `{}` is private", descr, ident); - err.span_label(ident.span, format!("private {}", descr)); + err.span_label(ident.span, format!("private {descr}")); if let Some((this_res, outer_ident)) = outermost_res { let import_suggestions = self.lookup_import_candidates( @@ -1718,7 +1745,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { 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]`"), + "cannot be constructed because it is `#[non_exhaustive]`", ); } err.span_note(note_span, msg); @@ -1811,7 +1838,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { _ => format!("`{parent}`"), }; - let mut msg = format!("could not find `{}` in {}", ident, parent); + let mut msg = format!("could not find `{ident}` in {parent}"); if ns == TypeNS || ns == ValueNS { let ns_to_try = if ns == TypeNS { ValueNS } else { TypeNS }; let binding = if let Some(module) = module { @@ -1926,12 +1953,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let suggestion = match_span.map(|span| { ( vec![(span, String::from(""))], - format!("`{}` is defined here, but is not a type", ident), + format!("`{ident}` is defined here, but is not a type"), Applicability::MaybeIncorrect, ) }); - (format!("use of undeclared type `{}`", ident), suggestion) + (format!("use of undeclared type `{ident}`"), suggestion) } else { let mut suggestion = None; if ident.name == sym::alloc { @@ -1953,7 +1980,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }, ) }); - (format!("use of undeclared crate or module `{}`", ident), suggestion) + (format!("use of undeclared crate or module `{ident}`"), suggestion) } } @@ -2137,16 +2164,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let module_name = crate_module.kind.name().unwrap(); let import_snippet = match import.kind { ImportKind::Single { source, target, .. } if source != target => { - format!("{} as {}", source, target) + format!("{source} as {target}") } - _ => format!("{}", ident), + _ => format!("{ident}"), }; let mut corrections: Vec<(Span, String)> = Vec::new(); if !import.is_nested() { // Assume this is the easy case of `use issue_59764::foo::makro;` and just remove // intermediate segments. - corrections.push((import.span, format!("{}::{}", module_name, import_snippet))); + corrections.push((import.span, format!("{module_name}::{import_snippet}"))); } else { // Find the binding span (and any trailing commas and spaces). // ie. `use a::b::{c, d, e};` @@ -2213,11 +2240,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { start_point, if has_nested { // In this case, `start_snippet` must equal '{'. - format!("{}{}, ", start_snippet, import_snippet) + format!("{start_snippet}{import_snippet}, ") } else { // In this case, add a `{`, then the moved import, then whatever // was there before. - format!("{{{}, {}", import_snippet, start_snippet) + format!("{{{import_snippet}, {start_snippet}") }, )); @@ -2634,9 +2661,9 @@ fn show_candidates( "item" }; let plural_descr = - if descr.ends_with('s') { format!("{}es", descr) } else { format!("{}s", descr) }; + if descr.ends_with('s') { format!("{descr}es") } else { format!("{descr}s") }; - let mut msg = format!("{}these {} exist but are inaccessible", prefix, plural_descr); + let mut msg = format!("{prefix}these {plural_descr} exist but are inaccessible"); let mut has_colon = false; let mut spans = Vec::new(); @@ -2657,7 +2684,7 @@ fn show_candidates( let mut multi_span = MultiSpan::from_spans(spans.iter().map(|(_, sp)| *sp).collect()); for (name, span) in spans { - multi_span.push_span_label(span, format!("`{}`: not accessible", name)); + multi_span.push_span_label(span, format!("`{name}`: not accessible")); } for note in inaccessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) { diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index de431444769..3bd9cea27ce 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -677,6 +677,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ident: orig_ident, b1: innermost_binding, b2: binding, + warning: false, misc1: misc(innermost_flags), misc2: misc(flags), }); @@ -905,6 +906,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ident, b1: binding, b2: shadowed_glob, + warning: false, misc1: AmbiguityErrorMisc::None, misc2: AmbiguityErrorMisc::None, }); @@ -1443,12 +1445,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let name_str = if name == kw::PathRoot { "crate root".to_string() } else { - format!("`{}`", name) + format!("`{name}`") }; let label = if segment_idx == 1 && path[0].ident.name == kw::PathRoot { - format!("global paths cannot start with {}", name_str) + format!("global paths cannot start with {name_str}") } else { - format!("{} in paths can only be used in start position", name_str) + format!("{name_str} in paths can only be used in start position") }; (label, None) }); diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 526fc9c3aa5..7f436438e8a 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -284,6 +284,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.arenas.alloc_name_binding(NameBindingData { kind: NameBindingKind::Import { binding, import, used: Cell::new(false) }, ambiguity: None, + warn_ambiguity: false, span: import.span, vis, expansion: import.parent_scope.expansion, @@ -291,16 +292,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } /// Define the name or return the existing binding if there is a collision. + /// `update` indicates if the definition is a redefinition of an existing binding. pub(crate) fn try_define( &mut self, module: Module<'a>, key: BindingKey, binding: NameBinding<'a>, + warn_ambiguity: bool, ) -> Result<(), NameBinding<'a>> { let res = binding.res(); self.check_reserved_macro_name(key.ident, res); self.set_binding_parent_module(binding, module); - self.update_resolution(module, key, |this, resolution| { + self.update_resolution(module, key, warn_ambiguity, |this, resolution| { if let Some(old_binding) = resolution.binding { if res == Res::Err && old_binding.res() != Res::Err { // Do not override real bindings with `Res::Err`s from error recovery. @@ -308,15 +311,42 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } match (old_binding.is_glob_import(), binding.is_glob_import()) { (true, true) => { - if res != old_binding.res() { - resolution.binding = Some(this.ambiguity( - AmbiguityKind::GlobVsGlob, - old_binding, - binding, - )); + // FIXME: remove `!binding.is_ambiguity()` after delete the warning ambiguity. + if !binding.is_ambiguity() + && let NameBindingKind::Import { import: old_import, .. } = old_binding.kind + && let NameBindingKind::Import { import, .. } = binding.kind + && old_import == import { + // We should replace the `old_binding` with `binding` regardless + // of whether they has same resolution or not when they are + // imported from the same glob-import statement. + // However we currently using `Some(old_binding)` for back compact + // purposes. + // This case can be removed after once `Undetermined` is prepared + // for glob-imports. + } else if res != old_binding.res() { + let binding = if warn_ambiguity { + this.warn_ambiguity( + AmbiguityKind::GlobVsGlob, + old_binding, + binding, + ) + } else { + this.ambiguity( + AmbiguityKind::GlobVsGlob, + old_binding, + binding, + ) + }; + resolution.binding = Some(binding); } 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); + } else if binding.is_ambiguity() { + resolution.binding = + Some(self.arenas.alloc_name_binding(NameBindingData { + warn_ambiguity: true, + ..(*binding).clone() + })); } } (old_glob @ true, false) | (old_glob @ false, true) => { @@ -374,29 +404,52 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }) } + fn warn_ambiguity( + &self, + kind: AmbiguityKind, + primary_binding: NameBinding<'a>, + secondary_binding: NameBinding<'a>, + ) -> NameBinding<'a> { + self.arenas.alloc_name_binding(NameBindingData { + ambiguity: Some((secondary_binding, kind)), + warn_ambiguity: true, + ..(*primary_binding).clone() + }) + } + // Use `f` to mutate the resolution of the name in the module. // If the resolution becomes a success, define it in the module's glob importers. - fn update_resolution<T, F>(&mut self, module: Module<'a>, key: BindingKey, f: F) -> T + fn update_resolution<T, F>( + &mut self, + module: Module<'a>, + key: BindingKey, + warn_ambiguity: bool, + f: F, + ) -> T where F: FnOnce(&mut Resolver<'a, 'tcx>, &mut NameResolution<'a>) -> T, { // Ensure that `resolution` isn't borrowed when defining in the module's glob importers, // during which the resolution might end up getting re-defined via a glob cycle. - let (binding, t) = { + let (binding, t, warn_ambiguity) = { let resolution = &mut *self.resolution(module, key).borrow_mut(); let old_binding = resolution.binding(); let t = f(self, resolution); - if old_binding.is_none() && let Some(binding) = resolution.binding() { - (binding, t) + if let Some(binding) = resolution.binding() && old_binding != Some(binding) { + (binding, t, warn_ambiguity || old_binding.is_some()) } else { return t; } }; - // Define `binding` in `module`s glob importers. - for import in module.glob_importers.borrow_mut().iter() { + let Ok(glob_importers) = module.glob_importers.try_borrow_mut() else { + return t; + }; + + // Define or update `binding` in `module`s glob importers. + for import in glob_importers.iter() { let mut ident = key.ident; let scope = match ident.span.reverse_glob_adjust(module.expansion, import.span) { Some(Some(def)) => self.expn_def_scope(def), @@ -406,7 +459,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if self.is_accessible_from(binding.vis, scope) { let imported_binding = self.import(binding, *import); let key = BindingKey { ident, ..key }; - let _ = self.try_define(import.parent_scope.module, key, imported_binding); + let _ = self.try_define( + import.parent_scope.module, + key, + imported_binding, + warn_ambiguity, + ); } } @@ -425,7 +483,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let dummy_binding = self.import(dummy_binding, import); self.per_ns(|this, ns| { let key = BindingKey::new(target, ns); - let _ = this.try_define(import.parent_scope.module, key, dummy_binding); + let _ = this.try_define(import.parent_scope.module, key, dummy_binding, false); }); self.record_use(target, dummy_binding, false); } else if import.imported_module.get().is_none() { @@ -700,7 +758,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Segment::names_to_string(&import.module_path), module_to_string(import.parent_scope.module).unwrap_or_else(|| "???".to_string()), ); - let module = if let Some(module) = import.imported_module.get() { module } else { @@ -773,7 +830,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { .emit(); } let key = BindingKey::new(target, ns); - this.update_resolution(parent, key, |_, resolution| { + this.update_resolution(parent, key, false, |_, resolution| { resolution.single_imports.remove(&import); }); } @@ -989,14 +1046,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { initial_binding.res() }); let res = binding.res(); + let has_ambiguity_error = this + .ambiguity_errors + .iter() + .filter(|error| !error.warning) + .next() + .is_some(); + if res == Res::Err || has_ambiguity_error { + this.tcx + .sess + .delay_span_bug(import.span, "some error happened for an import"); + return; + } if let Ok(initial_res) = initial_res { - if res != initial_res && this.ambiguity_errors.is_empty() { + if res != initial_res { span_bug!(import.span, "inconsistent resolution for an import"); } - } else if res != Res::Err - && this.ambiguity_errors.is_empty() - && this.privacy_errors.is_empty() - { + } else if this.privacy_errors.is_empty() { this.tcx .sess .create_err(CannotDetermineImportResolution { span: import.span }) @@ -1087,18 +1153,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ModuleOrUniformRoot::Module(module) => { let module_str = module_to_string(module); if let Some(module_str) = module_str { - format!("no `{}` in `{}`", ident, module_str) + format!("no `{ident}` in `{module_str}`") } else { - format!("no `{}` in the root", ident) + format!("no `{ident}` in the root") } } _ => { if !ident.is_path_segment_keyword() { - format!("no external crate `{}`", ident) + format!("no external crate `{ident}`") } else { // HACK(eddyb) this shows up for `self` & `super`, which // should work instead - for now keep the same error message. - format!("no `{}` in the root", ident) + format!("no `{ident}` in the root") } } }; @@ -1146,10 +1212,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let (ns, binding) = reexport_error.unwrap(); if pub_use_of_private_extern_crate_hack(import, binding) { let msg = format!( - "extern crate `{}` is private, and cannot be \ + "extern crate `{ident}` is private, and cannot be \ re-exported (error E0365), consider declaring with \ - `pub`", - ident + `pub`" ); self.lint_buffer.buffer_lint( PUB_USE_OF_PRIVATE_EXTERN_CRATE, @@ -1289,7 +1354,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { UNUSED_IMPORTS, id, import.span, - format!("the item `{}` is imported redundantly", ident), + format!("the item `{ident}` is imported redundantly"), BuiltinLintDiagnostics::RedundantImport(redundant_spans, ident), ); } @@ -1335,7 +1400,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }; if self.is_accessible_from(binding.vis, scope) { let imported_binding = self.import(binding, import); - let _ = self.try_define(import.parent_scope.module, key, imported_binding); + let warn_ambiguity = self + .resolution(import.parent_scope.module, key) + .borrow() + .binding() + .is_some_and(|binding| binding.is_warn_ambiguity()); + let _ = self.try_define( + import.parent_scope.module, + key, + imported_binding, + warn_ambiguity, + ); } } @@ -1354,7 +1429,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { module.for_each_child(self, |this, ident, _, binding| { let res = binding.res().expect_non_local(); - if res != def::Res::Err && !binding.is_ambiguity() { + let error_ambiguity = binding.is_ambiguity() && !binding.warn_ambiguity; + if res != def::Res::Err && !error_ambiguity { let mut reexport_chain = SmallVec::new(); let mut next_binding = binding; while let NameBindingKind::Import { binding, import, .. } = next_binding.kind { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 05128a51016..0e9d74480a9 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -337,6 +337,7 @@ enum LifetimeBinderKind { PolyTrait, WhereBound, Item, + ConstItem, Function, Closure, ImplBlock, @@ -349,7 +350,7 @@ impl LifetimeBinderKind { BareFnType => "type", PolyTrait => "bound", WhereBound => "bound", - Item => "item", + Item | ConstItem => "item", ImplBlock => "impl block", Function => "function", Closure => "closure", @@ -549,6 +550,7 @@ enum MaybeExported<'a> { Ok(NodeId), Impl(Option<DefId>), ImplItem(Result<DefId, &'a Visibility>), + NestedUse(&'a Visibility), } impl MaybeExported<'_> { @@ -559,7 +561,9 @@ impl MaybeExported<'_> { trait_def_id.as_local() } MaybeExported::Impl(None) => return true, - MaybeExported::ImplItem(Err(vis)) => return vis.kind.is_pub(), + MaybeExported::ImplItem(Err(vis)) | MaybeExported::NestedUse(vis) => { + return vis.kind.is_pub(); + } }; def_id.map_or(true, |def_id| r.effective_visibilities.is_exported(def_id)) } @@ -1913,10 +1917,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { candidate: LifetimeElisionCandidate, ) { if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) { - panic!( - "lifetime {:?} resolved multiple times ({:?} before, {:?} now)", - id, prev_res, res - ) + panic!("lifetime {id:?} resolved multiple times ({prev_res:?} before, {res:?} now)") } match res { LifetimeRes::Param { .. } | LifetimeRes::Fresh { .. } | LifetimeRes::Static => { @@ -1932,8 +1933,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { fn record_lifetime_param(&mut self, id: NodeId, res: LifetimeRes) { if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) { panic!( - "lifetime parameter {:?} resolved multiple times ({:?} before, {:?} now)", - id, prev_res, res + "lifetime parameter {id:?} resolved multiple times ({prev_res:?} before, {res:?} now)" ) } } @@ -2284,7 +2284,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { fn resolve_item(&mut self, item: &'ast Item) { let mod_inner_docs = matches!(item.kind, ItemKind::Mod(..)) && rustdoc::inner_docs(&item.attrs); - if !mod_inner_docs && !matches!(item.kind, ItemKind::Impl(..)) { + if !mod_inner_docs && !matches!(item.kind, ItemKind::Impl(..) | ItemKind::Use(..)) { self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id)); } @@ -2401,33 +2401,53 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { }); } - ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. }) - | ItemKind::Const(box ast::ConstItem { ref ty, ref expr, .. }) => { + ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. }) => { self.with_static_rib(|this| { this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| { this.visit_ty(ty); }); - this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| { + if let Some(expr) = expr { + // We already forbid generic params because of the above item rib, + // so it doesn't matter whether this is a trivial constant. + this.resolve_const_body(expr, Some((item.ident, ConstantItemKind::Static))); + } + }); + } + + ItemKind::Const(box ast::ConstItem { ref generics, ref ty, ref expr, .. }) => { + self.with_generic_param_rib( + &generics.params, + RibKind::Item(HasGenericParams::Yes(generics.span)), + LifetimeRibKind::Generics { + binder: item.id, + kind: LifetimeBinderKind::ConstItem, + span: generics.span, + }, + |this| { + this.visit_generics(generics); + + this.with_lifetime_rib( + LifetimeRibKind::Elided(LifetimeRes::Static), + |this| this.visit_ty(ty), + ); + if let Some(expr) = expr { - let constant_item_kind = match item.kind { - ItemKind::Const(..) => ConstantItemKind::Const, - ItemKind::Static(..) => ConstantItemKind::Static, - _ => unreachable!(), - }; - // We already forbid generic params because of the above item rib, - // so it doesn't matter whether this is a trivial constant. - this.with_constant_rib( - IsRepeatExpr::No, - ConstantHasGenerics::Yes, - Some((item.ident, constant_item_kind)), - |this| this.visit_expr(expr), + this.resolve_const_body( + expr, + Some((item.ident, ConstantItemKind::Const)), ); } - }); - }); + }, + ); } ItemKind::Use(ref use_tree) => { + let maybe_exported = match use_tree.kind { + UseTreeKind::Simple(_) | UseTreeKind::Glob => MaybeExported::Ok(item.id), + UseTreeKind::Nested(_) => MaybeExported::NestedUse(&item.vis), + }; + self.resolve_doc_links(&item.attrs, maybe_exported); + self.future_proof_import(use_tree); } @@ -2569,7 +2589,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { let res = match kind { RibKind::Item(..) | RibKind::AssocItem => Res::Def(def_kind, def_id.to_def_id()), RibKind::Normal => { - if self.r.tcx.sess.features_untracked().non_lifetime_binders { + if self.r.tcx.features().non_lifetime_binders { Res::Def(def_kind, def_id.to_def_id()) } else { Res::Err @@ -2691,28 +2711,31 @@ 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(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) = 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. - self.with_lifetime_rib( - LifetimeRibKind::Elided(LifetimeRes::Infer), - |this| { - this.with_constant_rib( - IsRepeatExpr::No, - ConstantHasGenerics::Yes, - None, - |this| this.visit_expr(expr), - ) - }, - ); - } + AssocItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => { + self.with_generic_param_rib( + &generics.params, + RibKind::AssocItem, + LifetimeRibKind::Generics { + binder: item.id, + span: generics.span, + kind: LifetimeBinderKind::ConstItem, + }, + |this| { + this.visit_generics(generics); + this.visit_ty(ty); + + // Only impose the restrictions of `ConstRibKind` for an + // actual constant expression in a provided default. + 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); + } + }, + ); } AssocItemKind::Fn(box Fn { generics, .. }) => { walk_assoc_item(self, generics, LifetimeBinderKind::Function, item); @@ -2867,36 +2890,42 @@ 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(box ast::ConstItem { ty, expr, .. }) => { + AssocItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => { debug!("resolve_implementation AssocItemKind::Const"); - // If this is a trait impl, ensure the const - // exists in trait - self.check_trait_item( - item.id, - item.ident, - &item.kind, - ValueNS, - item.span, - seen_trait_items, - |i, s, c| ConstNotMemberOfTrait(i, s, c), - ); - self.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. - self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| { - this.with_constant_rib( - IsRepeatExpr::No, - ConstantHasGenerics::Yes, - None, - |this| this.visit_expr(expr), - ) - }); - } + self.with_generic_param_rib( + &generics.params, + RibKind::AssocItem, + LifetimeRibKind::Generics { + binder: item.id, + span: generics.span, + 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.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); + } + }, + ); } AssocItemKind::Fn(box Fn { generics, .. }) => { debug!("resolve_implementation AssocItemKind::Fn"); @@ -3054,6 +3083,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ); } + fn resolve_const_body(&mut self, expr: &'ast Expr, item: Option<(Ident, ConstantItemKind)>) { + self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| { + this.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, item, |this| { + this.visit_expr(expr) + }); + }) + } + fn resolve_params(&mut self, params: &'ast [Param]) { let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| { @@ -4439,6 +4476,7 @@ impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> { fn visit_item(&mut self, item: &'ast Item) { match &item.kind { ItemKind::TyAlias(box TyAlias { ref generics, .. }) + | ItemKind::Const(box ConstItem { ref generics, .. }) | ItemKind::Fn(box Fn { ref generics, .. }) | ItemKind::Enum(_, ref generics) | ItemKind::Struct(_, ref generics) @@ -4458,7 +4496,6 @@ impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> { ItemKind::Mod(..) | ItemKind::ForeignMod(..) | ItemKind::Static(..) - | ItemKind::Const(..) | ItemKind::Use(..) | ItemKind::ExternCrate(..) | ItemKind::MacroDef(..) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 753a1adc66d..974580f815b 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -585,13 +585,13 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { let others = match enum_candidates.len() { 1 => String::new(), 2 => " and 1 other".to_owned(), - n => format!(" and {} others", n), + n => format!(" and {n} others"), }; format!("there is an enum variant `{}`{}; ", enum_candidates[0].0, others) } else { String::new() }; - let msg = format!("{}try using the variant's enum", preamble); + let msg = format!("{preamble}try using the variant's enum"); err.span_suggestions( span, @@ -696,7 +696,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { ident.name == path[0].ident.name { err.span_help( ident.span, - format!("the binding `{}` is available in a different scope in the same function", path_str), + format!("the binding `{path_str}` is available in a different scope in the same function"), ); return (true, candidates); } @@ -858,7 +858,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { for label_rib in &self.label_ribs { for (label_ident, node_id) in &label_rib.bindings { let ident = path.last().unwrap().ident; - if format!("'{}", ident) == label_ident.to_string() { + if format!("'{ident}") == label_ident.to_string() { err.span_label(label_ident.span, "a label with a similar name exists"); if let PathSource::Expr(Some(Expr { kind: ExprKind::Break(None, Some(_)), @@ -983,7 +983,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { if let Some(ident) = fn_kind.ident() { err.span_label( ident.span, - format!("this function {} have a `self` parameter", doesnt), + format!("this function {doesnt} have a `self` parameter"), ); } } @@ -1164,7 +1164,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { }; err.span_suggestion_verbose( *where_span, - format!("constrain the associated type to `{}`", ident), + format!("constrain the associated type to `{ident}`"), where_bound_predicate_to_string(&new_where_bound_predicate), Applicability::MaybeIncorrect, ); @@ -1338,8 +1338,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { span, // Note the parentheses surrounding the suggestion below format!( "you might want to surround a struct literal with parentheses: \ - `({} {{ /* fields */ }})`?", - path_str + `({path_str} {{ /* fields */ }})`?" ), ); } @@ -1373,7 +1372,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { .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 } + if let Some(Some(old)) = old && new != *old { format!("{new}: {old}") } else { new } }) .collect::<Vec<String>>() } else { @@ -1390,7 +1389,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { }; err.span_suggestion( span, - format!("use struct {} syntax instead", descr), + format!("use struct {descr} syntax instead"), format!("{path_str} {{{pad}{fields}{pad}}}"), applicability, ); @@ -1584,7 +1583,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { err.span_suggestion( span, "use the tuple variant pattern syntax instead", - format!("{}({})", path_str, fields), + format!("{path_str}({fields})"), Applicability::HasPlaceholders, ); } @@ -1994,9 +1993,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { if !suggestable_variants.is_empty() { let msg = if non_suggestable_variant_count == 0 && suggestable_variants.len() == 1 { - format!("try {} the enum's variant", source_msg) + format!("try {source_msg} the enum's variant") } else { - format!("try {} one of the enum's variants", source_msg) + format!("try {source_msg} one of the enum's variants") }; err.span_suggestions( @@ -2009,19 +2008,15 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { // If the enum has no tuple variants.. if non_suggestable_variant_count == variants.len() { - err.help(format!("the enum has no tuple variants {}", source_msg)); + err.help(format!("the enum has no tuple variants {source_msg}")); } // If there are also non-tuple variants.. if non_suggestable_variant_count == 1 { - err.help(format!( - "you might have meant {} the enum's non-tuple variant", - source_msg - )); + err.help(format!("you might have meant {source_msg} the enum's non-tuple variant")); } else if non_suggestable_variant_count >= 1 { err.help(format!( - "you might have meant {} one of the enum's non-tuple variants", - source_msg + "you might have meant {source_msg} one of the enum's non-tuple variants" )); } } else { @@ -2041,7 +2036,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { .map(|(variant, _, kind)| (path_names_to_string(variant), kind)) .map(|(variant, kind)| match kind { CtorKind::Const => variant, - CtorKind::Fn => format!("({}())", variant), + CtorKind::Fn => format!("({variant}())"), }) .collect::<Vec<_>>(); let no_suggestable_variant = suggestable_variants.is_empty(); @@ -2066,7 +2061,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { .filter(|(_, def_id, kind)| needs_placeholder(*def_id, *kind)) .map(|(variant, _, kind)| (path_names_to_string(variant), kind)) .filter_map(|(variant, kind)| match kind { - CtorKind::Fn => Some(format!("({}(/* fields */))", variant)), + CtorKind::Fn => Some(format!("({variant}(/* fields */))")), _ => None, }) .collect::<Vec<_>>(); @@ -2348,13 +2343,20 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { let mut should_continue = true; match rib.kind { LifetimeRibKind::Generics { binder: _, span, kind } => { + // Avoid suggesting placing lifetime parameters on constant items unless the relevant + // feature is enabled. Suggest the parent item as a possible location if applicable. + if let LifetimeBinderKind::ConstItem = kind + && !self.r.tcx().features().generic_const_items + { + continue; + } + if !span.can_be_used_for_suggestions() && suggest_note && let Some(name) = name { suggest_note = false; // Avoid displaying the same help multiple times. err.span_label( span, format!( - "lifetime `{}` is missing in item created through this procedural macro", - name, + "lifetime `{name}` is missing in item created through this procedural macro", ), ); continue; @@ -2398,7 +2400,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { ); } else if let Some(name) = name { let message = - Cow::from(format!("consider introducing lifetime `{}` here", name)); + Cow::from(format!("consider introducing lifetime `{name}` here")); should_continue = suggest(err, false, span, message, sugg); } else { let message = Cow::from("consider introducing a named lifetime parameter"); @@ -2542,7 +2544,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } let help_name = if let Some(ident) = ident { - format!("`{}`", ident) + format!("`{ident}`") } else { format!("argument {}", index + 1) }; @@ -2550,7 +2552,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { if lifetime_count == 1 { m.push_str(&help_name[..]) } else { - m.push_str(&format!("one of {}'s {} lifetimes", help_name, lifetime_count)[..]) + m.push_str(&format!("one of {help_name}'s {lifetime_count} lifetimes")[..]) } } @@ -2580,14 +2582,12 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } else if num_params == 1 { err.help(format!( "this function's return type contains a borrowed value, \ - but the signature does not say which {} it is borrowed from", - m + but the signature does not say which {m} it is borrowed from" )); } else { err.help(format!( "this function's return type contains a borrowed value, \ - but the signature does not say whether it is borrowed from {}", - m + but the signature does not say whether it is borrowed from {m}" )); } } @@ -2606,7 +2606,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } MissingLifetimeKind::Ampersand => { debug_assert_eq!(lt.count, 1); - (lt.span.shrink_to_hi(), format!("{} ", existing_name)) + (lt.span.shrink_to_hi(), format!("{existing_name} ")) } MissingLifetimeKind::Comma => { let sugg: String = std::iter::repeat([existing_name.as_str(), ", "]) @@ -2653,7 +2653,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } 1 => { err.multipart_suggestion_verbose( - format!("consider using the `{}` lifetime", existing_name), + format!("consider using the `{existing_name}` lifetime"), spans_suggs, Applicability::MaybeIncorrect, ); @@ -2770,9 +2770,9 @@ pub(super) fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident let shadower = shadower.span; let mut err = sess.struct_span_warn( shadower, - format!("label name `{}` shadows a label name that is already in scope", name), + format!("label name `{name}` shadows a label name that is already in scope"), ); err.span_label(orig, "first declared here"); - err.span_label(shadower, format!("label `{}` already in scope", name)); + err.span_label(shadower, format!("label `{name}` already in scope")); err.emit(); } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index faa672db59c..da5e92a075a 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -658,6 +658,7 @@ impl<'a> fmt::Debug for Module<'a> { struct NameBindingData<'a> { kind: NameBindingKind<'a>, ambiguity: Option<(NameBinding<'a>, AmbiguityKind)>, + warn_ambiguity: bool, expansion: LocalExpnId, span: Span, vis: ty::Visibility<DefId>, @@ -767,6 +768,7 @@ struct AmbiguityError<'a> { b2: NameBinding<'a>, misc1: AmbiguityErrorMisc, misc2: AmbiguityErrorMisc, + warning: bool, } impl<'a> NameBindingData<'a> { @@ -794,6 +796,14 @@ impl<'a> NameBindingData<'a> { } } + fn is_warn_ambiguity(&self) -> bool { + self.warn_ambiguity + || match self.kind { + NameBindingKind::Import { binding, .. } => binding.is_warn_ambiguity(), + _ => false, + } + } + fn is_possibly_imported_variant(&self) -> bool { match self.kind { NameBindingKind::Import { binding, .. } => binding.is_possibly_imported_variant(), @@ -1158,7 +1168,7 @@ impl<'tcx> Resolver<'_, 'tcx> { } fn local_def_id(&self, node: NodeId) -> LocalDefId { - self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node)) + self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`")) } /// Adds a definition with a parent definition. @@ -1322,6 +1332,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { 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, @@ -1685,6 +1696,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } fn record_use(&mut self, ident: Ident, used_binding: NameBinding<'a>, is_lexical_scope: bool) { + self.record_use_inner(ident, used_binding, is_lexical_scope, used_binding.warn_ambiguity); + } + + fn record_use_inner( + &mut self, + ident: Ident, + used_binding: NameBinding<'a>, + is_lexical_scope: bool, + warn_ambiguity: bool, + ) { if let Some((b2, kind)) = used_binding.ambiguity { let ambiguity_error = AmbiguityError { kind, @@ -1693,9 +1714,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { b2, misc1: AmbiguityErrorMisc::None, misc2: AmbiguityErrorMisc::None, + warning: warn_ambiguity, }; if !self.matches_previous_ambiguity_error(&ambiguity_error) { - // avoid duplicated span information to be emitt out + // avoid duplicated span information to be emit out self.ambiguity_errors.push(ambiguity_error); } } @@ -1715,7 +1737,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.used_imports.insert(id); } self.add_to_glob_map(import, ident); - self.record_use(ident, binding, false); + self.record_use_inner(ident, binding, false, warn_ambiguity || binding.warn_ambiguity); } } @@ -1812,7 +1834,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn record_partial_res(&mut self, node_id: NodeId, resolution: PartialRes) { debug!("(recording res) recording {:?} for {}", resolution, node_id); if let Some(prev_res) = self.partial_res_map.insert(node_id, resolution) { - panic!("path resolved multiple times ({:?} before, {:?} now)", prev_res, resolution); + panic!("path resolved multiple times ({prev_res:?} before, {resolution:?} now)"); } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index d16b7902f60..614a29e7578 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -24,7 +24,9 @@ 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::{ + LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE, UNKNOWN_DIAGNOSTIC_ATTRIBUTES, +}; use rustc_session::lint::builtin::{UNUSED_MACROS, UNUSED_MACRO_RULES}; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::feature_err; @@ -140,9 +142,9 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { } } } - // We implicitly add `rustfmt` and `clippy` to known tools, + // We implicitly add `rustfmt`, `clippy`, `diagnostic` to known tools, // but it's not an error to register them explicitly. - let predefined_tools = [sym::clippy, sym::rustfmt]; + let predefined_tools = [sym::clippy, sym::rustfmt, sym::diagnostic]; registered_tools.extend(predefined_tools.iter().cloned().map(Ident::with_dummy_span)); registered_tools } @@ -205,7 +207,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> { self.tcx .sess .diagnostic() - .bug(format!("built-in macro `{}` was already registered", name)); + .bug(format!("built-in macro `{name}` was already registered")); } } @@ -568,7 +570,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } let mut err = self.tcx.sess.create_err(err); - err.span_label(path.span, format!("not {} {}", article, expected)); + err.span_label(path.span, format!("not {article} {expected}")); err.emit(); @@ -576,10 +578,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } // We are trying to avoid reporting this error if other related errors were reported. - if res != Res::Err - && inner_attr - && !self.tcx.sess.features_untracked().custom_inner_attributes - { + if res != Res::Err && inner_attr && !self.tcx.features().custom_inner_attributes { let msg = match res { Res::Def(..) => "inner macro attributes are unstable", Res::NonMacroAttr(..) => "custom inner attributes are unstable", @@ -598,6 +597,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } + if res == Res::NonMacroAttr(NonMacroAttrKind::Tool) + && path.segments.len() >= 2 + && path.segments[0].ident.name == sym::diagnostic + { + self.tcx.sess.parse_sess.buffer_lint( + UNKNOWN_DIAGNOSTIC_ATTRIBUTES, + path.segments[1].span(), + node_id, + "unknown diagnostic attribute", + ); + } + Ok((ext, res)) } @@ -895,7 +906,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) { self.tcx.sess.span_err( ident.span, - format!("name `{}` is reserved in attribute namespace", ident), + format!("name `{ident}` is reserved in attribute namespace"), ); } } |
