Skip to content

Commit

Permalink
Prohibit public glob reexports of private variants
Browse files Browse the repository at this point in the history
  • Loading branch information
petrochenkov committed Dec 18, 2015
1 parent 187c89a commit 8f359d5
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 10 deletions.
5 changes: 0 additions & 5 deletions src/librustc_resolve/lib.rs
Expand Up @@ -1012,11 +1012,6 @@ impl NameBinding {
self.defined_with(DefModifiers::PUBLIC)
}

fn is_reexportable(&self) -> bool {
self.defined_with(DefModifiers::PUBLIC) &&
!self.defined_with(DefModifiers::PRIVATE_VARIANT)
}

fn def_and_lp(&self) -> (Def, LastPrivate) {
let def = self.def().unwrap();
(def, LastMod(if self.is_public() { AllPublic } else { DependsOn(def.def_id()) }))
Expand Down
40 changes: 37 additions & 3 deletions src/librustc_resolve/resolve_imports.rs
Expand Up @@ -25,6 +25,7 @@ use {resolve_error, ResolutionError};

use build_reduced_graph;

use rustc::lint;
use rustc::middle::def::*;
use rustc::middle::def_id::DefId;
use rustc::middle::privacy::*;
Expand Down Expand Up @@ -443,7 +444,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
debug!("(resolving single import) found value binding");
value_result = BoundResult(target_module.clone(),
child_name_bindings.value_ns.clone());
if directive.is_public && !child_name_bindings.value_ns.is_reexportable() {
if directive.is_public && !child_name_bindings.value_ns.is_public() {
let msg = format!("`{}` is private, and cannot be reexported", source);
let note_msg = format!("Consider marking `{}` as `pub` in the imported \
module",
Expand All @@ -452,19 +453,40 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
self.resolver.session.span_note(directive.span, &note_msg);
pub_err = true;
}
if directive.is_public && child_name_bindings.value_ns.
defined_with(DefModifiers::PRIVATE_VARIANT) {
let msg = format!("variant `{}` is private, and cannot be reexported ( \
error E0364), consider declaring its enum as `pub`",
source);
self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
directive.id,
directive.span,
msg);
pub_err = true;
}
}
if child_name_bindings.type_ns.defined() {
debug!("(resolving single import) found type binding");
type_result = BoundResult(target_module.clone(),
child_name_bindings.type_ns.clone());
if !pub_err && directive.is_public &&
!child_name_bindings.type_ns.is_reexportable() {
!child_name_bindings.type_ns.is_public() {
let msg = format!("`{}` is private, and cannot be reexported", source);
let note_msg = format!("Consider declaring module `{}` as a `pub mod`",
source);
span_err!(self.resolver.session, directive.span, E0365, "{}", &msg);
self.resolver.session.span_note(directive.span, &note_msg);
}
if !pub_err && directive.is_public && child_name_bindings.type_ns.
defined_with(DefModifiers::PRIVATE_VARIANT) {
let msg = format!("variant `{}` is private, and cannot be reexported ( \
error E0365), consider declaring its enum as `pub`",
source);
self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
directive.id,
directive.span,
msg);
}
}
}
}
Expand Down Expand Up @@ -842,10 +864,22 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
module_to_string(module_));

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

let modifier = DefModifiers::IMPORTABLE | DefModifiers::PUBLIC;
if name_bindings[namespace].defined_with(modifier) {
let namespace_name = match namespace {
TypeNS => "type",
Expand Down
22 changes: 20 additions & 2 deletions src/test/compile-fail/private-variant-reexport.rs
Expand Up @@ -8,8 +8,26 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

pub use E::V; //~ERROR `V` is private, and cannot be reexported
#![feature(rustc_attrs)]
#![allow(dead_code)]

mod m1 {
pub use ::E::V; //~ WARN variant `V` is private, and cannot be reexported
}

mod m2 {
pub use ::E::{V}; //~ WARN variant `V` is private, and cannot be reexported
}

mod m3 {
pub use ::E::V::{self}; //~ WARN variant `V` is private, and cannot be reexported
}

mod m4 {
pub use ::E::*; //~ WARN variant `V` is private, and cannot be reexported
}

enum E { V }

fn main() {}
#[rustc_error]
fn main() {} //~ ERROR compilation successful

0 comments on commit 8f359d5

Please sign in to comment.