From c56a5afd4d1c4717770efa693e69eead13abee34 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 19 Aug 2016 22:52:26 +0000 Subject: [PATCH] item_like_imports: Allow single imports with a given visibility to reexport some (but not all) namespaces with less visibility. --- src/librustc_resolve/resolve_imports.rs | 51 +++++++++++++++++----- src/test/compile-fail/imports/reexports.rs | 37 ++++++++++++++++ 2 files changed, 77 insertions(+), 11 deletions(-) create mode 100644 src/test/compile-fail/imports/reexports.rs diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index c7cb3a35178..7084aa685ae 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -285,13 +285,20 @@ impl<'a> Resolver<'a> { // return the corresponding binding defined by the import directive. fn import(&mut self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>) -> NameBinding<'a> { + let vis = if binding.pseudo_vis().is_at_least(directive.vis.get(), self) || + !directive.is_glob() && binding.is_extern_crate() { // c.f. `PRIVATE_IN_PUBLIC` + directive.vis.get() + } else { + binding.pseudo_vis() + }; + NameBinding { kind: NameBindingKind::Import { binding: binding, directive: directive, }, span: directive.span, - vis: directive.vis.get(), + vis: vis, } } @@ -597,22 +604,44 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } } + let session = self.session; + let reexport_error = || { + let msg = format!("`{}` is private, and cannot be reexported", name); + let note_msg = + format!("consider marking `{}` as `pub` in the imported module", name); + struct_span_err!(session, directive.span, E0364, "{}", &msg) + .span_note(directive.span, ¬e_msg) + .emit(); + }; + + let extern_crate_lint = || { + let msg = format!("extern crate `{}` is private, and cannot be reexported \ + (error E0364), consider declaring with `pub`", + name); + session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg); + }; + match (value_result, type_result) { + // With `#![feature(item_like_imports)]`, all namespaces + // must be re-exported with extra visibility for an error to occur. + (Ok(value_binding), Ok(type_binding)) if self.new_import_semantics => { + let vis = directive.vis.get(); + if !value_binding.pseudo_vis().is_at_least(vis, self) && + !type_binding.pseudo_vis().is_at_least(vis, self) { + reexport_error(); + } else if type_binding.is_extern_crate() && + !type_binding.vis.is_at_least(vis, self) { + extern_crate_lint(); + } + } + (Ok(binding), _) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => { - let msg = format!("`{}` is private, and cannot be reexported", name); - let note_msg = - format!("consider marking `{}` as `pub` in the imported module", name); - struct_span_err!(self.session, directive.span, E0364, "{}", &msg) - .span_note(directive.span, ¬e_msg) - .emit(); + reexport_error(); } (_, Ok(binding)) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => { if binding.is_extern_crate() { - let msg = format!("extern crate `{}` is private, and cannot be reexported \ - (error E0364), consider declaring with `pub`", - name); - self.session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg); + extern_crate_lint(); } else { struct_span_err!(self.session, directive.span, E0365, "`{}` is private, and cannot be reexported", name) diff --git a/src/test/compile-fail/imports/reexports.rs b/src/test/compile-fail/imports/reexports.rs new file mode 100644 index 00000000000..f8dbb4d4448 --- /dev/null +++ b/src/test/compile-fail/imports/reexports.rs @@ -0,0 +1,37 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(item_like_imports)] + +mod a { + fn foo() {} + mod foo {} + + mod a { + pub use super::foo; //~ ERROR cannot be reexported + } +} + +mod b { + pub fn foo() {} + mod foo { pub struct S; } + + pub mod a { + pub use super::foo; // This is OK since the value `foo` is visible enough. + fn f(_: foo::S) {} // `foo` is imported in the type namespace (but not `pub` reexported). + } +} + +mod c { + // Test that `foo` is not reexported. + use b::a::foo::S; //~ ERROR `foo` +} + +fn main() {}