mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
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
This commit is contained in:
parent
092e1c9d23
commit
3a77bb86ff
@ -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.
|
||||
//
|
||||
|
@ -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};
|
||||
|
@ -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<Id = LocalDefId> {
|
||||
pub map: FxHashMap<Id, AccessLevel>,
|
||||
}
|
||||
|
@ -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<CrateStoreDyn>,
|
||||
pub visibilities: FxHashMap<LocalDefId, Visibility>,
|
||||
pub access_levels: AccessLevels,
|
||||
pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
|
||||
pub maybe_unused_trait_imports: FxHashSet<LocalDefId>,
|
||||
pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
|
||||
|
@ -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<AccessLevel>,
|
||||
) -> Option<AccessLevel> {
|
||||
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<AccessLevel>) -> Option<AccessLevel> {
|
||||
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 <https://github.com/rust-lang/rust/pull/57922#discussion_r251234202>.
|
||||
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::<AccessLevel>::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::<AccessLevel>::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)
|
||||
}
|
||||
|
237
compiler/rustc_resolve/src/access_levels.rs
Normal file
237
compiler/rustc_resolve/src/access_levels.rs
Normal file
@ -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<AccessLevel>,
|
||||
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::<Vec<_>>();
|
||||
|
||||
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<AccessLevel>,
|
||||
) -> Option<AccessLevel> {
|
||||
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<AccessLevel>,
|
||||
) -> Option<AccessLevel> {
|
||||
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!(),
|
||||
}
|
||||
}
|
||||
}
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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<NodeId>;
|
||||
|
||||
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<NodeId>,
|
||||
confused_type_with_std_module: FxHashMap<Span, Span>,
|
||||
|
||||
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());
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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")]
|
||||
|
@ -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};
|
||||
|
@ -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
|
||||
|
@ -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 = "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::stdio::{StderrLock, StdinLock, StdoutLock};
|
||||
#[unstable(feature = "print_internals", issue = "none")]
|
||||
pub use self::stdio::{_eprint, _print};
|
||||
#[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;
|
||||
|
@ -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};
|
||||
}
|
||||
|
||||
|
@ -2,4 +2,5 @@
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use crate::os::fd::raw::*;
|
||||
|
28
src/test/ui/lint/lint-pub-unreachable-for-nested-glob.rs
Normal file
28
src/test/ui/lint/lint-pub-unreachable-for-nested-glob.rs
Normal file
@ -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() {}
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user