diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 64bcdc7920a01..3ef0633e7f400 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -14,6 +14,7 @@ use syntax::ast; use syntax::ext::base::MacroKind; use syntax_pos::Span; use hir; +use ty; #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum CtorKind { @@ -126,6 +127,11 @@ pub struct Export { pub def: Def, /// The span of the target definition. pub span: Span, + /// The visibility of the export. + /// We include non-`pub` exports for hygienic macros that get used from extern crates. + pub vis: ty::Visibility, + /// True if from a `use` or and `extern crate`. + pub is_import: bool, } impl CtorKind { diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 1533e37d7f759..6fc49e5189d55 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -1068,7 +1068,9 @@ for hir::def_id::DefIndex { impl_stable_hash_for!(struct hir::def::Export { ident, def, - span + vis, + span, + is_import }); impl<'gcx> HashStable> diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index afe999cede70d..93ef29855ce1d 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -307,6 +307,15 @@ impl Visibility { self.is_accessible_from(vis_restriction, tree) } + + // Returns true if this item is visible anywhere in the local crate. + pub fn is_visible_locally(self) -> bool { + match self { + Visibility::Public => true, + Visibility::Restricted(def_id) => def_id.is_local(), + Visibility::Invisible => false, + } + } } #[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Copy)] diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 911b4dac4e13a..bcf749da8cd44 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -305,12 +305,12 @@ pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { let mut add_child = |bfs_queue: &mut VecDeque<_>, child: &def::Export, parent: DefId| { - let child = child.def.def_id(); - - if tcx.visibility(child) != ty::Visibility::Public { + if child.vis != ty::Visibility::Public { return; } + let child = child.def.def_id(); + match visible_parent_map.entry(child) { Entry::Occupied(mut entry) => { // If `child` is defined in crate `cnum`, ensure diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 3be99e9722361..49a017535ffd1 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -639,7 +639,13 @@ impl<'a, 'tcx> CrateMetadata { ext.kind() ); let ident = Ident::with_empty_ctxt(name); - callback(def::Export { ident: ident, def: def, span: DUMMY_SP }); + callback(def::Export { + ident: ident, + def: def, + vis: ty::Visibility::Public, + span: DUMMY_SP, + is_import: false, + }); } } return @@ -676,7 +682,9 @@ impl<'a, 'tcx> CrateMetadata { callback(def::Export { def, ident: Ident::from_str(&self.item_name(child_index)), + vis: self.get_visibility(child_index), span: self.entry(child_index).span.decode((self, sess)), + is_import: false, }); } } @@ -693,7 +701,9 @@ impl<'a, 'tcx> CrateMetadata { if let (Some(def), Some(name)) = (self.get_def(child_index), def_key.disambiguated_data.data.get_opt_name()) { let ident = Ident::from_str(&name); - callback(def::Export { def: def, ident: ident, span: span }); + let vis = self.get_visibility(child_index); + let is_import = false; + callback(def::Export { def, ident, vis, span, is_import }); // For non-reexport structs and variants add their constructors to children. // Reexport lists automatically contain constructors when necessary. match def { @@ -701,7 +711,11 @@ impl<'a, 'tcx> CrateMetadata { if let Some(ctor_def_id) = self.get_struct_ctor_def_id(child_index) { let ctor_kind = self.get_ctor_kind(child_index); let ctor_def = Def::StructCtor(ctor_def_id, ctor_kind); - callback(def::Export { def: ctor_def, ident: ident, span: span }); + callback(def::Export { + def: ctor_def, + vis: self.get_visibility(ctor_def_id.index), + ident, span, is_import, + }); } } Def::Variant(def_id) => { @@ -709,7 +723,8 @@ impl<'a, 'tcx> CrateMetadata { // value namespace, they are reserved for possible future use. let ctor_kind = self.get_ctor_kind(child_index); let ctor_def = Def::VariantCtor(def_id, ctor_kind); - callback(def::Export { def: ctor_def, ident: ident, span: span }); + let vis = self.get_visibility(child_index); + callback(def::Export { def: ctor_def, ident, vis, span, is_import }); } _ => {} } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 6cfa324797c5d..7de3b8a4264e3 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -506,9 +506,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { let data = ModData { reexports: match tcx.module_exports(def_id) { - Some(ref exports) if *vis == hir::Public => { - self.lazy_seq_from_slice(exports.as_slice()) - } + Some(ref exports) => self.lazy_seq_from_slice(exports.as_slice()), _ => LazySeq::empty(), }, }; diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 74d92ce1c3e62..27898b5dd64bc 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -331,7 +331,9 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { if let Some(exports) = self.tcx.module_exports(def_id) { for export in exports.iter() { if let Some(node_id) = self.tcx.hir.as_local_node_id(export.def.def_id()) { - self.update(node_id, Some(AccessLevel::Exported)); + if export.vis == ty::Visibility::Public { + self.update(node_id, Some(AccessLevel::Exported)); + } } } } @@ -365,6 +367,15 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { for id in &module.item_ids { self.update(id.id, level); } + let def_id = self.tcx.hir.local_def_id(module_id); + if let Some(exports) = self.tcx.module_exports(def_id) { + for export in exports.iter() { + if let Some(node_id) = self.tcx.hir.as_local_node_id(export.def.def_id()) { + self.update(node_id, level); + } + } + } + if module_id == ast::CRATE_NODE_ID { break } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index afca6ea2c0751..33fe432f0670a 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -466,11 +466,8 @@ impl<'a> Resolver<'a> { /// Builds the reduced graph for a single item in an external crate. fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'a>, child: Export) { - let ident = child.ident; - let def = child.def; + let Export { ident, def, vis, span, .. } = child; let def_id = def.def_id(); - let vis = self.cstore.visibility_untracked(def_id); - let span = child.span; let expansion = Mark::root(); // FIXME(jseyfried) intercrate hygiene match def { Def::Mod(..) | Def::Enum(..) => { @@ -674,7 +671,8 @@ impl<'a> Resolver<'a> { let ident = Ident::with_empty_ctxt(name); let result = self.resolve_ident_in_module(module, ident, MacroNS, false, false, span); if let Ok(binding) = result { - self.macro_exports.push(Export { ident: ident, def: binding.def(), span: span }); + let (def, vis) = (binding.def(), binding.vis); + self.macro_exports.push(Export { ident, def, vis, span, is_import: true }); } else { span_err!(self.session, span, E0470, "reexported macro not found"); } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index ca822faeeac01..30b808fb9d7c4 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1108,7 +1108,11 @@ impl<'a> NameBinding<'a> { // We sometimes need to treat variants as `pub` for backwards compatibility fn pseudo_vis(&self) -> ty::Visibility { - if self.is_variant() { ty::Visibility::Public } else { self.vis } + if self.is_variant() && self.def().def_id().is_local() { + ty::Visibility::Public + } else { + self.vis + } } fn is_variant(&self) -> bool { @@ -3613,9 +3617,9 @@ impl<'a> Resolver<'a> { self.populate_module_if_necessary(in_module); in_module.for_each_child_stable(|ident, _, name_binding| { - // abort if the module is already found - if let Some(_) = result { - return (); + // abort if the module is already found or if name_binding is private external + if result.is_some() || !name_binding.vis.is_visible_locally() { + return } if let Some(module) = name_binding.module() { // form the path diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 3d1d7c0c48a1e..f2162f2321f61 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -746,8 +746,13 @@ impl<'a> Resolver<'a> { })); if attr::contains_name(&item.attrs, "macro_export") { let def = Def::Macro(def_id, MacroKind::Bang); - self.macro_exports - .push(Export { ident: ident.modern(), def: def, span: item.span }); + self.macro_exports.push(Export { + ident: ident.modern(), + def: def, + vis: ty::Visibility::Public, + span: item.span, + is_import: false, + }); } else { self.unused_macros.insert(def_id); } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 2dbcbb364d86c..e249ecfca588e 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -898,8 +898,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { None => continue, }; - if binding.vis == ty::Visibility::Public && - (binding.is_import() || binding.is_macro_def()) { + if binding.is_import() || binding.is_macro_def() { let def = binding.def(); if def != Def::Err { if !def.def_id().is_local() { @@ -915,7 +914,13 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { .emit(); } } - reexports.push(Export { ident: ident.modern(), def: def, span: binding.span }); + reexports.push(Export { + ident: ident.modern(), + def: def, + span: binding.span, + vis: binding.vis, + is_import: true, + }); } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 16b5216d58d43..60592cc186ed8 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -392,7 +392,7 @@ fn build_module(cx: &DocContext, did: DefId) -> clean::Module { let mut visited = FxHashSet(); for &item in cx.tcx.item_children(did).iter() { let def_id = item.def.def_id(); - if cx.tcx.visibility(def_id) == ty::Visibility::Public { + if item.vis == ty::Visibility::Public { if !visited.insert(def_id) { continue } if let Some(i) = try_inline(cx, item.def, item.ident.name) { items.extend(i) diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index 9f75388238f0c..2fd47fa0a6d0a 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -68,7 +68,9 @@ impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> { } for item in self.cx.tcx.item_children(def_id).iter() { - self.visit_item(item.def); + if !item.is_import || item.vis == Visibility::Public { + self.visit_item(item.def); + } } } diff --git a/src/test/run-pass/hygiene/auxiliary/xcrate.rs b/src/test/run-pass/hygiene/auxiliary/xcrate.rs new file mode 100644 index 0000000000000..2ccd043097f8e --- /dev/null +++ b/src/test/run-pass/hygiene/auxiliary/xcrate.rs @@ -0,0 +1,38 @@ +// Copyright 2017 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(decl_macro)] +#![allow(unused)] + +pub use bar::test; + +extern crate std as foo; + +pub fn f() {} +use f as f2; + +mod bar { + pub fn g() {} + use baz::h; + + pub macro test() { + use std::mem; + use foo::cell; + ::f(); + ::f2(); + g(); + h(); + ::bar::h(); + } +} + +mod baz { + pub fn h() {} +} diff --git a/src/test/run-pass/hygiene/xcrate.rs b/src/test/run-pass/hygiene/xcrate.rs new file mode 100644 index 0000000000000..6df3a34d3c87f --- /dev/null +++ b/src/test/run-pass/hygiene/xcrate.rs @@ -0,0 +1,21 @@ +// Copyright 2017 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. + +// ignore-pretty pretty-printing is unhygienic + +// aux-build:xcrate.rs + +#![feature(decl_macro)] + +extern crate xcrate; + +fn main() { + xcrate::test!(); +}