@@ -2515,6 +2515,8 @@ extern "rust-intrinsic" {
2515
2515
/// intrinsic will be replaced with a call to `called_in_const`. It gets
2516
2516
/// replaced with a call to `called_at_rt` otherwise.
2517
2517
///
2518
+ /// This function is safe to call, but note the stability concerns below.
2519
+ ///
2518
2520
/// # Type Requirements
2519
2521
///
2520
2522
/// The two functions must be both function items. They cannot be function
@@ -2524,45 +2526,47 @@ extern "rust-intrinsic" {
2524
2526
/// the two functions, therefore, both functions must accept the same type of
2525
2527
/// arguments. Both functions must return RET.
2526
2528
///
2527
- /// # Safety
2529
+ /// # Stability concerns
2528
2530
///
2529
- /// The two functions must behave observably equivalent. Safe code in other
2530
- /// crates may assume that calling a `const fn` at compile-time and at run-time
2531
- /// produces the same result. A function that produces a different result when
2532
- /// evaluated at run-time, or has any other observable side-effects, is
2533
- /// *unsound*.
2531
+ /// Rust has not yet decided that `const fn` are allowed to tell whether
2532
+ /// they run at compile-time or at runtime. Therefore, when using this
2533
+ /// intrinsic anywhere that can be reached from stable, it is crucial that
2534
+ /// the end-to-end behavior of the stable `const fn` is the same for both
2535
+ /// modes of execution. (Here, Undefined Behavior is considerd "the same"
2536
+ /// as any other behavior, so if the function exhibits UB at runtime then
2537
+ /// it may do whatever it wants at compile-time.)
2534
2538
///
2535
2539
/// Here is an example of how this could cause a problem:
2536
2540
/// ```no_run
2537
2541
/// #![feature(const_eval_select)]
2538
2542
/// #![feature(core_intrinsics)]
2539
2543
/// # #![allow(internal_features)]
2540
- /// use std::hint::unreachable_unchecked;
2544
+ /// # #![cfg_attr(bootstrap, allow(unused))]
2541
2545
/// use std::intrinsics::const_eval_select;
2542
2546
///
2543
- /// // Crate A
2547
+ /// // Standard library
2548
+ /// # #[cfg(not(bootstrap))]
2544
2549
/// pub const fn inconsistent() -> i32 {
2545
2550
/// fn runtime() -> i32 { 1 }
2546
2551
/// const fn compiletime() -> i32 { 2 }
2547
2552
///
2548
- /// unsafe {
2549
- // // ⚠ This code violates the required equivalence of `compiletime`
2550
- /// // and `runtime`.
2551
- /// const_eval_select((), compiletime, runtime)
2552
- /// }
2553
+ // // ⚠ This code violates the required equivalence of `compiletime`
2554
+ /// // and `runtime`.
2555
+ /// const_eval_select((), compiletime, runtime)
2553
2556
/// }
2557
+ /// # #[cfg(bootstrap)]
2558
+ /// # pub const fn inconsistent() -> i32 { 0 }
2554
2559
///
2555
- /// // Crate B
2560
+ /// // User Crate
2556
2561
/// const X: i32 = inconsistent();
2557
2562
/// let x = inconsistent();
2558
- /// if x != X { unsafe { unreachable_unchecked(); }}
2563
+ /// assert_eq!(x, X);
2559
2564
/// ```
2560
2565
///
2561
- /// This code causes Undefined Behavior when being run, since the
2562
- /// `unreachable_unchecked` is actually being reached. The bug is in *crate A*,
2563
- /// which violates the principle that a `const fn` must behave the same at
2564
- /// compile-time and at run-time. The unsafe code in crate B is fine.
2566
+ /// Currently such an assertion would always succeed; until Rust decides
2567
+ /// otherwise, that principle should not be violated.
2565
2568
#[ rustc_const_unstable( feature = "const_eval_select" , issue = "none" ) ]
2569
+ #[ cfg_attr( not( bootstrap) , rustc_safe_intrinsic) ]
2566
2570
pub fn const_eval_select < ARG : Tuple , F , G , RET > (
2567
2571
arg : ARG ,
2568
2572
called_in_const : F ,
0 commit comments