54
54
) ]
55
55
#![ allow( missing_docs) ]
56
56
57
- use crate :: marker:: { Destruct , DiscriminantKind } ;
57
+ #[ cfg( bootstrap) ]
58
+ use crate :: marker:: Destruct ;
59
+ use crate :: marker:: DiscriminantKind ;
58
60
use crate :: mem;
59
61
60
62
// These imports are used for simplifying intra-doc links
@@ -2085,6 +2087,65 @@ extern "rust-intrinsic" {
2085
2087
/// `ptr` must point to a vtable.
2086
2088
/// The intrinsic will return the alignment stored in that vtable.
2087
2089
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 > ;
2088
2149
}
2089
2150
2090
2151
// Some functions are defined here because they accidentally got made
@@ -2095,6 +2156,11 @@ extern "rust-intrinsic" {
2095
2156
/// Check that the preconditions of an unsafe function are followed, if debug_assertions are on,
2096
2157
/// and only at runtime.
2097
2158
///
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
+ ///
2098
2164
/// # Safety
2099
2165
///
2100
2166
/// Invoking this macro is only sound if the following code is already UB when the passed
@@ -2109,18 +2175,21 @@ extern "rust-intrinsic" {
2109
2175
/// the occasional mistake, and this check should help them figure things out.
2110
2176
#[ allow_internal_unstable( const_eval_select) ] // permit this to be called in stably-const fn
2111
2177
macro_rules! assert_unsafe_precondition {
2112
- ( $e: expr) => {
2178
+ ( $( [ $ ( $tt : tt ) * ] ) ? ( $ ( $i : ident : $ty : ty ) , * $ ( , ) ? ) => $ e: expr) => {
2113
2179
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) ,* ) {
2116
2184
if !$e {
2117
2185
// abort instead of panicking to reduce impact on code size
2118
2186
:: core:: intrinsics:: abort( ) ;
2119
2187
}
2120
- } ;
2121
- const fn comptime( ) { }
2188
+ }
2189
+ #[ allow( non_snake_case) ]
2190
+ const fn comptime$( <$( $tt) * >) ?( $( _: $ty) ,* ) { }
2122
2191
2123
- :: core:: intrinsics:: const_eval_select( ( ) , comptime, runtime) ;
2192
+ :: core:: intrinsics:: const_eval_select( ( $ ( $i , ) * ) , comptime, runtime) ;
2124
2193
}
2125
2194
} ;
2126
2195
}
@@ -2243,7 +2312,7 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
2243
2312
// SAFETY: the safety contract for `copy_nonoverlapping` must be
2244
2313
// upheld by the caller.
2245
2314
unsafe {
2246
- assert_unsafe_precondition ! (
2315
+ assert_unsafe_precondition ! ( [ T ] ( src : * const T , dst : * mut T , count : usize ) =>
2247
2316
is_aligned_and_not_null( src)
2248
2317
&& is_aligned_and_not_null( dst)
2249
2318
&& is_nonoverlapping( src, dst, count)
@@ -2329,7 +2398,8 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
2329
2398
2330
2399
// SAFETY: the safety contract for `copy` must be upheld by the caller.
2331
2400
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) ) ;
2333
2403
copy ( src, dst, count)
2334
2404
}
2335
2405
}
@@ -2397,63 +2467,12 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
2397
2467
2398
2468
// SAFETY: the safety contract for `write_bytes` must be upheld by the caller.
2399
2469
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) ) ;
2401
2471
write_bytes ( dst, val, count)
2402
2472
}
2403
2473
}
2404
2474
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) ]
2457
2476
#[ unstable(
2458
2477
feature = "const_eval_select" ,
2459
2478
issue = "none" ,
@@ -2475,6 +2494,7 @@ where
2475
2494
called_at_rt. call_once ( arg)
2476
2495
}
2477
2496
2497
+ #[ cfg( bootstrap) ]
2478
2498
#[ unstable(
2479
2499
feature = "const_eval_select" ,
2480
2500
issue = "none" ,
0 commit comments