From dfa519ee9cc51bf55ed7612f6dd5d0ba97c905f7 Mon Sep 17 00:00:00 2001 From: tmiasko Date: Sat, 10 Oct 2026 11:12:34 +0000 Subject: [PATCH] Fix incorrect impl JoinSemiLattice for State The implementation had an incorrect short-circruting behavior, i.e., it failed to join `borrow` when `qualif` changed. This lead implementation to accept code that should have been rejected. Fix the issue and fallout in the standard library and tests. --- .../src/check_consts/resolver.rs | 5 ++++- library/alloctests/tests/lib.rs | 1 + library/core/src/mem/maybe_dangling.rs | 1 + library/coretests/tests/lib.rs | 1 + .../consts/qualif-indirect-mutation-fail.rs | 22 +++++++++++++++++++ .../qualif-indirect-mutation-fail.stderr | 20 ++++++++++++++++- 6 files changed, 48 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs index 4fc8c62ccf80a..e1850c983af7f 100644 --- a/compiler/rustc_const_eval/src/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs @@ -319,7 +319,10 @@ impl DebugWithContext for State { impl JoinSemiLattice for State { fn join(&mut self, other: &Self) -> bool { - self.qualif.join(&other.qualif) || self.borrow.join(&other.borrow) + // `join` has a side-effect on `self` so make sure we always call it on both fields. + let a = self.qualif.join(&other.qualif); + let b = self.borrow.join(&other.borrow); + a | b } } diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index 5c8ee92388dd0..5987bc66632c4 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -16,6 +16,7 @@ #![feature(const_btree_len)] #![feature(const_cmp)] #![feature(const_heap)] +#![feature(const_precise_live_drops)] #![feature(const_trait_impl)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] diff --git a/library/core/src/mem/maybe_dangling.rs b/library/core/src/mem/maybe_dangling.rs index 46e5228a2da3f..d0ed5440cccd1 100644 --- a/library/core/src/mem/maybe_dangling.rs +++ b/library/core/src/mem/maybe_dangling.rs @@ -99,6 +99,7 @@ impl MaybeDangling

{ /// Extracts the value from the `MaybeDangling` container. /// /// Note that this is UB if the inner value is currently dangling. + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] pub const fn into_inner(self) -> P where P: Sized, diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 1fdb0c820d662..4e9628a9b3294 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -36,6 +36,7 @@ #![feature(const_iter)] #![feature(const_ops)] #![feature(const_option_ops)] +#![feature(const_precise_live_drops)] #![feature(const_ref_cell)] #![feature(const_result_trait_fn)] #![feature(const_select_unpredictable)] diff --git a/tests/ui/consts/qualif-indirect-mutation-fail.rs b/tests/ui/consts/qualif-indirect-mutation-fail.rs index 26d251788c3ab..a4a063a4520f3 100644 --- a/tests/ui/consts/qualif-indirect-mutation-fail.rs +++ b/tests/ui/consts/qualif-indirect-mutation-fail.rs @@ -69,3 +69,25 @@ pub const fn address_of_const() { let y: Option = None; //~ ERROR destructor of std::ptr::addr_of!(y); } + +// Regression test for an incorrect implementation of state join. +pub const fn regression_test_for_incorrect_join() { + let mut a = Some(NotConstDestruct); //~ ERROR destructor of + let b = NotConstDestruct; + let p = &raw mut a; + let x = unsafe { std::ptr::read(p) }; + std::mem::forget(a); + std::mem::forget(x); + a = None; + unsafe { std::ptr::write(p, Some(b)) }; +} + +// Use after move cannot sneak past checks. +// NB: Semantics of MIR move elimination might make it possible to accept this. +pub const fn use_after_move() { + let mut a = None; //~ ERROR destructor of + let p = &raw mut a; + std::mem::forget(a); + a = None; + unsafe { std::ptr::write(p, Some(NotConstDestruct)) }; +} diff --git a/tests/ui/consts/qualif-indirect-mutation-fail.stderr b/tests/ui/consts/qualif-indirect-mutation-fail.stderr index 2301490065d45..8d5e6010e582e 100644 --- a/tests/ui/consts/qualif-indirect-mutation-fail.stderr +++ b/tests/ui/consts/qualif-indirect-mutation-fail.stderr @@ -77,6 +77,24 @@ LL | let x: Option = None; LL | } | - value is dropped here -error: aborting due to 9 previous errors +error[E0493]: destructor of `Option` cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:75:9 + | +LL | let mut a = Some(NotConstDestruct); + | ^^^^^ the destructor for this type cannot be evaluated in constant functions +... +LL | } + | - value is dropped here + +error[E0493]: destructor of `Option` cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:88:9 + | +LL | let mut a = None; + | ^^^^^ the destructor for this type cannot be evaluated in constant functions +... +LL | } + | - value is dropped here + +error: aborting due to 11 previous errors For more information about this error, try `rustc --explain E0493`.