diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index e12e74c0f1a6b..8795700d49328 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -26,9 +26,9 @@ use rustc_errors::{MultiSpan, listify}; use rustc_hir as hir; use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId, LocalModDefId}; +use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::intravisit::{self, InferKind, Visitor}; -use rustc_hir::{AmbigArg, ForeignItemId, ItemId, PatKind, find_attr}; +use rustc_hir::{AmbigArg, ForeignItemId, ItemId, OwnerId, PatKind, find_attr}; use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level}; use rustc_middle::query::Providers; use rustc_middle::ty::print::PrintTraitRefExt as _; @@ -599,7 +599,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { DefKind::Struct | DefKind::Union => { // While structs and unions have type privacy, their fields do not. let struct_def = self.tcx.adt_def(def_id); - for field in struct_def.non_enum_variant().fields.iter() { + for field in &struct_def.non_enum_variant().fields { let def_id = field.did.expect_local(); let field_vis = self.tcx.local_visibility(def_id); if field_vis.is_accessible_from(module, self.tcx) { @@ -637,45 +637,49 @@ impl<'tcx> EmbargoVisitor<'tcx> { } } -impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { +impl<'tcx> EmbargoVisitor<'tcx> { + fn check_def_id(&mut self, owner_id: OwnerId) { // Update levels of nested things and mark all items // in interfaces of reachable items as reachable. - let item_ev = self.get(item.owner_id.def_id); - match item.kind { + let item_ev = self.get(owner_id.def_id); + match self.tcx.def_kind(owner_id) { // The interface is empty, and no nested items. - hir::ItemKind::Use(..) - | hir::ItemKind::ExternCrate(..) - | hir::ItemKind::GlobalAsm { .. } => {} - // The interface is empty, and all nested items are processed by `visit_item`. - hir::ItemKind::Mod(..) => {} - hir::ItemKind::Macro(_, macro_def, _) => { + DefKind::Use | DefKind::ExternCrate | DefKind::GlobalAsm => {} + // The interface is empty, and all nested items are processed by `check_def_id`. + DefKind::Mod => {} + DefKind::Macro { .. } => { if let Some(item_ev) = item_ev { - self.update_reachability_from_macro(item.owner_id.def_id, macro_def, item_ev); + let (_, macro_def, _) = + self.tcx.hir_expect_item(owner_id.def_id).expect_macro(); + self.update_reachability_from_macro(owner_id.def_id, macro_def, item_ev); } } - hir::ItemKind::Const(..) - | hir::ItemKind::Static(..) - | hir::ItemKind::Fn { .. } - | hir::ItemKind::TyAlias(..) => { + DefKind::ForeignTy + | DefKind::Const + | DefKind::Static { .. } + | DefKind::Fn + | DefKind::TyAlias => { if let Some(item_ev) = item_ev { - self.reach(item.owner_id.def_id, item_ev).generics().predicates().ty(); + self.reach(owner_id.def_id, item_ev).generics().predicates().ty(); } } - hir::ItemKind::Trait(.., trait_item_refs) => { + DefKind::Trait => { if let Some(item_ev) = item_ev { - self.reach(item.owner_id.def_id, item_ev).generics().predicates(); + self.reach(owner_id.def_id, item_ev).generics().predicates(); + + for assoc_item in self.tcx.associated_items(owner_id).in_definition_order() { + if assoc_item.is_impl_trait_in_trait() { + continue; + } - for trait_item_ref in trait_item_refs { - self.update(trait_item_ref.owner_id.def_id, item_ev, Level::Reachable); + let def_id = assoc_item.def_id.expect_local(); + self.update(def_id, item_ev, Level::Reachable); let tcx = self.tcx; - let mut reach = self.reach(trait_item_ref.owner_id.def_id, item_ev); + let mut reach = self.reach(def_id, item_ev); reach.generics().predicates(); - if let DefKind::AssocTy = tcx.def_kind(trait_item_ref.owner_id) - && !tcx.defaultness(trait_item_ref.owner_id).has_value() - { + if assoc_item.is_type() && !assoc_item.defaultness(tcx).has_value() { // No type to visit. } else { reach.ty(); @@ -683,12 +687,12 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } } } - hir::ItemKind::TraitAlias(..) => { + DefKind::TraitAlias => { if let Some(item_ev) = item_ev { - self.reach(item.owner_id.def_id, item_ev).generics().predicates(); + self.reach(owner_id.def_id, item_ev).generics().predicates(); } } - hir::ItemKind::Impl(impl_) => { + DefKind::Impl { of_trait } => { // Type inference is very smart sometimes. It can make an impl reachable even some // components of its type or trait are unreachable. E.g. methods of // `impl ReachableTrait for ReachableTy { ... }` @@ -700,19 +704,23 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { // without knowing both "shallow" version of its self type and "shallow" version of // its trait if it exists (which require reaching the `DefId`s in them). let item_ev = EffectiveVisibility::of_impl::( - item.owner_id.def_id, + owner_id.def_id, self.tcx, &self.effective_visibilities, ); - self.update_eff_vis(item.owner_id.def_id, item_ev, None, Level::Direct); + self.update_eff_vis(owner_id.def_id, item_ev, None, Level::Direct); + + self.reach(owner_id.def_id, item_ev).generics().predicates().ty().trait_ref(); - self.reach(item.owner_id.def_id, item_ev).generics().predicates().ty().trait_ref(); + for assoc_item in self.tcx.associated_items(owner_id).in_definition_order() { + if assoc_item.is_impl_trait_in_trait() { + continue; + } - for impl_item_ref in impl_.items { - let def_id = impl_item_ref.owner_id.def_id; + let def_id = assoc_item.def_id.expect_local(); let max_vis = - impl_.of_trait.is_none().then(|| self.tcx.local_visibility(def_id)); + if of_trait { None } else { Some(self.tcx.local_visibility(def_id)) }; self.update_eff_vis(def_id, item_ev, max_vis, Level::Direct); if let Some(impl_item_ev) = self.get(def_id) { @@ -720,65 +728,76 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } } } - hir::ItemKind::Enum(_, _, ref def) => { + DefKind::Enum => { if let Some(item_ev) = item_ev { - self.reach(item.owner_id.def_id, item_ev).generics().predicates(); + self.reach(owner_id.def_id, item_ev).generics().predicates(); } - for variant in def.variants { + let def = self.tcx.adt_def(owner_id); + for variant in def.variants() { if let Some(item_ev) = item_ev { - self.update(variant.def_id, item_ev, Level::Reachable); + self.update(variant.def_id.expect_local(), item_ev, Level::Reachable); } - if let Some(variant_ev) = self.get(variant.def_id) { - if let Some(ctor_def_id) = variant.data.ctor_def_id() { - self.update(ctor_def_id, variant_ev, Level::Reachable); + if let Some(variant_ev) = self.get(variant.def_id.expect_local()) { + if let Some(ctor_def_id) = variant.ctor_def_id() { + self.update(ctor_def_id.expect_local(), variant_ev, Level::Reachable); } - for field in variant.data.fields() { - self.update(field.def_id, variant_ev, Level::Reachable); - self.reach(field.def_id, variant_ev).ty(); + for field in &variant.fields { + let field = field.did.expect_local(); + self.update(field, variant_ev, Level::Reachable); + self.reach(field, variant_ev).ty(); } // Corner case: if the variant is reachable, but its // enum is not, make the enum reachable as well. - self.reach(item.owner_id.def_id, variant_ev).ty(); + self.reach(owner_id.def_id, variant_ev).ty(); } - if let Some(ctor_def_id) = variant.data.ctor_def_id() { - if let Some(ctor_ev) = self.get(ctor_def_id) { - self.reach(item.owner_id.def_id, ctor_ev).ty(); + if let Some(ctor_def_id) = variant.ctor_def_id() { + if let Some(ctor_ev) = self.get(ctor_def_id.expect_local()) { + self.reach(owner_id.def_id, ctor_ev).ty(); } } } } - hir::ItemKind::ForeignMod { items, .. } => { - for foreign_item in items { - if let Some(foreign_item_ev) = self.get(foreign_item.owner_id.def_id) { - self.reach(foreign_item.owner_id.def_id, foreign_item_ev) - .generics() - .predicates() - .ty(); - } - } - } - hir::ItemKind::Struct(_, _, ref struct_def) - | hir::ItemKind::Union(_, _, ref struct_def) => { + DefKind::Struct | DefKind::Union => { + let def = self.tcx.adt_def(owner_id).non_enum_variant(); if let Some(item_ev) = item_ev { - self.reach(item.owner_id.def_id, item_ev).generics().predicates(); - for field in struct_def.fields() { - self.update(field.def_id, item_ev, Level::Reachable); - if let Some(field_ev) = self.get(field.def_id) { - self.reach(field.def_id, field_ev).ty(); + self.reach(owner_id.def_id, item_ev).generics().predicates(); + for field in &def.fields { + let field = field.did.expect_local(); + self.update(field, item_ev, Level::Reachable); + if let Some(field_ev) = self.get(field) { + self.reach(field, field_ev).ty(); } } } - if let Some(ctor_def_id) = struct_def.ctor_def_id() { + if let Some(ctor_def_id) = def.ctor_def_id() { if let Some(item_ev) = item_ev { - self.update(ctor_def_id, item_ev, Level::Reachable); + self.update(ctor_def_id.expect_local(), item_ev, Level::Reachable); } - if let Some(ctor_ev) = self.get(ctor_def_id) { - self.reach(item.owner_id.def_id, ctor_ev).ty(); + if let Some(ctor_ev) = self.get(ctor_def_id.expect_local()) { + self.reach(owner_id.def_id, ctor_ev).ty(); } } } + // Contents are checked directly. + DefKind::ForeignMod => {} + DefKind::Field + | DefKind::Variant + | DefKind::AssocFn + | DefKind::AssocTy + | DefKind::AssocConst + | DefKind::TyParam + | DefKind::AnonConst + | DefKind::InlineConst + | DefKind::OpaqueTy + | DefKind::Closure + | DefKind::SyntheticCoroutineBody + | DefKind::ConstParam + | DefKind::LifetimeParam + | DefKind::Ctor(..) => { + bug!("should be checked while checking parent") + } } } } @@ -839,7 +858,7 @@ pub struct TestReachabilityVisitor<'a, 'tcx> { } impl<'a, 'tcx> TestReachabilityVisitor<'a, 'tcx> { - fn effective_visibility_diagnostic(&mut self, def_id: LocalDefId) { + fn effective_visibility_diagnostic(&self, def_id: LocalDefId) { if self.tcx.has_attr(def_id, sym::rustc_effective_visibility) { let mut error_msg = String::new(); let span = self.tcx.def_span(def_id.to_def_id()); @@ -859,43 +878,35 @@ impl<'a, 'tcx> TestReachabilityVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for TestReachabilityVisitor<'a, 'tcx> { - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - self.effective_visibility_diagnostic(item.owner_id.def_id); +impl<'a, 'tcx> TestReachabilityVisitor<'a, 'tcx> { + fn check_def_id(&self, owner_id: OwnerId) { + self.effective_visibility_diagnostic(owner_id.def_id); - match item.kind { - hir::ItemKind::Enum(_, _, ref def) => { - for variant in def.variants.iter() { - self.effective_visibility_diagnostic(variant.def_id); - if let Some(ctor_def_id) = variant.data.ctor_def_id() { - self.effective_visibility_diagnostic(ctor_def_id); + match self.tcx.def_kind(owner_id) { + DefKind::Enum => { + let def = self.tcx.adt_def(owner_id.def_id); + for variant in def.variants() { + self.effective_visibility_diagnostic(variant.def_id.expect_local()); + if let Some(ctor_def_id) = variant.ctor_def_id() { + self.effective_visibility_diagnostic(ctor_def_id.expect_local()); } - for field in variant.data.fields() { - self.effective_visibility_diagnostic(field.def_id); + for field in &variant.fields { + self.effective_visibility_diagnostic(field.did.expect_local()); } } } - hir::ItemKind::Struct(_, _, ref def) | hir::ItemKind::Union(_, _, ref def) => { + DefKind::Struct | DefKind::Union => { + let def = self.tcx.adt_def(owner_id.def_id).non_enum_variant(); if let Some(ctor_def_id) = def.ctor_def_id() { - self.effective_visibility_diagnostic(ctor_def_id); + self.effective_visibility_diagnostic(ctor_def_id.expect_local()); } - for field in def.fields() { - self.effective_visibility_diagnostic(field.def_id); + for field in &def.fields { + self.effective_visibility_diagnostic(field.did.expect_local()); } } _ => {} } } - - fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem<'tcx>) { - self.effective_visibility_diagnostic(item.owner_id.def_id); - } - fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem<'tcx>) { - self.effective_visibility_diagnostic(item.owner_id.def_id); - } - fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { - self.effective_visibility_diagnostic(item.owner_id.def_id); - } } ////////////////////////////////////////////////////////////////////////////////////// @@ -1836,8 +1847,14 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities { visitor.changed = false; } + let crate_items = tcx.hir_crate_items(()); loop { - tcx.hir_visit_all_item_likes_in_crate(&mut visitor); + for id in crate_items.free_items() { + visitor.check_def_id(id.owner_id); + } + for id in crate_items.foreign_items() { + visitor.check_def_id(id.owner_id); + } if visitor.changed { visitor.changed = false; } else { @@ -1846,10 +1863,11 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities { } visitor.effective_visibilities.check_invariants(tcx); - let mut check_visitor = + let check_visitor = TestReachabilityVisitor { tcx, effective_visibilities: &visitor.effective_visibilities }; - check_visitor.effective_visibility_diagnostic(CRATE_DEF_ID); - tcx.hir_visit_all_item_likes_in_crate(&mut check_visitor); + for id in crate_items.owners() { + check_visitor.check_def_id(id); + } tcx.arena.alloc(visitor.effective_visibilities) }