From 6c99f69a2838ede0bdb24d9a90a4b586328e4939 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 19 Aug 2026 21:39:48 +1000 Subject: [PATCH 1/4] Fix obvious copy/paste bug in `State::fmt_diff_with` --- compiler/rustc_const_eval/src/check_consts/resolver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs index 29b6e26d950d5..fa2ff057f64f2 100644 --- a/compiler/rustc_const_eval/src/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs @@ -309,7 +309,7 @@ impl DebugWithContext for State { if self.borrow != old.borrow { f.write_str("borrow: ")?; - self.qualif.fmt_diff_with(&old.borrow, ctxt, f)?; + self.borrow.fmt_diff_with(&old.borrow, ctxt, f)?; f.write_str("\n")?; } From dffe2777a0963d1fb01fb3c67e85068f1510b2fa Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 19 Aug 2026 21:49:16 +1000 Subject: [PATCH 2/4] Remove unnecessary arg from `FlowSensitiveAnalysis::new` --- compiler/rustc_const_eval/src/check_consts/check.rs | 6 +++--- compiler/rustc_const_eval/src/check_consts/resolver.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 7648bf4eb241d..b79286f030be5 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -69,7 +69,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { let needs_drop = self.needs_drop.get_or_insert_with(|| { let ConstCx { tcx, body, .. } = *ccx; - FlowSensitiveAnalysis::new(NeedsDrop, ccx) + FlowSensitiveAnalysis::new(ccx) .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body) }); @@ -98,7 +98,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { let needs_non_const_drop = self.needs_non_const_drop.get_or_insert_with(|| { let ConstCx { tcx, body, .. } = *ccx; - FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx) + FlowSensitiveAnalysis::new(ccx) .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body) }); @@ -127,7 +127,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { let has_mut_interior = self.has_mut_interior.get_or_insert_with(|| { let ConstCx { tcx, body, .. } = *ccx; - FlowSensitiveAnalysis::new(HasMutInterior, ccx) + FlowSensitiveAnalysis::new(ccx) .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body) }); diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs index fa2ff057f64f2..4fc8c62ccf80a 100644 --- a/compiler/rustc_const_eval/src/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs @@ -247,7 +247,7 @@ impl<'mir, 'tcx, Q> FlowSensitiveAnalysis<'mir, 'tcx, Q> where Q: Qualif, { - pub(super) fn new(_: Q, ccx: &'mir ConstCx<'mir, 'tcx>) -> Self { + pub(super) fn new(ccx: &'mir ConstCx<'mir, 'tcx>) -> Self { FlowSensitiveAnalysis { ccx, _qualif: PhantomData } } From c7ead52dcd58af93a3daac4ba2af452fd0795a2b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 19 Aug 2026 22:08:31 +1000 Subject: [PATCH 3/4] Factor out duplicated code in `Qualifs` --- .../src/check_consts/check.rs | 103 ++++++------------ 1 file changed, 31 insertions(+), 72 deletions(-) diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index b79286f030be5..b1efe62e57a04 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -49,69 +49,11 @@ pub(crate) struct Qualifs<'mir, 'tcx> { } impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { - /// Returns `true` if `local` is `NeedsDrop` at the given `Location`. - /// - /// Only updates the cursor if absolutely necessary - pub(crate) fn needs_drop( - &mut self, - ccx: &'mir ConstCx<'mir, 'tcx>, - local: Local, - location: Location, - ) -> bool { - let ty = ccx.body.local_decls[local].ty; - // Peeking into opaque types causes cycles if the current function declares said opaque - // type. Thus we avoid short circuiting on the type and instead run the more expensive - // analysis that looks at the actual usage within this function - if !ty.has_opaque_types() && !NeedsDrop::in_any_value_of_ty(ccx, ty) { - return false; - } - - let needs_drop = self.needs_drop.get_or_insert_with(|| { - let ConstCx { tcx, body, .. } = *ccx; - - FlowSensitiveAnalysis::new(ccx) - .iterate_to_fixpoint(tcx, body, None) - .into_results_cursor(body) - }); - - needs_drop.seek_before_primary_effect(location); - needs_drop.get().contains(local) - } - - /// Returns `true` if `local` is `NeedsNonConstDrop` at the given `Location`. - /// - /// Only updates the cursor if absolutely necessary - pub(crate) fn needs_non_const_drop( - &mut self, - ccx: &'mir ConstCx<'mir, 'tcx>, - local: Local, - location: Location, - ) -> bool { - let ty = ccx.body.local_decls[local].ty; - // Peeking into opaque types causes cycles if the current function declares said opaque - // type. Thus we avoid short circuiting on the type and instead run the more expensive - // analysis that looks at the actual usage within this function - if !ty.has_opaque_types() && !NeedsNonConstDrop::in_any_value_of_ty(ccx, ty) { - return false; - } - - let needs_non_const_drop = self.needs_non_const_drop.get_or_insert_with(|| { - let ConstCx { tcx, body, .. } = *ccx; - - FlowSensitiveAnalysis::new(ccx) - .iterate_to_fixpoint(tcx, body, None) - .into_results_cursor(body) - }); - - needs_non_const_drop.seek_before_primary_effect(location); - needs_non_const_drop.get().contains(local) - } - - /// Returns `true` if `local` is `HasMutInterior` at the given `Location`. + /// Does `Q` hold for the `local` at the given `Location`? /// /// Only updates the cursor if absolutely necessary. - fn has_mut_interior( - &mut self, + fn in_local( + qualif_results: &mut Option>, ccx: &'mir ConstCx<'mir, 'tcx>, local: Local, location: Location, @@ -119,12 +61,12 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { let ty = ccx.body.local_decls[local].ty; // Peeking into opaque types causes cycles if the current function declares said opaque // type. Thus we avoid short circuiting on the type and instead run the more expensive - // analysis that looks at the actual usage within this function - if !ty.has_opaque_types() && !HasMutInterior::in_any_value_of_ty(ccx, ty) { + // analysis that looks at the actual usage within this function. + if !ty.has_opaque_types() && !Q::in_any_value_of_ty(ccx, ty) { return false; } - let has_mut_interior = self.has_mut_interior.get_or_insert_with(|| { + let qualif_results = qualif_results.get_or_insert_with(|| { let ConstCx { tcx, body, .. } = *ccx; FlowSensitiveAnalysis::new(ccx) @@ -132,8 +74,8 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { .into_results_cursor(body) }); - has_mut_interior.seek_before_primary_effect(location); - has_mut_interior.get().contains(local) + qualif_results.seek_before_primary_effect(location); + qualif_results.get().contains(local) } fn in_return_place( @@ -161,9 +103,19 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { let return_loc = ccx.body.terminator_loc(return_block); ConstQualifs { - needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc), - needs_non_const_drop: self.needs_non_const_drop(ccx, RETURN_PLACE, return_loc), - has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc), + needs_drop: Self::in_local(&mut self.needs_drop, ccx, RETURN_PLACE, return_loc), + needs_non_const_drop: Self::in_local( + &mut self.needs_non_const_drop, + ccx, + RETURN_PLACE, + return_loc, + ), + has_mut_interior: Self::in_local( + &mut self.has_mut_interior, + ccx, + RETURN_PLACE, + return_loc, + ), tainted_by_errors, } } @@ -435,7 +387,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { let ty_of_dropped_place = dropped_place.ty(self.body, self.tcx).ty; let needs_drop = if let Some(local) = dropped_place.as_local() { - self.qualifs.needs_drop(self.ccx, local, location) + Qualifs::in_local(&mut self.qualifs.needs_drop, self.ccx, local, location) } else { qualifs::NeedsDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place) }; @@ -448,7 +400,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { let needs_non_const_drop = if let Some(local) = dropped_place.as_local() { // Use the span where the local was declared as the span of the drop error. err_span = self.body.local_decls[local].source_info.span; - self.qualifs.needs_non_const_drop(self.ccx, local, location) + Qualifs::in_local(&mut self.qualifs.needs_non_const_drop, self.ccx, local, location) } else { qualifs::NeedsNonConstDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place) }; @@ -602,7 +554,14 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { | Rvalue::RawPtr(RawPtrKind::Const, place) => { let borrowed_place_has_mut_interior = qualifs::in_place::( self.ccx, - &mut |local| self.qualifs.has_mut_interior(self.ccx, local, location), + &mut |local| { + Qualifs::in_local( + &mut self.qualifs.has_mut_interior, + self.ccx, + local, + location, + ) + }, place.as_ref(), ); From 6229d6d70ef5d4d220f7db9b8d2cdab08b369253 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 20 Aug 2026 08:49:34 +1000 Subject: [PATCH 4/4] Remove defaults for `Qualif` assoc consts There are only three impls of `Qualif`, and the extra explicitness is clearer. --- compiler/rustc_const_eval/src/check_consts/qualifs.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index b2b8a567860e0..daac2d5176258 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -45,10 +45,10 @@ pub trait Qualif { const ANALYSIS_NAME: &'static str; /// Whether this `Qualif` is cleared when a local is moved from. - const IS_CLEARED_ON_MOVE: bool = false; + const IS_CLEARED_ON_MOVE: bool; /// Whether this `Qualif` might be evaluated after the promotion and can encounter a promoted. - const ALLOW_PROMOTED: bool = false; + const ALLOW_PROMOTED: bool; /// Extracts the field of `ConstQualifs` that corresponds to this `Qualif`. fn in_qualifs(qualifs: &ConstQualifs) -> bool; @@ -79,6 +79,8 @@ pub struct HasMutInterior; impl Qualif for HasMutInterior { const ANALYSIS_NAME: &'static str = "flow_has_mut_interior"; + const IS_CLEARED_ON_MOVE: bool = false; + const ALLOW_PROMOTED: bool = false; fn in_qualifs(qualifs: &ConstQualifs) -> bool { qualifs.has_mut_interior