Skip to content

Commit 8f359d5

Browse files
committed
Prohibit public glob reexports of private variants
1 parent 187c89a commit 8f359d5

File tree

3 files changed

+57
-10
lines changed

3 files changed

+57
-10
lines changed

src/librustc_resolve/lib.rs

-5
Original file line numberDiff line numberDiff line change
@@ -1012,11 +1012,6 @@ impl NameBinding {
10121012
self.defined_with(DefModifiers::PUBLIC)
10131013
}
10141014

1015-
fn is_reexportable(&self) -> bool {
1016-
self.defined_with(DefModifiers::PUBLIC) &&
1017-
!self.defined_with(DefModifiers::PRIVATE_VARIANT)
1018-
}
1019-
10201015
fn def_and_lp(&self) -> (Def, LastPrivate) {
10211016
let def = self.def().unwrap();
10221017
(def, LastMod(if self.is_public() { AllPublic } else { DependsOn(def.def_id()) }))

src/librustc_resolve/resolve_imports.rs

+37-3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use {resolve_error, ResolutionError};
2525

2626
use build_reduced_graph;
2727

28+
use rustc::lint;
2829
use rustc::middle::def::*;
2930
use rustc::middle::def_id::DefId;
3031
use rustc::middle::privacy::*;
@@ -443,7 +444,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
443444
debug!("(resolving single import) found value binding");
444445
value_result = BoundResult(target_module.clone(),
445446
child_name_bindings.value_ns.clone());
446-
if directive.is_public && !child_name_bindings.value_ns.is_reexportable() {
447+
if directive.is_public && !child_name_bindings.value_ns.is_public() {
447448
let msg = format!("`{}` is private, and cannot be reexported", source);
448449
let note_msg = format!("Consider marking `{}` as `pub` in the imported \
449450
module",
@@ -452,19 +453,40 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
452453
self.resolver.session.span_note(directive.span, &note_msg);
453454
pub_err = true;
454455
}
456+
if directive.is_public && child_name_bindings.value_ns.
457+
defined_with(DefModifiers::PRIVATE_VARIANT) {
458+
let msg = format!("variant `{}` is private, and cannot be reexported ( \
459+
error E0364), consider declaring its enum as `pub`",
460+
source);
461+
self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
462+
directive.id,
463+
directive.span,
464+
msg);
465+
pub_err = true;
466+
}
455467
}
456468
if child_name_bindings.type_ns.defined() {
457469
debug!("(resolving single import) found type binding");
458470
type_result = BoundResult(target_module.clone(),
459471
child_name_bindings.type_ns.clone());
460472
if !pub_err && directive.is_public &&
461-
!child_name_bindings.type_ns.is_reexportable() {
473+
!child_name_bindings.type_ns.is_public() {
462474
let msg = format!("`{}` is private, and cannot be reexported", source);
463475
let note_msg = format!("Consider declaring module `{}` as a `pub mod`",
464476
source);
465477
span_err!(self.resolver.session, directive.span, E0365, "{}", &msg);
466478
self.resolver.session.span_note(directive.span, &note_msg);
467479
}
480+
if !pub_err && directive.is_public && child_name_bindings.type_ns.
481+
defined_with(DefModifiers::PRIVATE_VARIANT) {
482+
let msg = format!("variant `{}` is private, and cannot be reexported ( \
483+
error E0365), consider declaring its enum as `pub`",
484+
source);
485+
self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
486+
directive.id,
487+
directive.span,
488+
msg);
489+
}
468490
}
469491
}
470492
}
@@ -842,10 +864,22 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
842864
module_to_string(module_));
843865

844866
// Merge the child item into the import resolution.
867+
// pub_err makes sure we don't give the same error twice.
868+
let mut pub_err = false;
845869
{
846870
let mut merge_child_item = |namespace| {
847-
let modifier = DefModifiers::IMPORTABLE | DefModifiers::PUBLIC;
871+
if !pub_err && is_public &&
872+
name_bindings[namespace].defined_with(DefModifiers::PRIVATE_VARIANT) {
873+
let msg = format!("variant `{}` is private, and cannot be reexported (error \
874+
E0364), consider declaring its enum as `pub`", name);
875+
self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
876+
import_directive.id,
877+
import_directive.span,
878+
msg);
879+
pub_err = true;
880+
}
848881

882+
let modifier = DefModifiers::IMPORTABLE | DefModifiers::PUBLIC;
849883
if name_bindings[namespace].defined_with(modifier) {
850884
let namespace_name = match namespace {
851885
TypeNS => "type",

src/test/compile-fail/private-variant-reexport.rs

+20-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,26 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
pub use E::V; //~ERROR `V` is private, and cannot be reexported
11+
#![feature(rustc_attrs)]
12+
#![allow(dead_code)]
13+
14+
mod m1 {
15+
pub use ::E::V; //~ WARN variant `V` is private, and cannot be reexported
16+
}
17+
18+
mod m2 {
19+
pub use ::E::{V}; //~ WARN variant `V` is private, and cannot be reexported
20+
}
21+
22+
mod m3 {
23+
pub use ::E::V::{self}; //~ WARN variant `V` is private, and cannot be reexported
24+
}
25+
26+
mod m4 {
27+
pub use ::E::*; //~ WARN variant `V` is private, and cannot be reexported
28+
}
1229

1330
enum E { V }
1431

15-
fn main() {}
32+
#[rustc_error]
33+
fn main() {} //~ ERROR compilation successful

0 commit comments

Comments
 (0)