From 7a17d4a4008aa58a0df54fd9391aad14894ee88a Mon Sep 17 00:00:00 2001 From: ltdk Date: Tue, 14 Oct 2025 20:23:39 -0400 Subject: [PATCH] const select_unpredictable --- library/core/src/hint.rs | 7 ++++- library/core/src/intrinsics/mod.rs | 8 ++++-- library/core/src/lib.rs | 1 + library/coretests/tests/hint.rs | 41 ++++++++++++++++++------------ library/coretests/tests/lib.rs | 1 + 5 files changed, 39 insertions(+), 19 deletions(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 23cfdf5bfde2b..6efe95a9edce9 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -4,6 +4,7 @@ //! //! Hints may be compile time or runtime. +use crate::marker::Destruct; use crate::mem::MaybeUninit; use crate::{intrinsics, ub_checks}; @@ -771,7 +772,11 @@ pub const fn cold_path() { /// ``` #[inline(always)] #[stable(feature = "select_unpredictable", since = "1.88.0")] -pub fn select_unpredictable(condition: bool, true_val: T, false_val: T) -> T { +#[rustc_const_unstable(feature = "const_select_unpredictable", issue = "145938")] +pub const fn select_unpredictable(condition: bool, true_val: T, false_val: T) -> T +where + T: [const] Destruct, +{ // FIXME(https://github.com/rust-lang/unsafe-code-guidelines/issues/245): // Change this to use ManuallyDrop instead. let mut true_val = MaybeUninit::new(true_val); diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index cef700be9ea1f..19d977e4cfb1a 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -55,7 +55,7 @@ #![allow(missing_docs)] use crate::ffi::va_list::{VaArgSafe, VaListImpl}; -use crate::marker::{ConstParamTy, DiscriminantKind, PointeeSized, Tuple}; +use crate::marker::{ConstParamTy, Destruct, DiscriminantKind, PointeeSized, Tuple}; use crate::ptr; mod bounds; @@ -477,11 +477,15 @@ pub const fn unlikely(b: bool) -> bool { /// However unlike the public form, the intrinsic will not drop the value that /// is not selected. #[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_const_unstable(feature = "const_select_unpredictable", issue = "145938")] #[rustc_intrinsic] #[rustc_nounwind] #[miri::intrinsic_fallback_is_spec] #[inline] -pub fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { +pub const fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T +where + T: [const] Destruct, +{ if b { true_val } else { false_val } } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 54adf97f10020..c74e18a5404f4 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -106,6 +106,7 @@ #![feature(const_cmp)] #![feature(const_destruct)] #![feature(const_eval_select)] +#![feature(const_select_unpredictable)] #![feature(core_intrinsics)] #![feature(coverage_attribute)] #![feature(disjoint_bitor)] diff --git a/library/coretests/tests/hint.rs b/library/coretests/tests/hint.rs index 24de27b24b802..9e5a79c3afb8d 100644 --- a/library/coretests/tests/hint.rs +++ b/library/coretests/tests/hint.rs @@ -1,25 +1,34 @@ #[test] fn select_unpredictable_drop() { - use core::cell::Cell; - struct X<'a>(&'a Cell); - impl Drop for X<'_> { + struct X(*mut bool); + impl const Drop for X { fn drop(&mut self) { - self.0.set(true); + // FIXME(const-hack): Once const cells work, we could remove unsafe code here. + unsafe { + *self.0 = true; + } } } - let a_dropped = Cell::new(false); - let b_dropped = Cell::new(false); - let a = X(&a_dropped); - let b = X(&b_dropped); - assert!(!a_dropped.get()); - assert!(!b_dropped.get()); - let selected = core::hint::select_unpredictable(core::hint::black_box(true), a, b); - assert!(!a_dropped.get()); - assert!(b_dropped.get()); - drop(selected); - assert!(a_dropped.get()); - assert!(b_dropped.get()); + const fn do_test() { + let mut a_dropped = false; + let mut b_dropped = false; + let a = X(&raw mut a_dropped); + let b = X(&raw mut b_dropped); + assert!(!a_dropped); + assert!(!b_dropped); + let selected = core::hint::select_unpredictable(core::hint::black_box(true), a, b); + assert!(!a_dropped); + assert!(b_dropped); + drop(selected); + assert!(a_dropped); + assert!(b_dropped); + } + + do_test(); + const { + do_test(); + } } #[test] diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index c2dc3a99ab109..7a1f16589ed7a 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -26,6 +26,7 @@ #![feature(const_option_ops)] #![feature(const_ref_cell)] #![feature(const_result_trait_fn)] +#![feature(const_select_unpredictable)] #![feature(const_trait_impl)] #![feature(control_flow_ok)] #![feature(core_float_math)]