From 4dc82e99efad0d0fbb91218b82394a48fcd0ed87 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 5 Feb 2026 18:21:27 +1100 Subject: [PATCH] Move the needs-drop check for `arena_cache` queries out of macro code --- compiler/rustc_middle/src/queries.rs | 1 - .../rustc_middle/src/query/arena_cached.rs | 33 +++++++++----- compiler/rustc_middle/src/query/plumbing.rs | 44 ++++++++----------- 3 files changed, 40 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index de22989144389..2fdc44ecd2691 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -63,7 +63,6 @@ #![allow(unused_parens)] use std::ffi::OsStr; -use std::mem; use std::path::PathBuf; use std::sync::Arc; diff --git a/compiler/rustc_middle/src/query/arena_cached.rs b/compiler/rustc_middle/src/query/arena_cached.rs index ec6e466ff688c..7c7ad12622604 100644 --- a/compiler/rustc_middle/src/query/arena_cached.rs +++ b/compiler/rustc_middle/src/query/arena_cached.rs @@ -1,3 +1,9 @@ +use std::mem; + +use rustc_arena::TypedArena; + +use crate::ty::TyCtxt; + /// Helper trait that allows `arena_cache` queries to return `Option<&T>` /// instead of `&Option`, and avoid allocating `None` in the arena. /// @@ -11,10 +17,11 @@ pub trait ArenaCached<'tcx>: Sized { /// Type that is stored in the arena. type Allocated: 'tcx; - /// Takes a provided value, and allocates it in the arena (if appropriate) - /// with the help of the given `arena_alloc` closure. + /// Takes a provided value, and allocates it in an appropriate arena, + /// unless the particular value doesn't need allocation (e.g. `None`). fn alloc_in_arena( - arena_alloc: impl Fn(Self::Allocated) -> &'tcx Self::Allocated, + tcx: TyCtxt<'tcx>, + typed_arena: &'tcx TypedArena, value: Self::Provided, ) -> Self; } @@ -23,12 +30,9 @@ impl<'tcx, T> ArenaCached<'tcx> for &'tcx T { type Provided = T; type Allocated = T; - fn alloc_in_arena( - arena_alloc: impl Fn(Self::Allocated) -> &'tcx Self::Allocated, - value: Self::Provided, - ) -> Self { + fn alloc_in_arena(tcx: TyCtxt<'tcx>, typed_arena: &'tcx TypedArena, value: T) -> Self { // Just allocate in the arena normally. - arena_alloc(value) + do_alloc(tcx, typed_arena, value) } } @@ -38,10 +42,17 @@ impl<'tcx, T> ArenaCached<'tcx> for Option<&'tcx T> { type Allocated = T; fn alloc_in_arena( - arena_alloc: impl Fn(Self::Allocated) -> &'tcx Self::Allocated, - value: Self::Provided, + tcx: TyCtxt<'tcx>, + typed_arena: &'tcx TypedArena, + value: Option, ) -> Self { // Don't store None in the arena, and wrap the allocated reference in Some. - value.map(arena_alloc) + try { do_alloc(tcx, typed_arena, value?) } } } + +/// Allocates a value in either its dedicated arena, or in the common dropless +/// arena, depending on whether it needs to be dropped. +fn do_alloc<'tcx, T>(tcx: TyCtxt<'tcx>, typed_arena: &'tcx TypedArena, value: T) -> &'tcx T { + if mem::needs_drop::() { typed_arena.alloc(value) } else { tcx.arena.dropless.alloc(value) } +} diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 04a3ceb0918af..b80f096ec9935 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -295,36 +295,28 @@ macro_rules! define_callbacks { ($V) ); - /// This function takes `ProvidedValue` and converts it to an erased `Value` by - /// allocating it on an arena if the query has the `arena_cache` modifier. The - /// value is then erased and returned. This will happen when computing the query - /// using a provider or decoding a stored result. + /// This helper function takes a value returned by the query provider + /// (or loaded from disk, or supplied by query feeding), allocates + /// it in an arena if requested by the `arena_cache` modifier, and + /// then returns an erased copy of it. #[inline(always)] pub fn provided_to_erased<'tcx>( - _tcx: TyCtxt<'tcx>, + tcx: TyCtxt<'tcx>, provided_value: ProvidedValue<'tcx>, ) -> Erased> { - // Store the provided value in an arena and get a reference - // to it, for queries with `arena_cache`. - let value: Value<'tcx> = query_if_arena!([$($modifiers)*] - { - use $crate::query::arena_cached::ArenaCached; - - if mem::needs_drop::<<$V as ArenaCached<'tcx>>::Allocated>() { - <$V as ArenaCached>::alloc_in_arena( - |v| _tcx.query_system.arenas.$name.alloc(v), - provided_value, - ) - } else { - <$V as ArenaCached>::alloc_in_arena( - |v| _tcx.arena.dropless.alloc(v), - provided_value, - ) - } - } - // Otherwise, the provided value is the value. - (provided_value) - ); + // For queries with the `arena_cache` modifier, store the + // provided value in an arena and get a reference to it. + let value: Value<'tcx> = query_if_arena!([$($modifiers)*] { + <$V as $crate::query::arena_cached::ArenaCached>::alloc_in_arena( + tcx, + &tcx.query_system.arenas.$name, + provided_value, + ) + } { + // Otherwise, the provided value is the value (and `tcx` is unused). + let _ = tcx; + provided_value + }); erase::erase_val(value) }