Skip to content

Commit 7a88f69

Browse files
committed
const_eval_select: make it safe but be careful with what we expose on stable for now
1 parent 4cdd205 commit 7a88f69

File tree

12 files changed

+72
-30
lines changed

12 files changed

+72
-30
lines changed

compiler/rustc_hir_analysis/src/check/intrinsic.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
128128
| sym::fsub_algebraic
129129
| sym::fmul_algebraic
130130
| sym::fdiv_algebraic
131-
| sym::frem_algebraic => hir::Unsafety::Normal,
131+
| sym::frem_algebraic
132+
| sym::const_eval_select => hir::Unsafety::Normal,
132133
_ => hir::Unsafety::Unsafe,
133134
};
134135

library/alloc/src/alloc.rs

+1
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,7 @@ pub const fn handle_alloc_error(layout: Layout) -> ! {
385385
}
386386

387387
#[cfg(not(feature = "panic_immediate_abort"))]
388+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
388389
unsafe {
389390
core::intrinsics::const_eval_select((layout,), ct_error, rt_error)
390391
}

library/core/src/ffi/c_str.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,10 @@ impl CStr {
431431
// SAFETY: The const and runtime versions have identical behavior
432432
// unless the safety contract of `from_bytes_with_nul_unchecked` is
433433
// violated, which is UB.
434-
unsafe { intrinsics::const_eval_select((bytes,), const_impl, rt_impl) }
434+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
435+
unsafe {
436+
intrinsics::const_eval_select((bytes,), const_impl, rt_impl)
437+
}
435438
}
436439

437440
/// Returns the inner pointer to this C string.
@@ -720,5 +723,8 @@ const unsafe fn const_strlen(ptr: *const c_char) -> usize {
720723
}
721724

722725
// SAFETY: the two functions always provide equivalent functionality
723-
unsafe { intrinsics::const_eval_select((ptr,), strlen_ct, strlen_rt) }
726+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
727+
unsafe {
728+
intrinsics::const_eval_select((ptr,), strlen_ct, strlen_rt)
729+
}
724730
}

library/core/src/intrinsics.rs

+19-18
Original file line numberDiff line numberDiff line change
@@ -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,

library/core/src/num/f32.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -1154,7 +1154,10 @@ impl f32 {
11541154
unsafe { mem::transmute(x) }
11551155
}
11561156
// SAFETY: We use internal implementations that either always work or fail at compile time.
1157-
unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) }
1157+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
1158+
unsafe {
1159+
intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32)
1160+
}
11581161
}
11591162

11601163
/// Raw transmutation from `u32`.
@@ -1246,7 +1249,10 @@ impl f32 {
12461249
unsafe { mem::transmute(x) }
12471250
}
12481251
// SAFETY: We use internal implementations that either always work or fail at compile time.
1249-
unsafe { intrinsics::const_eval_select((v,), ct_u32_to_f32, rt_u32_to_f32) }
1252+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
1253+
unsafe {
1254+
intrinsics::const_eval_select((v,), ct_u32_to_f32, rt_u32_to_f32)
1255+
}
12501256
}
12511257

12521258
/// Return the memory representation of this floating point number as a byte array in

library/core/src/num/f64.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -1147,7 +1147,10 @@ impl f64 {
11471147
unsafe { mem::transmute::<f64, u64>(rt) }
11481148
}
11491149
// SAFETY: We use internal implementations that either always work or fail at compile time.
1150-
unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) }
1150+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
1151+
unsafe {
1152+
intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64)
1153+
}
11511154
}
11521155

11531156
/// Raw transmutation from `u64`.
@@ -1244,7 +1247,10 @@ impl f64 {
12441247
unsafe { mem::transmute::<u64, f64>(rt) }
12451248
}
12461249
// SAFETY: We use internal implementations that either always work or fail at compile time.
1247-
unsafe { intrinsics::const_eval_select((v,), ct_u64_to_f64, rt_u64_to_f64) }
1250+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
1251+
unsafe {
1252+
intrinsics::const_eval_select((v,), ct_u64_to_f64, rt_u64_to_f64)
1253+
}
12481254
}
12491255

