about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2021-11-28 13:48:53 -0500
committerRalf Jung <post@ralfj.de>2021-11-28 13:54:56 -0500
commit15a4ed693722b4bb6d2fa43272a58ab94acfec1a (patch)
tree8d246430b577f0417436d2e40a4d4ff8fde0965f
parente6d2de9483a27f846f003fc745713339a9122473 (diff)
downloadrust-15a4ed693722b4bb6d2fa43272a58ab94acfec1a.tar.gz
rust-15a4ed693722b4bb6d2fa43272a58ab94acfec1a.zip
adjust const_eval_select documentation
-rw-r--r--library/core/src/intrinsics.rs41
1 files changed, 31 insertions, 10 deletions
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 23b28766d70..3814c4237f1 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -2271,19 +2271,40 @@ pub unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
 ///
 /// # Safety
 ///
-/// This intrinsic allows breaking [referential transparency] in `const fn`
-/// and is therefore `unsafe`.
+/// The two functions must behave observably equivalent. Safe code in other
+/// crates may assume that calling a `const fn` at compile-time and at run-time
+/// produces the same result. A function that produces a different result when
+/// evaluated at run-time, or has any other observable side-effects, is
+/// *unsound*.
+///
+/// Here is an example of how this could cause a problem:
+/// ```no_run
+/// #![feature(const_eval_select)]
+/// use std::hint::unreachable_unchecked;
+/// use std::intrinsics::const_eval_select;
+///
+/// // Crate A
+/// pub const fn inconsistent() -> i32 {
+///     fn runtime() -> i32 { 1 }
+///     const fn compiletime() -> i32 { 2 }
 ///
-/// Code that uses this intrinsic must be extremely careful to ensure that
-/// `const fn`s remain referentially-transparent independently of when they
-/// are evaluated.
+///     unsafe {
+//          // ⚠ This code violates the required equivalence of `compiletime`
+///         // and `runtime`.
+///         const_eval_select((), compiletime, runtime)
+///     }
+/// }
 ///
-/// The Rust compiler assumes that it is sound to replace a call to a `const
-/// fn` with the result produced by evaluating it at compile-time. If
-/// evaluating the function at run-time were to produce a different result,
-/// or have any other observable side-effects, the behavior is undefined.
+/// // Crate B
+/// const X: i32 = inconsistent();
+/// let x = inconsistent();
+/// if x != X { unsafe { unreachable_unchecked(); }}
+/// ```
 ///
-/// [referential transparency]: https://en.wikipedia.org/wiki/Referential_transparency
+/// This code causes Undefined Behavior when being run, since the
+/// `unreachable_unchecked` is actually being reached. The bug is in *crate A*,
+/// which violates the principle that a `const fn` must behave the same at
+/// compile-time and at run-time. The unsafe code in crate B is fine.
 #[unstable(
     feature = "const_eval_select",
     issue = "none",