From a7b687c26ef55bfc3481761fef6e46154e5f95ea Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 27 Mar 2025 11:48:06 +0000 Subject: [PATCH 01/12] Decouple trait impls of different traits wrt incremental --- compiler/rustc_hir_analysis/src/coherence/mod.rs | 5 ++++- compiler/rustc_middle/src/hir/map.rs | 2 +- compiler/rustc_middle/src/hir/mod.rs | 2 ++ compiler/rustc_middle/src/query/mod.rs | 5 +++++ src/tools/clippy/clippy_lints/src/derive.rs | 6 ++---- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index 15e0a72fdcb..16bac430491 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -153,9 +153,12 @@ pub(crate) fn provide(providers: &mut Providers) { } fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed> { + let impls = tcx.local_trait_impls(def_id); // If there are no impls for the trait, then "all impls" are trivially coherent and we won't check anything // anyway. Thus we bail out even before the specialization graph, avoiding the dep_graph edge. - let Some(impls) = tcx.all_local_trait_impls(()).get(&def_id) else { return Ok(()) }; + if impls.is_empty() { + return Ok(()); + } // Trigger building the specialization graph for the trait. This will detect and report any // overlap errors. let mut res = tcx.ensure_ok().specialization_graph_of(def_id); diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 52f155a16b8..80370910032 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -368,7 +368,7 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn hir_trait_impls(self, trait_did: DefId) -> &'tcx [LocalDefId] { - self.all_local_trait_impls(()).get(&trait_did).map_or(&[], |xs| &xs[..]) + self.local_trait_impls(trait_did) } /// Gets the attributes on the crate. This is preferable to diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 347bc5ea312..cae9b2fb544 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -238,6 +238,8 @@ pub fn provide(providers: &mut Providers) { } }; providers.all_local_trait_impls = |tcx, ()| &tcx.resolutions(()).trait_impls; + providers.local_trait_impls = + |tcx, trait_id| tcx.resolutions(()).trait_impls.get(&trait_id).map_or(&[], |xs| &xs[..]); providers.expn_that_defined = |tcx, id| tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root()); providers.in_scope_traits_map = |tcx, id| { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d7ed703f4ae..4b3236e4b84 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1502,6 +1502,11 @@ rustc_queries! { desc { "finding local trait impls" } } + /// Return all `impl` blocks of the given trait in the current crate. + query local_trait_impls(trait_id: DefId) -> &'tcx [LocalDefId] { + desc { "finding local trait impls of `{}`", tcx.def_path_str(trait_id) } + } + /// Given a trait `trait_id`, return all known `impl` blocks. query trait_impls_of(trait_id: DefId) -> &'tcx ty::trait_def::TraitImpls { arena_cache diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index 2ae35b40055..fae01026487 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -324,11 +324,9 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h // there's a Copy impl for any instance of the adt. if !is_copy(cx, ty) { if ty_subs.non_erasable_generics().next().is_some() { - let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(©_id).is_some_and(|impls| { - impls.iter().any(|&id| { - matches!(cx.tcx.type_of(id).instantiate_identity().kind(), ty::Adt(adt, _) + let has_copy_impl = cx.tcx.local_trait_impls(copy_id).iter().any(|&id| { + matches!(cx.tcx.type_of(id).instantiate_identity().kind(), ty::Adt(adt, _) if ty_adt.did() == adt.did()) - }) }); if !has_copy_impl { return; From aec77398378cc7af99043c3d1dd2394eb3d33c43 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 27 Mar 2025 12:03:48 +0000 Subject: [PATCH 02/12] Remove an unnecessary dtor computation and use the cached query result instead --- compiler/rustc_mir_transform/src/check_const_item_mutation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs index ceea72c6755..76d1e671c5d 100644 --- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs +++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs @@ -53,7 +53,7 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> { // // #[const_mutation_allowed] // pub const LOG: Log = Log { msg: "" }; - match self.tcx.calculate_dtor(def_id, |_, _| Ok(())) { + match self.tcx.adt_destructor(def_id) { Some(_) => None, None => Some(def_id), } From c0fe46d6b72c96bda16bf62e7476e6d85ba68afe Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 27 Mar 2025 12:08:00 +0000 Subject: [PATCH 03/12] Make missing optimized MIR error more informative --- compiler/rustc_monomorphize/messages.ftl | 2 +- compiler/rustc_monomorphize/src/collector.rs | 1 + compiler/rustc_monomorphize/src/errors.rs | 1 + tests/ui/rmeta/no_optitimized_mir.rs | 2 +- tests/ui/rmeta/no_optitimized_mir.stderr | 2 +- 5 files changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl index aae2d79c161..6b6653e7de0 100644 --- a/compiler/rustc_monomorphize/messages.ftl +++ b/compiler/rustc_monomorphize/messages.ftl @@ -48,7 +48,7 @@ monomorphize_large_assignments = .note = The current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` monomorphize_no_optimized_mir = - missing optimized MIR for an item in the crate `{$crate_name}` + missing optimized MIR for `{$instance}` in the crate `{$crate_name}` .note = missing optimized MIR for this item (was the crate `{$crate_name}` compiled with `--emit=metadata`?) monomorphize_recursion_limit = diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 2a1b20ba48b..6e676ac6b8d 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -989,6 +989,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> tcx.dcx().emit_fatal(NoOptimizedMir { span: tcx.def_span(def_id), crate_name: tcx.crate_name(def_id.krate), + instance: instance.to_string(), }); } diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index dffa372279f..adfe096f0cd 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -24,6 +24,7 @@ pub(crate) struct NoOptimizedMir { #[note] pub span: Span, pub crate_name: Symbol, + pub instance: String, } #[derive(LintDiagnostic)] diff --git a/tests/ui/rmeta/no_optitimized_mir.rs b/tests/ui/rmeta/no_optitimized_mir.rs index 708cdfc803f..c8ed00b039b 100644 --- a/tests/ui/rmeta/no_optitimized_mir.rs +++ b/tests/ui/rmeta/no_optitimized_mir.rs @@ -10,4 +10,4 @@ fn main() { rmeta_meta::missing_optimized_mir(); } -//~? ERROR missing optimized MIR for an item in the crate `rmeta_meta` +//~? ERROR missing optimized MIR for `missing_optimized_mir` in the crate `rmeta_meta` diff --git a/tests/ui/rmeta/no_optitimized_mir.stderr b/tests/ui/rmeta/no_optitimized_mir.stderr index 92f22d78000..254f100aa7b 100644 --- a/tests/ui/rmeta/no_optitimized_mir.stderr +++ b/tests/ui/rmeta/no_optitimized_mir.stderr @@ -1,4 +1,4 @@ -error: missing optimized MIR for an item in the crate `rmeta_meta` +error: missing optimized MIR for `missing_optimized_mir` in the crate `rmeta_meta` | note: missing optimized MIR for this item (was the crate `rmeta_meta` compiled with `--emit=metadata`?) --> $DIR/auxiliary/rmeta-meta.rs:10:1 From 23f1fb58f201cce980128a0dae491c4e5393629a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 27 Mar 2025 12:08:00 +0000 Subject: [PATCH 04/12] Store adt_destructor in metadata --- compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs | 5 +---- compiler/rustc_metadata/src/rmeta/encoder.rs | 4 ++++ compiler/rustc_metadata/src/rmeta/mod.rs | 1 + compiler/rustc_middle/src/ty/parameterized.rs | 1 + 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 776b081a463..5c425e7a418 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -330,10 +330,7 @@ provide! { tcx, def_id, other, cdata, visibility => { cdata.get_visibility(def_id.index) } adt_def => { cdata.get_adt_def(def_id.index, tcx) } - adt_destructor => { - let _ = cdata; - tcx.calculate_dtor(def_id, |_,_| Ok(())) - } + adt_destructor => { table } adt_async_destructor => { let _ = cdata; tcx.calculate_async_dtor(def_id, |_,_| Ok(())) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 7ab3d432bdf..a9beab1a70a 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1633,6 +1633,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.fn_sig[variant.def_id] <- fn_sig); } } + + if let Some(destructor) = tcx.adt_destructor(local_def_id) { + record!(self.tables.adt_destructor[def_id] <- destructor); + } } #[instrument(level = "debug", skip(self))] diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index dc453b1e747..fb5fcff8d33 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -446,6 +446,7 @@ define_tables! { fn_arg_names: Table>>, coroutine_kind: Table, coroutine_for_closure: Table, + adt_destructor: Table>, coroutine_by_move_body_def_id: Table, eval_static_initializer: Table>>, trait_def: Table>, diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 19e2b574563..d6f18166956 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -68,6 +68,7 @@ trivially_parameterized_over_tcx! { ty::AssocItemContainer, ty::Asyncness, ty::DeducedParamAttrs, + ty::Destructor, ty::Generics, ty::ImplPolarity, ty::ImplTraitInTraitData, From 2b1c416da724a45f5a9c8e501c27a87ca4b536cc Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 27 Mar 2025 12:46:04 +0000 Subject: [PATCH 05/12] Store adt_async_destructor in metadata --- compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs | 5 +---- compiler/rustc_metadata/src/rmeta/encoder.rs | 4 ++++ compiler/rustc_metadata/src/rmeta/mod.rs | 1 + compiler/rustc_middle/src/ty/parameterized.rs | 1 + 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 5c425e7a418..3dc82ce9d18 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -331,10 +331,7 @@ provide! { tcx, def_id, other, cdata, visibility => { cdata.get_visibility(def_id.index) } adt_def => { cdata.get_adt_def(def_id.index, tcx) } adt_destructor => { table } - adt_async_destructor => { - let _ = cdata; - tcx.calculate_async_dtor(def_id, |_,_| Ok(())) - } + adt_async_destructor => { table } associated_item_def_ids => { tcx.arena.alloc_from_iter(cdata.get_associated_item_or_field_def_ids(def_id.index)) } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index a9beab1a70a..b6f799e7ff7 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1637,6 +1637,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if let Some(destructor) = tcx.adt_destructor(local_def_id) { record!(self.tables.adt_destructor[def_id] <- destructor); } + + if let Some(destructor) = tcx.adt_async_destructor(local_def_id) { + record!(self.tables.adt_async_destructor[def_id] <- destructor); + } } #[instrument(level = "debug", skip(self))] diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index fb5fcff8d33..8fef3ef2355 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -447,6 +447,7 @@ define_tables! { coroutine_kind: Table, coroutine_for_closure: Table, adt_destructor: Table>, + adt_async_destructor: Table>, coroutine_by_move_body_def_id: Table, eval_static_initializer: Table>>, trait_def: Table>, diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index d6f18166956..61b35b33a09 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -65,6 +65,7 @@ trivially_parameterized_over_tcx! { crate::middle::lib_features::FeatureStability, crate::middle::resolve_bound_vars::ObjectLifetimeDefault, crate::mir::ConstQualifs, + ty::AsyncDestructor, ty::AssocItemContainer, ty::Asyncness, ty::DeducedParamAttrs, From 51184c70c897619f6a2883538f8a85292306a0c8 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 27 Mar 2025 12:48:54 +0000 Subject: [PATCH 06/12] Ensure `calculcate_dtor` is only ever called on local types --- compiler/rustc_hir_analysis/src/check/mod.rs | 4 ++-- compiler/rustc_middle/src/ty/util.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index d8ae4214527..ee1e78a79cd 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -114,11 +114,11 @@ pub fn provide(providers: &mut Providers) { } fn adt_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { - tcx.calculate_dtor(def_id.to_def_id(), always_applicable::check_drop_impl) + tcx.calculate_dtor(def_id, always_applicable::check_drop_impl) } fn adt_async_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { - tcx.calculate_async_dtor(def_id.to_def_id(), always_applicable::check_drop_impl) + tcx.calculate_async_dtor(def_id, always_applicable::check_drop_impl) } /// Given a `DefId` for an opaque type in return position, find its parent item's return diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index c0d4130336e..61d8b5ce52e 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -389,7 +389,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Calculate the destructor of a given type. pub fn calculate_dtor( self, - adt_did: DefId, + adt_did: LocalDefId, validate: impl Fn(Self, DefId) -> Result<(), ErrorGuaranteed>, ) -> Option { let drop_trait = self.lang_items().drop_trait()?; @@ -426,7 +426,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Calculate the async destructor of a given type. pub fn calculate_async_dtor( self, - adt_did: DefId, + adt_did: LocalDefId, validate: impl Fn(Self, DefId) -> Result<(), ErrorGuaranteed>, ) -> Option { let async_drop_trait = self.lang_items().async_drop_trait()?; From ca32447c0ccd38367ad1ff98c784f17f21d0e80e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 27 Mar 2025 14:11:44 +0000 Subject: [PATCH 07/12] Only look at trait impls in the current crate when looking for `Drop` impls --- .../src/check/always_applicable.rs | 4 +-- compiler/rustc_middle/src/ty/util.rs | 34 ++++++++++++------- .../src/check_const_item_mutation.rs | 10 ++++-- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/always_applicable.rs b/compiler/rustc_hir_analysis/src/check/always_applicable.rs index 8a841a11556..7a6a84c6392 100644 --- a/compiler/rustc_hir_analysis/src/check/always_applicable.rs +++ b/compiler/rustc_hir_analysis/src/check/always_applicable.rs @@ -36,10 +36,8 @@ use crate::hir::def_id::{DefId, LocalDefId}; /// cannot do `struct S; impl Drop for S { ... }`). pub(crate) fn check_drop_impl( tcx: TyCtxt<'_>, - drop_impl_did: DefId, + drop_impl_did: LocalDefId, ) -> Result<(), ErrorGuaranteed> { - let drop_impl_did = drop_impl_did.expect_local(); - match tcx.impl_polarity(drop_impl_did) { ty::ImplPolarity::Positive => {} ty::ImplPolarity::Negative => { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 61d8b5ce52e..45a7635087e 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -390,23 +390,28 @@ impl<'tcx> TyCtxt<'tcx> { pub fn calculate_dtor( self, adt_did: LocalDefId, - validate: impl Fn(Self, DefId) -> Result<(), ErrorGuaranteed>, + validate: impl Fn(Self, LocalDefId) -> Result<(), ErrorGuaranteed>, ) -> Option { let drop_trait = self.lang_items().drop_trait()?; self.ensure_ok().coherent_trait(drop_trait).ok()?; - let ty = self.type_of(adt_did).instantiate_identity(); let mut dtor_candidate = None; - self.for_each_relevant_impl(drop_trait, ty, |impl_did| { + // `Drop` impls can only be written in the same crate as the adt, and cannot be blanket impls + for &impl_did in self.local_trait_impls(drop_trait) { + let Some(adt_def) = self.type_of(impl_did).skip_binder().ty_adt_def() else { continue }; + if adt_def.did() != adt_did.to_def_id() { + continue; + } + if validate(self, impl_did).is_err() { // Already `ErrorGuaranteed`, no need to delay a span bug here. - return; + continue; } let Some(item_id) = self.associated_item_def_ids(impl_did).first() else { self.dcx() .span_delayed_bug(self.def_span(impl_did), "Drop impl without drop function"); - return; + continue; }; if let Some((old_item_id, _)) = dtor_candidate { @@ -417,7 +422,7 @@ impl<'tcx> TyCtxt<'tcx> { } dtor_candidate = Some((*item_id, self.impl_trait_header(impl_did).unwrap().constness)); - }); + } let (did, constness) = dtor_candidate?; Some(ty::Destructor { did, constness }) @@ -427,17 +432,22 @@ impl<'tcx> TyCtxt<'tcx> { pub fn calculate_async_dtor( self, adt_did: LocalDefId, - validate: impl Fn(Self, DefId) -> Result<(), ErrorGuaranteed>, + validate: impl Fn(Self, LocalDefId) -> Result<(), ErrorGuaranteed>, ) -> Option { let async_drop_trait = self.lang_items().async_drop_trait()?; self.ensure_ok().coherent_trait(async_drop_trait).ok()?; - let ty = self.type_of(adt_did).instantiate_identity(); let mut dtor_candidate = None; - self.for_each_relevant_impl(async_drop_trait, ty, |impl_did| { + // `AsyncDrop` impls can only be written in the same crate as the adt, and cannot be blanket impls + for &impl_did in self.local_trait_impls(async_drop_trait) { + let Some(adt_def) = self.type_of(impl_did).skip_binder().ty_adt_def() else { continue }; + if adt_def.did() != adt_did.to_def_id() { + continue; + } + if validate(self, impl_did).is_err() { // Already `ErrorGuaranteed`, no need to delay a span bug here. - return; + continue; } let [future, ctor] = self.associated_item_def_ids(impl_did) else { @@ -445,7 +455,7 @@ impl<'tcx> TyCtxt<'tcx> { self.def_span(impl_did), "AsyncDrop impl without async_drop function or Dropper type", ); - return; + continue; }; if let Some((_, _, old_impl_did)) = dtor_candidate { @@ -456,7 +466,7 @@ impl<'tcx> TyCtxt<'tcx> { } dtor_candidate = Some((*future, *ctor, impl_did)); - }); + } let (future, ctor, _) = dtor_candidate?; Some(ty::AsyncDestructor { future, ctor }) diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs index 76d1e671c5d..375db17fb73 100644 --- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs +++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs @@ -53,9 +53,13 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> { // // #[const_mutation_allowed] // pub const LOG: Log = Log { msg: "" }; - match self.tcx.adt_destructor(def_id) { - Some(_) => None, - None => Some(def_id), + // FIXME: this should not be checking for `Drop` impls, + // but whether it or any field has a Drop impl (`needs_drop`) + // as fields' Drop impls may make this observable, too. + match self.tcx.type_of(def_id).skip_binder().ty_adt_def().map(|adt| adt.has_dtor(self.tcx)) + { + Some(true) => None, + Some(false) | None => Some(def_id), } } From 6697f02761c98a6b1a213ca65a70f70e08b184cf Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 1 Apr 2025 09:28:46 +0000 Subject: [PATCH 08/12] Fetch the destructor constness lazily --- compiler/rustc_middle/src/ty/adt.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 2 -- compiler/rustc_middle/src/ty/util.rs | 8 ++++---- compiler/rustc_trait_selection/src/traits/effects.rs | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index cb245c0aec4..00fe5cb0c5d 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -236,7 +236,7 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef> for AdtDef<'tcx> { } fn destructor(self, tcx: TyCtxt<'tcx>) -> Option { - Some(match self.destructor(tcx)?.constness { + Some(match tcx.constness(self.destructor(tcx)?.did) { hir::Constness::Const => AdtDestructorKind::Const, hir::Constness::NotConst => AdtDestructorKind::NotConst, }) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 0ffaef82f1c..255d464d265 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1119,8 +1119,6 @@ pub struct PseudoCanonicalInput<'tcx, T> { pub struct Destructor { /// The `DefId` of the destructor method pub did: DefId, - /// The constness of the destructor method - pub constness: hir::Constness, } // FIXME: consider combining this definition with regular `Destructor` diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 45a7635087e..7743e202aae 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -414,18 +414,18 @@ impl<'tcx> TyCtxt<'tcx> { continue; }; - if let Some((old_item_id, _)) = dtor_candidate { + if let Some(old_item_id) = dtor_candidate { self.dcx() .struct_span_err(self.def_span(item_id), "multiple drop impls found") .with_span_note(self.def_span(old_item_id), "other impl here") .delay_as_bug(); } - dtor_candidate = Some((*item_id, self.impl_trait_header(impl_did).unwrap().constness)); + dtor_candidate = Some(*item_id); } - let (did, constness) = dtor_candidate?; - Some(ty::Destructor { did, constness }) + let did = dtor_candidate?; + Some(ty::Destructor { did }) } /// Calculate the async destructor of a given type. diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index 3c127416cbf..bcb51ff8d01 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -263,7 +263,7 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>( .all_fields() .map(|field| ty::TraitRef::new(tcx, destruct_def_id, [field.ty(tcx, args)])) .collect(); - match adt_def.destructor(tcx).map(|dtor| dtor.constness) { + match adt_def.destructor(tcx).map(|dtor| tcx.constness(dtor.did)) { // `Drop` impl exists, but it's not const. Type cannot be `~const Destruct`. Some(hir::Constness::NotConst) => return Err(EvaluationFailure::NoSolution), // `Drop` impl exists, and it's const. Require `Ty: ~const Drop` to hold. From 7192a0643d5d3d975203a0ae653af8459b2dc6b2 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 1 Apr 2025 09:35:59 +0000 Subject: [PATCH 09/12] Directly fetch the impl self type --- compiler/rustc_hir_analysis/src/check/always_applicable.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/always_applicable.rs b/compiler/rustc_hir_analysis/src/check/always_applicable.rs index 7a6a84c6392..58c3020f60e 100644 --- a/compiler/rustc_hir_analysis/src/check/always_applicable.rs +++ b/compiler/rustc_hir_analysis/src/check/always_applicable.rs @@ -54,9 +54,9 @@ pub(crate) fn check_drop_impl( tcx.ensure_ok().orphan_check_impl(drop_impl_did)?; - let dtor_impl_trait_ref = tcx.impl_trait_ref(drop_impl_did).unwrap().instantiate_identity(); + let self_ty = tcx.type_of(drop_impl_did).instantiate_identity(); - match dtor_impl_trait_ref.self_ty().kind() { + match self_ty.kind() { ty::Adt(adt_def, adt_to_impl_args) => { ensure_impl_params_and_item_params_correspond( tcx, From 062ef5365d325fe9b1d8e7ba12b2471959d72415 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 1 Apr 2025 09:48:17 +0000 Subject: [PATCH 10/12] Remove a `hir_*` helper that was just forwarding to a query --- compiler/rustc_middle/src/hir/map.rs | 4 ---- compiler/rustc_middle/src/ty/trait_def.rs | 2 +- .../infer/nice_region_error/static_impl_trait.rs | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 80370910032..224a650b754 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -367,10 +367,6 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub fn hir_trait_impls(self, trait_did: DefId) -> &'tcx [LocalDefId] { - self.local_trait_impls(trait_did) - } - /// Gets the attributes on the crate. This is preferable to /// invoking `krate.attrs` because it registers a tighter /// dep-graph access. diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 8fa1c569737..fde9b9ea382 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -235,7 +235,7 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait } } - for &impl_def_id in tcx.hir_trait_impls(trait_id) { + for &impl_def_id in tcx.local_trait_impls(trait_id) { let impl_def_id = impl_def_id.to_def_id(); let impl_self_ty = tcx.type_of(impl_def_id).instantiate_identity(); diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs index 083ce022238..3559c660ee2 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs @@ -365,7 +365,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // obligation comes from the `impl`. Find that `impl` so that we can point // at it in the suggestion. let trait_did = trait_id.to_def_id(); - tcx.hir_trait_impls(trait_did).iter().find_map(|&impl_did| { + tcx.local_trait_impls(trait_did).iter().find_map(|&impl_did| { if let Node::Item(Item { kind: ItemKind::Impl(hir::Impl { self_ty, .. }), .. }) = tcx.hir_node_by_def_id(impl_did) From 798987982c6a0077edd62c14123b0ac1d4941e6a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 1 Apr 2025 10:03:55 +0000 Subject: [PATCH 11/12] Remove a function that has no necessary callers --- compiler/rustc_middle/src/ty/trait_def.rs | 15 --------------- .../clippy_lints/src/new_without_default.rs | 4 ++-- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index fde9b9ea382..ea25ce65f77 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -129,21 +129,6 @@ impl<'tcx> TraitDef { } impl<'tcx> TyCtxt<'tcx> { - /// `trait_def_id` MUST BE the `DefId` of a trait. - pub fn for_each_impl(self, trait_def_id: DefId, mut f: F) { - let impls = self.trait_impls_of(trait_def_id); - - for &impl_def_id in impls.blanket_impls.iter() { - f(impl_def_id); - } - - for v in impls.non_blanket_impls.values() { - for &impl_def_id in v { - f(impl_def_id); - } - } - } - /// Iterate over every impl that could possibly match the self type `self_ty`. /// /// `trait_def_id` MUST BE the `DefId` of a trait. diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs index f0ee613791f..1e469c3b63a 100644 --- a/src/tools/clippy/clippy_lints/src/new_without_default.rs +++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs @@ -97,14 +97,14 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { { if self.impling_types.is_none() { let mut impls = HirIdSet::default(); - cx.tcx.for_each_impl(default_trait_id, |d| { + for &d in cx.tcx.local_trait_impls(default_trait_id) { let ty = cx.tcx.type_of(d).instantiate_identity(); if let Some(ty_def) = ty.ty_adt_def() { if let Some(local_def_id) = ty_def.did().as_local() { impls.insert(cx.tcx.local_def_id_to_hir_id(local_def_id)); } } - }); + } self.impling_types = Some(impls); } From 49c74d29fdb04aa419f911fe9a42d13ca743b715 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 1 Apr 2025 10:06:27 +0000 Subject: [PATCH 12/12] Only walk local items instead of filtering for them later --- .../src/hir_ty_lowering/mod.rs | 34 +++++++++---------- compiler/rustc_passes/src/dead.rs | 6 ++-- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 76a880da418..9f3045ddc4c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1730,25 +1730,23 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .is_accessible_from(self.item_def_id(), tcx) && tcx.all_impls(*trait_def_id) .any(|impl_def_id| { - let impl_header = tcx.impl_trait_header(impl_def_id); - impl_header.is_some_and(|header| { - let trait_ref = header.trait_ref.instantiate( - tcx, - infcx.fresh_args_for_item(DUMMY_SP, impl_def_id), - ); + let header = tcx.impl_trait_header(impl_def_id).unwrap(); + let trait_ref = header.trait_ref.instantiate( + tcx, + infcx.fresh_args_for_item(DUMMY_SP, impl_def_id), + ); - let value = fold_regions(tcx, qself_ty, |_, _| tcx.lifetimes.re_erased); - // FIXME: Don't bother dealing with non-lifetime binders here... - if value.has_escaping_bound_vars() { - return false; - } - infcx - .can_eq( - ty::ParamEnv::empty(), - trait_ref.self_ty(), - value, - ) && header.polarity != ty::ImplPolarity::Negative - }) + let value = fold_regions(tcx, qself_ty, |_, _| tcx.lifetimes.re_erased); + // FIXME: Don't bother dealing with non-lifetime binders here... + if value.has_escaping_bound_vars() { + return false; + } + infcx + .can_eq( + ty::ParamEnv::empty(), + trait_ref.self_ty(), + value, + ) && header.polarity != ty::ImplPolarity::Negative }) }) .map(|trait_def_id| tcx.def_path_str(trait_def_id)) diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index f77e1db42d4..b62d94d65f1 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -421,10 +421,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } hir::ItemKind::ForeignMod { .. } => {} hir::ItemKind::Trait(..) => { - for impl_def_id in self.tcx.all_impls(item.owner_id.to_def_id()) { - if let Some(local_def_id) = impl_def_id.as_local() - && let ItemKind::Impl(impl_ref) = - self.tcx.hir_expect_item(local_def_id).kind + for &impl_def_id in self.tcx.local_trait_impls(item.owner_id.def_id) { + if let ItemKind::Impl(impl_ref) = self.tcx.hir_expect_item(impl_def_id).kind { // skip items // mark dependent traits live