From acca3984bd37ac5b2fb7fd138dd0f3739b4019b1 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 8 Oct 2025 17:45:42 +0300 Subject: [PATCH 1/5] privacy: Avoid some unnecessary mutability --- compiler/rustc_privacy/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index c9dbb204f61f7..81846741e4928 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -923,7 +923,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 @@ -941,7 +941,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, @@ -1004,7 +1004,7 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { } fn check_expanded_fields( - &mut self, + &self, adt: ty::AdtDef<'tcx>, variant: &'tcx ty::VariantDef, fields: &[hir::ExprField<'tcx>], @@ -1142,7 +1142,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() }); @@ -1401,7 +1401,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, From 62e357f6a7a58567fc962f889feccdae578f978e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 8 Oct 2025 19:23:45 +0300 Subject: [PATCH 2/5] privacy: Visit `DefId`s once in `DefIdVisitorSkeleton` --- compiler/rustc_privacy/src/lib.rs | 48 +++++++++++-------- .../generic_const_exprs/eval-privacy.rs | 1 - .../generic_const_exprs/eval-privacy.stderr | 13 +---- tests/ui/privacy/pub-priv-dep/pub-priv1.rs | 1 - .../ui/privacy/pub-priv-dep/pub-priv1.stderr | 28 ++++------- tests/ui/privacy/where-priv-type.rs | 1 - tests/ui/privacy/where-priv-type.stderr | 13 +---- 7 files changed, 41 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 81846741e4928..4e928af99e4ab 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -75,6 +75,8 @@ pub trait DefIdVisitor<'tcx> { } fn tcx(&self) -> TyCtxt<'tcx>; + /// NOTE: Def-id visiting should be idempotent, because `DefIdVisitorSkeleton` will 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 +84,7 @@ pub trait DefIdVisitor<'tcx> { fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'tcx, Self> { DefIdVisitorSkeleton { def_id_visitor: self, - visited_opaque_tys: Default::default(), + visited_def_ids: Default::default(), dummy: Default::default(), } } @@ -102,7 +104,7 @@ pub trait DefIdVisitor<'tcx> { pub struct DefIdVisitorSkeleton<'v, 'tcx, V: ?Sized> { def_id_visitor: &'v mut V, - visited_opaque_tys: FxHashSet, + visited_def_ids: FxHashSet, dummy: PhantomData>, } @@ -112,11 +114,13 @@ where { fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> V::Result { let TraitRef { def_id, args, .. } = trait_ref; - try_visit!(self.def_id_visitor.visit_def_id( - def_id, - "trait", - &trait_ref.print_only_trait_path() - )); + if self.visited_def_ids.insert(def_id) { + try_visit!(self.def_id_visitor.visit_def_id( + def_id, + "trait", + &trait_ref.print_only_trait_path() + )); + } if V::SHALLOW { V::Result::output() } else { args.visit_with(self) } } @@ -190,7 +194,9 @@ where | ty::Closure(def_id, ..) | ty::CoroutineClosure(def_id, ..) | ty::Coroutine(def_id, ..) => { - try_visit!(self.def_id_visitor.visit_def_id(def_id, "type", &ty)); + if self.visited_def_ids.insert(def_id) { + try_visit!(self.def_id_visitor.visit_def_id(def_id, "type", &ty)); + } if V::SHALLOW { return V::Result::output(); } @@ -221,15 +227,17 @@ where return V::Result::output(); } - try_visit!(self.def_id_visitor.visit_def_id( - data.def_id, - match kind { - ty::Inherent | ty::Projection => "associated type", - ty::Free => "type alias", - ty::Opaque => unreachable!(), - }, - &LazyDefPathStr { def_id: data.def_id, tcx }, - )); + if self.visited_def_ids.insert(data.def_id) { + try_visit!(self.def_id_visitor.visit_def_id( + data.def_id, + match kind { + ty::Inherent | ty::Projection => "associated type", + ty::Free => "type alias", + ty::Opaque => unreachable!(), + }, + &LazyDefPathStr { def_id: data.def_id, tcx }, + )); + } // This will also visit args if necessary, so we don't need to recurse. return if V::SHALLOW { @@ -254,12 +262,14 @@ where } }; let ty::ExistentialTraitRef { def_id, .. } = trait_ref; - try_visit!(self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref)); + if self.visited_def_ids.insert(def_id) { + try_visit!(self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref)); + } } } 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_def_ids.insert(def_id) { // 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 diff --git a/tests/ui/const-generics/generic_const_exprs/eval-privacy.rs b/tests/ui/const-generics/generic_const_exprs/eval-privacy.rs index b662939c27eb3..525e8976d4068 100644 --- a/tests/ui/const-generics/generic_const_exprs/eval-privacy.rs +++ b/tests/ui/const-generics/generic_const_exprs/eval-privacy.rs @@ -16,7 +16,6 @@ where { type AssocTy = Const<{ my_const_fn(U) }>; //~^ ERROR private type - //~| ERROR private type fn assoc_fn() -> Self::AssocTy { Const } diff --git a/tests/ui/const-generics/generic_const_exprs/eval-privacy.stderr b/tests/ui/const-generics/generic_const_exprs/eval-privacy.stderr index 98dac313be413..df8e397ebe53f 100644 --- a/tests/ui/const-generics/generic_const_exprs/eval-privacy.stderr +++ b/tests/ui/const-generics/generic_const_exprs/eval-privacy.stderr @@ -7,17 +7,6 @@ LL | type AssocTy = Const<{ my_const_fn(U) }>; LL | const fn my_const_fn(val: u8) -> u8 { | ----------------------------------- `fn(u8) -> u8 {my_const_fn}` declared as private -error[E0446]: private type `fn(u8) -> u8 {my_const_fn}` in public interface - --> $DIR/eval-privacy.rs:17:5 - | -LL | type AssocTy = Const<{ my_const_fn(U) }>; - | ^^^^^^^^^^^^ can't leak private type -... -LL | const fn my_const_fn(val: u8) -> u8 { - | ----------------------------------- `fn(u8) -> u8 {my_const_fn}` declared as private - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0446`. diff --git a/tests/ui/privacy/pub-priv-dep/pub-priv1.rs b/tests/ui/privacy/pub-priv-dep/pub-priv1.rs index eae0f9756a10e..5cbbaf361b791 100644 --- a/tests/ui/privacy/pub-priv-dep/pub-priv1.rs +++ b/tests/ui/privacy/pub-priv-dep/pub-priv1.rs @@ -145,7 +145,6 @@ impl From for OtherType { //~| ERROR type `OtherType` from private dependency 'priv_dep' in public interface fn from(val: PublicWithStdImpl) -> Self { Self } //~^ ERROR type `OtherType` from private dependency 'priv_dep' in public interface - //~| ERROR type `OtherType` from private dependency 'priv_dep' in public interface } pub struct AllowedPrivType { diff --git a/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr b/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr index e66db53f65dd0..604d99837278a 100644 --- a/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr +++ b/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr @@ -11,55 +11,55 @@ LL | #![deny(exported_private_dependencies)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: macro `m` from private dependency 'priv_dep' is re-exported - --> $DIR/pub-priv1.rs:156:9 + --> $DIR/pub-priv1.rs:155:9 | LL | pub use priv_dep::m; | ^^^^^^^^^^^ error: macro `fn_like` from private dependency 'pm' is re-exported - --> $DIR/pub-priv1.rs:158:9 + --> $DIR/pub-priv1.rs:157:9 | LL | pub use pm::fn_like; | ^^^^^^^^^^^ error: derive macro `PmDerive` from private dependency 'pm' is re-exported - --> $DIR/pub-priv1.rs:160:9 + --> $DIR/pub-priv1.rs:159:9 | LL | pub use pm::PmDerive; | ^^^^^^^^^^^^ error: attribute macro `pm_attr` from private dependency 'pm' is re-exported - --> $DIR/pub-priv1.rs:162:9 + --> $DIR/pub-priv1.rs:161:9 | LL | pub use pm::pm_attr; | ^^^^^^^^^^^ error: variant `V1` from private dependency 'priv_dep' is re-exported - --> $DIR/pub-priv1.rs:165:9 + --> $DIR/pub-priv1.rs:164:9 | LL | pub use priv_dep::E::V1; | ^^^^^^^^^^^^^^^ error: type alias `Unit` from private dependency 'priv_dep' is re-exported - --> $DIR/pub-priv1.rs:168:9 + --> $DIR/pub-priv1.rs:167:9 | LL | pub use priv_dep::Unit; | ^^^^^^^^^^^^^^ error: type alias `PubPub` from private dependency 'priv_dep' is re-exported - --> $DIR/pub-priv1.rs:170:9 + --> $DIR/pub-priv1.rs:169:9 | LL | pub use priv_dep::PubPub; | ^^^^^^^^^^^^^^^^ error: type alias `PubPriv` from private dependency 'priv_dep' is re-exported - --> $DIR/pub-priv1.rs:172:9 + --> $DIR/pub-priv1.rs:171:9 | LL | pub use priv_dep::PubPriv; | ^^^^^^^^^^^^^^^^^ error: struct `Renamed` from private dependency 'priv_dep' is re-exported - --> $DIR/pub-priv1.rs:174:9 + --> $DIR/pub-priv1.rs:173:9 | LL | pub use priv_dep::OtherType as Renamed; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -248,13 +248,5 @@ error: type `OtherType` from private dependency 'priv_dep' in public interface LL | fn from(val: PublicWithStdImpl) -> Self { Self } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:146:5 - | -LL | fn from(val: PublicWithStdImpl) -> Self { Self } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 41 previous errors +error: aborting due to 40 previous errors diff --git a/tests/ui/privacy/where-priv-type.rs b/tests/ui/privacy/where-priv-type.rs index 20467301ae17c..c48f1d6df67fd 100644 --- a/tests/ui/privacy/where-priv-type.rs +++ b/tests/ui/privacy/where-priv-type.rs @@ -65,7 +65,6 @@ where { type AssocTy = Const<{ my_const_fn(U) }>; //~^ ERROR private type - //~| ERROR private type fn assoc_fn() -> Self::AssocTy { Const } diff --git a/tests/ui/privacy/where-priv-type.stderr b/tests/ui/privacy/where-priv-type.stderr index 08963e07c35a3..0f876fc65446d 100644 --- a/tests/ui/privacy/where-priv-type.stderr +++ b/tests/ui/privacy/where-priv-type.stderr @@ -77,17 +77,6 @@ LL | type AssocTy = Const<{ my_const_fn(U) }>; LL | const fn my_const_fn(val: u8) -> u8 { | ----------------------------------- `fn(u8) -> u8 {my_const_fn}` declared as private -error[E0446]: private type `fn(u8) -> u8 {my_const_fn}` in public interface - --> $DIR/where-priv-type.rs:66:5 - | -LL | type AssocTy = Const<{ my_const_fn(U) }>; - | ^^^^^^^^^^^^ can't leak private type -... -LL | const fn my_const_fn(val: u8) -> u8 { - | ----------------------------------- `fn(u8) -> u8 {my_const_fn}` declared as private - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors; 5 warnings emitted +error: aborting due to 1 previous error; 5 warnings emitted For more information about this error, try `rustc --explain E0446`. From a4ada4fbb30241111099e71022087d2dc36a2f2e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 9 Oct 2025 15:25:54 +0300 Subject: [PATCH 3/5] privacy: Visit `Ty`s once in `DefIdVisitorSkeleton` --- compiler/rustc_privacy/src/lib.rs | 66 ++++++++++++++----------------- 1 file changed, 29 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 4e928af99e4ab..d3832f0a3e3b6 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -84,7 +84,7 @@ pub trait DefIdVisitor<'tcx> { fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'tcx, Self> { DefIdVisitorSkeleton { def_id_visitor: self, - visited_def_ids: Default::default(), + visited_tys: Default::default(), dummy: Default::default(), } } @@ -104,7 +104,7 @@ pub trait DefIdVisitor<'tcx> { pub struct DefIdVisitorSkeleton<'v, 'tcx, V: ?Sized> { def_id_visitor: &'v mut V, - visited_def_ids: FxHashSet, + visited_tys: FxHashSet>, dummy: PhantomData>, } @@ -114,13 +114,11 @@ where { fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> V::Result { let TraitRef { def_id, args, .. } = trait_ref; - if self.visited_def_ids.insert(def_id) { - try_visit!(self.def_id_visitor.visit_def_id( - def_id, - "trait", - &trait_ref.print_only_trait_path() - )); - } + try_visit!(self.def_id_visitor.visit_def_id( + def_id, + "trait", + &trait_ref.print_only_trait_path() + )); if V::SHALLOW { V::Result::output() } else { args.visit_with(self) } } @@ -184,6 +182,9 @@ where } fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { + if !self.visited_tys.insert(ty) { + return V::Result::output(); + } let tcx = self.def_id_visitor.tcx(); // GenericArgs are not visited here because they are visited below // in `super_visit_with`. @@ -194,9 +195,7 @@ where | ty::Closure(def_id, ..) | ty::CoroutineClosure(def_id, ..) | ty::Coroutine(def_id, ..) => { - if self.visited_def_ids.insert(def_id) { - try_visit!(self.def_id_visitor.visit_def_id(def_id, "type", &ty)); - } + try_visit!(self.def_id_visitor.visit_def_id(def_id, "type", &ty)); if V::SHALLOW { return V::Result::output(); } @@ -227,17 +226,15 @@ where return V::Result::output(); } - if self.visited_def_ids.insert(data.def_id) { - try_visit!(self.def_id_visitor.visit_def_id( - data.def_id, - match kind { - ty::Inherent | ty::Projection => "associated type", - ty::Free => "type alias", - ty::Opaque => unreachable!(), - }, - &LazyDefPathStr { def_id: data.def_id, tcx }, - )); - } + try_visit!(self.def_id_visitor.visit_def_id( + data.def_id, + match kind { + ty::Inherent | ty::Projection => "associated type", + ty::Free => "type alias", + ty::Opaque => unreachable!(), + }, + &LazyDefPathStr { def_id: data.def_id, tcx }, + )); // This will also visit args if necessary, so we don't need to recurse. return if V::SHALLOW { @@ -262,23 +259,18 @@ where } }; let ty::ExistentialTraitRef { def_id, .. } = trait_ref; - if self.visited_def_ids.insert(def_id) { - try_visit!(self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref)); - } + try_visit!(self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref)); } } ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { - // Skip repeated `Opaque`s to avoid infinite recursion. - if self.visited_def_ids.insert(def_id) { - // 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 - // visibilities of type aliases) and recurse into bounds instead to go - // through the trait list (default type visitor doesn't visit those traits). - // All traits in the list are considered the "primary" part of the type - // and are visited by shallow visitors. - try_visit!(self.visit_clauses(tcx.explicit_item_bounds(def_id).skip_binder())); - } + // 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 + // visibilities of type aliases) and recurse into bounds instead to go + // through the trait list (default type visitor doesn't visit those traits). + // All traits in the list are considered the "primary" part of the type + // and are visited by shallow visitors. + try_visit!(self.visit_clauses(tcx.explicit_item_bounds(def_id).skip_binder())); } // These types don't have their own def-ids (but may have subcomponents // with def-ids that should be visited recursively). From 9ae12b1d37ffa90124b9c45b3943e88e8ac6099f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 9 Oct 2025 23:54:30 +0300 Subject: [PATCH 4/5] privacy: Do not use `DefIdVisitorSkeleton` ty cache for primitives --- compiler/rustc_privacy/src/lib.rs | 33 ++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index d3832f0a3e3b6..07096112dc618 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -182,9 +182,6 @@ where } fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { - if !self.visited_tys.insert(ty) { - return V::Result::output(); - } let tcx = self.def_id_visitor.tcx(); // GenericArgs are not visited here because they are visited below // in `super_visit_with`. @@ -195,6 +192,9 @@ where | ty::Closure(def_id, ..) | ty::CoroutineClosure(def_id, ..) | ty::Coroutine(def_id, ..) => { + if !self.visited_tys.insert(ty) { + return V::Result::output(); + } try_visit!(self.def_id_visitor.visit_def_id(def_id, "type", &ty)); if V::SHALLOW { return V::Result::output(); @@ -217,6 +217,9 @@ where } } ty::Alias(kind @ (ty::Inherent | ty::Free | ty::Projection), data) => { + if !self.visited_tys.insert(ty) { + return V::Result::output(); + } if self.def_id_visitor.skip_assoc_tys() { // Visitors searching for minimal visibility/reachability want to // conservatively approximate associated types like `Type::Alias` @@ -248,6 +251,9 @@ where }; } ty::Dynamic(predicates, ..) => { + if !self.visited_tys.insert(ty) { + return V::Result::output(); + } // All traits in the list are considered the "primary" part of the type // and are visited by shallow visitors. for predicate in predicates { @@ -263,6 +269,9 @@ where } } ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { + if !self.visited_tys.insert(ty) { + return V::Result::output(); + } // 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 @@ -272,8 +281,7 @@ where // and are visited by shallow visitors. try_visit!(self.visit_clauses(tcx.explicit_item_bounds(def_id).skip_binder())); } - // These types don't have their own def-ids (but may have subcomponents - // with def-ids that should be visited recursively). + // These types have neither their own def-ids nor subcomponents. ty::Bool | ty::Char | ty::Int(..) @@ -281,7 +289,12 @@ where | ty::Float(..) | ty::Str | ty::Never - | ty::Array(..) + | ty::Bound(..) + | ty::Param(..) => return V::Result::output(), + + // These types don't have their own def-ids (but may have subcomponents + // with def-ids that should be visited recursively). + ty::Array(..) | ty::Slice(..) | ty::Tuple(..) | ty::RawPtr(..) @@ -289,10 +302,12 @@ where | ty::Pat(..) | ty::FnPtr(..) | ty::UnsafeBinder(_) - | ty::Param(..) - | ty::Bound(..) | ty::Error(_) - | ty::CoroutineWitness(..) => {} + | ty::CoroutineWitness(..) => { + if !self.visited_tys.insert(ty) { + return V::Result::output(); + } + } ty::Placeholder(..) | ty::Infer(..) => { bug!("unexpected type: {:?}", ty) } From ab1d001c4b47ae859552f4703576b553444b4c9f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 10 Oct 2025 18:22:16 +0300 Subject: [PATCH 5/5] WIP --- compiler/rustc_driver_impl/src/lib.rs | 7 +- compiler/rustc_privacy/src/lib.rs | 134 +++++++++++++++++++++----- 2 files changed, 114 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 8dab520cf36b9..62fea0b806bd0 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -276,10 +276,13 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) let registered_lints = config.register_lints.is_some(); + let mut crate_name = None; interface::run_compiler(config, |compiler| { let sess = &compiler.sess; let codegen_backend = &*compiler.codegen_backend; + crate_name = sess.opts.crate_name.clone(); + // This is used for early exits unrelated to errors. E.g. when just // printing some information without compiling, or exiting immediately // after parsing, etc. @@ -392,7 +395,9 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) if let Some(linker) = linker { linker.link(sess, codegen_backend); } - }) + }); + + eprintln!("{crate_name:?}: {:?}", rustc_privacy::brrr()); } fn dump_feature_usage_metrics(tcxt: TyCtxt<'_>, metrics_dir: &Path) { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 07096112dc618..4a24ae006b4d4 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -12,6 +12,8 @@ mod errors; use std::fmt; use std::marker::PhantomData; use std::ops::ControlFlow; +use std::sync::{Mutex, MutexGuard, OnceLock}; +use std::time::{Duration, Instant}; use errors::{ FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface, @@ -20,7 +22,7 @@ use errors::{ }; use rustc_ast::MacroDef; use rustc_ast::visit::{VisitorResult, try_visit}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::intern::Interned; use rustc_errors::{MultiSpan, listify}; use rustc_hir as hir; @@ -86,6 +88,7 @@ pub trait DefIdVisitor<'tcx> { def_id_visitor: self, visited_tys: Default::default(), dummy: Default::default(), + // brrr: Default::default(), } } fn visit(&mut self, ty_fragment: impl TypeVisitable>) -> Self::Result { @@ -102,6 +105,82 @@ pub trait DefIdVisitor<'tcx> { } } +#[derive(PartialEq, Eq, Hash, Debug)] +pub enum Ty2 { + Bool, + Char, + Int, + Uint, + Float, + Adt, + Foreign, + Str, + Array, + Pat, + Slice, + RawPtr, + Ref, + FnDef, + FnPtr, + UnsafeBinder, + Dynamic, + Closure, + CoroutineClosure, + Coroutine, + CoroutineWitness, + Never, + Tuple, + Alias, + Param, + Bound, + Placeholder, + Infer, + Error, +} + +use Ty2::*; + +impl Ty2 { + fn from_ty(ty: Ty<'_>) -> Ty2 { + match ty.kind() { + ty::Bool => Bool, + ty::Char => Char, + ty::Int(..) => Int, + ty::Uint(..) => Uint, + ty::Float(..) => Float, + ty::Adt(..) => Adt, + ty::Foreign(..) => Foreign, + ty::Str => Str, + ty::Array(..) => Array, + ty::Pat(..) => Pat, + ty::Slice(_) => Slice, + ty::RawPtr(..) => RawPtr, + ty::Ref(..) => Ref, + ty::FnDef(..) => FnDef, + ty::FnPtr(..) => FnPtr, + ty::UnsafeBinder(..) => UnsafeBinder, + ty::Dynamic(..) => Dynamic, + ty::Closure(..) => Closure, + ty::CoroutineClosure(..) => CoroutineClosure, + ty::Coroutine(..) => Coroutine, + ty::CoroutineWitness(..) => CoroutineWitness, + ty::Never => Never, + ty::Tuple(..) => Tuple, + ty::Alias(..) => Alias, + ty::Param(..) => Param, + ty::Bound(..) => Bound, + ty::Placeholder(..) => Placeholder, + ty::Infer(..) => Infer, + ty::Error(..) => Error, + } + } +} + +pub fn brrr() -> MutexGuard<'static, FxHashMap> { + static MAP: OnceLock>> = OnceLock::new(); + MAP.get_or_init(Default::default).lock().unwrap() +} + pub struct DefIdVisitorSkeleton<'v, 'tcx, V: ?Sized> { def_id_visitor: &'v mut V, visited_tys: FxHashSet>, @@ -171,6 +250,14 @@ where } } +// impl Drop for DefIdVisitorSkeleton<'_, '_, V> { +// fn drop(&mut self) { +// if !brrr().is_empty() { +// dbg!(brrr()); +// } +// } +// } + impl<'tcx, V> TypeVisitor> for DefIdVisitorSkeleton<'_, 'tcx, V> where V: DefIdVisitor<'tcx> + ?Sized, @@ -182,6 +269,8 @@ where } fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { + let new = self.visited_tys.insert(ty); + let instant = Instant::now(); let tcx = self.def_id_visitor.tcx(); // GenericArgs are not visited here because they are visited below // in `super_visit_with`. @@ -192,9 +281,6 @@ where | ty::Closure(def_id, ..) | ty::CoroutineClosure(def_id, ..) | ty::Coroutine(def_id, ..) => { - if !self.visited_tys.insert(ty) { - return V::Result::output(); - } try_visit!(self.def_id_visitor.visit_def_id(def_id, "type", &ty)); if V::SHALLOW { return V::Result::output(); @@ -217,9 +303,6 @@ where } } ty::Alias(kind @ (ty::Inherent | ty::Free | ty::Projection), data) => { - if !self.visited_tys.insert(ty) { - return V::Result::output(); - } if self.def_id_visitor.skip_assoc_tys() { // Visitors searching for minimal visibility/reachability want to // conservatively approximate associated types like `Type::Alias` @@ -251,9 +334,6 @@ where }; } ty::Dynamic(predicates, ..) => { - if !self.visited_tys.insert(ty) { - return V::Result::output(); - } // All traits in the list are considered the "primary" part of the type // and are visited by shallow visitors. for predicate in predicates { @@ -269,17 +349,16 @@ where } } ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { - if !self.visited_tys.insert(ty) { - return V::Result::output(); + if new { + // 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 + // visibilities of type aliases) and recurse into bounds instead to go + // through the trait list (default type visitor doesn't visit those traits). + // All traits in the list are considered the "primary" part of the type + // and are visited by shallow visitors. + try_visit!(self.visit_clauses(tcx.explicit_item_bounds(def_id).skip_binder())); } - // 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 - // visibilities of type aliases) and recurse into bounds instead to go - // through the trait list (default type visitor doesn't visit those traits). - // All traits in the list are considered the "primary" part of the type - // and are visited by shallow visitors. - try_visit!(self.visit_clauses(tcx.explicit_item_bounds(def_id).skip_binder())); } // These types have neither their own def-ids nor subcomponents. ty::Bool @@ -303,17 +382,20 @@ where | ty::FnPtr(..) | ty::UnsafeBinder(_) | ty::Error(_) - | ty::CoroutineWitness(..) => { - if !self.visited_tys.insert(ty) { - return V::Result::output(); - } - } + | ty::CoroutineWitness(..) => {} ty::Placeholder(..) | ty::Infer(..) => { bug!("unexpected type: {:?}", ty) } } - if V::SHALLOW { V::Result::output() } else { ty.super_visit_with(self) } + let result = if V::SHALLOW { V::Result::output() } else { ty.super_visit_with(self) }; + + if !new { + let duration = instant.elapsed(); + *brrr().entry(Ty2::from_ty(ty)).or_default() += duration; + } + + result } fn visit_const(&mut self, c: Const<'tcx>) -> Self::Result {