Skip to content

Commit 4fe1b28

Browse files
committed
Add is_const_eval intrinsic
The `core::intrinsic::is_const_eval` returns `true` if it is evaluated at compile-time and false otherwise.
1 parent ef906d0 commit 4fe1b28

File tree

7 files changed

+57
-2
lines changed

7 files changed

+57
-2
lines changed

src/libcore/intrinsics.rs

+20
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,26 @@ extern "rust-intrinsic" {
660660
/// Executes a breakpoint trap, for inspection by a debugger.
661661
pub fn breakpoint();
662662

663+
/// Returns `true` during constant evaluation and `false` otherwise.
664+
///
665+
/// # Safety
666+
///
667+
/// This intrinsic allows breaking [referential transparency] in `const fn`
668+
/// and is therefore `unsafe`.
669+
///
670+
/// Code that uses this intrinsic must be extremely careful to ensure that
671+
/// `const fn`s remain referentially-transparent independently of when they
672+
/// are evaluated.
673+
///
674+
/// The Rust compiler assumes that it is sound to replace a call to a `const
675+
/// fn` with the result produced by evaluating it at compile-time. If
676+
/// evaluating the function at run-time were to produce a different result,
677+
/// or have any other observable side-effects, the behavior is undefined.
678+
///
679+
/// [referential transparency]: https://en.wikipedia.org/wiki/Referential_transparency
680+
#[cfg(not(boostrap_stdarch_ignore_this))]
681+
pub fn is_const_eval() -> bool;
682+
663683
/// The size of a type in bytes.
664684
///
665685
/// More specifically, this is the offset in bytes between successive

src/librustc_codegen_llvm/intrinsic.rs

+3
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,9 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
518518
}
519519

520520
},
521+
"is_const_eval" => {
522+
self.const_bool(false)
523+
},
521524
"fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => {
522525
match float_type_width(arg_tys[0]) {
523526
Some(_width) =>

src/librustc_mir/interpret/intrinsics.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,11 @@ crate fn eval_nullary_intrinsic<'tcx>(
4646
def_id: DefId,
4747
substs: SubstsRef<'tcx>,
4848
) -> InterpResult<'tcx, &'tcx ty::Const<'tcx>> {
49-
let tp_ty = substs.type_at(0);
5049
let name = &*tcx.item_name(def_id).as_str();
50+
if name == "is_const_eval" {
51+
return Ok(ty::Const::from_bool(tcx, true));
52+
}
53+
let tp_ty = substs.type_at(0);
5154
Ok(match name {
5255
"type_name" => {
5356
let alloc = type_name::alloc_type_name(tcx, tp_ty);
@@ -94,6 +97,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
9497

9598
let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..];
9699
match intrinsic_name {
100+
"is_const_eval" |
97101
"min_align_of" |
98102
"pref_align_of" |
99103
"needs_drop" |

src/librustc_mir/transform/qualify_consts.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -557,8 +557,8 @@ impl Qualif for IsNotPromotable {
557557
| "saturating_add"
558558
| "saturating_sub"
559559
| "transmute"
560+
| "is_const_eval"
560561
=> return true,
561-
562562
_ => {}
563563
}
564564
}

src/librustc_typeck/check/intrinsic.rs

+1
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem) {
145145
"rustc_peek" => (1, vec![param(0)], param(0)),
146146
"panic_if_uninhabited" => (1, Vec::new(), tcx.mk_unit()),
147147
"init" => (1, Vec::new(), param(0)),
148+
"is_const_eval" => (0, Vec::new(), tcx.types.bool),
148149
"uninit" => (1, Vec::new(), param(0)),
149150
"forget" => (1, vec![param(0)], tcx.mk_unit()),
150151
"transmute" => (2, vec![ param(0) ], param(1)),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// compile-flags: -C no-prepopulate-passes
2+
3+
#![crate_type = "lib"]
4+
#![feature(core_intrinsics)]
5+
6+
use std::intrinsics::is_const_eval;
7+
8+
// CHECK-LABEL: @is_const_eval_test
9+
#[no_mangle]
10+
pub unsafe fn is_const_eval_test() -> bool {
11+
// CHECK: %0 = alloca i8, align 1
12+
// CHECK: store i8 0, i8* %0, align 1
13+
// CHECK: %2 = trunc i8 %1 to i1
14+
// CHECK: ret i1 %2
15+
is_const_eval()
16+
}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// run-pass
2+
3+
#![feature(core_intrinsics)]
4+
use std::intrinsics::is_const_eval;
5+
6+
fn main() {
7+
const X: bool = unsafe { is_const_eval() };
8+
let y = unsafe { is_const_eval() };
9+
assert_eq!(X, true);
10+
assert_eq!(y, false);
11+
}

0 commit comments

Comments
 (0)