Skip to content

Commit 6501e64

Browse files
committed
Auto merge of rust-lang#147486 - petrochenkov:optpriv, r=lcnr
privacy: Introduce some caching to type visiting in `DefIdVisitorSkeleton` The caching fixes compilation speed issues in special cases like rust-lang#145741, without introducing too much overhead in general cases. I tried to cache more, but it caused regressions from the caching overhead, like it can be seen from benchmark runs below. Inspired by rust-lang#146128. Closes rust-lang#145741.
2 parents 11d2046 + f9464f8 commit 6501e64

File tree

1 file changed

+20
-10
lines changed
  • compiler/rustc_privacy/src

1 file changed

+20
-10
lines changed

compiler/rustc_privacy/src/lib.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,17 @@ pub trait DefIdVisitor<'tcx> {
7575
}
7676

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

8184
/// Not overridden, but used to actually visit types and traits.
8285
fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'tcx, Self> {
8386
DefIdVisitorSkeleton {
8487
def_id_visitor: self,
85-
visited_opaque_tys: Default::default(),
88+
visited_tys: Default::default(),
8689
dummy: Default::default(),
8790
}
8891
}
@@ -102,7 +105,7 @@ pub trait DefIdVisitor<'tcx> {
102105

103106
pub struct DefIdVisitorSkeleton<'v, 'tcx, V: ?Sized> {
104107
def_id_visitor: &'v mut V,
105-
visited_opaque_tys: FxHashSet<DefId>,
108+
visited_tys: FxHashSet<Ty<'tcx>>,
106109
dummy: PhantomData<TyCtxt<'tcx>>,
107110
}
108111

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

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

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

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

10121022
fn check_expanded_fields(
1013-
&mut self,
1023+
&self,
10141024
adt: ty::AdtDef<'tcx>,
10151025
variant: &'tcx ty::VariantDef,
10161026
fields: &[hir::ExprField<'tcx>],
@@ -1148,7 +1158,7 @@ impl<'tcx> TypePrivacyVisitor<'tcx> {
11481158
result.is_break()
11491159
}
11501160

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

1408-
fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
1418+
fn check_def_id(&self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
14091419
if self.leaks_private_dep(def_id) {
14101420
self.tcx.emit_node_span_lint(
14111421
lint::builtin::EXPORTED_PRIVATE_DEPENDENCIES,

0 commit comments

Comments
 (0)