Skip to content

Commit 327842b

Browse files
authored
Rollup merge of #121894 - RalfJung:const_eval_select, r=oli-obk
const_eval_select: make it safe but be careful with what we expose on stable for now As this is all still nightly-only I think `````@rust-lang/wg-const-eval````` can do that without involving t-lang. r? `````@oli-obk````` Cc `````@Nilstrieb````` -- the updated version of your RFC would basically say that we can remove these comments about not making behavior differences visible in stable `const fn`
2 parents 2875b10 + d858809 commit 327842b

File tree

18 files changed

+84
-43
lines changed

18 files changed

+84
-43
lines changed

compiler/rustc_hir_analysis/src/check/intrinsic.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,8 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
132132
| sym::fsub_algebraic
133133
| sym::fmul_algebraic
134134
| sym::fdiv_algebraic
135-
| sym::frem_algebraic => hir::Unsafety::Normal,
135+
| sym::frem_algebraic
136+
| sym::const_eval_select => hir::Unsafety::Normal,
136137
_ => hir::Unsafety::Unsafe,
137138
};
138139

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
@@ -428,10 +428,13 @@ impl CStr {
428428
unsafe { &*(bytes as *const [u8] as *const CStr) }
429429
}
430430

431+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
431432
// SAFETY: The const and runtime versions have identical behavior
432433
// unless the safety contract of `from_bytes_with_nul_unchecked` is
433434
// violated, which is UB.
434-
unsafe { intrinsics::const_eval_select((bytes,), const_impl, rt_impl) }
435+
unsafe {
436+
intrinsics::const_eval_select((bytes,), const_impl, rt_impl)
437+
}
435438
}
436439

437440
/// Returns the inner pointer to this C string.
@@ -719,6 +722,9 @@ const unsafe fn const_strlen(ptr: *const c_char) -> usize {
719722
unsafe { strlen(s) }
720723
}
721724

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

library/core/src/intrinsics.rs

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

library/core/src/num/f32.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -1153,8 +1153,11 @@ impl f32 {
11531153
// Stability concerns.
11541154
unsafe { mem::transmute(x) }
11551155
}
1156+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
11561157
// 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) }
1158+
unsafe {
1159+
intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32)
1160+
}
11581161
}
11591162

11601163
/// Raw transmutation from `u32`.
@@ -1245,8 +1248,11 @@ impl f32 {
12451248
// Stability concerns.
12461249
unsafe { mem::transmute(x) }
12471250
}
1251+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
12481252
// 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) }
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
@@ -1146,8 +1146,11 @@ impl f64 {
11461146
// Stability concerns.
11471147
unsafe { mem::transmute::<f64, u64>(rt) }
11481148
}
1149+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
11491150
// 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) }
1151+
unsafe {
1152+
intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64)
1153+
}
11511154
}
11521155

11531156
/// Raw transmutation from `u64`.
@@ -1243,8 +1246,11 @@ impl f64 {
12431246
// Stability concerns.
12441247
unsafe { mem::transmute::<u64, f64>(rt) }
12451248
}
1249+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
12461250
// 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) }
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
@@ -117,6 +117,7 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo
117117
panic_fmt(fmt);
118118
}
119119

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

library/core/src/ptr/const_ptr.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,11 @@ impl<T: ?Sized> *const T {
4848
}
4949
}
5050

51+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
5152
// SAFETY: The two versions are equivalent at runtime.
52-
unsafe { const_eval_select((self as *const u8,), const_impl, runtime_impl) }
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.
@@ -806,6 +809,7 @@ impl<T: ?Sized> *const T {
806809
where
807810
T: Sized,
808811
{
812+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
809813
// SAFETY: The comparison has no side-effects, and the intrinsic
810814
// does this check internally in the CTFE implementation.
811815
unsafe {
@@ -1623,8 +1627,11 @@ impl<T: ?Sized> *const T {
16231627
ptr.align_offset(align) == 0
16241628
}
16251629

1630+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
16261631
// SAFETY: The two versions are equivalent at runtime.
1627-
unsafe { const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl) }
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
@@ -995,6 +995,7 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
995995
};
996996
}
997997

