Skip to content

Commit

Permalink
resolve: Remove visibility hacks for enum variants and trait items
Browse files Browse the repository at this point in the history
Special treatment like this was necessary before `pub(restricted)` had been implemented and only two visibilities existed - `pub` and non-`pub`.
Now it's no longer necessary and the desired behavior follows from `pub(restricted)`-style visibilities naturally assigned to enum variants and trait items.
  • Loading branch information
petrochenkov committed Feb 10, 2021
1 parent b4b6b62 commit 8e74842
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 137 deletions.
5 changes: 1 addition & 4 deletions compiler/rustc_resolve/src/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1398,10 +1398,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
let parent = self.parent_scope.module;
let expansion = self.parent_scope.expansion;
let res = Res::Def(def_kind, def_id);
// FIXME: For historical reasons the binding visibility is set to public,
// use actual visibility here instead, using enum variants as an example.
let vis_hack = ty::Visibility::Public;
self.r.define(parent, item.ident, ns, (res, vis_hack, item.span, expansion));
self.r.define(parent, item.ident, ns, (res, vis, item.span, expansion));
}

visit::walk_assoc_item(self, item, ctxt);
Expand Down
81 changes: 7 additions & 74 deletions compiler/rustc_resolve/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@ use rustc_errors::{pluralize, struct_span_err, Applicability};
use rustc_hir::def::{self, PartialRes};
use rustc_hir::def_id::DefId;
use rustc_middle::hir::exports::Export;
use rustc_middle::span_bug;
use rustc_middle::ty;
use rustc_middle::{bug, span_bug};
use rustc_session::lint::builtin::{PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS};
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_session::DiagnosticMessageId;
use rustc_span::hygiene::ExpnId;
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::symbol::{kw, Ident, Symbol};
Expand Down Expand Up @@ -456,13 +455,13 @@ impl<'a> Resolver<'a> {
binding: &'a NameBinding<'a>,
import: &'a Import<'a>,
) -> &'a NameBinding<'a> {
let vis = if binding.pseudo_vis().is_at_least(import.vis.get(), self) ||
let vis = if binding.vis.is_at_least(import.vis.get(), self) ||
// cf. `PUB_USE_OF_PRIVATE_EXTERN_CRATE`
!import.is_glob() && binding.is_extern_crate()
{
import.vis.get()
} else {
binding.pseudo_vis()
binding.vis
};

if let ImportKind::Glob { ref max_vis, .. } = import.kind {
Expand Down Expand Up @@ -1178,7 +1177,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
self.r.per_ns(|this, ns| {
if let Ok(binding) = source_bindings[ns].get() {
let vis = import.vis.get();
if !binding.pseudo_vis().is_at_least(vis, &*this) {
if !binding.vis.is_at_least(vis, &*this) {
reexport_error = Some((ns, binding));
} else {
any_successful_reexport = true;
Expand Down Expand Up @@ -1362,7 +1361,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
Some(None) => import.parent_scope.module,
None => continue,
};
if self.r.is_accessible_from(binding.pseudo_vis(), scope) {
if self.r.is_accessible_from(binding.vis, scope) {
let imported_binding = self.r.import(binding, import);
let _ = self.r.try_define(import.parent_scope.module, key, imported_binding);
}
Expand All @@ -1380,9 +1379,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> {

let mut reexports = Vec::new();

module.for_each_child(self.r, |this, ident, ns, binding| {
// Filter away ambiguous imports and anything that has def-site
// hygiene.
module.for_each_child(self.r, |this, ident, _, binding| {
// Filter away ambiguous imports and anything that has def-site hygiene.
// FIXME: Implement actual cross-crate hygiene.
let is_good_import =
binding.is_import() && !binding.is_ambiguity() && !ident.span.from_expansion();
Expand All @@ -1392,71 +1390,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
reexports.push(Export { ident, res, span: binding.span, vis: binding.vis });
}
}

if let NameBindingKind::Import { binding: orig_binding, import, .. } = binding.kind {
if ns == TypeNS
&& orig_binding.is_variant()
&& !orig_binding.vis.is_at_least(binding.vis, &*this)
{
let msg = match import.kind {
ImportKind::Single { .. } => {
format!("variant `{}` is private and cannot be re-exported", ident)
}
ImportKind::Glob { .. } => {
let msg = "enum is private and its variants \
cannot be re-exported"
.to_owned();
let error_id = (
DiagnosticMessageId::ErrorId(0), // no code?!
Some(binding.span),
msg.clone(),
);
let fresh =
this.session.one_time_diagnostics.borrow_mut().insert(error_id);
if !fresh {
return;
}
msg
}
ref s => bug!("unexpected import kind {:?}", s),
};
let mut err = this.session.struct_span_err(binding.span, &msg);

let imported_module = match import.imported_module.get() {
Some(ModuleOrUniformRoot::Module(module)) => module,
_ => bug!("module should exist"),
};
let parent_module = imported_module.parent.expect("parent should exist");
let resolutions = this.resolutions(parent_module).borrow();
let enum_path_segment_index = import.module_path.len() - 1;
let enum_ident = import.module_path[enum_path_segment_index].ident;

let key = this.new_key(enum_ident, TypeNS);
let enum_resolution = resolutions.get(&key).expect("resolution should exist");
let enum_span =
enum_resolution.borrow().binding.expect("binding should exist").span;
let enum_def_span = this.session.source_map().guess_head_span(enum_span);
let enum_def_snippet = this
.session
.source_map()
.span_to_snippet(enum_def_span)
.expect("snippet should exist");
// potentially need to strip extant `crate`/`pub(path)` for suggestion
let after_vis_index = enum_def_snippet
.find("enum")
.expect("`enum` keyword should exist in snippet");
let suggestion = format!("pub {}", &enum_def_snippet[after_vis_index..]);

this.session.diag_span_suggestion_once(
&mut err,
DiagnosticMessageId::ErrorId(0),
enum_def_span,
"consider making the enum public",
suggestion,
);
err.emit();
}
}
});

if !reexports.is_empty() {
Expand Down
21 changes: 3 additions & 18 deletions compiler/rustc_resolve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -750,27 +750,12 @@ impl<'a> NameBinding<'a> {
fn is_possibly_imported_variant(&self) -> bool {
match self.kind {
NameBindingKind::Import { binding, .. } => binding.is_possibly_imported_variant(),
_ => self.is_variant(),
}
}

// We sometimes need to treat variants as `pub` for backwards compatibility.
fn pseudo_vis(&self) -> ty::Visibility {
if self.is_variant() && self.res().def_id().is_local() {
ty::Visibility::Public
} else {
self.vis
}
}

fn is_variant(&self) -> bool {
matches!(
self.kind,
NameBindingKind::Res(
Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), _),
_,
)
)
) => true,
NameBindingKind::Res(..) | NameBindingKind::Module(..) => false,
}
}

fn is_extern_crate(&self) -> bool {
Expand Down
11 changes: 6 additions & 5 deletions src/test/ui/privacy/issue-46209-private-enum-variant-reexport.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
#![feature(crate_visibility_modifier)]

#[deny(unused_imports)]
mod rank {
pub use self::Professor::*;
//~^ ERROR enum is private and its variants cannot be re-exported
//~^ ERROR glob import doesn't reexport anything
pub use self::Lieutenant::{JuniorGrade, Full};
//~^ ERROR variant `JuniorGrade` is private and cannot be re-exported
//~| ERROR variant `Full` is private and cannot be re-exported
//~^ ERROR `JuniorGrade` is private, and cannot be re-exported
//~| ERROR `Full` is private, and cannot be re-exported
pub use self::PettyOfficer::*;
//~^ ERROR enum is private and its variants cannot be re-exported
//~^ ERROR glob import doesn't reexport anything
pub use self::Crewman::*;
//~^ ERROR enum is private and its variants cannot be re-exported
//~^ ERROR glob import doesn't reexport anything

enum Professor {
Adjunct,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,44 +1,51 @@
error: variant `JuniorGrade` is private and cannot be re-exported
--> $DIR/issue-46209-private-enum-variant-reexport.rs:6:32
error[E0364]: `JuniorGrade` is private, and cannot be re-exported
--> $DIR/issue-46209-private-enum-variant-reexport.rs:7:32
|
LL | pub use self::Lieutenant::{JuniorGrade, Full};
| ^^^^^^^^^^^
|
note: consider marking `JuniorGrade` as `pub` in the imported module
--> $DIR/issue-46209-private-enum-variant-reexport.rs:7:32
|
LL | pub use self::Lieutenant::{JuniorGrade, Full};
| ^^^^^^^^^^^
...
LL | enum Lieutenant {
| --------------- help: consider making the enum public: `pub enum Lieutenant`

error: variant `Full` is private and cannot be re-exported
--> $DIR/issue-46209-private-enum-variant-reexport.rs:6:45
error[E0364]: `Full` is private, and cannot be re-exported
--> $DIR/issue-46209-private-enum-variant-reexport.rs:7:45
|
LL | pub use self::Lieutenant::{JuniorGrade, Full};
| ^^^^
|
note: consider marking `Full` as `pub` in the imported module
--> $DIR/issue-46209-private-enum-variant-reexport.rs:7:45
|
LL | pub use self::Lieutenant::{JuniorGrade, Full};
| ^^^^

error: enum is private and its variants cannot be re-exported
--> $DIR/issue-46209-private-enum-variant-reexport.rs:4:13
error: glob import doesn't reexport anything because no candidate is public enough
--> $DIR/issue-46209-private-enum-variant-reexport.rs:5:13
|
LL | pub use self::Professor::*;
| ^^^^^^^^^^^^^^^^^^
...
LL | enum Professor {
| -------------- help: consider making the enum public: `pub enum Professor`
|
note: the lint level is defined here
--> $DIR/issue-46209-private-enum-variant-reexport.rs:3:8
|
LL | #[deny(unused_imports)]
| ^^^^^^^^^^^^^^

error: enum is private and its variants cannot be re-exported
--> $DIR/issue-46209-private-enum-variant-reexport.rs:9:13
error: glob import doesn't reexport anything because no candidate is public enough
--> $DIR/issue-46209-private-enum-variant-reexport.rs:10:13
|
LL | pub use self::PettyOfficer::*;
| ^^^^^^^^^^^^^^^^^^^^^
...
LL | pub(in rank) enum PettyOfficer {
| ------------------------------ help: consider making the enum public: `pub enum PettyOfficer`

error: enum is private and its variants cannot be re-exported
--> $DIR/issue-46209-private-enum-variant-reexport.rs:11:13
error: glob import doesn't reexport anything because no candidate is public enough
--> $DIR/issue-46209-private-enum-variant-reexport.rs:12:13
|
LL | pub use self::Crewman::*;
| ^^^^^^^^^^^^^^^^
...
LL | crate enum Crewman {
| ------------------ help: consider making the enum public: `pub enum Crewman`

error: aborting due to 5 previous errors

For more information about this error, try `rustc --explain E0364`.
9 changes: 5 additions & 4 deletions src/test/ui/privacy/private-variant-reexport.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
mod m1 {
pub use ::E::V; //~ ERROR variant `V` is private and cannot be re-exported
pub use ::E::V; //~ ERROR `V` is private, and cannot be re-exported
}

mod m2 {
pub use ::E::{V}; //~ ERROR variant `V` is private and cannot be re-exported
pub use ::E::{V}; //~ ERROR `V` is private, and cannot be re-exported
}

mod m3 {
pub use ::E::V::{self}; //~ ERROR variant `V` is private and cannot be re-exported
pub use ::E::V::{self}; //~ ERROR `V` is private, and cannot be re-exported
}

#[deny(unused_imports)]
mod m4 {
pub use ::E::*; //~ ERROR enum is private and its variants cannot be re-exported
pub use ::E::*; //~ ERROR glob import doesn't reexport anything
}

enum E { V }
Expand Down
37 changes: 28 additions & 9 deletions src/test/ui/privacy/private-variant-reexport.stderr
Original file line number Diff line number Diff line change
@@ -1,29 +1,48 @@
error: variant `V` is private and cannot be re-exported
error[E0364]: `V` is private, and cannot be re-exported
--> $DIR/private-variant-reexport.rs:2:13
|
LL | pub use ::E::V;
| ^^^^^^
|
note: consider marking `V` as `pub` in the imported module
--> $DIR/private-variant-reexport.rs:2:13
|
LL | pub use ::E::V;
| ^^^^^^
...
LL | enum E { V }
| ------ help: consider making the enum public: `pub enum E`

error: variant `V` is private and cannot be re-exported
error[E0364]: `V` is private, and cannot be re-exported
--> $DIR/private-variant-reexport.rs:6:19
|
LL | pub use ::E::{V};
| ^
|
note: consider marking `V` as `pub` in the imported module
--> $DIR/private-variant-reexport.rs:6:19
|
LL | pub use ::E::{V};
| ^

error: variant `V` is private and cannot be re-exported
error[E0365]: `V` is private, and cannot be re-exported
--> $DIR/private-variant-reexport.rs:10:22
|
LL | pub use ::E::V::{self};
| ^^^^
| ^^^^ re-export of private `V`
|
= note: consider declaring type or module `V` with `pub`

error: enum is private and its variants cannot be re-exported
--> $DIR/private-variant-reexport.rs:14:13
error: glob import doesn't reexport anything because no candidate is public enough
--> $DIR/private-variant-reexport.rs:15:13
|
LL | pub use ::E::*;
| ^^^^^^
|
note: the lint level is defined here
--> $DIR/private-variant-reexport.rs:13:8
|
LL | #[deny(unused_imports)]
| ^^^^^^^^^^^^^^

error: aborting due to 4 previous errors

Some errors have detailed explanations: E0364, E0365.
For more information about an error, try `rustc --explain E0364`.
2 changes: 1 addition & 1 deletion src/test/ui/variants/variant-namespacing.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// aux-build:variant-namespacing.rs

enum E {
pub enum E {
Struct { a: u8 },
Tuple(u8),
Unit,
Expand Down

0 comments on commit 8e74842

Please sign in to comment.