diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index acad0c6726d9..47b4e9ca2c69 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2307,7 +2307,6 @@ fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) { self.mention_default_field_values(source, ident, &mut err); - let mut not_publicly_reexported = false; if let Some((this_res, outer_ident)) = outermost_res { let mut import_suggestions = self.lookup_import_candidates( outer_ident, @@ -2332,7 +2331,6 @@ fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) { ); // If we suggest importing a public re-export, don't point at the definition. if point_to_def && ident.span != outer_ident.span { - not_publicly_reexported = true; let label = errors::OuterIdentIsNotPubliclyReexported { span: outer_ident.span, outer_ident_descr: this_res.descr(), @@ -2428,7 +2426,7 @@ fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) { }; match binding.kind { - DeclKind::Import { import, .. } => { + DeclKind::Import { source_decl, import, .. } => { for segment in &import.module_path { // Don't include `{{root}}` in suggestions - it's an internal symbol // that should never be shown to users. @@ -2436,9 +2434,10 @@ fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) { path.push(segment.ident); } } + let through_reexport = !matches!(source_decl.kind, DeclKind::Def(_)); sugg_paths.push(( path.iter().cloned().chain(std::iter::once(ident)).collect::>(), - true, // re-export + through_reexport, )); } DeclKind::Def(_) => {} @@ -2472,27 +2471,34 @@ fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) { }; err.subdiagnostic(note); } - // We prioritize shorter paths, non-core imports and direct imports over the alternatives. - sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0].name == sym::core, *reexport)); - // In nested imports `dedup_span` is just the inner ident, so a full path - // substitution would produce invalid code. See #156060. - for (sugg, reexport) in sugg_paths { - if not_publicly_reexported || single_nested { + // The suggestion replaces `dedup_span` with a path reaching the failing ident. + // That's valid only when + // 1) the failing ident is the imported leaf, otherwise `as` renames and trailing segments + // get dropped, and + // 2) the use isn't nested, otherwise `dedup_span` is one ident in `{...}`. + // + // See issue #156060. + let can_replace_use = + !single_nested && !outermost_res.is_some_and(|(_, outer)| outer.span != ident.span); + if can_replace_use { + // We prioritize shorter paths, non-core imports and direct imports over the + // alternatives. + sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0].name == sym::core, *reexport)); + for (sugg, reexport) in sugg_paths { + if sugg.len() <= 1 { + // A single path segment suggestion is wrong. This happens on circular + // imports. `tests/ui/imports/issue-55884-2.rs` + continue; + } + let path = join_path_idents(sugg); + let sugg = if reexport { + errors::ImportIdent::ThroughReExport { span: dedup_span, ident, path } + } else { + errors::ImportIdent::Directly { span: dedup_span, ident, path } + }; + err.subdiagnostic(sugg); break; } - if sugg.len() <= 1 { - // A single path segment suggestion is wrong. This happens on circular imports. - // `tests/ui/imports/issue-55884-2.rs` - continue; - } - let path = join_path_idents(sugg); - let sugg = if reexport { - errors::ImportIdent::ThroughReExport { span: dedup_span, ident, path } - } else { - errors::ImportIdent::Directly { span: dedup_span, ident, path } - }; - err.subdiagnostic(sugg); - break; } err.emit(); diff --git a/tests/ui/imports/ambiguous-import-visibility-globglob-priv.stderr b/tests/ui/imports/ambiguous-import-visibility-globglob-priv.stderr index 07c0be3726ee..a6119dba34d7 100644 --- a/tests/ui/imports/ambiguous-import-visibility-globglob-priv.stderr +++ b/tests/ui/imports/ambiguous-import-visibility-globglob-priv.stderr @@ -14,7 +14,7 @@ note: ...and refers to the struct `S` which is defined here | LL | pub struct S {} | ^^^^^^^^^^^^ you could import this directly -help: import `S` through the re-export +help: import `S` directly | LL - use crate::both::private::S; LL + use crate::m::S; @@ -36,7 +36,7 @@ note: ...and refers to the struct `S` which is defined here | LL | pub struct S {} | ^^^^^^^^^^^^ you could import this directly -help: import `S` through the re-export +help: import `S` directly | LL - use crate::both::private::S; LL + use crate::m::S; diff --git a/tests/ui/imports/private-import-suggestion-path-156244-edition2015.stderr b/tests/ui/imports/private-import-suggestion-path-156244-edition2015.stderr index 4723ac835e30..777e06043069 100644 --- a/tests/ui/imports/private-import-suggestion-path-156244-edition2015.stderr +++ b/tests/ui/imports/private-import-suggestion-path-156244-edition2015.stderr @@ -1,20 +1,20 @@ error[E0603]: struct import `One` is private - --> $DIR/private-import-suggestion-path-156244-edition2015.rs:16:14 + --> $DIR/private-import-suggestion-path-156244-edition2015.rs:12:14 | LL | use two::One; | ^^^ private struct import | note: the struct import `One` is defined here... - --> $DIR/private-import-suggestion-path-156244-edition2015.rs:12:9 + --> $DIR/private-import-suggestion-path-156244-edition2015.rs:8:9 | LL | use one::One; | ^^^^^^^^ note: ...and refers to the struct `One` which is defined here - --> $DIR/private-import-suggestion-path-156244-edition2015.rs:8:5 + --> $DIR/private-import-suggestion-path-156244-edition2015.rs:4:5 | LL | pub struct One(); | ^^^^^^^^^^^^^^^^^ you could import this directly -help: import `One` through the re-export +help: import `One` directly | LL - use two::One; LL + use one::One; diff --git a/tests/ui/imports/private-import-suggestion-path-156244.stderr b/tests/ui/imports/private-import-suggestion-path-156244.stderr index f31d18460b66..c4f8aff04990 100644 --- a/tests/ui/imports/private-import-suggestion-path-156244.stderr +++ b/tests/ui/imports/private-import-suggestion-path-156244.stderr @@ -1,20 +1,20 @@ error[E0603]: struct import `One` is private - --> $DIR/private-import-suggestion-path-156244.rs:15:21 + --> $DIR/private-import-suggestion-path-156244.rs:12:21 | LL | use crate::two::One; | ^^^ private struct import | note: the struct import `One` is defined here... - --> $DIR/private-import-suggestion-path-156244.rs:11:9 + --> $DIR/private-import-suggestion-path-156244.rs:8:9 | LL | use crate::one::One; | ^^^^^^^^^^^^^^^ note: ...and refers to the struct `One` which is defined here - --> $DIR/private-import-suggestion-path-156244.rs:7:5 + --> $DIR/private-import-suggestion-path-156244.rs:4:5 | LL | pub struct One(); | ^^^^^^^^^^^^^^^^^ you could import this directly -help: import `One` through the re-export +help: import `One` directly | LL - use crate::two::One; LL + use crate::one::One; diff --git a/tests/ui/imports/private-std-reexport-suggest-public.stderr b/tests/ui/imports/private-std-reexport-suggest-public.stderr index 49718da7fc93..cc4365d73ad9 100644 --- a/tests/ui/imports/private-std-reexport-suggest-public.stderr +++ b/tests/ui/imports/private-std-reexport-suggest-public.stderr @@ -13,7 +13,7 @@ note: ...and refers to the module `mem` which is defined here --> $SRC_DIR/std/src/lib.rs:LL:COL | = note: you could import this directly -help: import `mem` through the re-export +help: import `mem` directly | LL - use foo::mem; LL + use std::mem; diff --git a/tests/ui/privacy/privacy2.stderr b/tests/ui/privacy/privacy2.stderr index 5c720540db8e..cef8fdb6c515 100644 --- a/tests/ui/privacy/privacy2.stderr +++ b/tests/ui/privacy/privacy2.stderr @@ -20,7 +20,7 @@ note: ...and refers to the function `foo` which is defined here | LL | pub fn foo() {} | ^^^^^^^^^^^^ you could import this directly -help: import `foo` through the re-export +help: import `foo` directly | LL - use bar::glob::foo; LL + use crate::foo;