12501256
/// Return the memory representation of this floating point number as a byte array in

library/core/src/panicking.rs

+1
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo
118118
}
119119

120120
// SAFETY: const panic does not care about unwinding
121+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
121122
unsafe {
122123
super::intrinsics::const_eval_select((fmt, force_no_backtrace), comptime, runtime);
123124
}

library/core/src/ptr/const_ptr.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,10 @@ impl<T: ?Sized> *const T {
4949
}
5050

5151
// SAFETY: The two versions are equivalent at runtime.
52-
unsafe { const_eval_select((self as *const u8,), const_impl, runtime_impl) }
52+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
53+
unsafe {
54+
const_eval_select((self as *const u8,), const_impl, runtime_impl)
55+
}
5356
}
5457

5558
/// Casts to a pointer of another type.
@@ -808,6 +811,7 @@ impl<T: ?Sized> *const T {
808811
{
809812
// SAFETY: The comparison has no side-effects, and the intrinsic
810813
// does this check internally in the CTFE implementation.
814+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
811815
unsafe {
812816
assert_unsafe_precondition!(
813817
"ptr::sub_ptr requires `self >= origin`",
@@ -1624,7 +1628,10 @@ impl<T: ?Sized> *const T {
16241628
}
16251629

16261630
// SAFETY: The two versions are equivalent at runtime.
1627-
unsafe { const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl) }
1631+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
1632+
unsafe {
1633+
const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl)
1634+
}
16281635
}
16291636
}
16301637

library/core/src/ptr/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,7 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
993993

994994
// SAFETY: the caller must guarantee that `x` and `y` are
995995
// valid for writes and properly aligned.
996+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
996997
unsafe {
997998
assert_unsafe_precondition!(
998999
"ptr::swap_nonoverlapping requires that both pointer arguments are aligned and non-null \

library/core/src/ptr/mut_ptr.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,10 @@ impl<T: ?Sized> *mut T {
4949
}
5050

5151
// SAFETY: The two versions are equivalent at runtime.
52-
unsafe { const_eval_select((self as *mut u8,), const_impl, runtime_impl) }
52+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
53+
unsafe {
54+
const_eval_select((self as *mut u8,), const_impl, runtime_impl)
55+
}
5356
}
5457

5558
/// Casts to a pointer of another type.
@@ -1897,7 +1900,10 @@ impl<T: ?Sized> *mut T {
18971900
}
18981901

18991902
// SAFETY: The two versions are equivalent at runtime.
1900-
unsafe { const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl) }
1903+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
1904+
unsafe {
1905+
const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl)
1906+
}
19011907
}
19021908
}
19031909

library/core/src/slice/index.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ where
3636
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
3737
const fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
3838
// SAFETY: we are just panicking here
39+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
3940
unsafe {
4041
const_eval_select(
4142
(index, len),
@@ -64,6 +65,7 @@ const fn slice_start_index_len_fail_ct(_: usize, _: usize) -> ! {
6465
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
6566
const fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
6667
// SAFETY: we are just panicking here
68+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
6769
unsafe {
6870
const_eval_select((index, len), slice_end_index_len_fail_ct, slice_end_index_len_fail_rt)
6971
}
@@ -88,7 +90,10 @@ const fn slice_end_index_len_fail_ct(_: usize, _: usize) -> ! {
8890
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
8991
const fn slice_index_order_fail(index: usize, end: usize) -> ! {
9092
// SAFETY: we are just panicking here
91-
unsafe { const_eval_select((index, end), slice_index_order_fail_ct, slice_index_order_fail_rt) }
93+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
94+
unsafe {
95+
const_eval_select((index, end), slice_index_order_fail_ct, slice_index_order_fail_rt)
96+
}
9297
}
9398

9499
// FIXME const-hack

library/core/src/str/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ use iter::{MatchesInternal, SplitNInternal};
8787
#[cfg(not(feature = "panic_immediate_abort"))]
8888
const fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
8989
// SAFETY: panics for both branches
90+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
9091
unsafe {
9192
crate::intrinsics::const_eval_select(
9293
(s, begin, end),

0 commit comments

Comments
 (0)