Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 20 additions & 10 deletions compiler/rustc_privacy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,17 @@ pub trait DefIdVisitor<'tcx> {
}

fn tcx(&self) -> TyCtxt<'tcx>;
/// NOTE: Def-id visiting should be idempotent (or at least produce duplicated errors),
/// because `DefIdVisitorSkeleton` will use caching and sometimes avoid visiting duplicate
/// def-ids. All the current visitors follow this rule.
fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display)
-> Self::Result;

/// Not overridden, but used to actually visit types and traits.
fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'tcx, Self> {
DefIdVisitorSkeleton {
def_id_visitor: self,
visited_opaque_tys: Default::default(),
visited_tys: Default::default(),
dummy: Default::default(),
}
}
Expand All @@ -102,7 +105,7 @@ pub trait DefIdVisitor<'tcx> {

pub struct DefIdVisitorSkeleton<'v, 'tcx, V: ?Sized> {
def_id_visitor: &'v mut V,
visited_opaque_tys: FxHashSet<DefId>,
visited_tys: FxHashSet<Ty<'tcx>>,
dummy: PhantomData<TyCtxt<'tcx>>,
}

Expand Down Expand Up @@ -183,7 +186,8 @@ where
let tcx = self.def_id_visitor.tcx();
// GenericArgs are not visited here because they are visited below
// in `super_visit_with`.
match *ty.kind() {
let ty_kind = *ty.kind();
match ty_kind {
ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), ..)
| ty::Foreign(def_id)
| ty::FnDef(def_id, ..)
Expand All @@ -197,7 +201,7 @@ where
// Default type visitor doesn't visit signatures of fn types.
// Something like `fn() -> Priv {my_func}` is considered a private type even if
// `my_func` is public, so we need to visit signatures.
if let ty::FnDef(..) = ty.kind() {
if let ty::FnDef(..) = ty_kind {
// FIXME: this should probably use `args` from `FnDef`
try_visit!(tcx.fn_sig(def_id).instantiate_identity().visit_with(self));
}
Expand All @@ -220,6 +224,12 @@ where
// free type aliases, but this isn't done yet.
return V::Result::output();
}
if !self.visited_tys.insert(ty) {
// Avoid repeatedly visiting alias types (including projections).
// This helps with special cases like #145741, but doesn't introduce
// too much overhead in general case, unlike caching for other types.
return V::Result::output();
}

try_visit!(self.def_id_visitor.visit_def_id(
data.def_id,
Expand Down Expand Up @@ -259,7 +269,7 @@ where
}
ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
// Skip repeated `Opaque`s to avoid infinite recursion.
if self.visited_opaque_tys.insert(def_id) {
if self.visited_tys.insert(ty) {
// The intent is to treat `impl Trait1 + Trait2` identically to
// `dyn Trait1 + Trait2`. Therefore we ignore def-id of the opaque type itself
// (it either has no visibility, or its visibility is insignificant, like
Expand Down Expand Up @@ -929,7 +939,7 @@ impl<'tcx> NamePrivacyVisitor<'tcx> {

// Checks that a field in a struct constructor (expression or pattern) is accessible.
fn check_field(
&mut self,
&self,
hir_id: hir::HirId, // ID of the field use
use_ctxt: Span, // syntax context of the field name at the use site
def: ty::AdtDef<'tcx>, // definition of the struct or enum
Expand All @@ -947,7 +957,7 @@ impl<'tcx> NamePrivacyVisitor<'tcx> {

// Checks that a field in a struct constructor (expression or pattern) is accessible.
fn emit_unreachable_field_error(
&mut self,
&self,
fields: Vec<(Symbol, Span, bool /* field is present */)>,
def: ty::AdtDef<'tcx>, // definition of the struct or enum
update_syntax: Option<Span>,
Expand Down Expand Up @@ -1010,7 +1020,7 @@ impl<'tcx> NamePrivacyVisitor<'tcx> {
}

fn check_expanded_fields(
&mut self,
&self,
adt: ty::AdtDef<'tcx>,
variant: &'tcx ty::VariantDef,
fields: &[hir::ExprField<'tcx>],
Expand Down Expand Up @@ -1148,7 +1158,7 @@ impl<'tcx> TypePrivacyVisitor<'tcx> {
result.is_break()
}

fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
fn check_def_id(&self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
let is_error = !self.item_is_accessible(def_id);
if is_error {
self.tcx.dcx().emit_err(ItemIsPrivate { span: self.span, kind, descr: descr.into() });
Expand Down Expand Up @@ -1405,7 +1415,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
self
}

fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
fn check_def_id(&self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
if self.leaks_private_dep(def_id) {
self.tcx.emit_node_span_lint(
lint::builtin::EXPORTED_PRIVATE_DEPENDENCIES,
Expand Down
Loading