998+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
998999
// SAFETY: the caller must guarantee that `x` and `y` are
9991000
// valid for writes and properly aligned.
10001001
unsafe {

library/core/src/ptr/mut_ptr.rs

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

51+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
5152
// SAFETY: The two versions are equivalent at runtime.
52-
unsafe { const_eval_select((self as *mut u8,), const_impl, runtime_impl) }
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.
@@ -1896,8 +1899,11 @@ impl<T: ?Sized> *mut T {
18961899
ptr.align_offset(align) == 0
18971900
}
18981901

1902+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
18991903
// SAFETY: The two versions are equivalent at runtime.
1900-
unsafe { const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl) }
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
@@ -35,6 +35,7 @@ where
3535
#[track_caller]
3636
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
3737
const fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
38+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
3839
// SAFETY: we are just panicking here
3940
unsafe {
4041
const_eval_select(
@@ -63,6 +64,7 @@ const fn slice_start_index_len_fail_ct(_: usize, _: usize) -> ! {
6364
#[track_caller]
6465
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
6566
const fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
67+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
6668
// SAFETY: we are just panicking here
6769
unsafe {
6870
const_eval_select((index, len), slice_end_index_len_fail_ct, slice_end_index_len_fail_rt)
@@ -87,8 +89,11 @@ const fn slice_end_index_len_fail_ct(_: usize, _: usize) -> ! {
8789
#[track_caller]
8890
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
8991
const fn slice_index_order_fail(index: usize, end: usize) -> ! {
92+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
9093
// SAFETY: we are just panicking here
91-
unsafe { const_eval_select((index, end), slice_index_order_fail_ct, slice_index_order_fail_rt) }
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
@@ -86,6 +86,7 @@ use iter::{MatchesInternal, SplitNInternal};
8686
#[rustc_allow_const_fn_unstable(const_eval_select)]
8787
#[cfg(not(feature = "panic_immediate_abort"))]
8888
const fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
89+
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
8990
// SAFETY: panics for both branches
9091
unsafe {
9192
crate::intrinsics::const_eval_select(

tests/ui/intrinsics/const-eval-select-backtrace.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,5 @@ fn uhoh() {
1212
const fn c() {}
1313

1414
fn main() {
15-
// safety: this is unsound and just used to test
16-
unsafe {
17-
std::intrinsics::const_eval_select((), c, uhoh);
18-
}
15+
std::intrinsics::const_eval_select((), c, uhoh);
1916
}
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
thread 'main' panicked at $DIR/const-eval-select-backtrace.rs:17:9:
1+
thread 'main' panicked at $DIR/const-eval-select-backtrace.rs:15:5:
22
Aaah!
33
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

tests/ui/intrinsics/const-eval-select-stability.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const fn nothing(){}
1313

1414
#[stable(since = "1.0", feature = "hey")]
1515
#[rustc_const_stable(since = "1.0", feature = "const_hey")]
16-
pub const unsafe fn hey() {
16+
pub const fn hey() {
1717
const_eval_select((), nothing, log);
1818
//~^ ERROR `const_eval_select` is not yet stable as a const fn
1919
}

tests/ui/intrinsics/const-eval-select-x86_64.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@ fn eq_rt(x: [i32; 4], y: [i32; 4]) -> bool {
2222
}
2323

2424
const fn eq(x: [i32; 4], y: [i32; 4]) -> bool {
25-
unsafe {
26-
const_eval_select((x, y), eq_ct, eq_rt)
27-
}
25+
const_eval_select((x, y), eq_ct, eq_rt)
2826
}
2927

3028
fn main() {

tests/ui/intrinsics/const-eval-select.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ fn no() -> bool {
1313
false
1414
}
1515

16-
// not a sound use case; testing only
16+
// not allowed on stable; testing only
1717
const fn is_const_eval() -> bool {
18-
unsafe { const_eval_select((), yes, no) }
18+
const_eval_select((), yes, no)
1919
}
2020

2121
fn main() {

tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,7 @@ const fn drop<T: ~const Destruct>(_: T) {}
511511

512512
extern "rust-intrinsic" {
513513
#[rustc_const_stable(feature = "const_eval_select", since = "1.0.0")]
514+
#[rustc_safe_intrinsic]
514515
fn const_eval_select<ARG: Tuple, F, G, RET>(
515516
arg: ARG,
516517
called_in_const: F,
@@ -525,5 +526,5 @@ fn test_const_eval_select() {
525526
const fn const_fn() {}
526527
fn rt_fn() {}
527528

528-
unsafe { const_eval_select((), const_fn, rt_fn); }
529+
const_eval_select((), const_fn, rt_fn);
529530
}

0 commit comments

Comments
 (0)