diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
commit | 698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch) | |
tree | 173a775858bd501c378080a10dca74132f05bc50 /src/test/ui/intrinsics | |
parent | Initial commit. (diff) | |
download | rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip |
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/test/ui/intrinsics')
33 files changed, 1464 insertions, 0 deletions
diff --git a/src/test/ui/intrinsics/auxiliary/cci_intrinsic.rs b/src/test/ui/intrinsics/auxiliary/cci_intrinsic.rs new file mode 100644 index 000000000..f3b9d569c --- /dev/null +++ b/src/test/ui/intrinsics/auxiliary/cci_intrinsic.rs @@ -0,0 +1,14 @@ +#![feature(intrinsics)] + +pub mod rusti { + extern "rust-intrinsic" { + pub fn atomic_xchg_seqcst<T>(dst: *mut T, src: T) -> T; + } +} + +#[inline(always)] +pub fn atomic_xchg_seqcst(dst: *mut isize, src: isize) -> isize { + unsafe { + rusti::atomic_xchg_seqcst(dst, src) + } +} diff --git a/src/test/ui/intrinsics/bad-intrinsic-monomorphization.rs b/src/test/ui/intrinsics/bad-intrinsic-monomorphization.rs new file mode 100644 index 000000000..f36a5f1ac --- /dev/null +++ b/src/test/ui/intrinsics/bad-intrinsic-monomorphization.rs @@ -0,0 +1,32 @@ +// build-fail + +#![feature(repr_simd, platform_intrinsics, core_intrinsics)] +#![allow(warnings)] +#![crate_type = "rlib"] + +// Bad monomorphizations could previously cause LLVM asserts even though the +// error was caught in the compiler. + +extern "platform-intrinsic" { + fn simd_add<T>(x: T, y: T) -> T; +} + +use std::intrinsics; + +#[derive(Copy, Clone)] +pub struct Foo(i64); + +pub fn test_cttz(v: Foo) -> Foo { + intrinsics::cttz(v) + //~^ ERROR `cttz` intrinsic: expected basic integer type, found `Foo` +} + +pub unsafe fn test_fadd_fast(a: Foo, b: Foo) -> Foo { + intrinsics::fadd_fast(a, b) + //~^ ERROR `fadd_fast` intrinsic: expected basic float type, found `Foo` +} + +pub unsafe fn test_simd_add(a: Foo, b: Foo) -> Foo { + simd_add(a, b) + //~^ ERROR `simd_add` intrinsic: expected SIMD input type, found non-SIMD `Foo` +} diff --git a/src/test/ui/intrinsics/bad-intrinsic-monomorphization.stderr b/src/test/ui/intrinsics/bad-intrinsic-monomorphization.stderr new file mode 100644 index 000000000..c070f0181 --- /dev/null +++ b/src/test/ui/intrinsics/bad-intrinsic-monomorphization.stderr @@ -0,0 +1,21 @@ +error[E0511]: invalid monomorphization of `cttz` intrinsic: expected basic integer type, found `Foo` + --> $DIR/bad-intrinsic-monomorphization.rs:20:5 + | +LL | intrinsics::cttz(v) + | ^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `fadd_fast` intrinsic: expected basic float type, found `Foo` + --> $DIR/bad-intrinsic-monomorphization.rs:25:5 + | +LL | intrinsics::fadd_fast(a, b) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_add` intrinsic: expected SIMD input type, found non-SIMD `Foo` + --> $DIR/bad-intrinsic-monomorphization.rs:30:5 + | +LL | simd_add(a, b) + | ^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0511`. diff --git a/src/test/ui/intrinsics/const-eval-select-bad.rs b/src/test/ui/intrinsics/const-eval-select-bad.rs new file mode 100644 index 000000000..52f4e594f --- /dev/null +++ b/src/test/ui/intrinsics/const-eval-select-bad.rs @@ -0,0 +1,38 @@ +#![feature(const_eval_select)] +#![feature(core_intrinsics)] + +use std::intrinsics::const_eval_select; + +const fn not_fn_items() { + const_eval_select((), || {}, || {}); + //~^ ERROR the trait bound + const_eval_select((), 42, 0xDEADBEEF); + //~^ ERROR the trait bound + //~| 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() {} diff --git a/src/test/ui/intrinsics/const-eval-select-bad.stderr b/src/test/ui/intrinsics/const-eval-select-bad.stderr new file mode 100644 index 000000000..89dba12c8 --- /dev/null +++ b/src/test/ui/intrinsics/const-eval-select-bad.stderr @@ -0,0 +1,88 @@ +error[E0277]: the trait bound `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]: FnOnce<()>` is not satisfied + --> $DIR/const-eval-select-bad.rs:7:27 + | +LL | const_eval_select((), || {}, || {}); + | ----------------- ^^^^^ expected an `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]` + | | + | required by a bound introduced by this call + | + = help: the trait `~const FnOnce<()>` is not implemented for `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]` +note: the trait `FnOnce<()>` is implemented for `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]`, but that implementation is not `const` + --> $DIR/const-eval-select-bad.rs:7:27 + | +LL | const_eval_select((), || {}, || {}); + | ^^^^^ + = note: wrap the `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]` 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]: the trait bound `{integer}: FnOnce<()>` is not satisfied + --> $DIR/const-eval-select-bad.rs:9:27 + | +LL | const_eval_select((), 42, 0xDEADBEEF); + | ----------------- ^^ expected an `FnOnce<()>` closure, found `{integer}` + | | + | required by a bound introduced by this call + | + = help: the trait `~const 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[E0277]: expected a `FnOnce<()>` closure, found `{integer}` + --> $DIR/const-eval-select-bad.rs:9: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 | G: FnOnce<ARG, Output = RET> + ~const Destruct, + | ^^^^^^^^^^^^^^^^^^^^^^^^^ 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:29: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 Destruct, + | ^^^^^^^^^^^^ required by this bound in `const_eval_select` + +error[E0631]: type mismatch in function arguments + --> $DIR/const-eval-select-bad.rs:34:32 + | +LL | const fn foo(n: i32) -> i32 { + | --------------------------- found signature defined here +... +LL | const_eval_select((true,), foo, baz); + | ----------------- ^^^ expected due to this + | | + | required by a bound introduced by this call + | + = note: expected function signature `fn(bool) -> _` + found function signature `fn(i32) -> _` +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 5 previous errors + +Some errors have detailed explanations: E0271, E0277, E0631. +For more information about an error, try `rustc --explain E0271`. diff --git a/src/test/ui/intrinsics/const-eval-select-stability.rs b/src/test/ui/intrinsics/const-eval-select-stability.rs new file mode 100644 index 000000000..f9554dece --- /dev/null +++ b/src/test/ui/intrinsics/const-eval-select-stability.rs @@ -0,0 +1,21 @@ +#![feature(staged_api)] +#![feature(const_eval_select)] +#![feature(core_intrinsics)] +#![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() {} diff --git a/src/test/ui/intrinsics/const-eval-select-stability.stderr b/src/test/ui/intrinsics/const-eval-select-stability.stderr new file mode 100644 index 000000000..65b507b88 --- /dev/null +++ b/src/test/ui/intrinsics/const-eval-select-stability.stderr @@ -0,0 +1,10 @@ +error: `const_eval_select` is not yet stable as a const fn + --> $DIR/const-eval-select-stability.rs:17:5 + | +LL | const_eval_select((), nothing, log); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: const-stable functions can only call other const-stable functions + +error: aborting due to previous error + diff --git a/src/test/ui/intrinsics/const-eval-select-x86_64.rs b/src/test/ui/intrinsics/const-eval-select-x86_64.rs new file mode 100644 index 000000000..f3924acf0 --- /dev/null +++ b/src/test/ui/intrinsics/const-eval-select-x86_64.rs @@ -0,0 +1,40 @@ +// run-pass +// only-x86_64 + +#![feature(const_eval_select)] +#![feature(core_intrinsics)] +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); +} diff --git a/src/test/ui/intrinsics/const-eval-select.rs b/src/test/ui/intrinsics/const-eval-select.rs new file mode 100644 index 000000000..9ff20d3fb --- /dev/null +++ b/src/test/ui/intrinsics/const-eval-select.rs @@ -0,0 +1,27 @@ +// run-pass + +#![feature(const_eval_select)] +#![feature(core_intrinsics)] + +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); +} diff --git a/src/test/ui/intrinsics/intrinsic-alignment.rs b/src/test/ui/intrinsics/intrinsic-alignment.rs new file mode 100644 index 000000000..6007eba8c --- /dev/null +++ b/src/test/ui/intrinsics/intrinsic-alignment.rs @@ -0,0 +1,66 @@ +// run-pass +// ignore-wasm32-bare seems not important to test here + +#![feature(intrinsics)] + +mod rusti { + extern "rust-intrinsic" { + pub fn pref_align_of<T>() -> usize; + pub fn min_align_of<T>() -> usize; + } +} + +#[cfg(any(target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "vxworks"))] +mod m { + #[cfg(target_arch = "x86")] + pub fn main() { + unsafe { + assert_eq!(::rusti::pref_align_of::<u64>(), 8); + assert_eq!(::rusti::min_align_of::<u64>(), 4); + } + } + + #[cfg(not(target_arch = "x86"))] + pub fn main() { + unsafe { + assert_eq!(::rusti::pref_align_of::<u64>(), 8); + assert_eq!(::rusti::min_align_of::<u64>(), 8); + } + } +} + +#[cfg(target_env = "sgx")] +mod m { + #[cfg(target_arch = "x86_64")] + pub fn main() { + unsafe { + assert_eq!(::rusti::pref_align_of::<u64>(), 8); + assert_eq!(::rusti::min_align_of::<u64>(), 8); + } + } +} + +#[cfg(target_os = "windows")] +mod m { + pub fn main() { + unsafe { + assert_eq!(::rusti::pref_align_of::<u64>(), 8); + assert_eq!(::rusti::min_align_of::<u64>(), 8); + } + } +} + +fn main() { + m::main(); +} diff --git a/src/test/ui/intrinsics/intrinsic-assume.rs b/src/test/ui/intrinsics/intrinsic-assume.rs new file mode 100644 index 000000000..3c9d70cb5 --- /dev/null +++ b/src/test/ui/intrinsics/intrinsic-assume.rs @@ -0,0 +1,17 @@ +// run-pass +#![feature(core_intrinsics)] + +use std::intrinsics::assume; + +unsafe fn f(x: i32) -> i32 { + assume(x == 34); + match x { + 34 => 42, + _ => 30 + } +} + +fn main() { + let x = unsafe { f(34) }; + assert_eq!(x, 42); +} diff --git a/src/test/ui/intrinsics/intrinsic-atomics-cc.rs b/src/test/ui/intrinsics/intrinsic-atomics-cc.rs new file mode 100644 index 000000000..ce3fa7b0c --- /dev/null +++ b/src/test/ui/intrinsics/intrinsic-atomics-cc.rs @@ -0,0 +1,12 @@ +// run-pass +// aux-build:cci_intrinsic.rs + + +extern crate cci_intrinsic; +use cci_intrinsic::atomic_xchg_seqcst; + +pub fn main() { + let mut x = 1; + atomic_xchg_seqcst(&mut x, 5); + assert_eq!(x, 5); +} diff --git a/src/test/ui/intrinsics/intrinsic-atomics.rs b/src/test/ui/intrinsics/intrinsic-atomics.rs new file mode 100644 index 000000000..b17f4347b --- /dev/null +++ b/src/test/ui/intrinsics/intrinsic-atomics.rs @@ -0,0 +1,102 @@ +// run-pass +#![feature(intrinsics)] + +mod rusti { + extern "rust-intrinsic" { + pub fn atomic_cxchg_seqcst_seqcst<T>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchg_acquire_acquire<T>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchg_release_relaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool); + + pub fn atomic_cxchgweak_seqcst_seqcst<T>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchgweak_acquire_acquire<T>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchgweak_release_relaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool); + + pub fn atomic_load_seqcst<T>(src: *const T) -> T; + pub fn atomic_load_acquire<T>(src: *const T) -> T; + + pub fn atomic_store_seqcst<T>(dst: *mut T, val: T); + pub fn atomic_store_release<T>(dst: *mut T, val: T); + + pub fn atomic_xchg_seqcst<T>(dst: *mut T, src: T) -> T; + pub fn atomic_xchg_acquire<T>(dst: *mut T, src: T) -> T; + pub fn atomic_xchg_release<T>(dst: *mut T, src: T) -> T; + + pub fn atomic_xadd_seqcst<T>(dst: *mut T, src: T) -> T; + pub fn atomic_xadd_acquire<T>(dst: *mut T, src: T) -> T; + pub fn atomic_xadd_release<T>(dst: *mut T, src: T) -> T; + + pub fn atomic_xsub_seqcst<T>(dst: *mut T, src: T) -> T; + pub fn atomic_xsub_acquire<T>(dst: *mut T, src: T) -> T; + pub fn atomic_xsub_release<T>(dst: *mut T, src: T) -> T; + } +} + +pub fn main() { + unsafe { + let mut x: Box<_> = Box::new(1); + + assert_eq!(rusti::atomic_load_seqcst(&*x), 1); + *x = 5; + assert_eq!(rusti::atomic_load_acquire(&*x), 5); + + rusti::atomic_store_seqcst(&mut *x,3); + assert_eq!(*x, 3); + rusti::atomic_store_release(&mut *x,1); + assert_eq!(*x, 1); + + assert_eq!(rusti::atomic_cxchg_seqcst_seqcst(&mut *x, 1, 2), (1, true)); + assert_eq!(*x, 2); + + assert_eq!(rusti::atomic_cxchg_acquire_acquire(&mut *x, 1, 3), (2, false)); + assert_eq!(*x, 2); + + assert_eq!(rusti::atomic_cxchg_release_relaxed(&mut *x, 2, 1), (2, true)); + assert_eq!(*x, 1); + + assert_eq!(rusti::atomic_xchg_seqcst(&mut *x, 0), 1); + assert_eq!(*x, 0); + + assert_eq!(rusti::atomic_xchg_acquire(&mut *x, 1), 0); + assert_eq!(*x, 1); + + assert_eq!(rusti::atomic_xchg_release(&mut *x, 0), 1); + assert_eq!(*x, 0); + + assert_eq!(rusti::atomic_xadd_seqcst(&mut *x, 1), 0); + assert_eq!(rusti::atomic_xadd_acquire(&mut *x, 1), 1); + assert_eq!(rusti::atomic_xadd_release(&mut *x, 1), 2); + assert_eq!(*x, 3); + + assert_eq!(rusti::atomic_xsub_seqcst(&mut *x, 1), 3); + assert_eq!(rusti::atomic_xsub_acquire(&mut *x, 1), 2); + assert_eq!(rusti::atomic_xsub_release(&mut *x, 1), 1); + assert_eq!(*x, 0); + + loop { + let res = rusti::atomic_cxchgweak_seqcst_seqcst(&mut *x, 0, 1); + assert_eq!(res.0, 0); + if res.1 { + break; + } + } + assert_eq!(*x, 1); + + loop { + let res = rusti::atomic_cxchgweak_acquire_acquire(&mut *x, 1, 2); + assert_eq!(res.0, 1); + if res.1 { + break; + } + } + assert_eq!(*x, 2); + + loop { + let res = rusti::atomic_cxchgweak_release_relaxed(&mut *x, 2, 3); + assert_eq!(res.0, 2); + if res.1 { + break; + } + } + assert_eq!(*x, 3); + } +} diff --git a/src/test/ui/intrinsics/intrinsic-nearby.rs b/src/test/ui/intrinsics/intrinsic-nearby.rs new file mode 100644 index 000000000..7b1d1eeaa --- /dev/null +++ b/src/test/ui/intrinsics/intrinsic-nearby.rs @@ -0,0 +1,11 @@ +// run-pass +#![feature(core_intrinsics)] + +use std::intrinsics::*; + +fn main() { + unsafe { + assert_eq!(nearbyintf32(5.234f32), 5f32); + assert_eq!(nearbyintf64(6.777f64), 7f64); + } +} diff --git a/src/test/ui/intrinsics/intrinsic-raw_eq-const-padding.rs b/src/test/ui/intrinsics/intrinsic-raw_eq-const-padding.rs new file mode 100644 index 000000000..a205a8730 --- /dev/null +++ b/src/test/ui/intrinsics/intrinsic-raw_eq-const-padding.rs @@ -0,0 +1,11 @@ +#![feature(core_intrinsics)] +#![feature(const_intrinsic_raw_eq)] +#![deny(const_err)] + +const BAD_RAW_EQ_CALL: bool = unsafe { + std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16)) +//~^ ERROR evaluation of constant value failed +}; + +pub fn main() { +} diff --git a/src/test/ui/intrinsics/intrinsic-raw_eq-const-padding.stderr b/src/test/ui/intrinsics/intrinsic-raw_eq-const-padding.stderr new file mode 100644 index 000000000..9322654b2 --- /dev/null +++ b/src/test/ui/intrinsics/intrinsic-raw_eq-const-padding.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/intrinsic-raw_eq-const-padding.rs:6:5 + | +LL | std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at alloc3[0x0..0x4], but memory is uninitialized at [0x1..0x2], and this operation requires initialized memory + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/intrinsics/intrinsic-raw_eq-const.rs b/src/test/ui/intrinsics/intrinsic-raw_eq-const.rs new file mode 100644 index 000000000..8ea954673 --- /dev/null +++ b/src/test/ui/intrinsics/intrinsic-raw_eq-const.rs @@ -0,0 +1,27 @@ +// run-pass + +#![feature(core_intrinsics)] +#![feature(const_intrinsic_raw_eq)] +#![deny(const_err)] + +pub fn main() { + use std::intrinsics::raw_eq; + + const RAW_EQ_I32_TRUE: bool = unsafe { raw_eq(&42_i32, &42) }; + assert!(RAW_EQ_I32_TRUE); + + const RAW_EQ_I32_FALSE: bool = unsafe { raw_eq(&4_i32, &2) }; + assert!(!RAW_EQ_I32_FALSE); + + const RAW_EQ_CHAR_TRUE: bool = unsafe { raw_eq(&'a', &'a') }; + assert!(RAW_EQ_CHAR_TRUE); + + const RAW_EQ_CHAR_FALSE: bool = unsafe { raw_eq(&'a', &'A') }; + assert!(!RAW_EQ_CHAR_FALSE); + + const RAW_EQ_ARRAY_TRUE: bool = unsafe { raw_eq(&[13_u8, 42], &[13, 42]) }; + assert!(RAW_EQ_ARRAY_TRUE); + + const RAW_EQ_ARRAY_FALSE: bool = unsafe { raw_eq(&[13_u8, 42], &[42, 13]) }; + assert!(!RAW_EQ_ARRAY_FALSE); +} diff --git a/src/test/ui/intrinsics/intrinsic-unreachable.rs b/src/test/ui/intrinsics/intrinsic-unreachable.rs new file mode 100644 index 000000000..da1a32d58 --- /dev/null +++ b/src/test/ui/intrinsics/intrinsic-unreachable.rs @@ -0,0 +1,17 @@ +// run-pass +#![feature(core_intrinsics)] + +use std::intrinsics; + +// See also src/test/run-make/intrinsic-unreachable. + +unsafe fn f(x: usize) -> usize { + match x { + 17 => 23, + _ => intrinsics::unreachable(), + } +} + +fn main() { + assert_eq!(unsafe { f(17) }, 23); +} diff --git a/src/test/ui/intrinsics/intrinsic-volatile.rs b/src/test/ui/intrinsics/intrinsic-volatile.rs new file mode 100644 index 000000000..7b2c825a2 --- /dev/null +++ b/src/test/ui/intrinsics/intrinsic-volatile.rs @@ -0,0 +1,44 @@ +// run-pass + +#![feature(core_intrinsics)] + +use std::intrinsics::*; + +pub fn main() { + unsafe { + let mut x: Box<u8> = Box::new(0); + let mut y: Box<u8> = Box::new(0); + + // test volatile load + assert_eq!(volatile_load(&*x), 0); + *x = 1; + assert_eq!(volatile_load(&*x), 1); + + // test volatile store + volatile_store(&mut *x, 2); + assert_eq!(*x, 2); + + // test volatile copy memory + volatile_copy_memory(&mut *y, &*x, 1); + assert_eq!(*y, 2); + + // test volatile copy non-overlapping memory + *x = 3; + volatile_copy_nonoverlapping_memory(&mut *y, &*x, 1); + assert_eq!(*y, 3); + + // test volatile set memory + volatile_set_memory(&mut *x, 4, 1); + assert_eq!(*x, 4); + + // test unaligned volatile load + let arr: [u8; 3] = [1, 2, 3]; + let ptr = arr[1..].as_ptr() as *const u16; + assert_eq!(unaligned_volatile_load(ptr), u16::from_ne_bytes([arr[1], arr[2]])); + + // test unaligned volatile store + let ptr = arr[1..].as_ptr() as *mut u16; + unaligned_volatile_store(ptr, 0); + assert_eq!(arr, [1, 0, 0]); + } +} diff --git a/src/test/ui/intrinsics/intrinsics-integer.rs b/src/test/ui/intrinsics/intrinsics-integer.rs new file mode 100644 index 000000000..bac6c8d87 --- /dev/null +++ b/src/test/ui/intrinsics/intrinsics-integer.rs @@ -0,0 +1,171 @@ +// run-pass + +#![feature(intrinsics)] + +mod rusti { + extern "rust-intrinsic" { + pub fn ctpop<T>(x: T) -> T; + pub fn ctlz<T>(x: T) -> T; + pub fn ctlz_nonzero<T>(x: T) -> T; + pub fn cttz<T>(x: T) -> T; + pub fn cttz_nonzero<T>(x: T) -> T; + pub fn bswap<T>(x: T) -> T; + pub fn bitreverse<T>(x: T) -> T; + } +} + +pub fn main() { + use rusti::*; + + assert_eq!(ctpop(0u8), 0); assert_eq!(ctpop(0i8), 0); + assert_eq!(ctpop(0u16), 0); assert_eq!(ctpop(0i16), 0); + assert_eq!(ctpop(0u32), 0); assert_eq!(ctpop(0i32), 0); + assert_eq!(ctpop(0u64), 0); assert_eq!(ctpop(0i64), 0); + assert_eq!(ctpop(0u128), 0); assert_eq!(ctpop(0i128), 0); + + assert_eq!(ctpop(1u8), 1); assert_eq!(ctpop(1i8), 1); + assert_eq!(ctpop(1u16), 1); assert_eq!(ctpop(1i16), 1); + assert_eq!(ctpop(1u32), 1); assert_eq!(ctpop(1i32), 1); + assert_eq!(ctpop(1u64), 1); assert_eq!(ctpop(1i64), 1); + assert_eq!(ctpop(1u128), 1); assert_eq!(ctpop(1i128), 1); + + assert_eq!(ctpop(10u8), 2); assert_eq!(ctpop(10i8), 2); + assert_eq!(ctpop(10u16), 2); assert_eq!(ctpop(10i16), 2); + assert_eq!(ctpop(10u32), 2); assert_eq!(ctpop(10i32), 2); + assert_eq!(ctpop(10u64), 2); assert_eq!(ctpop(10i64), 2); + assert_eq!(ctpop(10u128), 2); assert_eq!(ctpop(10i128), 2); + + assert_eq!(ctpop(100u8), 3); assert_eq!(ctpop(100i8), 3); + assert_eq!(ctpop(100u16), 3); assert_eq!(ctpop(100i16), 3); + assert_eq!(ctpop(100u32), 3); assert_eq!(ctpop(100i32), 3); + assert_eq!(ctpop(100u64), 3); assert_eq!(ctpop(100i64), 3); + assert_eq!(ctpop(100u128), 3); assert_eq!(ctpop(100i128), 3); + + assert_eq!(ctpop(-1i8 as u8), 8); assert_eq!(ctpop(-1i8), 8); + assert_eq!(ctpop(-1i16 as u16), 16); assert_eq!(ctpop(-1i16), 16); + assert_eq!(ctpop(-1i32 as u32), 32); assert_eq!(ctpop(-1i32), 32); + assert_eq!(ctpop(-1i64 as u64), 64); assert_eq!(ctpop(-1i64), 64); + assert_eq!(ctpop(-1i128 as u128), 128); assert_eq!(ctpop(-1i128), 128); + + assert_eq!(ctlz(0u8), 8); assert_eq!(ctlz(0i8), 8); + assert_eq!(ctlz(0u16), 16); assert_eq!(ctlz(0i16), 16); + assert_eq!(ctlz(0u32), 32); assert_eq!(ctlz(0i32), 32); + assert_eq!(ctlz(0u64), 64); assert_eq!(ctlz(0i64), 64); + assert_eq!(ctlz(0u128), 128); assert_eq!(ctlz(0i128), 128); + + assert_eq!(ctlz(1u8), 7); assert_eq!(ctlz(1i8), 7); + assert_eq!(ctlz(1u16), 15); assert_eq!(ctlz(1i16), 15); + assert_eq!(ctlz(1u32), 31); assert_eq!(ctlz(1i32), 31); + assert_eq!(ctlz(1u64), 63); assert_eq!(ctlz(1i64), 63); + assert_eq!(ctlz(1u128), 127); assert_eq!(ctlz(1i128), 127); + + assert_eq!(ctlz(10u8), 4); assert_eq!(ctlz(10i8), 4); + assert_eq!(ctlz(10u16), 12); assert_eq!(ctlz(10i16), 12); + assert_eq!(ctlz(10u32), 28); assert_eq!(ctlz(10i32), 28); + assert_eq!(ctlz(10u64), 60); assert_eq!(ctlz(10i64), 60); + assert_eq!(ctlz(10u128), 124); assert_eq!(ctlz(10i128), 124); + + assert_eq!(ctlz(100u8), 1); assert_eq!(ctlz(100i8), 1); + assert_eq!(ctlz(100u16), 9); assert_eq!(ctlz(100i16), 9); + assert_eq!(ctlz(100u32), 25); assert_eq!(ctlz(100i32), 25); + assert_eq!(ctlz(100u64), 57); assert_eq!(ctlz(100i64), 57); + assert_eq!(ctlz(100u128), 121); assert_eq!(ctlz(100i128), 121); + + unsafe { + assert_eq!(ctlz_nonzero(1u8), 7); assert_eq!(ctlz_nonzero(1i8), 7); + assert_eq!(ctlz_nonzero(1u16), 15); assert_eq!(ctlz_nonzero(1i16), 15); + assert_eq!(ctlz_nonzero(1u32), 31); assert_eq!(ctlz_nonzero(1i32), 31); + assert_eq!(ctlz_nonzero(1u64), 63); assert_eq!(ctlz_nonzero(1i64), 63); + assert_eq!(ctlz_nonzero(1u128), 127); assert_eq!(ctlz_nonzero(1i128), 127); + + assert_eq!(ctlz_nonzero(10u8), 4); assert_eq!(ctlz_nonzero(10i8), 4); + assert_eq!(ctlz_nonzero(10u16), 12); assert_eq!(ctlz_nonzero(10i16), 12); + assert_eq!(ctlz_nonzero(10u32), 28); assert_eq!(ctlz_nonzero(10i32), 28); + assert_eq!(ctlz_nonzero(10u64), 60); assert_eq!(ctlz_nonzero(10i64), 60); + assert_eq!(ctlz_nonzero(10u128), 124); assert_eq!(ctlz_nonzero(10i128), 124); + + assert_eq!(ctlz_nonzero(100u8), 1); assert_eq!(ctlz_nonzero(100i8), 1); + assert_eq!(ctlz_nonzero(100u16), 9); assert_eq!(ctlz_nonzero(100i16), 9); + assert_eq!(ctlz_nonzero(100u32), 25); assert_eq!(ctlz_nonzero(100i32), 25); + assert_eq!(ctlz_nonzero(100u64), 57); assert_eq!(ctlz_nonzero(100i64), 57); + assert_eq!(ctlz_nonzero(100u128), 121); assert_eq!(ctlz_nonzero(100i128), 121); + } + + assert_eq!(cttz(-1i8 as u8), 0); assert_eq!(cttz(-1i8), 0); + assert_eq!(cttz(-1i16 as u16), 0); assert_eq!(cttz(-1i16), 0); + assert_eq!(cttz(-1i32 as u32), 0); assert_eq!(cttz(-1i32), 0); + assert_eq!(cttz(-1i64 as u64), 0); assert_eq!(cttz(-1i64), 0); + assert_eq!(cttz(-1i128 as u128), 0); assert_eq!(cttz(-1i128), 0); + + assert_eq!(cttz(0u8), 8); assert_eq!(cttz(0i8), 8); + assert_eq!(cttz(0u16), 16); assert_eq!(cttz(0i16), 16); + assert_eq!(cttz(0u32), 32); assert_eq!(cttz(0i32), 32); + assert_eq!(cttz(0u64), 64); assert_eq!(cttz(0i64), 64); + assert_eq!(cttz(0u128), 128); assert_eq!(cttz(0i128), 128); + + assert_eq!(cttz(1u8), 0); assert_eq!(cttz(1i8), 0); + assert_eq!(cttz(1u16), 0); assert_eq!(cttz(1i16), 0); + assert_eq!(cttz(1u32), 0); assert_eq!(cttz(1i32), 0); + assert_eq!(cttz(1u64), 0); assert_eq!(cttz(1i64), 0); + assert_eq!(cttz(1u128), 0); assert_eq!(cttz(1i128), 0); + + assert_eq!(cttz(10u8), 1); assert_eq!(cttz(10i8), 1); + assert_eq!(cttz(10u16), 1); assert_eq!(cttz(10i16), 1); + assert_eq!(cttz(10u32), 1); assert_eq!(cttz(10i32), 1); + assert_eq!(cttz(10u64), 1); assert_eq!(cttz(10i64), 1); + assert_eq!(cttz(10u128), 1); assert_eq!(cttz(10i128), 1); + + assert_eq!(cttz(100u8), 2); assert_eq!(cttz(100i8), 2); + assert_eq!(cttz(100u16), 2); assert_eq!(cttz(100i16), 2); + assert_eq!(cttz(100u32), 2); assert_eq!(cttz(100i32), 2); + assert_eq!(cttz(100u64), 2); assert_eq!(cttz(100i64), 2); + assert_eq!(cttz(100u128), 2); assert_eq!(cttz(100i128), 2); + + unsafe { + assert_eq!(cttz_nonzero(-1i8 as u8), 0); assert_eq!(cttz_nonzero(-1i8), 0); + assert_eq!(cttz_nonzero(-1i16 as u16), 0); assert_eq!(cttz_nonzero(-1i16), 0); + assert_eq!(cttz_nonzero(-1i32 as u32), 0); assert_eq!(cttz_nonzero(-1i32), 0); + assert_eq!(cttz_nonzero(-1i64 as u64), 0); assert_eq!(cttz_nonzero(-1i64), 0); + assert_eq!(cttz_nonzero(-1i128 as u128), 0); assert_eq!(cttz_nonzero(-1i128), 0); + + assert_eq!(cttz_nonzero(1u8), 0); assert_eq!(cttz_nonzero(1i8), 0); + assert_eq!(cttz_nonzero(1u16), 0); assert_eq!(cttz_nonzero(1i16), 0); + assert_eq!(cttz_nonzero(1u32), 0); assert_eq!(cttz_nonzero(1i32), 0); + assert_eq!(cttz_nonzero(1u64), 0); assert_eq!(cttz_nonzero(1i64), 0); + assert_eq!(cttz_nonzero(1u128), 0); assert_eq!(cttz_nonzero(1i128), 0); + + assert_eq!(cttz_nonzero(10u8), 1); assert_eq!(cttz_nonzero(10i8), 1); + assert_eq!(cttz_nonzero(10u16), 1); assert_eq!(cttz_nonzero(10i16), 1); + assert_eq!(cttz_nonzero(10u32), 1); assert_eq!(cttz_nonzero(10i32), 1); + assert_eq!(cttz_nonzero(10u64), 1); assert_eq!(cttz_nonzero(10i64), 1); + assert_eq!(cttz_nonzero(10u128), 1); assert_eq!(cttz_nonzero(10i128), 1); + + assert_eq!(cttz_nonzero(100u8), 2); assert_eq!(cttz_nonzero(100i8), 2); + assert_eq!(cttz_nonzero(100u16), 2); assert_eq!(cttz_nonzero(100i16), 2); + assert_eq!(cttz_nonzero(100u32), 2); assert_eq!(cttz_nonzero(100i32), 2); + assert_eq!(cttz_nonzero(100u64), 2); assert_eq!(cttz_nonzero(100i64), 2); + assert_eq!(cttz_nonzero(100u128), 2); assert_eq!(cttz_nonzero(100i128), 2); + } + + assert_eq!(bswap(0x0Au8), 0x0A); // no-op + assert_eq!(bswap(0x0Ai8), 0x0A); // no-op + assert_eq!(bswap(0x0A0Bu16), 0x0B0A); + assert_eq!(bswap(0x0A0Bi16), 0x0B0A); + assert_eq!(bswap(0x0ABBCC0Du32), 0x0DCCBB0A); + assert_eq!(bswap(0x0ABBCC0Di32), 0x0DCCBB0A); + assert_eq!(bswap(0x0122334455667708u64), 0x0877665544332201); + assert_eq!(bswap(0x0122334455667708i64), 0x0877665544332201); + assert_eq!(bswap(0x0122334455667708u128), 0x08776655443322010000000000000000); + assert_eq!(bswap(0x0122334455667708i128), 0x08776655443322010000000000000000); + + assert_eq!(bitreverse(0x0Au8), 0x50); + assert_eq!(bitreverse(0x0Ai8), 0x50); + assert_eq!(bitreverse(0x0A0Cu16), 0x3050); + assert_eq!(bitreverse(0x0A0Ci16), 0x3050); + assert_eq!(bitreverse(0x0ABBCC0Eu32), 0x7033DD50); + assert_eq!(bitreverse(0x0ABBCC0Ei32), 0x7033DD50); + assert_eq!(bitreverse(0x0122334455667708u64), 0x10EE66AA22CC4480); + assert_eq!(bitreverse(0x0122334455667708i64), 0x10EE66AA22CC4480); + assert_eq!(bitreverse(0x0122334455667708u128), 0x10EE66AA22CC44800000000000000000); + assert_eq!(bitreverse(0x0122334455667708i128), 0x10EE66AA22CC44800000000000000000); +} diff --git a/src/test/ui/intrinsics/intrinsics-math.rs b/src/test/ui/intrinsics/intrinsics-math.rs new file mode 100644 index 000000000..aea9fde69 --- /dev/null +++ b/src/test/ui/intrinsics/intrinsics-math.rs @@ -0,0 +1,60 @@ +// run-pass +// ignore-emscripten fma not implemented in emscripten + +macro_rules! assert_approx_eq { + ($a:expr, $b:expr) => ({ + let (a, b) = (&$a, &$b); + assert!((*a - *b).abs() < 1.0e-6, + "{} is not approximately equal to {}", *a, *b); + }) +} + +pub fn main() { + use std::f32; + use std::f64; + + assert_approx_eq!(64f32.sqrt(), 8f32); + assert_approx_eq!(64f64.sqrt(), 8f64); + + assert_approx_eq!(25f32.powi(-2), 0.0016f32); + assert_approx_eq!(23.2f64.powi(2), 538.24f64); + + assert_approx_eq!(0f32.sin(), 0f32); + assert_approx_eq!((f64::consts::PI / 2f64).sin(), 1f64); + + assert_approx_eq!(0f32.cos(), 1f32); + assert_approx_eq!((f64::consts::PI * 2f64).cos(), 1f64); + + assert_approx_eq!(25f32.powf(-2f32), 0.0016f32); + assert_approx_eq!(400f64.powf(0.5f64), 20f64); + + assert_approx_eq!((1f32.exp() - f32::consts::E).abs(), 0f32); + assert_approx_eq!(1f64.exp(), f64::consts::E); + + assert_approx_eq!(10f32.exp2(), 1024f32); + assert_approx_eq!(50f64.exp2(), 1125899906842624f64); + + assert_approx_eq!((f32::consts::E.ln() - 1f32).abs(), 0f32); + assert_approx_eq!(1f64.ln(), 0f64); + + assert_approx_eq!(10f32.log10(), 1f32); + assert_approx_eq!(f64::consts::E.log10(), f64::consts::LOG10_E); + + assert_approx_eq!(8f32.log2(), 3f32); + assert_approx_eq!(f64::consts::E.log2(), f64::consts::LOG2_E); + + assert_approx_eq!(1.0f32.mul_add(2.0f32, 5.0f32), 7.0f32); + assert_approx_eq!(0.0f64.mul_add(-2.0f64, f64::consts::E), f64::consts::E); + + assert_approx_eq!((-1.0f32).abs(), 1.0f32); + assert_approx_eq!(34.2f64.abs(), 34.2f64); + + assert_approx_eq!(3.8f32.floor(), 3.0f32); + assert_approx_eq!((-1.1f64).floor(), -2.0f64); + + assert_approx_eq!((-2.3f32).ceil(), -2.0f32); + assert_approx_eq!(3.8f64.ceil(), 4.0f64); + + assert_approx_eq!(0.1f32.trunc(), 0.0f32); + assert_approx_eq!((-0.1f64).trunc(), 0.0f64); +} diff --git a/src/test/ui/intrinsics/issue-28575.mir.stderr b/src/test/ui/intrinsics/issue-28575.mir.stderr new file mode 100644 index 000000000..c42498390 --- /dev/null +++ b/src/test/ui/intrinsics/issue-28575.mir.stderr @@ -0,0 +1,11 @@ +error[E0133]: use of extern static is unsafe and requires unsafe function or block + --> $DIR/issue-28575.rs:11:5 + | +LL | FOO() + | ^^^ use of extern static + | + = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/intrinsics/issue-28575.rs b/src/test/ui/intrinsics/issue-28575.rs new file mode 100644 index 000000000..410f664f8 --- /dev/null +++ b/src/test/ui/intrinsics/issue-28575.rs @@ -0,0 +1,12 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + +#![feature(intrinsics)] + +extern "C" { + pub static FOO: extern "rust-intrinsic" fn(); +} + +fn main() { + FOO() //~ ERROR: use of extern static is unsafe +} diff --git a/src/test/ui/intrinsics/issue-28575.thir.stderr b/src/test/ui/intrinsics/issue-28575.thir.stderr new file mode 100644 index 000000000..c42498390 --- /dev/null +++ b/src/test/ui/intrinsics/issue-28575.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: use of extern static is unsafe and requires unsafe function or block + --> $DIR/issue-28575.rs:11:5 + | +LL | FOO() + | ^^^ use of extern static + | + = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/intrinsics/issue-84297-reifying-copy.rs b/src/test/ui/intrinsics/issue-84297-reifying-copy.rs new file mode 100644 index 000000000..08ba9ce7e --- /dev/null +++ b/src/test/ui/intrinsics/issue-84297-reifying-copy.rs @@ -0,0 +1,9 @@ +// check-pass + +fn main() { + let _unused = if true { + core::ptr::copy::<i32> + } else { + core::ptr::copy_nonoverlapping::<i32> + }; +} diff --git a/src/test/ui/intrinsics/non-integer-atomic.rs b/src/test/ui/intrinsics/non-integer-atomic.rs new file mode 100644 index 000000000..85ea81ba6 --- /dev/null +++ b/src/test/ui/intrinsics/non-integer-atomic.rs @@ -0,0 +1,92 @@ +// build-fail + +#![feature(core_intrinsics)] +#![allow(warnings)] +#![crate_type = "rlib"] + +use std::intrinsics; + +#[derive(Copy, Clone)] +pub struct Foo(i64); +pub type Bar = &'static Fn(); +pub type Quux = [u8; 100]; + +pub unsafe fn test_bool_load(p: &mut bool, v: bool) { + intrinsics::atomic_load_seqcst(p); + //~^ ERROR `atomic_load_seqcst` intrinsic: expected basic integer type, found `bool` +} + +pub unsafe fn test_bool_store(p: &mut bool, v: bool) { + intrinsics::atomic_store_seqcst(p, v); + //~^ ERROR `atomic_store_seqcst` intrinsic: expected basic integer type, found `bool` +} + +pub unsafe fn test_bool_xchg(p: &mut bool, v: bool) { + intrinsics::atomic_xchg_seqcst(p, v); + //~^ ERROR `atomic_xchg_seqcst` intrinsic: expected basic integer type, found `bool` +} + +pub unsafe fn test_bool_cxchg(p: &mut bool, v: bool) { + intrinsics::atomic_cxchg_seqcst_seqcst(p, v, v); + //~^ ERROR `atomic_cxchg_seqcst_seqcst` intrinsic: expected basic integer type, found `bool` +} + +pub unsafe fn test_Foo_load(p: &mut Foo, v: Foo) { + intrinsics::atomic_load_seqcst(p); + //~^ ERROR `atomic_load_seqcst` intrinsic: expected basic integer type, found `Foo` +} + +pub unsafe fn test_Foo_store(p: &mut Foo, v: Foo) { + intrinsics::atomic_store_seqcst(p, v); + //~^ ERROR `atomic_store_seqcst` intrinsic: expected basic integer type, found `Foo` +} + +pub unsafe fn test_Foo_xchg(p: &mut Foo, v: Foo) { + intrinsics::atomic_xchg_seqcst(p, v); + //~^ ERROR `atomic_xchg_seqcst` intrinsic: expected basic integer type, found `Foo` +} + +pub unsafe fn test_Foo_cxchg(p: &mut Foo, v: Foo) { + intrinsics::atomic_cxchg_seqcst_seqcst(p, v, v); + //~^ ERROR `atomic_cxchg_seqcst_seqcst` intrinsic: expected basic integer type, found `Foo` +} + +pub unsafe fn test_Bar_load(p: &mut Bar, v: Bar) { + intrinsics::atomic_load_seqcst(p); + //~^ ERROR expected basic integer type, found `&dyn Fn()` +} + +pub unsafe fn test_Bar_store(p: &mut Bar, v: Bar) { + intrinsics::atomic_store_seqcst(p, v); + //~^ ERROR expected basic integer type, found `&dyn Fn()` +} + +pub unsafe fn test_Bar_xchg(p: &mut Bar, v: Bar) { + intrinsics::atomic_xchg_seqcst(p, v); + //~^ ERROR expected basic integer type, found `&dyn Fn()` +} + +pub unsafe fn test_Bar_cxchg(p: &mut Bar, v: Bar) { + intrinsics::atomic_cxchg_seqcst_seqcst(p, v, v); + //~^ ERROR expected basic integer type, found `&dyn Fn()` +} + +pub unsafe fn test_Quux_load(p: &mut Quux, v: Quux) { + intrinsics::atomic_load_seqcst(p); + //~^ ERROR `atomic_load_seqcst` intrinsic: expected basic integer type, found `[u8; 100]` +} + +pub unsafe fn test_Quux_store(p: &mut Quux, v: Quux) { + intrinsics::atomic_store_seqcst(p, v); + //~^ ERROR `atomic_store_seqcst` intrinsic: expected basic integer type, found `[u8; 100]` +} + +pub unsafe fn test_Quux_xchg(p: &mut Quux, v: Quux) { + intrinsics::atomic_xchg_seqcst(p, v); + //~^ ERROR `atomic_xchg_seqcst` intrinsic: expected basic integer type, found `[u8; 100]` +} + +pub unsafe fn test_Quux_cxchg(p: &mut Quux, v: Quux) { + intrinsics::atomic_cxchg_seqcst_seqcst(p, v, v); + //~^ ERROR `atomic_cxchg_seqcst_seqcst` intrinsic: expected basic integer type, found `[u8; 100]` +} diff --git a/src/test/ui/intrinsics/non-integer-atomic.stderr b/src/test/ui/intrinsics/non-integer-atomic.stderr new file mode 100644 index 000000000..32791a8e8 --- /dev/null +++ b/src/test/ui/intrinsics/non-integer-atomic.stderr @@ -0,0 +1,99 @@ +error[E0511]: invalid monomorphization of `atomic_load_seqcst` intrinsic: expected basic integer type, found `bool` + --> $DIR/non-integer-atomic.rs:15:5 + | +LL | intrinsics::atomic_load_seqcst(p); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `atomic_store_seqcst` intrinsic: expected basic integer type, found `bool` + --> $DIR/non-integer-atomic.rs:20:5 + | +LL | intrinsics::atomic_store_seqcst(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `atomic_xchg_seqcst` intrinsic: expected basic integer type, found `bool` + --> $DIR/non-integer-atomic.rs:25:5 + | +LL | intrinsics::atomic_xchg_seqcst(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `atomic_cxchg_seqcst_seqcst` intrinsic: expected basic integer type, found `bool` + --> $DIR/non-integer-atomic.rs:30:5 + | +LL | intrinsics::atomic_cxchg_seqcst_seqcst(p, v, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `atomic_load_seqcst` intrinsic: expected basic integer type, found `Foo` + --> $DIR/non-integer-atomic.rs:35:5 + | +LL | intrinsics::atomic_load_seqcst(p); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `atomic_store_seqcst` intrinsic: expected basic integer type, found `Foo` + --> $DIR/non-integer-atomic.rs:40:5 + | +LL | intrinsics::atomic_store_seqcst(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `atomic_xchg_seqcst` intrinsic: expected basic integer type, found `Foo` + --> $DIR/non-integer-atomic.rs:45:5 + | +LL | intrinsics::atomic_xchg_seqcst(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `atomic_cxchg_seqcst_seqcst` intrinsic: expected basic integer type, found `Foo` + --> $DIR/non-integer-atomic.rs:50:5 + | +LL | intrinsics::atomic_cxchg_seqcst_seqcst(p, v, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `atomic_load_seqcst` intrinsic: expected basic integer type, found `&dyn Fn()` + --> $DIR/non-integer-atomic.rs:55:5 + | +LL | intrinsics::atomic_load_seqcst(p); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `atomic_store_seqcst` intrinsic: expected basic integer type, found `&dyn Fn()` + --> $DIR/non-integer-atomic.rs:60:5 + | +LL | intrinsics::atomic_store_seqcst(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `atomic_xchg_seqcst` intrinsic: expected basic integer type, found `&dyn Fn()` + --> $DIR/non-integer-atomic.rs:65:5 + | +LL | intrinsics::atomic_xchg_seqcst(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `atomic_cxchg_seqcst_seqcst` intrinsic: expected basic integer type, found `&dyn Fn()` + --> $DIR/non-integer-atomic.rs:70:5 + | +LL | intrinsics::atomic_cxchg_seqcst_seqcst(p, v, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `atomic_load_seqcst` intrinsic: expected basic integer type, found `[u8; 100]` + --> $DIR/non-integer-atomic.rs:75:5 + | +LL | intrinsics::atomic_load_seqcst(p); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `atomic_store_seqcst` intrinsic: expected basic integer type, found `[u8; 100]` + --> $DIR/non-integer-atomic.rs:80:5 + | +LL | intrinsics::atomic_store_seqcst(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `atomic_xchg_seqcst` intrinsic: expected basic integer type, found `[u8; 100]` + --> $DIR/non-integer-atomic.rs:85:5 + | +LL | intrinsics::atomic_xchg_seqcst(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `atomic_cxchg_seqcst_seqcst` intrinsic: expected basic integer type, found `[u8; 100]` + --> $DIR/non-integer-atomic.rs:90:5 + | +LL | intrinsics::atomic_cxchg_seqcst_seqcst(p, v, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 16 previous errors + +For more information about this error, try `rustc --explain E0511`. diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs new file mode 100644 index 000000000..255151a96 --- /dev/null +++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -0,0 +1,292 @@ +// run-pass +// needs-unwind +// ignore-wasm32-bare compiled with panic=abort by default +// revisions: mir thir strict +// [thir]compile-flags: -Zthir-unsafeck +// [strict]compile-flags: -Zstrict-init-checks +// ignore-tidy-linelength + +// This test checks panic emitted from `mem::{uninitialized,zeroed}`. + +#![feature(never_type, arbitrary_enum_discriminant)] +#![allow(deprecated, invalid_value)] + +use std::{ + mem::{self, MaybeUninit, ManuallyDrop}, + panic, + ptr::NonNull, + num, +}; + +#[allow(dead_code)] +struct Foo { + x: u8, + y: !, +} + +enum Bar {} + +#[allow(dead_code)] +enum OneVariant { Variant(i32) } + +#[allow(dead_code, non_camel_case_types)] +enum OneVariant_NonZero { + Variant(i32, i32, num::NonZeroI32), + DeadVariant(Bar), +} + +// An `Aggregate` abi enum where 0 is not a valid discriminant. +#[allow(dead_code)] +#[repr(i32)] +enum NoNullVariant { + Variant1(i32, i32) = 1, + Variant2(i32, i32) = 2, +} + +// An enum with ScalarPair layout +#[allow(dead_code)] +enum LR { + Left(i64), + Right(i64), +} +#[allow(dead_code, non_camel_case_types)] +enum LR_NonZero { + Left(num::NonZeroI64), + Right(num::NonZeroI64), +} + +struct ZeroSized; + +#[allow(dead_code)] +#[repr(i32)] +enum ZeroIsValid { + Zero(u8) = 0, + One(NonNull<()>) = 1, +} + +fn test_panic_msg<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) { + let err = panic::catch_unwind(op).err(); + assert_eq!( + err.as_ref().and_then(|a| a.downcast_ref::<&str>()), + Some(&msg) + ); +} + +fn main() { + unsafe { + // Uninhabited types + test_panic_msg( + || mem::uninitialized::<!>(), + "attempted to instantiate uninhabited type `!`" + ); + test_panic_msg( + || mem::zeroed::<!>(), + "attempted to instantiate uninhabited type `!`" + ); + test_panic_msg( + || MaybeUninit::<!>::uninit().assume_init(), + "attempted to instantiate uninhabited type `!`" + ); + + test_panic_msg( + || mem::uninitialized::<Foo>(), + "attempted to instantiate uninhabited type `Foo`" + ); + test_panic_msg( + || mem::zeroed::<Foo>(), + "attempted to instantiate uninhabited type `Foo`" + ); + test_panic_msg( + || MaybeUninit::<Foo>::uninit().assume_init(), + "attempted to instantiate uninhabited type `Foo`" + ); + + test_panic_msg( + || mem::uninitialized::<Bar>(), + "attempted to instantiate uninhabited type `Bar`" + ); + test_panic_msg( + || mem::zeroed::<Bar>(), + "attempted to instantiate uninhabited type `Bar`" + ); + test_panic_msg( + || MaybeUninit::<Bar>::uninit().assume_init(), + "attempted to instantiate uninhabited type `Bar`" + ); + + test_panic_msg( + || mem::uninitialized::<[Foo; 2]>(), + "attempted to instantiate uninhabited type `[Foo; 2]`" + ); + test_panic_msg( + || mem::zeroed::<[Foo; 2]>(), + "attempted to instantiate uninhabited type `[Foo; 2]`" + ); + test_panic_msg( + || MaybeUninit::<[Foo; 2]>::uninit().assume_init(), + "attempted to instantiate uninhabited type `[Foo; 2]`" + ); + + test_panic_msg( + || mem::uninitialized::<[Bar; 2]>(), + "attempted to instantiate uninhabited type `[Bar; 2]`" + ); + test_panic_msg( + || mem::zeroed::<[Bar; 2]>(), + "attempted to instantiate uninhabited type `[Bar; 2]`" + ); + test_panic_msg( + || MaybeUninit::<[Bar; 2]>::uninit().assume_init(), + "attempted to instantiate uninhabited type `[Bar; 2]`" + ); + + // Types that do not like zero-initialziation + test_panic_msg( + || mem::uninitialized::<fn()>(), + "attempted to leave type `fn()` uninitialized, which is invalid" + ); + test_panic_msg( + || mem::zeroed::<fn()>(), + "attempted to zero-initialize type `fn()`, which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<*const dyn Send>(), + "attempted to leave type `*const dyn core::marker::Send` uninitialized, which is invalid" + ); + test_panic_msg( + || mem::zeroed::<*const dyn Send>(), + "attempted to zero-initialize type `*const dyn core::marker::Send`, which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<(NonNull<u32>, u32, u32)>(), + "attempted to leave type `(core::ptr::non_null::NonNull<u32>, u32, u32)` uninitialized, \ + which is invalid" + ); + + test_panic_msg( + || mem::zeroed::<(NonNull<u32>, u32, u32)>(), + "attempted to zero-initialize type `(core::ptr::non_null::NonNull<u32>, u32, u32)`, \ + which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<OneVariant_NonZero>(), + "attempted to leave type `OneVariant_NonZero` uninitialized, \ + which is invalid" + ); + test_panic_msg( + || mem::zeroed::<OneVariant_NonZero>(), + "attempted to zero-initialize type `OneVariant_NonZero`, \ + which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<LR_NonZero>(), + "attempted to leave type `LR_NonZero` uninitialized, which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<ManuallyDrop<LR_NonZero>>(), + "attempted to leave type `core::mem::manually_drop::ManuallyDrop<LR_NonZero>` uninitialized, \ + which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<NoNullVariant>(), + "attempted to leave type `NoNullVariant` uninitialized, \ + which is invalid" + ); + + test_panic_msg( + || mem::zeroed::<NoNullVariant>(), + "attempted to zero-initialize type `NoNullVariant`, \ + which is invalid" + ); + + // Types that can be zero, but not uninit. + test_panic_msg( + || mem::uninitialized::<bool>(), + "attempted to leave type `bool` uninitialized, which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<LR>(), + "attempted to leave type `LR` uninitialized, which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<ManuallyDrop<LR>>(), + "attempted to leave type `core::mem::manually_drop::ManuallyDrop<LR>` uninitialized, which is invalid" + ); + + // Some things that should work. + let _val = mem::zeroed::<bool>(); + let _val = mem::zeroed::<LR>(); + let _val = mem::zeroed::<ManuallyDrop<LR>>(); + let _val = mem::zeroed::<OneVariant>(); + let _val = mem::zeroed::<Option<&'static i32>>(); + let _val = mem::zeroed::<MaybeUninit<NonNull<u32>>>(); + let _val = mem::zeroed::<[!; 0]>(); + let _val = mem::zeroed::<ZeroIsValid>(); + let _val = mem::uninitialized::<MaybeUninit<bool>>(); + let _val = mem::uninitialized::<[!; 0]>(); + let _val = mem::uninitialized::<()>(); + let _val = mem::uninitialized::<ZeroSized>(); + + if cfg!(strict) { + test_panic_msg( + || mem::uninitialized::<i32>(), + "attempted to leave type `i32` uninitialized, which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<*const ()>(), + "attempted to leave type `*const ()` uninitialized, which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<[i32; 1]>(), + "attempted to leave type `[i32; 1]` uninitialized, which is invalid" + ); + + test_panic_msg( + || mem::zeroed::<NonNull<()>>(), + "attempted to zero-initialize type `core::ptr::non_null::NonNull<()>`, which is invalid" + ); + + test_panic_msg( + || mem::zeroed::<[NonNull<()>; 1]>(), + "attempted to zero-initialize type `[core::ptr::non_null::NonNull<()>; 1]`, which is invalid" + ); + + // FIXME(#66151) we conservatively do not error here yet (by default). + test_panic_msg( + || mem::zeroed::<LR_NonZero>(), + "attempted to zero-initialize type `LR_NonZero`, which is invalid" + ); + + test_panic_msg( + || mem::zeroed::<ManuallyDrop<LR_NonZero>>(), + "attempted to zero-initialize type `core::mem::manually_drop::ManuallyDrop<LR_NonZero>`, \ + which is invalid" + ); + } else { + // These are UB because they have not been officially blessed, but we await the resolution + // of <https://github.com/rust-lang/unsafe-code-guidelines/issues/71> before doing + // anything about that. + let _val = mem::uninitialized::<i32>(); + let _val = mem::uninitialized::<*const ()>(); + + // These are UB, but best to test them to ensure we don't become unintentionally + // stricter. + + // It's currently unchecked to create invalid enums and values inside arrays. + let _val = mem::zeroed::<LR_NonZero>(); + let _val = mem::zeroed::<[LR_NonZero; 1]>(); + let _val = mem::zeroed::<[NonNull<()>; 1]>(); + let _val = mem::uninitialized::<[NonNull<()>; 1]>(); + } + } +} diff --git a/src/test/ui/intrinsics/unchecked_math_unsafe.mir.stderr b/src/test/ui/intrinsics/unchecked_math_unsafe.mir.stderr new file mode 100644 index 000000000..26b2f9f27 --- /dev/null +++ b/src/test/ui/intrinsics/unchecked_math_unsafe.mir.stderr @@ -0,0 +1,27 @@ +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/unchecked_math_unsafe.rs:8:15 + | +LL | let add = std::intrinsics::unchecked_add(x, y); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/unchecked_math_unsafe.rs:9:15 + | +LL | let sub = std::intrinsics::unchecked_sub(x, y); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/unchecked_math_unsafe.rs:10:15 + | +LL | let mul = std::intrinsics::unchecked_mul(x, y); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/intrinsics/unchecked_math_unsafe.rs b/src/test/ui/intrinsics/unchecked_math_unsafe.rs new file mode 100644 index 000000000..98d3a11ad --- /dev/null +++ b/src/test/ui/intrinsics/unchecked_math_unsafe.rs @@ -0,0 +1,11 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + +#![feature(core_intrinsics)] + +fn main() { + let (x, y) = (1u32, 2u32); + let add = std::intrinsics::unchecked_add(x, y); //~ ERROR call to unsafe function + let sub = std::intrinsics::unchecked_sub(x, y); //~ ERROR call to unsafe function + let mul = std::intrinsics::unchecked_mul(x, y); //~ ERROR call to unsafe function +} diff --git a/src/test/ui/intrinsics/unchecked_math_unsafe.thir.stderr b/src/test/ui/intrinsics/unchecked_math_unsafe.thir.stderr new file mode 100644 index 000000000..5c3728ccd --- /dev/null +++ b/src/test/ui/intrinsics/unchecked_math_unsafe.thir.stderr @@ -0,0 +1,27 @@ +error[E0133]: call to unsafe function `unchecked_add` is unsafe and requires unsafe function or block + --> $DIR/unchecked_math_unsafe.rs:8:15 + | +LL | let add = std::intrinsics::unchecked_add(x, y); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: call to unsafe function `unchecked_sub` is unsafe and requires unsafe function or block + --> $DIR/unchecked_math_unsafe.rs:9:15 + | +LL | let sub = std::intrinsics::unchecked_sub(x, y); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: call to unsafe function `unchecked_mul` is unsafe and requires unsafe function or block + --> $DIR/unchecked_math_unsafe.rs:10:15 + | +LL | let mul = std::intrinsics::unchecked_mul(x, y); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/intrinsics/unchecked_math_unstable.rs b/src/test/ui/intrinsics/unchecked_math_unstable.rs new file mode 100644 index 000000000..8869063d1 --- /dev/null +++ b/src/test/ui/intrinsics/unchecked_math_unstable.rs @@ -0,0 +1,8 @@ +fn main() { + let (x, y) = (1u32, 2u32); + unsafe { + let add = std::intrinsics::unchecked_add(x, y); //~ ERROR use of unstable library feature + let sub = std::intrinsics::unchecked_sub(x, y); //~ ERROR use of unstable library feature + let mul = std::intrinsics::unchecked_mul(x, y); //~ ERROR use of unstable library feature + } +} diff --git a/src/test/ui/intrinsics/unchecked_math_unstable.stderr b/src/test/ui/intrinsics/unchecked_math_unstable.stderr new file mode 100644 index 000000000..a43aa16ae --- /dev/null +++ b/src/test/ui/intrinsics/unchecked_math_unstable.stderr @@ -0,0 +1,27 @@ +error[E0658]: use of unstable library feature 'core_intrinsics': intrinsics are unlikely to ever be stabilized, instead they should be used through stabilized interfaces in the rest of the standard library + --> $DIR/unchecked_math_unstable.rs:4:19 + | +LL | let add = std::intrinsics::unchecked_add(x, y); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(core_intrinsics)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'core_intrinsics': intrinsics are unlikely to ever be stabilized, instead they should be used through stabilized interfaces in the rest of the standard library + --> $DIR/unchecked_math_unstable.rs:5:19 + | +LL | let sub = std::intrinsics::unchecked_sub(x, y); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(core_intrinsics)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'core_intrinsics': intrinsics are unlikely to ever be stabilized, instead they should be used through stabilized interfaces in the rest of the standard library + --> $DIR/unchecked_math_unstable.rs:6:19 + | +LL | let mul = std::intrinsics::unchecked_mul(x, y); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(core_intrinsics)]` to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. |