about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs2
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs32
-rw-r--r--compiler/rustc_resolve/src/ident.rs139
-rw-r--r--compiler/rustc_resolve/src/imports.rs24
-rw-r--r--compiler/rustc_resolve/src/late.rs59
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs8
-rw-r--r--compiler/rustc_resolve/src/lib.rs47
-rw-r--r--compiler/rustc_resolve/src/macros.rs9
8 files changed, 122 insertions, 198 deletions
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 650a0dc82ce..7485dd51863 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -298,7 +298,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                     &segments,
                     Some(TypeNS),
                     parent_scope,
-                    if finalize { Finalize::SimplePath(id, path.span) } else { Finalize::No },
+                    finalize.then(|| Finalize::new(id, path.span)),
                     None,
                 ) {
                     PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index e0a83ba8c0d..7d40ecb18b7 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -417,15 +417,12 @@ impl<'a> Resolver<'a> {
 
     crate fn lint_if_path_starts_with_module(
         &mut self,
-        finalize: Finalize,
+        finalize: Option<Finalize>,
         path: &[Segment],
         second_binding: Option<&NameBinding<'_>>,
     ) {
-        let (diag_id, diag_span) = match finalize {
-            Finalize::No => return,
-            Finalize::SimplePath(id, path_span) => (id, path_span),
-            Finalize::UsePath { root_id, root_span, .. } => (root_id, root_span),
-            Finalize::QPathTrait { qpath_id, qpath_span, .. } => (qpath_id, qpath_span),
+        let Some(Finalize { node_id, root_span, .. }) = finalize else {
+            return;
         };
 
         let first_name = match path.get(0) {
@@ -463,11 +460,11 @@ impl<'a> Resolver<'a> {
             }
         }
 
-        let diag = BuiltinLintDiagnostics::AbsPathWithModule(diag_span);
+        let diag = BuiltinLintDiagnostics::AbsPathWithModule(root_span);
         self.lint_buffer.buffer_lint_with_diagnostic(
             ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
-            diag_id,
-            diag_span,
+            node_id,
+            root_span,
             "absolute paths must start with `self`, `super`, \
              `crate`, or an external crate name in the 2018 edition",
             diag,
@@ -1503,7 +1500,6 @@ impl<'a> Resolver<'a> {
                 &parent_scope,
                 None,
                 false,
-                false,
                 None,
             ) {
                 let desc = match binding.res() {
@@ -1811,7 +1807,7 @@ impl<'a> Resolver<'a> {
         opt_ns: Option<Namespace>, // `None` indicates a module path in import
         parent_scope: &ParentScope<'a>,
         ribs: Option<&PerNS<Vec<Rib<'a>>>>,
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
         module: Option<ModuleOrUniformRoot<'a>>,
         i: usize,
         ident: Ident,
@@ -1863,8 +1859,7 @@ impl<'a> Resolver<'a> {
                         ns_to_try,
                         parent_scope,
                         None,
-                        false,
-                        unusable_binding,
+                        ignore_binding,
                     ).ok()
                 } else if let Some(ribs) = ribs
                     && let Some(TypeNS | ValueNS) = opt_ns
@@ -1873,9 +1868,9 @@ impl<'a> Resolver<'a> {
                         ident,
                         ns_to_try,
                         parent_scope,
-                        Finalize::No,
+                        None,
                         &ribs[ns_to_try],
-                        unusable_binding,
+                        ignore_binding,
                     ) {
                         // we found a locally-imported or available item/module
                         Some(LexicalScopeBinding::Item(binding)) => Some(binding),
@@ -1889,8 +1884,7 @@ impl<'a> Resolver<'a> {
                         parent_scope,
                         None,
                         false,
-                        false,
-                        unusable_binding,
+                        ignore_binding,
                     ).ok()
                 };
                 if let Some(binding) = binding {
@@ -1921,9 +1915,9 @@ impl<'a> Resolver<'a> {
                     ident,
                     ValueNS,
                     parent_scope,
-                    Finalize::No,
+                    None,
                     &ribs[ValueNS],
-                    unusable_binding,
+                    ignore_binding,
                 )
             } else {
                 None
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 84fe0ec83d2..18ce359524d 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -279,9 +279,9 @@ impl<'a> Resolver<'a> {
         mut ident: Ident,
         ns: Namespace,
         parent_scope: &ParentScope<'a>,
-        finalize_full: Finalize,
+        finalize: Option<Finalize>,
         ribs: &[Rib<'a>],
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> Option<LexicalScopeBinding<'a>> {
         assert!(ns == TypeNS || ns == ValueNS);
         let orig_ident = ident;
@@ -302,7 +302,6 @@ impl<'a> Resolver<'a> {
         let normalized_ident = Ident { span: normalized_span, ..ident };
 
         // Walk backwards up the ribs in scope.
-        let finalize = finalize_full.path_span();
         let mut module = self.graph_root;
         for i in (0..ribs.len()).rev() {
             debug!("walk rib\n{:?}", ribs[i].bindings);
@@ -316,7 +315,7 @@ impl<'a> Resolver<'a> {
                     i,
                     rib_ident,
                     *res,
-                    finalize,
+                    finalize.map(|finalize| finalize.path_span),
                     *original_rib_ident_def,
                     ribs,
                 )));
@@ -344,8 +343,7 @@ impl<'a> Resolver<'a> {
                 ns,
                 parent_scope,
                 finalize,
-                false,
-                unusable_binding,
+                ignore_binding,
             );
             if let Ok(binding) = item {
                 // The ident resolves to an item.
@@ -354,12 +352,11 @@ impl<'a> Resolver<'a> {
         }
         self.early_resolve_ident_in_lexical_scope(
             orig_ident,
-            ScopeSet::Late(ns, module, finalize_full.node_id()),
+            ScopeSet::Late(ns, module, finalize.map(|finalize| finalize.node_id)),
             parent_scope,
             finalize,
             finalize.is_some(),
-            false,
-            unusable_binding,
+            ignore_binding,
         )
         .ok()
         .map(LexicalScopeBinding::Item)
@@ -376,10 +373,9 @@ impl<'a> Resolver<'a> {
         orig_ident: Ident,
         scope_set: ScopeSet<'a>,
         parent_scope: &ParentScope<'a>,
-        finalize: Option<Span>,
+        finalize: Option<Finalize>,
         force: bool,
-        last_import_segment: bool,
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> Result<&'a NameBinding<'a>, Determinacy> {
         bitflags::bitflags! {
             struct Flags: u8 {
@@ -499,8 +495,7 @@ impl<'a> Resolver<'a> {
                             ns,
                             parent_scope,
                             finalize,
-                            last_import_segment,
-                            unusable_binding,
+                            ignore_binding,
                         );
                         match binding {
                             Ok(binding) => Ok((binding, Flags::MODULE | Flags::MISC_SUGGEST_CRATE)),
@@ -522,8 +517,7 @@ impl<'a> Resolver<'a> {
                             adjusted_parent_scope,
                             !matches!(scope_set, ScopeSet::Late(..)),
                             finalize,
-                            last_import_segment,
-                            unusable_binding,
+                            ignore_binding,
                         );
                         match binding {
                             Ok(binding) => {
@@ -608,8 +602,7 @@ impl<'a> Resolver<'a> {
                                 ns,
                                 parent_scope,
                                 None,
-                                last_import_segment,
-                                unusable_binding,
+                                ignore_binding,
                             ) {
                                 if use_prelude || this.is_builtin_macro(binding.res()) {
                                     result = Ok((binding, Flags::MISC_FROM_PRELUDE));
@@ -731,7 +724,7 @@ impl<'a> Resolver<'a> {
         ns: Namespace,
         parent_scope: &ParentScope<'a>,
     ) -> Result<&'a NameBinding<'a>, Determinacy> {
-        self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, None, false, None)
+        self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, None, None)
             .map_err(|(determinacy, _)| determinacy)
     }
 
@@ -742,23 +735,11 @@ impl<'a> Resolver<'a> {
         ident: Ident,
         ns: Namespace,
         parent_scope: &ParentScope<'a>,
-        finalize: Option<Span>,
-        // We are resolving a last import segment during import validation.
-        last_import_segment: bool,
-        // This binding should be ignored during in-module resolution, so that we don't get
-        // "self-confirming" import resolutions during import validation.
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        finalize: Option<Finalize>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> Result<&'a NameBinding<'a>, Determinacy> {
-        self.resolve_ident_in_module_ext(
-            module,
-            ident,
-            ns,
-            parent_scope,
-            finalize,
-            last_import_segment,
-            unusable_binding,
-        )
-        .map_err(|(determinacy, _)| determinacy)
+        self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, finalize, ignore_binding)
+            .map_err(|(determinacy, _)| determinacy)
     }
 
     #[tracing::instrument(level = "debug", skip(self))]
@@ -768,9 +749,8 @@ impl<'a> Resolver<'a> {
         mut ident: Ident,
         ns: Namespace,
         parent_scope: &ParentScope<'a>,
-        finalize: Option<Span>,
-        last_import_segment: bool,
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        finalize: Option<Finalize>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> Result<&'a NameBinding<'a>, (Determinacy, Weak)> {
         let tmp_parent_scope;
         let mut adjusted_parent_scope = parent_scope;
@@ -796,8 +776,7 @@ impl<'a> Resolver<'a> {
             adjusted_parent_scope,
             false,
             finalize,
-            last_import_segment,
-            unusable_binding,
+            ignore_binding,
         )
     }
 
@@ -808,9 +787,8 @@ impl<'a> Resolver<'a> {
         ident: Ident,
         ns: Namespace,
         parent_scope: &ParentScope<'a>,
-        finalize: Option<Span>,
-        last_import_segment: bool,
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        finalize: Option<Finalize>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> Result<&'a NameBinding<'a>, Determinacy> {
         self.resolve_ident_in_module_unadjusted_ext(
             module,
@@ -819,8 +797,7 @@ impl<'a> Resolver<'a> {
             parent_scope,
             false,
             finalize,
-            last_import_segment,
-            unusable_binding,
+            ignore_binding,
         )
         .map_err(|(determinacy, _)| determinacy)
     }
@@ -835,9 +812,10 @@ impl<'a> Resolver<'a> {
         ns: Namespace,
         parent_scope: &ParentScope<'a>,
         restricted_shadowing: bool,
-        finalize: Option<Span>,
-        last_import_segment: bool,
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        finalize: Option<Finalize>,
+        // This binding should be ignored during in-module resolution, so that we don't get
+        // "self-confirming" import resolutions during import validation and checking.
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> Result<&'a NameBinding<'a>, (Determinacy, Weak)> {
         let module = match module {
             ModuleOrUniformRoot::Module(module) => module,
@@ -849,8 +827,7 @@ impl<'a> Resolver<'a> {
                     parent_scope,
                     finalize,
                     finalize.is_some(),
-                    last_import_segment,
-                    unusable_binding,
+                    ignore_binding,
                 );
                 return binding.map_err(|determinacy| (determinacy, Weak::No));
             }
@@ -890,8 +867,7 @@ impl<'a> Resolver<'a> {
                     parent_scope,
                     finalize,
                     finalize.is_some(),
-                    last_import_segment,
-                    unusable_binding,
+                    ignore_binding,
                 );
                 return binding.map_err(|determinacy| (determinacy, Weak::No));
             }
@@ -901,19 +877,15 @@ impl<'a> Resolver<'a> {
         let resolution =
             self.resolution(module, key).try_borrow_mut().map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports.
 
-        if let Some(path_span) = finalize {
+        if let Some(Finalize { path_span, report_private, .. }) = finalize {
             // If the primary binding is unusable, search further and return the shadowed glob
             // binding if it exists. What we really want here is having two separate scopes in
             // a module - one for non-globs and one for globs, but until that's done use this
             // hack to avoid inconsistent resolution ICEs during import validation.
             let binding = [resolution.binding, resolution.shadowed_glob]
                 .into_iter()
-                .filter_map(|binding| match (binding, unusable_binding) {
-                    (Some(binding), Some(unusable_binding))
-                        if ptr::eq(binding, unusable_binding) =>
-                    {
-                        None
-                    }
+                .filter_map(|binding| match (binding, ignore_binding) {
+                    (Some(binding), Some(ignored)) if ptr::eq(binding, ignored) => None,
                     _ => binding,
                 })
                 .next();
@@ -922,14 +894,14 @@ impl<'a> Resolver<'a> {
             };
 
             if !self.is_accessible_from(binding.vis, parent_scope.module) {
-                if last_import_segment {
-                    return Err((Determined, Weak::No));
-                } else {
+                if report_private {
                     self.privacy_errors.push(PrivacyError {
                         ident,
                         binding,
                         dedup_span: path_span,
                     });
+                } else {
+                    return Err((Determined, Weak::No));
                 }
             }
 
@@ -960,10 +932,8 @@ impl<'a> Resolver<'a> {
         }
 
         let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| {
-            if let Some(unusable_binding) = unusable_binding {
-                if ptr::eq(binding, unusable_binding) {
-                    return Err((Determined, Weak::No));
-                }
+            if let Some(ignored) = ignore_binding && ptr::eq(binding, ignored) {
+                return Err((Determined, Weak::No));
             }
             let usable = this.is_accessible_from(binding.vis, parent_scope.module);
             if usable { Ok(binding) } else { Err((Determined, Weak::No)) }
@@ -996,8 +966,7 @@ impl<'a> Resolver<'a> {
                 ns,
                 &single_import.parent_scope,
                 None,
-                last_import_segment,
-                unusable_binding,
+                ignore_binding,
             ) {
                 Err(Determined) => continue,
                 Ok(binding)
@@ -1073,8 +1042,7 @@ impl<'a> Resolver<'a> {
                 ns,
                 adjusted_parent_scope,
                 None,
-                last_import_segment,
-                unusable_binding,
+                ignore_binding,
             );
 
             match result {
@@ -1371,7 +1339,7 @@ impl<'a> Resolver<'a> {
         opt_ns: Option<Namespace>, // `None` indicates a module path in import
         parent_scope: &ParentScope<'a>,
     ) -> PathResult<'a> {
-        self.resolve_path_with_ribs(path, opt_ns, parent_scope, Finalize::No, None, None)
+        self.resolve_path_with_ribs(path, opt_ns, parent_scope, None, None, None)
     }
 
     #[tracing::instrument(level = "debug", skip(self))]
@@ -1380,10 +1348,10 @@ impl<'a> Resolver<'a> {
         path: &[Segment],
         opt_ns: Option<Namespace>, // `None` indicates a module path in import
         parent_scope: &ParentScope<'a>,
-        finalize: Finalize,
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        finalize: Option<Finalize>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> PathResult<'a> {
-        self.resolve_path_with_ribs(path, opt_ns, parent_scope, finalize, None, unusable_binding)
+        self.resolve_path_with_ribs(path, opt_ns, parent_scope, finalize, None, ignore_binding)
     }
 
     crate fn resolve_path_with_ribs(
@@ -1391,13 +1359,12 @@ impl<'a> Resolver<'a> {
         path: &[Segment],
         opt_ns: Option<Namespace>, // `None` indicates a module path in import
         parent_scope: &ParentScope<'a>,
-        finalize_full: Finalize,
+        finalize: Option<Finalize>,
         ribs: Option<&PerNS<Vec<Rib<'a>>>>,
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> PathResult<'a> {
-        debug!("resolve_path(path={:?}, opt_ns={:?}, finalize={:?})", path, opt_ns, finalize_full);
+        debug!("resolve_path(path={:?}, opt_ns={:?}, finalize={:?})", path, opt_ns, finalize);
 
-        let finalize = finalize_full.path_span();
         let mut module = None;
         let mut allow_super = true;
         let mut second_binding = None;
@@ -1497,8 +1464,7 @@ impl<'a> Resolver<'a> {
                         ns,
                         parent_scope,
                         finalize,
-                        false,
-                        unusable_binding,
+                        ignore_binding,
                     )
                 } else if let Some(ribs) = ribs
                     && let Some(TypeNS | ValueNS) = opt_ns
@@ -1507,9 +1473,9 @@ impl<'a> Resolver<'a> {
                         ident,
                         ns,
                         parent_scope,
-                        finalize_full,
+                        finalize,
                         &ribs[ns],
-                        unusable_binding,
+                        ignore_binding,
                     ) {
                         // we found a locally-imported or available item/module
                         Some(LexicalScopeBinding::Item(binding)) => Ok(binding),
@@ -1525,8 +1491,7 @@ impl<'a> Resolver<'a> {
                         parent_scope,
                         finalize,
                         finalize.is_some(),
-                        false,
-                        unusable_binding,
+                        ignore_binding,
                     )
                 };
                 FindBindingResult::Binding(binding)
@@ -1566,7 +1531,7 @@ impl<'a> Resolver<'a> {
                     } else if res == Res::Err {
                         return PathResult::NonModule(PartialRes::new(Res::Err));
                     } else if opt_ns.is_some() && (is_last || maybe_assoc) {
-                        self.lint_if_path_starts_with_module(finalize_full, path, second_binding);
+                        self.lint_if_path_starts_with_module(finalize, path, second_binding);
                         return PathResult::NonModule(PartialRes::with_unresolved_segments(
                             res,
                             path.len() - i - 1,
@@ -1599,7 +1564,7 @@ impl<'a> Resolver<'a> {
                             opt_ns,
                             parent_scope,
                             ribs,
-                            unusable_binding,
+                            ignore_binding,
                             module,
                             i,
                             ident,
@@ -1609,7 +1574,7 @@ impl<'a> Resolver<'a> {
             }
         }
 
-        self.lint_if_path_starts_with_module(finalize_full, path, second_binding);
+        self.lint_if_path_starts_with_module(finalize, path, second_binding);
 
         PathResult::Module(match module {
             Some(module) => module,
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 01dc727737a..ef06ec356bd 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -545,7 +545,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                         ns,
                         &import.parent_scope,
                         None,
-                        false,
                         None,
                     );
                     import.vis.set(orig_vis);
@@ -589,22 +588,18 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
     /// consolidate multiple unresolved import errors into a single diagnostic.
     fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImportError> {
         let orig_vis = import.vis.replace(ty::Visibility::Invisible);
-        let unusable_binding = match &import.kind {
+        let ignore_binding = match &import.kind {
             ImportKind::Single { target_bindings, .. } => target_bindings[TypeNS].get(),
             _ => None,
         };
         let prev_ambiguity_errors_len = self.r.ambiguity_errors.len();
-        let finalize = Finalize::UsePath {
-            root_id: import.root_id,
-            root_span: import.root_span,
-            path_span: import.span,
-        };
+        let finalize = Finalize::with_root_span(import.root_id, import.span, import.root_span);
         let path_res = self.r.resolve_path(
             &import.module_path,
             None,
             &import.parent_scope,
-            finalize,
-            unusable_binding,
+            Some(finalize),
+            ignore_binding,
         );
         let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len;
         import.vis.set(orig_vis);
@@ -685,7 +680,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                     // 2 segments, so the `resolve_path` above won't trigger it.
                     let mut full_path = import.module_path.clone();
                     full_path.push(Segment::from_ident(Ident::empty()));
-                    self.r.lint_if_path_starts_with_module(finalize, &full_path, None);
+                    self.r.lint_if_path_starts_with_module(Some(finalize), &full_path, None);
                 }
 
                 if let ModuleOrUniformRoot::Module(module) = module {
@@ -720,8 +715,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                     ident,
                     ns,
                     &import.parent_scope,
-                    Some(import.span),
-                    true,
+                    Some(Finalize { report_private: false, ..finalize }),
                     target_bindings[ns].get(),
                 );
                 import.vis.set(orig_vis);
@@ -781,8 +775,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                         ident,
                         ns,
                         &import.parent_scope,
-                        Some(import.span),
-                        false,
+                        Some(finalize),
                         None,
                     );
                     if binding.is_ok() {
@@ -948,7 +941,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
             full_path.push(Segment::from_ident(ident));
             self.r.per_ns(|this, ns| {
                 if let Ok(binding) = source_bindings[ns].get() {
-                    this.lint_if_path_starts_with_module(finalize, &full_path, Some(binding));
+                    this.lint_if_path_starts_with_module(Some(finalize), &full_path, Some(binding));
                 }
             });
         }
@@ -1003,7 +996,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                     &import.parent_scope,
                     None,
                     false,
-                    false,
                     target_bindings[ns].get(),
                 ) {
                     Ok(other_binding) => {
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 53bd589fdcd..ca89f610322 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -578,7 +578,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                     .resolve_ident_in_lexical_scope(
                         self_ty,
                         TypeNS,
-                        Finalize::SimplePath(ty.id, ty.span),
+                        Some(Finalize::new(ty.id, ty.span)),
                         None,
                     )
                     .map_or(Res::Err, |d| d.res());
@@ -958,7 +958,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             ident,
             ns,
             &self.parent_scope,
-            Finalize::No,
+            None,
             &self.ribs[ns],
             None,
         )
@@ -968,8 +968,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         &mut self,
         ident: Ident,
         ns: Namespace,
-        finalize: Finalize,
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        finalize: Option<Finalize>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> Option<LexicalScopeBinding<'a>> {
         self.r.resolve_ident_in_lexical_scope(
             ident,
@@ -977,7 +977,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             &self.parent_scope,
             finalize,
             &self.ribs[ns],
-            unusable_binding,
+            ignore_binding,
         )
     }
 
@@ -985,7 +985,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         &mut self,
         path: &[Segment],
         opt_ns: Option<Namespace>, // `None` indicates a module path in import
-        finalize: Finalize,
+        finalize: Option<Finalize>,
     ) -> PathResult<'a> {
         self.r.resolve_path_with_ribs(
             path,
@@ -1299,11 +1299,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         partial_res: PartialRes,
         path: &[Segment],
         source: PathSource<'_>,
-        finalize: Finalize,
+        path_span: Span,
     ) {
-        let Some(path_span) = finalize.path_span() else {
-            return;
-        };
         let proj_start = path.len() - partial_res.unresolved_segments();
         for (i, segment) in path.iter().enumerate() {
             if segment.has_lifetime_args {
@@ -1576,8 +1573,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                         report_error(self, ns);
                     }
                     Some(LexicalScopeBinding::Item(binding)) => {
-                        if let Some(LexicalScopeBinding::Res(..)) = self
-                            .resolve_ident_in_lexical_scope(ident, ns, Finalize::No, Some(binding))
+                        if let Some(LexicalScopeBinding::Res(..)) =
+                            self.resolve_ident_in_lexical_scope(ident, ns, None, Some(binding))
                         {
                             report_error(self, ns);
                         }
@@ -1979,7 +1976,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 None,
                 &path,
                 PathSource::Trait(AliasPossibility::No),
-                Finalize::SimplePath(trait_ref.ref_id, trait_ref.path.span),
+                Finalize::new(trait_ref.ref_id, trait_ref.path.span),
             );
             if let Some(def_id) = res.base_res().opt_def_id() {
                 new_id = Some(def_id);
@@ -2653,7 +2650,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             qself,
             &Segment::from_path(path),
             source,
-            Finalize::SimplePath(id, path.span),
+            Finalize::new(id, path.span),
         );
     }
 
@@ -2672,8 +2669,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         );
         let ns = source.namespace();
 
-        let (id, path_span) =
-            finalize.node_id_and_path_span().expect("unexpected speculative resolution");
+        let Finalize { node_id, path_span, .. } = finalize;
         let report_errors = |this: &mut Self, res: Option<Res>| {
             if this.should_report_errs() {
                 let (err, candidates) =
@@ -2787,7 +2783,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 if ns == ValueNS {
                     let item_name = path.last().unwrap().ident;
                     let traits = self.traits_in_scope(item_name, ns);
-                    self.r.trait_map.insert(id, traits);
+                    self.r.trait_map.insert(node_id, traits);
                 }
 
                 if PrimTy::from_name(path[0].ident.name).is_some() {
@@ -2796,7 +2792,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                     std_path.push(Segment::from_ident(Ident::with_dummy_span(sym::std)));
                     std_path.extend(path);
                     if let PathResult::Module(_) | PathResult::NonModule(_) =
-                        self.resolve_path(&std_path, Some(ns), Finalize::No)
+                        self.resolve_path(&std_path, Some(ns), None)
                     {
                         // Check if we wrote `str::from_utf8` instead of `std::str::from_utf8`
                         let item_span =
@@ -2823,8 +2819,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
 
         if !matches!(source, PathSource::TraitItem(..)) {
             // Avoid recording definition of `A::B` in `<T as A>::B::C`.
-            self.r.record_partial_res(id, partial_res);
-            self.resolve_elided_lifetimes_in_path(id, partial_res, path, source, finalize);
+            self.r.record_partial_res(node_id, partial_res);
+            self.resolve_elided_lifetimes_in_path(node_id, partial_res, path, source, path_span);
         }
 
         partial_res
@@ -2932,21 +2928,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             // the trait (the slice upto and including
             // `qself.position`). And then we recursively resolve that,
             // but with `qself` set to `None`.
-            //
-            // However, setting `qself` to none (but not changing the
-            // span) loses the information about where this path
-            // *actually* appears, so for the purposes of the crate
-            // lint we pass along information that this is the trait
-            // name from a fully qualified path, and this also
-            // contains the full span (the `Finalize::QPathTrait`).
             let ns = if qself.position + 1 == path.len() { ns } else { TypeNS };
             let partial_res = self.smart_resolve_path_fragment(
                 None,
                 &path[..=qself.position],
                 PathSource::TraitItem(ns),
-                finalize.node_id_and_path_span().map_or(Finalize::No, |(qpath_id, path_span)| {
-                    Finalize::QPathTrait { qpath_id, qpath_span: qself.path_span, path_span }
-                }),
+                Finalize::with_root_span(finalize.node_id, finalize.path_span, qself.path_span),
             );
 
             // The remaining segments (the `C` in our example) will
@@ -2958,7 +2945,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             )));
         }
 
-        let result = match self.resolve_path(&path, Some(ns), finalize) {
+        let result = match self.resolve_path(&path, Some(ns), Some(finalize)) {
             PathResult::NonModule(path_res) => path_res,
             PathResult::Module(ModuleOrUniformRoot::Module(module)) if !module.is_normal() => {
                 PartialRes::new(module.res().unwrap())
@@ -2996,10 +2983,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             && result.base_res() != Res::Err
             && path[0].ident.name != kw::PathRoot
             && path[0].ident.name != kw::DollarCrate
-            && let Some((id, path_span)) = finalize.node_id_and_path_span()
         {
             let unqualified_result = {
-                match self.resolve_path(&[*path.last().unwrap()], Some(ns), Finalize::No) {
+                match self.resolve_path(&[*path.last().unwrap()], Some(ns), None) {
                     PathResult::NonModule(path_res) => path_res.base_res(),
                     PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
                         module.res().unwrap()
@@ -3009,7 +2995,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             };
             if result.base_res() == unqualified_result {
                 let lint = lint::builtin::UNUSED_QUALIFICATIONS;
-                self.r.lint_buffer.buffer_lint(lint, id, path_span, "unnecessary qualification")
+                self.r.lint_buffer.buffer_lint(
+                    lint,
+                    finalize.node_id,
+                    finalize.path_span,
+                    "unnecessary qualification",
+                )
             }
         }
 
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index a5243bf8ac3..3076cc11317 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -3,7 +3,7 @@ use crate::late::lifetimes::{ElisionFailureInfo, LifetimeContext};
 use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind};
 use crate::late::{LifetimeBinderKind, LifetimeRibKind};
 use crate::path_names_to_string;
-use crate::{Finalize, Module, ModuleKind, ModuleOrUniformRoot};
+use crate::{Module, ModuleKind, ModuleOrUniformRoot};
 use crate::{PathResult, PathSource, Segment};
 
 use rustc_ast::visit::FnKind;
@@ -189,7 +189,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                 (String::new(), "the crate root".to_string())
             } else {
                 let mod_path = &path[..path.len() - 1];
-                let mod_prefix = match self.resolve_path(mod_path, Some(TypeNS), Finalize::No) {
+                let mod_prefix = match self.resolve_path(mod_path, Some(TypeNS), None) {
                     PathResult::Module(ModuleOrUniformRoot::Module(module)) => module.res(),
                     _ => None,
                 }
@@ -648,7 +648,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         if let crate::PathSource::TraitItem(_) = source {
             let mod_path = &path[..path.len() - 1];
             if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
-                self.resolve_path(mod_path, None, Finalize::No)
+                self.resolve_path(mod_path, None, None)
             {
                 let resolutions = self.r.resolutions(module).borrow();
                 let targets: Vec<_> =
@@ -1362,7 +1362,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
             // Search in module.
             let mod_path = &path[..path.len() - 1];
             if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
-                self.resolve_path(mod_path, Some(TypeNS), Finalize::No)
+                self.resolve_path(mod_path, Some(TypeNS), None)
             {
                 self.r.add_module_candidates(module, &mut names, &filter_fn);
             }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index dbc4f337ad3..2e625fc1b4f 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -2044,42 +2044,27 @@ fn module_to_string(module: Module<'_>) -> Option<String> {
 }
 
 #[derive(Copy, Clone, Debug)]
-enum Finalize {
-    /// Do not issue the lint.
-    No,
-
-    /// This lint applies to some arbitrary path; e.g., `impl ::foo::Bar`.
-    /// In this case, we can take the span of that path.
-    SimplePath(NodeId, Span),
-
-    /// This lint comes from a `use` statement. In this case, what we
-    /// care about really is the *root* `use` statement; e.g., if we
-    /// have nested things like `use a::{b, c}`, we care about the
-    /// `use a` part.
-    UsePath { root_id: NodeId, root_span: Span, path_span: Span },
-
-    /// This is the "trait item" from a fully qualified path. For example,
-    /// we might be resolving  `X::Y::Z` from a path like `<T as X::Y>::Z`.
-    /// The `path_span` is the span of the to the trait itself (`X::Y`).
-    QPathTrait { qpath_id: NodeId, qpath_span: Span, path_span: Span },
+struct Finalize {
+    /// Node ID for linting.
+    node_id: NodeId,
+    /// Span of the whole path or some its characteristic fragment.
+    /// E.g. span of `b` in `foo::{a, b, c}`, or full span for regular paths.
+    path_span: Span,
+    /// Span of the path start, suitable for prepending something to to it.
+    /// E.g. span of `foo` in `foo::{a, b, c}`, or full span for regular paths.
+    root_span: Span,
+    /// Whether to report privacy errors or silently return "no resolution" for them,
+    /// similarly to speculative resolution.
+    report_private: bool,
 }
 
 impl Finalize {
-    fn node_id_and_path_span(&self) -> Option<(NodeId, Span)> {
-        match *self {
-            Finalize::No => None,
-            Finalize::SimplePath(id, path_span)
-            | Finalize::UsePath { root_id: id, path_span, .. }
-            | Finalize::QPathTrait { qpath_id: id, path_span, .. } => Some((id, path_span)),
-        }
-    }
-
-    fn node_id(&self) -> Option<NodeId> {
-        self.node_id_and_path_span().map(|(id, _)| id)
+    fn new(node_id: NodeId, path_span: Span) -> Finalize {
+        Finalize::with_root_span(node_id, path_span, path_span)
     }
 
-    fn path_span(&self) -> Option<Span> {
-        self.node_id_and_path_span().map(|(_, path_span)| path_span)
+    fn with_root_span(node_id: NodeId, path_span: Span, root_span: Span) -> Finalize {
+        Finalize { node_id, path_span, root_span, report_private: true }
     }
 }
 
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 01f0b11f1ac..19a9c1b99fc 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -604,7 +604,6 @@ impl<'a> Resolver<'a> {
                 parent_scope,
                 None,
                 force,
-                false,
                 None,
             );
             if let Err(Determinacy::Undetermined) = binding {
@@ -673,7 +672,7 @@ impl<'a> Resolver<'a> {
                 &path,
                 Some(MacroNS),
                 &parent_scope,
-                Finalize::SimplePath(ast::CRATE_NODE_ID, path_span),
+                Some(Finalize::new(ast::CRATE_NODE_ID, path_span)),
                 None,
             ) {
                 PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
@@ -708,9 +707,8 @@ impl<'a> Resolver<'a> {
                 ident,
                 ScopeSet::Macro(kind),
                 &parent_scope,
-                Some(ident.span),
+                Some(Finalize::new(ast::CRATE_NODE_ID, ident.span)),
                 true,
-                false,
                 None,
             ) {
                 Ok(binding) => {
@@ -751,9 +749,8 @@ impl<'a> Resolver<'a> {
                 ident,
                 ScopeSet::Macro(MacroKind::Attr),
                 &parent_scope,
-                Some(ident.span),
+                Some(Finalize::new(ast::CRATE_NODE_ID, ident.span)),
                 true,
-                false,
                 None,
             );
         }