Calculate visibilities once in resolve
Then use them through a query based on resolver outputs
This commit is contained in:
parent
cb2462c53f
commit
cee5521a03
26 changed files with 323 additions and 409 deletions
|
@ -1,6 +1,7 @@
|
|||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(nll)]
|
||||
#![feature(or_patterns)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
use rustc_attr as attr;
|
||||
|
@ -14,13 +15,14 @@ use rustc_hir::{AssocItemKind, HirIdSet, Node, PatKind};
|
|||
use rustc_middle::bug;
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::fold::TypeVisitor;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::subst::InternalSubsts;
|
||||
use rustc_middle::ty::{self, 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 std::marker::PhantomData;
|
||||
|
@ -233,125 +235,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn def_id_visibility<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
) -> (ty::Visibility, Span, &'static str) {
|
||||
match def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id)) {
|
||||
Some(hir_id) => {
|
||||
let vis = match tcx.hir().get(hir_id) {
|
||||
Node::Item(item) => &item.vis,
|
||||
Node::ForeignItem(foreign_item) => &foreign_item.vis,
|
||||
Node::MacroDef(macro_def) => {
|
||||
if tcx.sess.contains_name(¯o_def.attrs, sym::macro_export) {
|
||||
return (ty::Visibility::Public, macro_def.span, "public");
|
||||
} else {
|
||||
¯o_def.vis
|
||||
}
|
||||
}
|
||||
Node::TraitItem(..) | Node::Variant(..) => {
|
||||
return def_id_visibility(tcx, tcx.hir().get_parent_did(hir_id).to_def_id());
|
||||
}
|
||||
Node::ImplItem(impl_item) => {
|
||||
match tcx.hir().get(tcx.hir().get_parent_item(hir_id)) {
|
||||
Node::Item(item) => match &item.kind {
|
||||
hir::ItemKind::Impl { of_trait: None, .. } => &impl_item.vis,
|
||||
hir::ItemKind::Impl { of_trait: Some(trait_ref), .. } => {
|
||||
return def_id_visibility(tcx, trait_ref.path.res.def_id());
|
||||
}
|
||||
kind => bug!("unexpected item kind: {:?}", kind),
|
||||
},
|
||||
node => bug!("unexpected node kind: {:?}", node),
|
||||
}
|
||||
}
|
||||
Node::Ctor(vdata) => {
|
||||
let parent_hir_id = tcx.hir().get_parent_node(hir_id);
|
||||
match tcx.hir().get(parent_hir_id) {
|
||||
Node::Variant(..) => {
|
||||
let parent_did = tcx.hir().local_def_id(parent_hir_id);
|
||||
let (mut ctor_vis, mut span, mut descr) =
|
||||
def_id_visibility(tcx, parent_did.to_def_id());
|
||||
|
||||
let adt_def = tcx.adt_def(tcx.hir().get_parent_did(hir_id).to_def_id());
|
||||
let ctor_did = tcx.hir().local_def_id(vdata.ctor_hir_id().unwrap());
|
||||
let variant = adt_def.variant_with_ctor_id(ctor_did.to_def_id());
|
||||
|
||||
if variant.is_field_list_non_exhaustive()
|
||||
&& ctor_vis == ty::Visibility::Public
|
||||
{
|
||||
ctor_vis =
|
||||
ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
|
||||
let attrs = tcx.get_attrs(variant.def_id);
|
||||
span = tcx
|
||||
.sess
|
||||
.find_by_name(&attrs, sym::non_exhaustive)
|
||||
.unwrap()
|
||||
.span;
|
||||
descr = "crate-visible";
|
||||
}
|
||||
|
||||
return (ctor_vis, span, descr);
|
||||
}
|
||||
Node::Item(..) => {
|
||||
let item = match tcx.hir().get(parent_hir_id) {
|
||||
Node::Item(item) => item,
|
||||
node => bug!("unexpected node kind: {:?}", node),
|
||||
};
|
||||
let (mut ctor_vis, mut span, mut descr) = (
|
||||
ty::Visibility::from_hir(&item.vis, parent_hir_id, tcx),
|
||||
item.vis.span,
|
||||
item.vis.node.descr(),
|
||||
);
|
||||
for field in vdata.fields() {
|
||||
let field_vis = ty::Visibility::from_hir(&field.vis, hir_id, tcx);
|
||||
if ctor_vis.is_at_least(field_vis, tcx) {
|
||||
ctor_vis = field_vis;
|
||||
span = field.vis.span;
|
||||
descr = field.vis.node.descr();
|
||||
}
|
||||
}
|
||||
|
||||
// If the structure is marked as non_exhaustive then lower the
|
||||
// visibility to within the crate.
|
||||
if ctor_vis == ty::Visibility::Public {
|
||||
let adt_def =
|
||||
tcx.adt_def(tcx.hir().get_parent_did(hir_id).to_def_id());
|
||||
if adt_def.non_enum_variant().is_field_list_non_exhaustive() {
|
||||
ctor_vis =
|
||||
ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
|
||||
span = tcx
|
||||
.sess
|
||||
.find_by_name(&item.attrs, sym::non_exhaustive)
|
||||
.unwrap()
|
||||
.span;
|
||||
descr = "crate-visible";
|
||||
}
|
||||
}
|
||||
|
||||
return (ctor_vis, span, descr);
|
||||
}
|
||||
node => bug!("unexpected node kind: {:?}", node),
|
||||
}
|
||||
}
|
||||
Node::Expr(expr) => {
|
||||
return (
|
||||
ty::Visibility::Restricted(tcx.parent_module(expr.hir_id).to_def_id()),
|
||||
expr.span,
|
||||
"private",
|
||||
);
|
||||
}
|
||||
node => bug!("unexpected node kind: {:?}", node),
|
||||
};
|
||||
(ty::Visibility::from_hir(vis, hir_id, tcx), vis.span, vis.node.descr())
|
||||
}
|
||||
None => {
|
||||
let vis = tcx.visibility(def_id);
|
||||
let descr = if vis == ty::Visibility::Public { "public" } else { "private" };
|
||||
(vis, tcx.def_span(def_id), descr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn min(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'_>) -> ty::Visibility {
|
||||
if vis1.is_at_least(vis2, tcx) { vis2 } else { vis1 }
|
||||
}
|
||||
|
@ -424,7 +307,7 @@ trait VisibilityLike: Sized {
|
|||
impl VisibilityLike for ty::Visibility {
|
||||
const MAX: Self = ty::Visibility::Public;
|
||||
fn new_min(find: &FindMin<'_, '_, Self>, def_id: DefId) -> Self {
|
||||
min(def_id_visibility(find.tcx, def_id).0, find.min, find.tcx)
|
||||
min(find.tcx.visibility(def_id), find.min, find.tcx)
|
||||
}
|
||||
}
|
||||
impl VisibilityLike for Option<AccessLevel> {
|
||||
|
@ -534,17 +417,16 @@ impl EmbargoVisitor<'tcx> {
|
|||
let hir_id = item_id.id;
|
||||
let item_def_id = self.tcx.hir().local_def_id(hir_id);
|
||||
let def_kind = self.tcx.def_kind(item_def_id);
|
||||
let item = self.tcx.hir().expect_item(hir_id);
|
||||
let vis = ty::Visibility::from_hir(&item.vis, hir_id, self.tcx);
|
||||
let vis = self.tcx.visibility(item_def_id);
|
||||
self.update_macro_reachable_def(hir_id, def_kind, vis, defining_mod);
|
||||
}
|
||||
if let Some(exports) = self.tcx.module_exports(module_def_id) {
|
||||
for export in exports {
|
||||
if export.vis.is_accessible_from(defining_mod, self.tcx) {
|
||||
if let Res::Def(def_kind, def_id) = export.res {
|
||||
let vis = def_id_visibility(self.tcx, def_id).0;
|
||||
if let Some(def_id) = def_id.as_local() {
|
||||
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
let vis = self.tcx.visibility(def_id.to_def_id());
|
||||
self.update_macro_reachable_def(hir_id, def_kind, vis, defining_mod);
|
||||
}
|
||||
}
|
||||
|
@ -596,7 +478,7 @@ impl EmbargoVisitor<'tcx> {
|
|||
{
|
||||
for field in struct_def.fields() {
|
||||
let field_vis =
|
||||
ty::Visibility::from_hir(&field.vis, field.hir_id, self.tcx);
|
||||
self.tcx.visibility(self.tcx.hir().local_def_id(field.hir_id));
|
||||
if field_vis.is_accessible_from(module, self.tcx) {
|
||||
self.reach(field.hir_id, level).ty();
|
||||
}
|
||||
|
@ -1015,11 +897,10 @@ impl DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
|
|||
}
|
||||
fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) -> bool {
|
||||
if let Some(def_id) = def_id.as_local() {
|
||||
let hir_id = self.ev.tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
if let ((ty::Visibility::Public, ..), _)
|
||||
| (_, Some(AccessLevel::ReachableFromImplTrait)) =
|
||||
(def_id_visibility(self.tcx(), def_id.to_def_id()), self.access_level)
|
||||
if let (ty::Visibility::Public, _) | (_, Some(AccessLevel::ReachableFromImplTrait)) =
|
||||
(self.tcx().visibility(def_id.to_def_id()), self.access_level)
|
||||
{
|
||||
let hir_id = self.ev.tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
self.ev.update(hir_id, self.access_level);
|
||||
}
|
||||
}
|
||||
|
@ -1184,9 +1065,7 @@ impl<'tcx> TypePrivacyVisitor<'tcx> {
|
|||
}
|
||||
|
||||
fn item_is_accessible(&self, did: DefId) -> bool {
|
||||
def_id_visibility(self.tcx, did)
|
||||
.0
|
||||
.is_accessible_from(self.current_item.to_def_id(), self.tcx)
|
||||
self.tcx.visibility(did).is_accessible_from(self.current_item.to_def_id(), self.tcx)
|
||||
}
|
||||
|
||||
// Take node-id of an expression or pattern and check its type for privacy.
|
||||
|
@ -1840,8 +1719,21 @@ impl SearchInterfaceForPrivateItemsVisitor<'tcx> {
|
|||
None => return false,
|
||||
};
|
||||
|
||||
let (vis, vis_span, vis_descr) = def_id_visibility(self.tcx, def_id);
|
||||
let vis = self.tcx.visibility(def_id);
|
||||
if !vis.is_at_least(self.required_visibility, self.tcx) {
|
||||
let vis_descr = match vis {
|
||||
ty::Visibility::Public => "public",
|
||||
ty::Visibility::Invisible => "private",
|
||||
ty::Visibility::Restricted(vis_def_id) => {
|
||||
if vis_def_id == self.tcx.parent_module(hir_id).to_def_id() {
|
||||
"private"
|
||||
} else if vis_def_id.is_top_level_module() {
|
||||
"crate-private"
|
||||
} else {
|
||||
"restricted"
|
||||
}
|
||||
}
|
||||
};
|
||||
let make_msg = || format!("{} {} `{}` in public interface", vis_descr, kind, descr);
|
||||
if self.has_pub_restricted || self.has_old_errors || self.in_assoc_ty {
|
||||
let mut err = if kind == "trait" {
|
||||
|
@ -1849,6 +1741,8 @@ impl SearchInterfaceForPrivateItemsVisitor<'tcx> {
|
|||
} else {
|
||||
struct_span_err!(self.tcx.sess, self.span, E0446, "{}", make_msg())
|
||||
};
|
||||
let vis_span =
|
||||
self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id));
|
||||
err.span_label(self.span, format!("can't leak {} {}", vis_descr, kind));
|
||||
err.span_label(vis_span, format!("`{}` declared as {}", descr, vis_descr));
|
||||
err.emit();
|
||||
|
@ -1965,7 +1859,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
|
|||
|
||||
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
|
||||
let tcx = self.tcx;
|
||||
let item_visibility = ty::Visibility::from_hir(&item.vis, item.hir_id, tcx);
|
||||
let item_visibility = tcx.visibility(tcx.hir().local_def_id(item.hir_id).to_def_id());
|
||||
|
||||
match item.kind {
|
||||
// Crates are always public.
|
||||
|
@ -2019,7 +1913,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
|
|||
// Subitems of foreign modules have their own publicity.
|
||||
hir::ItemKind::ForeignMod(ref foreign_mod) => {
|
||||
for foreign_item in foreign_mod.items {
|
||||
let vis = ty::Visibility::from_hir(&foreign_item.vis, item.hir_id, tcx);
|
||||
let vis = tcx.visibility(tcx.hir().local_def_id(foreign_item.hir_id));
|
||||
self.check(foreign_item.hir_id, vis).generics().predicates().ty();
|
||||
}
|
||||
}
|
||||
|
@ -2028,7 +1922,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
|
|||
self.check(item.hir_id, item_visibility).generics().predicates();
|
||||
|
||||
for field in struct_def.fields() {
|
||||
let field_visibility = ty::Visibility::from_hir(&field.vis, item.hir_id, tcx);
|
||||
let field_visibility = tcx.visibility(tcx.hir().local_def_id(field.hir_id));
|
||||
self.check(field.hir_id, min(item_visibility, field_visibility, tcx)).ty();
|
||||
}
|
||||
}
|
||||
|
@ -2040,10 +1934,9 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
|
|||
let impl_vis = ty::Visibility::of_impl(item.hir_id, tcx, &Default::default());
|
||||
self.check(item.hir_id, impl_vis).generics().predicates();
|
||||
for impl_item_ref in items {
|
||||
let impl_item = tcx.hir().impl_item(impl_item_ref.id);
|
||||
let impl_item_vis = if of_trait.is_none() {
|
||||
min(
|
||||
ty::Visibility::from_hir(&impl_item.vis, item.hir_id, tcx),
|
||||
tcx.visibility(tcx.hir().local_def_id(impl_item_ref.id.hir_id)),
|
||||
impl_vis,
|
||||
tcx,
|
||||
)
|
||||
|
@ -2064,6 +1957,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
|
|||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
*providers = Providers {
|
||||
visibility,
|
||||
privacy_access_levels,
|
||||
check_private_in_public,
|
||||
check_mod_privacy,
|
||||
|
@ -2071,6 +1965,55 @@ pub fn provide(providers: &mut Providers) {
|
|||
};
|
||||
}
|
||||
|
||||
fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility {
|
||||
let def_id = def_id.expect_local();
|
||||
match tcx.visibilities.get(&def_id) {
|
||||
Some(vis) => *vis,
|
||||
None => {
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
match tcx.hir().get(hir_id) {
|
||||
// Unique types created for closures participate in type privacy checking.
|
||||
// They have visibilities inherited from the module they are defined in.
|
||||
Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => {
|
||||
ty::Visibility::Restricted(tcx.parent_module(hir_id).to_def_id())
|
||||
}
|
||||
// - AST lowering may clone `use` items and the clones don't
|
||||
// get their entries in the resolver's visibility table.
|
||||
// - AST lowering also creates opaque type items with inherited visibilies.
|
||||
// Visibility on them should have no effect, but to avoid the visibility
|
||||
// query failing on some items, we provide it for opaque types as well.
|
||||
Node::Item(hir::Item {
|
||||
vis,
|
||||
kind: hir::ItemKind::Use(..) | hir::ItemKind::OpaqueTy(..),
|
||||
..
|
||||
}) => ty::Visibility::from_hir(vis, hir_id, tcx),
|
||||
// Visibilities of trait impl items are inherited from their traits
|
||||
// and are not filled in resolve.
|
||||
Node::ImplItem(impl_item) => {
|
||||
match tcx.hir().get(tcx.hir().get_parent_item(hir_id)) {
|
||||
Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Impl { of_trait: Some(tr), .. },
|
||||
..
|
||||
}) => tr.path.res.opt_def_id().map_or_else(
|
||||
|| {
|
||||
tcx.sess.delay_span_bug(tr.path.span, "trait without a def-id");
|
||||
ty::Visibility::Public
|
||||
},
|
||||
|def_id| tcx.visibility(def_id),
|
||||
),
|
||||
_ => span_bug!(impl_item.span, "the parent is not a trait impl"),
|
||||
}
|
||||
}
|
||||
_ => span_bug!(
|
||||
tcx.def_span(def_id),
|
||||
"visibility table unexpectedly missing a def-id: {:?}",
|
||||
def_id,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||
// Check privacy of names not checked in previous compilation stages.
|
||||
let mut visitor = NamePrivacyVisitor { tcx, maybe_typeck_results: None, current_item: None };
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue