Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 89 additions & 10 deletions compiler/rustc_resolve/src/error_helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2472,17 +2472,96 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {

match binding.kind {
DeclKind::Import { source_decl, import, .. } => {
// Don't include `{{root}}` in suggestions - it's an internal symbol
// that should never be shown to users.
let path = import
.module_path
.iter()
.filter(|seg| seg.ident.name != kw::PathRoot)
.map(|seg| seg.ident.clone())
.chain(std::iter::once(ident))
.collect::<Vec<_>>();
let through_reexport = !matches!(source_decl.kind, DeclKind::Def(_));
sugg_paths.push((path, through_reexport));
let uses_relative_path = import
.module_path
.first()
.is_some_and(|seg| matches!(seg.ident.name, kw::SelfLower | kw::Super));
let res_def_id = res.opt_def_id();
let path = if uses_relative_path {
// A path recovered from `self`/`super` is only useful if both the
// target and every module segment can be named from the failing use site.
let module_path = if let Some(ModuleOrUniformRoot::Module(module)) =
import.imported_module.get()
&& module.is_local()
&& let Some(module_path) = self.module_path_names(module)
&& let Some(mut def_id) = module.opt_def_id()
&& res_def_id.is_none_or(|def_id| {
self.is_accessible_from(
self.tcx.visibility(def_id),
parent_scope.module,
)
}) {
// `module_path_names` tells us the resolved module's canonical path.
// Before suggesting that path from the failing use site, make sure
// every segment in it can actually be named from there.
let mut visible_from_use_site = true;
while let Some(parent) = self.tcx.opt_parent(def_id) {
if !self.is_accessible_from(
self.tcx.visibility(def_id),
parent_scope.module,
) {
visible_from_use_site = false;
break;
}
if parent.is_top_level_module() {
break;
}
def_id = parent;
}
if visible_from_use_site { Some(module_path) } else { None }
} else {
None
};

if let Some(module_path) = module_path {
// `import.module_path` is relative to the import's module, not to the
// failing use site.
let mut suggestion = ImportSuggestion {
did: res_def_id,
descr: "",
path: Path {
span: ident.span,
segments: module_path
.into_iter()
.chain(std::iter::once(ident.name))
.map(|name| {
ast::PathSegment::from_ident(Ident::with_dummy_span(
name,
))
})
.collect(),
tokens: None,
},
accessible: true,
doc_visible: true,
via_import: false,
note: None,
is_stable: true,
};
// Reuse the existing relative shortening policy. The fields above
// other than `did` and `path` are not used by this helper.
self.shorten_candidate_path(&mut suggestion, parent_scope.module);
Some(suggestion.path.segments.iter().map(|seg| seg.ident).collect())
} else {
None
}
} else {
// Don't include `{{root}}` in suggestions - it's an internal symbol
// that should never be shown to users.
Some(
import
.module_path
.iter()
.filter(|seg| seg.ident.name != kw::PathRoot)
.map(|seg| seg.ident.clone())
.chain(std::iter::once(ident))
.collect::<Vec<_>>(),
)
};
if let Some(path) = path {
sugg_paths.push((path, through_reexport));
}
}
DeclKind::Def(_) => {}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,66 @@ LL - use crate::rename::inner::Item as Item1;
LL + use outer::actual::Item as Item1;
|

error: aborting due to 4 previous errors
error[E0603]: struct import `Hi` is private
--> $DIR/private-import-suggestion-path-156244.rs:51:14
|
LL | use testing::Hi;
| ^^ private struct import
|
note: the struct import `Hi` is defined here...
--> $DIR/private-import-suggestion-path-156244.rs:48:9
|
LL | use super::public::Hi;
| ^^^^^^^^^^^^^^^^^
note: ...and refers to the struct `Hi` which is defined here
--> $DIR/private-import-suggestion-path-156244.rs:44:5
|
LL | pub struct Hi;
| ^^^^^^^^^^^^^^ you could import this directly
help: import `Hi` directly
|
LL - use testing::Hi;
LL + use public::Hi;
|

error[E0603]: struct import `Hi` is private
--> $DIR/private-import-suggestion-path-156244.rs:67:37
|
LL | use inaccessible_ancestor::testing::Hi;
| ^^ private struct import
|
note: the struct import `Hi` is defined here...
--> $DIR/private-import-suggestion-path-156244.rs:63:13
|
LL | use super::private::public::Hi;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...and refers to the struct `Hi` which is defined here
--> $DIR/private-import-suggestion-path-156244.rs:58:13
|
LL | pub struct Hi;
| ^^^^^^^^^^^^^^ you could import this directly

error[E0603]: module import `mem` is private
--> $DIR/private-import-suggestion-path-156244.rs:77:21
|
LL | use external_alias::mem;
| ^^^ private module import
|
note: the module import `mem` is defined here...
--> $DIR/private-import-suggestion-path-156244.rs:74:9
|
LL | use super::s::mem;
| ^^^^^^^^^^^^^
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` directly
|
LL - use external_alias::mem;
LL + use core::mem;
|

error: aborting due to 7 previous errors

For more information about this error, try `rustc --explain E0603`.
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,66 @@ LL - use crate::rename::inner::Item as Item1;
LL + use crate::outer::actual::Item as Item1;
|

error: aborting due to 4 previous errors
error[E0603]: struct import `Hi` is private
--> $DIR/private-import-suggestion-path-156244.rs:51:14
|
LL | use testing::Hi;
| ^^ private struct import
|
note: the struct import `Hi` is defined here...
--> $DIR/private-import-suggestion-path-156244.rs:48:9
|
LL | use super::public::Hi;
| ^^^^^^^^^^^^^^^^^
note: ...and refers to the struct `Hi` which is defined here
--> $DIR/private-import-suggestion-path-156244.rs:44:5
|
LL | pub struct Hi;
| ^^^^^^^^^^^^^^ you could import this directly
help: import `Hi` directly
|
LL - use testing::Hi;
LL + use public::Hi;
|

error[E0603]: struct import `Hi` is private
--> $DIR/private-import-suggestion-path-156244.rs:67:37
|
LL | use inaccessible_ancestor::testing::Hi;
| ^^ private struct import
|
note: the struct import `Hi` is defined here...
--> $DIR/private-import-suggestion-path-156244.rs:63:13
|
LL | use super::private::public::Hi;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...and refers to the struct `Hi` which is defined here
--> $DIR/private-import-suggestion-path-156244.rs:58:13
|
LL | pub struct Hi;
| ^^^^^^^^^^^^^^ you could import this directly

error[E0603]: module import `mem` is private
--> $DIR/private-import-suggestion-path-156244.rs:77:21
|
LL | use external_alias::mem;
| ^^^ private module import
|
note: the module import `mem` is defined here...
--> $DIR/private-import-suggestion-path-156244.rs:74:9
|
LL | use super::s::mem;
| ^^^^^^^^^^^^^
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` directly
|
LL - use external_alias::mem;
LL + use core::mem;
|

error: aborting due to 7 previous errors

For more information about this error, try `rustc --explain E0603`.
38 changes: 38 additions & 0 deletions tests/ui/imports/private-import-suggestion-path-156244.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,42 @@ mod bad {
//~^ ERROR module import `inner` is private [E0603]
}

// Regression test for https://github.com/rust-lang/rust/issues/157455: no root `super`.
mod public {
pub struct Hi;
}

mod testing {
use super::public::Hi;
}

use testing::Hi;
//~^ ERROR struct import `Hi` is private [E0603]

// Regression test for https://github.com/rust-lang/rust/issues/157455: no private ancestors.
mod inaccessible_ancestor {
mod private {
pub mod public {
pub struct Hi;
}
}

pub mod testing {
use super::private::public::Hi;
}
}

use inaccessible_ancestor::testing::Hi;
//~^ ERROR struct import `Hi` is private [E0603]

// Regression test for https://github.com/rust-lang/rust/issues/157455: no external alias rewrite.
use std as s;

mod external_alias {
use super::s::mem;
}

use external_alias::mem;
//~^ ERROR module import `mem` is private [E0603]

fn main() {}
Loading