diff options
Diffstat (limited to 'compiler/rustc_resolve/src')
| -rw-r--r-- | compiler/rustc_resolve/src/build_reduced_graph.rs | 72 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/def_collector.rs | 30 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/diagnostics.rs | 210 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/errors.rs | 16 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/ident.rs | 262 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/imports.rs | 31 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/late.rs | 267 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/late/diagnostics.rs | 73 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/lib.rs | 92 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/macros.rs | 76 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/rustdoc.rs | 106 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/rustdoc/tests.rs | 6 |
12 files changed, 768 insertions, 473 deletions
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index c30ed781f35..ef122deba4e 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -18,6 +18,7 @@ use rustc_expand::base::ResolverExpand; use rustc_expand::expand::AstFragment; use rustc_hir::def::{self, *}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; +use rustc_index::bit_set::DenseBitSet; use rustc_metadata::creader::LoadedMacro; use rustc_middle::metadata::ModChild; use rustc_middle::ty::Feed; @@ -161,28 +162,30 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - pub(crate) fn get_macro(&mut self, res: Res) -> Option<&MacroData> { + pub(crate) fn get_macro(&self, res: Res) -> Option<&'ra MacroData> { match res { Res::Def(DefKind::Macro(..), def_id) => Some(self.get_macro_by_def_id(def_id)), - Res::NonMacroAttr(_) => Some(&self.non_macro_attr), + Res::NonMacroAttr(_) => Some(self.non_macro_attr), _ => None, } } - pub(crate) fn get_macro_by_def_id(&mut self, def_id: DefId) -> &MacroData { - if self.macro_map.contains_key(&def_id) { - return &self.macro_map[&def_id]; - } - - let loaded_macro = self.cstore().load_macro_untracked(def_id, self.tcx); - let macro_data = match loaded_macro { - LoadedMacro::MacroDef { def, ident, attrs, span, edition } => { - self.compile_macro(&def, ident, &attrs, span, ast::DUMMY_NODE_ID, edition) - } - LoadedMacro::ProcMacro(ext) => MacroData::new(Arc::new(ext)), - }; + pub(crate) fn get_macro_by_def_id(&self, def_id: DefId) -> &'ra MacroData { + // Local macros are always compiled. + match def_id.as_local() { + Some(local_def_id) => self.local_macro_map[&local_def_id], + None => *self.extern_macro_map.borrow_mut().entry(def_id).or_insert_with(|| { + let loaded_macro = self.cstore().load_macro_untracked(def_id, self.tcx); + let macro_data = match loaded_macro { + LoadedMacro::MacroDef { def, ident, attrs, span, edition } => { + self.compile_macro(&def, ident, &attrs, span, ast::DUMMY_NODE_ID, edition) + } + LoadedMacro::ProcMacro(ext) => MacroData::new(Arc::new(ext)), + }; - self.macro_map.entry(def_id).or_insert(macro_data) + self.arenas.alloc_macro(macro_data) + }), + } } pub(crate) fn build_reduced_graph( @@ -1098,22 +1101,20 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.potentially_unused_imports.push(import); module.for_each_child(self, |this, ident, ns, binding| { if ns == MacroNS { - let imported_binding = - if this.r.is_accessible_from(binding.vis, this.parent_scope.module) { - this.r.import(binding, import) - } else if !this.r.is_builtin_macro(binding.res()) - && !this.r.macro_use_prelude.contains_key(&ident.name) - { - // - `!r.is_builtin_macro(res)` excluding the built-in macros such as `Debug` or `Hash`. - // - `!r.macro_use_prelude.contains_key(name)` excluding macros defined in other extern - // crates such as `std`. - // FIXME: This branch should eventually be removed. - let import = macro_use_import(this, span, true); - this.r.import(binding, import) - } else { + let import = if this.r.is_accessible_from(binding.vis, this.parent_scope.module) + { + import + } else { + // FIXME: This branch is used for reporting the `private_macro_use` lint + // and should eventually be removed. + if this.r.macro_use_prelude.contains_key(&ident.name) { + // Do not override already existing entries with compatibility entries. return; - }; - this.add_macro_use_binding(ident.name, imported_binding, span, allow_shadowing); + } + macro_use_import(this, span, true) + }; + let import_binding = this.r.import(binding, import); + this.add_macro_use_binding(ident.name, import_binding, span, allow_shadowing); } }); } else { @@ -1204,13 +1205,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { fn insert_unused_macro(&mut self, ident: Ident, def_id: LocalDefId, node_id: NodeId) { if !ident.as_str().starts_with('_') { self.r.unused_macros.insert(def_id, (node_id, ident)); - for (rule_i, rule_span) in &self.r.macro_map[&def_id.to_def_id()].rule_spans { - self.r - .unused_macro_rules - .entry(node_id) - .or_default() - .insert(*rule_i, (ident, *rule_span)); - } + let nrules = self.r.local_macro_map[&def_id].nrules; + self.r.unused_macro_rules.insert(node_id, DenseBitSet::new_filled(nrules)); } } @@ -1228,7 +1224,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { Some((macro_kind, ident, span)) => { let res = Res::Def(DefKind::Macro(macro_kind), def_id.to_def_id()); let macro_data = MacroData::new(self.r.dummy_ext(macro_kind)); - self.r.macro_map.insert(def_id.to_def_id(), macro_data); + self.r.new_local_macro(def_id, macro_data); self.r.proc_macro_stubs.insert(def_id); (res, ident, span, false) } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index dc16fe212b1..e2caf632dd2 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -2,12 +2,12 @@ use std::mem; use rustc_ast::visit::FnKind; use rustc_ast::*; -use rustc_ast_pretty::pprust; -use rustc_attr_parsing::{AttributeParser, OmitDoc}; +use rustc_attr_parsing::{AttributeParser, Early, OmitDoc}; use rustc_expand::expand::AstFragment; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::def_id::LocalDefId; +use rustc_middle::span_bug; use rustc_span::hygiene::LocalExpnId; use rustc_span::{Span, Symbol, sym}; use tracing::debug; @@ -128,7 +128,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { // FIXME(jdonszelmann) make one of these in the resolver? // FIXME(jdonszelmann) don't care about tools here maybe? Just parse what we can. // Does that prevents errors from happening? maybe - let parser = AttributeParser::new( + let mut parser = AttributeParser::<'_, Early>::new( &self.resolver.tcx.sess, self.resolver.tcx.features(), Vec::new(), @@ -136,8 +136,14 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { let attrs = parser.parse_attribute_list( &i.attrs, i.span, + i.id, OmitDoc::Skip, std::convert::identity, + |_l| { + // FIXME(jdonszelmann): emit lints here properly + // NOTE that before new attribute parsing, they didn't happen either + // but it would be nice if we could change that. + }, ); let macro_data = @@ -159,7 +165,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { self.create_def(i.id, i.kind.ident().map(|ident| ident.name), def_kind, i.span); if let Some(macro_data) = opt_macro_data { - self.resolver.macro_map.insert(def_id.to_def_id(), macro_data); + self.resolver.new_local_macro(def_id, macro_data); } self.with_parent(def_id, |this| { @@ -374,20 +380,20 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } fn visit_ty(&mut self, ty: &'a Ty) { - match &ty.kind { + match ty.kind { TyKind::MacCall(..) => self.visit_macro_invoc(ty.id), - TyKind::ImplTrait(id, _) => { - // HACK: pprust breaks strings with newlines when the type - // gets too long. We don't want these to show up in compiler - // output or built artifacts, so replace them here... - // Perhaps we should instead format APITs more robustly. - let name = Symbol::intern(&pprust::ty_to_string(ty).replace('\n', " ")); + TyKind::ImplTrait(opaque_id, _) => { + let name = *self + .resolver + .impl_trait_names + .get(&ty.id) + .unwrap_or_else(|| span_bug!(ty.span, "expected this opaque to be named")); let kind = match self.invocation_parent.impl_trait_context { ImplTraitContext::Universal => DefKind::TyParam, ImplTraitContext::Existential => DefKind::OpaqueTy, ImplTraitContext::InBinding => return visit::walk_ty(self, ty), }; - let id = self.create_def(*id, Some(name), kind, ty.span); + let id = self.create_def(opaque_id, Some(name), kind, ty.span); match self.invocation_parent.impl_trait_context { // Do not nest APIT, as we desugar them as `impl_trait: bounds`, // so the `impl_trait` node is not a parent to `bounds`. diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 201b1c0a493..c4ff5770e76 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -5,9 +5,9 @@ use rustc_ast::{ self as ast, CRATE_NODE_ID, Crate, ItemKind, MetaItemInner, MetaItemKind, ModKind, NodeId, Path, }; use rustc_ast_pretty::pprust; -use rustc_attr_data_structures::{self as attr, Stability}; +use rustc_attr_data_structures::{self as attr, AttributeKind, Stability, find_attr}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::unord::UnordSet; +use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, MultiSpan, SuggestionStyle, @@ -256,22 +256,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; let label = match new_binding.is_import_user_facing() { - true => errors::NameDefinedMultipleTimeLabel::Reimported { span, name }, - false => errors::NameDefinedMultipleTimeLabel::Redefined { span, name }, + true => errors::NameDefinedMultipleTimeLabel::Reimported { span }, + false => errors::NameDefinedMultipleTimeLabel::Redefined { span }, }; let old_binding_label = (!old_binding.span.is_dummy() && old_binding.span != span).then(|| { let span = self.tcx.sess.source_map().guess_head_span(old_binding.span); match old_binding.is_import_user_facing() { - true => errors::NameDefinedMultipleTimeOldBindingLabel::Import { - span, - name, - old_kind, - }, + true => { + errors::NameDefinedMultipleTimeOldBindingLabel::Import { span, old_kind } + } false => errors::NameDefinedMultipleTimeOldBindingLabel::Definition { span, - name, old_kind, }, } @@ -281,6 +278,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .dcx() .create_err(errors::NameDefinedMultipleTime { span, + name, descr: ns.descr(), container, label, @@ -1054,6 +1052,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { false, false, None, + None, ) else { continue; }; @@ -1482,7 +1481,35 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, ident: Ident, krate: &Crate, + sugg_span: Option<Span>, ) { + // Bring imported but unused `derive` macros into `macro_map` so we ensure they can be used + // for suggestions. + self.visit_scopes( + ScopeSet::Macro(MacroKind::Derive), + &parent_scope, + ident.span.ctxt(), + |this, scope, _use_prelude, _ctxt| { + let Scope::Module(m, _) = scope else { + return None; + }; + for (_, resolution) in this.resolutions(m).borrow().iter() { + let Some(binding) = resolution.borrow().binding else { + continue; + }; + let Res::Def(DefKind::Macro(MacroKind::Derive | MacroKind::Attr), def_id) = + binding.res() + else { + continue; + }; + // By doing this all *imported* macros get added to the `macro_map` even if they + // are *unused*, which makes the later suggestions find them and work. + let _ = this.get_macro_by_def_id(def_id); + } + None::<()> + }, + ); + let is_expected = &|res: Res| res.macro_kind() == Some(macro_kind); let suggestion = self.early_lookup_typo_candidate( ScopeSet::Macro(macro_kind), @@ -1490,7 +1517,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, is_expected, ); - self.add_typo_suggestion(err, suggestion, ident.span); + if !self.add_typo_suggestion(err, suggestion, ident.span) { + self.detect_derive_attribute(err, ident, parent_scope, sugg_span); + } let import_suggestions = self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected); @@ -1623,6 +1652,110 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } + /// Given an attribute macro that failed to be resolved, look for `derive` macros that could + /// provide it, either as-is or with small typos. + fn detect_derive_attribute( + &self, + err: &mut Diag<'_>, + ident: Ident, + parent_scope: &ParentScope<'ra>, + sugg_span: Option<Span>, + ) { + // Find all of the `derive`s in scope and collect their corresponding declared + // attributes. + // FIXME: this only works if the crate that owns the macro that has the helper_attr + // has already been imported. + let mut derives = vec![]; + let mut all_attrs: UnordMap<Symbol, Vec<_>> = UnordMap::default(); + // We're collecting these in a hashmap, and handle ordering the output further down. + #[allow(rustc::potential_query_instability)] + for (def_id, data) in self + .local_macro_map + .iter() + .map(|(local_id, data)| (local_id.to_def_id(), data)) + .chain(self.extern_macro_map.borrow().iter().map(|(id, d)| (*id, d))) + { + for helper_attr in &data.ext.helper_attrs { + let item_name = self.tcx.item_name(def_id); + all_attrs.entry(*helper_attr).or_default().push(item_name); + if helper_attr == &ident.name { + derives.push(item_name); + } + } + } + let kind = MacroKind::Derive.descr(); + if !derives.is_empty() { + // We found an exact match for the missing attribute in a `derive` macro. Suggest it. + let mut derives: Vec<String> = derives.into_iter().map(|d| d.to_string()).collect(); + derives.sort(); + derives.dedup(); + let msg = match &derives[..] { + [derive] => format!(" `{derive}`"), + [start @ .., last] => format!( + "s {} and `{last}`", + start.iter().map(|d| format!("`{d}`")).collect::<Vec<_>>().join(", ") + ), + [] => unreachable!("we checked for this to be non-empty 10 lines above!?"), + }; + let msg = format!( + "`{}` is an attribute that can be used by the {kind}{msg}, you might be \ + missing a `derive` attribute", + ident.name, + ); + let sugg_span = if let ModuleKind::Def(DefKind::Enum, id, _) = parent_scope.module.kind + { + let span = self.def_span(id); + if span.from_expansion() { + None + } else { + // For enum variants sugg_span is empty but we can get the enum's Span. + Some(span.shrink_to_lo()) + } + } else { + // For items this `Span` will be populated, everything else it'll be None. + sugg_span + }; + match sugg_span { + Some(span) => { + err.span_suggestion_verbose( + span, + msg, + format!("#[derive({})]\n", derives.join(", ")), + Applicability::MaybeIncorrect, + ); + } + None => { + err.note(msg); + } + } + } else { + // We didn't find an exact match. Look for close matches. If any, suggest fixing typo. + let all_attr_names = all_attrs.keys().map(|s| *s).into_sorted_stable_ord(); + if let Some(best_match) = find_best_match_for_name(&all_attr_names, ident.name, None) + && let Some(macros) = all_attrs.get(&best_match) + { + let mut macros: Vec<String> = macros.into_iter().map(|d| d.to_string()).collect(); + macros.sort(); + macros.dedup(); + let msg = match ¯os[..] { + [] => return, + [name] => format!(" `{name}` accepts"), + [start @ .., end] => format!( + "s {} and `{end}` accept", + start.iter().map(|m| format!("`{m}`")).collect::<Vec<_>>().join(", "), + ), + }; + let msg = format!("the {kind}{msg} the similarly named `{best_match}` attribute"); + err.span_suggestion_verbose( + ident.span, + msg, + best_match, + Applicability::MaybeIncorrect, + ); + } + } + } + pub(crate) fn add_typo_suggestion( &self, err: &mut Diag<'_>, @@ -1870,9 +2003,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Otherwise, point out if the struct has any private fields. if let Some(def_id) = res.opt_def_id() && !def_id.is_local() - && let Some(attr) = self.tcx.get_attr(def_id, sym::non_exhaustive) + && let Some(attr_span) = find_attr!(self.tcx.get_all_attrs(def_id), AttributeKind::NonExhaustive(span) => *span) { - non_exhaustive = Some(attr.span()); + non_exhaustive = Some(attr_span); } else if let Some(span) = ctor_fields_span { let label = errors::ConstructorPrivateIfAnyFieldPrivate { span }; err.subdiagnostic(label); @@ -2293,6 +2426,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } else { let suggestion = if suggestion.is_some() { suggestion + } else if let Some(m) = self.undeclared_module_exists(ident) { + self.undeclared_module_suggest_declare(ident, m) } else if was_invoked_from_cargo() { Some(( vec![], @@ -2314,6 +2449,55 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } + fn undeclared_module_suggest_declare( + &mut self, + ident: Ident, + path: std::path::PathBuf, + ) -> Option<(Vec<(Span, String)>, String, Applicability)> { + Some(( + vec![(self.current_crate_outer_attr_insert_span, format!("mod {ident};\n"))], + format!( + "to make use of source file {}, use `mod {ident}` \ + in this file to declare the module", + path.display() + ), + Applicability::MaybeIncorrect, + )) + } + + fn undeclared_module_exists(&mut self, ident: Ident) -> Option<std::path::PathBuf> { + let map = self.tcx.sess.source_map(); + + let src = map.span_to_filename(ident.span).into_local_path()?; + let i = ident.as_str(); + // FIXME: add case where non parent using undeclared module (hard?) + let dir = src.parent()?; + let src = src.file_stem()?.to_str()?; + for file in [ + // …/x.rs + dir.join(i).with_extension("rs"), + // …/x/mod.rs + dir.join(i).join("mod.rs"), + ] { + if file.exists() { + return Some(file); + } + } + if !matches!(src, "main" | "lib" | "mod") { + for file in [ + // …/x/y.rs + dir.join(src).join(i).with_extension("rs"), + // …/x/y/mod.rs + dir.join(src).join(i).join("mod.rs"), + ] { + if file.exists() { + return Some(file); + } + } + } + None + } + /// Adds suggestions for a path that cannot be resolved. #[instrument(level = "debug", skip(self, parent_scope))] pub(crate) fn make_path_suggestion( diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 7fe74378b67..b34bcb38f84 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -878,12 +878,12 @@ pub(crate) struct MacroExpandedExternCrateCannotShadowExternArguments { #[derive(Diagnostic)] #[diag(resolve_elided_anonymous_lifetime_report_error, code = E0637)] -pub(crate) struct ElidedAnonymousLivetimeReportError { +pub(crate) struct ElidedAnonymousLifetimeReportError { #[primary_span] #[label] pub(crate) span: Span, #[subdiagnostic] - pub(crate) suggestion: Option<ElidedAnonymousLivetimeReportErrorSuggestion>, + pub(crate) suggestion: Option<ElidedAnonymousLifetimeReportErrorSuggestion>, } #[derive(Diagnostic)] @@ -897,7 +897,7 @@ pub(crate) struct LendingIteratorReportError { #[derive(Diagnostic)] #[diag(resolve_anonymous_lifetime_non_gat_report_error)] -pub(crate) struct AnonymousLivetimeNonGatReportError { +pub(crate) struct AnonymousLifetimeNonGatReportError { #[primary_span] #[label] pub(crate) lifetime: Span, @@ -908,7 +908,7 @@ pub(crate) struct AnonymousLivetimeNonGatReportError { resolve_elided_anonymous_lifetime_report_error_suggestion, applicability = "machine-applicable" )] -pub(crate) struct ElidedAnonymousLivetimeReportErrorSuggestion { +pub(crate) struct ElidedAnonymousLifetimeReportErrorSuggestion { #[suggestion_part(code = "for<'a> ")] pub(crate) lo: Span, #[suggestion_part(code = "'a ")] @@ -917,7 +917,7 @@ pub(crate) struct ElidedAnonymousLivetimeReportErrorSuggestion { #[derive(Diagnostic)] #[diag(resolve_explicit_anonymous_lifetime_report_error, code = E0637)] -pub(crate) struct ExplicitAnonymousLivetimeReportError { +pub(crate) struct ExplicitAnonymousLifetimeReportError { #[primary_span] #[label] pub(crate) span: Span, @@ -934,6 +934,7 @@ pub(crate) struct ImplicitElidedLifetimeNotAllowedHere { #[derive(Diagnostic)] #[diag(resolve_underscore_lifetime_is_reserved, code = E0637)] +#[help] pub(crate) struct UnderscoreLifetimeIsReserved { #[primary_span] #[label] @@ -978,6 +979,7 @@ pub(crate) struct VariableNotInAllPatterns { pub(crate) struct NameDefinedMultipleTime { #[primary_span] pub(crate) span: Span, + pub(crate) name: Symbol, pub(crate) descr: &'static str, pub(crate) container: &'static str, #[subdiagnostic] @@ -992,13 +994,11 @@ pub(crate) enum NameDefinedMultipleTimeLabel { Reimported { #[primary_span] span: Span, - name: Symbol, }, #[label(resolve_name_defined_multiple_time_redefined)] Redefined { #[primary_span] span: Span, - name: Symbol, }, } @@ -1008,14 +1008,12 @@ pub(crate) enum NameDefinedMultipleTimeOldBindingLabel { Import { #[primary_span] span: Span, - name: Symbol, old_kind: &'static str, }, #[label(resolve_name_defined_multiple_time_old_binding_definition)] Definition { #[primary_span] span: Span, - name: Symbol, old_kind: &'static str, }, } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 180d6af219d..558cbef0014 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -13,7 +13,7 @@ use rustc_span::{Ident, Span, kw, sym}; use tracing::{debug, instrument}; use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst}; -use crate::imports::Import; +use crate::imports::{Import, NameResolution}; use crate::late::{ConstantHasGenerics, NoConstantGenericsReason, PathSource, Rib, RibKind}; use crate::macros::{MacroRulesScope, sub_namespace_match}; use crate::{ @@ -37,7 +37,7 @@ impl From<UsePrelude> for bool { } } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Clone, Copy)] enum Shadowing { Restricted, Unrestricted, @@ -460,6 +460,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { true, force, ignore_import, + None, ) { Ok((Some(ext), _)) => { if ext.helper_attrs.contains(&ident.name) { @@ -878,53 +879,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .into_iter() .find_map(|binding| if binding == ignore_binding { None } else { binding }); - if let Some(Finalize { path_span, report_private, used, root_span, .. }) = finalize { - let Some(binding) = binding else { - return Err((Determined, Weak::No)); - }; - - if !self.is_accessible_from(binding.vis, parent_scope.module) { - if report_private { - self.privacy_errors.push(PrivacyError { - ident, - binding, - dedup_span: path_span, - outermost_res: None, - parent_scope: *parent_scope, - single_nested: path_span != root_span, - }); - } else { - return Err((Determined, Weak::No)); - } - } - - // Forbid expanded shadowing to avoid time travel. - if let Some(shadowed_glob) = resolution.shadowed_glob - && shadowing == Shadowing::Restricted - && binding.expansion != LocalExpnId::ROOT - && binding.res() != shadowed_glob.res() - { - self.ambiguity_errors.push(AmbiguityError { - kind: AmbiguityKind::GlobVsExpanded, - ident, - b1: binding, - b2: shadowed_glob, - warning: false, - misc1: AmbiguityErrorMisc::None, - misc2: AmbiguityErrorMisc::None, - }); - } - - if shadowing == Shadowing::Unrestricted - && binding.expansion != LocalExpnId::ROOT - && let NameBindingKind::Import { import, .. } = binding.kind - && matches!(import.kind, ImportKind::MacroExport) - { - self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); - } - - self.record_use(ident, binding, used); - return Ok(binding); + if let Some(finalize) = finalize { + return self.finalize_module_binding( + ident, + binding, + resolution.shadowed_glob, + parent_scope, + finalize, + shadowing, + ); } let check_usable = |this: &mut Self, binding: NameBinding<'ra>| { @@ -943,75 +906,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Check if one of single imports can still define the name, // if it can then our result is not determined and can be invalidated. - for single_import in &resolution.single_imports { - if ignore_import == Some(*single_import) { - // This branch handles a cycle in single imports. - // - // For example: - // ``` - // use a::b; - // use b as a; - // ``` - // 1. Record `use a::b` as the `ignore_import` and attempt to locate `a` in the - // current module. - // 2. Encounter the import `use b as a`, which is a `single_import` for `a`, - // and try to find `b` in the current module. - // 3. Re-encounter the `use a::b` import since it's a `single_import` of `b`. - // This leads to entering this branch. - continue; - } - if !self.is_accessible_from(single_import.vis, parent_scope.module) { - continue; - } - if let Some(ignored) = ignore_binding - && let NameBindingKind::Import { import, .. } = ignored.kind - && import == *single_import - { - // Ignore not just the binding itself, but if it has a shadowed_glob, - // ignore that, too, because this loop is supposed to only process - // named imports. - continue; - } - - let Some(module) = single_import.imported_module.get() else { - return Err((Undetermined, Weak::No)); - }; - let ImportKind::Single { source, target, target_bindings, .. } = &single_import.kind - else { - unreachable!(); - }; - if source != target { - // This branch allows the binding to be defined or updated later if the target name - // can hide the source. - if target_bindings.iter().all(|binding| binding.get().is_none()) { - // None of the target bindings are available, so we can't determine - // if this binding is correct or not. - // See more details in #124840 - return Err((Undetermined, Weak::No)); - } else if target_bindings[ns].get().is_none() && binding.is_some() { - // `binding.is_some()` avoids the condition where the binding - // truly doesn't exist in this namespace and should return `Err(Determined)`. - return Err((Undetermined, Weak::No)); - } - } - - match self.resolve_ident_in_module( - module, - *source, - ns, - &single_import.parent_scope, - None, - ignore_binding, - ignore_import, - ) { - Err((Determined, _)) => continue, - Ok(binding) - if !self.is_accessible_from(binding.vis, single_import.parent_scope.module) => - { - continue; - } - Ok(_) | Err((Undetermined, _)) => return Err((Undetermined, Weak::No)), - } + if self.single_import_can_define_name( + &resolution, + binding, + ns, + ignore_import, + ignore_binding, + parent_scope, + ) { + return Err((Undetermined, Weak::No)); } // So we have a resolution that's from a glob import. This resolution is determined @@ -1100,6 +1003,129 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Err((Determined, Weak::No)) } + fn finalize_module_binding( + &mut self, + ident: Ident, + binding: Option<NameBinding<'ra>>, + shadowed_glob: Option<NameBinding<'ra>>, + parent_scope: &ParentScope<'ra>, + finalize: Finalize, + shadowing: Shadowing, + ) -> Result<NameBinding<'ra>, (Determinacy, Weak)> { + let Finalize { path_span, report_private, used, root_span, .. } = finalize; + + let Some(binding) = binding else { + return Err((Determined, Weak::No)); + }; + + if !self.is_accessible_from(binding.vis, parent_scope.module) { + if report_private { + self.privacy_errors.push(PrivacyError { + ident, + binding, + dedup_span: path_span, + outermost_res: None, + parent_scope: *parent_scope, + single_nested: path_span != root_span, + }); + } else { + return Err((Determined, Weak::No)); + } + } + + // Forbid expanded shadowing to avoid time travel. + if let Some(shadowed_glob) = shadowed_glob + && shadowing == Shadowing::Restricted + && binding.expansion != LocalExpnId::ROOT + && binding.res() != shadowed_glob.res() + { + self.ambiguity_errors.push(AmbiguityError { + kind: AmbiguityKind::GlobVsExpanded, + ident, + b1: binding, + b2: shadowed_glob, + warning: false, + misc1: AmbiguityErrorMisc::None, + misc2: AmbiguityErrorMisc::None, + }); + } + + if shadowing == Shadowing::Unrestricted + && binding.expansion != LocalExpnId::ROOT + && let NameBindingKind::Import { import, .. } = binding.kind + && matches!(import.kind, ImportKind::MacroExport) + { + self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); + } + + self.record_use(ident, binding, used); + return Ok(binding); + } + + // Checks if a single import can define the `Ident` corresponding to `binding`. + // This is used to check whether we can definitively accept a glob as a resolution. + fn single_import_can_define_name( + &mut self, + resolution: &NameResolution<'ra>, + binding: Option<NameBinding<'ra>>, + ns: Namespace, + ignore_import: Option<Import<'ra>>, + ignore_binding: Option<NameBinding<'ra>>, + parent_scope: &ParentScope<'ra>, + ) -> bool { + for single_import in &resolution.single_imports { + if ignore_import == Some(*single_import) { + continue; + } + if !self.is_accessible_from(single_import.vis, parent_scope.module) { + continue; + } + if let Some(ignored) = ignore_binding + && let NameBindingKind::Import { import, .. } = ignored.kind + && import == *single_import + { + continue; + } + + let Some(module) = single_import.imported_module.get() else { + return true; + }; + let ImportKind::Single { source, target, target_bindings, .. } = &single_import.kind + else { + unreachable!(); + }; + if source != target { + if target_bindings.iter().all(|binding| binding.get().is_none()) { + return true; + } else if target_bindings[ns].get().is_none() && binding.is_some() { + return true; + } + } + + match self.resolve_ident_in_module( + module, + *source, + ns, + &single_import.parent_scope, + None, + ignore_binding, + ignore_import, + ) { + Err((Determined, _)) => continue, + Ok(binding) + if !self.is_accessible_from(binding.vis, single_import.parent_scope.module) => + { + continue; + } + Ok(_) | Err((Undetermined, _)) => { + return true; + } + } + } + + false + } + /// Validate a local resolution (from ribs). #[instrument(level = "debug", skip(self, all_ribs))] fn validate_res_from_ribs( diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 816efd0d5fa..2e81b54b136 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -133,7 +133,9 @@ impl<'ra> std::fmt::Debug for ImportKind<'ra> { .field("target", target) .field("id", id) .finish(), - MacroUse { .. } => f.debug_struct("MacroUse").finish(), + MacroUse { warn_private } => { + f.debug_struct("MacroUse").field("warn_private", warn_private).finish() + } MacroExport => f.debug_struct("MacroExport").finish(), } } @@ -172,7 +174,14 @@ pub(crate) struct ImportData<'ra> { pub parent_scope: ParentScope<'ra>, pub module_path: Vec<Segment>, - /// The resolution of `module_path`. + /// The resolution of `module_path`: + /// + /// | `module_path` | `imported_module` | remark | + /// |-|-|-| + /// |`use prefix::foo`| `ModuleOrUniformRoot::Module(prefix)` | - | + /// |`use ::foo` | `ModuleOrUniformRoot::ExternPrelude` | 2018+ editions | + /// |`use ::foo` | `ModuleOrUniformRoot::CrateRootAndExternPrelude` | a special case in 2015 edition | + /// |`use foo` | `ModuleOrUniformRoot::CurrentScope` | - | pub imported_module: Cell<Option<ModuleOrUniformRoot<'ra>>>, pub vis: ty::Visibility, } @@ -606,7 +615,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - self.throw_unresolved_import_error(errors, glob_error); + if !errors.is_empty() { + self.throw_unresolved_import_error(errors, glob_error); + } } pub(crate) fn check_hidden_glob_reexports( @@ -686,14 +697,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(def_id) if self.mods_with_parse_errors.contains(&def_id) => false, _ => true, }); + errors.retain(|(_import, err)| { + // If we've encountered something like `use _;`, we've already emitted an error stating + // that `_` is not a valid identifier, so we ignore that resolve error. + err.segment != Some(kw::Underscore) + }); + if errors.is_empty() { + self.tcx.dcx().delayed_bug("expected a parse or \"`_` can't be an identifier\" error"); return; } - /// Upper limit on the number of `span_label` messages. - const MAX_LABEL_COUNT: usize = 10; - let span = MultiSpan::from_spans(errors.iter().map(|(_, err)| err.span).collect()); + let paths = errors .iter() .map(|(import, err)| { @@ -713,6 +729,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { diag.note(note.clone()); } + /// Upper limit on the number of `span_label` messages. + const MAX_LABEL_COUNT: usize = 10; + for (import, err) in errors.into_iter().take(MAX_LABEL_COUNT) { if let Some(label) = err.label { diag.span_label(err.span, label); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 3dc285fdab6..08629090bb1 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -370,7 +370,7 @@ enum LifetimeRibKind { #[derive(Copy, Clone, Debug)] enum LifetimeBinderKind { - BareFnType, + FnPtrType, PolyTrait, WhereBound, Item, @@ -384,7 +384,7 @@ impl LifetimeBinderKind { fn descr(self) -> &'static str { use LifetimeBinderKind::*; match self { - BareFnType => "type", + FnPtrType => "type", PolyTrait => "bound", WhereBound => "bound", Item | ConstItem => "item", @@ -415,24 +415,24 @@ pub(crate) enum AliasPossibility { } #[derive(Copy, Clone, Debug)] -pub(crate) enum PathSource<'a, 'c> { +pub(crate) enum PathSource<'a, 'ast, 'ra> { /// Type paths `Path`. Type, /// Trait paths in bounds or impls. Trait(AliasPossibility), /// Expression paths `path`, with optional parent context. - Expr(Option<&'a Expr>), + Expr(Option<&'ast Expr>), /// Paths in path patterns `Path`. Pat, /// Paths in struct expressions and patterns `Path { .. }`. Struct, /// Paths in tuple struct patterns `Path(..)`. - TupleStruct(Span, &'a [Span]), + TupleStruct(Span, &'ra [Span]), /// `m::A::B` in `<T as m::A>::B::C`. /// /// Second field holds the "cause" of this one, i.e. the context within /// which the trait item is resolved. Used for diagnostics. - TraitItem(Namespace, &'c PathSource<'a, 'c>), + TraitItem(Namespace, &'a PathSource<'a, 'ast, 'ra>), /// Paths in delegation item Delegation, /// An arg in a `use<'a, N>` precise-capturing bound. @@ -443,7 +443,7 @@ pub(crate) enum PathSource<'a, 'c> { DefineOpaques, } -impl<'a> PathSource<'a, '_> { +impl PathSource<'_, '_, '_> { fn namespace(self) -> Namespace { match self { PathSource::Type @@ -773,7 +773,7 @@ struct LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } /// Walks the whole crate in DFS order, visiting each item, resolving names as it goes. -impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { +impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn visit_attribute(&mut self, _: &'ast Attribute) { // We do not want to resolve expressions that appear in attributes, // as they do not correspond to actual code. @@ -869,11 +869,9 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r self.with_generic_param_rib( &[], RibKind::Normal, - LifetimeRibKind::Generics { - binder: ty.id, - kind: LifetimeBinderKind::PolyTrait, - span, - }, + ty.id, + LifetimeBinderKind::PolyTrait, + span, |this| this.visit_path(path), ); } else { @@ -902,18 +900,16 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r self.diag_metadata.current_trait_object = Some(&bounds[..]); visit::walk_ty(self, ty) } - TyKind::BareFn(bare_fn) => { - let span = ty.span.shrink_to_lo().to(bare_fn.decl_span.shrink_to_lo()); + TyKind::FnPtr(fn_ptr) => { + let span = ty.span.shrink_to_lo().to(fn_ptr.decl_span.shrink_to_lo()); self.with_generic_param_rib( - &bare_fn.generic_params, + &fn_ptr.generic_params, RibKind::Normal, - LifetimeRibKind::Generics { - binder: ty.id, - kind: LifetimeBinderKind::BareFnType, - span, - }, + ty.id, + LifetimeBinderKind::FnPtrType, + span, |this| { - this.visit_generic_params(&bare_fn.generic_params, false); + this.visit_generic_params(&fn_ptr.generic_params, false); this.with_lifetime_rib( LifetimeRibKind::AnonymousCreateParameter { binder: ty.id, @@ -925,12 +921,8 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r false, // We don't need to deal with patterns in parameters, because // they are not possible for foreign or bodiless functions. - bare_fn - .decl - .inputs - .iter() - .map(|Param { ty, .. }| (None, &**ty)), - &bare_fn.decl.output, + fn_ptr.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)), + &fn_ptr.decl.output, ) }, ); @@ -942,11 +934,9 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r self.with_generic_param_rib( &unsafe_binder.generic_params, RibKind::Normal, - LifetimeRibKind::Generics { - binder: ty.id, - kind: LifetimeBinderKind::BareFnType, - span, - }, + ty.id, + LifetimeBinderKind::FnPtrType, + span, |this| { this.visit_generic_params(&unsafe_binder.generic_params, false); this.with_lifetime_rib( @@ -995,11 +985,9 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r self.with_generic_param_rib( &tref.bound_generic_params, RibKind::Normal, - LifetimeRibKind::Generics { - binder: tref.trait_ref.ref_id, - kind: LifetimeBinderKind::PolyTrait, - span, - }, + tref.trait_ref.ref_id, + LifetimeBinderKind::PolyTrait, + span, |this| { this.visit_generic_params(&tref.bound_generic_params, false); this.smart_resolve_path( @@ -1020,11 +1008,9 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r self.with_generic_param_rib( &generics.params, RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), - LifetimeRibKind::Generics { - binder: foreign_item.id, - kind: LifetimeBinderKind::Item, - span: generics.span, - }, + foreign_item.id, + LifetimeBinderKind::Item, + generics.span, |this| visit::walk_item(this, foreign_item), ); } @@ -1032,11 +1018,9 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r self.with_generic_param_rib( &generics.params, RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), - LifetimeRibKind::Generics { - binder: foreign_item.id, - kind: LifetimeBinderKind::Function, - span: generics.span, - }, + foreign_item.id, + LifetimeBinderKind::Function, + generics.span, |this| visit::walk_item(this, foreign_item), ); } @@ -1374,11 +1358,9 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r this.with_generic_param_rib( bound_generic_params, RibKind::Normal, - LifetimeRibKind::Generics { - binder: bounded_ty.id, - kind: LifetimeBinderKind::WhereBound, - span, - }, + bounded_ty.id, + LifetimeBinderKind::WhereBound, + span, |this| { this.visit_generic_params(bound_generic_params, false); this.visit_ty(bounded_ty); @@ -1432,11 +1414,14 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r fn visit_variant(&mut self, v: &'ast Variant) { self.resolve_doc_links(&v.attrs, MaybeExported::Ok(v.id)); - visit::walk_variant(self, v) - } - - fn visit_variant_discr(&mut self, discr: &'ast AnonConst) { - self.resolve_anon_const(discr, AnonConstKind::EnumDiscriminant); + self.visit_id(v.id); + walk_list!(self, visit_attribute, &v.attrs); + self.visit_vis(&v.vis); + self.visit_ident(&v.ident); + self.visit_variant_data(&v.data); + if let Some(discr) = &v.disr_expr { + self.resolve_anon_const(discr, AnonConstKind::EnumDiscriminant); + } } fn visit_field_def(&mut self, f: &'ast FieldDef) { @@ -1462,7 +1447,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r } } -impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { +impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { fn new(resolver: &'a mut Resolver<'ra, 'tcx>) -> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // During late resolution we only track the module component of the parent scope, // although it may be useful to track other components as well for diagnostics. @@ -1667,7 +1652,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { forward_ty_ban_rib.bindings.swap_remove(i); forward_ty_ban_rib_const_param_ty.bindings.swap_remove(i); } - GenericParamKind::Const { ref ty, kw_span: _, ref default } => { + GenericParamKind::Const { ref ty, span: _, ref default } => { // Const parameters can't have param bounds. assert!(param.bounds.is_empty()); @@ -1903,7 +1888,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { .. } = rib.kind { - Some(errors::ElidedAnonymousLivetimeReportErrorSuggestion { + Some(errors::ElidedAnonymousLifetimeReportErrorSuggestion { lo: span.shrink_to_lo(), hi: lifetime.ident.span.shrink_to_hi(), }) @@ -1929,18 +1914,18 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ty: ty.span, }); } else { - self.r.dcx().emit_err(errors::AnonymousLivetimeNonGatReportError { + self.r.dcx().emit_err(errors::AnonymousLifetimeNonGatReportError { lifetime: lifetime.ident.span, }); } } else { - self.r.dcx().emit_err(errors::ElidedAnonymousLivetimeReportError { + self.r.dcx().emit_err(errors::ElidedAnonymousLifetimeReportError { span: lifetime.ident.span, suggestion, }); } } else { - self.r.dcx().emit_err(errors::ExplicitAnonymousLivetimeReportError { + self.r.dcx().emit_err(errors::ExplicitAnonymousLifetimeReportError { span: lifetime.ident.span, }); }; @@ -2010,7 +1995,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { &mut self, partial_res: PartialRes, path: &[Segment], - source: PathSource<'_, '_>, + source: PathSource<'_, '_, '_>, path_span: Span, ) { let proj_start = path.len() - partial_res.unresolved_segments(); @@ -2555,11 +2540,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { this.with_generic_param_rib( &generics.params, RibKind::Item(HasGenericParams::Yes(generics.span), kind), - LifetimeRibKind::Generics { - binder: item.id, - kind: LifetimeBinderKind::Item, - span: generics.span, - }, + item.id, + LifetimeBinderKind::Item, + generics.span, |this| { let item_def_id = this.r.local_def_id(item.id).to_def_id(); this.with_self_rib( @@ -2632,11 +2615,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &generics.params, RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), - LifetimeRibKind::Generics { - binder: item.id, - kind: LifetimeBinderKind::Item, - span: generics.span, - }, + item.id, + LifetimeBinderKind::Item, + generics.span, |this| visit::walk_item(this, item), ); } @@ -2645,11 +2626,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &generics.params, RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), - LifetimeRibKind::Generics { - binder: item.id, - kind: LifetimeBinderKind::Function, - span: generics.span, - }, + item.id, + LifetimeBinderKind::Function, + generics.span, |this| visit::walk_item(this, item), ); self.resolve_define_opaques(define_opaque); @@ -2685,11 +2664,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &generics.params, RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), - LifetimeRibKind::Generics { - binder: item.id, - kind: LifetimeBinderKind::Item, - span: generics.span, - }, + item.id, + LifetimeBinderKind::Item, + generics.span, |this| { let local_def_id = this.r.local_def_id(item.id).to_def_id(); this.with_self_rib(Res::SelfTyParam { trait_: local_def_id }, |this| { @@ -2706,11 +2683,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &generics.params, RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), - LifetimeRibKind::Generics { - binder: item.id, - kind: LifetimeBinderKind::Item, - span: generics.span, - }, + item.id, + LifetimeBinderKind::Item, + generics.span, |this| { let local_def_id = this.r.local_def_id(item.id).to_def_id(); this.with_self_rib(Res::SelfTyParam { trait_: local_def_id }, |this| { @@ -2776,11 +2751,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }, def_kind, ), - LifetimeRibKind::Generics { - binder: item.id, - kind: LifetimeBinderKind::ConstItem, - span: generics.span, - }, + item.id, + LifetimeBinderKind::ConstItem, + generics.span, |this| { this.visit_generics(generics); @@ -2825,11 +2798,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &[], RibKind::Item(HasGenericParams::Yes(span), def_kind), - LifetimeRibKind::Generics { - binder: item.id, - kind: LifetimeBinderKind::Function, - span, - }, + item.id, + LifetimeBinderKind::Function, + span, |this| this.resolve_delegation(delegation), ); } @@ -2846,17 +2817,16 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { &'c mut self, params: &'c [GenericParam], kind: RibKind<'ra>, - lifetime_kind: LifetimeRibKind, + binder: NodeId, + generics_kind: LifetimeBinderKind, + generics_span: Span, f: F, ) where F: FnOnce(&mut Self), { debug!("with_generic_param_rib"); - let LifetimeRibKind::Generics { binder, span: generics_span, kind: generics_kind, .. } = - lifetime_kind - else { - panic!() - }; + let lifetime_kind = + LifetimeRibKind::Generics { binder, span: generics_span, kind: generics_kind }; let mut function_type_rib = Rib::new(kind); let mut function_value_rib = Rib::new(kind); @@ -3002,7 +2972,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } } - if let LifetimeBinderKind::BareFnType + if let LifetimeBinderKind::FnPtrType | LifetimeBinderKind::WhereBound | LifetimeBinderKind::Function | LifetimeBinderKind::ImplBlock = generics_kind @@ -3086,7 +3056,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { this.with_generic_param_rib( &generics.params, RibKind::AssocItem, - LifetimeRibKind::Generics { binder: item.id, span: generics.span, kind }, + item.id, + kind, + generics.span, |this| visit::walk_assoc_item(this, item, AssocCtxt::Trait), ); }; @@ -3104,11 +3076,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &generics.params, RibKind::AssocItem, - LifetimeRibKind::Generics { - binder: item.id, - span: generics.span, - kind: LifetimeBinderKind::ConstItem, - }, + item.id, + LifetimeBinderKind::ConstItem, + generics.span, |this| { this.with_lifetime_rib( LifetimeRibKind::StaticIfNoLifetimeInScope { @@ -3145,11 +3115,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &[], RibKind::AssocItem, - LifetimeRibKind::Generics { - binder: item.id, - kind: LifetimeBinderKind::Function, - span: delegation.path.segments.last().unwrap().ident.span, - }, + item.id, + LifetimeBinderKind::Function, + delegation.path.segments.last().unwrap().ident.span, |this| this.resolve_delegation(delegation), ); } @@ -3227,11 +3195,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &generics.params, RibKind::Item(HasGenericParams::Yes(generics.span), self.r.local_def_kind(item_id)), - LifetimeRibKind::Generics { - span: generics.span, - binder: item_id, - kind: LifetimeBinderKind::ImplBlock, - }, + item_id, + LifetimeBinderKind::ImplBlock, + generics.span, |this| { // Dummy self type for better errors if `Self` is used in the trait path. this.with_self_rib(Res::SelfTyParam { trait_: LOCAL_CRATE.as_def_id() }, |this| { @@ -3316,15 +3282,14 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &generics.params, RibKind::AssocItem, - LifetimeRibKind::Generics { - binder: item.id, - span: generics.span, - kind: LifetimeBinderKind::ConstItem, - }, + item.id, + LifetimeBinderKind::ConstItem, + generics.span, |this| { this.with_lifetime_rib( - // Until these are a hard error, we need to create them within the correct binder, - // Otherwise the lifetimes of this assoc const think they are lifetimes of the trait. + // Until these are a hard error, we need to create them within the + // correct binder, Otherwise the lifetimes of this assoc const think + // they are lifetimes of the trait. LifetimeRibKind::AnonymousCreateParameter { binder: item.id, report_in_path: true, @@ -3373,11 +3338,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &generics.params, RibKind::AssocItem, - LifetimeRibKind::Generics { - binder: item.id, - span: generics.span, - kind: LifetimeBinderKind::Function, - }, + item.id, + LifetimeBinderKind::Function, + generics.span, |this| { // If this is a trait impl, ensure the method // exists in trait @@ -3404,11 +3367,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &generics.params, RibKind::AssocItem, - LifetimeRibKind::Generics { - binder: item.id, - span: generics.span, - kind: LifetimeBinderKind::Item, - }, + item.id, + LifetimeBinderKind::Item, + generics.span, |this| { this.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { // If this is a trait impl, ensure the type @@ -3434,11 +3395,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &[], RibKind::AssocItem, - LifetimeRibKind::Generics { - binder: item.id, - kind: LifetimeBinderKind::Function, - span: delegation.path.segments.last().unwrap().ident.span, - }, + item.id, + LifetimeBinderKind::Function, + delegation.path.segments.last().unwrap().ident.span, |this| { this.check_trait_item( item.id, @@ -4161,7 +4120,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { id: NodeId, qself: &Option<P<QSelf>>, path: &Path, - source: PathSource<'ast, '_>, + source: PathSource<'_, 'ast, '_>, ) { self.smart_resolve_path_fragment( qself, @@ -4178,7 +4137,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { &mut self, qself: &Option<P<QSelf>>, path: &[Segment], - source: PathSource<'ast, '_>, + source: PathSource<'_, 'ast, '_>, finalize: Finalize, record_partial_res: RecordPartialRes, parent_qself: Option<&QSelf>, @@ -4482,7 +4441,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { span: Span, defer_to_typeck: bool, finalize: Finalize, - source: PathSource<'ast, '_>, + source: PathSource<'_, 'ast, '_>, ) -> Result<Option<PartialRes>, Spanned<ResolutionError<'ra>>> { let mut fin_res = None; @@ -4509,7 +4468,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident); let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None }; if let Ok((_, res)) = - self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false, None) + self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false, None, None) { return Ok(Some(PartialRes::new(res))); } @@ -4525,7 +4484,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { path: &[Segment], ns: Namespace, finalize: Finalize, - source: PathSource<'ast, '_>, + source: PathSource<'_, 'ast, '_>, ) -> Result<Option<PartialRes>, Spanned<ResolutionError<'ra>>> { debug!( "resolve_qpath(qself={:?}, path={:?}, ns={:?}, finalize={:?})", @@ -4951,11 +4910,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( generic_params, RibKind::Normal, - LifetimeRibKind::Generics { - binder: expr.id, - kind: LifetimeBinderKind::Closure, - span, - }, + expr.id, + LifetimeBinderKind::Closure, + span, |this| visit::walk_expr(this, expr), ); } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 2f6aed35f25..8114021510e 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -170,12 +170,12 @@ impl TypoCandidate { } } -impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { +impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn make_base_error( &mut self, path: &[Segment], span: Span, - source: PathSource<'_, '_>, + source: PathSource<'_, '_, '_>, res: Option<Res>, ) -> BaseError { // Make the base error. @@ -328,8 +328,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let module_did = mod_prefix.as_ref().and_then(Res::mod_def_id); let mod_prefix = - mod_prefix.map_or_else(String::new, |res| (format!("{} ", res.descr()))); - + mod_prefix.map_or_else(String::new, |res| format!("{} ", res.descr())); (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)), module_did, None) }; @@ -421,7 +420,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { path: &[Segment], following_seg: Option<&Segment>, span: Span, - source: PathSource<'_, '_>, + source: PathSource<'_, '_, '_>, res: Option<Res>, qself: Option<&QSelf>, ) -> (Diag<'tcx>, Vec<ImportSuggestion>) { @@ -539,7 +538,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { path: &[Segment], following_seg: Option<&Segment>, span: Span, - source: PathSource<'_, '_>, + source: PathSource<'_, '_, '_>, res: Option<Res>, qself: Option<&QSelf>, ) { @@ -650,7 +649,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn try_lookup_name_relaxed( &mut self, err: &mut Diag<'_>, - source: PathSource<'_, '_>, + source: PathSource<'_, '_, '_>, path: &[Segment], following_seg: Option<&Segment>, span: Span, @@ -940,7 +939,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn suggest_trait_and_bounds( &mut self, err: &mut Diag<'_>, - source: PathSource<'_, '_>, + source: PathSource<'_, '_, '_>, res: Option<Res>, span: Span, base_error: &BaseError, @@ -1017,7 +1016,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn suggest_typo( &mut self, err: &mut Diag<'_>, - source: PathSource<'_, '_>, + source: PathSource<'_, '_, '_>, path: &[Segment], following_seg: Option<&Segment>, span: Span, @@ -1063,7 +1062,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn suggest_shadowed( &mut self, err: &mut Diag<'_>, - source: PathSource<'_, '_>, + source: PathSource<'_, '_, '_>, path: &[Segment], following_seg: Option<&Segment>, span: Span, @@ -1096,7 +1095,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn err_code_special_cases( &mut self, err: &mut Diag<'_>, - source: PathSource<'_, '_>, + source: PathSource<'_, '_, '_>, path: &[Segment], span: Span, ) { @@ -1141,7 +1140,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn suggest_self_ty( &mut self, err: &mut Diag<'_>, - source: PathSource<'_, '_>, + source: PathSource<'_, '_, '_>, path: &[Segment], span: Span, ) -> bool { @@ -1164,7 +1163,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn suggest_self_value( &mut self, err: &mut Diag<'_>, - source: PathSource<'_, '_>, + source: PathSource<'_, '_, '_>, path: &[Segment], span: Span, ) -> bool { @@ -1183,15 +1182,23 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { _ => "`self` value is a keyword only available in methods with a `self` parameter", }, ); + + // using `let self` is wrong even if we're not in an associated method or if we're in a macro expansion. + // So, we should return early if we're in a pattern, see issue #143134. + if matches!(source, PathSource::Pat) { + return true; + } + let is_assoc_fn = self.self_type_is_available(); let self_from_macro = "a `self` parameter, but a macro invocation can only \ access identifiers it receives from parameters"; - if let Some((fn_kind, span)) = &self.diag_metadata.current_function { + if let Some((fn_kind, fn_span)) = &self.diag_metadata.current_function { // The current function has a `self` parameter, but we were unable to resolve // a reference to `self`. This can only happen if the `self` identifier we - // are resolving came from a different hygiene context. + // are resolving came from a different hygiene context or a variable binding. + // But variable binding error is returned early above. if fn_kind.decl().inputs.get(0).is_some_and(|p| p.is_self()) { - err.span_label(*span, format!("this function has {self_from_macro}")); + err.span_label(*fn_span, format!("this function has {self_from_macro}")); } else { let doesnt = if is_assoc_fn { let (span, sugg) = fn_kind @@ -1204,7 +1211,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // This avoids placing the suggestion into the visibility specifier. let span = fn_kind .ident() - .map_or(*span, |ident| span.with_lo(ident.span.hi())); + .map_or(*fn_span, |ident| fn_span.with_lo(ident.span.hi())); ( self.r .tcx @@ -1332,7 +1339,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn suggest_swapping_misplaced_self_ty_and_trait( &mut self, err: &mut Diag<'_>, - source: PathSource<'_, '_>, + source: PathSource<'_, '_, '_>, res: Option<Res>, span: Span, ) { @@ -1361,7 +1368,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { &mut self, err: &mut Diag<'_>, res: Option<Res>, - source: PathSource<'_, '_>, + source: PathSource<'_, '_, '_>, ) { let PathSource::TupleStruct(_, _) = source else { return }; let Some(Res::Def(DefKind::Fn, _)) = res else { return }; @@ -1373,7 +1380,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { &mut self, err: &mut Diag<'_>, res: Option<Res>, - source: PathSource<'_, '_>, + source: PathSource<'_, '_, '_>, span: Span, ) { let PathSource::Trait(_) = source else { return }; @@ -1422,7 +1429,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn suggest_pattern_match_with_let( &mut self, err: &mut Diag<'_>, - source: PathSource<'_, '_>, + source: PathSource<'_, '_, '_>, span: Span, ) -> bool { if let PathSource::Expr(_) = source @@ -1448,7 +1455,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn get_single_associated_item( &mut self, path: &[Segment], - source: &PathSource<'_, '_>, + source: &PathSource<'_, '_, '_>, filter_fn: &impl Fn(Res) -> bool, ) -> Option<TypoSuggestion> { if let crate::PathSource::TraitItem(_, _) = source { @@ -1556,7 +1563,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { /// Check if the source is call expression and the first argument is `self`. If true, /// return the span of whole call and the span for all arguments expect the first one (`self`). - fn call_has_self_arg(&self, source: PathSource<'_, '_>) -> Option<(Span, Option<Span>)> { + fn call_has_self_arg(&self, source: PathSource<'_, '_, '_>) -> Option<(Span, Option<Span>)> { let mut has_self_arg = None; if let PathSource::Expr(Some(parent)) = source && let ExprKind::Call(_, args) = &parent.kind @@ -1614,7 +1621,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { &mut self, err: &mut Diag<'_>, span: Span, - source: PathSource<'_, '_>, + source: PathSource<'_, '_, '_>, path: &[Segment], res: Res, path_str: &str, @@ -1666,7 +1673,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } }; - let find_span = |source: &PathSource<'_, '_>, err: &mut Diag<'_>| { + let find_span = |source: &PathSource<'_, '_, '_>, err: &mut Diag<'_>| { match source { PathSource::Expr(Some(Expr { span, kind: ExprKind::Call(_, _), .. })) | PathSource::TupleStruct(span, _) => { @@ -2699,7 +2706,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn suggest_using_enum_variant( &mut self, err: &mut Diag<'_>, - source: PathSource<'_, '_>, + source: PathSource<'_, '_, '_>, def_id: DefId, span: Span, ) { @@ -2877,7 +2884,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { pub(crate) fn suggest_adding_generic_parameter( &self, path: &[Segment], - source: PathSource<'_, '_>, + source: PathSource<'_, '_, '_>, ) -> Option<(Span, &'static str, String, Applicability)> { let (ident, span) = match path { [segment] @@ -2940,7 +2947,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let span = if let [.., bound] = ¶m.bounds[..] { bound.span() } else if let GenericParam { - kind: GenericParamKind::Const { ty, kw_span: _, default }, .. + kind: GenericParamKind::Const { ty, span: _, default }, .. } = param { default.as_ref().map(|def| def.value.span).unwrap_or(ty.span) } else { @@ -3122,15 +3129,10 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { &mut err, Some(lifetime_ref.ident.name.as_str()), |err, _, span, message, suggestion, span_suggs| { - err.multipart_suggestion_with_style( + err.multipart_suggestion_verbose( message, std::iter::once((span, suggestion)).chain(span_suggs.clone()).collect(), Applicability::MaybeIncorrect, - if span_suggs.is_empty() { - SuggestionStyle::ShowCode - } else { - SuggestionStyle::ShowAlways - }, ); true }, @@ -3182,7 +3184,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let higher_ranked = matches!( kind, - LifetimeBinderKind::BareFnType + LifetimeBinderKind::FnPtrType | LifetimeBinderKind::PolyTrait | LifetimeBinderKind::WhereBound ); @@ -3837,6 +3839,7 @@ fn mk_where_bound_predicate( ref_id: DUMMY_NODE_ID, }, span: DUMMY_SP, + parens: ast::Parens::No, })], }; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 9ba70abd4d9..6e4c5ef1909 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -46,7 +46,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::FreezeReadGuard; -use rustc_data_structures::unord::UnordMap; +use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::{Applicability, Diag, ErrCode, ErrorGuaranteed}; use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind}; use rustc_feature::BUILTIN_ATTRIBUTES; @@ -57,6 +57,7 @@ use rustc_hir::def::{ use rustc_hir::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalDefIdMap}; use rustc_hir::definitions::DisambiguatorState; use rustc_hir::{PrimTy, TraitCandidate}; +use rustc_index::bit_set::DenseBitSet; use rustc_metadata::creader::{CStore, CrateLoader}; use rustc_middle::metadata::ModChild; use rustc_middle::middle::privacy::EffectiveVisibilities; @@ -1014,13 +1015,13 @@ struct DeriveData { struct MacroData { ext: Arc<SyntaxExtension>, - rule_spans: Vec<(usize, Span)>, + nrules: usize, macro_rules: bool, } impl MacroData { fn new(ext: Arc<SyntaxExtension>) -> MacroData { - MacroData { ext, rule_spans: Vec::new(), macro_rules: false } + MacroData { ext, nrules: 0, macro_rules: false } } } @@ -1031,7 +1032,7 @@ pub struct Resolver<'ra, 'tcx> { tcx: TyCtxt<'tcx>, /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`. - expn_that_defined: FxHashMap<LocalDefId, ExpnId>, + expn_that_defined: UnordMap<LocalDefId, ExpnId>, graph_root: Module<'ra>, @@ -1127,19 +1128,21 @@ pub struct Resolver<'ra, 'tcx> { builtin_macros: FxHashMap<Symbol, SyntaxExtensionKind>, registered_tools: &'tcx RegisteredTools, macro_use_prelude: FxIndexMap<Symbol, NameBinding<'ra>>, - macro_map: FxHashMap<DefId, MacroData>, + local_macro_map: FxHashMap<LocalDefId, &'ra MacroData>, + /// Lazily populated cache of macros loaded from external crates. + extern_macro_map: RefCell<FxHashMap<DefId, &'ra MacroData>>, dummy_ext_bang: Arc<SyntaxExtension>, dummy_ext_derive: Arc<SyntaxExtension>, - non_macro_attr: MacroData, + non_macro_attr: &'ra MacroData, local_macro_def_scopes: FxHashMap<LocalDefId, Module<'ra>>, ast_transform_scopes: FxHashMap<LocalExpnId, Module<'ra>>, unused_macros: FxIndexMap<LocalDefId, (NodeId, Ident)>, /// A map from the macro to all its potentially unused arms. - unused_macro_rules: FxIndexMap<NodeId, UnordMap<usize, (Ident, Span)>>, + unused_macro_rules: FxIndexMap<NodeId, DenseBitSet<usize>>, proc_macro_stubs: FxHashSet<LocalDefId>, /// Traces collected during macro resolution and validated when it's complete. single_segment_macro_resolutions: - Vec<(Ident, MacroKind, ParentScope<'ra>, Option<NameBinding<'ra>>)>, + Vec<(Ident, MacroKind, ParentScope<'ra>, Option<NameBinding<'ra>>, Option<Span>)>, multi_segment_macro_resolutions: Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'ra>, Option<Res>, Namespace)>, builtin_attrs: Vec<(Ident, ParentScope<'ra>)>, @@ -1208,7 +1211,7 @@ pub struct Resolver<'ra, 'tcx> { effective_visibilities: EffectiveVisibilities, doc_link_resolutions: FxIndexMap<LocalDefId, DocLinkResMap>, doc_link_traits_in_scope: FxIndexMap<LocalDefId, Vec<DefId>>, - all_macro_rules: FxHashSet<Symbol>, + all_macro_rules: UnordSet<Symbol>, /// Invocation ids of all glob delegations. glob_delegation_invoc_ids: FxHashSet<LocalExpnId>, @@ -1224,6 +1227,11 @@ pub struct Resolver<'ra, 'tcx> { current_crate_outer_attr_insert_span: Span, mods_with_parse_errors: FxHashSet<DefId>, + + // Stores pre-expansion and pre-placeholder-fragment-insertion names for `impl Trait` types + // that were encountered during resolution. These names are used to generate item names + // for APITs, so we don't want to leak details of resolution into these names. + impl_trait_names: FxHashMap<NodeId, Symbol>, } /// This provides memory for the rest of the crate. The `'ra` lifetime that is @@ -1235,6 +1243,7 @@ pub struct ResolverArenas<'ra> { imports: TypedArena<ImportData<'ra>>, name_resolutions: TypedArena<RefCell<NameResolution<'ra>>>, ast_paths: TypedArena<ast::Path>, + macros: TypedArena<MacroData>, dropless: DroplessArena, } @@ -1281,7 +1290,7 @@ impl<'ra> ResolverArenas<'ra> { self.name_resolutions.alloc(Default::default()) } fn alloc_macro_rules_scope(&'ra self, scope: MacroRulesScope<'ra>) -> MacroRulesScopeRef<'ra> { - Interned::new_unchecked(self.dropless.alloc(Cell::new(scope))) + self.dropless.alloc(Cell::new(scope)) } fn alloc_macro_rules_binding( &'ra self, @@ -1292,6 +1301,9 @@ impl<'ra> ResolverArenas<'ra> { fn alloc_ast_paths(&'ra self, paths: &[ast::Path]) -> &'ra [ast::Path] { self.ast_paths.alloc_from_iter(paths.iter().cloned()) } + fn alloc_macro(&'ra self, macro_data: MacroData) -> &'ra MacroData { + self.macros.alloc(macro_data) + } fn alloc_pattern_spans(&'ra self, spans: impl Iterator<Item = Span>) -> &'ra [Span] { self.dropless.alloc_from_iter(spans) } @@ -1534,10 +1546,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { builtin_macros: Default::default(), registered_tools, macro_use_prelude: Default::default(), - macro_map: FxHashMap::default(), + local_macro_map: Default::default(), + extern_macro_map: Default::default(), dummy_ext_bang: Arc::new(SyntaxExtension::dummy_bang(edition)), dummy_ext_derive: Arc::new(SyntaxExtension::dummy_derive(edition)), - non_macro_attr: MacroData::new(Arc::new(SyntaxExtension::non_macro_attr(edition))), + non_macro_attr: arenas + .alloc_macro(MacroData::new(Arc::new(SyntaxExtension::non_macro_attr(edition)))), invocation_parent_scopes: Default::default(), output_macro_rules_scopes: Default::default(), macro_rules_scopes: Default::default(), @@ -1579,6 +1593,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { impl_binding_keys: Default::default(), current_crate_outer_attr_insert_span, mods_with_parse_errors: Default::default(), + impl_trait_names: Default::default(), }; let root_parent_scope = ParentScope::module(graph_root, &resolver); @@ -1609,6 +1624,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) } + fn new_local_macro(&mut self, def_id: LocalDefId, macro_data: MacroData) -> &'ra MacroData { + let mac = self.arenas.alloc_macro(macro_data); + self.local_macro_map.insert(def_id, mac); + mac + } + fn next_node_id(&mut self) -> NodeId { let start = self.next_node_id; let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds"); @@ -1647,16 +1668,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let confused_type_with_std_module = self.confused_type_with_std_module; let effective_visibilities = self.effective_visibilities; - let stripped_cfg_items = Steal::new( - self.stripped_cfg_items - .into_iter() - .filter_map(|item| { - let parent_module = - self.node_id_to_def_id.get(&item.parent_module)?.key().to_def_id(); - Some(StrippedCfgItem { parent_module, ident: item.ident, cfg: item.cfg }) - }) - .collect(), - ); + let stripped_cfg_items = self + .stripped_cfg_items + .into_iter() + .filter_map(|item| { + let parent_module = + self.node_id_to_def_id.get(&item.parent_module)?.key().to_def_id(); + Some(StrippedCfgItem { parent_module, ident: item.ident, cfg: item.cfg }) + }) + .collect(); let global_ctxt = ResolverGlobalCtxt { expn_that_defined, @@ -1728,7 +1748,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { f(self, MacroNS); } - fn is_builtin_macro(&mut self, res: Res) -> bool { + fn is_builtin_macro(&self, res: Res) -> bool { self.get_macro(res).is_some_and(|macro_data| macro_data.ext.builtin_name.is_some()) } @@ -1934,12 +1954,26 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } if let NameBindingKind::Import { import, binding } = used_binding.kind { if let ImportKind::MacroUse { warn_private: true } = import.kind { - self.lint_buffer().buffer_lint( - PRIVATE_MACRO_USE, - import.root_id, - ident.span, - BuiltinLintDiag::MacroIsPrivate(ident), - ); + // Do not report the lint if the macro name resolves in stdlib prelude + // even without the problematic `macro_use` import. + let found_in_stdlib_prelude = self.prelude.is_some_and(|prelude| { + self.maybe_resolve_ident_in_module( + ModuleOrUniformRoot::Module(prelude), + ident, + MacroNS, + &ParentScope::module(self.empty_module, self), + None, + ) + .is_ok() + }); + if !found_in_stdlib_prelude { + self.lint_buffer().buffer_lint( + PRIVATE_MACRO_USE, + import.root_id, + ident.span, + BuiltinLintDiag::MacroIsPrivate(ident), + ); + } } // Avoid marking `extern crate` items that refer to a name from extern prelude, // but not introduce it, as used if they are accessed from lexical scope. diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index ee905065b96..89bbe8dad98 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -9,10 +9,10 @@ use rustc_ast::expand::StrippedCfgItem; use rustc_ast::{self as ast, Crate, NodeId, attr}; use rustc_ast_pretty::pprust; use rustc_attr_data_structures::StabilityLevel; -use rustc_data_structures::intern::Interned; use rustc_errors::{Applicability, DiagCtxtHandle, StashKey}; use rustc_expand::base::{ - DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, SyntaxExtensionKind, + Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, + SyntaxExtensionKind, }; use rustc_expand::compile_declarative_macro; use rustc_expand::expand::{ @@ -79,7 +79,7 @@ pub(crate) enum MacroRulesScope<'ra> { /// This helps to avoid uncontrollable growth of `macro_rules!` scope chains, /// which usually grow linearly with the number of macro invocations /// in a module (including derives) and hurt performance. -pub(crate) type MacroRulesScopeRef<'ra> = Interned<'ra, Cell<MacroRulesScope<'ra>>>; +pub(crate) type MacroRulesScopeRef<'ra> = &'ra Cell<MacroRulesScope<'ra>>; /// Macro namespace is separated into two sub-namespaces, one for bang macros and /// one for attribute-like macros (attributes, derives). @@ -294,6 +294,14 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { && self.tcx.def_kind(mod_def_id) == DefKind::Mod }) .map(|&InvocationParent { parent_def: mod_def_id, .. }| mod_def_id); + let sugg_span = match &invoc.kind { + InvocationKind::Attr { item: Annotatable::Item(item), .. } + if !item.span.from_expansion() => + { + Some(item.span.shrink_to_lo()) + } + _ => None, + }; let (ext, res) = self.smart_resolve_macro_path( path, kind, @@ -304,6 +312,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { force, deleg_impl, looks_like_invoc_in_mod_inert_attr, + sugg_span, )?; let span = invoc.span(); @@ -324,7 +333,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { fn record_macro_rule_usage(&mut self, id: NodeId, rule_i: usize) { if let Some(rules) = self.unused_macro_rules.get_mut(&id) { - rules.remove(&rule_i); + rules.remove(rule_i); } } @@ -341,13 +350,23 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { } for (&node_id, unused_arms) in self.unused_macro_rules.iter() { - for (&arm_i, &(ident, rule_span)) in unused_arms.to_sorted_stable_ord() { - self.lint_buffer.buffer_lint( - UNUSED_MACRO_RULES, - node_id, - rule_span, - BuiltinLintDiag::MacroRuleNeverUsed(arm_i, ident.name), - ); + if unused_arms.is_empty() { + continue; + } + let def_id = self.local_def_id(node_id); + let m = &self.local_macro_map[&def_id]; + let SyntaxExtensionKind::LegacyBang(ref ext) = m.ext.kind else { + continue; + }; + for arm_i in unused_arms.iter() { + if let Some((ident, rule_span)) = ext.get_unused_rule(arm_i) { + self.lint_buffer.buffer_lint( + UNUSED_MACRO_RULES, + node_id, + rule_span, + BuiltinLintDiag::MacroRuleNeverUsed(arm_i, ident.name), + ); + } } } } @@ -386,6 +405,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { true, force, None, + None, ) { Ok((Some(ext), _)) => { if !ext.helper_attrs.is_empty() { @@ -511,6 +531,10 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { }); Ok(idents) } + + fn insert_impl_trait_name(&mut self, id: NodeId, name: Symbol) { + self.impl_trait_names.insert(id, name); + } } impl<'ra, 'tcx> Resolver<'ra, 'tcx> { @@ -528,6 +552,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { force: bool, deleg_impl: Option<LocalDefId>, invoc_in_mod_inert_attr: Option<LocalDefId>, + suggestion_span: Option<Span>, ) -> Result<(Arc<SyntaxExtension>, Res), Indeterminate> { let (ext, res) = match self.resolve_macro_or_delegation_path( path, @@ -538,6 +563,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { deleg_impl, invoc_in_mod_inert_attr.map(|def_id| (def_id, node_id)), None, + suggestion_span, ) { Ok((Some(ext), res)) => (ext, res), Ok((None, res)) => (self.dummy_ext(kind), res), @@ -681,6 +707,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { trace: bool, force: bool, ignore_import: Option<Import<'ra>>, + suggestion_span: Option<Span>, ) -> Result<(Option<Arc<SyntaxExtension>>, Res), Determinacy> { self.resolve_macro_or_delegation_path( path, @@ -691,6 +718,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None, None, ignore_import, + suggestion_span, ) } @@ -704,6 +732,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { deleg_impl: Option<LocalDefId>, invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>, ignore_import: Option<Import<'ra>>, + suggestion_span: Option<Span>, ) -> Result<(Option<Arc<SyntaxExtension>>, Res), Determinacy> { let path_span = ast_path.span; let mut path = Segment::from_path(ast_path); @@ -768,6 +797,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { kind, *parent_scope, binding.ok(), + suggestion_span, )); } @@ -905,7 +935,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let macro_resolutions = mem::take(&mut self.single_segment_macro_resolutions); - for (ident, kind, parent_scope, initial_binding) in macro_resolutions { + for (ident, kind, parent_scope, initial_binding, sugg_span) in macro_resolutions { match self.early_resolve_ident_in_lexical_scope( ident, ScopeSet::Macro(kind), @@ -946,7 +976,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { expected, ident, }); - self.unresolved_macro_suggestions(&mut err, kind, &parent_scope, ident, krate); + self.unresolved_macro_suggestions( + &mut err, + kind, + &parent_scope, + ident, + krate, + sugg_span, + ); err.emit(); } } @@ -974,7 +1011,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { let span = path.span; if let Some(stability) = &ext.stability { - if let StabilityLevel::Unstable { reason, issue, is_soft, implied_by } = stability.level + if let StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. } = + stability.level { let feature = stability.feature; @@ -1093,7 +1131,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - pub(crate) fn check_reserved_macro_name(&mut self, ident: Ident, res: Res) { + pub(crate) fn check_reserved_macro_name(&self, ident: Ident, res: Res) { // Reserve some names that are not quite covered by the general check // performed on `Resolver::builtin_attrs`. if ident.name == sym::cfg || ident.name == sym::cfg_attr { @@ -1109,7 +1147,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// /// Possibly replace its expander to a pre-defined one for built-in macros. pub(crate) fn compile_macro( - &mut self, + &self, macro_def: &ast::MacroDef, ident: Ident, attrs: &[rustc_hir::Attribute], @@ -1117,7 +1155,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { node_id: NodeId, edition: Edition, ) -> MacroData { - let (mut ext, mut rule_spans) = compile_declarative_macro( + let (mut ext, mut nrules) = compile_declarative_macro( self.tcx.sess, self.tcx.features(), macro_def, @@ -1134,13 +1172,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // The macro is a built-in, replace its expander function // while still taking everything else from the source code. ext.kind = builtin_ext_kind.clone(); - rule_spans = Vec::new(); + nrules = 0; } else { self.dcx().emit_err(errors::CannotFindBuiltinMacroWithName { span, ident }); } } - MacroData { ext: Arc::new(ext), rule_spans, macro_rules: macro_def.macro_rules } + MacroData { ext: Arc::new(ext), nrules, macro_rules: macro_def.macro_rules } } fn path_accessible( diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index fa839d2748d..f61cd1f0adf 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -49,6 +49,9 @@ pub struct DocFragment { pub doc: Symbol, pub kind: DocFragmentKind, pub indent: usize, + /// Because we tamper with the spans context, this information cannot be correctly retrieved + /// later on. So instead, we compute it and store it here. + pub from_expansion: bool, } #[derive(Clone, Copy, Debug)] @@ -208,17 +211,18 @@ pub fn attrs_to_doc_fragments<'a, A: AttributeExt + Clone + 'a>( for (attr, item_id) in attrs { if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() { let doc = beautify_doc_string(doc_str, comment_kind); - let (span, kind) = if attr.is_doc_comment() { - (attr.span(), DocFragmentKind::SugaredDoc) + let (span, kind, from_expansion) = if attr.is_doc_comment() { + let span = attr.span(); + (span, DocFragmentKind::SugaredDoc, span.from_expansion()) } else { - ( - attr.value_span() - .map(|i| i.with_ctxt(attr.span().ctxt())) - .unwrap_or(attr.span()), - DocFragmentKind::RawDoc, - ) + let attr_span = attr.span(); + let (span, from_expansion) = match attr.value_span() { + Some(sp) => (sp.with_ctxt(attr_span.ctxt()), sp.from_expansion()), + None => (attr_span, attr_span.from_expansion()), + }; + (span, DocFragmentKind::RawDoc, from_expansion) }; - let fragment = DocFragment { span, doc, kind, item_id, indent: 0 }; + let fragment = DocFragment { span, doc, kind, item_id, indent: 0, from_expansion }; doc_fragments.push(fragment); } else if !doc_only { other_attrs.push(attr.clone()); @@ -356,7 +360,12 @@ pub fn strip_generics_from_path(path_str: &str) -> Result<Box<str>, MalformedGen /// If there are no doc-comments, return true. /// FIXME(#78591): Support both inner and outer attributes on the same item. pub fn inner_docs(attrs: &[impl AttributeExt]) -> bool { - attrs.iter().find(|a| a.doc_str().is_some()).is_none_or(|a| a.style() == ast::AttrStyle::Inner) + for attr in attrs { + if let Some(attr_style) = attr.doc_resolution_scope() { + return attr_style == ast::AttrStyle::Inner; + } + } + true } /// Has `#[rustc_doc_primitive]` or `#[doc(keyword)]`. @@ -500,17 +509,26 @@ fn collect_link_data<'input, F: BrokenLinkCallback<'input>>( display_text.map(String::into_boxed_str) } -/// Returns a span encompassing all the document fragments. -pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> { - if fragments.is_empty() { - return None; - } - let start = fragments[0].span; - if start == DUMMY_SP { +/// Returns a tuple containing a span encompassing all the document fragments and a boolean that is +/// `true` if any of the fragments are from a macro expansion. +pub fn span_of_fragments_with_expansion(fragments: &[DocFragment]) -> Option<(Span, bool)> { + let (first_fragment, last_fragment) = match fragments { + [] => return None, + [first, .., last] => (first, last), + [first] => (first, first), + }; + if first_fragment.span == DUMMY_SP { return None; } - let end = fragments.last().expect("no doc strings provided").span; - Some(start.to(end)) + Some(( + first_fragment.span.to(last_fragment.span), + fragments.iter().any(|frag| frag.from_expansion), + )) +} + +/// Returns a span encompassing all the document fragments. +pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> { + span_of_fragments_with_expansion(fragments).map(|(sp, _)| sp) } /// Attempts to match a range of bytes from parsed markdown to a `Span` in the source code. @@ -524,18 +542,22 @@ pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> { /// This method will return `Some` only if one of the following is true: /// /// - The doc is made entirely from sugared doc comments, which cannot contain escapes -/// - The doc is entirely from a single doc fragment with a string literal exactly equal to `markdown`. +/// - The doc is entirely from a single doc fragment with a string literal exactly equal to +/// `markdown`. /// - The doc comes from `include_str!` -/// - The doc includes exactly one substring matching `markdown[md_range]` which is contained in a single doc fragment. +/// - The doc includes exactly one substring matching `markdown[md_range]` which is contained in a +/// single doc fragment. +/// +/// This function is defined in the compiler so it can be used by both `rustdoc` and `clippy`. /// -/// This function is defined in the compiler so it can be used by -/// both `rustdoc` and `clippy`. +/// It returns a tuple containing a span encompassing all the document fragments and a boolean that +/// is `true` if any of the *matched* fragments are from a macro expansion. pub fn source_span_for_markdown_range( tcx: TyCtxt<'_>, markdown: &str, md_range: &Range<usize>, fragments: &[DocFragment], -) -> Option<Span> { +) -> Option<(Span, bool)> { let map = tcx.sess.source_map(); source_span_for_markdown_range_inner(map, markdown, md_range, fragments) } @@ -546,7 +568,7 @@ pub fn source_span_for_markdown_range_inner( markdown: &str, md_range: &Range<usize>, fragments: &[DocFragment], -) -> Option<Span> { +) -> Option<(Span, bool)> { use rustc_span::BytePos; if let &[fragment] = &fragments @@ -557,11 +579,14 @@ pub fn source_span_for_markdown_range_inner( && let Ok(md_range_hi) = u32::try_from(md_range.end) { // Single fragment with string that contains same bytes as doc. - return Some(Span::new( - fragment.span.lo() + rustc_span::BytePos(md_range_lo), - fragment.span.lo() + rustc_span::BytePos(md_range_hi), - fragment.span.ctxt(), - fragment.span.parent(), + return Some(( + Span::new( + fragment.span.lo() + rustc_span::BytePos(md_range_lo), + fragment.span.lo() + rustc_span::BytePos(md_range_hi), + fragment.span.ctxt(), + fragment.span.parent(), + ), + fragment.from_expansion, )); } @@ -593,19 +618,21 @@ pub fn source_span_for_markdown_range_inner( { match_data = Some((i, match_start)); } else { - // Heirustic produced ambiguity, return nothing. + // Heuristic produced ambiguity, return nothing. return None; } } } if let Some((i, match_start)) = match_data { - let sp = fragments[i].span; + let fragment = &fragments[i]; + let sp = fragment.span; // we need to calculate the span start, - // then use that in our calulations for the span end + // then use that in our calculations for the span end let lo = sp.lo() + BytePos(match_start as u32); - return Some( + return Some(( sp.with_lo(lo).with_hi(lo + BytePos((md_range.end - md_range.start) as u32)), - ); + fragment.from_expansion, + )); } return None; } @@ -659,8 +686,13 @@ pub fn source_span_for_markdown_range_inner( } } - Some(span_of_fragments(fragments)?.from_inner(InnerSpan::new( + let (span, _) = span_of_fragments_with_expansion(fragments)?; + let src_span = span.from_inner(InnerSpan::new( md_range.start + start_bytes, md_range.end + start_bytes + end_bytes, - ))) + )); + Some(( + src_span, + fragments.iter().any(|frag| frag.span.overlaps(src_span) && frag.from_expansion), + )) } diff --git a/compiler/rustc_resolve/src/rustdoc/tests.rs b/compiler/rustc_resolve/src/rustdoc/tests.rs index 221ac907e7c..6a98ae06630 100644 --- a/compiler/rustc_resolve/src/rustdoc/tests.rs +++ b/compiler/rustc_resolve/src/rustdoc/tests.rs @@ -10,7 +10,7 @@ use super::{DocFragment, DocFragmentKind, source_span_for_markdown_range_inner}; fn single_backtick() { let sm = SourceMap::new(FilePathMapping::empty()); sm.new_source_file(PathBuf::from("foo.rs").into(), r#"#[doc = "`"] fn foo() {}"#.to_string()); - let span = source_span_for_markdown_range_inner( + let (span, _) = source_span_for_markdown_range_inner( &sm, "`", &(0..1), @@ -20,6 +20,7 @@ fn single_backtick() { kind: DocFragmentKind::RawDoc, doc: sym::empty, // unused placeholder indent: 0, + from_expansion: false, }], ) .unwrap(); @@ -32,7 +33,7 @@ fn utf8() { // regression test for https://github.com/rust-lang/rust/issues/141665 let sm = SourceMap::new(FilePathMapping::empty()); sm.new_source_file(PathBuf::from("foo.rs").into(), r#"#[doc = "⚠"] fn foo() {}"#.to_string()); - let span = source_span_for_markdown_range_inner( + let (span, _) = source_span_for_markdown_range_inner( &sm, "⚠", &(0..3), @@ -42,6 +43,7 @@ fn utf8() { kind: DocFragmentKind::RawDoc, doc: sym::empty, // unused placeholder indent: 0, + from_expansion: false, }], ) .unwrap(); |
