@@ -2515,6 +2515,8 @@ extern "rust-intrinsic" {
25152515 /// intrinsic will be replaced with a call to `called_in_const`. It gets
25162516 /// replaced with a call to `called_at_rt` otherwise.
25172517 ///
2518+ /// This function is safe to call, but note the stability concerns below.
2519+ ///
25182520 /// # Type Requirements
25192521 ///
25202522 /// The two functions must be both function items. They cannot be function
@@ -2524,13 +2526,15 @@ extern "rust-intrinsic" {
25242526 /// the two functions, therefore, both functions must accept the same type of
25252527 /// arguments. Both functions must return RET.
25262528 ///
2527- /// # Safety
2529+ /// # Stability concerns
25282530 ///
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.)
25342538 ///
25352539 /// Here is an example of how this could cause a problem:
25362540 /// ```no_run
@@ -2540,29 +2544,26 @@ extern "rust-intrinsic" {
25402544 /// use std::hint::unreachable_unchecked;
25412545 /// use std::intrinsics::const_eval_select;
25422546 ///
2543- /// // Crate A
2547+ /// // Standard library
25442548 /// pub const fn inconsistent() -> i32 {
25452549 /// fn runtime() -> i32 { 1 }
25462550 /// const fn compiletime() -> i32 { 2 }
25472551 ///
2548- /// unsafe {
2549- // // ⚠ This code violates the required equivalence of `compiletime`
2550- /// // and `runtime`.
2551- /// const_eval_select((), compiletime, runtime)
2552- /// }
2552+ // // ⚠ This code violates the required equivalence of `compiletime`
2553+ /// // and `runtime`.
2554+ /// const_eval_select((), compiletime, runtime)
25532555 /// }
25542556 ///
2555- /// // Crate B
2557+ /// // User Crate
25562558 /// const X: i32 = inconsistent();
25572559 /// let x = inconsistent();
2558- /// if x != X { unsafe { unreachable_unchecked(); }}
2560+ /// assert_eq!(x, X);
25592561 /// ```
25602562 ///
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.
2563+ /// Currently such an assertion would always succeed; until Rust decides
2564+ /// otherwise, that principle should not be violated.
25652565 #[ rustc_const_unstable( feature = "const_eval_select" , issue = "none" ) ]
2566+ #[ cfg_attr( not( bootstrap) , rustc_safe_intrinsic) ]
25662567 pub fn const_eval_select < ARG : Tuple , F , G , RET > (
25672568 arg : ARG ,
25682569 called_in_const : F ,
0 commit comments