5454) ]
5555#![ allow( missing_docs) ]
5656
57- use crate :: marker:: { Destruct , DiscriminantKind } ;
57+ #[ cfg( bootstrap) ]
58+ use crate :: marker:: Destruct ;
59+ use crate :: marker:: DiscriminantKind ;
5860use crate :: mem;
5961
6062// These imports are used for simplifying intra-doc links
@@ -2085,6 +2087,65 @@ extern "rust-intrinsic" {
20852087 /// `ptr` must point to a vtable.
20862088 /// The intrinsic will return the alignment stored in that vtable.
20872089 pub fn vtable_align ( ptr : * const ( ) ) -> usize ;
2090+
2091+ /// Selects which function to call depending on the context.
2092+ ///
2093+ /// If this function is evaluated at compile-time, then a call to this
2094+ /// intrinsic will be replaced with a call to `called_in_const`. It gets
2095+ /// replaced with a call to `called_at_rt` otherwise.
2096+ ///
2097+ /// # Type Requirements
2098+ ///
2099+ /// The two functions must be both function items. They cannot be function
2100+ /// pointers or closures. The first function must be a `const fn`.
2101+ ///
2102+ /// `arg` will be the tupled arguments that will be passed to either one of
2103+ /// the two functions, therefore, both functions must accept the same type of
2104+ /// arguments. Both functions must return RET.
2105+ ///
2106+ /// # Safety
2107+ ///
2108+ /// The two functions must behave observably equivalent. Safe code in other
2109+ /// crates may assume that calling a `const fn` at compile-time and at run-time
2110+ /// produces the same result. A function that produces a different result when
2111+ /// evaluated at run-time, or has any other observable side-effects, is
2112+ /// *unsound*.
2113+ ///
2114+ /// Here is an example of how this could cause a problem:
2115+ /// ```no_run
2116+ /// #![feature(const_eval_select)]
2117+ /// #![feature(core_intrinsics)]
2118+ /// use std::hint::unreachable_unchecked;
2119+ /// use std::intrinsics::const_eval_select;
2120+ ///
2121+ /// // Crate A
2122+ /// pub const fn inconsistent() -> i32 {
2123+ /// fn runtime() -> i32 { 1 }
2124+ /// const fn compiletime() -> i32 { 2 }
2125+ ///
2126+ /// unsafe {
2127+ // // ⚠ This code violates the required equivalence of `compiletime`
2128+ /// // and `runtime`.
2129+ /// const_eval_select((), compiletime, runtime)
2130+ /// }
2131+ /// }
2132+ ///
2133+ /// // Crate B
2134+ /// const X: i32 = inconsistent();
2135+ /// let x = inconsistent();
2136+ /// if x != X { unsafe { unreachable_unchecked(); }}
2137+ /// ```
2138+ ///
2139+ /// This code causes Undefined Behavior when being run, since the
2140+ /// `unreachable_unchecked` is actually being reached. The bug is in *crate A*,
2141+ /// which violates the principle that a `const fn` must behave the same at
2142+ /// compile-time and at run-time. The unsafe code in crate B is fine.
2143+ #[ cfg( not( bootstrap) ) ]
2144+ #[ rustc_const_unstable( feature = "const_eval_select" , issue = "none" ) ]
2145+ pub fn const_eval_select < ARG , F , G , RET > ( arg : ARG , called_in_const : F , called_at_rt : G ) -> RET
2146+ where
2147+ G : FnOnce < ARG , Output = RET > ,
2148+ F : FnOnce < ARG , Output = RET > ;
20882149}
20892150
20902151// Some functions are defined here because they accidentally got made
@@ -2095,6 +2156,11 @@ extern "rust-intrinsic" {
20952156/// Check that the preconditions of an unsafe function are followed, if debug_assertions are on,
20962157/// and only at runtime.
20972158///
2159+ /// This macro should be called as `assert_unsafe_precondition!([Generics](name: Type) => Expression)`
2160+ /// where the names specified will be moved into the macro as captured variables, and defines an item
2161+ /// to call `const_eval_select` on. The tokens inside the square brackets are used to denote generics
2162+ /// for the function declaractions and can be omitted if there is no generics.
2163+ ///
20982164/// # Safety
20992165///
21002166/// Invoking this macro is only sound if the following code is already UB when the passed
@@ -2109,18 +2175,21 @@ extern "rust-intrinsic" {
21092175/// the occasional mistake, and this check should help them figure things out.
21102176#[ allow_internal_unstable( const_eval_select) ] // permit this to be called in stably-const fn
21112177macro_rules! assert_unsafe_precondition {
2112- ( $e: expr) => {
2178+ ( $( [ $ ( $tt : tt ) * ] ) ? ( $ ( $i : ident : $ty : ty ) , * $ ( , ) ? ) => $ e: expr) => {
21132179 if cfg!( debug_assertions) {
2114- // Use a closure so that we can capture arbitrary expressions from the invocation
2115- let runtime = || {
2180+ // allow non_snake_case to allow capturing const generics
2181+ #[ allow( non_snake_case) ]
2182+ #[ inline( always) ]
2183+ fn runtime$( <$( $tt) * >) ?( $( $i: $ty) ,* ) {
21162184 if !$e {
21172185 // abort instead of panicking to reduce impact on code size
21182186 :: core:: intrinsics:: abort( ) ;
21192187 }
2120- } ;
2121- const fn comptime( ) { }
2188+ }
2189+ #[ allow( non_snake_case) ]
2190+ const fn comptime$( <$( $tt) * >) ?( $( _: $ty) ,* ) { }
21222191
2123- :: core:: intrinsics:: const_eval_select( ( ) , comptime, runtime) ;
2192+ :: core:: intrinsics:: const_eval_select( ( $ ( $i , ) * ) , comptime, runtime) ;
21242193 }
21252194 } ;
21262195}
@@ -2243,7 +2312,7 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
22432312 // SAFETY: the safety contract for `copy_nonoverlapping` must be
22442313 // upheld by the caller.
22452314 unsafe {
2246- assert_unsafe_precondition ! (
2315+ assert_unsafe_precondition ! ( [ T ] ( src : * const T , dst : * mut T , count : usize ) =>
22472316 is_aligned_and_not_null( src)
22482317 && is_aligned_and_not_null( dst)
22492318 && is_nonoverlapping( src, dst, count)
@@ -2329,7 +2398,8 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
23292398
23302399 // SAFETY: the safety contract for `copy` must be upheld by the caller.
23312400 unsafe {
2332- assert_unsafe_precondition ! ( is_aligned_and_not_null( src) && is_aligned_and_not_null( dst) ) ;
2401+ assert_unsafe_precondition ! ( [ T ] ( src: * const T , dst: * mut T ) =>
2402+ is_aligned_and_not_null( src) && is_aligned_and_not_null( dst) ) ;
23332403 copy ( src, dst, count)
23342404 }
23352405}
@@ -2397,63 +2467,12 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
23972467
23982468 // SAFETY: the safety contract for `write_bytes` must be upheld by the caller.
23992469 unsafe {
2400- assert_unsafe_precondition ! ( is_aligned_and_not_null( dst) ) ;
2470+ assert_unsafe_precondition ! ( [ T ] ( dst : * mut T ) => is_aligned_and_not_null( dst) ) ;
24012471 write_bytes ( dst, val, count)
24022472 }
24032473}
24042474
2405- /// Selects which function to call depending on the context.
2406- ///
2407- /// If this function is evaluated at compile-time, then a call to this
2408- /// intrinsic will be replaced with a call to `called_in_const`. It gets
2409- /// replaced with a call to `called_at_rt` otherwise.
2410- ///
2411- /// # Type Requirements
2412- ///
2413- /// The two functions must be both function items. They cannot be function
2414- /// pointers or closures.
2415- ///
2416- /// `arg` will be the arguments that will be passed to either one of the
2417- /// two functions, therefore, both functions must accept the same type of
2418- /// arguments. Both functions must return RET.
2419- ///
2420- /// # Safety
2421- ///
2422- /// The two functions must behave observably equivalent. Safe code in other
2423- /// crates may assume that calling a `const fn` at compile-time and at run-time
2424- /// produces the same result. A function that produces a different result when
2425- /// evaluated at run-time, or has any other observable side-effects, is
2426- /// *unsound*.
2427- ///
2428- /// Here is an example of how this could cause a problem:
2429- /// ```no_run
2430- /// #![feature(const_eval_select)]
2431- /// #![feature(core_intrinsics)]
2432- /// use std::hint::unreachable_unchecked;
2433- /// use std::intrinsics::const_eval_select;
2434- ///
2435- /// // Crate A
2436- /// pub const fn inconsistent() -> i32 {
2437- /// fn runtime() -> i32 { 1 }
2438- /// const fn compiletime() -> i32 { 2 }
2439- ///
2440- /// unsafe {
2441- // // ⚠ This code violates the required equivalence of `compiletime`
2442- /// // and `runtime`.
2443- /// const_eval_select((), compiletime, runtime)
2444- /// }
2445- /// }
2446- ///
2447- /// // Crate B
2448- /// const X: i32 = inconsistent();
2449- /// let x = inconsistent();
2450- /// if x != X { unsafe { unreachable_unchecked(); }}
2451- /// ```
2452- ///
2453- /// This code causes Undefined Behavior when being run, since the
2454- /// `unreachable_unchecked` is actually being reached. The bug is in *crate A*,
2455- /// which violates the principle that a `const fn` must behave the same at
2456- /// compile-time and at run-time. The unsafe code in crate B is fine.
2475+ #[ cfg( bootstrap) ]
24572476#[ unstable(
24582477 feature = "const_eval_select" ,
24592478 issue = "none" ,
@@ -2475,6 +2494,7 @@ where
24752494 called_at_rt. call_once ( arg)
24762495}
24772496
2497+ #[ cfg( bootstrap) ]
24782498#[ unstable(
24792499 feature = "const_eval_select" ,
24802500 issue = "none" ,
0 commit comments