mirror of
https://github.com/rust-lang/rust.git
synced 2026-01-25 07:48:44 +00:00
Auto merge of #144554 - cjgillot:no-hir-eff-vis, r=petrochenkov
Use less HIR to compute effective visibility. r? `@ghost`
This commit is contained in:
@@ -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 trait_item_ref in trait_item_refs {
|
||||
self.update(trait_item_ref.owner_id.def_id, item_ev, Level::Reachable);
|
||||
for assoc_item in self.tcx.associated_items(owner_id).in_definition_order() {
|
||||
if assoc_item.is_impl_trait_in_trait() {
|
||||
continue;
|
||||
}
|
||||
|
||||
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<UnreachableTy> for ReachableTy<UnreachableTy> { ... }`
|
||||
@@ -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::<true>(
|
||||
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(item.owner_id.def_id, item_ev).generics().predicates().ty().trait_ref();
|
||||
self.reach(owner_id.def_id, item_ev).generics().predicates().ty().trait_ref();
|
||||
|
||||
for impl_item_ref in impl_.items {
|
||||
let def_id = impl_item_ref.owner_id.def_id;
|
||||
for assoc_item in self.tcx.associated_items(owner_id).in_definition_order() {
|
||||
if assoc_item.is_impl_trait_in_trait() {
|
||||
continue;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -1838,8 +1849,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 {
|
||||
@@ -1848,10 +1865,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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user