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