From 8f359d5912de9162534d65fe01fb2f52941e97d0 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 13 Dec 2015 21:57:07 +0300 Subject: [PATCH] Prohibit public glob reexports of private variants --- src/librustc_resolve/lib.rs | 5 --- src/librustc_resolve/resolve_imports.rs | 40 +++++++++++++++++-- .../compile-fail/private-variant-reexport.rs | 22 +++++++++- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 1d98aa36e8fc8..6896e8e534057 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -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()) })) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index c4296241633f1..69d5621ce73d9 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -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::*; @@ -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", @@ -452,19 +453,40 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { self.resolver.session.span_note(directive.span, ¬e_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, ¬e_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); + } } } } @@ -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", diff --git a/src/test/compile-fail/private-variant-reexport.rs b/src/test/compile-fail/private-variant-reexport.rs index f38546167998f..39698fa593a28 100644 --- a/src/test/compile-fail/private-variant-reexport.rs +++ b/src/test/compile-fail/private-variant-reexport.rs @@ -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