Auto merge of #87487 - lambinoo:I-64762_unreachable_pub_lint, r=petrochenkov
Fixes wrong unreachable_pub lints on nested and glob public reexport Linked issues: #64762 & #82064
This commit is contained in:
commit
df035a33b2
19 changed files with 359 additions and 218 deletions
|
|
@ -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…
Add table
Add a link
Reference in a new issue