diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 85646b575bff6..e87bac6114dd6 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -75,6 +75,9 @@ 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; @@ -82,7 +85,7 @@ pub trait DefIdVisitor<'tcx> { fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'tcx, Self> { DefIdVisitorSkeleton { def_id_visitor: self, - visited_opaque_tys: Default::default(), + visited_tys: Default::default(), dummy: Default::default(), } } @@ -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, + visited_tys: FxHashSet>, dummy: PhantomData>, } @@ -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, ..) @@ -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)); } @@ -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, @@ -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 @@ -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 @@ -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, @@ -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>], @@ -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() }); @@ -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,