Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

On privacy error caused by private reexport, use spans to show the use chain #67951

Closed
wants to merge 1 commit into from
Closed
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
6 changes: 5 additions & 1 deletion src/librustc/hir/map/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,11 @@ impl DefPath {
let mut s = String::with_capacity(self.data.len() * 16);

for component in &self.data {
write!(s, "::{}[{}]", component.data.as_symbol(), component.disambiguator).unwrap();
if component.disambiguator == 0 {
write!(s, "::{}", component.data.as_symbol()).unwrap();
} else {
write!(s, "::{}[{}]", component.data.as_symbol(), component.disambiguator).unwrap();
}
}

s
Expand Down
116 changes: 106 additions & 10 deletions src/librustc_resolve/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use crate::lifetimes::{ElisionFailureInfo, LifetimeContext};
use crate::path_names_to_string;
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind};
use crate::{BindingError, CrateLint, HasGenericParams, LegacyScope, Module, ModuleOrUniformRoot};
use crate::{ModuleData, ModuleKind};
use crate::{NameBinding, NameBindingKind, PrivacyError, VisResolutionError};
use crate::{ParentScope, PathResult, ResolutionError, Resolver, Scope, ScopeSet, Segment};

Expand Down Expand Up @@ -419,8 +420,7 @@ impl<'a> Resolver<'a> {
self.session,
span,
E0128,
"type parameters with a default cannot use \
forward declared identifiers"
"type parameters with a default cannot use forward declared identifiers"
);
err.span_label(
span,
Expand Down Expand Up @@ -952,8 +952,7 @@ impl<'a> Resolver<'a> {
err.emit();
}

crate fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) {
let PrivacyError { ident, binding, .. } = *privacy_error;
crate fn report_privacy_error(&self, PrivacyError { ident, binding, .. }: &PrivacyError<'_>) {
let session = &self.session;
let mk_struct_span_error = |is_constructor| {
let mut descr = binding.res().descr().to_string();
Expand All @@ -966,13 +965,7 @@ impl<'a> Resolver<'a> {

let mut err =
struct_span_err!(session, ident.span, E0603, "{} `{}` is private", descr, ident);

err.span_label(ident.span, &format!("this {} is private", descr));
err.span_note(
session.source_map().def_span(binding.span),
&format!("the {} `{}` is defined here", descr, ident),
);

err
};

Expand All @@ -997,6 +990,109 @@ impl<'a> Resolver<'a> {
mk_struct_span_error(false)
};

// Display the chain of re-exports through to the original def for cases where the
// `use` is private but the def is public.
let mut imported = false;
let mut binding = *binding;
loop {
let binding_span = session.source_map().def_span(binding.span);
match binding.kind {
NameBindingKind::Res(res, _is_macro_export) => {
match (res, imported, binding.vis) {
(Res::Def(_, def_id), true, ty::Visibility::Public) => {
// FIXME: we should verify that this def is actually
// reachable from the user's crate, as the parent modules
// of this ADT might be private.
if def_id.is_local() {
err.span_help(
binding_span,
&format!(
"consider importing {} `{}` directly",
res.descr(),
self.definitions
.def_path(def_id.index)
.to_string_no_crate(),
),
);
} else {
err.span_help(
binding_span,
&format!(
"consider importing {} `{}` directly",
res.descr(),
ident.name
),
);
}
}
(Res::Def(_, def_id), true, _) if def_id.is_local() => {
err.span_help(
binding_span,
&format!("consider making {} `{}` public", res.descr(), ident.name),
);
}
_ => {
err.span_note(
binding_span,
&format!(
"the {}{} `{}` is defined here",
if imported { "re-exported " } else { "" },
res.descr(),
ident.name
),
);
}
}
break;
}
NameBindingKind::Module(ModuleData {
kind: ModuleKind::Def(DefKind::Mod, def_id, _),
..
}) if def_id.index == CRATE_DEF_INDEX && def_id.krate != LOCAL_CRATE => {
// Do not point at `extern crate foo;` twice.
break;
}
NameBindingKind::Module(ModuleData {
kind: ModuleKind::Def(kind, def_id, _),
..
}) => {
err.span_note(
binding_span,
&format!(
"the {}{} `{}` is defined here",
if imported { "re-exported " } else { "" },
kind.descr(*def_id),
ident.name,
),
);
break;
}
NameBindingKind::Module(_) => break,
NameBindingKind::Import { binding: inner_binding, .. } => {
err.span_note(
binding_span,
&format!(
"{} {} re-export of `{}`{}",
if imported { "...through this" } else { "the used" },
if binding.vis == ty::Visibility::Public {
"public"
} else {
"restricted"
},
ident.name,
if let NameBindingKind::Import { .. } = inner_binding.kind {
"..."
} else {
""
},
),
);
binding = inner_binding;
imported = true;
}
}
}

err.emit();
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/extern/extern-crate-visibility.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error[E0603]: crate import `core` is private
LL | use foo::core::cell;
| ^^^^ this crate import is private
|
note: the crate import `core` is defined here
note: the used restricted re-export of `core`
--> $DIR/extern-crate-visibility.rs:2:5
|
LL | extern crate core;
Expand All @@ -16,7 +16,7 @@ error[E0603]: crate import `core` is private
LL | foo::core::cell::Cell::new(0);
| ^^^^ this crate import is private
|
note: the crate import `core` is defined here
note: the used restricted re-export of `core`
--> $DIR/extern-crate-visibility.rs:2:5
|
LL | extern crate core;
Expand Down
3 changes: 2 additions & 1 deletion src/test/ui/import.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ error[E0603]: unresolved item import `foo` is private
LL | zed::foo();
| ^^^ this unresolved item import is private
|
note: the unresolved item import `foo` is defined here
note: the used restricted re-export of `foo`
--> $DIR/import.rs:10:9
|
LL | use foo;
| ^^^
= note: the re-exported unresolved item `foo` is defined here

error: aborting due to 3 previous errors

Expand Down
17 changes: 16 additions & 1 deletion src/test/ui/imports/issue-55884-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,26 @@ error[E0603]: struct import `ParseOptions` is private
LL | pub use parser::ParseOptions;
| ^^^^^^^^^^^^ this struct import is private
|
note: the struct import `ParseOptions` is defined here
note: the used restricted re-export of `ParseOptions`...
--> $DIR/issue-55884-2.rs:9:9
|
LL | use ParseOptions;
| ^^^^^^^^^^^^
note: ...through this public re-export of `ParseOptions`...
--> $DIR/issue-55884-2.rs:12:9
|
LL | pub use parser::ParseOptions;
| ^^^^^^^^^^^^^^^^^^^^
note: ...through this public re-export of `ParseOptions`
--> $DIR/issue-55884-2.rs:6:13
|
LL | pub use options::*;
| ^^^^^^^^^^
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this clarification in particular will be incredibly useful when trying to understand these errors.

help: consider importing struct `::options::ParseOptions` directly
--> $DIR/issue-55884-2.rs:2:5
|
LL | pub struct ParseOptions {}
| ^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

Expand Down
14 changes: 12 additions & 2 deletions src/test/ui/imports/reexports.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,33 @@ error[E0603]: module import `foo` is private
LL | use b::a::foo::S;
| ^^^ this module import is private
|
note: the module import `foo` is defined here
note: the used restricted re-export of `foo`
--> $DIR/reexports.rs:21:17
|
LL | pub use super::foo; // This is OK since the value `foo` is visible enough.
| ^^^^^^^^^^
note: the re-exported module `foo` is defined here
--> $DIR/reexports.rs:16:5
|
LL | mod foo {
| ^^^^^^^

error[E0603]: module import `foo` is private
--> $DIR/reexports.rs:34:15
|
LL | use b::b::foo::S as T;
| ^^^ this module import is private
|
note: the module import `foo` is defined here
note: the used restricted re-export of `foo`
--> $DIR/reexports.rs:26:17
|
LL | pub use super::*; // This is also OK since the value `foo` is visible enough.
| ^^^^^^^^
note: the re-exported module `foo` is defined here
--> $DIR/reexports.rs:16:5
|
LL | mod foo {
| ^^^^^^^

warning: glob import doesn't reexport anything because no candidate is public enough
--> $DIR/reexports.rs:9:17
Expand Down
7 changes: 6 additions & 1 deletion src/test/ui/privacy/privacy2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,16 @@ error[E0603]: function import `foo` is private
LL | use bar::glob::foo;
| ^^^ this function import is private
|
note: the function import `foo` is defined here
note: the used restricted re-export of `foo`
--> $DIR/privacy2.rs:10:13
|
LL | use foo;
| ^^^
help: consider importing function `::foo` directly
--> $DIR/privacy2.rs:14:1
|
LL | pub fn foo() {}
| ^^^^^^^^^^^^

error: requires `sized` lang_item

Expand Down
Loading