From 6084bf541b23251b9c5b06466e075d176a9445e0 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sun, 8 Mar 2026 23:04:14 +0900 Subject: [PATCH 1/6] add regression test for EII declaration conflicting with constructor --- .../eii-declaration-conflicts-with-constructor.rs | 11 +++++++++++ ...i-declaration-conflicts-with-constructor.stderr | 14 ++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 tests/ui/eii/duplicate/eii-declaration-conflicts-with-constructor.rs create mode 100644 tests/ui/eii/duplicate/eii-declaration-conflicts-with-constructor.stderr diff --git a/tests/ui/eii/duplicate/eii-declaration-conflicts-with-constructor.rs b/tests/ui/eii/duplicate/eii-declaration-conflicts-with-constructor.rs new file mode 100644 index 0000000000000..23b930cddaa13 --- /dev/null +++ b/tests/ui/eii/duplicate/eii-declaration-conflicts-with-constructor.rs @@ -0,0 +1,11 @@ +#![feature(extern_item_impls)] + +// Regression test for : + +struct Foo(i32); + +#[eii] +pub fn Foo(x: u64) {} +//~^ ERROR the name `Foo` is defined multiple times + +fn main() {} diff --git a/tests/ui/eii/duplicate/eii-declaration-conflicts-with-constructor.stderr b/tests/ui/eii/duplicate/eii-declaration-conflicts-with-constructor.stderr new file mode 100644 index 0000000000000..e95ab395ff240 --- /dev/null +++ b/tests/ui/eii/duplicate/eii-declaration-conflicts-with-constructor.stderr @@ -0,0 +1,14 @@ +error[E0428]: the name `Foo` is defined multiple times + --> $DIR/eii-declaration-conflicts-with-constructor.rs:8:1 + | +LL | struct Foo(i32); + | ---------------- previous definition of the value `Foo` here +... +LL | pub fn Foo(x: u64) {} + | ^^^^^^^^^^^^^^^^^^ `Foo` redefined here + | + = note: `Foo` must be defined only once in the value namespace of this module + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0428`. From be78a0d629bd6058c2fd3b9b405a8484434ebcfb Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sun, 8 Mar 2026 23:04:49 +0900 Subject: [PATCH 2/6] avoid ICE when EII target resolves to a constructor remove span_delayed_bug --- .../rustc_hir_analysis/src/check/compare_eii.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index 9443aaac2258f..29213058d1d5e 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -9,6 +9,7 @@ use std::iter; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{Applicability, E0806, struct_span_code_err}; use rustc_hir::attrs::EiiImplResolution; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, FnSig, HirId, ItemKind, find_attr}; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; @@ -37,6 +38,14 @@ pub(crate) fn compare_eii_function_types<'tcx>( eii_name: Symbol, eii_attr_span: Span, ) -> Result<(), ErrorGuaranteed> { + // Error recovery can resolve the EII target to another value item with the same name, + // such as a tuple-struct constructor. Skip the comparison in that case and rely on the + // earlier name-resolution error instead of ICEing while building EII diagnostics. + // See . + if !is_foreign_function(tcx, foreign_item) { + return Ok(()); + } + check_is_structurally_compatible(tcx, external_impl, foreign_item, eii_name, eii_attr_span)?; let external_impl_span = tcx.def_span(external_impl); @@ -442,3 +451,7 @@ fn get_declaration_sig<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Option<&' let hir_id: HirId = tcx.local_def_id_to_hir_id(def_id); tcx.hir_fn_sig_by_hir_id(hir_id) } + +fn is_foreign_function(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + tcx.is_foreign_item(def_id) && matches!(tcx.def_kind(def_id), DefKind::Fn) +} From 3399ed3c9a25d51b777f10ac7dafc4bbb64eff35 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 5 Mar 2026 17:30:22 +1100 Subject: [PATCH 3/6] Simplify `type_of_opaque`. There is a bunch of complexity supporting the "cannot check whether the hidden type of opaque type satisfies auto traits" error that shows up in `tests/ui/impl-trait/auto-trait-leak.rs`. This is an obscure error that shows up in a single test. If we are willing to downgrade that error message to a cycle error, we can do the following. - Simplify the `type_of_opaque` return value. - Remove the `cycle_stash` query modifier. - Remove the `CyclePlaceholder` type. - Remove the `SelectionError::OpaqueTypeAutoTraitLeakageUnknown` variant. - Remove a `FromCycleError` impl. - Remove `report_opaque_type_auto_trait_leakage`. - Remove the `StashKey::Cycle` variant. - Remove the `CycleErrorHandling::Stash` variant. That's a lot! I think this is a worthwhile trade-off. --- compiler/rustc_errors/src/lib.rs | 2 - .../rustc_hir_analysis/src/collect/type_of.rs | 17 ++-- compiler/rustc_macros/src/query.rs | 9 -- compiler/rustc_middle/src/queries.rs | 12 +-- compiler/rustc_middle/src/query/erase.rs | 5 -- compiler/rustc_middle/src/query/modifiers.rs | 5 -- compiler/rustc_middle/src/query/plumbing.rs | 5 -- compiler/rustc_middle/src/traits/mod.rs | 4 - compiler/rustc_query_impl/src/execution.rs | 12 +-- .../rustc_query_impl/src/from_cycle_error.rs | 4 - .../traits/fulfillment_errors.rs | 33 ------- .../src/traits/select/mod.rs | 14 ++- .../auto-trait-leakage/auto-trait-leak.rs | 3 +- .../auto-trait-leakage/auto-trait-leak.stderr | 88 ++++++++++++++++--- .../type-alias-impl-trait/in-where-clause.rs | 1 - .../in-where-clause.stderr | 21 +---- 16 files changed, 91 insertions(+), 144 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index a96eceb6c715d..9b3dba15f55e2 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -371,8 +371,6 @@ pub enum StashKey { MaybeFruTypo, CallAssocMethod, AssociatedTypeSuggestion, - /// Query cycle detected, stashing in favor of a better error. - Cycle, UndeterminedMacroResolution, /// Used by `Parser::maybe_recover_trailing_expr` ExprInPat, diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 23df419d06a70..f2ae5c1f928d0 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -4,7 +4,6 @@ use rustc_errors::{Applicability, StashKey, Suggestions}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::VisitorExt; use rustc_hir::{self as hir, AmbigArg, HirId}; -use rustc_middle::query::plumbing::CyclePlaceholder; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, DefiningScopeKind, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; @@ -183,10 +182,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ } }, - Node::OpaqueTy(..) => tcx.type_of_opaque(def_id).map_or_else( - |CyclePlaceholder(guar)| Ty::new_error(tcx, guar), - |ty| ty.instantiate_identity(), - ), + Node::OpaqueTy(..) => tcx.type_of_opaque(def_id).instantiate_identity(), Node::ForeignItem(foreign_item) => match foreign_item.kind { ForeignItemKind::Fn(..) => { @@ -249,12 +245,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ } } -pub(super) fn type_of_opaque( - tcx: TyCtxt<'_>, - def_id: DefId, -) -> Result>, CyclePlaceholder> { +pub(super) fn type_of_opaque(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<'_, Ty<'_>> { if let Some(def_id) = def_id.as_local() { - Ok(match tcx.hir_node_by_def_id(def_id).expect_opaque_ty().origin { + match tcx.hir_node_by_def_id(def_id).expect_opaque_ty().origin { hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => { opaque::find_opaque_ty_constraints_for_tait( tcx, @@ -287,11 +280,11 @@ pub(super) fn type_of_opaque( DefiningScopeKind::MirBorrowck, ) } - }) + } } else { // Foreign opaque type will go through the foreign provider // and load the type from metadata. - Ok(tcx.type_of(def_id)) + tcx.type_of(def_id) } } diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 05a28c48f8063..ed5951fe1c034 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -144,7 +144,6 @@ struct QueryModifiers { arena_cache: Option, cache_on_disk_if: Option, cycle_delay_bug: Option, - cycle_stash: Option, depth_limit: Option, desc: Desc, eval_always: Option, @@ -159,7 +158,6 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { let mut cache_on_disk_if = None; let mut desc = None; let mut cycle_delay_bug = None; - let mut cycle_stash = None; let mut no_hash = None; let mut anon = None; let mut eval_always = None; @@ -195,8 +193,6 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { try_insert!(arena_cache = modifier); } else if modifier == "cycle_delay_bug" { try_insert!(cycle_delay_bug = modifier); - } else if modifier == "cycle_stash" { - try_insert!(cycle_stash = modifier); } else if modifier == "no_hash" { try_insert!(no_hash = modifier); } else if modifier == "anon" { @@ -221,7 +217,6 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { cache_on_disk_if, desc, cycle_delay_bug, - cycle_stash, no_hash, anon, eval_always, @@ -257,7 +252,6 @@ fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream { arena_cache, cache_on_disk_if, cycle_delay_bug, - cycle_stash, depth_limit, desc: _, eval_always, @@ -273,8 +267,6 @@ fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream { let cycle_error_handling = if cycle_delay_bug.is_some() { quote! { DelayBug } - } else if cycle_stash.is_some() { - quote! { Stash } } else { quote! { Error } }; @@ -411,7 +403,6 @@ fn add_to_analyzer_stream(query: &Query, analyzer_stream: &mut proc_macro2::Toke doc_link!( arena_cache, cycle_delay_bug, - cycle_stash, no_hash, anon, eval_always, diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index c20a389f56b97..25ac06a6ed099 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -33,7 +33,6 @@ //! - `cache_on_disk_if { ... }`: Cache the query result to disk if the provided block evaluates to //! true. The query key identifier is available for use within the block, as is `tcx`. //! - `cycle_delay_bug`: If a dependency cycle is detected, emit a delayed bug instead of aborting immediately. -//! - `cycle_stash`: If a dependency cycle is detected, stash the error for later handling. //! - `no_hash`: Do not hash the query result for incremental compilation; just mark as dirty if recomputed. //! - `anon`: Make the query anonymous in the dependency graph (no dep node is created). //! - `eval_always`: Always evaluate the query, ignoring its dependencies and cached results. @@ -118,7 +117,6 @@ use crate::mir::mono::{ CodegenUnit, CollectionMode, MonoItem, MonoItemPartitions, NormalizationErrorInMono, }; use crate::query::describe_as_module; -use crate::query::plumbing::CyclePlaceholder; use crate::traits::query::{ CanonicalAliasGoal, CanonicalDropckOutlivesGoal, CanonicalImpliedOutlivesBoundsGoal, CanonicalMethodAutoderefStepsGoal, CanonicalPredicateGoal, CanonicalTypeOpAscribeUserTypeGoal, @@ -339,22 +337,16 @@ rustc_queries! { feedable } - /// Returns the *hidden type* of the opaque type given by `DefId` unless a cycle occurred. - /// - /// This is a specialized instance of [`Self::type_of`] that detects query cycles. - /// Unless `CyclePlaceholder` needs to be handled separately, call [`Self::type_of`] instead. - /// This is used to improve the error message in cases where revealing the hidden type - /// for auto-trait leakage cycles. + /// Returns the *hidden type* of the opaque type given by `DefId`. /// /// # Panics /// /// This query will panic if the given definition is not an opaque type. - query type_of_opaque(key: DefId) -> Result>, CyclePlaceholder> { + query type_of_opaque(key: DefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> { desc { "computing type of opaque `{path}`", path = tcx.def_path_str(key), } - cycle_stash } query type_of_opaque_hir_typeck(key: LocalDefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> { desc { diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index a02f6f89b9b90..fc96566b069a1 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -14,7 +14,6 @@ use rustc_span::{ErrorGuaranteed, Spanned}; use crate::mir::interpret::EvalToValTreeResult; use crate::mir::mono::{MonoItem, NormalizationErrorInMono}; -use crate::query::plumbing::CyclePlaceholder; use crate::traits::solve; use crate::ty::adjustment::CoerceUnsizedInfo; use crate::ty::{self, Ty, TyCtxt}; @@ -212,10 +211,6 @@ impl Erasable for Result<&'_ ty::List>, ty::util::AlwaysRequiresDrop> { [u8; size_of::>, ty::util::AlwaysRequiresDrop>>()]; } -impl Erasable for Result>, CyclePlaceholder> { - type Storage = [u8; size_of::>, CyclePlaceholder>>()]; -} - impl Erasable for Result<(&'_ [Spanned>], &'_ [Spanned>]), NormalizationErrorInMono> { diff --git a/compiler/rustc_middle/src/query/modifiers.rs b/compiler/rustc_middle/src/query/modifiers.rs index 2bc70dd588df7..eb9fc330a2316 100644 --- a/compiler/rustc_middle/src/query/modifiers.rs +++ b/compiler/rustc_middle/src/query/modifiers.rs @@ -28,11 +28,6 @@ pub(crate) struct cache_on_disk_if; /// A cycle error results in a delay_bug call pub(crate) struct cycle_delay_bug; -/// # `cycle_stash` query modifier -/// -/// A cycle error results in a stashed cycle error that can be unstashed and canceled later -pub(crate) struct cycle_stash; - /// # `depth_limit` query modifier /// /// Whether the query has a call depth limit diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index ad0b6f7c335ef..72330eab30d58 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -7,7 +7,6 @@ use rustc_data_structures::sharded::Sharded; use rustc_data_structures::sync::{AtomicU64, WorkerLocal}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::hir_id::OwnerId; -use rustc_macros::HashStable; use rustc_span::{ErrorGuaranteed, Span}; pub use sealed::IntoQueryParam; @@ -58,7 +57,6 @@ pub enum ActiveKeyStatus<'tcx> { pub enum CycleErrorHandling { Error, DelayBug, - Stash, } #[derive(Clone, Debug)] @@ -651,9 +649,6 @@ mod sealed { } } -#[derive(Copy, Clone, Debug, HashStable)] -pub struct CyclePlaceholder(pub ErrorGuaranteed); - #[cold] pub(crate) fn default_query(name: &str, key: &dyn std::fmt::Debug) -> ! { bug!( diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 2fca85c9f2f19..a940365b90088 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -633,10 +633,6 @@ pub enum SelectionError<'tcx> { NotConstEvaluatable(NotConstEvaluatable), /// Exceeded the recursion depth during type projection. Overflow(OverflowError), - /// Computing an opaque type's hidden type caused an error (e.g. a cycle error). - /// We can thus not know whether the hidden type implements an auto trait, so - /// we should not presume anything about it. - OpaqueTypeAutoTraitLeakageUnknown(DefId), /// Error for a `ConstArgHasType` goal ConstArgHasWrongType { ct: ty::Const<'tcx>, ct_ty: Ty<'tcx>, expected_ty: Ty<'tcx> }, } diff --git a/compiler/rustc_query_impl/src/execution.rs b/compiler/rustc_query_impl/src/execution.rs index 57d503ef7b076..52e92d02b4629 100644 --- a/compiler/rustc_query_impl/src/execution.rs +++ b/compiler/rustc_query_impl/src/execution.rs @@ -5,7 +5,7 @@ use rustc_data_structures::hash_table::{Entry, HashTable}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_data_structures::{outline, sharded, sync}; -use rustc_errors::{FatalError, StashKey}; +use rustc_errors::FatalError; use rustc_middle::dep_graph::{DepGraphData, DepNodeKey, SerializedDepNodeIndex}; use rustc_middle::query::plumbing::QueryVTable; use rustc_middle::query::{ @@ -110,16 +110,6 @@ fn mk_cycle<'tcx, C: QueryCache>( let guar = error.delay_as_bug(); (query.value_from_cycle_error)(tcx, cycle_error, guar) } - CycleErrorHandling::Stash => { - let guar = if let Some(root) = cycle_error.cycle.first() - && let Some(span) = root.frame.info.span - { - error.stash(span, StashKey::Cycle).unwrap() - } else { - error.emit() - }; - (query.value_from_cycle_error)(tcx, cycle_error, guar) - } } } diff --git a/compiler/rustc_query_impl/src/from_cycle_error.rs b/compiler/rustc_query_impl/src/from_cycle_error.rs index 2599c2fde5d08..0b7f69765823f 100644 --- a/compiler/rustc_query_impl/src/from_cycle_error.rs +++ b/compiler/rustc_query_impl/src/from_cycle_error.rs @@ -12,7 +12,6 @@ use rustc_middle::dep_graph::DepKind; use rustc_middle::queries::QueryVTables; use rustc_middle::query::CycleError; use rustc_middle::query::erase::erase_val; -use rustc_middle::query::plumbing::CyclePlaceholder; use rustc_middle::ty::layout::{LayoutError, TyAndLayout}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; @@ -31,9 +30,6 @@ pub(crate) fn specialize_query_vtables<'tcx>(vtables: &mut QueryVTables<'tcx>) { vtables.erase_and_anonymize_regions_ty.value_from_cycle_error = |tcx, _, guar| erase_val(Ty::new_error(tcx, guar)); - vtables.type_of_opaque.value_from_cycle_error = - |_, _, guar| erase_val(Err(CyclePlaceholder(guar))); - vtables.fn_sig.value_from_cycle_error = |tcx, cycle, guar| erase_val(fn_sig(tcx, cycle, guar)); vtables.check_representability.value_from_cycle_error = diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 364152475e94d..f6f7635e5feb5 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -756,11 +756,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id) => return self.report_opaque_type_auto_trait_leakage( - &obligation, - def_id, - ), - SelectionError::TraitDynIncompatible(did) => { let violations = self.tcx.dyn_compatibility_violations(did); report_dyn_incompatibility(self.tcx, span, None, did, violations) @@ -3330,34 +3325,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) } - fn report_opaque_type_auto_trait_leakage( - &self, - obligation: &PredicateObligation<'tcx>, - def_id: DefId, - ) -> ErrorGuaranteed { - let name = match self.tcx.local_opaque_ty_origin(def_id.expect_local()) { - hir::OpaqueTyOrigin::FnReturn { .. } | hir::OpaqueTyOrigin::AsyncFn { .. } => { - "opaque type".to_string() - } - hir::OpaqueTyOrigin::TyAlias { .. } => { - format!("`{}`", self.tcx.def_path_debug_str(def_id)) - } - }; - let mut err = self.dcx().struct_span_err( - obligation.cause.span, - format!("cannot check whether the hidden type of {name} satisfies auto traits"), - ); - - err.note( - "fetching the hidden types of an opaque inside of the defining scope is not supported. \ - You can try moving the opaque type and the item that actually registers a hidden type into a new submodule", - ); - err.span_note(self.tcx.def_span(def_id), "opaque type is declared here"); - - self.note_obligation_cause(&mut err, &obligation); - self.dcx().try_steal_replace_and_emit_err(self.tcx.def_span(def_id), StashKey::Cycle, err) - } - fn report_signature_mismatch_error( &self, obligation: &PredicateObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index a7f47a8615c24..83d199fa8b4cd 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2404,15 +2404,11 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // We can resolve the opaque type to its hidden type, // which enforces a DAG between the functions requiring // the auto trait bounds in question. - match self.tcx().type_of_opaque(def_id) { - Ok(ty) => ty::Binder::dummy(AutoImplConstituents { - types: vec![ty.instantiate(self.tcx(), args)], - assumptions: vec![], - }), - Err(_) => { - return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id)); - } - } + let ty = self.tcx().type_of_opaque(def_id); + ty::Binder::dummy(AutoImplConstituents { + types: vec![ty.instantiate(self.tcx(), args)], + assumptions: vec![], + }) } } }) diff --git a/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.rs b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.rs index de4f523c23aa1..c2fab7d4c5f68 100644 --- a/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.rs +++ b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.rs @@ -8,7 +8,7 @@ fn main() {} // Cycles should work as the deferred obligations are // independently resolved and only require the concrete // return type, which can't depend on the obligation. -fn cycle1() -> impl Clone { +fn cycle1() -> impl Clone { //~ ERROR: cycle detected send(cycle2().clone()); Rc::new(Cell::new(5)) @@ -16,7 +16,6 @@ fn cycle1() -> impl Clone { fn cycle2() -> impl Clone { send(cycle1().clone()); - //~^ ERROR: cannot check whether the hidden type of opaque type satisfies auto traits Rc::new(String::from("foo")) } diff --git a/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.stderr b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.stderr index cc9939f2d57f9..ae10516999882 100644 --- a/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.stderr +++ b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.stderr @@ -1,22 +1,84 @@ -error: cannot check whether the hidden type of opaque type satisfies auto traits - --> $DIR/auto-trait-leak.rs:18:10 +error[E0391]: cycle detected when computing type of opaque `cycle1::{opaque#0}` + --> $DIR/auto-trait-leak.rs:11:16 | -LL | send(cycle1().clone()); - | ---- ^^^^^^^^^^^^^^^^ - | | - | required by a bound introduced by this call +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^ | - = note: fetching the hidden types of an opaque inside of the defining scope is not supported. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule -note: opaque type is declared here - --> $DIR/auto-trait-leak.rs:11:16 +note: ...which requires borrow-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:11:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires promoting constants in MIR for `cycle1`... + --> $DIR/auto-trait-leak.rs:11:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires checking if `cycle1` contains FFI-unwind calls... + --> $DIR/auto-trait-leak.rs:11:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for `cycle1`... + --> $DIR/auto-trait-leak.rs:11:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires match-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:11:1 | LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:5 + | +LL | send(cycle2().clone()); + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which requires evaluating trait selection obligation `cycle2::{opaque#0}: core::marker::Send`... +note: ...which requires computing type of opaque `cycle2::{opaque#0}`... + --> $DIR/auto-trait-leak.rs:17:16 + | +LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^ -note: required by a bound in `send` - --> $DIR/auto-trait-leak.rs:4:12 +note: ...which requires borrow-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:17:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires promoting constants in MIR for `cycle2`... + --> $DIR/auto-trait-leak.rs:17:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires checking if `cycle2` contains FFI-unwind calls... + --> $DIR/auto-trait-leak.rs:17:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for `cycle2`... + --> $DIR/auto-trait-leak.rs:17:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires match-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:17:1 | -LL | fn send(_: T) {} - | ^^^^ required by this bound in `send` +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:18:5 + | +LL | send(cycle1().clone()); + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which requires evaluating trait selection obligation `cycle1::{opaque#0}: core::marker::Send`... + = note: ...which again requires computing type of opaque `cycle1::{opaque#0}`, completing the cycle +note: cycle used when computing type of `cycle1::{opaque#0}` + --> $DIR/auto-trait-leak.rs:11:16 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/type-alias-impl-trait/in-where-clause.rs b/tests/ui/type-alias-impl-trait/in-where-clause.rs index 8d5bfc48a66e9..f4b788b5b6803 100644 --- a/tests/ui/type-alias-impl-trait/in-where-clause.rs +++ b/tests/ui/type-alias-impl-trait/in-where-clause.rs @@ -11,7 +11,6 @@ where Bar: Send, { [0; 1 + 2] - //~^ ERROR: type annotations needed: cannot satisfy `Bar: Send` } fn main() {} diff --git a/tests/ui/type-alias-impl-trait/in-where-clause.stderr b/tests/ui/type-alias-impl-trait/in-where-clause.stderr index 81be8c8362e35..fcb590a961c18 100644 --- a/tests/ui/type-alias-impl-trait/in-where-clause.stderr +++ b/tests/ui/type-alias-impl-trait/in-where-clause.stderr @@ -1,19 +1,3 @@ -error[E0283]: type annotations needed: cannot satisfy `Bar: Send` - --> $DIR/in-where-clause.rs:13:9 - | -LL | [0; 1 + 2] - | ^^^^^ - | - = note: cannot satisfy `Bar: Send` -note: required by a bound in `foo` - --> $DIR/in-where-clause.rs:11:10 - | -LL | fn foo() -> Bar - | --- required by a bound in this function -LL | where -LL | Bar: Send, - | ^^^^ required by this bound in `foo` - error[E0391]: cycle detected when computing type of opaque `Bar::{opaque#0}` --> $DIR/in-where-clause.rs:5:12 | @@ -77,7 +61,6 @@ LL | type Bar = impl Sized; = note: cycle used when evaluating trait selection obligation `Bar: core::marker::Send` = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0283, E0391. -For more information about an error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0391`. From 59733c61e88ab0dd4b2cdb097677b44a15b1fa9e Mon Sep 17 00:00:00 2001 From: cyrgani Date: Wed, 11 Mar 2026 11:09:43 +0000 Subject: [PATCH 4/6] remove `.ftl` checks from tidy --- src/tools/tidy/src/style.rs | 11 ++--------- src/tools/tidy/src/ui_tests.rs | 1 - 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 111fe89e7eb0a..3c2cddb2516dc 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -227,8 +227,6 @@ fn should_ignore(line: &str) -> bool { /// Returns `true` if `line` is allowed to be longer than the normal limit. fn long_line_is_ok(extension: &str, is_error_code: bool, max_columns: usize, line: &str) -> bool { match extension { - // fluent files are allowed to be any length - "ftl" => true, // non-error code markdown is allowed to be any length "md" if !is_error_code => true, // HACK(Ezrashaw): there is no way to split a markdown header over multiple lines @@ -357,7 +355,7 @@ pub fn check(path: &Path, tidy_ctx: TidyCtx) { return false; } - let extensions = ["rs", "py", "js", "sh", "c", "cpp", "h", "md", "css", "ftl", "goml"]; + let extensions = ["rs", "py", "js", "sh", "c", "cpp", "h", "md", "css", "goml"]; // NB: don't skip paths without extensions (or else we'll skip all directories and will only check top level files) if path.extension().is_none_or(|ext| !extensions.iter().any(|e| ext == OsStr::new(e))) { @@ -602,12 +600,7 @@ pub fn check(path: &Path, tidy_ctx: TidyCtx) { err(DOUBLE_SPACE_AFTER_DOT) } - if filename.ends_with(".ftl") { - let line_backticks = trimmed.chars().filter(|ch| *ch == '`').count(); - if line_backticks % 2 == 1 { - suppressible_tidy_err!(err, skip_odd_backticks, "odd number of backticks"); - } - } else if trimmed.contains("//") { + if trimmed.contains("//") { let (start_line, mut backtick_count) = comment_block.unwrap_or((i + 1, 0)); let line_backticks = trimmed.chars().filter(|ch| *ch == '`').count(); let comment_text = trimmed.split("//").nth(1).unwrap(); diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index c16cfbe899b7b..50ec411987672 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -214,7 +214,6 @@ fn check_unexpected_extension(check: &mut RunningCheck, file_path: &Path, ext: & "stdout", // expected stdout file, corresponds to a rs file "fixed", // expected source file after applying fixes "md", // test directory descriptions - "ftl", // translation tests ]; const EXTENSION_EXCEPTION_PATHS: &[&str] = &[ From 0059012ab24e2a556682fcb21c16852bc3c14610 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 10 Mar 2026 18:20:32 +1100 Subject: [PATCH 5/6] Introduce `for_each_query_vtable!` to move more code out of query macros --- compiler/rustc_query_impl/src/execution.rs | 31 +++- compiler/rustc_query_impl/src/job.rs | 2 +- compiler/rustc_query_impl/src/lib.rs | 11 +- compiler/rustc_query_impl/src/plumbing.rs | 149 +++++++----------- .../rustc_query_impl/src/profiling_support.rs | 33 +++- 5 files changed, 129 insertions(+), 97 deletions(-) diff --git a/compiler/rustc_query_impl/src/execution.rs b/compiler/rustc_query_impl/src/execution.rs index 57d503ef7b076..a240a7d035ccb 100644 --- a/compiler/rustc_query_impl/src/execution.rs +++ b/compiler/rustc_query_impl/src/execution.rs @@ -16,8 +16,8 @@ use rustc_middle::ty::TyCtxt; use rustc_middle::verify_ich::incremental_verify_ich; use rustc_span::{DUMMY_SP, Span}; -use crate::collect_active_jobs_from_all_queries; use crate::dep_graph::{DepNode, DepNodeIndex}; +use crate::for_each_query_vtable; use crate::job::{QueryJobInfo, QueryJobMap, find_cycle_in_stack, report_cycle}; use crate::plumbing::{current_query_job, next_job_id, start_query}; @@ -30,6 +30,33 @@ pub(crate) fn all_inactive<'tcx, K>(state: &QueryState<'tcx, K>) -> bool { state.active.lock_shards().all(|shard| shard.is_empty()) } +/// Returns a map of currently active query jobs, collected from all queries. +/// +/// If `require_complete` is `true`, this function locks all shards of the +/// query results to produce a complete map, which always returns `Ok`. +/// Otherwise, it may return an incomplete map as an error if any shard +/// lock cannot be acquired. +/// +/// Prefer passing `false` to `require_complete` to avoid potential deadlocks, +/// especially when called from within a deadlock handler, unless a +/// complete map is needed and no deadlock is possible at this call site. +pub fn collect_active_jobs_from_all_queries<'tcx>( + tcx: TyCtxt<'tcx>, + require_complete: bool, +) -> Result, QueryJobMap<'tcx>> { + let mut job_map_out = QueryJobMap::default(); + let mut complete = true; + + for_each_query_vtable!(ALL, tcx, |query| { + let res = gather_active_jobs(query, tcx, require_complete, &mut job_map_out); + if res.is_none() { + complete = false; + } + }); + + if complete { Ok(job_map_out) } else { Err(job_map_out) } +} + /// Internal plumbing for collecting the set of active jobs for this query. /// /// Should only be called from `collect_active_jobs_from_all_queries`. @@ -37,7 +64,7 @@ pub(crate) fn all_inactive<'tcx, K>(state: &QueryState<'tcx, K>) -> bool { /// (We arbitrarily use the word "gather" when collecting the jobs for /// each individual query, so that we have distinct function names to /// grep for.) -pub(crate) fn gather_active_jobs<'tcx, C>( +fn gather_active_jobs<'tcx, C>( query: &'tcx QueryVTable<'tcx, C>, tcx: TyCtxt<'tcx>, require_complete: bool, diff --git a/compiler/rustc_query_impl/src/job.rs b/compiler/rustc_query_impl/src/job.rs index 2a7f7bf5efd41..744bac4722a91 100644 --- a/compiler/rustc_query_impl/src/job.rs +++ b/compiler/rustc_query_impl/src/job.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::{DUMMY_SP, Span}; -use crate::collect_active_jobs_from_all_queries; +use crate::execution::collect_active_jobs_from_all_queries; /// Map from query job IDs to job information collected by /// `collect_active_jobs_from_all_queries`. diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 6482384f99ea3..41642f66967da 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -11,15 +11,15 @@ use rustc_data_structures::sync::AtomicU64; use rustc_middle::dep_graph; use rustc_middle::queries::{self, ExternProviders, Providers}; -use rustc_middle::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex, OnDiskCache}; +use rustc_middle::query::on_disk_cache::OnDiskCache; use rustc_middle::query::plumbing::{QuerySystem, QueryVTable}; use rustc_middle::query::{AsLocalQueryKey, QueryCache, QueryMode}; use rustc_middle::ty::TyCtxt; use rustc_span::Span; pub use crate::dep_kind_vtables::make_dep_kind_vtables; +pub use crate::execution::collect_active_jobs_from_all_queries; pub use crate::job::{QueryJobMap, break_query_cycles, print_query_stack}; -use crate::profiling_support::QueryKeyStringCache; #[macro_use] mod plumbing; @@ -66,7 +66,8 @@ pub fn query_system<'tcx>( rustc_middle::rustc_with_all_queries! { define_queries! } pub fn provide(providers: &mut rustc_middle::util::Providers) { - providers.hooks.alloc_self_profile_query_strings = alloc_self_profile_query_strings; - providers.hooks.query_key_hash_verify_all = query_key_hash_verify_all; - providers.hooks.encode_all_query_results = encode_all_query_results; + providers.hooks.alloc_self_profile_query_strings = + profiling_support::alloc_self_profile_query_strings; + providers.hooks.query_key_hash_verify_all = plumbing::query_key_hash_verify_all; + providers.hooks.encode_all_query_results = plumbing::encode_all_query_results; } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 558ecdda5c4b0..ddce892345907 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -33,7 +33,7 @@ use rustc_span::def_id::LOCAL_CRATE; use crate::error::{QueryOverflow, QueryOverflowNote}; use crate::execution::{all_inactive, force_query}; use crate::job::find_dep_kind_root; -use crate::{GetQueryVTable, collect_active_jobs_from_all_queries}; +use crate::{GetQueryVTable, collect_active_jobs_from_all_queries, for_each_query_vtable}; fn depth_limit_error<'tcx>(tcx: TyCtxt<'tcx>, job: QueryJobId) { let job_map = @@ -146,7 +146,17 @@ where QueryStackFrame::new(info, kind, def_id, def_id_for_ty_in_cycle) } -pub(crate) fn encode_query_results<'a, 'tcx, C, V>( +pub(crate) fn encode_all_query_results<'tcx>( + tcx: TyCtxt<'tcx>, + encoder: &mut CacheEncoder<'_, 'tcx>, + query_result_index: &mut EncodedDepNodeIndex, +) { + for_each_query_vtable!(CACHE_ON_DISK, tcx, |query| { + encode_query_results(tcx, query, encoder, query_result_index) + }); +} + +fn encode_query_results<'a, 'tcx, C, V>( tcx: TyCtxt<'tcx>, query: &'tcx QueryVTable<'tcx, C>, encoder: &mut CacheEncoder<'a, 'tcx>, @@ -172,7 +182,17 @@ pub(crate) fn encode_query_results<'a, 'tcx, C, V>( }); } -pub(crate) fn query_key_hash_verify<'tcx, C: QueryCache>( +pub(crate) fn query_key_hash_verify_all<'tcx>(tcx: TyCtxt<'tcx>) { + if tcx.sess.opts.unstable_opts.incremental_verify_ich || cfg!(debug_assertions) { + tcx.sess.time("query_key_hash_verify_all", || { + for_each_query_vtable!(ALL, tcx, |query| { + query_key_hash_verify(query, tcx); + }); + }); + } +} + +fn query_key_hash_verify<'tcx, C: QueryCache>( query: &'tcx QueryVTable<'tcx, C>, tcx: TyCtxt<'tcx>, ) { @@ -510,95 +530,48 @@ macro_rules! define_queries { } } - /// Returns a map of currently active query jobs, collected from all queries. + /// Given a filter condition (e.g. `ALL` or `CACHE_ON_DISK`), a `tcx`, + /// and a closure expression that accepts `&QueryVTable`, this macro + /// calls that closure with each query vtable that satisfies the filter + /// condition. /// - /// If `require_complete` is `true`, this function locks all shards of the - /// query results to produce a complete map, which always returns `Ok`. - /// Otherwise, it may return an incomplete map as an error if any shard - /// lock cannot be acquired. + /// This needs to be a macro, because the vtables can have different + /// key/value/cache types for different queries. /// - /// Prefer passing `false` to `require_complete` to avoid potential deadlocks, - /// especially when called from within a deadlock handler, unless a - /// complete map is needed and no deadlock is possible at this call site. - pub fn collect_active_jobs_from_all_queries<'tcx>( - tcx: TyCtxt<'tcx>, - require_complete: bool, - ) -> Result, QueryJobMap<'tcx>> { - let mut job_map_out = QueryJobMap::default(); - let mut complete = true; - - $( - let res = crate::execution::gather_active_jobs( - &tcx.query_system.query_vtables.$name, - tcx, - require_complete, - &mut job_map_out, - ); - if res.is_none() { - complete = false; - } - )* - - if complete { Ok(job_map_out) } else { Err(job_map_out) } - } - - /// All self-profiling events generated by the query engine use - /// virtual `StringId`s for their `event_id`. This method makes all - /// those virtual `StringId`s point to actual strings. + /// This macro's argument syntax is specifically intended to look like + /// plain Rust code, so that `for_each_query_vtable!(..)` calls will be + /// formatted by rustfmt. /// - /// If we are recording only summary data, the ids will point to - /// just the query names. If we are recording query keys too, we - /// allocate the corresponding strings here. - pub fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) { - if !tcx.prof.enabled() { - return; - } - - let _prof_timer = tcx.sess.prof.generic_activity("self_profile_alloc_query_strings"); - - let mut string_cache = QueryKeyStringCache::new(); - - $( - $crate::profiling_support::alloc_self_profile_query_strings_for_query_cache( - tcx, - stringify!($name), - &tcx.query_system.query_vtables.$name.cache, - &mut string_cache, - ); - )* - - tcx.sess.prof.store_query_cache_hits(); - } - - fn encode_all_query_results<'tcx>( - tcx: TyCtxt<'tcx>, - encoder: &mut CacheEncoder<'_, 'tcx>, - query_result_index: &mut EncodedDepNodeIndex, - ) { - $( - #[cfg($cache_on_disk)] - { - $crate::plumbing::encode_query_results( - tcx, - &tcx.query_system.query_vtables.$name, - encoder, - query_result_index, - ) - } - )* + /// To avoid too much nested-macro complication, filter conditions are + /// implemented by hand as needed. + macro_rules! for_each_query_vtable { + // Call with all queries. + (ALL, $tcx:expr, $closure:expr) => {{ + let tcx: rustc_middle::ty::TyCtxt<'_> = $tcx; + $( + let query: &rustc_middle::query::plumbing::QueryVTable<'_, _> = + &tcx.query_system.query_vtables.$name; + $closure(query); + )* + }}; + + // Only call with queries that can potentially cache to disk. + // + // This allows the use of trait bounds that only need to be satisfied + // by the subset of queries that actually cache to disk. + (CACHE_ON_DISK, $tcx:expr, $closure:expr) => {{ + let tcx: rustc_middle::ty::TyCtxt<'_> = $tcx; + $( + #[cfg($cache_on_disk)] + { + let query: &rustc_middle::query::plumbing::QueryVTable<'_, _> = + &tcx.query_system.query_vtables.$name; + $closure(query); + } + )* + }} } - pub fn query_key_hash_verify_all<'tcx>(tcx: TyCtxt<'tcx>) { - if tcx.sess.opts.unstable_opts.incremental_verify_ich || cfg!(debug_assertions) { - tcx.sess.time("query_key_hash_verify_all", || { - $( - $crate::plumbing::query_key_hash_verify( - &tcx.query_system.query_vtables.$name, - tcx - ); - )* - }) - } - } + pub(crate) use for_each_query_vtable; } } diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs index 0c0e966f1fa43..08fbd88ac8eec 100644 --- a/compiler/rustc_query_impl/src/profiling_support.rs +++ b/compiler/rustc_query_impl/src/profiling_support.rs @@ -7,8 +7,11 @@ use rustc_data_structures::profiling::SelfProfiler; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE, LocalDefId}; use rustc_hir::definitions::DefPathData; use rustc_middle::query::QueryCache; +use rustc_middle::query::plumbing::QueryVTable; use rustc_middle::ty::TyCtxt; +use crate::for_each_query_vtable; + pub(crate) struct QueryKeyStringCache { def_id_cache: FxHashMap, } @@ -172,10 +175,38 @@ where } } +/// All self-profiling events generated by the query engine use +/// virtual `StringId`s for their `event_id`. This method makes all +/// those virtual `StringId`s point to actual strings. +/// +/// If we are recording only summary data, the ids will point to +/// just the query names. If we are recording query keys too, we +/// allocate the corresponding strings here. +pub(crate) fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) { + if !tcx.prof.enabled() { + return; + } + + let _prof_timer = tcx.sess.prof.generic_activity("self_profile_alloc_query_strings"); + + let mut string_cache = QueryKeyStringCache::new(); + + for_each_query_vtable!(ALL, tcx, |query: &QueryVTable<'_, _>| { + alloc_self_profile_query_strings_for_query_cache( + tcx, + query.name, + &query.cache, + &mut string_cache, + ); + }); + + tcx.sess.prof.store_query_cache_hits(); +} + /// Allocate the self-profiling query strings for a single query cache. This /// method is called from `alloc_self_profile_query_strings` which knows all /// the queries via macro magic. -pub(crate) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>( +fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>( tcx: TyCtxt<'tcx>, query_name: &'static str, query_cache: &C, From d066ff726319231ac519ecbc3e1d2996320f34a0 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 11 Mar 2026 13:49:56 +1100 Subject: [PATCH 6/6] Pass the vtable to `alloc_self_profile_query_strings_for_query_cache` This simplifies the inner function's signature, and makes it more consistent with other uses of `for_each_query_vtable!`. --- .../rustc_query_impl/src/profiling_support.rs | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs index 08fbd88ac8eec..c88bc8845ebdb 100644 --- a/compiler/rustc_query_impl/src/profiling_support.rs +++ b/compiler/rustc_query_impl/src/profiling_support.rs @@ -191,13 +191,8 @@ pub(crate) fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) { let mut string_cache = QueryKeyStringCache::new(); - for_each_query_vtable!(ALL, tcx, |query: &QueryVTable<'_, _>| { - alloc_self_profile_query_strings_for_query_cache( - tcx, - query.name, - &query.cache, - &mut string_cache, - ); + for_each_query_vtable!(ALL, tcx, |query| { + alloc_self_profile_query_strings_for_query_cache(tcx, query, &mut string_cache); }); tcx.sess.prof.store_query_cache_hits(); @@ -208,8 +203,7 @@ pub(crate) fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) { /// the queries via macro magic. fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>( tcx: TyCtxt<'tcx>, - query_name: &'static str, - query_cache: &C, + query: &'tcx QueryVTable<'tcx, C>, string_cache: &mut QueryKeyStringCache, ) where C: QueryCache, @@ -224,14 +218,14 @@ fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>( if profiler.query_key_recording_enabled() { let mut query_string_builder = QueryKeyStringBuilder::new(profiler, tcx, string_cache); - let query_name = profiler.get_or_alloc_cached_string(query_name); + let query_name = profiler.get_or_alloc_cached_string(query.name); // Since building the string representation of query keys might // need to invoke queries itself, we cannot keep the query caches // locked while doing so. Instead we copy out the // `(query_key, dep_node_index)` pairs and release the lock again. let mut query_keys_and_indices = Vec::new(); - query_cache.for_each(&mut |k, _, i| query_keys_and_indices.push((*k, i))); + query.cache.for_each(&mut |k, _, i| query_keys_and_indices.push((*k, i))); // Now actually allocate the strings. If allocating the strings // generates new entries in the query cache, we'll miss them but @@ -252,14 +246,14 @@ fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>( } } else { // In this branch we don't allocate query keys - let query_name = profiler.get_or_alloc_cached_string(query_name); + let query_name = profiler.get_or_alloc_cached_string(query.name); let event_id = event_id_builder.from_label(query_name).to_string_id(); // FIXME(eddyb) make this O(1) by using a pre-cached query name `EventId`, // instead of passing the `DepNodeIndex` to `finish_with_query_invocation_id`, // when recording the event in the first place. let mut query_invocation_ids = Vec::new(); - query_cache.for_each(&mut |_, _, i| { + query.cache.for_each(&mut |_, _, i| { query_invocation_ids.push(i.into()); });