From 3a77bb86ff33bd4633aa831f2580aa3792a9c279 Mon Sep 17 00:00:00 2001 From: Lamb Date: Mon, 26 Jul 2021 05:38:16 +0200 Subject: [PATCH] Compute most of Public/Exported access level in rustc_resolve Mak DefId to AccessLevel map in resolve for export hir_id to accesslevel in resolve and applied in privacy using local def id removing tracing probes making function not recursive and adding comments Move most of Exported/Public res to rustc_resolve moving public/export res to resolve fix missing stability attributes in core, std and alloc move code to access_levels.rs return for some kinds instead of going through them Export correctness, macro changes, comments add comment for import binding add comment for import binding renmae to access level visitor, remove comments, move fn as closure, remove new_key fmt fix rebase fix rebase fmt fmt fix: move macro def to rustc_resolve fix: reachable AccessLevel for enum variants fmt fix: missing stability attributes for other architectures allow unreachable pub in rustfmt fix: missing impl access level + renaming export to reexport Missing impl access level was found thanks to a test in clippy --- compiler/rustc_errors/src/snippet.rs | 3 - compiler/rustc_lint/src/lib.rs | 3 +- compiler/rustc_middle/src/middle/privacy.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 2 + compiler/rustc_privacy/src/lib.rs | 220 +++------------- compiler/rustc_resolve/src/access_levels.rs | 237 ++++++++++++++++++ .../rustc_resolve/src/build_reduced_graph.rs | 6 +- compiler/rustc_resolve/src/imports.rs | 4 +- compiler/rustc_resolve/src/lib.rs | 13 + library/alloc/src/collections/btree/map.rs | 3 + library/core/src/iter/adapters/mod.rs | 1 + library/core/src/iter/sources.rs | 1 + library/core/src/iter/traits/mod.rs | 16 +- library/std/src/io/buffered/mod.rs | 8 +- library/std/src/io/mod.rs | 27 +- library/std/src/os/linux/raw.rs | 1 + library/std/src/os/unix/io/raw.rs | 1 + .../lint-pub-unreachable-for-nested-glob.rs | 28 +++ src/tools/rustfmt/src/lib.rs | 1 + 19 files changed, 359 insertions(+), 218 deletions(-) create mode 100644 compiler/rustc_resolve/src/access_levels.rs create mode 100644 src/test/ui/lint/lint-pub-unreachable-for-nested-glob.rs diff --git a/compiler/rustc_errors/src/snippet.rs b/compiler/rustc_errors/src/snippet.rs index 64353461e90e0..e4cc44c41ddec 100644 --- a/compiler/rustc_errors/src/snippet.rs +++ b/compiler/rustc_errors/src/snippet.rs @@ -69,9 +69,6 @@ pub enum AnnotationType { /// Annotation under a single line of code Singleline, - /// Annotation enclosing the first and last character of a multiline span - Multiline(MultilineAnnotation), - // The Multiline type above is replaced with the following three in order // to reuse the current label drawing code. // diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index c7823032b0c23..c6145ae0d510b 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -92,7 +92,8 @@ use unused::*; /// Useful for other parts of the compiler / Clippy. pub use builtin::SoftLints; -pub use context::{CheckLintNameResult, EarlyContext, LateContext, LintContext, LintStore}; +pub use context::{CheckLintNameResult, FindLintError, LintStore}; +pub use context::{EarlyContext, LateContext, LintContext}; pub use early::check_ast_crate; pub use late::check_crate; pub use passes::{EarlyLintPass, LateLintPass}; diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index f33bd3438b968..ff993ac392cf7 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -28,7 +28,7 @@ pub enum AccessLevel { } /// Holds a map of accessibility levels for reachable HIR nodes. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct AccessLevels { pub map: FxHashMap, } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f5f55dcf38cf4..16adf93b69a36 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -20,6 +20,7 @@ pub use generics::*; pub use vtable::*; use crate::metadata::ModChild; +use crate::middle::privacy::AccessLevels; use crate::mir::{Body, GeneratorLayout}; use crate::traits::{self, Reveal}; use crate::ty; @@ -123,6 +124,7 @@ pub struct ResolverOutputs { pub definitions: rustc_hir::definitions::Definitions, pub cstore: Box, pub visibilities: FxHashMap, + pub access_levels: AccessLevels, pub extern_crate_map: FxHashMap, pub maybe_unused_trait_imports: FxHashSet, pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>, diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 16418e627f2dc..e93cd813db53e 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -11,8 +11,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet}; -use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID}; use rustc_hir::intravisit::{self, DeepVisitor, NestedVisitorMap, Visitor}; use rustc_hir::{AssocItemKind, HirIdSet, Node, PatKind}; use rustc_middle::bug; @@ -26,7 +25,7 @@ use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeFoldable}; use rustc_session::lint; use rustc_span::hygiene::Transparency; -use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; use rustc_trait_selection::traits::const_evaluatable::{self, AbstractConst}; @@ -436,6 +435,15 @@ impl<'tcx> EmbargoVisitor<'tcx> { self.access_levels.map.get(&def_id).copied() } + fn update_with_hir_id( + &mut self, + hir_id: hir::HirId, + level: Option, + ) -> Option { + let def_id = self.tcx.hir().local_def_id(hir_id); + self.update(def_id, level) + } + /// Updates node level and returns the updated level. fn update(&mut self, def_id: LocalDefId, level: Option) -> Option { let old_level = self.get(def_id); @@ -623,54 +631,6 @@ impl<'tcx> EmbargoVisitor<'tcx> { | DefKind::Generator => (), } } - - /// Given the path segments of an `ItemKind::Use`, then we need - /// to update the visibility of the intermediate use so that it isn't linted - /// by `unreachable_pub`. - /// - /// This isn't trivial as `path.res` has the `DefId` of the eventual target - /// of the use statement not of the next intermediate use statement. - /// - /// To do this, consider the last two segments of the path to our intermediate - /// use statement. We expect the penultimate segment to be a module and the - /// last segment to be the name of the item we are exporting. We can then - /// look at the items contained in the module for the use statement with that - /// name and update that item's visibility. - /// - /// FIXME: This solution won't work with glob imports and doesn't respect - /// namespaces. See . - fn update_visibility_of_intermediate_use_statements( - &mut self, - segments: &[hir::PathSegment<'_>], - ) { - if let [.., module, segment] = segments { - if let Some(item) = module - .res - .and_then(|res| res.mod_def_id()) - // If the module is `self`, i.e. the current crate, - // there will be no corresponding item. - .filter(|def_id| def_id.index != CRATE_DEF_INDEX || def_id.krate != LOCAL_CRATE) - .and_then(|def_id| def_id.as_local()) - .map(|module_hir_id| self.tcx.hir().expect_item(module_hir_id)) - { - if let hir::ItemKind::Mod(m) = &item.kind { - for &item_id in m.item_ids { - let item = self.tcx.hir().item(item_id); - if !self.tcx.hygienic_eq( - segment.ident, - item.ident, - item_id.def_id.to_def_id(), - ) { - continue; - } - if let hir::ItemKind::Use(..) = item.kind { - self.update(item.def_id, Some(AccessLevel::Exported)); - } - } - } - } - } - } } impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { @@ -683,120 +643,22 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - let inherited_item_level = match item.kind { + let item_level = match item.kind { hir::ItemKind::Impl { .. } => { - Option::::of_impl(item.def_id, self.tcx, &self.access_levels) - } - // Only exported `macro_rules!` items are public, but they always are. - hir::ItemKind::Macro(MacroDef { macro_rules: true, .. }) => { - let def_id = item.def_id.to_def_id(); - let is_macro_export = self.tcx.has_attr(def_id, sym::macro_export); - if is_macro_export { Some(AccessLevel::Public) } else { None } - } - // Foreign modules inherit level from parents. - hir::ItemKind::ForeignMod { .. } => self.prev_level, - // Other `pub` items inherit levels from parents. - hir::ItemKind::Const(..) - | hir::ItemKind::Enum(..) - | hir::ItemKind::ExternCrate(..) - | hir::ItemKind::GlobalAsm(..) - | hir::ItemKind::Fn(..) - | hir::ItemKind::Macro(..) - | hir::ItemKind::Mod(..) - | hir::ItemKind::Static(..) - | hir::ItemKind::Struct(..) - | hir::ItemKind::Trait(..) - | hir::ItemKind::TraitAlias(..) - | hir::ItemKind::OpaqueTy(..) - | hir::ItemKind::TyAlias(..) - | hir::ItemKind::Union(..) - | hir::ItemKind::Use(..) => { - if item.vis.node.is_pub() { - self.prev_level - } else { - None - } + let impl_level = + Option::::of_impl(item.def_id, self.tcx, &self.access_levels); + self.update(item.def_id, impl_level) } + _ => self.get(item.def_id), }; - // Update level of the item itself. - let item_level = self.update(item.def_id, inherited_item_level); - - // Update levels of nested things. - match item.kind { - hir::ItemKind::Enum(ref def, _) => { - for variant in def.variants { - let variant_level = - self.update(self.tcx.hir().local_def_id(variant.id), item_level); - if let Some(ctor_hir_id) = variant.data.ctor_hir_id() { - self.update(self.tcx.hir().local_def_id(ctor_hir_id), item_level); - } - for field in variant.data.fields() { - self.update(self.tcx.hir().local_def_id(field.hir_id), variant_level); - } - } - } - hir::ItemKind::Impl(ref impl_) => { - for impl_item_ref in impl_.items { - if impl_.of_trait.is_some() - || self.tcx.visibility(impl_item_ref.id.def_id) == ty::Visibility::Public - { - self.update(impl_item_ref.id.def_id, item_level); - } - } - } - hir::ItemKind::Trait(.., trait_item_refs) => { - for trait_item_ref in trait_item_refs { - self.update(trait_item_ref.id.def_id, item_level); - } - } - hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => { - if let Some(ctor_hir_id) = def.ctor_hir_id() { - self.update(self.tcx.hir().local_def_id(ctor_hir_id), item_level); - } - for field in def.fields() { - if field.vis.node.is_pub() { - self.update(self.tcx.hir().local_def_id(field.hir_id), item_level); - } - } - } - hir::ItemKind::Macro(ref macro_def) => { - self.update_reachability_from_macro(item.def_id, macro_def); - } - hir::ItemKind::ForeignMod { items, .. } => { - for foreign_item in items { - if self.tcx.visibility(foreign_item.id.def_id) == ty::Visibility::Public { - self.update(foreign_item.id.def_id, item_level); - } - } - } - - hir::ItemKind::OpaqueTy(..) - | hir::ItemKind::Use(..) - | hir::ItemKind::Static(..) - | hir::ItemKind::Const(..) - | hir::ItemKind::GlobalAsm(..) - | hir::ItemKind::TyAlias(..) - | hir::ItemKind::Mod(..) - | hir::ItemKind::TraitAlias(..) - | hir::ItemKind::Fn(..) - | hir::ItemKind::ExternCrate(..) => {} - } - // Mark all items in interfaces of reachable items as reachable. match item.kind { // The interface is empty. - hir::ItemKind::Macro(..) | hir::ItemKind::ExternCrate(..) => {} + hir::ItemKind::ExternCrate(..) => {} // All nested items are checked by `visit_item`. hir::ItemKind::Mod(..) => {} - // Re-exports are handled in `visit_mod`. However, in order to avoid looping over - // all of the items of a mod in `visit_mod` looking for use statements, we handle - // making sure that intermediate use statements have their visibilities updated here. - hir::ItemKind::Use(path, _) => { - if item_level.is_some() { - self.update_visibility_of_intermediate_use_statements(path.segments.as_ref()); - } - } + hir::ItemKind::Use(..) => {} // The interface is empty. hir::ItemKind::GlobalAsm(..) => {} hir::ItemKind::OpaqueTy(..) => { @@ -847,6 +709,14 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } // Visit everything except for private impl items. hir::ItemKind::Impl(ref impl_) => { + for impl_item_ref in impl_.items { + if impl_.of_trait.is_some() + || self.tcx.visibility(impl_item_ref.id.def_id) == ty::Visibility::Public + { + self.update(impl_item_ref.id.def_id, item_level); + } + } + if item_level.is_some() { self.reach(item.def_id, item_level).generics().predicates().ty().trait_ref(); @@ -861,15 +731,21 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } } } - // Visit everything, but enum variants have their own levels. hir::ItemKind::Enum(ref def, _) => { if item_level.is_some() { self.reach(item.def_id, item_level).generics().predicates(); } + + let enum_level = self.get(item.def_id); for variant in def.variants { - let variant_level = self.get(self.tcx.hir().local_def_id(variant.id)); + let variant_level = self.update_with_hir_id(variant.id, enum_level); + if variant_level.is_some() { + if let Some(ctor_id) = variant.data.ctor_hir_id() { + self.update_with_hir_id(ctor_id, variant_level); + } + for field in variant.data.fields() { self.reach(self.tcx.hir().local_def_id(field.hir_id), variant_level) .ty(); @@ -880,6 +756,9 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } } } + hir::ItemKind::Macro(ref macro_def) => { + self.update_reachability_from_macro(item.def_id, macro_def); + } // Visit everything, but foreign items have their own levels. hir::ItemKind::ForeignMod { items, .. } => { for foreign_item in items { @@ -920,27 +799,6 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { intravisit::walk_block(self, b); self.prev_level = orig_level; } - - fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, _sp: Span, id: hir::HirId) { - // This code is here instead of in visit_item so that the - // crate module gets processed as well. - if self.prev_level.is_some() { - let def_id = self.tcx.hir().local_def_id(id); - if let Some(exports) = self.tcx.module_reexports(def_id) { - for export in exports.iter() { - if export.vis.is_public() { - if let Some(def_id) = export.res.opt_def_id() { - if let Some(def_id) = def_id.as_local() { - self.update(def_id, Some(AccessLevel::Exported)); - } - } - } - } - } - } - - intravisit::walk_mod(self, m, id); - } } impl ReachEverythingInTheInterfaceVisitor<'_, '_> { @@ -2166,11 +2024,12 @@ fn privacy_access_levels(tcx: TyCtxt<'_>, (): ()) -> &AccessLevels { // items which are reachable from external crates based on visibility. let mut visitor = EmbargoVisitor { tcx, - access_levels: Default::default(), + access_levels: tcx.resolutions(()).access_levels.clone(), macro_reachable: Default::default(), prev_level: Some(AccessLevel::Public), changed: false, }; + loop { tcx.hir().walk_toplevel_module(&mut visitor); if visitor.changed { @@ -2179,7 +2038,6 @@ fn privacy_access_levels(tcx: TyCtxt<'_>, (): ()) -> &AccessLevels { break; } } - visitor.update(CRATE_DEF_ID, Some(AccessLevel::Public)); tcx.arena.alloc(visitor.access_levels) } diff --git a/compiler/rustc_resolve/src/access_levels.rs b/compiler/rustc_resolve/src/access_levels.rs new file mode 100644 index 0000000000000..60cc4248edc9d --- /dev/null +++ b/compiler/rustc_resolve/src/access_levels.rs @@ -0,0 +1,237 @@ +use rustc_ast::ast; +use rustc_ast::visit; +use rustc_ast::visit::Visitor; +use rustc_ast::Crate; +use rustc_ast::EnumDef; +use rustc_ast::ForeignMod; +use rustc_ast::NodeId; +use rustc_ast_lowering::ResolverAstLowering; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::def_id::CRATE_DEF_ID; +use rustc_middle::middle::privacy::AccessLevel; +use rustc_middle::ty::Visibility; +use rustc_span::sym; + +use crate::imports::ImportKind; +use crate::BindingKey; +use crate::NameBinding; +use crate::NameBindingKind; +use crate::Resolver; + +pub struct AccessLevelsVisitor<'r, 'a> { + r: &'r mut Resolver<'a>, + prev_level: Option, + changed: bool, +} + +impl<'r, 'a> AccessLevelsVisitor<'r, 'a> { + /// Fills the `Resolver::access_levels` table with public & exported items + /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we + /// need access to a TyCtxt for that. + pub fn compute_access_levels<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) { + let mut visitor = + AccessLevelsVisitor { r, changed: false, prev_level: Some(AccessLevel::Public) }; + + visitor.set_access_level_def_id(CRATE_DEF_ID, Some(AccessLevel::Public)); + visitor.set_exports_access_level(CRATE_DEF_ID); + + while visitor.changed { + visitor.reset(); + visit::walk_crate(&mut visitor, krate); + } + + tracing::info!("resolve::access_levels: {:#?}", r.access_levels); + } + + fn reset(&mut self) { + self.changed = false; + self.prev_level = Some(AccessLevel::Public); + } + + /// Update the access level of the exports of the given module accordingly. The module access + /// level has to be Exported or Public. + /// This will also follow `use` chains (see PrivacyVisitor::set_import_binding_access_level). + fn set_exports_access_level(&mut self, module_id: LocalDefId) { + assert!(self.r.module_map.contains_key(&&module_id.to_def_id())); + + // Set the given binding access level to `AccessLevel::Public` and + // sets the rest of the `use` chain to `AccessLevel::Exported` until + // we hit the actual exported item. + let set_import_binding_access_level = + |this: &mut Self, mut binding: &NameBinding<'a>, mut access_level| { + while let NameBindingKind::Import { binding: nested_binding, import, .. } = + binding.kind + { + this.set_access_level(import.id, access_level); + if let ImportKind::Single { additional_ids, .. } = import.kind { + this.set_access_level(additional_ids.0, access_level); + this.set_access_level(additional_ids.1, access_level); + } + + access_level = Some(AccessLevel::Exported); + binding = nested_binding; + } + }; + + let module_level = self.r.access_levels.map.get(&module_id).copied(); + assert!(module_level >= Some(AccessLevel::Exported)); + + if let Some(exports) = self.r.reexport_map.get(&module_id) { + let pub_exports = exports + .iter() + .filter(|ex| ex.vis == Visibility::Public) + .cloned() + .collect::>(); + + let module = self.r.get_module(module_id.to_def_id()).unwrap(); + for export in pub_exports.into_iter() { + if let Some(export_def_id) = export.res.opt_def_id().and_then(|id| id.as_local()) { + self.set_access_level_def_id(export_def_id, Some(AccessLevel::Exported)); + } + + if let Some(ns) = export.res.ns() { + let key = BindingKey { ident: export.ident, ns, disambiguator: 0 }; + let name_res = self.r.resolution(module, key); + if let Some(binding) = name_res.borrow().binding() { + set_import_binding_access_level(self, binding, module_level) + } + } + } + } + } + + /// Sets the access level of the `LocalDefId` corresponding to the given `NodeId`. + /// This function will panic if the `NodeId` does not have a `LocalDefId` + fn set_access_level( + &mut self, + node_id: NodeId, + access_level: Option, + ) -> Option { + self.set_access_level_def_id(self.r.local_def_id(node_id), access_level) + } + + fn set_access_level_def_id( + &mut self, + def_id: LocalDefId, + access_level: Option, + ) -> Option { + let old_level = self.r.access_levels.map.get(&def_id).copied(); + if old_level < access_level { + self.r.access_levels.map.insert(def_id, access_level.unwrap()); + self.changed = true; + access_level + } else { + old_level + } + } +} + +impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> { + fn visit_item(&mut self, item: &'ast ast::Item) { + let inherited_item_level = match item.kind { + // Resolved in rustc_privacy when types are available + ast::ItemKind::Impl(..) => return, + + // Only exported `macro_rules!` items are public, but they always are + ast::ItemKind::MacroDef(..) => { + let is_macro_export = + item.attrs.iter().any(|attr| attr.has_name(sym::macro_export)); + if is_macro_export { Some(AccessLevel::Public) } else { None } + } + + // Foreign modules inherit level from parents. + ast::ItemKind::ForeignMod(..) => self.prev_level, + + // Other `pub` items inherit levels from parents. + ast::ItemKind::ExternCrate(..) + | ast::ItemKind::Use(..) + | ast::ItemKind::Static(..) + | ast::ItemKind::Const(..) + | ast::ItemKind::Fn(..) + | ast::ItemKind::Mod(..) + | ast::ItemKind::GlobalAsm(..) + | ast::ItemKind::TyAlias(..) + | ast::ItemKind::Enum(..) + | ast::ItemKind::Struct(..) + | ast::ItemKind::Union(..) + | ast::ItemKind::Trait(..) + | ast::ItemKind::TraitAlias(..) => { + if item.vis.kind.is_pub() { + self.prev_level + } else { + None + } + } + + // Should be unreachable at this stage + ast::ItemKind::MacCall(..) => panic!( + "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage" + ), + }; + + let access_level = self.set_access_level(item.id, inherited_item_level); + + // Set access level of nested items. + // If it's a mod, also make the visitor walk all of its items + match item.kind { + ast::ItemKind::Mod(..) => { + if access_level.is_some() { + self.set_exports_access_level(self.r.local_def_id(item.id)); + } + + let orig_level = std::mem::replace(&mut self.prev_level, access_level); + visit::walk_item(self, item); + self.prev_level = orig_level; + } + + ast::ItemKind::ForeignMod(ForeignMod { ref items, .. }) => { + for nested in items { + if nested.vis.kind.is_pub() { + self.set_access_level(nested.id, access_level); + } + } + } + ast::ItemKind::Enum(EnumDef { ref variants }, _) => { + for variant in variants { + let variant_level = self.set_access_level(variant.id, access_level); + if let Some(ctor_id) = variant.data.ctor_id() { + self.set_access_level(ctor_id, access_level); + } + + for field in variant.data.fields() { + self.set_access_level(field.id, variant_level); + } + } + } + ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => { + if let Some(ctor_id) = def.ctor_id() { + self.set_access_level(ctor_id, access_level); + } + + for field in def.fields() { + if field.vis.kind.is_pub() { + self.set_access_level(field.id, access_level); + } + } + } + ast::ItemKind::Trait(ref trait_kind) => { + for nested in trait_kind.items.iter() { + self.set_access_level(nested.id, access_level); + } + } + + ast::ItemKind::ExternCrate(..) + | ast::ItemKind::Use(..) + | ast::ItemKind::Static(..) + | ast::ItemKind::Const(..) + | ast::ItemKind::GlobalAsm(..) + | ast::ItemKind::TyAlias(..) + | ast::ItemKind::TraitAlias(..) + | ast::ItemKind::MacroDef(..) + | ast::ItemKind::Fn(..) => return, + + // Unreachable kinds + ast::ItemKind::Impl(..) | ast::ItemKind::MacCall(..) => unreachable!(), + } + } +} diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 944e71851840c..052770b201a5b 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -383,8 +383,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { used: Cell::new(false), }); - debug!("add_import({:?})", import); - self.r.indeterminate_imports.push(import); match import.kind { // Don't add unresolved underscore imports to modules @@ -455,7 +453,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { prefix.is_empty() || prefix.len() == 1 && prefix[0].ident.name == kw::PathRoot }; match use_tree.kind { - ast::UseTreeKind::Simple(rename, ..) => { + ast::UseTreeKind::Simple(rename, id1, id2) => { let mut ident = use_tree.ident(); let mut module_path = prefix; let mut source = module_path.pop().unwrap(); @@ -565,7 +563,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { }, type_ns_only, nested, + additional_ids: (id1, id2), }; + self.add_import( module_path, kind, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 2832f59a5efc6..e7f76a18ad31a 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -48,6 +48,9 @@ pub enum ImportKind<'a> { type_ns_only: bool, /// Did this import result from a nested import? ie. `use foo::{bar, baz};` nested: bool, + /// Additional `NodeId`s allocated to a `ast::UseTree` for automatically generated `use` statement + /// (eg. implicit struct constructors) + additional_ids: (NodeId, NodeId), }, Glob { is_prelude: bool, @@ -834,7 +837,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> { import.span, ); import.vis.set(orig_vis); - source_bindings[ns].set(binding); } else { return; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 37be0e228d27a..2843774275883 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -50,6 +50,7 @@ use rustc_hir::TraitCandidate; use rustc_index::vec::IndexVec; use rustc_metadata::creader::{CStore, CrateLoader}; use rustc_middle::metadata::ModChild; +use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::span_bug; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, DefIdTree, MainDefinition, ResolverOutputs}; @@ -77,8 +78,11 @@ use imports::{Import, ImportKind, ImportResolver, NameResolution}; use late::{ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind::*}; use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; +use crate::access_levels::AccessLevelsVisitor; + type Res = def::Res; +mod access_levels; mod build_reduced_graph; mod check_unused; mod def_collector; @@ -1052,6 +1056,8 @@ pub struct Resolver<'a> { /// they are declared in the static array generated by proc_macro_harness. proc_macros: Vec, confused_type_with_std_module: FxHashMap, + + access_levels: AccessLevels, } /// Nothing really interesting here; it just provides memory for the rest of the crate. @@ -1407,6 +1413,7 @@ impl<'a> Resolver<'a> { trait_impls: Default::default(), proc_macros: Default::default(), confused_type_with_std_module: Default::default(), + access_levels: Default::default(), }; let root_parent_scope = ParentScope::module(graph_root, &resolver); @@ -1452,10 +1459,12 @@ impl<'a> Resolver<'a> { let glob_map = self.glob_map; let main_def = self.main_def; let confused_type_with_std_module = self.confused_type_with_std_module; + let access_levels = self.access_levels; ResolverOutputs { definitions, cstore: Box::new(self.crate_loader.into_cstore()), visibilities, + access_levels, extern_crate_map, reexport_map, glob_map, @@ -1477,6 +1486,7 @@ impl<'a> Resolver<'a> { let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect(); ResolverOutputs { definitions: self.definitions.clone(), + access_levels: self.access_levels.clone(), cstore: Box::new(self.cstore().clone()), visibilities: self.visibilities.clone(), extern_crate_map: self.extern_crate_map.clone(), @@ -1532,6 +1542,9 @@ impl<'a> Resolver<'a> { pub fn resolve_crate(&mut self, krate: &Crate) { self.session.time("resolve_crate", || { self.session.time("finalize_imports", || ImportResolver { r: self }.finalize_imports()); + self.session.time("resolve_access_levels", || { + AccessLevelsVisitor::compute_access_levels(self, krate) + }); self.session.time("finalize_macro_resolutions", || self.finalize_macro_resolutions()); self.session.time("late_resolve_crate", || self.late_resolve_crate(krate)); self.session.time("resolve_main", || self.resolve_main()); diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 199c05dc5df3e..62153efbb393b 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -16,7 +16,10 @@ use super::node::{self, marker, ForceResult::*, Handle, NodeRef, Root}; use super::search::SearchResult::*; mod entry; + +#[stable(feature = "rust1", since = "1.0.0")] pub use entry::{Entry, OccupiedEntry, OccupiedError, VacantEntry}; + use Entry::*; /// Minimum number of elements in a node that is not a root. diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index b1b917775c3fa..db8776ac7418d 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -24,6 +24,7 @@ mod take; mod take_while; mod zip; +#[stable(feature = "rust1", since = "1.0.0")] pub use self::{ chain::Chain, cycle::Cycle, enumerate::Enumerate, filter::Filter, filter_map::FilterMap, flatten::FlatMap, fuse::Fuse, inspect::Inspect, map::Map, peekable::Peekable, rev::Rev, diff --git a/library/core/src/iter/sources.rs b/library/core/src/iter/sources.rs index de0663141e252..37b6f2e2565b2 100644 --- a/library/core/src/iter/sources.rs +++ b/library/core/src/iter/sources.rs @@ -6,6 +6,7 @@ mod repeat; mod repeat_with; mod successors; +#[stable(feature = "rust1", since = "1.0.0")] pub use self::repeat::{repeat, Repeat}; #[stable(feature = "iter_empty", since = "1.2.0")] diff --git a/library/core/src/iter/traits/mod.rs b/library/core/src/iter/traits/mod.rs index ffd745a46b12c..ed0fb634dbf05 100644 --- a/library/core/src/iter/traits/mod.rs +++ b/library/core/src/iter/traits/mod.rs @@ -5,15 +5,17 @@ mod exact_size; mod iterator; mod marker; -pub use self::accum::{Product, Sum}; -pub use self::collect::{Extend, FromIterator, IntoIterator}; -pub use self::double_ended::DoubleEndedIterator; -pub use self::exact_size::ExactSizeIterator; #[stable(feature = "rust1", since = "1.0.0")] -pub use self::iterator::Iterator; +pub use self::{ + accum::{Product, Sum}, + collect::{Extend, FromIterator, IntoIterator}, + double_ended::DoubleEndedIterator, + exact_size::ExactSizeIterator, + iterator::Iterator, + marker::{FusedIterator, TrustedLen}, +}; + #[unstable(issue = "none", feature = "inplace_iteration")] pub use self::marker::InPlaceIterable; #[unstable(feature = "trusted_step", issue = "85731")] pub use self::marker::TrustedStep; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::marker::{FusedIterator, TrustedLen}; diff --git a/library/std/src/io/buffered/mod.rs b/library/std/src/io/buffered/mod.rs index 179bdf7fe553a..100dab1e2493c 100644 --- a/library/std/src/io/buffered/mod.rs +++ b/library/std/src/io/buffered/mod.rs @@ -12,12 +12,12 @@ use crate::error; use crate::fmt; use crate::io::Error; -pub use bufreader::BufReader; -pub use bufwriter::BufWriter; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::{bufreader::BufReader, bufwriter::BufWriter, linewriter::LineWriter}; +use linewritershim::LineWriterShim; + #[stable(feature = "bufwriter_into_parts", since = "1.56.0")] pub use bufwriter::WriterPanicked; -pub use linewriter::LineWriter; -use linewritershim::LineWriterShim; /// An error returned by [`BufWriter::into_inner`] which combines an error that /// happened while writing out the buffer, and the buffered writer object diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index ecc9e91b6bdb2..358ef22e708d7 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -261,31 +261,24 @@ use crate::str; use crate::sys; use crate::sys_common::memchr; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::buffered::IntoInnerError; #[stable(feature = "bufwriter_into_parts", since = "1.56.0")] pub use self::buffered::WriterPanicked; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::buffered::{BufReader, BufWriter, LineWriter}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::copy::copy; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::cursor::Cursor; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::error::{Error, ErrorKind, Result}; #[unstable(feature = "internal_output_capture", issue = "none")] #[doc(no_inline, hidden)] pub use self::stdio::set_output_capture; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::stdio::{stderr, stdin, stdout, Stderr, Stdin, Stdout}; -#[unstable(feature = "stdio_locked", issue = "86845")] -pub use self::stdio::{stderr_locked, stdin_locked, stdout_locked}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::stdio::{StderrLock, StdinLock, StdoutLock}; #[unstable(feature = "print_internals", issue = "none")] pub use self::stdio::{_eprint, _print}; +#[unstable(feature = "stdio_locked", issue = "86845")] +pub use self::stdio::{stderr_locked, stdin_locked, stdout_locked}; #[stable(feature = "rust1", since = "1.0.0")] -pub use self::util::{empty, repeat, sink, Empty, Repeat, Sink}; +pub use self::{ + buffered::{BufReader, BufWriter, IntoInnerError, LineWriter}, + copy::copy, + cursor::Cursor, + error::{Error, ErrorKind, Result}, + stdio::{stderr, stdin, stdout, Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock}, + util::{empty, repeat, sink, Empty, Repeat, Sink}, +}; #[unstable(feature = "read_buf", issue = "78485")] pub use self::readbuf::ReadBuf; diff --git a/library/std/src/os/linux/raw.rs b/library/std/src/os/linux/raw.rs index cd92dcabdf520..d78049bce24c2 100644 --- a/library/std/src/os/linux/raw.rs +++ b/library/std/src/os/linux/raw.rs @@ -239,6 +239,7 @@ mod arch { target_arch = "riscv32" ))] mod arch { + #[stable(feature = "raw_ext", since = "1.1.0")] pub use libc::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t}; } diff --git a/library/std/src/os/unix/io/raw.rs b/library/std/src/os/unix/io/raw.rs index 6317e31747119..a4d2ba797d9c4 100644 --- a/library/std/src/os/unix/io/raw.rs +++ b/library/std/src/os/unix/io/raw.rs @@ -2,4 +2,5 @@ #![stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "rust1", since = "1.0.0")] pub use crate::os::fd::raw::*; diff --git a/src/test/ui/lint/lint-pub-unreachable-for-nested-glob.rs b/src/test/ui/lint/lint-pub-unreachable-for-nested-glob.rs new file mode 100644 index 0000000000000..2df6d08e7aeb6 --- /dev/null +++ b/src/test/ui/lint/lint-pub-unreachable-for-nested-glob.rs @@ -0,0 +1,28 @@ +// check-pass + +#![deny(unreachable_pub)] + +pub use self::m1::*; + +mod m1 { + pub use self::m2::*; + + mod m2 { + pub struct Item1; + pub struct Item2; + } +} + + +pub use self::o1::{ Item42, Item24 }; + +mod o1 { + pub use self::o2::{ Item42, Item24 }; + + mod o2 { + pub struct Item42; + pub struct Item24; + } +} + +fn main() {} diff --git a/src/tools/rustfmt/src/lib.rs b/src/tools/rustfmt/src/lib.rs index ad23b16e02ec1..fae8080c02e41 100644 --- a/src/tools/rustfmt/src/lib.rs +++ b/src/tools/rustfmt/src/lib.rs @@ -3,6 +3,7 @@ #![warn(unreachable_pub)] #![recursion_limit = "256"] #![allow(clippy::match_like_matches_macro)] +#![allow(unreachable_pub)] #[macro_use] extern crate derive_new;