From 5c1567b6aa783cb3e0ad36ddc37ca3ac9f9a2a6d Mon Sep 17 00:00:00 2001 From: Raushan singh Date: Sat, 7 Nov 2026 09:47:12 +0000 Subject: [PATCH 1/6] test(resolve): add baseline ui test for E0603 on grouped imports --- .../private-import-grouped-suggestion.rs | 142 ++++++ .../private-import-grouped-suggestion.stderr | 425 ++++++++++++++++++ 2 files changed, 567 insertions(+) create mode 100644 tests/ui/imports/private-import-grouped-suggestion.rs create mode 100644 tests/ui/imports/private-import-grouped-suggestion.stderr diff --git a/tests/ui/imports/private-import-grouped-suggestion.rs b/tests/ui/imports/private-import-grouped-suggestion.rs new file mode 100644 index 0000000000000..fd7aa7321e8cf --- /dev/null +++ b/tests/ui/imports/private-import-grouped-suggestion.rs @@ -0,0 +1,142 @@ +mod a { + pub struct A; + pub struct B; +} + +mod b { + use crate::a::{A, B}; + pub struct Z; +} + +mod failing_first { + use crate::b::{A, Z}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod failing_last { + use crate::b::{Z, A}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod failing_middle { + use crate::b::{Z, A, Z as Z2}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod single_item { + use crate::b::{A}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod both_failing { + use crate::b::{A, B}; + //~^ ERROR struct import `A` is private [E0603] + //~| ERROR struct import `B` is private [E0603] +} + +mod multiple_failing_mixed { + use crate::b::{A, Z, B}; + //~^ ERROR struct import `A` is private [E0603] + //~| ERROR struct import `B` is private [E0603] +} + +mod trailing_comma { + use crate::b::{Z, A,}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod multiline { + use crate::b::{ + Z, + A, + //~^ ERROR struct import `A` is private [E0603] + }; +} + +mod rename_inside_group { + use crate::b::{A as Renamed, Z}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod rename_single_item { + use crate::b::{A as Renamed}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod nested_group_multi { + use crate::{b::{A, Z}, a::B}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod nested_group_single { + use crate::{b::{A}, a::B}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod pub_use { + pub use crate::b::{A, Z}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod restricted_pub { + pub(crate) use crate::b::{A, Z}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod with_self { + use crate::b::{self, A}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod multibyte_between_items { + use crate::b::{Z, /* 🦀 日本語 */ A}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod non_ascii_sibling_before { + use crate::b::{Z as 变量, A}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod multiline_multibyte_comment { + use crate::b::{ + Z, + // 🦀 日本語 + A, + //~^ ERROR struct import `A` is private [E0603] + }; +} + +mod block_comment_adjacent { + use crate::b::{A /* c */, Z}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod with_attribute { + #[allow(unused_imports)] + use crate::b::{A, Z}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod inside_function_same_line { + fn f() { use crate::b::{A, Z}; } + //~^ ERROR struct import `A` is private [E0603] +} + +mod std_path { + use std::{fs::Path}; + //~^ ERROR struct `Path` is private [E0603] +} + +macro_rules! define_use { + () => { + use crate::b::{A, Z}; + //~^ ERROR struct import `A` is private [E0603] + }; +} + +mod macro_generated { + define_use!(); +} + +fn main() {} diff --git a/tests/ui/imports/private-import-grouped-suggestion.stderr b/tests/ui/imports/private-import-grouped-suggestion.stderr new file mode 100644 index 0000000000000..c8a1fe27a5510 --- /dev/null +++ b/tests/ui/imports/private-import-grouped-suggestion.stderr @@ -0,0 +1,425 @@ +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:12:20 + | +LL | use crate::b::{A, Z}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:17:23 + | +LL | use crate::b::{Z, A}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:22:23 + | +LL | use crate::b::{Z, A, Z as Z2}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:27:20 + | +LL | use crate::b::{A}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:32:20 + | +LL | use crate::b::{A, B}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct import `B` is private + --> $DIR/private-import-grouped-suggestion.rs:32:23 + | +LL | use crate::b::{A, B}; + | ^ private struct import + | +note: the struct import `B` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:23 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `B` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:3:5 + | +LL | pub struct B; + | ^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:38:20 + | +LL | use crate::b::{A, Z, B}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct import `B` is private + --> $DIR/private-import-grouped-suggestion.rs:38:26 + | +LL | use crate::b::{A, Z, B}; + | ^ private struct import + | +note: the struct import `B` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:23 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `B` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:3:5 + | +LL | pub struct B; + | ^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:44:23 + | +LL | use crate::b::{Z, A,}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:51:9 + | +LL | A, + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:57:20 + | +LL | use crate::b::{A as Renamed, Z}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:62:20 + | +LL | use crate::b::{A as Renamed}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:67:21 + | +LL | use crate::{b::{A, Z}, a::B}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:72:21 + | +LL | use crate::{b::{A}, a::B}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:77:24 + | +LL | pub use crate::b::{A, Z}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:82:31 + | +LL | pub(crate) use crate::b::{A, Z}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:87:26 + | +LL | use crate::b::{self, A}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:92:35 + | +LL | use crate::b::{Z, /* 🦀 日本語 */ A}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:97:29 + | +LL | use crate::b::{Z as 变量, A}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:105:9 + | +LL | A, + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:111:20 + | +LL | use crate::b::{A /* c */, Z}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:117:20 + | +LL | use crate::b::{A, Z}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:122:29 + | +LL | fn f() { use crate::b::{A, Z}; } + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct `Path` is private + --> $DIR/private-import-grouped-suggestion.rs:127:19 + | +LL | use std::{fs::Path}; + | ^^^^ private struct + | +note: the struct `Path` is defined here + --> $SRC_DIR/std/src/fs.rs:LL:COL + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:133:24 + | +LL | macro_rules! define_use { +LL | () => { +LL | use crate::b::{A, Z}; + | ^ private struct import +... +LL | define_use!(); + | ------------- in this macro invocation + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly + +error: aborting due to 25 previous errors + +For more information about this error, try `rustc --explain E0603`. From 7c08e3dafd4fb2ab059d88a57f68b7965187fb40 Mon Sep 17 00:00:00 2001 From: Raushan singh Date: Sat, 7 Nov 2026 11:07:31 +0000 Subject: [PATCH 2/6] refactor(resolve): factor nested use-tree removal span out of calc_unused_spans --- compiler/rustc_resolve/src/check_unused.rs | 32 +++++++++++++++++----- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 91e6188a8c63c..4e76bc256b8de 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -299,6 +299,27 @@ enum UnusedSpanResult { PartialUnused { spans: Vec, remove: Vec }, } +/// Derives the span to remove an item from a multi-item nested `UseTree` group +/// using only AST spans, avoiding source-text scanning and byte arithmetic. +pub(crate) fn nested_item_removal_span( + items: &[ast::UseTreeAndId], + pos: usize, + with_preceding_comma: bool, +) -> Span { + debug_assert!(items.len() >= 2); + debug_assert!(pos < items.len()); + let item = &items[pos].inner; + if with_preceding_comma { + debug_assert!(pos > 0); + let prev = &items[pos - 1].inner; + prev.hi_span().shrink_to_hi().to(item.hi_span()) + } else { + debug_assert!(pos + 1 < items.len()); + let next = &items[pos + 1].inner; + item.prefix.span.to(next.prefix.span.shrink_to_lo()) + } +} + fn calc_unused_spans( unused_import: &UnusedImport, use_tree: &ast::UseTree, @@ -352,14 +373,11 @@ fn calc_unused_spans( if let Some(remove) = remove { let remove_span = if nested.len() == 1 { remove - } else if pos == nested.len() - 1 || used_children > 0 { - // Delete everything from the end of the last import, to delete the - // previous comma - nested[pos - 1].inner.hi_span().shrink_to_hi().to(use_tree.inner.hi_span()) } else { - // Delete everything until the next import, to delete the trailing commas - let inner = &nested[pos + 1].inner; - use_tree.inner.prefix.span.to(inner.prefix.span.shrink_to_lo()) + // Delete previous comma when earlier items are kept or at the last position; + // otherwise delete trailing comma. + let with_preceding_comma = pos == nested.len() - 1 || used_children > 0; + nested_item_removal_span(nested, pos, with_preceding_comma) }; // Try to collapse adjacent spans into a single one. This prevents all cases of From e8e8f06f2a447c4519f4d612dc526d684b105f47 Mon Sep 17 00:00:00 2001 From: Raushan singh Date: Sat, 7 Nov 2026 13:50:00 +0000 Subject: [PATCH 3/6] test(resolve): add glob-in-group cases to baseline E0603 test --- .../private-import-grouped-suggestion.rs | 31 ++++++ .../private-import-grouped-suggestion.stderr | 94 ++++++++++++++++++- 2 files changed, 124 insertions(+), 1 deletion(-) diff --git a/tests/ui/imports/private-import-grouped-suggestion.rs b/tests/ui/imports/private-import-grouped-suggestion.rs index fd7aa7321e8cf..cf6e54eff6963 100644 --- a/tests/ui/imports/private-import-grouped-suggestion.rs +++ b/tests/ui/imports/private-import-grouped-suggestion.rs @@ -139,4 +139,35 @@ mod macro_generated { define_use!(); } +mod x { + pub mod m { + pub struct Item; + } +} + +mod c { + use crate::x::m; + pub struct Other; +} + +mod glob_in_group_single { + use crate::c::{m::*}; + //~^ ERROR module import `m` is private [E0603] +} + +mod glob_in_group_multi { + use crate::c::{m::*, Other}; + //~^ ERROR module import `m` is private [E0603] +} + +mod non_glob_control_single { + use crate::c::{m::Item}; + //~^ ERROR module import `m` is private [E0603] +} + +mod non_glob_control_multi { + use crate::c::{m::Item, Other}; + //~^ ERROR module import `m` is private [E0603] +} + fn main() {} diff --git a/tests/ui/imports/private-import-grouped-suggestion.stderr b/tests/ui/imports/private-import-grouped-suggestion.stderr index c8a1fe27a5510..bc24014f39dd8 100644 --- a/tests/ui/imports/private-import-grouped-suggestion.stderr +++ b/tests/ui/imports/private-import-grouped-suggestion.stderr @@ -398,6 +398,98 @@ LL | use std::{fs::Path}; note: the struct `Path` is defined here --> $SRC_DIR/std/src/fs.rs:LL:COL +error[E0603]: module import `m` is private + --> $DIR/private-import-grouped-suggestion.rs:154:20 + | +LL | use crate::c::{m::*}; + | ^ private module import + | +help: consider importing this module instead: + x::m + --> $DIR/private-import-grouped-suggestion.rs:154:20 + | +LL | use crate::c::{m::*}; + | ^ +note: the module import `m` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:149:9 + | +LL | use crate::x::m; + | ^^^^^^^^^^^ +note: ...and refers to the module `m` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:143:5 + | +LL | pub mod m { + | ^^^^^^^^^ you could import this directly + +error[E0603]: module import `m` is private + --> $DIR/private-import-grouped-suggestion.rs:159:20 + | +LL | use crate::c::{m::*, Other}; + | ^ private module import + | +help: consider importing this module instead: + x::m + --> $DIR/private-import-grouped-suggestion.rs:159:20 + | +LL | use crate::c::{m::*, Other}; + | ^ +note: the module import `m` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:149:9 + | +LL | use crate::x::m; + | ^^^^^^^^^^^ +note: ...and refers to the module `m` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:143:5 + | +LL | pub mod m { + | ^^^^^^^^^ you could import this directly + +error[E0603]: module import `m` is private + --> $DIR/private-import-grouped-suggestion.rs:164:20 + | +LL | use crate::c::{m::Item}; + | ^ private module import + | +help: consider importing this struct instead: + x::m::Item + --> $DIR/private-import-grouped-suggestion.rs:164:20 + | +LL | use crate::c::{m::Item}; + | ^^^^^^^ +note: the module import `m` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:149:9 + | +LL | use crate::x::m; + | ^^^^^^^^^^^ +note: ...and refers to the module `m` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:143:5 + | +LL | pub mod m { + | ^^^^^^^^^ you could import this directly + +error[E0603]: module import `m` is private + --> $DIR/private-import-grouped-suggestion.rs:169:20 + | +LL | use crate::c::{m::Item, Other}; + | ^ private module import + | +help: consider importing this struct instead: + x::m::Item + --> $DIR/private-import-grouped-suggestion.rs:169:20 + | +LL | use crate::c::{m::Item, Other}; + | ^^^^^^^ +note: the module import `m` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:149:9 + | +LL | use crate::x::m; + | ^^^^^^^^^^^ +note: ...and refers to the module `m` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:143:5 + | +LL | pub mod m { + | ^^^^^^^^^ you could import this directly + error[E0603]: struct import `A` is private --> $DIR/private-import-grouped-suggestion.rs:133:24 | @@ -420,6 +512,6 @@ note: ...and refers to the struct `A` which is defined here LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly -error: aborting due to 25 previous errors +error: aborting due to 29 previous errors For more information about this error, try `rustc --explain E0603`. From bbfe1def224110f1d78dd46de7e934354e63c8b1 Mon Sep 17 00:00:00 2001 From: Raushan singh Date: Sun, 8 Nov 2026 04:03:13 +0000 Subject: [PATCH 4/6] refactor(resolve): carry nested import removal info into PrivacyError nested is stored on ImportData rather than ImportKind::Single so that glob imports inside groups are also treated as nested. --- .../rustc_resolve/src/build_reduced_graph.rs | 65 +++++++++++++++---- .../rustc_resolve/src/diagnostics/impls.rs | 6 +- compiler/rustc_resolve/src/ident.rs | 4 +- compiler/rustc_resolve/src/imports.rs | 12 ++-- compiler/rustc_resolve/src/lib.rs | 17 ++++- 5 files changed, 81 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 1eb438933e489..e326636d842dd 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -31,6 +31,7 @@ use thin_vec::ThinVec; use tracing::debug; use crate::Namespace::{MacroNS, TypeNS, ValueNS}; +use crate::check_unused::nested_item_removal_span; use crate::def_collector::DefCollector; use crate::diagnostics::impls::{OnUnknownData, StructCtor}; use crate::imports::{ImportData, ImportKind, NameResolution, NameResolutionRef}; @@ -39,8 +40,8 @@ use crate::ref_mut::CmCell; use crate::{ BindingKey, Decl, DeclData, DeclKind, DelayedVisResolutionError, ExternModule, ExternPreludeEntry, Finalize, IdentKey, LocalModule, Module, ModuleKind, ModuleOrUniformRoot, - ParentScope, PathResult, Res, ResolutionTable, Resolver, Segment, Used, VisResolutionError, - diagnostics, + NestedImportRemoval, ParentScope, PathResult, Res, ResolutionTable, Resolver, Segment, Used, + VisResolutionError, diagnostics, }; impl<'ra, 'tcx> Resolver<'ra, 'tcx> { @@ -548,6 +549,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { root_span: Span, root_id: NodeId, vis: Visibility, + nested: Option, ) { let current_module = self.parent_scope.module.expect_local(); let import = self.r.arenas.alloc_import(ImportData { @@ -564,6 +566,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { vis, vis_span: item.vis.span, on_unknown_attr: OnUnknownData::from_attrs(self.r, &item.attrs), + nested, }); self.r.indeterminate_imports.push((import, None, 0)); @@ -595,20 +598,20 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { use_tree: &ast::UseTree, id: NodeId, parent_prefix: &[Segment], - nested: bool, + nested: Option, list_stem: bool, vis: Visibility, root_span: Span, feed: TyCtxtFeed<'tcx, LocalDefId>, ) { debug!( - "build_reduced_graph_for_use_tree(parent_prefix={:?}, use_tree={:?}, nested={})", + "build_reduced_graph_for_use_tree(parent_prefix={:?}, use_tree={:?}, nested={:?})", parent_prefix, use_tree, nested ); // Top level use tree reuses the item's id and list stems reuse their parent // use tree's ids, so in both cases their visibilities are already filled. - if nested && !list_stem { + if nested.is_some() && !list_stem { self.r.feed_visibility(feed, vis); } @@ -733,18 +736,36 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { source: source.ident, target: ident, decls: Default::default(), - nested, + nested: nested.is_some(), id, def_id: feed.def_id(), }; - self.add_import(module_path, kind, use_tree.span(), item, root_span, item.id, vis); + self.add_import( + module_path, + kind, + use_tree.span(), + item, + root_span, + item.id, + vis, + nested, + ); } ast::UseTreeKind::Glob(_) => { if !ast::attr::contains_name(&item.attrs, sym::prelude_import) { let kind = ImportKind::Glob { max_vis: CmCell::new(None), id, def_id: feed.def_id() }; - self.add_import(prefix, kind, use_tree.span(), item, root_span, item.id, vis); + self.add_import( + prefix, + kind, + use_tree.span(), + item, + root_span, + item.id, + vis, + nested, + ); } else { // Resolve the prelude import early. let path_res = @@ -757,15 +778,24 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { } } ast::UseTreeKind::Nested { ref items, .. } => { - for tree in items { + for (pos, tree) in items.iter().enumerate() { let id = tree.id; let feed = self.create_def(id, None, DefKind::Use, use_tree.span()); + let item_nested = if items.len() > 1 { + Some(NestedImportRemoval::Remove(nested_item_removal_span( + items, + pos, + pos > 0, + ))) + } else { + Some(nested.unwrap_or(NestedImportRemoval::ReplaceRoot)) + }; self.build_reduced_graph_for_use_tree( item, &tree.inner, id, &prefix, - true, + item_nested, false, vis, root_span, @@ -789,7 +819,15 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { self.parent_scope.module.nearest_parent_mod().expect_local(), ); self.build_reduced_graph_for_use_tree( - item, &tree, id, &prefix, true, true, vis, root_span, feed, + item, + &tree, + id, + &prefix, + nested.or(Some(NestedImportRemoval::ReplaceRoot)), + true, + vis, + root_span, + feed, ); } } @@ -840,7 +878,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { use_tree, item.id, &[], - false, + None, false, vis, use_tree.span(), @@ -1053,6 +1091,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { vis, vis_span: item.vis.span, on_unknown_attr: OnUnknownData::from_attrs(self.r, &item.attrs), + nested: None, }); if used { self.r.import_use_map.insert(import, Used::Other); @@ -1185,6 +1224,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { vis: Visibility::Restricted(CRATE_MOD_ID), vis_span: item.vis.span, on_unknown_attr: OnUnknownData::from_attrs(this.r, &item.attrs), + nested: None, }) }; @@ -1368,6 +1408,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { vis, vis_span: item.vis.span, on_unknown_attr: OnUnknownData::from_attrs(self.r, &item.attrs), + nested: None, }); self.r.import_use_map.insert(import, Used::Other); let import_decl = self.r.new_import_decl(decl, import); diff --git a/compiler/rustc_resolve/src/diagnostics/impls.rs b/compiler/rustc_resolve/src/diagnostics/impls.rs index 7b4ecee52dad1..1f067dc098e68 100644 --- a/compiler/rustc_resolve/src/diagnostics/impls.rs +++ b/compiler/rustc_resolve/src/diagnostics/impls.rs @@ -2727,7 +2727,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { decl, outermost_res, parent_scope, - single_nested, + nested, dedup_span, ref source, } = *privacy_error; @@ -2765,7 +2765,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &import_suggestions, Instead::Yes, FoundUse::Yes, - DiagMode::Import { append: single_nested, unresolved_import: false }, + DiagMode::Import { append: nested.is_some(), unresolved_import: false }, vec![], "", ); @@ -2961,7 +2961,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // // See issue #156060. let can_replace_use = !shown_candidates - && !single_nested + && nested.is_none() && !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 diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 25b1ad5e9d01c..0185b2ed7de2f 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1365,7 +1365,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { finalize: Finalize, shadowing: Shadowing, ) -> Result, ControlFlow> { - let Finalize { path_span, report_private, used, root_span, .. } = finalize; + let Finalize { path_span, report_private, used, .. } = finalize; let Some(binding) = binding else { return Err(ControlFlow::Continue(Determined)); @@ -1381,7 +1381,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { outermost_res: None, source: None, parent_scope: *parent_scope, - single_nested: path_span != root_span, + nested: finalize.nested, }); } else { return Err(ControlFlow::Break(Determined)); diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 9afbb425eeb9d..69bbb20e9fdbd 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -34,9 +34,9 @@ use crate::diagnostics::{ use crate::ref_mut::{CmCell, CmRefCell}; use crate::{ AmbiguityError, BindingKey, Decl, DeclData, DeclKind, Determinacy, Finalize, IdentKey, - ImportSuggestion, ImportSummary, LocalModule, ModuleOrUniformRoot, ParentScope, PathResult, - PerNS, Res, ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string, - names_to_string, + ImportSuggestion, ImportSummary, LocalModule, ModuleOrUniformRoot, NestedImportRemoval, + ParentScope, PathResult, PerNS, Res, ResolutionError, Resolver, ScopeSet, Segment, Used, + module_to_string, names_to_string, }; /// A potential import declaration in the process of being planted into a module. @@ -208,6 +208,7 @@ pub(crate) struct ImportData<'ra> { /// /// This is `None` if the feature flag for `diagnostic::on_unknown` is disabled. pub on_unknown_attr: Option, + pub nested: Option, } /// `Interned` is used because values of this type have "identity" and compare as unequal even if @@ -1200,7 +1201,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { errors.iter().filter(|error| error.warning.is_none()).count() }; let prev_ambiguity_errors_len = ambiguity_errors_len(&self.ambiguity_errors); - let finalize = Finalize::with_root_span(import.root_id, import.span, import.root_span); + let finalize = Finalize { + nested: import.nested, + ..Finalize::with_root_span(import.root_id, import.span, import.root_span) + }; // We'll provide more context to the privacy errors later, up to `len`. let privacy_errors_len = self.privacy_errors.len(); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 0fc9c31f43e32..02756df812f8d 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1079,15 +1079,26 @@ impl<'ra> DeclKind<'ra> { } } +/// Removal or replacement strategy for diagnostics on nested use-trees. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub(crate) enum NestedImportRemoval { + /// The root use statement imports only this item (e.g. `use a::{B};`, `use a::{b::{C}};`), + /// so the entire statement can be replaced in-place by a path. + ReplaceRoot, + /// Span removing the item and an adjacent comma (trailing if first item, preceding otherwise). + Remove(Span), +} + #[derive(Debug)] struct PrivacyError<'ra> { ident: Ident, decl: Decl<'ra>, + /// Span of the use-tree or AST path, used as the deduplication key and replacement target. dedup_span: Span, outermost_res: Option<(Res, Ident)>, parent_scope: ParentScope<'ra>, - /// Is the format `use a::{b,c}`? - single_nested: bool, + /// Removal strategy if part of a nested use-tree, for diagnostic suggestions. + nested: Option, source: Option, } @@ -2873,6 +2884,8 @@ struct Finalize { stage: Stage = Stage::Early, /// Some import data, in case we are resolving an import's final segment. import: Option = None, + /// Removal strategy if part of a nested use-tree, for diagnostic suggestions. + nested: Option = None, } impl Finalize { From 6ef0b63a6a2249847f4ed415050199a85bdb2094 Mon Sep 17 00:00:00 2001 From: Raushan singh Date: Sun, 8 Nov 2026 08:53:24 +0000 Subject: [PATCH 5/6] feat(resolve): suggest replacing single-item grouped imports in E0603 When a private item is imported inside a group where it is the only item of the root use-tree (e.g. `use a::{B};`, `use a::{b::{C}};`), emit an in-place suggestion replacing the root use-tree with the accessible path. Single-item groups carrying renames (`use a::{B as C};`) or globs (`use a::{m::*};`), as well as imports expanded from macros where the root span cannot be used for suggestions, are skipped to prevent dropping aliases, trailing glob wildcards, or proposing edits inside macro definitions. --- .../rustc_resolve/src/build_reduced_graph.rs | 4 +- .../rustc_resolve/src/diagnostics/impls.rs | 40 ++-- compiler/rustc_resolve/src/lib.rs | 6 +- .../private-import-grouped-suggestion.rs | 44 +++++ .../private-import-grouped-suggestion.stderr | 171 +++++++++++++++--- 5 files changed, 217 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index e326636d842dd..3715cce1c8836 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -788,7 +788,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { pos > 0, ))) } else { - Some(nested.unwrap_or(NestedImportRemoval::ReplaceRoot)) + nested.or(Some(NestedImportRemoval::ReplaceRoot(root_span))) }; self.build_reduced_graph_for_use_tree( item, @@ -823,7 +823,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { &tree, id, &prefix, - nested.or(Some(NestedImportRemoval::ReplaceRoot)), + nested.or(Some(NestedImportRemoval::ReplaceRoot(root_span))), true, vis, root_span, diff --git a/compiler/rustc_resolve/src/diagnostics/impls.rs b/compiler/rustc_resolve/src/diagnostics/impls.rs index 1f067dc098e68..d2d63b3bd4403 100644 --- a/compiler/rustc_resolve/src/diagnostics/impls.rs +++ b/compiler/rustc_resolve/src/diagnostics/impls.rs @@ -55,9 +55,9 @@ use crate::late::{ConstantRequiresType, DiagMetadata, PatternSource, Rib}; use crate::{ AmbiguityError, AmbiguityKind, AmbiguityWarning, BindingError, BindingKey, Decl, DeclKind, DelayedVisResolutionError, Finalize, ForwardGenericParamBanReason, HasGenericParams, IdentKey, - LateDecl, MacroRulesScope, Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, - PrivacyError, Res, ResolutionError, Resolver, Scope, ScopeSet, Segment, UseError, Used, - VisResolutionError, path_names_to_string, + LateDecl, MacroRulesScope, Module, ModuleKind, ModuleOrUniformRoot, NestedImportRemoval, + ParentScope, PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope, ScopeSet, + Segment, UseError, Used, VisResolutionError, path_names_to_string, }; /// A vector of spans and replacements, a message and applicability. @@ -2953,17 +2953,27 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; err.subdiagnostic(note); } - // 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 `{...}`. + // The suggestion replaces `sugg_span` with a path reaching the failing ident. + // That's valid only when: + // 1) the failing ident is the imported leaf, otherwise trailing segments get dropped, and + // 2) for grouped imports, the failing item is the only item in the root use-tree. // - // See issue #156060. - let can_replace_use = !shown_candidates - && nested.is_none() - && !outermost_res.is_some_and(|(_, outer)| outer.span != ident.span); - if can_replace_use { + // See issue #156060 and #157453. + let is_leaf = !outermost_res.is_some_and(|(_, outer)| outer.span != ident.span); + let sugg_span = match nested { + None => Some(dedup_span), + Some(NestedImportRemoval::ReplaceRoot(root_span)) => { + // Replacing the root with a path drops renames (`A as Renamed`) and globs (`m::*`). + let is_renamed_or_glob = dedup_span.hi() != ident.span.hi(); + (!is_renamed_or_glob && root_span.can_be_used_for_suggestions()) + .then_some(root_span) + } + Some(NestedImportRemoval::Remove(_)) => None, + }; + if !shown_candidates + && is_leaf + && let Some(sugg_span) = sugg_span + { // 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)); @@ -2977,9 +2987,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let ident = *sugg.last().expect("at least one segment"); let path = join_path_idents(sugg); let sugg = if reexport { - diagnostics::ImportIdent::ThroughReExport { span: dedup_span, ident, path } + diagnostics::ImportIdent::ThroughReExport { span: sugg_span, ident, path } } else { - diagnostics::ImportIdent::Directly { span: dedup_span, ident, path } + diagnostics::ImportIdent::Directly { span: sugg_span, ident, path } }; err.subdiagnostic(sugg); break; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 02756df812f8d..148682a830d35 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1082,9 +1082,9 @@ impl<'ra> DeclKind<'ra> { /// Removal or replacement strategy for diagnostics on nested use-trees. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub(crate) enum NestedImportRemoval { - /// The root use statement imports only this item (e.g. `use a::{B};`, `use a::{b::{C}};`), - /// so the entire statement can be replaced in-place by a path. - ReplaceRoot, + /// The root use-tree imports only this item (e.g. `use a::{B};`, `use a::{b::{C}};`), + /// so it can be replaced in-place by a path. + ReplaceRoot(Span), /// Span removing the item and an adjacent comma (trailing if first item, preceding otherwise). Remove(Span), } diff --git a/tests/ui/imports/private-import-grouped-suggestion.rs b/tests/ui/imports/private-import-grouped-suggestion.rs index cf6e54eff6963..953bac1ecfca5 100644 --- a/tests/ui/imports/private-import-grouped-suggestion.rs +++ b/tests/ui/imports/private-import-grouped-suggestion.rs @@ -73,11 +73,21 @@ mod nested_group_single { //~^ ERROR struct import `A` is private [E0603] } +mod nested_single_in_single { + use crate::{b::{A}}; + //~^ ERROR struct import `A` is private [E0603] +} + mod pub_use { pub use crate::b::{A, Z}; //~^ ERROR struct import `A` is private [E0603] } +mod pub_use_single { + pub use crate::b::{A}; + //~^ ERROR struct import `A` is private [E0603] +} + mod restricted_pub { pub(crate) use crate::b::{A, Z}; //~^ ERROR struct import `A` is private [E0603] @@ -118,6 +128,12 @@ mod with_attribute { //~^ ERROR struct import `A` is private [E0603] } +mod with_attribute_single { + #[allow(unused_imports)] + use crate::b::{A}; + //~^ ERROR struct import `A` is private [E0603] +} + mod inside_function_same_line { fn f() { use crate::b::{A, Z}; } //~^ ERROR struct import `A` is private [E0603] @@ -139,6 +155,17 @@ mod macro_generated { define_use!(); } +macro_rules! define_use_single { + () => { + use crate::b::{A}; + //~^ ERROR struct import `A` is private [E0603] + }; +} + +mod macro_generated_single { + define_use_single!(); +} + mod x { pub mod m { pub struct Item; @@ -170,4 +197,21 @@ mod non_glob_control_multi { //~^ ERROR module import `m` is private [E0603] } +mod unexported { + mod hidden { + pub mod m { + pub struct Item; + } + } + + pub mod intermediate { + use super::hidden::m; + } +} + +mod glob_in_single_group_no_candidate { + use crate::unexported::intermediate::{m::*}; + //~^ ERROR module import `m` is private [E0603] +} + fn main() {} diff --git a/tests/ui/imports/private-import-grouped-suggestion.stderr b/tests/ui/imports/private-import-grouped-suggestion.stderr index bc24014f39dd8..1ad0918c9dc30 100644 --- a/tests/ui/imports/private-import-grouped-suggestion.stderr +++ b/tests/ui/imports/private-import-grouped-suggestion.stderr @@ -65,6 +65,11 @@ note: ...and refers to the struct `A` which is defined here | LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL - use crate::b::{A}; +LL + use crate::a::A; + | error[E0603]: struct import `A` is private --> $DIR/private-import-grouped-suggestion.rs:32:20 @@ -237,7 +242,29 @@ LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly error[E0603]: struct import `A` is private - --> $DIR/private-import-grouped-suggestion.rs:77:24 + --> $DIR/private-import-grouped-suggestion.rs:77:21 + | +LL | use crate::{b::{A}}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL - use crate::{b::{A}}; +LL + use crate::a::A; + | + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:82:24 | LL | pub use crate::b::{A, Z}; | ^ private struct import @@ -254,7 +281,29 @@ LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly error[E0603]: struct import `A` is private - --> $DIR/private-import-grouped-suggestion.rs:82:31 + --> $DIR/private-import-grouped-suggestion.rs:87:24 + | +LL | pub use crate::b::{A}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL - pub use crate::b::{A}; +LL + pub use crate::a::A; + | + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:92:31 | LL | pub(crate) use crate::b::{A, Z}; | ^ private struct import @@ -271,7 +320,7 @@ LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly error[E0603]: struct import `A` is private - --> $DIR/private-import-grouped-suggestion.rs:87:26 + --> $DIR/private-import-grouped-suggestion.rs:97:26 | LL | use crate::b::{self, A}; | ^ private struct import @@ -288,7 +337,7 @@ LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly error[E0603]: struct import `A` is private - --> $DIR/private-import-grouped-suggestion.rs:92:35 + --> $DIR/private-import-grouped-suggestion.rs:102:35 | LL | use crate::b::{Z, /* 🦀 日本語 */ A}; | ^ private struct import @@ -305,7 +354,7 @@ LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly error[E0603]: struct import `A` is private - --> $DIR/private-import-grouped-suggestion.rs:97:29 + --> $DIR/private-import-grouped-suggestion.rs:107:29 | LL | use crate::b::{Z as 变量, A}; | ^ private struct import @@ -322,7 +371,7 @@ LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly error[E0603]: struct import `A` is private - --> $DIR/private-import-grouped-suggestion.rs:105:9 + --> $DIR/private-import-grouped-suggestion.rs:115:9 | LL | A, | ^ private struct import @@ -339,7 +388,7 @@ LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly error[E0603]: struct import `A` is private - --> $DIR/private-import-grouped-suggestion.rs:111:20 + --> $DIR/private-import-grouped-suggestion.rs:121:20 | LL | use crate::b::{A /* c */, Z}; | ^ private struct import @@ -356,7 +405,7 @@ LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly error[E0603]: struct import `A` is private - --> $DIR/private-import-grouped-suggestion.rs:117:20 + --> $DIR/private-import-grouped-suggestion.rs:127:20 | LL | use crate::b::{A, Z}; | ^ private struct import @@ -373,7 +422,29 @@ LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly error[E0603]: struct import `A` is private - --> $DIR/private-import-grouped-suggestion.rs:122:29 + --> $DIR/private-import-grouped-suggestion.rs:133:20 + | +LL | use crate::b::{A}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL - use crate::b::{A}; +LL + use crate::a::A; + | + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:138:29 | LL | fn f() { use crate::b::{A, Z}; } | ^ private struct import @@ -390,108 +461,130 @@ LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly error[E0603]: struct `Path` is private - --> $DIR/private-import-grouped-suggestion.rs:127:19 + --> $DIR/private-import-grouped-suggestion.rs:143:19 | LL | use std::{fs::Path}; | ^^^^ private struct | note: the struct `Path` is defined here --> $SRC_DIR/std/src/fs.rs:LL:COL +help: import `Path` directly + | +LL - use std::{fs::Path}; +LL + use std::path::Path; + | error[E0603]: module import `m` is private - --> $DIR/private-import-grouped-suggestion.rs:154:20 + --> $DIR/private-import-grouped-suggestion.rs:181:20 | LL | use crate::c::{m::*}; | ^ private module import | help: consider importing this module instead: x::m - --> $DIR/private-import-grouped-suggestion.rs:154:20 + --> $DIR/private-import-grouped-suggestion.rs:181:20 | LL | use crate::c::{m::*}; | ^ note: the module import `m` is defined here... - --> $DIR/private-import-grouped-suggestion.rs:149:9 + --> $DIR/private-import-grouped-suggestion.rs:176:9 | LL | use crate::x::m; | ^^^^^^^^^^^ note: ...and refers to the module `m` which is defined here - --> $DIR/private-import-grouped-suggestion.rs:143:5 + --> $DIR/private-import-grouped-suggestion.rs:170:5 | LL | pub mod m { | ^^^^^^^^^ you could import this directly error[E0603]: module import `m` is private - --> $DIR/private-import-grouped-suggestion.rs:159:20 + --> $DIR/private-import-grouped-suggestion.rs:186:20 | LL | use crate::c::{m::*, Other}; | ^ private module import | help: consider importing this module instead: x::m - --> $DIR/private-import-grouped-suggestion.rs:159:20 + --> $DIR/private-import-grouped-suggestion.rs:186:20 | LL | use crate::c::{m::*, Other}; | ^ note: the module import `m` is defined here... - --> $DIR/private-import-grouped-suggestion.rs:149:9 + --> $DIR/private-import-grouped-suggestion.rs:176:9 | LL | use crate::x::m; | ^^^^^^^^^^^ note: ...and refers to the module `m` which is defined here - --> $DIR/private-import-grouped-suggestion.rs:143:5 + --> $DIR/private-import-grouped-suggestion.rs:170:5 | LL | pub mod m { | ^^^^^^^^^ you could import this directly error[E0603]: module import `m` is private - --> $DIR/private-import-grouped-suggestion.rs:164:20 + --> $DIR/private-import-grouped-suggestion.rs:191:20 | LL | use crate::c::{m::Item}; | ^ private module import | help: consider importing this struct instead: x::m::Item - --> $DIR/private-import-grouped-suggestion.rs:164:20 + --> $DIR/private-import-grouped-suggestion.rs:191:20 | LL | use crate::c::{m::Item}; | ^^^^^^^ note: the module import `m` is defined here... - --> $DIR/private-import-grouped-suggestion.rs:149:9 + --> $DIR/private-import-grouped-suggestion.rs:176:9 | LL | use crate::x::m; | ^^^^^^^^^^^ note: ...and refers to the module `m` which is defined here - --> $DIR/private-import-grouped-suggestion.rs:143:5 + --> $DIR/private-import-grouped-suggestion.rs:170:5 | LL | pub mod m { | ^^^^^^^^^ you could import this directly error[E0603]: module import `m` is private - --> $DIR/private-import-grouped-suggestion.rs:169:20 + --> $DIR/private-import-grouped-suggestion.rs:196:20 | LL | use crate::c::{m::Item, Other}; | ^ private module import | help: consider importing this struct instead: x::m::Item - --> $DIR/private-import-grouped-suggestion.rs:169:20 + --> $DIR/private-import-grouped-suggestion.rs:196:20 | LL | use crate::c::{m::Item, Other}; | ^^^^^^^ note: the module import `m` is defined here... - --> $DIR/private-import-grouped-suggestion.rs:149:9 + --> $DIR/private-import-grouped-suggestion.rs:176:9 | LL | use crate::x::m; | ^^^^^^^^^^^ note: ...and refers to the module `m` which is defined here - --> $DIR/private-import-grouped-suggestion.rs:143:5 + --> $DIR/private-import-grouped-suggestion.rs:170:5 | LL | pub mod m { | ^^^^^^^^^ you could import this directly +error[E0603]: module import `m` is private + --> $DIR/private-import-grouped-suggestion.rs:213:43 + | +LL | use crate::unexported::intermediate::{m::*}; + | ^ private module import + | +note: the module import `m` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:208:13 + | +LL | use super::hidden::m; + | ^^^^^^^^^^^^^^^^ +note: ...and refers to the module `m` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:202:9 + | +LL | pub mod m { + | ^^^^^^^^^ + error[E0603]: struct import `A` is private - --> $DIR/private-import-grouped-suggestion.rs:133:24 + --> $DIR/private-import-grouped-suggestion.rs:149:24 | LL | macro_rules! define_use { LL | () => { @@ -512,6 +605,28 @@ note: ...and refers to the struct `A` which is defined here LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly -error: aborting due to 29 previous errors +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion.rs:160:24 + | +LL | macro_rules! define_use_single { +LL | () => { +LL | use crate::b::{A}; + | ^ private struct import +... +LL | define_use_single!(); + | -------------------- in this macro invocation + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion.rs:7:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion.rs:2:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly + +error: aborting due to 34 previous errors For more information about this error, try `rustc --explain E0603`. From 102131eddbf7224c88e860c0842822000fb74882 Mon Sep 17 00:00:00 2001 From: Raushan singh Date: Sun, 8 Nov 2026 11:32:15 +0000 Subject: [PATCH 6/6] feat(resolve): suggest extracting failing items from grouped imports in E0603 When a private item is imported inside a multi-item grouped import statement (e.g. `use a::{B, C};` where `B` is private), emit a multipart suggestion extracting `B` into its own standalone `use` statement prepended before the root import and removing `B` from the group. Extraction is restricted to `use` items with inherited visibility and empty attributes to avoid losing visibility or attributes, and skipped for renames (`as Renamed`), globs (`::*`), and spans originating from macro expansions where spans cannot be used for suggestions. --- .../rustc_resolve/src/build_reduced_graph.rs | 12 +- .../rustc_resolve/src/diagnostics/impls.rs | 78 ++++-- compiler/rustc_resolve/src/diagnostics/mod.rs | 26 ++ compiler/rustc_resolve/src/lib.rs | 5 +- ...te-import-grouped-suggestion-rustfix.fixed | 79 ++++++ ...ivate-import-grouped-suggestion-rustfix.rs | 73 ++++++ ...e-import-grouped-suggestion-rustfix.stderr | 246 ++++++++++++++++++ .../private-import-grouped-suggestion.rs | 5 + .../private-import-grouped-suggestion.stderr | 145 +++++++++-- ...ate-import-nested-suggestion-156060.stderr | 5 + ...suggestion-path-156244.edition_2015.stderr | 10 + ...suggestion-path-156244.edition_2018.stderr | 10 + 12 files changed, 646 insertions(+), 48 deletions(-) create mode 100644 tests/ui/imports/private-import-grouped-suggestion-rustfix.fixed create mode 100644 tests/ui/imports/private-import-grouped-suggestion-rustfix.rs create mode 100644 tests/ui/imports/private-import-grouped-suggestion-rustfix.stderr diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 3715cce1c8836..facebeaf9fe36 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -778,15 +778,17 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { } } ast::UseTreeKind::Nested { ref items, .. } => { + let can_extract = item.attrs.is_empty() + && matches!(item.vis.kind, ast::VisibilityKind::Inherited); + let use_span = can_extract.then_some(item.span); for (pos, tree) in items.iter().enumerate() { let id = tree.id; let feed = self.create_def(id, None, DefKind::Use, use_tree.span()); let item_nested = if items.len() > 1 { - Some(NestedImportRemoval::Remove(nested_item_removal_span( - items, - pos, - pos > 0, - ))) + Some(NestedImportRemoval::Remove { + removal_span: nested_item_removal_span(items, pos, pos > 0), + use_span, + }) } else { nested.or(Some(NestedImportRemoval::ReplaceRoot(root_span))) }; diff --git a/compiler/rustc_resolve/src/diagnostics/impls.rs b/compiler/rustc_resolve/src/diagnostics/impls.rs index d2d63b3bd4403..e7bdf2ef4b05f 100644 --- a/compiler/rustc_resolve/src/diagnostics/impls.rs +++ b/compiler/rustc_resolve/src/diagnostics/impls.rs @@ -125,6 +125,13 @@ pub(crate) struct ImportSuggestion { pub is_stable: bool, } +/// Diagnostic suggestion target: in-place replacement or grouped import extraction. +#[derive(Copy, Clone, Debug)] +enum SuggTarget { + Replace(Span), + Extract { use_span: Span, removal_span: Span }, +} + /// Adjust the impl span so that just the `impl` keyword is taken by removing /// everything after `<` (`"impl Iterator for A {}" -> "impl"`) and /// everything after the first whitespace (`"impl Iterator for A" -> "impl"`). @@ -2953,26 +2960,30 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; err.subdiagnostic(note); } - // The suggestion replaces `sugg_span` with a path reaching the failing ident. - // That's valid only when: - // 1) the failing ident is the imported leaf, otherwise trailing segments get dropped, and - // 2) for grouped imports, the failing item is the only item in the root use-tree. - // - // See issue #156060 and #157453. let is_leaf = !outermost_res.is_some_and(|(_, outer)| outer.span != ident.span); - let sugg_span = match nested { - None => Some(dedup_span), - Some(NestedImportRemoval::ReplaceRoot(root_span)) => { - // Replacing the root with a path drops renames (`A as Renamed`) and globs (`m::*`). - let is_renamed_or_glob = dedup_span.hi() != ident.span.hi(); - (!is_renamed_or_glob && root_span.can_be_used_for_suggestions()) - .then_some(root_span) + // Modifying grouped imports drops renames (`A as Renamed`) and globs (`m::*`). + let is_renamed_or_glob = dedup_span.hi() != ident.span.hi(); + // The suggestion replaces the root tree for non-grouped or single-item imports, + // or extracts the failing item into its own `use` statement for multi-item groups. + let sugg_target = match nested { + None => Some(SuggTarget::Replace(dedup_span)), + Some(_) if is_renamed_or_glob => None, + Some(NestedImportRemoval::ReplaceRoot(root_span)) + if root_span.can_be_used_for_suggestions() => + { + Some(SuggTarget::Replace(root_span)) } - Some(NestedImportRemoval::Remove(_)) => None, + Some(NestedImportRemoval::Remove { removal_span, use_span: Some(use_span) }) + if use_span.can_be_used_for_suggestions() + && removal_span.can_be_used_for_suggestions() => + { + Some(SuggTarget::Extract { use_span, removal_span }) + } + Some(_) => None, }; if !shown_candidates && is_leaf - && let Some(sugg_span) = sugg_span + && let Some(sugg_target) = sugg_target { // We prioritize shorter paths, non-core imports and direct imports over the // alternatives. @@ -2986,10 +2997,39 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // The suggested path may use a different name than the private alias. let ident = *sugg.last().expect("at least one segment"); let path = join_path_idents(sugg); - let sugg = if reexport { - diagnostics::ImportIdent::ThroughReExport { span: sugg_span, ident, path } - } else { - diagnostics::ImportIdent::Directly { span: sugg_span, ident, path } + let sugg = match sugg_target { + SuggTarget::Replace(span) => { + if reexport { + diagnostics::ImportIdent::ThroughReExport { span, ident, path } + } else { + diagnostics::ImportIdent::Directly { span, ident, path } + } + } + SuggTarget::Extract { use_span, removal_span } => { + let indent = self + .tcx + .sess + .source_map() + .indentation_before(use_span) + .unwrap_or_default(); + let use_stmt = format!("use {path};\n{indent}"); + let insert_span = use_span.shrink_to_lo(); + if reexport { + diagnostics::ImportIdent::ExtractThroughReExport { + insert_span, + removal_span, + ident, + use_stmt, + } + } else { + diagnostics::ImportIdent::ExtractDirectly { + insert_span, + removal_span, + ident, + use_stmt, + } + } + } }; err.subdiagnostic(sugg); break; diff --git a/compiler/rustc_resolve/src/diagnostics/mod.rs b/compiler/rustc_resolve/src/diagnostics/mod.rs index e33255eec46d8..67e0bb7b76775 100644 --- a/compiler/rustc_resolve/src/diagnostics/mod.rs +++ b/compiler/rustc_resolve/src/diagnostics/mod.rs @@ -1330,6 +1330,32 @@ pub(crate) enum ImportIdent { ident: Ident, path: String, }, + #[multipart_suggestion( + "import `{$ident}` through the re-export", + applicability = "machine-applicable", + style = "verbose" + )] + ExtractThroughReExport { + #[suggestion_part(code = "{use_stmt}")] + insert_span: Span, + #[suggestion_part(code = "")] + removal_span: Span, + ident: Ident, + use_stmt: String, + }, + #[multipart_suggestion( + "import `{$ident}` directly", + applicability = "machine-applicable", + style = "verbose" + )] + ExtractDirectly { + #[suggestion_part(code = "{use_stmt}")] + insert_span: Span, + #[suggestion_part(code = "")] + removal_span: Span, + ident: Ident, + use_stmt: String, + }, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 148682a830d35..42ac060201469 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1085,8 +1085,9 @@ pub(crate) enum NestedImportRemoval { /// The root use-tree imports only this item (e.g. `use a::{B};`, `use a::{b::{C}};`), /// so it can be replaced in-place by a path. ReplaceRoot(Span), - /// Span removing the item and an adjacent comma (trailing if first item, preceding otherwise). - Remove(Span), + /// Span removing the item and an adjacent comma, plus optional span of the top-level + /// `use` statement if suitable for extraction. + Remove { removal_span: Span, use_span: Option }, } #[derive(Debug)] diff --git a/tests/ui/imports/private-import-grouped-suggestion-rustfix.fixed b/tests/ui/imports/private-import-grouped-suggestion-rustfix.fixed new file mode 100644 index 0000000000000..9811d4f7b8497 --- /dev/null +++ b/tests/ui/imports/private-import-grouped-suggestion-rustfix.fixed @@ -0,0 +1,79 @@ +//@ run-rustfix +#![allow(unused_imports, dead_code)] + +mod a { + pub struct A; + pub struct B; +} + +mod b { + use crate::a::{A, B}; + pub struct Z; +} + +mod failing_first { + use crate::a::A; + use crate::b::{Z}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod failing_last { + use crate::a::A; + use crate::b::{Z}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod trailing_comma { + use crate::a::A; + use crate::b::{Z,}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod multiline { + use crate::a::A; + use crate::b::{ + Z, + //~^ ERROR struct import `A` is private [E0603] + }; +} + +mod with_self { + use crate::a::A; + use crate::b::{self}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod nested_group_multi { + use crate::a::A; + use crate::{b::{Z}, a::B}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod nested_group_single { + use crate::a::A; + use crate::{a::B}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod single_item { + use crate::a::A; + //~^ ERROR struct import `A` is private [E0603] +} + +mod nested_single_in_single { + use crate::a::A; + //~^ ERROR struct import `A` is private [E0603] +} + +mod pub_use_single { + pub use crate::a::A; + //~^ ERROR struct import `A` is private [E0603] +} + +mod with_attribute_single { + #[allow(unused_imports)] + use crate::a::A; + //~^ ERROR struct import `A` is private [E0603] +} + +fn main() {} diff --git a/tests/ui/imports/private-import-grouped-suggestion-rustfix.rs b/tests/ui/imports/private-import-grouped-suggestion-rustfix.rs new file mode 100644 index 0000000000000..1d6ebb3f2a0a4 --- /dev/null +++ b/tests/ui/imports/private-import-grouped-suggestion-rustfix.rs @@ -0,0 +1,73 @@ +//@ run-rustfix +#![allow(unused_imports, dead_code)] + +mod a { + pub struct A; + pub struct B; +} + +mod b { + use crate::a::{A, B}; + pub struct Z; +} + +mod failing_first { + use crate::b::{A, Z}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod failing_last { + use crate::b::{Z, A}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod trailing_comma { + use crate::b::{Z, A,}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod multiline { + use crate::b::{ + Z, + A, + //~^ ERROR struct import `A` is private [E0603] + }; +} + +mod with_self { + use crate::b::{self, A}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod nested_group_multi { + use crate::{b::{A, Z}, a::B}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod nested_group_single { + use crate::{b::{A}, a::B}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod single_item { + use crate::b::{A}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod nested_single_in_single { + use crate::{b::{A}}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod pub_use_single { + pub use crate::b::{A}; + //~^ ERROR struct import `A` is private [E0603] +} + +mod with_attribute_single { + #[allow(unused_imports)] + use crate::b::{A}; + //~^ ERROR struct import `A` is private [E0603] +} + +fn main() {} diff --git a/tests/ui/imports/private-import-grouped-suggestion-rustfix.stderr b/tests/ui/imports/private-import-grouped-suggestion-rustfix.stderr new file mode 100644 index 0000000000000..3979acc5252d6 --- /dev/null +++ b/tests/ui/imports/private-import-grouped-suggestion-rustfix.stderr @@ -0,0 +1,246 @@ +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion-rustfix.rs:15:20 + | +LL | use crate::b::{A, Z}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion-rustfix.rs:10:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion-rustfix.rs:5:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL ~ use crate::a::A; +LL ~ use crate::b::{Z}; + | + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion-rustfix.rs:20:23 + | +LL | use crate::b::{Z, A}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion-rustfix.rs:10:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion-rustfix.rs:5:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL ~ use crate::a::A; +LL ~ use crate::b::{Z}; + | + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion-rustfix.rs:25:23 + | +LL | use crate::b::{Z, A,}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion-rustfix.rs:10:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion-rustfix.rs:5:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL ~ use crate::a::A; +LL ~ use crate::b::{Z,}; + | + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion-rustfix.rs:32:9 + | +LL | A, + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion-rustfix.rs:10:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion-rustfix.rs:5:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL ~ use crate::a::A; +LL ~ use crate::b::{ +LL ~ Z, + | + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion-rustfix.rs:38:26 + | +LL | use crate::b::{self, A}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion-rustfix.rs:10:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion-rustfix.rs:5:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL ~ use crate::a::A; +LL ~ use crate::b::{self}; + | + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion-rustfix.rs:43:21 + | +LL | use crate::{b::{A, Z}, a::B}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion-rustfix.rs:10:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion-rustfix.rs:5:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL ~ use crate::a::A; +LL ~ use crate::{b::{Z}, a::B}; + | + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion-rustfix.rs:48:21 + | +LL | use crate::{b::{A}, a::B}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion-rustfix.rs:10:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion-rustfix.rs:5:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL ~ use crate::a::A; +LL ~ use crate::{a::B}; + | + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion-rustfix.rs:53:20 + | +LL | use crate::b::{A}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion-rustfix.rs:10:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion-rustfix.rs:5:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL - use crate::b::{A}; +LL + use crate::a::A; + | + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion-rustfix.rs:58:21 + | +LL | use crate::{b::{A}}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion-rustfix.rs:10:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion-rustfix.rs:5:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL - use crate::{b::{A}}; +LL + use crate::a::A; + | + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion-rustfix.rs:63:24 + | +LL | pub use crate::b::{A}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion-rustfix.rs:10:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion-rustfix.rs:5:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL - pub use crate::b::{A}; +LL + pub use crate::a::A; + | + +error[E0603]: struct import `A` is private + --> $DIR/private-import-grouped-suggestion-rustfix.rs:69:20 + | +LL | use crate::b::{A}; + | ^ private struct import + | +note: the struct import `A` is defined here... + --> $DIR/private-import-grouped-suggestion-rustfix.rs:10:20 + | +LL | use crate::a::{A, B}; + | ^ +note: ...and refers to the struct `A` which is defined here + --> $DIR/private-import-grouped-suggestion-rustfix.rs:5:5 + | +LL | pub struct A; + | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL - use crate::b::{A}; +LL + use crate::a::A; + | + +error: aborting due to 11 previous errors + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/imports/private-import-grouped-suggestion.rs b/tests/ui/imports/private-import-grouped-suggestion.rs index 953bac1ecfca5..3fc030b1d7325 100644 --- a/tests/ui/imports/private-import-grouped-suggestion.rs +++ b/tests/ui/imports/private-import-grouped-suggestion.rs @@ -144,6 +144,11 @@ mod std_path { //~^ ERROR struct `Path` is private [E0603] } +mod std_multi { + use std::{fs::Path, io}; + //~^ ERROR struct `Path` is private [E0603] +} + macro_rules! define_use { () => { use crate::b::{A, Z}; diff --git a/tests/ui/imports/private-import-grouped-suggestion.stderr b/tests/ui/imports/private-import-grouped-suggestion.stderr index 1ad0918c9dc30..ae87823518f17 100644 --- a/tests/ui/imports/private-import-grouped-suggestion.stderr +++ b/tests/ui/imports/private-import-grouped-suggestion.stderr @@ -14,6 +14,11 @@ note: ...and refers to the struct `A` which is defined here | LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL ~ use crate::a::A; +LL ~ use crate::b::{Z}; + | error[E0603]: struct import `A` is private --> $DIR/private-import-grouped-suggestion.rs:17:23 @@ -31,6 +36,11 @@ note: ...and refers to the struct `A` which is defined here | LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL ~ use crate::a::A; +LL ~ use crate::b::{Z}; + | error[E0603]: struct import `A` is private --> $DIR/private-import-grouped-suggestion.rs:22:23 @@ -48,6 +58,11 @@ note: ...and refers to the struct `A` which is defined here | LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL ~ use crate::a::A; +LL ~ use crate::b::{Z, Z as Z2}; + | error[E0603]: struct import `A` is private --> $DIR/private-import-grouped-suggestion.rs:27:20 @@ -87,6 +102,11 @@ note: ...and refers to the struct `A` which is defined here | LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL ~ use crate::a::A; +LL ~ use crate::b::{B}; + | error[E0603]: struct import `B` is private --> $DIR/private-import-grouped-suggestion.rs:32:23 @@ -104,6 +124,11 @@ note: ...and refers to the struct `B` which is defined here | LL | pub struct B; | ^^^^^^^^^^^^^ you could import this directly +help: import `B` directly + | +LL ~ use crate::a::B; +LL ~ use crate::b::{A}; + | error[E0603]: struct import `A` is private --> $DIR/private-import-grouped-suggestion.rs:38:20 @@ -121,6 +146,11 @@ note: ...and refers to the struct `A` which is defined here | LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL ~ use crate::a::A; +LL ~ use crate::b::{Z, B}; + | error[E0603]: struct import `B` is private --> $DIR/private-import-grouped-suggestion.rs:38:26 @@ -138,6 +168,11 @@ note: ...and refers to the struct `B` which is defined here | LL | pub struct B; | ^^^^^^^^^^^^^ you could import this directly +help: import `B` directly + | +LL ~ use crate::a::B; +LL ~ use crate::b::{A, Z}; + | error[E0603]: struct import `A` is private --> $DIR/private-import-grouped-suggestion.rs:44:23 @@ -155,6 +190,11 @@ note: ...and refers to the struct `A` which is defined here | LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL ~ use crate::a::A; +LL ~ use crate::b::{Z,}; + | error[E0603]: struct import `A` is private --> $DIR/private-import-grouped-suggestion.rs:51:9 @@ -172,6 +212,12 @@ note: ...and refers to the struct `A` which is defined here | LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL ~ use crate::a::A; +LL ~ use crate::b::{ +LL ~ Z, + | error[E0603]: struct import `A` is private --> $DIR/private-import-grouped-suggestion.rs:57:20 @@ -223,6 +269,11 @@ note: ...and refers to the struct `A` which is defined here | LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL ~ use crate::a::A; +LL ~ use crate::{b::{Z}, a::B}; + | error[E0603]: struct import `A` is private --> $DIR/private-import-grouped-suggestion.rs:72:21 @@ -240,6 +291,11 @@ note: ...and refers to the struct `A` which is defined here | LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL ~ use crate::a::A; +LL ~ use crate::{a::B}; + | error[E0603]: struct import `A` is private --> $DIR/private-import-grouped-suggestion.rs:77:21 @@ -335,6 +391,11 @@ note: ...and refers to the struct `A` which is defined here | LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL ~ use crate::a::A; +LL ~ use crate::b::{self}; + | error[E0603]: struct import `A` is private --> $DIR/private-import-grouped-suggestion.rs:102:35 @@ -352,6 +413,11 @@ note: ...and refers to the struct `A` which is defined here | LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL ~ use crate::a::A; +LL ~ use crate::b::{Z}; + | error[E0603]: struct import `A` is private --> $DIR/private-import-grouped-suggestion.rs:107:29 @@ -369,6 +435,11 @@ note: ...and refers to the struct `A` which is defined here | LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL ~ use crate::a::A; +LL ~ use crate::b::{Z as 变量}; + | error[E0603]: struct import `A` is private --> $DIR/private-import-grouped-suggestion.rs:115:9 @@ -386,6 +457,12 @@ note: ...and refers to the struct `A` which is defined here | LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL ~ use crate::a::A; +LL ~ use crate::b::{ +LL ~ Z, + | error[E0603]: struct import `A` is private --> $DIR/private-import-grouped-suggestion.rs:121:20 @@ -403,6 +480,11 @@ note: ...and refers to the struct `A` which is defined here | LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL ~ use crate::a::A; +LL ~ use crate::b::{Z}; + | error[E0603]: struct import `A` is private --> $DIR/private-import-grouped-suggestion.rs:127:20 @@ -459,6 +541,11 @@ note: ...and refers to the struct `A` which is defined here | LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly +help: import `A` directly + | +LL ~ fn f() { use crate::a::A; +LL ~ use crate::b::{Z}; } + | error[E0603]: struct `Path` is private --> $DIR/private-import-grouped-suggestion.rs:143:19 @@ -474,117 +561,131 @@ LL - use std::{fs::Path}; LL + use std::path::Path; | +error[E0603]: struct `Path` is private + --> $DIR/private-import-grouped-suggestion.rs:148:19 + | +LL | use std::{fs::Path, io}; + | ^^^^ private struct + | +note: the struct `Path` is defined here + --> $SRC_DIR/std/src/fs.rs:LL:COL +help: import `Path` directly + | +LL ~ use std::path::Path; +LL ~ use std::{io}; + | + error[E0603]: module import `m` is private - --> $DIR/private-import-grouped-suggestion.rs:181:20 + --> $DIR/private-import-grouped-suggestion.rs:186:20 | LL | use crate::c::{m::*}; | ^ private module import | help: consider importing this module instead: x::m - --> $DIR/private-import-grouped-suggestion.rs:181:20 + --> $DIR/private-import-grouped-suggestion.rs:186:20 | LL | use crate::c::{m::*}; | ^ note: the module import `m` is defined here... - --> $DIR/private-import-grouped-suggestion.rs:176:9 + --> $DIR/private-import-grouped-suggestion.rs:181:9 | LL | use crate::x::m; | ^^^^^^^^^^^ note: ...and refers to the module `m` which is defined here - --> $DIR/private-import-grouped-suggestion.rs:170:5 + --> $DIR/private-import-grouped-suggestion.rs:175:5 | LL | pub mod m { | ^^^^^^^^^ you could import this directly error[E0603]: module import `m` is private - --> $DIR/private-import-grouped-suggestion.rs:186:20 + --> $DIR/private-import-grouped-suggestion.rs:191:20 | LL | use crate::c::{m::*, Other}; | ^ private module import | help: consider importing this module instead: x::m - --> $DIR/private-import-grouped-suggestion.rs:186:20 + --> $DIR/private-import-grouped-suggestion.rs:191:20 | LL | use crate::c::{m::*, Other}; | ^ note: the module import `m` is defined here... - --> $DIR/private-import-grouped-suggestion.rs:176:9 + --> $DIR/private-import-grouped-suggestion.rs:181:9 | LL | use crate::x::m; | ^^^^^^^^^^^ note: ...and refers to the module `m` which is defined here - --> $DIR/private-import-grouped-suggestion.rs:170:5 + --> $DIR/private-import-grouped-suggestion.rs:175:5 | LL | pub mod m { | ^^^^^^^^^ you could import this directly error[E0603]: module import `m` is private - --> $DIR/private-import-grouped-suggestion.rs:191:20 + --> $DIR/private-import-grouped-suggestion.rs:196:20 | LL | use crate::c::{m::Item}; | ^ private module import | help: consider importing this struct instead: x::m::Item - --> $DIR/private-import-grouped-suggestion.rs:191:20 + --> $DIR/private-import-grouped-suggestion.rs:196:20 | LL | use crate::c::{m::Item}; | ^^^^^^^ note: the module import `m` is defined here... - --> $DIR/private-import-grouped-suggestion.rs:176:9 + --> $DIR/private-import-grouped-suggestion.rs:181:9 | LL | use crate::x::m; | ^^^^^^^^^^^ note: ...and refers to the module `m` which is defined here - --> $DIR/private-import-grouped-suggestion.rs:170:5 + --> $DIR/private-import-grouped-suggestion.rs:175:5 | LL | pub mod m { | ^^^^^^^^^ you could import this directly error[E0603]: module import `m` is private - --> $DIR/private-import-grouped-suggestion.rs:196:20 + --> $DIR/private-import-grouped-suggestion.rs:201:20 | LL | use crate::c::{m::Item, Other}; | ^ private module import | help: consider importing this struct instead: x::m::Item - --> $DIR/private-import-grouped-suggestion.rs:196:20 + --> $DIR/private-import-grouped-suggestion.rs:201:20 | LL | use crate::c::{m::Item, Other}; | ^^^^^^^ note: the module import `m` is defined here... - --> $DIR/private-import-grouped-suggestion.rs:176:9 + --> $DIR/private-import-grouped-suggestion.rs:181:9 | LL | use crate::x::m; | ^^^^^^^^^^^ note: ...and refers to the module `m` which is defined here - --> $DIR/private-import-grouped-suggestion.rs:170:5 + --> $DIR/private-import-grouped-suggestion.rs:175:5 | LL | pub mod m { | ^^^^^^^^^ you could import this directly error[E0603]: module import `m` is private - --> $DIR/private-import-grouped-suggestion.rs:213:43 + --> $DIR/private-import-grouped-suggestion.rs:218:43 | LL | use crate::unexported::intermediate::{m::*}; | ^ private module import | note: the module import `m` is defined here... - --> $DIR/private-import-grouped-suggestion.rs:208:13 + --> $DIR/private-import-grouped-suggestion.rs:213:13 | LL | use super::hidden::m; | ^^^^^^^^^^^^^^^^ note: ...and refers to the module `m` which is defined here - --> $DIR/private-import-grouped-suggestion.rs:202:9 + --> $DIR/private-import-grouped-suggestion.rs:207:9 | LL | pub mod m { | ^^^^^^^^^ error[E0603]: struct import `A` is private - --> $DIR/private-import-grouped-suggestion.rs:149:24 + --> $DIR/private-import-grouped-suggestion.rs:154:24 | LL | macro_rules! define_use { LL | () => { @@ -606,7 +707,7 @@ LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly error[E0603]: struct import `A` is private - --> $DIR/private-import-grouped-suggestion.rs:160:24 + --> $DIR/private-import-grouped-suggestion.rs:165:24 | LL | macro_rules! define_use_single { LL | () => { @@ -627,6 +728,6 @@ note: ...and refers to the struct `A` which is defined here LL | pub struct A; | ^^^^^^^^^^^^^ you could import this directly -error: aborting due to 34 previous errors +error: aborting due to 35 previous errors For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/imports/private-import-nested-suggestion-156060.stderr b/tests/ui/imports/private-import-nested-suggestion-156060.stderr index 09d5391bd58df..62b8d0413903a 100644 --- a/tests/ui/imports/private-import-nested-suggestion-156060.stderr +++ b/tests/ui/imports/private-import-nested-suggestion-156060.stderr @@ -14,6 +14,11 @@ note: ...and refers to the struct `One` which is defined here | LL | pub struct One(); | ^^^^^^^^^^^^^^^^^ you could import this directly +help: import `One` directly + | +LL ~ use crate::one::One; +LL ~ use crate::two::{Two}; + | error: aborting due to 1 previous error diff --git a/tests/ui/imports/private-import-suggestion-path-156244.edition_2015.stderr b/tests/ui/imports/private-import-suggestion-path-156244.edition_2015.stderr index cf865e86f39b2..df1b6253d82b6 100644 --- a/tests/ui/imports/private-import-suggestion-path-156244.edition_2015.stderr +++ b/tests/ui/imports/private-import-suggestion-path-156244.edition_2015.stderr @@ -36,6 +36,11 @@ note: ...and refers to the struct `One` which is defined here | LL | pub struct One; | ^^^^^^^^^^^^^^^ you could import this directly +help: import `One` directly + | +LL ~ use crate::a::One; +LL ~ use crate::b::{Two}; + | error[E0603]: struct import `Two` is private --> $DIR/private-import-suggestion-path-156244.rs:35:25 @@ -53,6 +58,11 @@ note: ...and refers to the struct `Two` which is defined here | LL | pub struct Two; | ^^^^^^^^^^^^^^^ you could import this directly +help: import `Two` directly + | +LL ~ use crate::a::Two; +LL ~ use crate::b::{One}; + | error[E0603]: module import `inner` is private --> $DIR/private-import-suggestion-path-156244.rs:38:24 diff --git a/tests/ui/imports/private-import-suggestion-path-156244.edition_2018.stderr b/tests/ui/imports/private-import-suggestion-path-156244.edition_2018.stderr index 65bca594bf5ae..033ea42cf7b43 100644 --- a/tests/ui/imports/private-import-suggestion-path-156244.edition_2018.stderr +++ b/tests/ui/imports/private-import-suggestion-path-156244.edition_2018.stderr @@ -36,6 +36,11 @@ note: ...and refers to the struct `One` which is defined here | LL | pub struct One; | ^^^^^^^^^^^^^^^ you could import this directly +help: import `One` directly + | +LL ~ use crate::a::One; +LL ~ use crate::b::{Two}; + | error[E0603]: struct import `Two` is private --> $DIR/private-import-suggestion-path-156244.rs:35:25 @@ -53,6 +58,11 @@ note: ...and refers to the struct `Two` which is defined here | LL | pub struct Two; | ^^^^^^^^^^^^^^^ you could import this directly +help: import `Two` directly + | +LL ~ use crate::a::Two; +LL ~ use crate::b::{One}; + | error[E0603]: module import `inner` is private --> $DIR/private-import-suggestion-path-156244.rs:38:24