Auto merge of #89247 - fee1-dead:const-eval-select, r=oli-obk
Add `const_eval_select` intrinsic Adds an intrinsic that calls a given function when evaluated at compiler time, but generates a call to another function when called at runtime. See https://github.com/rust-lang/const-eval/issues/7 for previous discussion. r? `@oli-obk.`
This commit is contained in:
commit
c34ac8747c
22 changed files with 372 additions and 39 deletions
17
src/test/codegen/intrinsics/const_eval_select.rs
Normal file
17
src/test/codegen/intrinsics/const_eval_select.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// compile-flags: -C no-prepopulate-passes
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(const_eval_select)]
|
||||
|
||||
use std::intrinsics::const_eval_select;
|
||||
|
||||
const fn foo(_: i32) -> i32 { 1 }
|
||||
|
||||
#[no_mangle]
|
||||
pub fn hi(n: i32) -> i32 { n }
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn hey() {
|
||||
// CHECK: call i32 @hi(i32
|
||||
const_eval_select((42,), foo, hi);
|
||||
}
|
||||
36
src/test/ui/intrinsics/const-eval-select-bad.rs
Normal file
36
src/test/ui/intrinsics/const-eval-select-bad.rs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#![feature(const_eval_select)]
|
||||
|
||||
use std::intrinsics::const_eval_select;
|
||||
|
||||
const fn not_fn_items() {
|
||||
const_eval_select((), || {}, || {});
|
||||
//~^ ERROR expected a `FnOnce<()>` closure
|
||||
const_eval_select((), 42, 0xDEADBEEF);
|
||||
//~^ ERROR expected a `FnOnce<()>` closure
|
||||
}
|
||||
|
||||
const fn foo(n: i32) -> i32 {
|
||||
n
|
||||
}
|
||||
|
||||
fn bar(n: i32) -> bool {
|
||||
assert_eq!(n, 0, "{} must be equal to {}", n, 0);
|
||||
n == 0
|
||||
}
|
||||
|
||||
fn baz(n: bool) -> i32 {
|
||||
assert!(n, "{} must be true", n);
|
||||
n as i32
|
||||
}
|
||||
|
||||
const fn return_ty_mismatch() {
|
||||
const_eval_select((1,), foo, bar);
|
||||
//~^ ERROR type mismatch
|
||||
}
|
||||
|
||||
const fn args_ty_mismatch() {
|
||||
const_eval_select((true,), foo, baz);
|
||||
//~^ ERROR type mismatch
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
65
src/test/ui/intrinsics/const-eval-select-bad.stderr
Normal file
65
src/test/ui/intrinsics/const-eval-select-bad.stderr
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
error[E0277]: expected a `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]`
|
||||
--> $DIR/const-eval-select-bad.rs:6:34
|
||||
|
|
||||
LL | const_eval_select((), || {}, || {});
|
||||
| ----------------- ^^^^^ expected an `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the trait `FnOnce<()>` is not implemented for `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]`
|
||||
= note: wrap the `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]` in a closure with no arguments: `|| { /* code */ }`
|
||||
note: required by a bound in `const_eval_select`
|
||||
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
|
||||
|
|
||||
LL | F: ~const FnOnce<ARG, Output = RET>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
|
||||
|
||||
error[E0277]: expected a `FnOnce<()>` closure, found `{integer}`
|
||||
--> $DIR/const-eval-select-bad.rs:8:31
|
||||
|
|
||||
LL | const_eval_select((), 42, 0xDEADBEEF);
|
||||
| ----------------- ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `{integer}`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the trait `FnOnce<()>` is not implemented for `{integer}`
|
||||
= note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }`
|
||||
note: required by a bound in `const_eval_select`
|
||||
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
|
||||
|
|
||||
LL | F: ~const FnOnce<ARG, Output = RET>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
|
||||
|
||||
error[E0271]: type mismatch resolving `<fn(i32) -> bool {bar} as FnOnce<(i32,)>>::Output == i32`
|
||||
--> $DIR/const-eval-select-bad.rs:27:5
|
||||
|
|
||||
LL | const_eval_select((1,), foo, bar);
|
||||
| ^^^^^^^^^^^^^^^^^ expected `i32`, found `bool`
|
||||
|
|
||||
note: required by a bound in `const_eval_select`
|
||||
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
|
||||
|
|
||||
LL | G: FnOnce<ARG, Output = RET> + ~const Drop,
|
||||
| ^^^^^^^^^^^^ required by this bound in `const_eval_select`
|
||||
|
||||
error[E0631]: type mismatch in function arguments
|
||||
--> $DIR/const-eval-select-bad.rs:32:37
|
||||
|
|
||||
LL | const fn foo(n: i32) -> i32 {
|
||||
| --------------------------- found signature of `fn(i32) -> _`
|
||||
...
|
||||
LL | const_eval_select((true,), foo, baz);
|
||||
| ----------------- ^^^ expected signature of `fn(bool) -> _`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: required by a bound in `const_eval_select`
|
||||
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
|
||||
|
|
||||
LL | F: ~const FnOnce<ARG, Output = RET>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0271, E0277, E0631.
|
||||
For more information about an error, try `rustc --explain E0271`.
|
||||
20
src/test/ui/intrinsics/const-eval-select-stability.rs
Normal file
20
src/test/ui/intrinsics/const-eval-select-stability.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#![feature(staged_api)]
|
||||
#![feature(const_eval_select)]
|
||||
#![stable(since = "1.0", feature = "ui_test")]
|
||||
|
||||
use std::intrinsics::const_eval_select;
|
||||
|
||||
fn log() {
|
||||
println!("HEY HEY HEY")
|
||||
}
|
||||
|
||||
const fn nothing(){}
|
||||
|
||||
#[stable(since = "1.0", feature = "hey")]
|
||||
#[rustc_const_stable(since = "1.0", feature = "const_hey")]
|
||||
pub const unsafe fn hey() {
|
||||
const_eval_select((), nothing, log);
|
||||
//~^ ERROR `const_eval_select` is not yet stable as a const fn
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
10
src/test/ui/intrinsics/const-eval-select-stability.stderr
Normal file
10
src/test/ui/intrinsics/const-eval-select-stability.stderr
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
error: `const_eval_select` is not yet stable as a const fn
|
||||
--> $DIR/const-eval-select-stability.rs:16:5
|
||||
|
|
||||
LL | const_eval_select((), nothing, log);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: const-stable functions can only call other const-stable functions
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
39
src/test/ui/intrinsics/const-eval-select-x86_64.rs
Normal file
39
src/test/ui/intrinsics/const-eval-select-x86_64.rs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// run-pass
|
||||
// only-x86_64
|
||||
|
||||
#![feature(const_eval_select)]
|
||||
use std::intrinsics::const_eval_select;
|
||||
use std::arch::x86_64::*;
|
||||
use std::mem::transmute;
|
||||
|
||||
const fn eq_ct(x: [i32; 4], y: [i32; 4]) -> bool {
|
||||
x[0] == y[0] && x[1] == y[1] && x[2] == y[2] && x[3] == y[3]
|
||||
}
|
||||
|
||||
fn eq_rt(x: [i32; 4], y: [i32; 4]) -> bool {
|
||||
unsafe {
|
||||
let x = _mm_loadu_si128(&x as *const _ as *const _);
|
||||
let y = _mm_loadu_si128(&y as *const _ as *const _);
|
||||
let r = _mm_cmpeq_epi32(x, y);
|
||||
let r = _mm_movemask_ps(transmute(r) );
|
||||
r == 0b1111
|
||||
}
|
||||
}
|
||||
|
||||
const fn eq(x: [i32; 4], y: [i32; 4]) -> bool {
|
||||
unsafe {
|
||||
const_eval_select((x, y), eq_ct, eq_rt)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
const X: bool = eq([0, 1, 2, 3], [0, 1, 2, 3]);
|
||||
assert_eq!(X, true);
|
||||
let x = eq([0, 1, 2, 3], [0, 1, 2, 3]);
|
||||
assert_eq!(x, true);
|
||||
|
||||
const Y: bool = eq([0, 1, 2, 3], [0, 1, 3, 2]);
|
||||
assert_eq!(Y, false);
|
||||
let y = eq([0, 1, 2, 3], [0, 1, 3, 2]);
|
||||
assert_eq!(y, false);
|
||||
}
|
||||
26
src/test/ui/intrinsics/const-eval-select.rs
Normal file
26
src/test/ui/intrinsics/const-eval-select.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// run-pass
|
||||
|
||||
#![feature(const_eval_select)]
|
||||
|
||||
use std::intrinsics::const_eval_select;
|
||||
|
||||
const fn yes() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn no() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
// not a sound use case; testing only
|
||||
const fn is_const_eval() -> bool {
|
||||
unsafe { const_eval_select((), yes, no) }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
const YES: bool = is_const_eval();
|
||||
let no = is_const_eval();
|
||||
|
||||
assert_eq!(true, YES);
|
||||
assert_eq!(false, no);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue