blob: 5e85978e2990d208393d7d656c57bb10d48b76a0 [file] [log] [blame]
use super::*;
#[test]
fn size_of() {
check_number(
r#"
#[rustc_intrinsic]
pub fn size_of<T>() -> usize;
const GOAL: usize = size_of::<i32>();
"#,
4,
);
}
#[test]
fn size_of_val() {
check_number(
r#"
//- minicore: coerce_unsized
#[rustc_intrinsic]
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
struct X(i32, u8);
const GOAL: usize = size_of_val(&X(1, 2));
"#,
8,
);
check_number(
r#"
//- minicore: coerce_unsized
#[rustc_intrinsic]
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
const GOAL: usize = {
let it: &[i32] = &[1, 2, 3];
size_of_val(it)
};
"#,
12,
);
check_number(
r#"
//- minicore: coerce_unsized, transmute
use core::mem::transmute;
#[rustc_intrinsic]
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
struct X {
x: i64,
y: u8,
t: [i32],
}
const GOAL: usize = unsafe {
let y: &X = transmute([0usize, 3]);
size_of_val(y)
};
"#,
24,
);
check_number(
r#"
//- minicore: coerce_unsized, transmute
use core::mem::transmute;
#[rustc_intrinsic]
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
struct X {
x: i32,
y: i64,
t: [u8],
}
const GOAL: usize = unsafe {
let y: &X = transmute([0usize, 15]);
size_of_val(y)
};
"#,
32,
);
check_number(
r#"
//- minicore: coerce_unsized, fmt, builtin_impls, dispatch_from_dyn
#[rustc_intrinsic]
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
const GOAL: usize = {
let x: &i16 = &5;
let y: &dyn core::fmt::Debug = x;
let z: &dyn core::fmt::Debug = &y;
size_of_val(x) + size_of_val(y) * 10 + size_of_val(z) * 100
};
"#,
1622,
);
check_number(
r#"
//- minicore: coerce_unsized
#[rustc_intrinsic]
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
const GOAL: usize = {
size_of_val("salam")
};
"#,
5,
);
}
#[test]
fn align_of_val() {
check_number(
r#"
//- minicore: coerce_unsized
#[rustc_intrinsic]
pub fn align_of_val<T: ?Sized>(_: *const T) -> usize;
struct X(i32, u8);
const GOAL: usize = align_of_val(&X(1, 2));
"#,
4,
);
check_number(
r#"
//- minicore: coerce_unsized
#[rustc_intrinsic]
pub fn align_of_val<T: ?Sized>(_: *const T) -> usize;
const GOAL: usize = {
let x: &[i32] = &[1, 2, 3];
align_of_val(x)
};
"#,
4,
);
}
#[test]
fn type_name() {
check_str(
r#"
#[rustc_intrinsic]
pub fn type_name<T: ?Sized>() -> &'static str;
const GOAL: &str = type_name::<i32>();
"#,
"i32",
);
check_str(
r#"
#[rustc_intrinsic]
pub fn type_name<T: ?Sized>() -> &'static str;
mod mod1 {
pub mod mod2 {
pub struct Ty;
}
}
const GOAL: &str = type_name::<mod1::mod2::Ty>();
"#,
"mod1::mod2::Ty",
);
}
#[test]
fn transmute() {
check_number(
r#"
#[rustc_intrinsic]
pub fn transmute<T, U>(e: T) -> U;
const GOAL: i32 = transmute((1i16, 1i16));
"#,
0x00010001,
);
}
#[test]
fn read_via_copy() {
check_number(
r#"
#[rustc_intrinsic]
pub fn read_via_copy<T>(e: *const T) -> T;
#[rustc_intrinsic]
pub fn volatile_load<T>(e: *const T) -> T;
const GOAL: i32 = {
let x = 2;
read_via_copy(&x) + volatile_load(&x)
};
"#,
4,
);
}
#[test]
fn const_eval_select() {
check_number(
r#"
//- minicore: fn
extern "rust-intrinsic" {
pub fn const_eval_select<ARG, F, G, RET>(arg: ARG, called_in_const: F, called_at_rt: G) -> RET
where
G: FnOnce<ARG, Output = RET>,
F: FnOnce<ARG, Output = RET>;
}
const fn in_const(x: i32, y: i32) -> i32 {
x + y
}
fn in_rt(x: i32, y: i32) -> i32 {
x + y
}
const GOAL: i32 = const_eval_select((2, 3), in_const, in_rt);
"#,
5,
);
}
#[test]
fn wrapping_add() {
check_number(
r#"
extern "rust-intrinsic" {
pub fn wrapping_add<T>(a: T, b: T) -> T;
}
const GOAL: u8 = wrapping_add(10, 250);
"#,
4,
);
}
#[test]
fn ptr_offset_from() {
check_number(
r#"
//- minicore: index, slice, coerce_unsized
extern "rust-intrinsic" {
pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;
pub fn ptr_offset_from_unsigned<T>(ptr: *const T, base: *const T) -> usize;
}
const GOAL: isize = {
let x = [1, 2, 3, 4, 5i32];
let r1 = -ptr_offset_from(&x[0], &x[4]);
let r2 = ptr_offset_from(&x[3], &x[1]);
let r3 = ptr_offset_from_unsigned(&x[3], &x[0]) as isize;
r3 * 100 + r2 * 10 + r1
};
"#,
324,
);
}
#[test]
fn saturating() {
check_number(
r#"
extern "rust-intrinsic" {
pub fn saturating_add<T>(a: T, b: T) -> T;
}
const GOAL: u8 = saturating_add(10, 250);
"#,
255,
);
check_number(
r#"
extern "rust-intrinsic" {
pub fn saturating_sub<T>(a: T, b: T) -> T;
}
const GOAL: bool = saturating_sub(5u8, 7) == 0 && saturating_sub(8u8, 4) == 4;
"#,
1,
);
check_number(
r#"
extern "rust-intrinsic" {
pub fn saturating_add<T>(a: T, b: T) -> T;
}
const GOAL: i8 = saturating_add(5, 8);
"#,
13,
);
}
#[test]
fn allocator() {
check_number(
r#"
//- minicore: sized
extern "Rust" {
#[rustc_allocator]
fn __rust_alloc(size: usize, align: usize) -> *mut u8;
#[rustc_deallocator]
fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
#[rustc_reallocator]
fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8;
#[rustc_allocator_zeroed]
fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
}
const GOAL: u8 = unsafe {
let ptr = __rust_alloc(4, 1);
let ptr2 = ((ptr as usize) + 1) as *mut u8;
*ptr = 23;
*ptr2 = 32;
let ptr = __rust_realloc(ptr, 4, 1, 8);
let ptr = __rust_realloc(ptr, 8, 1, 3);
let ptr2 = ((ptr as usize) + 1) as *mut u8;
*ptr + *ptr2
};
"#,
55,
);
}
#[test]
fn overflowing_add() {
check_number(
r#"
extern "rust-intrinsic" {
pub fn add_with_overflow<T>(x: T, y: T) -> (T, bool);
}
const GOAL: u8 = add_with_overflow(1, 2).0;
"#,
3,
);
check_number(
r#"
extern "rust-intrinsic" {
pub fn add_with_overflow<T>(x: T, y: T) -> (T, bool);
}
const GOAL: u8 = add_with_overflow(1, 2).1 as u8;
"#,
0,
);
}
#[test]
fn needs_drop() {
check_number(
r#"
//- minicore: drop, manually_drop, copy, sized
use core::mem::ManuallyDrop;
extern "rust-intrinsic" {
pub fn needs_drop<T: ?Sized>() -> bool;
}
struct X;
struct NeedsDrop;
impl Drop for NeedsDrop {
fn drop(&mut self) {}
}
enum Enum<T> {
A(T),
B(X),
}
const fn val_needs_drop<T>(_v: T) -> bool { needs_drop::<T>() }
const fn closure_needs_drop() -> bool {
let a = NeedsDrop;
let b = X;
!val_needs_drop(|| &a) && val_needs_drop(move || &a) && !val_needs_drop(move || &b)
}
const fn opaque() -> impl Sized {
|| {}
}
const fn opaque_copy() -> impl Sized + Copy {
|| {}
}
trait Everything {}
impl<T> Everything for T {}
const GOAL: bool = !needs_drop::<i32>() && !needs_drop::<X>()
&& needs_drop::<NeedsDrop>() && !needs_drop::<ManuallyDrop<NeedsDrop>>()
&& needs_drop::<[NeedsDrop; 1]>() && !needs_drop::<[NeedsDrop; 0]>()
&& needs_drop::<(X, NeedsDrop)>()
&& needs_drop::<Enum<NeedsDrop>>() && !needs_drop::<Enum<X>>()
&& closure_needs_drop()
&& !val_needs_drop(opaque()) && !val_needs_drop(opaque_copy())
&& needs_drop::<[NeedsDrop]>() && needs_drop::<dyn Everything>()
&& !needs_drop::<&dyn Everything>() && !needs_drop::<str>();
"#,
1,
);
}
#[test]
fn discriminant_value() {
check_number(
r#"
//- minicore: discriminant, option
use core::marker::DiscriminantKind;
extern "rust-intrinsic" {
pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant;
}
const GOAL: bool = {
discriminant_value(&Some(2i32)) == discriminant_value(&Some(5i32))
&& discriminant_value(&Some(2i32)) != discriminant_value(&None::<i32>)
};
"#,
1,
);
}
#[test]
fn likely() {
check_number(
r#"
#[rustc_intrinsic]
pub const fn likely(b: bool) -> bool {
b
}
#[rustc_intrinsic]
pub const fn unlikely(b: bool) -> bool {
b
}
const GOAL: bool = likely(true) && unlikely(true) && !likely(false) && !unlikely(false);
"#,
1,
);
}
#[test]
fn floating_point() {
// FIXME(#17451): Add `f16` and `f128` tests once intrinsics are added.
check_number(
r#"
extern "rust-intrinsic" {
pub fn sqrtf32(x: f32) -> f32;
pub fn powf32(a: f32, x: f32) -> f32;
pub fn fmaf32(a: f32, b: f32, c: f32) -> f32;
}
const GOAL: f32 = sqrtf32(1.2) + powf32(3.4, 5.6) + fmaf32(-7.8, 1.3, 2.4);
"#,
i128::from_le_bytes(pad16(
&f32::to_le_bytes(1.2f32.sqrt() + 3.4f32.powf(5.6) + (-7.8f32).mul_add(1.3, 2.4)),
true,
)),
);
#[allow(unknown_lints, clippy::unnecessary_min_or_max)]
check_number(
r#"
extern "rust-intrinsic" {
pub fn powif64(a: f64, x: i32) -> f64;
pub fn sinf64(x: f64) -> f64;
pub fn minnumf64(x: f64, y: f64) -> f64;
}
const GOAL: f64 = powif64(1.2, 5) + sinf64(3.4) + minnumf64(-7.8, 1.3);
"#,
i128::from_le_bytes(pad16(
&f64::to_le_bytes(1.2f64.powi(5) + 3.4f64.sin() + (-7.8f64).min(1.3)),
true,
)),
);
}
#[test]
fn atomic() {
check_number(
r#"
//- minicore: copy
extern "rust-intrinsic" {
pub fn atomic_load_seqcst<T: Copy>(src: *const T) -> T;
pub fn atomic_xchg_acquire<T: Copy>(dst: *mut T, src: T) -> T;
pub fn atomic_cxchg_release_seqcst<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool);
pub fn atomic_cxchgweak_acquire_acquire<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool);
pub fn atomic_store_release<T: Copy>(dst: *mut T, val: T);
pub fn atomic_xadd_acqrel<T: Copy>(dst: *mut T, src: T) -> T;
pub fn atomic_xsub_seqcst<T: Copy>(dst: *mut T, src: T) -> T;
pub fn atomic_and_acquire<T: Copy>(dst: *mut T, src: T) -> T;
pub fn atomic_nand_seqcst<T: Copy>(dst: *mut T, src: T) -> T;
pub fn atomic_or_release<T: Copy>(dst: *mut T, src: T) -> T;
pub fn atomic_xor_seqcst<T: Copy>(dst: *mut T, src: T) -> T;
pub fn atomic_fence_seqcst();
pub fn atomic_singlethreadfence_acqrel();
}
fn should_not_reach() {
_ // fails the test if executed
}
const GOAL: i32 = {
let mut x = 5;
atomic_store_release(&mut x, 10);
let mut y = atomic_xchg_acquire(&mut x, 100);
atomic_xadd_acqrel(&mut y, 20);
if (30, true) != atomic_cxchg_release_seqcst(&mut y, 30, 40) {
should_not_reach();
}
atomic_fence_seqcst();
if (40, false) != atomic_cxchg_release_seqcst(&mut y, 30, 50) {
should_not_reach();
}
if (40, true) != atomic_cxchgweak_acquire_acquire(&mut y, 40, 30) {
should_not_reach();
}
let mut z = atomic_xsub_seqcst(&mut x, -200);
atomic_singlethreadfence_acqrel();
atomic_xor_seqcst(&mut x, 1024);
atomic_load_seqcst(&x) + z * 3 + atomic_load_seqcst(&y) * 2
};
"#,
660 + 1024,
);
}
#[test]
fn offset() {
check_number(
r#"
//- minicore: coerce_unsized, index, slice
extern "rust-intrinsic" {
pub fn offset<Ptr, Delta>(dst: Ptr, offset: Delta) -> Ptr;
pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
}
const GOAL: i32 = unsafe {
let ar: &[(i32, i32, i32)] = &[
(10, 11, 12),
(20, 21, 22),
(30, 31, 32),
(40, 41, 42),
(50, 51, 52),
];
let ar: *const [(i32, i32, i32)] = ar;
let ar = ar as *const (i32, i32, i32);
let element3 = *offset(ar, 2usize);
let element4 = *arith_offset(ar, 3);
element3.1 * 100 + element4.0
};
"#,
3140,
);
}
#[test]
fn arith_offset() {
check_number(
r#"
//- minicore: coerce_unsized, index, slice
extern "rust-intrinsic" {
pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
}
const GOAL: u8 = unsafe {
let ar: &[(u8, u8, u8)] = &[
(10, 11, 12),
(20, 21, 22),
(30, 31, 32),
(40, 41, 42),
(50, 51, 52),
];
let ar: *const [(u8, u8, u8)] = ar;
let ar = ar as *const (u8, u8, u8);
let element = *arith_offset(arith_offset(ar, 102), -100);
element.1
};
"#,
31,
);
}
#[test]
fn copy_nonoverlapping() {
check_number(
r#"
extern "rust-intrinsic" {
pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
}
const GOAL: u8 = unsafe {
let mut x = 2;
let y = 5;
copy_nonoverlapping(&y, &mut x, 1);
x
};
"#,
5,
);
}
#[test]
fn write_bytes() {
check_number(
r#"
extern "rust-intrinsic" {
fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
}
const GOAL: i32 = unsafe {
let mut x = 2;
write_bytes(&mut x, 5, 1);
x
};
"#,
0x05050505,
);
}
#[test]
fn write_via_move() {
check_number(
r#"
extern "rust-intrinsic" {
fn write_via_move<T>(ptr: *mut T, value: T);
}
const GOAL: i32 = unsafe {
let mut x = 2;
write_via_move(&mut x, 100);
x
};
"#,
100,
);
}
#[test]
fn copy() {
check_number(
r#"
//- minicore: coerce_unsized, index, slice
extern "rust-intrinsic" {
pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
}
const GOAL: i32 = unsafe {
let mut x = [1i32, 2, 3, 4, 5];
let y = (&mut x as *mut _) as *mut i32;
let z = (y as usize + 4) as *const i32;
copy(z, y, 4);
x[0] + x[1] + x[2] + x[3] + x[4]
};
"#,
19,
);
}
#[test]
fn ctpop() {
check_number(
r#"
extern "rust-intrinsic" {
pub fn ctpop<T: Copy>(x: T) -> T;
}
const GOAL: i64 = ctpop(-29);
"#,
61,
);
}
#[test]
fn ctlz() {
check_number(
r#"
extern "rust-intrinsic" {
pub fn ctlz<T: Copy>(x: T) -> T;
}
const GOAL: u8 = ctlz(0b0001_1100_u8);
"#,
3,
);
}
#[test]
fn cttz() {
check_number(
r#"
extern "rust-intrinsic" {
pub fn cttz<T: Copy>(x: T) -> T;
}
const GOAL: i64 = cttz(-24);
"#,
3,
);
}
#[test]
fn rotate() {
check_number(
r#"
extern "rust-intrinsic" {
pub fn rotate_left<T: Copy>(x: T, y: T) -> T;
}
const GOAL: i64 = rotate_left(0xaa00000000006e1i64, 12);
"#,
0x6e10aa,
);
check_number(
r#"
extern "rust-intrinsic" {
pub fn rotate_right<T: Copy>(x: T, y: T) -> T;
}
const GOAL: i64 = rotate_right(0x6e10aa, 12);
"#,
0xaa00000000006e1,
);
check_number(
r#"
extern "rust-intrinsic" {
pub fn rotate_left<T: Copy>(x: T, y: T) -> T;
}
const GOAL: i8 = rotate_left(129, 2);
"#,
6,
);
check_number(
r#"
#[rustc_intrinsic]
pub fn rotate_right<T: Copy>(x: T, y: T) -> T;
const GOAL: i32 = rotate_right(10006016, 1020315);
"#,
320192512,
);
}
#[test]
fn simd() {
check_number(
r#"
pub struct i8x16(
i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,
);
#[rustc_intrinsic]
pub fn simd_bitmask<T, U>(x: T) -> U;
const GOAL: u16 = simd_bitmask(i8x16(
0, 1, 0, 0, 2, 255, 100, 0, 50, 0, 1, 1, 0, 0, 0, 0
));
"#,
0b0000110101110010,
);
check_number(
r#"
pub struct i8x16(
i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,
);
#[rustc_intrinsic]
pub fn simd_lt<T, U>(x: T, y: T) -> U;
#[rustc_intrinsic]
pub fn simd_bitmask<T, U>(x: T) -> U;
const GOAL: u16 = simd_bitmask(simd_lt::<i8x16, i8x16>(
i8x16(
-105, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
),
i8x16(
-4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
),
));
"#,
0xFFFF,
);
}