diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:13 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:13 +0000 |
commit | 218caa410aa38c29984be31a5229b9fa717560ee (patch) | |
tree | c54bd55eeb6e4c508940a30e94c0032fbd45d677 /tests/ui/consts | |
parent | Releasing progress-linux version 1.67.1+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-218caa410aa38c29984be31a5229b9fa717560ee.tar.xz rustc-218caa410aa38c29984be31a5229b9fa717560ee.zip |
Merging upstream version 1.68.2+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/ui/consts')
984 files changed, 28105 insertions, 0 deletions
diff --git a/tests/ui/consts/array-literal-index-oob.rs b/tests/ui/consts/array-literal-index-oob.rs new file mode 100644 index 000000000..67b49b1ba --- /dev/null +++ b/tests/ui/consts/array-literal-index-oob.rs @@ -0,0 +1,9 @@ +// build-pass +// ignore-pass (test emits codegen-time warnings and verifies that they are not errors) + +#![warn(unconditional_panic)] + +fn main() { + &{ [1, 2, 3][4] }; + //~^ WARN operation will panic +} diff --git a/tests/ui/consts/array-literal-index-oob.stderr b/tests/ui/consts/array-literal-index-oob.stderr new file mode 100644 index 000000000..54bf3af81 --- /dev/null +++ b/tests/ui/consts/array-literal-index-oob.stderr @@ -0,0 +1,14 @@ +warning: this operation will panic at runtime + --> $DIR/array-literal-index-oob.rs:7:8 + | +LL | &{ [1, 2, 3][4] }; + | ^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4 + | +note: the lint level is defined here + --> $DIR/array-literal-index-oob.rs:4:9 + | +LL | #![warn(unconditional_panic)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/consts/array-to-slice-cast.rs b/tests/ui/consts/array-to-slice-cast.rs new file mode 100644 index 000000000..796f9d1b7 --- /dev/null +++ b/tests/ui/consts/array-to-slice-cast.rs @@ -0,0 +1,13 @@ +// check-pass + +fn main() {} + +const fn foo() { + let x = [1, 2, 3, 4, 5]; + let y: &[_] = &x; + + struct Foo<T: ?Sized>(bool, T); + + let x: Foo<[u8; 3]> = Foo(true, [1, 2, 3]); + let y: &Foo<[u8]> = &x; +} diff --git a/tests/ui/consts/assert-type-intrinsics.rs b/tests/ui/consts/assert-type-intrinsics.rs new file mode 100644 index 000000000..b4fd423be --- /dev/null +++ b/tests/ui/consts/assert-type-intrinsics.rs @@ -0,0 +1,23 @@ +#![feature(never_type)] +#![feature(const_assert_type2)] +#![feature(core_intrinsics)] + +use std::intrinsics; + +#[allow(invalid_value)] +fn main() { + use std::mem::MaybeUninit; + + const _BAD1: () = unsafe { + MaybeUninit::<!>::uninit().assume_init(); + //~^ERROR: evaluation of constant value failed + }; + const _BAD2: () = { + intrinsics::assert_mem_uninitialized_valid::<&'static i32>(); + //~^ERROR: evaluation of constant value failed + }; + const _BAD3: () = { + intrinsics::assert_zero_valid::<&'static i32>(); + //~^ERROR: evaluation of constant value failed + }; +} diff --git a/tests/ui/consts/assert-type-intrinsics.stderr b/tests/ui/consts/assert-type-intrinsics.stderr new file mode 100644 index 000000000..70aec91e2 --- /dev/null +++ b/tests/ui/consts/assert-type-intrinsics.stderr @@ -0,0 +1,21 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/assert-type-intrinsics.rs:12:9 + | +LL | MaybeUninit::<!>::uninit().assume_init(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!` + +error[E0080]: evaluation of constant value failed + --> $DIR/assert-type-intrinsics.rs:16:9 + | +LL | intrinsics::assert_mem_uninitialized_valid::<&'static i32>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to leave type `&i32` uninitialized, which is invalid + +error[E0080]: evaluation of constant value failed + --> $DIR/assert-type-intrinsics.rs:20:9 + | +LL | intrinsics::assert_zero_valid::<&'static i32>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to zero-initialize type `&i32`, which is invalid + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/assoc-const.rs b/tests/ui/consts/assoc-const.rs new file mode 100644 index 000000000..f542f2dcb --- /dev/null +++ b/tests/ui/consts/assoc-const.rs @@ -0,0 +1,21 @@ +// run-pass +#![allow(unused_variables)] + +trait Nat { + const VALUE: usize; +} + +struct Zero; +struct Succ<N>(#[allow(unused_tuple_struct_fields)] N); + +impl Nat for Zero { + const VALUE: usize = 0; +} + +impl<N: Nat> Nat for Succ<N> { + const VALUE: usize = N::VALUE + 1; +} + +fn main() { + let x: [i32; <Succ<Succ<Succ<Succ<Zero>>>>>::VALUE] = [1, 2, 3, 4]; +} diff --git a/tests/ui/consts/assoc_const_generic_impl.rs b/tests/ui/consts/assoc_const_generic_impl.rs new file mode 100644 index 000000000..3475c862b --- /dev/null +++ b/tests/ui/consts/assoc_const_generic_impl.rs @@ -0,0 +1,19 @@ +// build-fail + +trait ZeroSized: Sized { + const I_AM_ZERO_SIZED: (); + fn requires_zero_size(self); +} + +impl<T: Sized> ZeroSized for T { + const I_AM_ZERO_SIZED: () = [()][std::mem::size_of::<Self>()]; //~ ERROR evaluation of `<u32 as ZeroSized>::I_AM_ZERO_SIZED` failed + fn requires_zero_size(self) { + let () = Self::I_AM_ZERO_SIZED; + println!("requires_zero_size called"); + } +} + +fn main() { + ().requires_zero_size(); + 42_u32.requires_zero_size(); +} diff --git a/tests/ui/consts/assoc_const_generic_impl.stderr b/tests/ui/consts/assoc_const_generic_impl.stderr new file mode 100644 index 000000000..854b9ce5b --- /dev/null +++ b/tests/ui/consts/assoc_const_generic_impl.stderr @@ -0,0 +1,15 @@ +error[E0080]: evaluation of `<u32 as ZeroSized>::I_AM_ZERO_SIZED` failed + --> $DIR/assoc_const_generic_impl.rs:9:34 + | +LL | const I_AM_ZERO_SIZED: () = [()][std::mem::size_of::<Self>()]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 4 + +note: the above error was encountered while instantiating `fn <u32 as ZeroSized>::requires_zero_size` + --> $DIR/assoc_const_generic_impl.rs:18:5 + | +LL | 42_u32.requires_zero_size(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/associated_const_generic.rs b/tests/ui/consts/associated_const_generic.rs new file mode 100644 index 000000000..dee376cc1 --- /dev/null +++ b/tests/ui/consts/associated_const_generic.rs @@ -0,0 +1,25 @@ +// check-pass + +trait TraitA { + const VALUE: usize; +} + +struct A; +impl TraitA for A { + const VALUE: usize = 1; +} + +trait TraitB { + type MyA: TraitA; + const VALUE: usize = Self::MyA::VALUE; +} + +struct B; +impl TraitB for B { + type MyA = A; +} + +fn main() { + let _ = [0; A::VALUE]; + let _ = [0; B::VALUE]; // Indirectly refers to `A::VALUE` +} diff --git a/tests/ui/consts/async-block.rs b/tests/ui/consts/async-block.rs new file mode 100644 index 000000000..78ec8aea7 --- /dev/null +++ b/tests/ui/consts/async-block.rs @@ -0,0 +1,19 @@ +// gate-test-const_async_blocks + +// edition:2018 +// revisions: with_feature without_feature + +#![feature(rustc_attrs)] +#![cfg_attr(with_feature, feature(const_async_blocks))] + +use std::future::Future; + +// From <https://github.com/rust-lang/rust/issues/77361> +const _: i32 = { core::mem::ManuallyDrop::new(async { 0 }); 4 }; +//[without_feature]~^ `async` block + +static _FUT: &(dyn Future<Output = ()> + Sync) = &async {}; +//[without_feature]~^ `async` block + +#[rustc_error] +fn main() {} //[with_feature]~ fatal error triggered by #[rustc_error] diff --git a/tests/ui/consts/async-block.with_feature.stderr b/tests/ui/consts/async-block.with_feature.stderr new file mode 100644 index 000000000..8c6364aec --- /dev/null +++ b/tests/ui/consts/async-block.with_feature.stderr @@ -0,0 +1,8 @@ +error: fatal error triggered by #[rustc_error] + --> $DIR/async-block.rs:19:1 + | +LL | fn main() {} + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/consts/async-block.without_feature.stderr b/tests/ui/consts/async-block.without_feature.stderr new file mode 100644 index 000000000..751627c52 --- /dev/null +++ b/tests/ui/consts/async-block.without_feature.stderr @@ -0,0 +1,21 @@ +error[E0658]: `async` blocks are not allowed in constants + --> $DIR/async-block.rs:12:47 + | +LL | const _: i32 = { core::mem::ManuallyDrop::new(async { 0 }); 4 }; + | ^^^^^^^^^^^ + | + = note: see issue #85368 <https://github.com/rust-lang/rust/issues/85368> for more information + = help: add `#![feature(const_async_blocks)]` to the crate attributes to enable + +error[E0658]: `async` blocks are not allowed in statics + --> $DIR/async-block.rs:15:51 + | +LL | static _FUT: &(dyn Future<Output = ()> + Sync) = &async {}; + | ^^^^^^^^ + | + = note: see issue #85368 <https://github.com/rust-lang/rust/issues/85368> for more information + = help: add `#![feature(const_async_blocks)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/auxiliary/cci_const_block.rs b/tests/ui/consts/auxiliary/cci_const_block.rs new file mode 100644 index 000000000..ad618aab8 --- /dev/null +++ b/tests/ui/consts/auxiliary/cci_const_block.rs @@ -0,0 +1,6 @@ +pub static BLOCK_FN_DEF: fn(usize) -> usize = { + fn foo(a: usize) -> usize { + a + 10 + } + foo +}; diff --git a/tests/ui/consts/auxiliary/closure-in-foreign-crate.rs b/tests/ui/consts/auxiliary/closure-in-foreign-crate.rs new file mode 100644 index 000000000..edc7fa81a --- /dev/null +++ b/tests/ui/consts/auxiliary/closure-in-foreign-crate.rs @@ -0,0 +1,8 @@ +#![crate_type = "lib"] +#![feature(const_closures, const_trait_impl)] +#![allow(incomplete_features)] + +pub const fn test() { + let cl = const || {}; + cl(); +} diff --git a/tests/ui/consts/auxiliary/const_fn_lib.rs b/tests/ui/consts/auxiliary/const_fn_lib.rs new file mode 100644 index 000000000..88cea60e1 --- /dev/null +++ b/tests/ui/consts/auxiliary/const_fn_lib.rs @@ -0,0 +1,22 @@ +// Crate that exports a const fn. Used for testing cross-crate. + +#![crate_type="rlib"] + +pub const fn foo() -> usize { 22 } + +pub const fn bar() -> fn() { + fn x() {} + x +} + +#[inline] +pub const fn bar_inlined() -> fn() { + fn x() {} + x +} + +#[inline(always)] +pub const fn bar_inlined_always() -> fn() { + fn x() {} + x +} diff --git a/tests/ui/consts/auxiliary/external_macro.rs b/tests/ui/consts/auxiliary/external_macro.rs new file mode 100644 index 000000000..d260634c9 --- /dev/null +++ b/tests/ui/consts/auxiliary/external_macro.rs @@ -0,0 +1,14 @@ +#![feature(allow_internal_unstable)] + +// Macro to help ensure CONST_ERR lint errors +// are not silenced in external macros. +// https://github.com/rust-lang/rust/issues/65300 + +#[macro_export] +#[allow_internal_unstable(type_ascription)] +macro_rules! static_assert { + ($test:expr) => { + #[allow(dead_code)] + const _: () = [()][!($test: bool) as usize]; + } +} diff --git a/tests/ui/consts/auxiliary/issue-17718-aux.rs b/tests/ui/consts/auxiliary/issue-17718-aux.rs new file mode 100644 index 000000000..91abdbff8 --- /dev/null +++ b/tests/ui/consts/auxiliary/issue-17718-aux.rs @@ -0,0 +1,10 @@ +use std::sync::atomic; + +pub const C1: usize = 1; +pub const C2: atomic::AtomicUsize = atomic::AtomicUsize::new(0); +pub const C3: fn() = { fn foo() {} foo }; +pub const C4: usize = C1 * C1 + C1 / C1; +pub const C5: &'static usize = &C4; + +pub static S1: usize = 3; +pub static S2: atomic::AtomicUsize = atomic::AtomicUsize::new(0); diff --git a/tests/ui/consts/auxiliary/issue-63226.rs b/tests/ui/consts/auxiliary/issue-63226.rs new file mode 100644 index 000000000..2dc9539ba --- /dev/null +++ b/tests/ui/consts/auxiliary/issue-63226.rs @@ -0,0 +1,14 @@ +pub struct VTable{ + state:extern "C" fn(), +} + +impl VTable{ + pub const fn vtable()->&'static VTable{ + Self::VTABLE + } + + const VTABLE: &'static VTable = + &VTable{state}; +} + +extern "C" fn state() {} diff --git a/tests/ui/consts/auxiliary/promotable_const_fn_lib.rs b/tests/ui/consts/auxiliary/promotable_const_fn_lib.rs new file mode 100644 index 000000000..b1d5440b4 --- /dev/null +++ b/tests/ui/consts/auxiliary/promotable_const_fn_lib.rs @@ -0,0 +1,23 @@ +// Crate that exports a const fn. Used for testing cross-crate. + +#![feature(staged_api, rustc_attrs)] +#![stable(since="1.0.0", feature = "mep")] + +#![crate_type="rlib"] + +#[rustc_promotable] +#[stable(since="1.0.0", feature = "mep")] +#[rustc_const_stable(since="1.0.0", feature = "mep")] +#[inline] +pub const fn foo() -> usize { 22 } + +#[stable(since="1.0.0", feature = "mep")] +pub struct Foo(usize); + +impl Foo { + #[stable(since="1.0.0", feature = "mep")] + #[rustc_const_stable(feature = "mep", since = "1.0.0")] + #[inline] + #[rustc_promotable] + pub const fn foo() -> usize { 22 } +} diff --git a/tests/ui/consts/bswap-const.rs b/tests/ui/consts/bswap-const.rs new file mode 100644 index 000000000..3145c21ac --- /dev/null +++ b/tests/ui/consts/bswap-const.rs @@ -0,0 +1,15 @@ +// run-pass + +#![feature(core_intrinsics)] + +use std::intrinsics; + +const SWAPPED_U8: u8 = intrinsics::bswap(0x12_u8); +const SWAPPED_U16: u16 = intrinsics::bswap(0x12_34_u16); +const SWAPPED_I32: i32 = intrinsics::bswap(0x12_34_56_78_i32); + +fn main() { + assert_eq!(SWAPPED_U8, 0x12); + assert_eq!(SWAPPED_U16, 0x34_12); + assert_eq!(SWAPPED_I32, 0x78_56_34_12); +} diff --git a/tests/ui/consts/cast-discriminant-zst-enum.rs b/tests/ui/consts/cast-discriminant-zst-enum.rs new file mode 100644 index 000000000..2767f178f --- /dev/null +++ b/tests/ui/consts/cast-discriminant-zst-enum.rs @@ -0,0 +1,45 @@ +// run-pass +// Test a ZST enum whose dicriminant is ~0i128. This caused an ICE when casting to an i32. +use std::hint::black_box; + +#[derive(Copy, Clone)] +enum Nums { + NegOne = -1, +} + +const NEG_ONE_I8: i8 = Nums::NegOne as i8; +const NEG_ONE_I16: i16 = Nums::NegOne as i16; +const NEG_ONE_I32: i32 = Nums::NegOne as i32; +const NEG_ONE_I64: i64 = Nums::NegOne as i64; +const NEG_ONE_I128: i128 = Nums::NegOne as i128; + +fn test_as_arg(n: Nums) { + assert_eq!(-1i8, n as i8); + assert_eq!(-1i16, n as i16); + assert_eq!(-1i32, n as i32); + assert_eq!(-1i64, n as i64); + assert_eq!(-1i128, n as i128); +} + +fn main() { + let kind = Nums::NegOne; + assert_eq!(-1i8, kind as i8); + assert_eq!(-1i16, kind as i16); + assert_eq!(-1i32, kind as i32); + assert_eq!(-1i64, kind as i64); + assert_eq!(-1i128, kind as i128); + + assert_eq!(-1i8, black_box(kind) as i8); + assert_eq!(-1i16, black_box(kind) as i16); + assert_eq!(-1i32, black_box(kind) as i32); + assert_eq!(-1i64, black_box(kind) as i64); + assert_eq!(-1i128, black_box(kind) as i128); + + test_as_arg(Nums::NegOne); + + assert_eq!(-1i8, NEG_ONE_I8); + assert_eq!(-1i16, NEG_ONE_I16); + assert_eq!(-1i32, NEG_ONE_I32); + assert_eq!(-1i64, NEG_ONE_I64); + assert_eq!(-1i128, NEG_ONE_I128); +} diff --git a/tests/ui/consts/chained-constants-stackoverflow.rs b/tests/ui/consts/chained-constants-stackoverflow.rs new file mode 100644 index 000000000..a171567c5 --- /dev/null +++ b/tests/ui/consts/chained-constants-stackoverflow.rs @@ -0,0 +1,356 @@ +// run-pass + +// https://github.com/rust-lang/rust/issues/34997 + +pub const CST_1: u32 = 0; +pub const CST_2: u32 = CST_1+1; +pub const CST_3: u32 = CST_2+1; +pub const CST_4: u32 = CST_3+1; +pub const CST_5: u32 = CST_4+1; +pub const CST_6: u32 = CST_5+1; +pub const CST_7: u32 = CST_6+1; +pub const CST_8: u32 = CST_7+1; +pub const CST_9: u32 = CST_8+1; +pub const CST_10: u32 = CST_9+1; +pub const CST_11: u32 = CST_10+1; +pub const CST_12: u32 = CST_11+1; +pub const CST_13: u32 = CST_12+1; +pub const CST_14: u32 = CST_13+1; +pub const CST_15: u32 = CST_14+1; +pub const CST_16: u32 = CST_15+1; +pub const CST_17: u32 = CST_16+1; +pub const CST_18: u32 = CST_17+1; +pub const CST_19: u32 = CST_18+1; +pub const CST_20: u32 = CST_19+1; +pub const CST_21: u32 = CST_20+1; +pub const CST_22: u32 = CST_21+1; +pub const CST_23: u32 = CST_22+1; +pub const CST_24: u32 = CST_23+1; +pub const CST_25: u32 = CST_24+1; +pub const CST_26: u32 = CST_25+1; +pub const CST_27: u32 = CST_26+1; +pub const CST_28: u32 = CST_27+1; +pub const CST_29: u32 = CST_28+1; +pub const CST_30: u32 = CST_29+1; +pub const CST_31: u32 = CST_30+1; +pub const CST_32: u32 = CST_31+1; +pub const CST_33: u32 = CST_32+1; +pub const CST_34: u32 = CST_33+1; +pub const CST_35: u32 = CST_34+1; +pub const CST_36: u32 = CST_35+1; +pub const CST_37: u32 = CST_36+1; +pub const CST_38: u32 = CST_37+1; +pub const CST_39: u32 = CST_38+1; +pub const CST_40: u32 = CST_39+1; +pub const CST_41: u32 = CST_40+1; +pub const CST_42: u32 = CST_41+1; +pub const CST_43: u32 = CST_42+1; +pub const CST_44: u32 = CST_43+1; +pub const CST_45: u32 = CST_44+1; +pub const CST_46: u32 = CST_45+1; +pub const CST_47: u32 = CST_46+1; +pub const CST_48: u32 = CST_47+1; +pub const CST_49: u32 = CST_48+1; +pub const CST_50: u32 = CST_49+1; +pub const CST_51: u32 = CST_50+1; +pub const CST_52: u32 = CST_51+1; +pub const CST_53: u32 = CST_52+1; +pub const CST_54: u32 = CST_53+1; +pub const CST_55: u32 = CST_54+1; +pub const CST_56: u32 = CST_55+1; +pub const CST_57: u32 = CST_56+1; +pub const CST_58: u32 = CST_57+1; +pub const CST_59: u32 = CST_58+1; +pub const CST_60: u32 = CST_59+1; +pub const CST_61: u32 = CST_60+1; +pub const CST_62: u32 = CST_61+1; +pub const CST_63: u32 = CST_62+1; +pub const CST_64: u32 = CST_63+1; +pub const CST_65: u32 = CST_64+1; +pub const CST_66: u32 = CST_65+1; +pub const CST_67: u32 = CST_66+1; +pub const CST_68: u32 = CST_67+1; +pub const CST_69: u32 = CST_68+1; +pub const CST_70: u32 = CST_69+1; +pub const CST_71: u32 = CST_70+1; +pub const CST_72: u32 = CST_71+1; +pub const CST_73: u32 = CST_72+1; +pub const CST_74: u32 = CST_73+1; +pub const CST_75: u32 = CST_74+1; +pub const CST_76: u32 = CST_75+1; +pub const CST_77: u32 = CST_76+1; +pub const CST_78: u32 = CST_77+1; +pub const CST_79: u32 = CST_78+1; +pub const CST_80: u32 = CST_79+1; +pub const CST_81: u32 = CST_80+1; +pub const CST_82: u32 = CST_81+1; +pub const CST_83: u32 = CST_82+1; +pub const CST_84: u32 = CST_83+1; +pub const CST_85: u32 = CST_84+1; +pub const CST_86: u32 = CST_85+1; +pub const CST_87: u32 = CST_86+1; +pub const CST_88: u32 = CST_87+1; +pub const CST_89: u32 = CST_88+1; +pub const CST_90: u32 = CST_89+1; +pub const CST_91: u32 = CST_90+1; +pub const CST_92: u32 = CST_91+1; +pub const CST_93: u32 = CST_92+1; +pub const CST_94: u32 = CST_93+1; +pub const CST_95: u32 = CST_94+1; +pub const CST_96: u32 = CST_95+1; +pub const CST_97: u32 = CST_96+1; +pub const CST_98: u32 = CST_97+1; +pub const CST_99: u32 = CST_98+1; +pub const CST_100: u32 = CST_99+1; +pub const CST_101: u32 = CST_100+1; +pub const CST_102: u32 = CST_101+1; +pub const CST_103: u32 = CST_102+1; +pub const CST_104: u32 = CST_103+1; +pub const CST_105: u32 = CST_104+1; +pub const CST_106: u32 = CST_105+1; +pub const CST_107: u32 = CST_106+1; +pub const CST_108: u32 = CST_107+1; +pub const CST_109: u32 = CST_108+1; +pub const CST_110: u32 = CST_109+1; +pub const CST_111: u32 = CST_110+1; +pub const CST_112: u32 = CST_111+1; +pub const CST_113: u32 = CST_112+1; +pub const CST_114: u32 = CST_113+1; +pub const CST_115: u32 = CST_114+1; +pub const CST_116: u32 = CST_115+1; +pub const CST_117: u32 = CST_116+1; +pub const CST_118: u32 = CST_117+1; +pub const CST_119: u32 = CST_118+1; +pub const CST_120: u32 = CST_119+1; +pub const CST_121: u32 = CST_120+1; +pub const CST_122: u32 = CST_121+1; +pub const CST_123: u32 = CST_122+1; +pub const CST_124: u32 = CST_123+1; +pub const CST_125: u32 = CST_124+1; +pub const CST_126: u32 = CST_125+1; +pub const CST_127: u32 = CST_126+1; +pub const CST_128: u32 = CST_127+1; +pub const CST_129: u32 = CST_128+1; +pub const CST_130: u32 = CST_129+1; +pub const CST_131: u32 = CST_130+1; +pub const CST_132: u32 = CST_131+1; +pub const CST_133: u32 = CST_132+1; +pub const CST_134: u32 = CST_133+1; +pub const CST_135: u32 = CST_134+1; +pub const CST_136: u32 = CST_135+1; +pub const CST_137: u32 = CST_136+1; +pub const CST_138: u32 = CST_137+1; +pub const CST_139: u32 = CST_138+1; +pub const CST_140: u32 = CST_139+1; +pub const CST_141: u32 = CST_140+1; +pub const CST_142: u32 = CST_141+1; +pub const CST_143: u32 = CST_142+1; +pub const CST_144: u32 = CST_143+1; +pub const CST_145: u32 = CST_144+1; +pub const CST_146: u32 = CST_145+1; +pub const CST_147: u32 = CST_146+1; +pub const CST_148: u32 = CST_147+1; +pub const CST_149: u32 = CST_148+1; +pub const CST_150: u32 = CST_149+1; +pub const CST_151: u32 = CST_150+1; +pub const CST_152: u32 = CST_151+1; +pub const CST_153: u32 = CST_152+1; +pub const CST_154: u32 = CST_153+1; +pub const CST_155: u32 = CST_154+1; +pub const CST_156: u32 = CST_155+1; +pub const CST_157: u32 = CST_156+1; +pub const CST_158: u32 = CST_157+1; +pub const CST_159: u32 = CST_158+1; +pub const CST_160: u32 = CST_159+1; +pub const CST_161: u32 = CST_160+1; +pub const CST_162: u32 = CST_161+1; +pub const CST_163: u32 = CST_162+1; +pub const CST_164: u32 = CST_163+1; +pub const CST_165: u32 = CST_164+1; +pub const CST_166: u32 = CST_165+1; +pub const CST_167: u32 = CST_166+1; +pub const CST_168: u32 = CST_167+1; +pub const CST_169: u32 = CST_168+1; +pub const CST_170: u32 = CST_169+1; +pub const CST_171: u32 = CST_170+1; +pub const CST_172: u32 = CST_171+1; +pub const CST_173: u32 = CST_172+1; +pub const CST_174: u32 = CST_173+1; +pub const CST_175: u32 = CST_174+1; +pub const CST_176: u32 = CST_175+1; +pub const CST_177: u32 = CST_176+1; +pub const CST_178: u32 = CST_177+1; +pub const CST_179: u32 = CST_178+1; +pub const CST_180: u32 = CST_179+1; +pub const CST_181: u32 = CST_180+1; +pub const CST_182: u32 = CST_181+1; +pub const CST_183: u32 = CST_182+1; +pub const CST_184: u32 = CST_183+1; +pub const CST_185: u32 = CST_184+1; +pub const CST_186: u32 = CST_185+1; +pub const CST_187: u32 = CST_186+1; +pub const CST_188: u32 = CST_187+1; +pub const CST_189: u32 = CST_188+1; +pub const CST_190: u32 = CST_189+1; +pub const CST_191: u32 = CST_190+1; +pub const CST_192: u32 = CST_191+1; +pub const CST_193: u32 = CST_192+1; +pub const CST_194: u32 = CST_193+1; +pub const CST_195: u32 = CST_194+1; +pub const CST_196: u32 = CST_195+1; +pub const CST_197: u32 = CST_196+1; +pub const CST_198: u32 = CST_197+1; +pub const CST_199: u32 = CST_198+1; +pub const CST_200: u32 = CST_199+1; +pub const CST_201: u32 = CST_200+1; +pub const CST_202: u32 = CST_201+1; +pub const CST_203: u32 = CST_202+1; +pub const CST_204: u32 = CST_203+1; +pub const CST_205: u32 = CST_204+1; +pub const CST_206: u32 = CST_205+1; +pub const CST_207: u32 = CST_206+1; +pub const CST_208: u32 = CST_207+1; +pub const CST_209: u32 = CST_208+1; +pub const CST_210: u32 = CST_209+1; +pub const CST_211: u32 = CST_210+1; +pub const CST_212: u32 = CST_211+1; +pub const CST_213: u32 = CST_212+1; +pub const CST_214: u32 = CST_213+1; +pub const CST_215: u32 = CST_214+1; +pub const CST_216: u32 = CST_215+1; +pub const CST_217: u32 = CST_216+1; +pub const CST_218: u32 = CST_217+1; +pub const CST_219: u32 = CST_218+1; +pub const CST_220: u32 = CST_219+1; +pub const CST_221: u32 = CST_220+1; +pub const CST_222: u32 = CST_221+1; +pub const CST_223: u32 = CST_222+1; +pub const CST_224: u32 = CST_223+1; +pub const CST_225: u32 = CST_224+1; +pub const CST_226: u32 = CST_225+1; +pub const CST_227: u32 = CST_226+1; +pub const CST_228: u32 = CST_227+1; +pub const CST_229: u32 = CST_228+1; +pub const CST_230: u32 = CST_229+1; +pub const CST_231: u32 = CST_230+1; +pub const CST_232: u32 = CST_231+1; +pub const CST_233: u32 = CST_232+1; +pub const CST_234: u32 = CST_233+1; +pub const CST_235: u32 = CST_234+1; +pub const CST_236: u32 = CST_235+1; +pub const CST_237: u32 = CST_236+1; +pub const CST_238: u32 = CST_237+1; +pub const CST_239: u32 = CST_238+1; +pub const CST_240: u32 = CST_239+1; +pub const CST_241: u32 = CST_240+1; +pub const CST_242: u32 = CST_241+1; +pub const CST_243: u32 = CST_242+1; +pub const CST_244: u32 = CST_243+1; +pub const CST_245: u32 = CST_244+1; +pub const CST_246: u32 = CST_245+1; +pub const CST_247: u32 = CST_246+1; +pub const CST_248: u32 = CST_247+1; +pub const CST_249: u32 = CST_248+1; +pub const CST_250: u32 = CST_249+1; +pub const CST_251: u32 = CST_250+1; +pub const CST_252: u32 = CST_251+1; +pub const CST_253: u32 = CST_252+1; +pub const CST_254: u32 = CST_253+1; +pub const CST_255: u32 = CST_254+1; +pub const CST_256: u32 = CST_255+1; +pub const CST_257: u32 = CST_256+1; +pub const CST_258: u32 = CST_257+1; +pub const CST_259: u32 = CST_258+1; +pub const CST_260: u32 = CST_259+1; +pub const CST_261: u32 = CST_260+1; +pub const CST_262: u32 = CST_261+1; +pub const CST_263: u32 = CST_262+1; +pub const CST_264: u32 = CST_263+1; +pub const CST_265: u32 = CST_264+1; +pub const CST_266: u32 = CST_265+1; +pub const CST_267: u32 = CST_266+1; +pub const CST_268: u32 = CST_267+1; +pub const CST_269: u32 = CST_268+1; +pub const CST_270: u32 = CST_269+1; +pub const CST_271: u32 = CST_270+1; +pub const CST_272: u32 = CST_271+1; +pub const CST_273: u32 = CST_272+1; +pub const CST_274: u32 = CST_273+1; +pub const CST_275: u32 = CST_274+1; +pub const CST_276: u32 = CST_275+1; +pub const CST_277: u32 = CST_276+1; +pub const CST_278: u32 = CST_277+1; +pub const CST_279: u32 = CST_278+1; +pub const CST_280: u32 = CST_279+1; +pub const CST_281: u32 = CST_280+1; +pub const CST_282: u32 = CST_281+1; +pub const CST_283: u32 = CST_282+1; +pub const CST_284: u32 = CST_283+1; +pub const CST_285: u32 = CST_284+1; +pub const CST_286: u32 = CST_285+1; +pub const CST_287: u32 = CST_286+1; +pub const CST_288: u32 = CST_287+1; +pub const CST_289: u32 = CST_288+1; +pub const CST_290: u32 = CST_289+1; +pub const CST_291: u32 = CST_290+1; +pub const CST_292: u32 = CST_291+1; +pub const CST_293: u32 = CST_292+1; +pub const CST_294: u32 = CST_293+1; +pub const CST_295: u32 = CST_294+1; +pub const CST_296: u32 = CST_295+1; +pub const CST_297: u32 = CST_296+1; +pub const CST_298: u32 = CST_297+1; +pub const CST_299: u32 = CST_298+1; +pub const CST_300: u32 = CST_299+1; +pub const CST_301: u32 = CST_300+1; +pub const CST_302: u32 = CST_301+1; +pub const CST_303: u32 = CST_302+1; +pub const CST_304: u32 = CST_303+1; +pub const CST_305: u32 = CST_304+1; +pub const CST_306: u32 = CST_305+1; +pub const CST_307: u32 = CST_306+1; +pub const CST_308: u32 = CST_307+1; +pub const CST_309: u32 = CST_308+1; +pub const CST_310: u32 = CST_309+1; +pub const CST_311: u32 = CST_310+1; +pub const CST_312: u32 = CST_311+1; +pub const CST_313: u32 = CST_312+1; +pub const CST_314: u32 = CST_313+1; +pub const CST_315: u32 = CST_314+1; +pub const CST_316: u32 = CST_315+1; +pub const CST_317: u32 = CST_316+1; +pub const CST_318: u32 = CST_317+1; +pub const CST_319: u32 = CST_318+1; +pub const CST_320: u32 = CST_319+1; +pub const CST_321: u32 = CST_320+1; +pub const CST_322: u32 = CST_321+1; +pub const CST_323: u32 = CST_322+1; +pub const CST_324: u32 = CST_323+1; +pub const CST_325: u32 = CST_324+1; +pub const CST_326: u32 = CST_325+1; +pub const CST_327: u32 = CST_326+1; +pub const CST_328: u32 = CST_327+1; +pub const CST_329: u32 = CST_328+1; +pub const CST_330: u32 = CST_329+1; +pub const CST_331: u32 = CST_330+1; +pub const CST_332: u32 = CST_331+1; +pub const CST_333: u32 = CST_332+1; +pub const CST_334: u32 = CST_333+1; +pub const CST_335: u32 = CST_334+1; +pub const CST_336: u32 = CST_335+1; +pub const CST_337: u32 = CST_336+1; +pub const CST_338: u32 = CST_337+1; +pub const CST_339: u32 = CST_338+1; +pub const CST_340: u32 = CST_339+1; +pub const CST_341: u32 = CST_340+1; +pub const CST_342: u32 = CST_341+1; +pub const CST_343: u32 = CST_342+1; +pub const CST_344: u32 = CST_343+1; +pub const CST_345: u32 = CST_344+1; +pub const CST_346: u32 = CST_345+1; +pub const CST_347: u32 = CST_346+1; +pub const CST_348: u32 = CST_347+1; +pub const CST_349: u32 = CST_348+1; +pub const CST_350: u32 = CST_349+1; + +fn main() {} diff --git a/tests/ui/consts/check_const-feature-gated.rs b/tests/ui/consts/check_const-feature-gated.rs new file mode 100644 index 000000000..f4faab1ab --- /dev/null +++ b/tests/ui/consts/check_const-feature-gated.rs @@ -0,0 +1,7 @@ +// run-pass + +const ARR: [usize; 1] = [2]; + +fn main() { + let _ = 5 << ARR[0]; +} diff --git a/tests/ui/consts/closure-in-foreign-crate.rs b/tests/ui/consts/closure-in-foreign-crate.rs new file mode 100644 index 000000000..fc8f480e7 --- /dev/null +++ b/tests/ui/consts/closure-in-foreign-crate.rs @@ -0,0 +1,8 @@ +// aux-build:closure-in-foreign-crate.rs +// build-pass + +extern crate closure_in_foreign_crate; + +const _: () = closure_in_foreign_crate::test(); + +fn main() {} diff --git a/tests/ui/consts/closure-structural-match-issue-90013.rs b/tests/ui/consts/closure-structural-match-issue-90013.rs new file mode 100644 index 000000000..1952ddb94 --- /dev/null +++ b/tests/ui/consts/closure-structural-match-issue-90013.rs @@ -0,0 +1,7 @@ +// Regression test for issue 90013. +// check-pass +#![feature(inline_const)] + +fn main() { + const { || {} }; +} diff --git a/tests/ui/consts/const-address-of-interior-mut.rs b/tests/ui/consts/const-address-of-interior-mut.rs new file mode 100644 index 000000000..60c7c31da --- /dev/null +++ b/tests/ui/consts/const-address-of-interior-mut.rs @@ -0,0 +1,16 @@ +#![feature(raw_ref_op)] + +use std::cell::Cell; + +const A: () = { let x = Cell::new(2); &raw const x; }; //~ ERROR interior mutability + +static B: () = { let x = Cell::new(2); &raw const x; }; //~ ERROR interior mutability + +static mut C: () = { let x = Cell::new(2); &raw const x; }; //~ ERROR interior mutability + +const fn foo() { + let x = Cell::new(0); + let y = &raw const x; //~ ERROR interior mutability +} + +fn main() {} diff --git a/tests/ui/consts/const-address-of-interior-mut.stderr b/tests/ui/consts/const-address-of-interior-mut.stderr new file mode 100644 index 000000000..93120753b --- /dev/null +++ b/tests/ui/consts/const-address-of-interior-mut.stderr @@ -0,0 +1,39 @@ +error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability + --> $DIR/const-address-of-interior-mut.rs:5:39 + | +LL | const A: () = { let x = Cell::new(2); &raw const x; }; + | ^^^^^^^^^^^^ + | + = note: see issue #80384 <https://github.com/rust-lang/rust/issues/80384> for more information + = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable + +error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability + --> $DIR/const-address-of-interior-mut.rs:7:40 + | +LL | static B: () = { let x = Cell::new(2); &raw const x; }; + | ^^^^^^^^^^^^ + | + = note: see issue #80384 <https://github.com/rust-lang/rust/issues/80384> for more information + = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable + +error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability + --> $DIR/const-address-of-interior-mut.rs:9:44 + | +LL | static mut C: () = { let x = Cell::new(2); &raw const x; }; + | ^^^^^^^^^^^^ + | + = note: see issue #80384 <https://github.com/rust-lang/rust/issues/80384> for more information + = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable + +error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability + --> $DIR/const-address-of-interior-mut.rs:13:13 + | +LL | let y = &raw const x; + | ^^^^^^^^^^^^ + | + = note: see issue #80384 <https://github.com/rust-lang/rust/issues/80384> for more information + = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/const-address-of-mut.rs b/tests/ui/consts/const-address-of-mut.rs new file mode 100644 index 000000000..3788088b8 --- /dev/null +++ b/tests/ui/consts/const-address-of-mut.rs @@ -0,0 +1,14 @@ +#![feature(raw_ref_op)] + +const A: () = { let mut x = 2; &raw mut x; }; //~ mutable reference + +static B: () = { let mut x = 2; &raw mut x; }; //~ mutable reference + +static mut C: () = { let mut x = 2; &raw mut x; }; //~ mutable reference + +const fn foo() { + let mut x = 0; + let y = &raw mut x; //~ mutable reference +} + +fn main() {} diff --git a/tests/ui/consts/const-address-of-mut.stderr b/tests/ui/consts/const-address-of-mut.stderr new file mode 100644 index 000000000..60cdcc7df --- /dev/null +++ b/tests/ui/consts/const-address-of-mut.stderr @@ -0,0 +1,39 @@ +error[E0658]: raw mutable references are not allowed in constants + --> $DIR/const-address-of-mut.rs:3:32 + | +LL | const A: () = { let mut x = 2; &raw mut x; }; + | ^^^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: raw mutable references are not allowed in statics + --> $DIR/const-address-of-mut.rs:5:33 + | +LL | static B: () = { let mut x = 2; &raw mut x; }; + | ^^^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: raw mutable references are not allowed in statics + --> $DIR/const-address-of-mut.rs:7:37 + | +LL | static mut C: () = { let mut x = 2; &raw mut x; }; + | ^^^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: raw mutable references are not allowed in constant functions + --> $DIR/const-address-of-mut.rs:11:13 + | +LL | let y = &raw mut x; + | ^^^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/const-address-of.rs b/tests/ui/consts/const-address-of.rs new file mode 100644 index 000000000..ba162f2a2 --- /dev/null +++ b/tests/ui/consts/const-address-of.rs @@ -0,0 +1,19 @@ +// check-pass + +#![feature(raw_ref_op)] + +const A: *const i32 = &raw const *&2; +static B: () = { &raw const *&2; }; +static mut C: *const i32 = &raw const *&2; +const D: () = { let x = 2; &raw const x; }; +static E: () = { let x = 2; &raw const x; }; +static mut F: () = { let x = 2; &raw const x; }; + +const fn const_ptr() { + let x = 0; + let ptr = &raw const x; + let r = &x; + let ptr2 = &raw const *r; +} + +fn main() {} diff --git a/tests/ui/consts/const-adt-align-mismatch.rs b/tests/ui/consts/const-adt-align-mismatch.rs new file mode 100644 index 000000000..bd51bc9f2 --- /dev/null +++ b/tests/ui/consts/const-adt-align-mismatch.rs @@ -0,0 +1,22 @@ +// run-pass +#![allow(dead_code)] +#![allow(deprecated)] + +use std::mem; + +#[derive(PartialEq, Debug)] +enum Foo { + A(u32), + Bar([u16; 4]), + C +} + +// NOTE(eddyb) Don't make this a const, needs to be a static +// so it is always instantiated as a LLVM constant value. +static FOO: Foo = Foo::C; + +fn main() { + assert_eq!(FOO, Foo::C); + assert_eq!(mem::size_of::<Foo>(), 12); + assert_eq!(mem::min_align_of::<Foo>(), 4); +} diff --git a/tests/ui/consts/const-array-oob-arith.rs b/tests/ui/consts/const-array-oob-arith.rs new file mode 100644 index 000000000..9332cbbd4 --- /dev/null +++ b/tests/ui/consts/const-array-oob-arith.rs @@ -0,0 +1,14 @@ +const ARR: [i32; 6] = [42, 43, 44, 45, 46, 47]; +const IDX: usize = 3; +const VAL: i32 = ARR[IDX]; +const BONG: [i32; (ARR[0] - 41) as usize] = [5]; +const BLUB: [i32; (ARR[0] - 40) as usize] = [5]; +//~^ ERROR: mismatched types +//~| expected an array with a fixed size of 2 elements, found one with 1 element +const BOO: [i32; (ARR[0] - 41) as usize] = [5, 99]; +//~^ ERROR: mismatched types +//~| expected an array with a fixed size of 1 element, found one with 2 elements + +fn main() { + let _ = VAL; +} diff --git a/tests/ui/consts/const-array-oob-arith.stderr b/tests/ui/consts/const-array-oob-arith.stderr new file mode 100644 index 000000000..f7a55d3ca --- /dev/null +++ b/tests/ui/consts/const-array-oob-arith.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/const-array-oob-arith.rs:5:45 + | +LL | const BLUB: [i32; (ARR[0] - 40) as usize] = [5]; + | ^^^ expected an array with a fixed size of 2 elements, found one with 1 element + +error[E0308]: mismatched types + --> $DIR/const-array-oob-arith.rs:8:44 + | +LL | const BOO: [i32; (ARR[0] - 41) as usize] = [5, 99]; + | ^^^^^^^ expected an array with a fixed size of 1 element, found one with 2 elements + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/const-array-oob.rs b/tests/ui/consts/const-array-oob.rs new file mode 100644 index 000000000..c747ab50c --- /dev/null +++ b/tests/ui/consts/const-array-oob.rs @@ -0,0 +1,10 @@ +const FOO: [usize; 3] = [1, 2, 3]; +const BAR: usize = FOO[5]; // no error, because the error below occurs before regular const eval + +const BLUB: [u32; FOO[4]] = [5, 6]; +//~^ ERROR evaluation of constant value failed [E0080] +//~| index out of bounds: the length is 3 but the index is 4 + +fn main() { + let _ = BAR; +} diff --git a/tests/ui/consts/const-array-oob.stderr b/tests/ui/consts/const-array-oob.stderr new file mode 100644 index 000000000..f1c5f58af --- /dev/null +++ b/tests/ui/consts/const-array-oob.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-array-oob.rs:4:19 + | +LL | const BLUB: [u32; FOO[4]] = [5, 6]; + | ^^^^^^ index out of bounds: the length is 3 but the index is 4 + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-as-fn.rs b/tests/ui/consts/const-as-fn.rs new file mode 100644 index 000000000..388f907f8 --- /dev/null +++ b/tests/ui/consts/const-as-fn.rs @@ -0,0 +1,5 @@ +const FOO: usize = 0; + +fn main() { + FOO(); //~ ERROR expected function, found `usize` +} diff --git a/tests/ui/consts/const-as-fn.stderr b/tests/ui/consts/const-as-fn.stderr new file mode 100644 index 000000000..6c51ed893 --- /dev/null +++ b/tests/ui/consts/const-as-fn.stderr @@ -0,0 +1,14 @@ +error[E0618]: expected function, found `usize` + --> $DIR/const-as-fn.rs:4:5 + | +LL | const FOO: usize = 0; + | ---------------- `FOO` defined here +... +LL | FOO(); + | ^^^-- + | | + | call expression requires function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0618`. diff --git a/tests/ui/consts/const-autoderef.rs b/tests/ui/consts/const-autoderef.rs new file mode 100644 index 000000000..1c836318d --- /dev/null +++ b/tests/ui/consts/const-autoderef.rs @@ -0,0 +1,11 @@ +// run-pass + +const A: [u8; 1] = ['h' as u8]; +const B: u8 = (&A)[0]; +const C: &'static &'static &'static &'static [u8; 1] = & & & &A; +const D: u8 = (&C)[0]; + +pub fn main() { + assert_eq!(B, A[0]); + assert_eq!(D, A[0]); +} diff --git a/tests/ui/consts/const-big-enum.rs b/tests/ui/consts/const-big-enum.rs new file mode 100644 index 000000000..2f21e8a6d --- /dev/null +++ b/tests/ui/consts/const-big-enum.rs @@ -0,0 +1,30 @@ +// run-pass + +enum Foo { + Bar(u32), + Baz, + Quux(u64, u16) +} + +static X: Foo = Foo::Baz; + +pub fn main() { + match X { + Foo::Baz => {} + _ => panic!() + } + match Y { + Foo::Bar(s) => assert_eq!(s, 2654435769), + _ => panic!() + } + match Z { + Foo::Quux(d,h) => { + assert_eq!(d, 0x123456789abcdef0); + assert_eq!(h, 0x1234); + } + _ => panic!() + } +} + +static Y: Foo = Foo::Bar(2654435769); +static Z: Foo = Foo::Quux(0x123456789abcdef0, 0x1234); diff --git a/tests/ui/consts/const-binops.rs b/tests/ui/consts/const-binops.rs new file mode 100644 index 000000000..d038dfeb4 --- /dev/null +++ b/tests/ui/consts/const-binops.rs @@ -0,0 +1,126 @@ +// run-pass + +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); + }) +} + +static A: isize = -4 + 3; +static A2: usize = 3 + 3; +static B: f64 = 3.0 + 2.7; + +static C: isize = 3 - 4; +static D: usize = 3 - 3; +static E: f64 = 3.0 - 2.7; + +static E2: isize = -3 * 3; +static F: usize = 3 * 3; +static G: f64 = 3.3 * 3.3; + +static H: isize = 3 / -1; +static I: usize = 3 / 3; +static J: f64 = 3.3 / 3.3; + +static N: bool = true && false; + +static O: bool = true || false; + +static P: isize = 3 & 1; +static Q: usize = 1 & 3; + +static R: isize = 3 | 1; +static S: usize = 1 | 3; + +static T: isize = 3 ^ 1; +static U: usize = 1 ^ 3; + +static V: isize = 1 << 3; + +// NOTE: better shr coverage +static W: isize = 1024 >> 4; +static X: usize = 1024 >> 4; + +static Y: bool = 1 == 1; +static Z: bool = 1.0f64 == 1.0; + +static AA: bool = 1 <= 2; +static AB: bool = -1 <= 2; +static AC: bool = 1.0f64 <= 2.0; + +static AD: bool = 1 < 2; +static AE: bool = -1 < 2; +static AF: bool = 1.0f64 < 2.0; + +static AG: bool = 1 != 2; +static AH: bool = -1 != 2; +static AI: bool = 1.0f64 != 2.0; + +static AJ: bool = 2 >= 1; +static AK: bool = 2 >= -2; +static AL: bool = 1.0f64 >= -2.0; + +static AM: bool = 2 > 1; +static AN: bool = 2 > -2; +static AO: bool = 1.0f64 > -2.0; + +pub fn main() { + assert_eq!(A, -1); + assert_eq!(A2, 6); + assert_approx_eq!(B, 5.7); + + assert_eq!(C, -1); + assert_eq!(D, 0); + assert_approx_eq!(E, 0.3); + + assert_eq!(E2, -9); + assert_eq!(F, 9); + assert_approx_eq!(G, 10.89); + + assert_eq!(H, -3); + assert_eq!(I, 1); + assert_approx_eq!(J, 1.0); + + assert_eq!(N, false); + + assert_eq!(O, true); + + assert_eq!(P, 1); + assert_eq!(Q, 1); + + assert_eq!(R, 3); + assert_eq!(S, 3); + + assert_eq!(T, 2); + assert_eq!(U, 2); + + assert_eq!(V, 8); + + assert_eq!(W, 64); + assert_eq!(X, 64); + + assert_eq!(Y, true); + assert_eq!(Z, true); + + assert_eq!(AA, true); + assert_eq!(AB, true); + assert_eq!(AC, true); + + assert_eq!(AD, true); + assert_eq!(AE, true); + assert_eq!(AF, true); + + assert_eq!(AG, true); + assert_eq!(AH, true); + assert_eq!(AI, true); + + assert_eq!(AJ, true); + assert_eq!(AK, true); + assert_eq!(AL, true); + + assert_eq!(AM, true); + assert_eq!(AN, true); + assert_eq!(AO, true); +} diff --git a/tests/ui/consts/const-bitshift-rhs-inference.rs b/tests/ui/consts/const-bitshift-rhs-inference.rs new file mode 100644 index 000000000..cf21c296c --- /dev/null +++ b/tests/ui/consts/const-bitshift-rhs-inference.rs @@ -0,0 +1,24 @@ +// run-pass +const RHS: u8 = 8; +const IRHS: i8 = 8; +const RHS16: u16 = 8; +const IRHS16: i16 = 8; +const RHS32: u32 = 8; +const IRHS32: i32 = 8; +const RHS64: u64 = 8; +const IRHS64: i64 = 8; +const RHSUS: usize = 8; +const IRHSIS: isize = 8; + +fn main() { + let _: [&'static str; 1 << RHS] = [""; 256]; + let _: [&'static str; 1 << IRHS] = [""; 256]; + let _: [&'static str; 1 << RHS16] = [""; 256]; + let _: [&'static str; 1 << IRHS16] = [""; 256]; + let _: [&'static str; 1 << RHS32] = [""; 256]; + let _: [&'static str; 1 << IRHS32] = [""; 256]; + let _: [&'static str; 1 << RHS64] = [""; 256]; + let _: [&'static str; 1 << IRHS64] = [""; 256]; + let _: [&'static str; 1 << RHSUS] = [""; 256]; + let _: [&'static str; 1 << IRHSIS] = [""; 256]; +} diff --git a/tests/ui/consts/const-block-const-bound.rs b/tests/ui/consts/const-block-const-bound.rs new file mode 100644 index 000000000..42aa0216b --- /dev/null +++ b/tests/ui/consts/const-block-const-bound.rs @@ -0,0 +1,25 @@ +#![allow(unused)] +#![feature(const_trait_impl, inline_const, negative_impls)] + +use std::marker::Destruct; + +const fn f<T: ~const Destruct>(x: T) {} + +struct UnconstDrop; + +impl Drop for UnconstDrop { + fn drop(&mut self) {} +} + +struct NonDrop; + +impl !Drop for NonDrop {} + +fn main() { + const { + f(UnconstDrop); + //~^ ERROR can't drop + f(NonDrop); + //~^ ERROR can't drop + } +} diff --git a/tests/ui/consts/const-block-const-bound.stderr b/tests/ui/consts/const-block-const-bound.stderr new file mode 100644 index 000000000..b9c4d8866 --- /dev/null +++ b/tests/ui/consts/const-block-const-bound.stderr @@ -0,0 +1,45 @@ +error[E0277]: can't drop `UnconstDrop` in const contexts + --> $DIR/const-block-const-bound.rs:20:11 + | +LL | f(UnconstDrop); + | - ^^^^^^^^^^^ the trait `~const Destruct` is not implemented for `UnconstDrop` + | | + | required by a bound introduced by this call + | + = note: the trait bound `UnconstDrop: ~const Destruct` is not satisfied +note: required by a bound in `f` + --> $DIR/const-block-const-bound.rs:6:15 + | +LL | const fn f<T: ~const Destruct>(x: T) {} + | ^^^^^^^^^^^^^^^ required by this bound in `f` +help: consider borrowing here + | +LL | f(&UnconstDrop); + | + +LL | f(&mut UnconstDrop); + | ++++ + +error[E0277]: can't drop `NonDrop` in const contexts + --> $DIR/const-block-const-bound.rs:22:11 + | +LL | f(NonDrop); + | - ^^^^^^^ the trait `~const Destruct` is not implemented for `NonDrop` + | | + | required by a bound introduced by this call + | + = note: the trait bound `NonDrop: ~const Destruct` is not satisfied +note: required by a bound in `f` + --> $DIR/const-block-const-bound.rs:6:15 + | +LL | const fn f<T: ~const Destruct>(x: T) {} + | ^^^^^^^^^^^^^^^ required by this bound in `f` +help: consider borrowing here + | +LL | f(&NonDrop); + | + +LL | f(&mut NonDrop); + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/const-block-cross-crate-fn.rs b/tests/ui/consts/const-block-cross-crate-fn.rs new file mode 100644 index 000000000..0ac3830d2 --- /dev/null +++ b/tests/ui/consts/const-block-cross-crate-fn.rs @@ -0,0 +1,9 @@ +// run-pass +// aux-build:cci_const_block.rs + + +extern crate cci_const_block; + +pub fn main() { + assert_eq!(cci_const_block::BLOCK_FN_DEF(390), 400); +} diff --git a/tests/ui/consts/const-block-item-macro-codegen.rs b/tests/ui/consts/const-block-item-macro-codegen.rs new file mode 100644 index 000000000..7ad883686 --- /dev/null +++ b/tests/ui/consts/const-block-item-macro-codegen.rs @@ -0,0 +1,40 @@ +// run-pass +#![allow(dead_code)] +// General test that function items in static blocks +// can be generated with a macro. + + +struct MyType { + desc: &'static str, + data: usize, + code: fn(usize, usize) -> usize +} + +impl MyType { + fn eval(&self, a: usize) -> usize { + (self.code)(self.data, a) + } +} + +macro_rules! codegen { + ($e:expr, $v:expr) => { + { + fn generated(a: usize, b: usize) -> usize { + a - ($e * b) + } + MyType { + desc: "test", + data: $v, + code: generated + } + } + } +} + +static GENERATED_CODE_1: MyType = codegen!(2, 100); +static GENERATED_CODE_2: MyType = codegen!(5, 1000); + +pub fn main() { + assert_eq!(GENERATED_CODE_1.eval(10), 80); + assert_eq!(GENERATED_CODE_2.eval(100), 500); +} diff --git a/tests/ui/consts/const-block-item.rs b/tests/ui/consts/const-block-item.rs new file mode 100644 index 000000000..cf0d4441d --- /dev/null +++ b/tests/ui/consts/const-block-item.rs @@ -0,0 +1,41 @@ +// run-pass +#![allow(unused_imports)] + +mod foo { + pub trait Value { + fn value(&self) -> usize; + } +} + +static BLOCK_USE: usize = { + use foo::Value; + 100 +}; + +static BLOCK_STRUCT_DEF: usize = { + struct Foo { + a: usize + } + Foo{ a: 300 }.a +}; + +static BLOCK_FN_DEF: fn(usize) -> usize = { + fn foo(a: usize) -> usize { + a + 10 + } + foo +}; + +static BLOCK_MACRO_RULES: usize = { + macro_rules! baz { + () => (412) + } + baz!() +}; + +pub fn main() { + assert_eq!(BLOCK_USE, 100); + assert_eq!(BLOCK_STRUCT_DEF, 300); + assert_eq!(BLOCK_FN_DEF(390), 400); + assert_eq!(BLOCK_MACRO_RULES, 412); +} diff --git a/tests/ui/consts/const-block-non-item-statement-3.rs b/tests/ui/consts/const-block-non-item-statement-3.rs new file mode 100644 index 000000000..c513946d1 --- /dev/null +++ b/tests/ui/consts/const-block-non-item-statement-3.rs @@ -0,0 +1,8 @@ +// run-pass +#![allow(dead_code, unused)] + +type Array = [u32; { let x = 2; 5 }]; + +pub fn main() { + let _: Array = [0; 5]; +} diff --git a/tests/ui/consts/const-block-non-item-statement-rpass.rs b/tests/ui/consts/const-block-non-item-statement-rpass.rs new file mode 100644 index 000000000..3e52eb50e --- /dev/null +++ b/tests/ui/consts/const-block-non-item-statement-rpass.rs @@ -0,0 +1,11 @@ +// run-pass +#![allow(dead_code, unused)] + +#[repr(u8)] +enum Foo { + Bar = { let x = 1; 3 } +} + +pub fn main() { + assert_eq!(3, Foo::Bar as u8); +} diff --git a/tests/ui/consts/const-block-non-item-statement.rs b/tests/ui/consts/const-block-non-item-statement.rs new file mode 100644 index 000000000..07970b457 --- /dev/null +++ b/tests/ui/consts/const-block-non-item-statement.rs @@ -0,0 +1,23 @@ +// check-pass + +enum Foo { + Bar = { let x = 1; 3 } +} + + +const A: usize = { 1; 2 }; + +const B: usize = { { } 2 }; + +macro_rules! foo { + () => (()) +} + +const C: usize = { foo!(); 2 }; + +const D: usize = { let x = 4; 2 }; + +type Array = [u32; { let x = 2; 5 }]; +type Array2 = [u32; { let mut x = 2; x = 3; x}]; + +pub fn main() {} diff --git a/tests/ui/consts/const-block.rs b/tests/ui/consts/const-block.rs new file mode 100644 index 000000000..ec99c70f6 --- /dev/null +++ b/tests/ui/consts/const-block.rs @@ -0,0 +1,45 @@ +// run-pass +#![allow(unused_braces)] +#![allow(dead_code)] +#![allow(unused_unsafe)] + +use std::marker::Sync; + +struct Foo { + a: usize, + b: *const () +} + +unsafe impl Sync for Foo {} + +fn foo<T>(a: T) -> T { + a +} + +static BLOCK_INTEGRAL: usize = { 1 }; +static BLOCK_EXPLICIT_UNIT: () = { () }; +static BLOCK_IMPLICIT_UNIT: () = { }; +static BLOCK_FLOAT: f64 = { 1.0 }; +static BLOCK_ENUM: Option<usize> = { Some(100) }; +static BLOCK_STRUCT: Foo = { Foo { a: 12, b: std::ptr::null::<()>() } }; +static BLOCK_UNSAFE: usize = unsafe { 1000 }; + +static BLOCK_FN_INFERRED: fn(usize) -> usize = { foo }; + +static BLOCK_FN: fn(usize) -> usize = { foo::<usize> }; + +static BLOCK_ENUM_CONSTRUCTOR: fn(usize) -> Option<usize> = { Some }; + +pub fn main() { + assert_eq!(BLOCK_INTEGRAL, 1); + assert_eq!(BLOCK_EXPLICIT_UNIT, ()); + assert_eq!(BLOCK_IMPLICIT_UNIT, ()); + assert_eq!(BLOCK_FLOAT, 1.0_f64); + assert_eq!(BLOCK_STRUCT.a, 12); + assert_eq!(BLOCK_STRUCT.b, std::ptr::null::<()>()); + assert_eq!(BLOCK_ENUM, Some(100)); + assert_eq!(BLOCK_UNSAFE, 1000); + assert_eq!(BLOCK_FN_INFERRED(300), 300); + assert_eq!(BLOCK_FN(300), 300); + assert_eq!(BLOCK_ENUM_CONSTRUCTOR(200), Some(200)); +} diff --git a/tests/ui/consts/const-blocks/const-repeat.rs b/tests/ui/consts/const-blocks/const-repeat.rs new file mode 100644 index 000000000..65d02317d --- /dev/null +++ b/tests/ui/consts/const-blocks/const-repeat.rs @@ -0,0 +1,27 @@ +// run-pass + +// Repeating a *constant* of non-Copy type (not just a constant expression) is already stable. + +const EMPTY: Vec<i32> = Vec::new(); + +pub fn bar() -> [Vec<i32>; 2] { + [EMPTY; 2] +} + +struct Bomb; + +impl Drop for Bomb { + fn drop(&mut self) { + panic!("BOOM!"); + } +} + +const BOOM: Bomb = Bomb; + +fn main() { + let _x = bar(); + + // Make sure the destructor does not get called for empty arrays. `[CONST; N]` should + // instantiate (and then later drop) the const exactly `N` times. + let _x = [BOOM; 0]; +} diff --git a/tests/ui/consts/const-blocks/fn-call-in-const.rs b/tests/ui/consts/const-blocks/fn-call-in-const.rs new file mode 100644 index 000000000..20496f627 --- /dev/null +++ b/tests/ui/consts/const-blocks/fn-call-in-const.rs @@ -0,0 +1,23 @@ +// run-pass + +#![feature(inline_const)] +#![allow(unused)] + +// Some type that is not copyable. +struct Bar; + +const fn type_no_copy() -> Option<Bar> { + None +} + +const fn type_copy() -> u32 { + 3 +} + +const _: [u32; 2] = [type_copy(); 2]; + +// This is allowed because all promotion contexts use the explicit rules for promotability when +// inside an explicit const context. +const _: [Option<Bar>; 2] = [const { type_no_copy() }; 2]; + +fn main() {} diff --git a/tests/ui/consts/const-blocks/fn-call-in-non-const.rs b/tests/ui/consts/const-blocks/fn-call-in-non-const.rs new file mode 100644 index 000000000..18b4dc714 --- /dev/null +++ b/tests/ui/consts/const-blocks/fn-call-in-non-const.rs @@ -0,0 +1,16 @@ +// Some type that is not copyable. +struct Bar; + +const fn no_copy() -> Option<Bar> { + None +} + +const fn copy() -> u32 { + 3 +} + +fn main() { + let _: [u32; 2] = [copy(); 2]; + let _: [Option<Bar>; 2] = [no_copy(); 2]; + //~^ ERROR the trait bound `Bar: Copy` is not satisfied +} diff --git a/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr b/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr new file mode 100644 index 000000000..ee352700c --- /dev/null +++ b/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `Bar: Copy` is not satisfied + --> $DIR/fn-call-in-non-const.rs:14:32 + | +LL | let _: [Option<Bar>; 2] = [no_copy(); 2]; + | ^^^^^^^^^ the trait `Copy` is not implemented for `Bar` + | + = note: required for `Option<Bar>` to implement `Copy` + = note: the `Copy` trait is required because this value will be copied for each element of the array + = help: consider creating a new `const` item and initializing it with the result of the function call to be used in the repeat position, like `const VAL: Type = const_fn();` and `let x = [VAL; 42];` + = help: create an inline `const` block, see RFC #2920 <https://github.com/rust-lang/rfcs/pull/2920> for more information +help: consider annotating `Bar` with `#[derive(Copy)]` + | +LL | #[derive(Copy)] + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/const-blocks/migrate-fail.rs b/tests/ui/consts/const-blocks/migrate-fail.rs new file mode 100644 index 000000000..fddbfbb9d --- /dev/null +++ b/tests/ui/consts/const-blocks/migrate-fail.rs @@ -0,0 +1,22 @@ +#![allow(warnings)] + +// Some type that is not copyable. +struct Bar; + +mod non_constants { + use Bar; + + fn no_impl_copy_empty_value_multiple_elements() { + let x = None; + let arr: [Option<Bar>; 2] = [x; 2]; + //~^ ERROR the trait bound `Bar: Copy` is not satisfied [E0277] + } + + fn no_impl_copy_value_multiple_elements() { + let x = Some(Bar); + let arr: [Option<Bar>; 2] = [x; 2]; + //~^ ERROR the trait bound `Bar: Copy` is not satisfied [E0277] + } +} + +fn main() {} diff --git a/tests/ui/consts/const-blocks/migrate-fail.stderr b/tests/ui/consts/const-blocks/migrate-fail.stderr new file mode 100644 index 000000000..928ffd083 --- /dev/null +++ b/tests/ui/consts/const-blocks/migrate-fail.stderr @@ -0,0 +1,29 @@ +error[E0277]: the trait bound `Bar: Copy` is not satisfied + --> $DIR/migrate-fail.rs:11:38 + | +LL | let arr: [Option<Bar>; 2] = [x; 2]; + | ^ the trait `Copy` is not implemented for `Bar` + | + = note: required for `Option<Bar>` to implement `Copy` + = note: the `Copy` trait is required because this value will be copied for each element of the array +help: consider annotating `Bar` with `#[derive(Copy)]` + | +LL | #[derive(Copy)] + | + +error[E0277]: the trait bound `Bar: Copy` is not satisfied + --> $DIR/migrate-fail.rs:17:38 + | +LL | let arr: [Option<Bar>; 2] = [x; 2]; + | ^ the trait `Copy` is not implemented for `Bar` + | + = note: required for `Option<Bar>` to implement `Copy` + = note: the `Copy` trait is required because this value will be copied for each element of the array +help: consider annotating `Bar` with `#[derive(Copy)]` + | +LL | #[derive(Copy)] + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/const-blocks/migrate-pass.rs b/tests/ui/consts/const-blocks/migrate-pass.rs new file mode 100644 index 000000000..fd66f5aa6 --- /dev/null +++ b/tests/ui/consts/const-blocks/migrate-pass.rs @@ -0,0 +1,125 @@ +// check-pass +#![allow(warnings)] + +// Some type that is not copyable. +struct Bar; + +mod constants { + use Bar; + + fn no_impl_copy_empty_value_no_elements() { + const FOO: Option<Bar> = None; + const ARR: [Option<Bar>; 0] = [FOO; 0]; + } + + fn no_impl_copy_empty_value_single_element() { + const FOO: Option<Bar> = None; + const ARR: [Option<Bar>; 1] = [FOO; 1]; + } + + fn no_impl_copy_empty_value_multiple_elements() { + const FOO: Option<Bar> = None; + const ARR: [Option<Bar>; 2] = [FOO; 2]; + } + + fn no_impl_copy_value_no_elements() { + const FOO: Option<Bar> = Some(Bar); + const ARR: [Option<Bar>; 0] = [FOO; 0]; + } + + fn no_impl_copy_value_single_element() { + const FOO: Option<Bar> = Some(Bar); + const ARR: [Option<Bar>; 1] = [FOO; 1]; + } + + fn no_impl_copy_value_multiple_elements() { + const FOO: Option<Bar> = Some(Bar); + const ARR: [Option<Bar>; 2] = [FOO; 2]; + } + + fn impl_copy_empty_value_no_elements() { + const FOO: Option<u32> = None; + const ARR: [Option<u32>; 0] = [FOO; 0]; + } + + fn impl_copy_empty_value_one_element() { + const FOO: Option<u32> = None; + const ARR: [Option<u32>; 1] = [FOO; 1]; + } + + fn impl_copy_empty_value_multiple_elements() { + const FOO: Option<u32> = None; + const ARR: [Option<u32>; 2] = [FOO; 2]; + } + + fn impl_copy_value_no_elements() { + const FOO: Option<u32> = Some(4); + const ARR: [Option<u32>; 0] = [FOO; 0]; + } + + fn impl_copy_value_one_element() { + const FOO: Option<u32> = Some(4); + const ARR: [Option<u32>; 1] = [FOO; 1]; + } + + fn impl_copy_value_multiple_elements() { + const FOO: Option<u32> = Some(4); + const ARR: [Option<u32>; 2] = [FOO; 2]; + } +} + +mod non_constants { + use Bar; + + fn no_impl_copy_empty_value_no_elements() { + let x = None; + let arr: [Option<Bar>; 0] = [x; 0]; + } + + fn no_impl_copy_empty_value_single_element() { + let x = None; + let arr: [Option<Bar>; 1] = [x; 1]; + } + + fn no_impl_copy_value_no_elements() { + let x = Some(Bar); + let arr: [Option<Bar>; 0] = [x; 0]; + } + + fn no_impl_copy_value_single_element() { + let x = Some(Bar); + let arr: [Option<Bar>; 1] = [x; 1]; + } + + fn impl_copy_empty_value_no_elements() { + let x: Option<u32> = None; + let arr: [Option<u32>; 0] = [x; 0]; + } + + fn impl_copy_empty_value_one_element() { + let x: Option<u32> = None; + let arr: [Option<u32>; 1] = [x; 1]; + } + + fn impl_copy_empty_value_multiple_elements() { + let x: Option<u32> = None; + let arr: [Option<u32>; 2] = [x; 2]; + } + + fn impl_copy_value_no_elements() { + let x: Option<u32> = Some(4); + let arr: [Option<u32>; 0] = [x; 0]; + } + + fn impl_copy_value_one_element() { + let x: Option<u32> = Some(4); + let arr: [Option<u32>; 1] = [x; 1]; + } + + fn impl_copy_value_multiple_elements() { + let x: Option<u32> = Some(4); + let arr: [Option<u32>; 2] = [x; 2]; + } +} + +fn main() {} diff --git a/tests/ui/consts/const-blocks/nll-fail.rs b/tests/ui/consts/const-blocks/nll-fail.rs new file mode 100644 index 000000000..fddbfbb9d --- /dev/null +++ b/tests/ui/consts/const-blocks/nll-fail.rs @@ -0,0 +1,22 @@ +#![allow(warnings)] + +// Some type that is not copyable. +struct Bar; + +mod non_constants { + use Bar; + + fn no_impl_copy_empty_value_multiple_elements() { + let x = None; + let arr: [Option<Bar>; 2] = [x; 2]; + //~^ ERROR the trait bound `Bar: Copy` is not satisfied [E0277] + } + + fn no_impl_copy_value_multiple_elements() { + let x = Some(Bar); + let arr: [Option<Bar>; 2] = [x; 2]; + //~^ ERROR the trait bound `Bar: Copy` is not satisfied [E0277] + } +} + +fn main() {} diff --git a/tests/ui/consts/const-blocks/nll-fail.stderr b/tests/ui/consts/const-blocks/nll-fail.stderr new file mode 100644 index 000000000..fede00845 --- /dev/null +++ b/tests/ui/consts/const-blocks/nll-fail.stderr @@ -0,0 +1,29 @@ +error[E0277]: the trait bound `Bar: Copy` is not satisfied + --> $DIR/nll-fail.rs:11:38 + | +LL | let arr: [Option<Bar>; 2] = [x; 2]; + | ^ the trait `Copy` is not implemented for `Bar` + | + = note: required for `Option<Bar>` to implement `Copy` + = note: the `Copy` trait is required because this value will be copied for each element of the array +help: consider annotating `Bar` with `#[derive(Copy)]` + | +LL | #[derive(Copy)] + | + +error[E0277]: the trait bound `Bar: Copy` is not satisfied + --> $DIR/nll-fail.rs:17:38 + | +LL | let arr: [Option<Bar>; 2] = [x; 2]; + | ^ the trait `Copy` is not implemented for `Bar` + | + = note: required for `Option<Bar>` to implement `Copy` + = note: the `Copy` trait is required because this value will be copied for each element of the array +help: consider annotating `Bar` with `#[derive(Copy)]` + | +LL | #[derive(Copy)] + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/const-blocks/nll-pass.rs b/tests/ui/consts/const-blocks/nll-pass.rs new file mode 100644 index 000000000..fd66f5aa6 --- /dev/null +++ b/tests/ui/consts/const-blocks/nll-pass.rs @@ -0,0 +1,125 @@ +// check-pass +#![allow(warnings)] + +// Some type that is not copyable. +struct Bar; + +mod constants { + use Bar; + + fn no_impl_copy_empty_value_no_elements() { + const FOO: Option<Bar> = None; + const ARR: [Option<Bar>; 0] = [FOO; 0]; + } + + fn no_impl_copy_empty_value_single_element() { + const FOO: Option<Bar> = None; + const ARR: [Option<Bar>; 1] = [FOO; 1]; + } + + fn no_impl_copy_empty_value_multiple_elements() { + const FOO: Option<Bar> = None; + const ARR: [Option<Bar>; 2] = [FOO; 2]; + } + + fn no_impl_copy_value_no_elements() { + const FOO: Option<Bar> = Some(Bar); + const ARR: [Option<Bar>; 0] = [FOO; 0]; + } + + fn no_impl_copy_value_single_element() { + const FOO: Option<Bar> = Some(Bar); + const ARR: [Option<Bar>; 1] = [FOO; 1]; + } + + fn no_impl_copy_value_multiple_elements() { + const FOO: Option<Bar> = Some(Bar); + const ARR: [Option<Bar>; 2] = [FOO; 2]; + } + + fn impl_copy_empty_value_no_elements() { + const FOO: Option<u32> = None; + const ARR: [Option<u32>; 0] = [FOO; 0]; + } + + fn impl_copy_empty_value_one_element() { + const FOO: Option<u32> = None; + const ARR: [Option<u32>; 1] = [FOO; 1]; + } + + fn impl_copy_empty_value_multiple_elements() { + const FOO: Option<u32> = None; + const ARR: [Option<u32>; 2] = [FOO; 2]; + } + + fn impl_copy_value_no_elements() { + const FOO: Option<u32> = Some(4); + const ARR: [Option<u32>; 0] = [FOO; 0]; + } + + fn impl_copy_value_one_element() { + const FOO: Option<u32> = Some(4); + const ARR: [Option<u32>; 1] = [FOO; 1]; + } + + fn impl_copy_value_multiple_elements() { + const FOO: Option<u32> = Some(4); + const ARR: [Option<u32>; 2] = [FOO; 2]; + } +} + +mod non_constants { + use Bar; + + fn no_impl_copy_empty_value_no_elements() { + let x = None; + let arr: [Option<Bar>; 0] = [x; 0]; + } + + fn no_impl_copy_empty_value_single_element() { + let x = None; + let arr: [Option<Bar>; 1] = [x; 1]; + } + + fn no_impl_copy_value_no_elements() { + let x = Some(Bar); + let arr: [Option<Bar>; 0] = [x; 0]; + } + + fn no_impl_copy_value_single_element() { + let x = Some(Bar); + let arr: [Option<Bar>; 1] = [x; 1]; + } + + fn impl_copy_empty_value_no_elements() { + let x: Option<u32> = None; + let arr: [Option<u32>; 0] = [x; 0]; + } + + fn impl_copy_empty_value_one_element() { + let x: Option<u32> = None; + let arr: [Option<u32>; 1] = [x; 1]; + } + + fn impl_copy_empty_value_multiple_elements() { + let x: Option<u32> = None; + let arr: [Option<u32>; 2] = [x; 2]; + } + + fn impl_copy_value_no_elements() { + let x: Option<u32> = Some(4); + let arr: [Option<u32>; 0] = [x; 0]; + } + + fn impl_copy_value_one_element() { + let x: Option<u32> = Some(4); + let arr: [Option<u32>; 1] = [x; 1]; + } + + fn impl_copy_value_multiple_elements() { + let x: Option<u32> = Some(4); + let arr: [Option<u32>; 2] = [x; 2]; + } +} + +fn main() {} diff --git a/tests/ui/consts/const-blocks/run-pass.rs b/tests/ui/consts/const-blocks/run-pass.rs new file mode 100644 index 000000000..e11f69bab --- /dev/null +++ b/tests/ui/consts/const-blocks/run-pass.rs @@ -0,0 +1,11 @@ +// run-pass + +#[derive(Debug, Eq, PartialEq)] +struct Bar; + +fn main() { + const FOO: Option<Bar> = None; + const ARR: [Option<Bar>; 2] = [FOO; 2]; + + assert_eq!(ARR, [None::<Bar>, None::<Bar>]); +} diff --git a/tests/ui/consts/const-blocks/trait-error.rs b/tests/ui/consts/const-blocks/trait-error.rs new file mode 100644 index 000000000..49d1e9b94 --- /dev/null +++ b/tests/ui/consts/const-blocks/trait-error.rs @@ -0,0 +1,7 @@ +#[derive(Copy, Clone)] +struct Foo<T>(T); + +fn main() { + [Foo(String::new()); 4]; + //~^ ERROR the trait bound `String: Copy` is not satisfied [E0277] +} diff --git a/tests/ui/consts/const-blocks/trait-error.stderr b/tests/ui/consts/const-blocks/trait-error.stderr new file mode 100644 index 000000000..06fa4b0b1 --- /dev/null +++ b/tests/ui/consts/const-blocks/trait-error.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/trait-error.rs:5:6 + | +LL | [Foo(String::new()); 4]; + | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` + | +note: required for `Foo<String>` to implement `Copy` + --> $DIR/trait-error.rs:1:10 + | +LL | #[derive(Copy, Clone)] + | ^^^^ unsatisfied trait bound introduced in this `derive` macro + = note: the `Copy` trait is required because this value will be copied for each element of the array + = help: consider creating a new `const` item and initializing it with the result of the function call to be used in the repeat position, like `const VAL: Type = const_fn();` and `let x = [VAL; 42];` + = help: create an inline `const` block, see RFC #2920 <https://github.com/rust-lang/rfcs/pull/2920> for more information + = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/const-bound.rs b/tests/ui/consts/const-bound.rs new file mode 100644 index 000000000..735056a0a --- /dev/null +++ b/tests/ui/consts/const-bound.rs @@ -0,0 +1,20 @@ +// run-pass +#![allow(dead_code)] +// Make sure const bounds work on things, and test that a few types +// are const. + +// pretty-expanded FIXME #23616 + +fn foo<T: Sync>(x: T) -> T { x } + +struct F { field: isize } + +pub fn main() { + /*foo(1); + foo("hi".to_string()); + foo(vec![1, 2, 3]); + foo(F{field: 42}); + foo((1, 2)); + foo(@1);*/ + foo(Box::new(1)); +} diff --git a/tests/ui/consts/const-byte-str-cast.rs b/tests/ui/consts/const-byte-str-cast.rs new file mode 100644 index 000000000..65d626c29 --- /dev/null +++ b/tests/ui/consts/const-byte-str-cast.rs @@ -0,0 +1,9 @@ +// run-pass +#[deny(warnings)] + +pub fn main() { + let _ = b"x" as &[u8]; + let _ = b"y" as &[u8; 1]; + let _ = b"z" as *const u8; + let _ = "ä" as *const str; +} diff --git a/tests/ui/consts/const-call.rs b/tests/ui/consts/const-call.rs new file mode 100644 index 000000000..28e89559f --- /dev/null +++ b/tests/ui/consts/const-call.rs @@ -0,0 +1,8 @@ +fn f(x: usize) -> usize { + x +} + +fn main() { + let _ = [0; f(2)]; + //~^ ERROR cannot call non-const fn +} diff --git a/tests/ui/consts/const-call.stderr b/tests/ui/consts/const-call.stderr new file mode 100644 index 000000000..e46bcad0e --- /dev/null +++ b/tests/ui/consts/const-call.stderr @@ -0,0 +1,11 @@ +error[E0015]: cannot call non-const fn `f` in constants + --> $DIR/const-call.rs:6:17 + | +LL | let _ = [0; f(2)]; + | ^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/const-cast-different-types.rs b/tests/ui/consts/const-cast-different-types.rs new file mode 100644 index 000000000..5e6d7d899 --- /dev/null +++ b/tests/ui/consts/const-cast-different-types.rs @@ -0,0 +1,6 @@ +const a: &str = "foo"; +const b: *const u8 = a as *const u8; //~ ERROR casting +const c: *const u8 = &a as *const u8; //~ ERROR casting + +fn main() { +} diff --git a/tests/ui/consts/const-cast-different-types.stderr b/tests/ui/consts/const-cast-different-types.stderr new file mode 100644 index 000000000..9e622de2e --- /dev/null +++ b/tests/ui/consts/const-cast-different-types.stderr @@ -0,0 +1,15 @@ +error[E0606]: casting `&'static str` as `*const u8` is invalid + --> $DIR/const-cast-different-types.rs:2:22 + | +LL | const b: *const u8 = a as *const u8; + | ^^^^^^^^^^^^^^ + +error[E0606]: casting `&&'static str` as `*const u8` is invalid + --> $DIR/const-cast-different-types.rs:3:22 + | +LL | const c: *const u8 = &a as *const u8; + | ^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0606`. diff --git a/tests/ui/consts/const-cast-ptr-int.rs b/tests/ui/consts/const-cast-ptr-int.rs new file mode 100644 index 000000000..987d9616e --- /dev/null +++ b/tests/ui/consts/const-cast-ptr-int.rs @@ -0,0 +1,16 @@ +// run-pass +#![allow(non_upper_case_globals)] + +use std::ptr; + +struct TestStruct { + x: *const u8 +} + +unsafe impl Sync for TestStruct {} + +static a: TestStruct = TestStruct{x: 0 as *const u8}; + +pub fn main() { + assert_eq!(a.x, ptr::null()); +} diff --git a/tests/ui/consts/const-cast-wrong-type.rs b/tests/ui/consts/const-cast-wrong-type.rs new file mode 100644 index 000000000..6e055a2bc --- /dev/null +++ b/tests/ui/consts/const-cast-wrong-type.rs @@ -0,0 +1,5 @@ +const a: [u8; 3] = ['h' as u8, 'i' as u8, 0 as u8]; +const b: *const i8 = &a as *const i8; //~ ERROR mismatched types + +fn main() { +} diff --git a/tests/ui/consts/const-cast-wrong-type.stderr b/tests/ui/consts/const-cast-wrong-type.stderr new file mode 100644 index 000000000..ee186636e --- /dev/null +++ b/tests/ui/consts/const-cast-wrong-type.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/const-cast-wrong-type.rs:2:22 + | +LL | const b: *const i8 = &a as *const i8; + | ^^^^^^^^^^^^^^^ expected `u8`, found `i8` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/const-cast.rs b/tests/ui/consts/const-cast.rs new file mode 100644 index 000000000..abeb24121 --- /dev/null +++ b/tests/ui/consts/const-cast.rs @@ -0,0 +1,16 @@ +// run-pass +#![allow(non_upper_case_globals)] + +struct TestStruct { + x: *const u8, +} + +unsafe impl Sync for TestStruct {} + +extern "C" fn foo() {} +const x: extern "C" fn() = foo; +static y: TestStruct = TestStruct { x: x as *const u8 }; + +pub fn main() { + assert_eq!(x as *const u8, y.x); +} diff --git a/tests/ui/consts/const-const.rs b/tests/ui/consts/const-const.rs new file mode 100644 index 000000000..85e4a72e8 --- /dev/null +++ b/tests/ui/consts/const-const.rs @@ -0,0 +1,9 @@ +// run-pass +#![allow(non_upper_case_globals)] + +const a: isize = 1; +const b: isize = a + 2; + +pub fn main() { + assert_eq!(b, 3); +} diff --git a/tests/ui/consts/const-contents.rs b/tests/ui/consts/const-contents.rs new file mode 100644 index 000000000..7ba3d4356 --- /dev/null +++ b/tests/ui/consts/const-contents.rs @@ -0,0 +1,19 @@ +// run-pass +// Issue #570 +#![allow(non_upper_case_globals)] + +static lsl : isize = 1 << 2; +static add : isize = 1 + 2; +static addf : f64 = 1.0 + 2.0; +static not : isize = !0; +static notb : bool = !true; +static neg : isize = -(1); + +pub fn main() { + assert_eq!(lsl, 4); + assert_eq!(add, 3); + assert_eq!(addf, 3.0); + assert_eq!(not, -1); + assert_eq!(notb, false); + assert_eq!(neg, -1); +} diff --git a/tests/ui/consts/const-deref-ptr.rs b/tests/ui/consts/const-deref-ptr.rs new file mode 100644 index 000000000..4aca75e3a --- /dev/null +++ b/tests/ui/consts/const-deref-ptr.rs @@ -0,0 +1,7 @@ +// Check that you can't dereference invalid raw pointers in constants. + +fn main() { + static C: u64 = unsafe {*(0xdeadbeef as *const u64)}; + //~^ ERROR could not evaluate static initializer + println!("{}", C); +} diff --git a/tests/ui/consts/const-deref-ptr.stderr b/tests/ui/consts/const-deref-ptr.stderr new file mode 100644 index 000000000..22cb6451e --- /dev/null +++ b/tests/ui/consts/const-deref-ptr.stderr @@ -0,0 +1,9 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/const-deref-ptr.rs:4:29 + | +LL | static C: u64 = unsafe {*(0xdeadbeef as *const u64)}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0xdeadbeef[noalloc] is a dangling pointer (it has no provenance) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-deref.rs b/tests/ui/consts/const-deref.rs new file mode 100644 index 000000000..6060d8e51 --- /dev/null +++ b/tests/ui/consts/const-deref.rs @@ -0,0 +1,8 @@ +// run-pass + +const C: &'static isize = &1000; +static D: isize = *C; + +pub fn main() { + assert_eq!(D, 1000); +} diff --git a/tests/ui/consts/const-endianess.rs b/tests/ui/consts/const-endianess.rs new file mode 100644 index 000000000..936f31954 --- /dev/null +++ b/tests/ui/consts/const-endianess.rs @@ -0,0 +1,21 @@ +// run-pass +#![feature(test)] + +extern crate test; +use test::black_box as b; // prevent promotion of the argument and const-propagation of the result + +const BE_U32: u32 = 55u32.to_be(); +const LE_U32: u32 = 55u32.to_le(); + +fn main() { + assert_eq!(BE_U32, b(55u32).to_be()); + assert_eq!(LE_U32, b(55u32).to_le()); + + #[cfg(not(target_os = "emscripten"))] + { + const BE_U128: u128 = 999999u128.to_be(); + const LE_I128: i128 = (-999999i128).to_le(); + assert_eq!(BE_U128, b(999999u128).to_be()); + assert_eq!(LE_I128, b(-999999i128).to_le()); + } +} diff --git a/tests/ui/consts/const-enum-byref-self.rs b/tests/ui/consts/const-enum-byref-self.rs new file mode 100644 index 000000000..b7e14bfb7 --- /dev/null +++ b/tests/ui/consts/const-enum-byref-self.rs @@ -0,0 +1,18 @@ +// run-pass +#![allow(dead_code)] + +enum E { V, VV(isize) } +static C: E = E::V; + +impl E { + pub fn method(&self) { + match *self { + E::V => {} + E::VV(..) => panic!() + } + } +} + +pub fn main() { + C.method() +} diff --git a/tests/ui/consts/const-enum-byref.rs b/tests/ui/consts/const-enum-byref.rs new file mode 100644 index 000000000..badf52946 --- /dev/null +++ b/tests/ui/consts/const-enum-byref.rs @@ -0,0 +1,16 @@ +// run-pass +#![allow(dead_code)] + +enum E { V, VV(isize) } +static C: E = E::V; + +fn f(a: &E) { + match *a { + E::V => {} + E::VV(..) => panic!() + } +} + +pub fn main() { + f(&C) +} diff --git a/tests/ui/consts/const-enum-cast.rs b/tests/ui/consts/const-enum-cast.rs new file mode 100644 index 000000000..399684951 --- /dev/null +++ b/tests/ui/consts/const-enum-cast.rs @@ -0,0 +1,41 @@ +// run-pass +#![allow(non_upper_case_globals)] + +enum A { A1, A2 } +enum B { B1=4, B2=2 } + +#[allow(dead_code)] +#[repr(align(8))] +enum Aligned { + Zero = 0, + One = 1, +} + +// regression test for https://github.com/rust-lang/rust/issues/96185 +const X: u8 = { + let aligned = Aligned::Zero; + aligned as u8 +}; + +pub fn main () { + static c1: isize = A::A2 as isize; + static c2: isize = B::B2 as isize; + let a1 = A::A2 as isize; + let a2 = B::B2 as isize; + assert_eq!(c1, 1); + assert_eq!(c2, 2); + assert_eq!(a1, 1); + assert_eq!(a2, 2); + + // Turns out that adding a let-binding generates totally different MIR. + static c1_2: isize = { let v = A::A1; v as isize }; + static c2_2: isize = { let v = B::B1; v as isize }; + let a1_2 = { let v = A::A1; v as isize }; + let a2_2 = { let v = B::B1; v as isize }; + assert_eq!(c1_2, 0); + assert_eq!(c2_2, 4); + assert_eq!(a1_2, 0); + assert_eq!(a2_2, 4); + + assert_eq!(X, 0); +} diff --git a/tests/ui/consts/const-enum-ptr.rs b/tests/ui/consts/const-enum-ptr.rs new file mode 100644 index 000000000..84f4eb840 --- /dev/null +++ b/tests/ui/consts/const-enum-ptr.rs @@ -0,0 +1,12 @@ +// run-pass +#![allow(dead_code)] + +enum E { V0, V1(isize) } +static C: &'static E = &E::V0; + +pub fn main() { + match *C { + E::V0 => (), + _ => panic!() + } +} diff --git a/tests/ui/consts/const-enum-struct.rs b/tests/ui/consts/const-enum-struct.rs new file mode 100644 index 000000000..ee88c9361 --- /dev/null +++ b/tests/ui/consts/const-enum-struct.rs @@ -0,0 +1,12 @@ +// run-pass +#![allow(dead_code)] + +enum E { V16(u16), V32(u32) } +struct S { a: E, b: u16, c: u16 } +static C: S = S { a: E::V16(0xDEAD), b: 0x600D, c: 0xBAD }; + +pub fn main() { + let n = C.b; + assert!(n != 0xBAD); + assert_eq!(n, 0x600D); +} diff --git a/tests/ui/consts/const-enum-struct2.rs b/tests/ui/consts/const-enum-struct2.rs new file mode 100644 index 000000000..6dfe63d5d --- /dev/null +++ b/tests/ui/consts/const-enum-struct2.rs @@ -0,0 +1,12 @@ +// run-pass +#![allow(dead_code)] + +enum E { V0, V16(u16) } +struct S { a: E, b: u16, c: u16 } +static C: S = S { a: E::V0, b: 0x600D, c: 0xBAD }; + +pub fn main() { + let n = C.b; + assert!(n != 0xBAD); + assert_eq!(n, 0x600D); +} diff --git a/tests/ui/consts/const-enum-structlike.rs b/tests/ui/consts/const-enum-structlike.rs new file mode 100644 index 000000000..0ea79aebc --- /dev/null +++ b/tests/ui/consts/const-enum-structlike.rs @@ -0,0 +1,16 @@ +// run-pass +#![allow(dead_code)] + +enum E { + S0 { s: String }, + S1 { u: usize } +} + +static C: E = E::S1 { u: 23 }; + +pub fn main() { + match C { + E::S0 { .. } => panic!(), + E::S1 { u } => assert_eq!(u, 23) + } +} diff --git a/tests/ui/consts/const-enum-tuple.rs b/tests/ui/consts/const-enum-tuple.rs new file mode 100644 index 000000000..e0363166b --- /dev/null +++ b/tests/ui/consts/const-enum-tuple.rs @@ -0,0 +1,11 @@ +// run-pass +#![allow(dead_code)] + +enum E { V16(u16), V32(u32) } +static C: (E, u16, u16) = (E::V16(0xDEAD), 0x600D, 0xBAD); + +pub fn main() { + let (_, n, _) = C; + assert!(n != 0xBAD); + assert_eq!(n, 0x600D); +} diff --git a/tests/ui/consts/const-enum-tuple2.rs b/tests/ui/consts/const-enum-tuple2.rs new file mode 100644 index 000000000..ef378b599 --- /dev/null +++ b/tests/ui/consts/const-enum-tuple2.rs @@ -0,0 +1,11 @@ +// run-pass +#![allow(dead_code)] + +enum E { V0, V16(u16) } +static C: (E, u16, u16) = (E::V0, 0x600D, 0xBAD); + +pub fn main() { + let (_, n, _) = C; + assert!(n != 0xBAD); + assert_eq!(n, 0x600D); +} diff --git a/tests/ui/consts/const-enum-tuplestruct.rs b/tests/ui/consts/const-enum-tuplestruct.rs new file mode 100644 index 000000000..f93945c6a --- /dev/null +++ b/tests/ui/consts/const-enum-tuplestruct.rs @@ -0,0 +1,12 @@ +// run-pass +#![allow(dead_code)] + +enum E { V16(u16), V32(u32) } +struct S(E, u16, u16); +static C: S = S(E::V16(0xDEAD), 0x600D, 0xBAD); + +pub fn main() { + let S(_, n, _) = C; + assert!(n != 0xBAD); + assert_eq!(n, 0x600D); +} diff --git a/tests/ui/consts/const-enum-tuplestruct2.rs b/tests/ui/consts/const-enum-tuplestruct2.rs new file mode 100644 index 000000000..b8aa9a315 --- /dev/null +++ b/tests/ui/consts/const-enum-tuplestruct2.rs @@ -0,0 +1,12 @@ +// run-pass +#![allow(dead_code)] + +enum E { V0, V16(u16) } +struct S(E, u16, u16); +static C: S = S(E::V0, 0x600D, 0xBAD); + +pub fn main() { + let S(_, n, _) = C; + assert!(n != 0xBAD); + assert_eq!(n, 0x600D); +} diff --git a/tests/ui/consts/const-enum-vec-index.rs b/tests/ui/consts/const-enum-vec-index.rs new file mode 100644 index 000000000..3f155340a --- /dev/null +++ b/tests/ui/consts/const-enum-vec-index.rs @@ -0,0 +1,30 @@ +// run-pass +#[derive(Copy, Clone)] +enum E { V1(isize), V0 } + +const C: &'static [E] = &[E::V0, E::V1(0xDEADBEE)]; +static C0: E = C[0]; +static C1: E = C[1]; +const D: &'static [E; 2] = &[E::V0, E::V1(0xDEAFBEE)]; +static D0: E = D[0]; +static D1: E = D[1]; + +pub fn main() { + match C0 { + E::V0 => (), + _ => panic!() + } + match C1 { + E::V1(n) => assert_eq!(n, 0xDEADBEE), + _ => panic!() + } + + match D0 { + E::V0 => (), + _ => panic!() + } + match D1 { + E::V1(n) => assert_eq!(n, 0xDEAFBEE), + _ => panic!() + } +} diff --git a/tests/ui/consts/const-enum-vec-ptr.rs b/tests/ui/consts/const-enum-vec-ptr.rs new file mode 100644 index 000000000..43ffe6570 --- /dev/null +++ b/tests/ui/consts/const-enum-vec-ptr.rs @@ -0,0 +1,15 @@ +// run-pass + +enum E { V1(isize), V0 } +static C: &'static [E] = &[E::V0, E::V1(0xDEADBEE), E::V0]; + +pub fn main() { + match C[1] { + E::V1(n) => assert_eq!(n, 0xDEADBEE), + _ => panic!() + } + match C[2] { + E::V0 => (), + _ => panic!() + } +} diff --git a/tests/ui/consts/const-enum-vector.rs b/tests/ui/consts/const-enum-vector.rs new file mode 100644 index 000000000..ee3739f97 --- /dev/null +++ b/tests/ui/consts/const-enum-vector.rs @@ -0,0 +1,15 @@ +// run-pass + +enum E { V1(isize), V0 } +static C: [E; 3] = [E::V0, E::V1(0xDEADBEE), E::V0]; + +pub fn main() { + match C[1] { + E::V1(n) => assert_eq!(n, 0xDEADBEE), + _ => panic!() + } + match C[2] { + E::V0 => (), + _ => panic!() + } +} diff --git a/tests/ui/consts/const-err-early.rs b/tests/ui/consts/const-err-early.rs new file mode 100644 index 000000000..a3105b4fc --- /dev/null +++ b/tests/ui/consts/const-err-early.rs @@ -0,0 +1,14 @@ +pub const A: i8 = -i8::MIN; //~ ERROR constant +pub const B: u8 = 200u8 + 200u8; //~ ERROR constant +pub const C: u8 = 200u8 * 4; //~ ERROR constant +pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR constant +pub const E: u8 = [5u8][1]; //~ ERROR constant + +fn main() { + let _a = A; + let _b = B; + let _c = C; + let _d = D; + let _e = E; + let _e = [6u8][1]; +} diff --git a/tests/ui/consts/const-err-early.stderr b/tests/ui/consts/const-err-early.stderr new file mode 100644 index 000000000..59bf637b7 --- /dev/null +++ b/tests/ui/consts/const-err-early.stderr @@ -0,0 +1,33 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-err-early.rs:1:19 + | +LL | pub const A: i8 = -i8::MIN; + | ^^^^^^^^ attempt to negate `i8::MIN`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-err-early.rs:2:19 + | +LL | pub const B: u8 = 200u8 + 200u8; + | ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-err-early.rs:3:19 + | +LL | pub const C: u8 = 200u8 * 4; + | ^^^^^^^^^ attempt to compute `200_u8 * 4_u8`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-err-early.rs:4:19 + | +LL | pub const D: u8 = 42u8 - (42u8 + 1); + | ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-err-early.rs:5:19 + | +LL | pub const E: u8 = [5u8][1]; + | ^^^^^^^^ index out of bounds: the length is 1 but the index is 1 + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-err-late.rs b/tests/ui/consts/const-err-late.rs new file mode 100644 index 000000000..d2476e493 --- /dev/null +++ b/tests/ui/consts/const-err-late.rs @@ -0,0 +1,20 @@ +// build-fail +// compile-flags: -C overflow-checks=on + +#![allow(arithmetic_overflow, unconditional_panic)] + +fn black_box<T>(_: T) { + unimplemented!() +} + +struct S<T>(T); + +impl<T> S<T> { + const FOO: u8 = [5u8][1]; + //~^ ERROR evaluation of `S::<i32>::FOO` failed + //~| ERROR evaluation of `S::<u32>::FOO` failed +} + +fn main() { + black_box((S::<i32>::FOO, S::<u32>::FOO)); //~ constant +} diff --git a/tests/ui/consts/const-err-late.stderr b/tests/ui/consts/const-err-late.stderr new file mode 100644 index 000000000..c5c668189 --- /dev/null +++ b/tests/ui/consts/const-err-late.stderr @@ -0,0 +1,51 @@ +error[E0080]: evaluation of `S::<i32>::FOO` failed + --> $DIR/const-err-late.rs:13:21 + | +LL | const FOO: u8 = [5u8][1]; + | ^^^^^^^^ index out of bounds: the length is 1 but the index is 1 + +note: erroneous constant used + --> $DIR/const-err-late.rs:19:16 + | +LL | black_box((S::<i32>::FOO, S::<u32>::FOO)); + | ^^^^^^^^^^^^^ + +note: erroneous constant used + --> $DIR/const-err-late.rs:19:16 + | +LL | black_box((S::<i32>::FOO, S::<u32>::FOO)); + | ^^^^^^^^^^^^^ + +error[E0080]: evaluation of `S::<u32>::FOO` failed + --> $DIR/const-err-late.rs:13:21 + | +LL | const FOO: u8 = [5u8][1]; + | ^^^^^^^^ index out of bounds: the length is 1 but the index is 1 + +note: erroneous constant used + --> $DIR/const-err-late.rs:19:31 + | +LL | black_box((S::<i32>::FOO, S::<u32>::FOO)); + | ^^^^^^^^^^^^^ + +note: erroneous constant used + --> $DIR/const-err-late.rs:19:31 + | +LL | black_box((S::<i32>::FOO, S::<u32>::FOO)); + | ^^^^^^^^^^^^^ + +note: erroneous constant used + --> $DIR/const-err-late.rs:19:16 + | +LL | black_box((S::<i32>::FOO, S::<u32>::FOO)); + | ^^^^^^^^^^^^^ + +note: erroneous constant used + --> $DIR/const-err-late.rs:19:31 + | +LL | black_box((S::<i32>::FOO, S::<u32>::FOO)); + | ^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-err-multi.rs b/tests/ui/consts/const-err-multi.rs new file mode 100644 index 000000000..b265bc4c4 --- /dev/null +++ b/tests/ui/consts/const-err-multi.rs @@ -0,0 +1,12 @@ +pub const A: i8 = -i8::MIN; +//~^ ERROR constant +pub const B: i8 = A; +//~^ constant +pub const C: u8 = A as u8; +//~^ constant +pub const D: i8 = 50 - A; +//~^ constant + +fn main() { + let _ = (A, B, C, D); +} diff --git a/tests/ui/consts/const-err-multi.stderr b/tests/ui/consts/const-err-multi.stderr new file mode 100644 index 000000000..28af8e5eb --- /dev/null +++ b/tests/ui/consts/const-err-multi.stderr @@ -0,0 +1,27 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-err-multi.rs:1:19 + | +LL | pub const A: i8 = -i8::MIN; + | ^^^^^^^^ attempt to negate `i8::MIN`, which would overflow + +note: erroneous constant used + --> $DIR/const-err-multi.rs:3:19 + | +LL | pub const B: i8 = A; + | ^ + +note: erroneous constant used + --> $DIR/const-err-multi.rs:5:19 + | +LL | pub const C: u8 = A as u8; + | ^ + +note: erroneous constant used + --> $DIR/const-err-multi.rs:7:24 + | +LL | pub const D: i8 = 50 - A; + | ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-err-rpass.rs b/tests/ui/consts/const-err-rpass.rs new file mode 100644 index 000000000..e7fa10a2a --- /dev/null +++ b/tests/ui/consts/const-err-rpass.rs @@ -0,0 +1,18 @@ +// run-pass +#![allow(dead_code)] +// check for const_err regressions + +const X: *const u8 = b"" as _; +const Y: bool = 'A' == 'B'; +const Z: char = 'A'; +const W: bool = Z <= 'B'; + + +fn main() { + let _ = ((-1 as i8) << 8 - 1) as f32; + let _ = 0u8 as char; + let _ = true > false; + let _ = true >= false; + let _ = true < false; + let _ = true >= false; +} diff --git a/tests/ui/consts/const-err2.noopt.stderr b/tests/ui/consts/const-err2.noopt.stderr new file mode 100644 index 000000000..8b1688c4a --- /dev/null +++ b/tests/ui/consts/const-err2.noopt.stderr @@ -0,0 +1,48 @@ +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:19:13 + | +LL | let a = -i8::MIN; + | ^^^^^^^^ attempt to negate `i8::MIN`, which would overflow + | + = note: `#[deny(arithmetic_overflow)]` on by default + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:21:18 + | +LL | let a_i128 = -i128::MIN; + | ^^^^^^^^^^ attempt to negate `i128::MIN`, which would overflow + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:23:13 + | +LL | let b = 200u8 + 200u8 + 200u8; + | ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8`, which would overflow + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:25:18 + | +LL | let b_i128 = i128::MIN - i128::MAX; + | ^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX`, which would overflow + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:27:13 + | +LL | let c = 200u8 * 4; + | ^^^^^^^^^ attempt to compute `200_u8 * 4_u8`, which would overflow + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:29:13 + | +LL | let d = 42u8 - (42u8 + 1); + | ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8`, which would overflow + +error: this operation will panic at runtime + --> $DIR/const-err2.rs:31:14 + | +LL | let _e = [5u8][1]; + | ^^^^^^^^ index out of bounds: the length is 1 but the index is 1 + | + = note: `#[deny(unconditional_panic)]` on by default + +error: aborting due to 7 previous errors + diff --git a/tests/ui/consts/const-err2.opt.stderr b/tests/ui/consts/const-err2.opt.stderr new file mode 100644 index 000000000..8b1688c4a --- /dev/null +++ b/tests/ui/consts/const-err2.opt.stderr @@ -0,0 +1,48 @@ +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:19:13 + | +LL | let a = -i8::MIN; + | ^^^^^^^^ attempt to negate `i8::MIN`, which would overflow + | + = note: `#[deny(arithmetic_overflow)]` on by default + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:21:18 + | +LL | let a_i128 = -i128::MIN; + | ^^^^^^^^^^ attempt to negate `i128::MIN`, which would overflow + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:23:13 + | +LL | let b = 200u8 + 200u8 + 200u8; + | ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8`, which would overflow + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:25:18 + | +LL | let b_i128 = i128::MIN - i128::MAX; + | ^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX`, which would overflow + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:27:13 + | +LL | let c = 200u8 * 4; + | ^^^^^^^^^ attempt to compute `200_u8 * 4_u8`, which would overflow + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:29:13 + | +LL | let d = 42u8 - (42u8 + 1); + | ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8`, which would overflow + +error: this operation will panic at runtime + --> $DIR/const-err2.rs:31:14 + | +LL | let _e = [5u8][1]; + | ^^^^^^^^ index out of bounds: the length is 1 but the index is 1 + | + = note: `#[deny(unconditional_panic)]` on by default + +error: aborting due to 7 previous errors + diff --git a/tests/ui/consts/const-err2.opt_with_overflow_checks.stderr b/tests/ui/consts/const-err2.opt_with_overflow_checks.stderr new file mode 100644 index 000000000..8b1688c4a --- /dev/null +++ b/tests/ui/consts/const-err2.opt_with_overflow_checks.stderr @@ -0,0 +1,48 @@ +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:19:13 + | +LL | let a = -i8::MIN; + | ^^^^^^^^ attempt to negate `i8::MIN`, which would overflow + | + = note: `#[deny(arithmetic_overflow)]` on by default + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:21:18 + | +LL | let a_i128 = -i128::MIN; + | ^^^^^^^^^^ attempt to negate `i128::MIN`, which would overflow + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:23:13 + | +LL | let b = 200u8 + 200u8 + 200u8; + | ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8`, which would overflow + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:25:18 + | +LL | let b_i128 = i128::MIN - i128::MAX; + | ^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX`, which would overflow + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:27:13 + | +LL | let c = 200u8 * 4; + | ^^^^^^^^^ attempt to compute `200_u8 * 4_u8`, which would overflow + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:29:13 + | +LL | let d = 42u8 - (42u8 + 1); + | ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8`, which would overflow + +error: this operation will panic at runtime + --> $DIR/const-err2.rs:31:14 + | +LL | let _e = [5u8][1]; + | ^^^^^^^^ index out of bounds: the length is 1 but the index is 1 + | + = note: `#[deny(unconditional_panic)]` on by default + +error: aborting due to 7 previous errors + diff --git a/tests/ui/consts/const-err2.rs b/tests/ui/consts/const-err2.rs new file mode 100644 index 000000000..db49ec25a --- /dev/null +++ b/tests/ui/consts/const-err2.rs @@ -0,0 +1,39 @@ +// needed because negating int::MIN will behave differently between +// optimized compilation and unoptimized compilation and thus would +// lead to different lints being emitted + +// revisions: noopt opt opt_with_overflow_checks +//[noopt]compile-flags: -C opt-level=0 +//[opt]compile-flags: -O +//[opt_with_overflow_checks]compile-flags: -C overflow-checks=on -O + +// build-fail + +#![feature(rustc_attrs)] + +fn black_box<T>(_: T) { + unimplemented!() +} + +fn main() { + let a = -i8::MIN; + //~^ ERROR arithmetic operation will overflow + let a_i128 = -i128::MIN; + //~^ ERROR arithmetic operation will overflow + let b = 200u8 + 200u8 + 200u8; + //~^ ERROR arithmetic operation will overflow + let b_i128 = i128::MIN - i128::MAX; + //~^ ERROR arithmetic operation will overflow + let c = 200u8 * 4; + //~^ ERROR arithmetic operation will overflow + let d = 42u8 - (42u8 + 1); + //~^ ERROR arithmetic operation will overflow + let _e = [5u8][1]; + //~^ ERROR operation will panic + black_box(a); + black_box(a_i128); + black_box(b); + black_box(b_i128); + black_box(c); + black_box(d); +} diff --git a/tests/ui/consts/const-err4.32bit.stderr b/tests/ui/consts/const-err4.32bit.stderr new file mode 100644 index 000000000..1cbf78173 --- /dev/null +++ b/tests/ui/consts/const-err4.32bit.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-err4.rs:9:21 + | +LL | Boo = [unsafe { Foo { b: () }.a }; 4][3], + | ^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-err4.64bit.stderr b/tests/ui/consts/const-err4.64bit.stderr new file mode 100644 index 000000000..1cbf78173 --- /dev/null +++ b/tests/ui/consts/const-err4.64bit.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-err4.rs:9:21 + | +LL | Boo = [unsafe { Foo { b: () }.a }; 4][3], + | ^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-err4.rs b/tests/ui/consts/const-err4.rs new file mode 100644 index 000000000..107dc3f82 --- /dev/null +++ b/tests/ui/consts/const-err4.rs @@ -0,0 +1,16 @@ +// stderr-per-bitwidth +#[derive(Copy, Clone)] +union Foo { + a: isize, + b: (), +} + +enum Bar { + Boo = [unsafe { Foo { b: () }.a }; 4][3], + //~^ ERROR evaluation of constant value failed + //~| uninitialized +} + +fn main() { + assert_ne!(Bar::Boo as isize, 0); +} diff --git a/tests/ui/consts/const-eval/assign-to-static-within-other-static.rs b/tests/ui/consts/const-eval/assign-to-static-within-other-static.rs new file mode 100644 index 000000000..ecf97223f --- /dev/null +++ b/tests/ui/consts/const-eval/assign-to-static-within-other-static.rs @@ -0,0 +1,12 @@ +// New test for #53818: modifying static memory at compile-time is not allowed. +// The test should never compile successfully + +use std::cell::UnsafeCell; + +static mut FOO: u32 = 42; +static BOO: () = unsafe { + FOO = 5; + //~^ could not evaluate static initializer [E0080] +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/assign-to-static-within-other-static.stderr b/tests/ui/consts/const-eval/assign-to-static-within-other-static.stderr new file mode 100644 index 000000000..4b6784acf --- /dev/null +++ b/tests/ui/consts/const-eval/assign-to-static-within-other-static.stderr @@ -0,0 +1,9 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/assign-to-static-within-other-static.rs:8:5 + | +LL | FOO = 5; + | ^^^^^^^ modifying a static's initial value from another static's initializer + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/auxiliary/post_monomorphization_error.rs b/tests/ui/consts/const-eval/auxiliary/post_monomorphization_error.rs new file mode 100644 index 000000000..bdeaa0cd3 --- /dev/null +++ b/tests/ui/consts/const-eval/auxiliary/post_monomorphization_error.rs @@ -0,0 +1,20 @@ +// Auxiliary crate used for testing post-monomorphization errors cross-crate. +// It duplicates the setup used in `stdarch` to validate its intrinsics' const arguments. + +struct ValidateConstImm<const IMM: i32, const MIN: i32, const MAX: i32>; +impl<const IMM: i32, const MIN: i32, const MAX: i32> ValidateConstImm<IMM, MIN, MAX> { + pub(crate) const VALID: () = { + let _ = 1 / ((IMM >= MIN && IMM <= MAX) as usize); + }; +} + +macro_rules! static_assert_imm1 { + ($imm:ident) => { + let _ = $crate::ValidateConstImm::<$imm, 0, { (1 << 1) - 1 }>::VALID; + }; +} + +// This function triggers an error whenever the const argument does not fit in 1-bit. +pub fn stdarch_intrinsic<const IMM1: i32>() { + static_assert_imm1!(IMM1); +} diff --git a/tests/ui/consts/const-eval/auxiliary/stability.rs b/tests/ui/consts/const-eval/auxiliary/stability.rs new file mode 100644 index 000000000..e61595518 --- /dev/null +++ b/tests/ui/consts/const-eval/auxiliary/stability.rs @@ -0,0 +1,10 @@ +// Crate that exports a const fn. Used for testing cross-crate. + +#![crate_type="rlib"] +#![stable(feature = "rust1", since = "1.0.0")] + +#![feature(staged_api)] + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature="foo", issue = "none")] +pub const fn foo() -> u32 { 42 } diff --git a/tests/ui/consts/const-eval/conditional_array_execution.rs b/tests/ui/consts/const-eval/conditional_array_execution.rs new file mode 100644 index 000000000..27d5383d6 --- /dev/null +++ b/tests/ui/consts/const-eval/conditional_array_execution.rs @@ -0,0 +1,8 @@ +const X: u32 = 5; +const Y: u32 = 6; +const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; +//~^ ERROR constant + +fn main() { + println!("{}", FOO); +} diff --git a/tests/ui/consts/const-eval/conditional_array_execution.stderr b/tests/ui/consts/const-eval/conditional_array_execution.stderr new file mode 100644 index 000000000..c3401fbae --- /dev/null +++ b/tests/ui/consts/const-eval/conditional_array_execution.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/conditional_array_execution.rs:3:19 + | +LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; + | ^^^^^ attempt to compute `5_u32 - 6_u32`, which would overflow + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/const-eval-intrinsic-promotion.rs b/tests/ui/consts/const-eval/const-eval-intrinsic-promotion.rs new file mode 100644 index 000000000..bdcf53785 --- /dev/null +++ b/tests/ui/consts/const-eval/const-eval-intrinsic-promotion.rs @@ -0,0 +1,6 @@ +#![feature(core_intrinsics)] +fn main() { + // Test that calls to intrinsics are never promoted + let x: &'static usize = + &std::intrinsics::size_of::<i32>(); //~ ERROR temporary value dropped while borrowed +} diff --git a/tests/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr b/tests/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr new file mode 100644 index 000000000..ed6a6ee6e --- /dev/null +++ b/tests/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr @@ -0,0 +1,13 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-eval-intrinsic-promotion.rs:5:10 + | +LL | let x: &'static usize = + | -------------- type annotation requires that borrow lasts for `'static` +LL | &std::intrinsics::size_of::<i32>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/const-eval/const-eval-overflow-2.rs b/tests/ui/consts/const-eval/const-eval-overflow-2.rs new file mode 100644 index 000000000..535d91359 --- /dev/null +++ b/tests/ui/consts/const-eval/const-eval-overflow-2.rs @@ -0,0 +1,20 @@ +// Evaluation of constants in refutable patterns goes through +// different compiler control-flow paths. + +#![allow(unused_imports, warnings)] + +use std::fmt; +use std::{i8, i16, i32, i64, isize}; +use std::{u8, u16, u32, u64, usize}; + +const NEG_128: i8 = -128; +const NEG_NEG_128: i8 = -NEG_128; //~ ERROR constant + +fn main() { + match -128i8 { + NEG_NEG_128 => println!("A"), + //~^ ERROR could not evaluate constant pattern + //~| ERROR could not evaluate constant pattern + _ => println!("B"), + } +} diff --git a/tests/ui/consts/const-eval/const-eval-overflow-2.stderr b/tests/ui/consts/const-eval/const-eval-overflow-2.stderr new file mode 100644 index 000000000..7b1fe49d4 --- /dev/null +++ b/tests/ui/consts/const-eval/const-eval-overflow-2.stderr @@ -0,0 +1,21 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow-2.rs:11:25 + | +LL | const NEG_NEG_128: i8 = -NEG_128; + | ^^^^^^^^ attempt to negate `i8::MIN`, which would overflow + +error: could not evaluate constant pattern + --> $DIR/const-eval-overflow-2.rs:15:9 + | +LL | NEG_NEG_128 => println!("A"), + | ^^^^^^^^^^^ + +error: could not evaluate constant pattern + --> $DIR/const-eval-overflow-2.rs:15:9 + | +LL | NEG_NEG_128 => println!("A"), + | ^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/const-eval-overflow-3.rs b/tests/ui/consts/const-eval/const-eval-overflow-3.rs new file mode 100644 index 000000000..bcc966dc9 --- /dev/null +++ b/tests/ui/consts/const-eval/const-eval-overflow-3.rs @@ -0,0 +1,27 @@ +// Evaluation of constants in array-elem count goes through different +// compiler control-flow paths. +// +// This test is checking the count in an array expression. + + + + + + + +#![allow(unused_imports)] + +use std::fmt; + +const A_I8_I + : [u32; (i8::MAX as usize) + 1] + = [0; (i8::MAX + 1) as usize]; +//~^ ERROR evaluation of constant value failed + +fn main() { + foo(&A_I8_I[..]); +} + +fn foo<T:fmt::Debug>(x: T) { + println!("{:?}", x); +} diff --git a/tests/ui/consts/const-eval/const-eval-overflow-3.stderr b/tests/ui/consts/const-eval/const-eval-overflow-3.stderr new file mode 100644 index 000000000..73f421b5b --- /dev/null +++ b/tests/ui/consts/const-eval/const-eval-overflow-3.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow-3.rs:18:11 + | +LL | = [0; (i8::MAX + 1) as usize]; + | ^^^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8`, which would overflow + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/const-eval-overflow-3b.rs b/tests/ui/consts/const-eval/const-eval-overflow-3b.rs new file mode 100644 index 000000000..480069e67 --- /dev/null +++ b/tests/ui/consts/const-eval/const-eval-overflow-3b.rs @@ -0,0 +1,26 @@ +// Evaluation of constants in array-elem count goes through different +// compiler control-flow paths. +// +// This test is checking the count in an array expression. +// +// This is a variation of another such test, but in this case the +// types for the left- and right-hand sides of the addition do not +// match (as well as overflow). + +#![allow(unused_imports)] + +use std::fmt; + +const A_I8_I + : [u32; (i8::MAX as usize) + 1] + = [0; (i8::MAX + 1u8) as usize]; +//~^ ERROR mismatched types +//~| ERROR cannot add `u8` to `i8` + +fn main() { + foo(&A_I8_I[..]); +} + +fn foo<T:fmt::Debug>(x: T) { + println!("{:?}", x); +} diff --git a/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr b/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr new file mode 100644 index 000000000..f19917001 --- /dev/null +++ b/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr @@ -0,0 +1,23 @@ +error[E0308]: mismatched types + --> $DIR/const-eval-overflow-3b.rs:16:22 + | +LL | = [0; (i8::MAX + 1u8) as usize]; + | ^^^ expected `i8`, found `u8` + +error[E0277]: cannot add `u8` to `i8` in const contexts + --> $DIR/const-eval-overflow-3b.rs:16:20 + | +LL | = [0; (i8::MAX + 1u8) as usize]; + | ^ no implementation for `i8 + u8` + | + = help: the trait `~const Add<u8>` is not implemented for `i8` + = help: the following other types implement trait `Add<Rhs>`: + <&'a i8 as Add<i8>> + <&i8 as Add<&i8>> + <i8 as Add<&i8>> + <i8 as Add> + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/const-eval/const-eval-overflow-4.rs b/tests/ui/consts/const-eval/const-eval-overflow-4.rs new file mode 100644 index 000000000..762c7a968 --- /dev/null +++ b/tests/ui/consts/const-eval/const-eval-overflow-4.rs @@ -0,0 +1,21 @@ +// Evaluation of constants in array-elem count goes through different +// compiler control-flow paths. +// +// This test is checking the count in an array type. + +#![allow(unused_imports)] + +use std::fmt; + +const A_I8_T + : [u32; (i8::MAX as i8 + 1i8) as usize] + //~^ ERROR evaluation of constant value failed + = [0; (i8::MAX as usize) + 1]; + +fn main() { + foo(&A_I8_T[..]); +} + +fn foo<T:fmt::Debug>(x: T) { + println!("{:?}", x); +} diff --git a/tests/ui/consts/const-eval/const-eval-overflow-4.stderr b/tests/ui/consts/const-eval/const-eval-overflow-4.stderr new file mode 100644 index 000000000..94f419319 --- /dev/null +++ b/tests/ui/consts/const-eval/const-eval-overflow-4.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow-4.rs:11:13 + | +LL | : [u32; (i8::MAX as i8 + 1i8) as usize] + | ^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8`, which would overflow + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/const-eval-overflow-4b.rs b/tests/ui/consts/const-eval/const-eval-overflow-4b.rs new file mode 100644 index 000000000..ce9c980de --- /dev/null +++ b/tests/ui/consts/const-eval/const-eval-overflow-4b.rs @@ -0,0 +1,26 @@ +// Evaluation of constants in array-elem count goes through different +// compiler control-flow paths. +// +// This test is checking the count in an array type. + +#![allow(unused_imports)] + +const A_I8_T + : [u32; (i8::MAX as i8 + 1u8) as usize] + //~^ ERROR mismatched types + //~| expected `i8`, found `u8` + //~| ERROR cannot add `u8` to `i8` + = [0; (i8::MAX as usize) + 1]; + + +const A_CHAR_USIZE + : [u32; 5u8 as char as usize] + = [0; 5]; + + +const A_BAD_CHAR_USIZE + : [u32; 5i8 as char as usize] + //~^ ERROR only `u8` can be cast as `char`, not `i8` + = [0; 5]; + +fn main() {} diff --git a/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr b/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr new file mode 100644 index 000000000..1f8e40231 --- /dev/null +++ b/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr @@ -0,0 +1,35 @@ +error[E0308]: mismatched types + --> $DIR/const-eval-overflow-4b.rs:9:30 + | +LL | : [u32; (i8::MAX as i8 + 1u8) as usize] + | ^^^ expected `i8`, found `u8` + +error[E0277]: cannot add `u8` to `i8` in const contexts + --> $DIR/const-eval-overflow-4b.rs:9:28 + | +LL | : [u32; (i8::MAX as i8 + 1u8) as usize] + | ^ no implementation for `i8 + u8` + | + = help: the trait `~const Add<u8>` is not implemented for `i8` + = help: the following other types implement trait `Add<Rhs>`: + <&'a i8 as Add<i8>> + <&i8 as Add<&i8>> + <i8 as Add<&i8>> + <i8 as Add> + +error[E0604]: only `u8` can be cast as `char`, not `i8` + --> $DIR/const-eval-overflow-4b.rs:22:13 + | +LL | : [u32; 5i8 as char as usize] + | ^^^^^^^^^^^ invalid cast + | +help: try casting from `u8` instead + --> $DIR/const-eval-overflow-4b.rs:22:13 + | +LL | : [u32; 5i8 as char as usize] + | ^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0308, E0604. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/const-eval/const-eval-overflow2.rs b/tests/ui/consts/const-eval/const-eval-overflow2.rs new file mode 100644 index 000000000..1676f7c2a --- /dev/null +++ b/tests/ui/consts/const-eval/const-eval-overflow2.rs @@ -0,0 +1,69 @@ +#![allow(unused_imports)] + +// Note: the relevant lint pass here runs before some of the constant +// evaluation below (e.g., that performed by codegen and llvm), so if you +// change this warn to a deny, then the compiler will exit before +// those errors are detected. + +use std::fmt; + +const VALS_I8: (i8,) = + ( + i8::MIN - 1, + ); + //~^^ ERROR evaluation of constant value failed + +const VALS_I16: (i16,) = + ( + i16::MIN - 1, + ); + //~^^ ERROR evaluation of constant value failed + +const VALS_I32: (i32,) = + ( + i32::MIN - 1, + ); + //~^^ ERROR evaluation of constant value failed + +const VALS_I64: (i64,) = + ( + i64::MIN - 1, + ); + //~^^ ERROR evaluation of constant value failed + +const VALS_U8: (u8,) = + ( + u8::MIN - 1, + ); + //~^^ ERROR evaluation of constant value failed + +const VALS_U16: (u16,) = ( + u16::MIN - 1, + ); + //~^^ ERROR evaluation of constant value failed + +const VALS_U32: (u32,) = ( + u32::MIN - 1, + ); + //~^^ ERROR evaluation of constant value failed + +const VALS_U64: (u64,) = + ( + u64::MIN - 1, + ); + //~^^ ERROR evaluation of constant value failed + +fn main() { + foo(VALS_I8); + foo(VALS_I16); + foo(VALS_I32); + foo(VALS_I64); + + foo(VALS_U8); + foo(VALS_U16); + foo(VALS_U32); + foo(VALS_U64); +} + +fn foo<T>(_: T) { +} diff --git a/tests/ui/consts/const-eval/const-eval-overflow2.stderr b/tests/ui/consts/const-eval/const-eval-overflow2.stderr new file mode 100644 index 000000000..341c15daf --- /dev/null +++ b/tests/ui/consts/const-eval/const-eval-overflow2.stderr @@ -0,0 +1,51 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow2.rs:12:6 + | +LL | i8::MIN - 1, + | ^^^^^^^^^^^ attempt to compute `i8::MIN - 1_i8`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow2.rs:18:6 + | +LL | i16::MIN - 1, + | ^^^^^^^^^^^^ attempt to compute `i16::MIN - 1_i16`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow2.rs:24:6 + | +LL | i32::MIN - 1, + | ^^^^^^^^^^^^ attempt to compute `i32::MIN - 1_i32`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow2.rs:30:6 + | +LL | i64::MIN - 1, + | ^^^^^^^^^^^^ attempt to compute `i64::MIN - 1_i64`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow2.rs:36:6 + | +LL | u8::MIN - 1, + | ^^^^^^^^^^^ attempt to compute `0_u8 - 1_u8`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow2.rs:41:6 + | +LL | u16::MIN - 1, + | ^^^^^^^^^^^^ attempt to compute `0_u16 - 1_u16`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow2.rs:46:6 + | +LL | u32::MIN - 1, + | ^^^^^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow2.rs:52:6 + | +LL | u64::MIN - 1, + | ^^^^^^^^^^^^ attempt to compute `0_u64 - 1_u64`, which would overflow + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/const-eval-overflow2b.rs b/tests/ui/consts/const-eval/const-eval-overflow2b.rs new file mode 100644 index 000000000..59d1df568 --- /dev/null +++ b/tests/ui/consts/const-eval/const-eval-overflow2b.rs @@ -0,0 +1,69 @@ +#![allow(unused_imports)] + +// Note: the relevant lint pass here runs before some of the constant +// evaluation below (e.g., that performed by codegen and llvm), so if you +// change this warn to a deny, then the compiler will exit before +// those errors are detected. + +use std::fmt; + +const VALS_I8: (i8,) = + ( + i8::MAX + 1, + ); + //~^^ ERROR evaluation of constant value failed + +const VALS_I16: (i16,) = + ( + i16::MAX + 1, + ); + //~^^ ERROR evaluation of constant value failed + +const VALS_I32: (i32,) = + ( + i32::MAX + 1, + ); + //~^^ ERROR evaluation of constant value failed + +const VALS_I64: (i64,) = + ( + i64::MAX + 1, + ); + //~^^ ERROR evaluation of constant value failed + +const VALS_U8: (u8,) = + ( + u8::MAX + 1, + ); + //~^^ ERROR evaluation of constant value failed + +const VALS_U16: (u16,) = ( + u16::MAX + 1, + ); + //~^^ ERROR evaluation of constant value failed + +const VALS_U32: (u32,) = ( + u32::MAX + 1, + ); + //~^^ ERROR evaluation of constant value failed + +const VALS_U64: (u64,) = + ( + u64::MAX + 1, + ); + //~^^ ERROR evaluation of constant value failed + +fn main() { + foo(VALS_I8); + foo(VALS_I16); + foo(VALS_I32); + foo(VALS_I64); + + foo(VALS_U8); + foo(VALS_U16); + foo(VALS_U32); + foo(VALS_U64); +} + +fn foo<T>(_: T) { +} diff --git a/tests/ui/consts/const-eval/const-eval-overflow2b.stderr b/tests/ui/consts/const-eval/const-eval-overflow2b.stderr new file mode 100644 index 000000000..e661836b4 --- /dev/null +++ b/tests/ui/consts/const-eval/const-eval-overflow2b.stderr @@ -0,0 +1,51 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow2b.rs:12:6 + | +LL | i8::MAX + 1, + | ^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow2b.rs:18:6 + | +LL | i16::MAX + 1, + | ^^^^^^^^^^^^ attempt to compute `i16::MAX + 1_i16`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow2b.rs:24:6 + | +LL | i32::MAX + 1, + | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow2b.rs:30:6 + | +LL | i64::MAX + 1, + | ^^^^^^^^^^^^ attempt to compute `i64::MAX + 1_i64`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow2b.rs:36:6 + | +LL | u8::MAX + 1, + | ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow2b.rs:41:6 + | +LL | u16::MAX + 1, + | ^^^^^^^^^^^^ attempt to compute `u16::MAX + 1_u16`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow2b.rs:46:6 + | +LL | u32::MAX + 1, + | ^^^^^^^^^^^^ attempt to compute `u32::MAX + 1_u32`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow2b.rs:52:6 + | +LL | u64::MAX + 1, + | ^^^^^^^^^^^^ attempt to compute `u64::MAX + 1_u64`, which would overflow + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/const-eval-overflow2c.rs b/tests/ui/consts/const-eval/const-eval-overflow2c.rs new file mode 100644 index 000000000..33b892601 --- /dev/null +++ b/tests/ui/consts/const-eval/const-eval-overflow2c.rs @@ -0,0 +1,69 @@ +#![allow(unused_imports)] + +// Note: the relevant lint pass here runs before some of the constant +// evaluation below (e.g., that performed by codegen and llvm), so if you +// change this warn to a deny, then the compiler will exit before +// those errors are detected. + +use std::fmt; + +const VALS_I8: (i8,) = + ( + i8::MIN * 2, + ); + //~^^ ERROR evaluation of constant value failed + +const VALS_I16: (i16,) = + ( + i16::MIN * 2, + ); + //~^^ ERROR evaluation of constant value failed + +const VALS_I32: (i32,) = + ( + i32::MIN * 2, + ); + //~^^ ERROR evaluation of constant value failed + +const VALS_I64: (i64,) = + ( + i64::MIN * 2, + ); + //~^^ ERROR evaluation of constant value failed + +const VALS_U8: (u8,) = + ( + u8::MAX * 2, + ); + //~^^ ERROR evaluation of constant value failed + +const VALS_U16: (u16,) = ( + u16::MAX * 2, + ); + //~^^ ERROR evaluation of constant value failed + +const VALS_U32: (u32,) = ( + u32::MAX * 2, + ); + //~^^ ERROR evaluation of constant value failed + +const VALS_U64: (u64,) = + ( + u64::MAX * 2, + ); + //~^^ ERROR evaluation of constant value failed + +fn main() { + foo(VALS_I8); + foo(VALS_I16); + foo(VALS_I32); + foo(VALS_I64); + + foo(VALS_U8); + foo(VALS_U16); + foo(VALS_U32); + foo(VALS_U64); +} + +fn foo<T>(_: T) { +} diff --git a/tests/ui/consts/const-eval/const-eval-overflow2c.stderr b/tests/ui/consts/const-eval/const-eval-overflow2c.stderr new file mode 100644 index 000000000..1fad15492 --- /dev/null +++ b/tests/ui/consts/const-eval/const-eval-overflow2c.stderr @@ -0,0 +1,51 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow2c.rs:12:6 + | +LL | i8::MIN * 2, + | ^^^^^^^^^^^ attempt to compute `i8::MIN * 2_i8`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow2c.rs:18:6 + | +LL | i16::MIN * 2, + | ^^^^^^^^^^^^ attempt to compute `i16::MIN * 2_i16`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow2c.rs:24:6 + | +LL | i32::MIN * 2, + | ^^^^^^^^^^^^ attempt to compute `i32::MIN * 2_i32`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow2c.rs:30:6 + | +LL | i64::MIN * 2, + | ^^^^^^^^^^^^ attempt to compute `i64::MIN * 2_i64`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow2c.rs:36:6 + | +LL | u8::MAX * 2, + | ^^^^^^^^^^^ attempt to compute `u8::MAX * 2_u8`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow2c.rs:41:6 + | +LL | u16::MAX * 2, + | ^^^^^^^^^^^^ attempt to compute `u16::MAX * 2_u16`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow2c.rs:46:6 + | +LL | u32::MAX * 2, + | ^^^^^^^^^^^^ attempt to compute `u32::MAX * 2_u32`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-overflow2c.rs:52:6 + | +LL | u64::MAX * 2, + | ^^^^^^^^^^^^ attempt to compute `u64::MAX * 2_u64`, which would overflow + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/const-eval-query-stack.rs b/tests/ui/consts/const-eval/const-eval-query-stack.rs new file mode 100644 index 000000000..8f8a8cee3 --- /dev/null +++ b/tests/ui/consts/const-eval/const-eval-query-stack.rs @@ -0,0 +1,22 @@ +// compile-flags: -Ztreat-err-as-bug=1 +// failure-status: 101 +// rustc-env:RUST_BACKTRACE=1 +// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> "" +// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> "" +// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" +// normalize-stderr-test "note: compiler flags.*\n\n" -> "" +// normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" +// normalize-stderr-test "thread.*panicked.*\n" -> "" +// normalize-stderr-test "stack backtrace:\n" -> "" +// normalize-stderr-test "\s\d{1,}: .*\n" -> "" +// normalize-stderr-test "\s at .*\n" -> "" +// normalize-stderr-test ".*note: Some details.*\n" -> "" + +#![allow(unconditional_panic)] + +const X: i32 = 1 / 0; //~ERROR constant + +fn main() { + let x: &'static i32 = &X; + println!("x={}", x); +} diff --git a/tests/ui/consts/const-eval/const-eval-query-stack.stderr b/tests/ui/consts/const-eval/const-eval-query-stack.stderr new file mode 100644 index 000000000..b97975c4c --- /dev/null +++ b/tests/ui/consts/const-eval/const-eval-query-stack.stderr @@ -0,0 +1,13 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-eval-query-stack.rs:17:16 + | +LL | const X: i32 = 1 / 0; + | ^^^^^ attempt to divide `1_i32` by zero + +query stack during panic: +#0 [eval_to_allocation_raw] const-evaluating + checking `X` +#1 [eval_to_const_value_raw] simplifying constant for the type system `X` +#2 [eval_to_const_value_raw] simplifying constant for the type system `X` +#3 [lint_mod] linting top-level module +#4 [analysis] running analysis passes on this crate +end of query stack diff --git a/tests/ui/consts/const-eval/const-eval-span.rs b/tests/ui/consts/const-eval/const-eval-span.rs new file mode 100644 index 000000000..82f101b47 --- /dev/null +++ b/tests/ui/consts/const-eval/const-eval-span.rs @@ -0,0 +1,14 @@ +// Check that error in constant evaluation of enum discriminant +// provides the context for what caused the evaluation. + +struct S(i32); + +const CONSTANT: S = S(0); + +enum E { + V = CONSTANT, + //~^ ERROR mismatched types + //~| expected `isize`, found struct `S` +} + +fn main() {} diff --git a/tests/ui/consts/const-eval/const-eval-span.stderr b/tests/ui/consts/const-eval/const-eval-span.stderr new file mode 100644 index 000000000..c5b001899 --- /dev/null +++ b/tests/ui/consts/const-eval/const-eval-span.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/const-eval-span.rs:9:9 + | +LL | V = CONSTANT, + | ^^^^^^^^ expected `isize`, found struct `S` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr b/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr new file mode 100644 index 000000000..bf98d0394 --- /dev/null +++ b/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr @@ -0,0 +1,258 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:26:49 + | +LL | const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }.u }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:29:43 + | +LL | const I32_REF_U8_UNION: u8 = unsafe { Nonsense { int_32_ref: &3 }.uint_8 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:32:45 + | +LL | const I32_REF_U16_UNION: u16 = unsafe { Nonsense { int_32_ref: &3 }.uint_16 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:35:45 + | +LL | const I32_REF_U32_UNION: u32 = unsafe { Nonsense { int_32_ref: &3 }.uint_32 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:38:45 + | +LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:41:47 + | +LL | const I32_REF_U128_UNION: u128 = unsafe { Nonsense { int_32_ref: &3 }.uint_128 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:45:43 + | +LL | const I32_REF_I8_UNION: i8 = unsafe { Nonsense { int_32_ref: &3 }.int_8 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:48:45 + | +LL | const I32_REF_I16_UNION: i16 = unsafe { Nonsense { int_32_ref: &3 }.int_16 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:51:45 + | +LL | const I32_REF_I32_UNION: i32 = unsafe { Nonsense { int_32_ref: &3 }.int_32 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:54:45 + | +LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:57:47 + | +LL | const I32_REF_I128_UNION: i128 = unsafe { Nonsense { int_32_ref: &3 }.int_128 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:61:45 + | +LL | const I32_REF_F32_UNION: f32 = unsafe { Nonsense { int_32_ref: &3 }.float_32 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:64:45 + | +LL | const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:67:47 + | +LL | const I32_REF_BOOL_UNION: bool = unsafe { Nonsense { int_32_ref: &3 }.truthy_falsey }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:70:47 + | +LL | const I32_REF_CHAR_UNION: char = unsafe { Nonsense { int_32_ref: &3 }.character }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:73:39 + | +LL | const STR_U8_UNION: u8 = unsafe { Nonsense { stringy: "3" }.uint_8 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:76:41 + | +LL | const STR_U16_UNION: u16 = unsafe { Nonsense { stringy: "3" }.uint_16 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:79:41 + | +LL | const STR_U32_UNION: u32 = unsafe { Nonsense { stringy: "3" }.uint_32 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:82:41 + | +LL | const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:85:43 + | +LL | const STR_U128_UNION: u128 = unsafe { Nonsense { stringy: "3" }.uint_128 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:88:39 + | +LL | const STR_I8_UNION: i8 = unsafe { Nonsense { stringy: "3" }.int_8 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:91:41 + | +LL | const STR_I16_UNION: i16 = unsafe { Nonsense { stringy: "3" }.int_16 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:94:41 + | +LL | const STR_I32_UNION: i32 = unsafe { Nonsense { stringy: "3" }.int_32 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:97:41 + | +LL | const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:100:43 + | +LL | const STR_I128_UNION: i128 = unsafe { Nonsense { stringy: "3" }.int_128 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:103:41 + | +LL | const STR_F32_UNION: f32 = unsafe { Nonsense { stringy: "3" }.float_32 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:106:41 + | +LL | const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:109:43 + | +LL | const STR_BOOL_UNION: bool = unsafe { Nonsense { stringy: "3" }.truthy_falsey }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/const-pointer-values-in-various-types.rs:112:43 + | +LL | const STR_CHAR_UNION: char = unsafe { Nonsense { stringy: "3" }.character }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error: aborting due to 29 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/const-pointer-values-in-various-types.rs b/tests/ui/consts/const-eval/const-pointer-values-in-various-types.rs new file mode 100644 index 000000000..45eed9d84 --- /dev/null +++ b/tests/ui/consts/const-eval/const-pointer-values-in-various-types.rs @@ -0,0 +1,114 @@ +// only-x86_64 +// stderr-per-bitwidth + +#[repr(C)] +union Nonsense { + u: usize, + int_32_ref: &'static i32, + uint_8: u8, + uint_16: u16, + uint_32: u32, + uint_64: u64, + uint_128: u128, + int_8: i8, + int_16: i16, + int_32: i32, + int_64: i64, + int_128: i128, + float_32: f32, + float_64: f64, + truthy_falsey: bool, + character: char, + stringy: &'static str, +} + +fn main() { + const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }.u }; + //~^ ERROR evaluation of constant value failed + + const I32_REF_U8_UNION: u8 = unsafe { Nonsense { int_32_ref: &3 }.uint_8 }; + //~^ ERROR evaluation of constant value failed + + const I32_REF_U16_UNION: u16 = unsafe { Nonsense { int_32_ref: &3 }.uint_16 }; + //~^ ERROR evaluation of constant value failed + + const I32_REF_U32_UNION: u32 = unsafe { Nonsense { int_32_ref: &3 }.uint_32 }; + //~^ ERROR evaluation of constant value failed + + const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 }; + //~^ ERROR evaluation of constant value failed + + const I32_REF_U128_UNION: u128 = unsafe { Nonsense { int_32_ref: &3 }.uint_128 }; + //~^ ERROR evaluation of constant value failed + //~| uninitialized + + const I32_REF_I8_UNION: i8 = unsafe { Nonsense { int_32_ref: &3 }.int_8 }; + //~^ ERROR evaluation of constant value failed + + const I32_REF_I16_UNION: i16 = unsafe { Nonsense { int_32_ref: &3 }.int_16 }; + //~^ ERROR evaluation of constant value failed + + const I32_REF_I32_UNION: i32 = unsafe { Nonsense { int_32_ref: &3 }.int_32 }; + //~^ ERROR evaluation of constant value failed + + const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 }; + //~^ ERROR evaluation of constant value failed + + const I32_REF_I128_UNION: i128 = unsafe { Nonsense { int_32_ref: &3 }.int_128 }; + //~^ ERROR evaluation of constant value failed + //~| uninitialized + + const I32_REF_F32_UNION: f32 = unsafe { Nonsense { int_32_ref: &3 }.float_32 }; + //~^ ERROR evaluation of constant value failed + + const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 }; + //~^ ERROR evaluation of constant value failed + + const I32_REF_BOOL_UNION: bool = unsafe { Nonsense { int_32_ref: &3 }.truthy_falsey }; + //~^ ERROR evaluation of constant value failed + + const I32_REF_CHAR_UNION: char = unsafe { Nonsense { int_32_ref: &3 }.character }; + //~^ ERROR evaluation of constant value failed + + const STR_U8_UNION: u8 = unsafe { Nonsense { stringy: "3" }.uint_8 }; + //~^ ERROR evaluation of constant value failed + + const STR_U16_UNION: u16 = unsafe { Nonsense { stringy: "3" }.uint_16 }; + //~^ ERROR evaluation of constant value failed + + const STR_U32_UNION: u32 = unsafe { Nonsense { stringy: "3" }.uint_32 }; + //~^ ERROR evaluation of constant value failed + + const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 }; + //~^ ERROR evaluation of constant value failed + + const STR_U128_UNION: u128 = unsafe { Nonsense { stringy: "3" }.uint_128 }; + //~^ ERROR evaluation of constant value failed + + const STR_I8_UNION: i8 = unsafe { Nonsense { stringy: "3" }.int_8 }; + //~^ ERROR evaluation of constant value failed + + const STR_I16_UNION: i16 = unsafe { Nonsense { stringy: "3" }.int_16 }; + //~^ ERROR evaluation of constant value failed + + const STR_I32_UNION: i32 = unsafe { Nonsense { stringy: "3" }.int_32 }; + //~^ ERROR evaluation of constant value failed + + const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 }; + //~^ ERROR evaluation of constant value failed + + const STR_I128_UNION: i128 = unsafe { Nonsense { stringy: "3" }.int_128 }; + //~^ ERROR evaluation of constant value failed + + const STR_F32_UNION: f32 = unsafe { Nonsense { stringy: "3" }.float_32 }; + //~^ ERROR evaluation of constant value failed + + const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 }; + //~^ ERROR evaluation of constant value failed + + const STR_BOOL_UNION: bool = unsafe { Nonsense { stringy: "3" }.truthy_falsey }; + //~^ ERROR evaluation of constant value failed + + const STR_CHAR_UNION: char = unsafe { Nonsense { stringy: "3" }.character }; + //~^ ERROR evaluation of constant value failed +} diff --git a/tests/ui/consts/const-eval/const_fn_ptr.rs b/tests/ui/consts/const-eval/const_fn_ptr.rs new file mode 100644 index 000000000..b3c677c69 --- /dev/null +++ b/tests/ui/consts/const-eval/const_fn_ptr.rs @@ -0,0 +1,36 @@ +// run-pass +// compile-flags: -Zunleash-the-miri-inside-of-you + +fn double(x: usize) -> usize { x * 2 } +const fn double_const(x: usize) -> usize { x * 2 } + +const X: fn(usize) -> usize = double; +const X_CONST: fn(usize) -> usize = double_const; + +const fn bar(x: usize) -> usize { + X(x) +} + +const fn bar_const(x: usize) -> usize { + X_CONST(x) +} + +const fn foo(x: fn(usize) -> usize, y: usize) -> usize { + x(y) +} + +fn main() { + const Y: usize = bar_const(2); + assert_eq!(Y, 4); + let y = bar_const(2); + assert_eq!(y, 4); + let y = bar(2); + assert_eq!(y, 4); + + const Z: usize = foo(double_const, 2); + assert_eq!(Z, 4); + let z = foo(double_const, 2); + assert_eq!(z, 4); + let z = foo(double, 2); + assert_eq!(z, 4); +} diff --git a/tests/ui/consts/const-eval/const_fn_ptr.stderr b/tests/ui/consts/const-eval/const_fn_ptr.stderr new file mode 100644 index 000000000..ca1585f88 --- /dev/null +++ b/tests/ui/consts/const-eval/const_fn_ptr.stderr @@ -0,0 +1,20 @@ +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/const_fn_ptr.rs:11:5 + | +LL | X(x) + | ^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_fn_ptr.rs:15:5 + | +LL | X_CONST(x) + | ^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_fn_ptr.rs:19:5 + | +LL | x(y) + | ^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/consts/const-eval/const_fn_ptr_fail.rs b/tests/ui/consts/const-eval/const_fn_ptr_fail.rs new file mode 100644 index 000000000..1896eba82 --- /dev/null +++ b/tests/ui/consts/const-eval/const_fn_ptr_fail.rs @@ -0,0 +1,12 @@ +// run-pass +// compile-flags: -Zunleash-the-miri-inside-of-you +#![allow(unused)] + +fn double(x: usize) -> usize { x * 2 } +const X: fn(usize) -> usize = double; + +const fn bar(x: usize) -> usize { + X(x) // FIXME: this should error someday +} + +fn main() {} diff --git a/tests/ui/consts/const-eval/const_fn_ptr_fail.stderr b/tests/ui/consts/const-eval/const_fn_ptr_fail.stderr new file mode 100644 index 000000000..ec5de5759 --- /dev/null +++ b/tests/ui/consts/const-eval/const_fn_ptr_fail.stderr @@ -0,0 +1,10 @@ +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/const_fn_ptr_fail.rs:9:5 + | +LL | X(x) // FIXME: this should error someday + | ^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/consts/const-eval/const_fn_ptr_fail2.rs b/tests/ui/consts/const-eval/const_fn_ptr_fail2.rs new file mode 100644 index 000000000..b873940c4 --- /dev/null +++ b/tests/ui/consts/const-eval/const_fn_ptr_fail2.rs @@ -0,0 +1,20 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you + +fn double(x: usize) -> usize { + x * 2 +} +const X: fn(usize) -> usize = double; + +const fn bar(x: fn(usize) -> usize, y: usize) -> usize { + x(y) + //~^ ERROR evaluation of constant value failed + //~| ERROR evaluation of constant value failed +} + +const Y: usize = bar(X, 2); // FIXME: should fail to typeck someday +const Z: usize = bar(double, 2); // FIXME: should fail to typeck someday + +fn main() { + assert_eq!(Y, 4); + assert_eq!(Z, 4); +} diff --git a/tests/ui/consts/const-eval/const_fn_ptr_fail2.stderr b/tests/ui/consts/const-eval/const_fn_ptr_fail2.stderr new file mode 100644 index 000000000..0734f479f --- /dev/null +++ b/tests/ui/consts/const-eval/const_fn_ptr_fail2.stderr @@ -0,0 +1,45 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const_fn_ptr_fail2.rs:9:5 + | +LL | x(y) + | ^^^^ calling non-const function `double` + | +note: inside `bar` + --> $DIR/const_fn_ptr_fail2.rs:9:5 + | +LL | x(y) + | ^^^^ +note: inside `Y` + --> $DIR/const_fn_ptr_fail2.rs:14:18 + | +LL | const Y: usize = bar(X, 2); // FIXME: should fail to typeck someday + | ^^^^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $DIR/const_fn_ptr_fail2.rs:9:5 + | +LL | x(y) + | ^^^^ calling non-const function `double` + | +note: inside `bar` + --> $DIR/const_fn_ptr_fail2.rs:9:5 + | +LL | x(y) + | ^^^^ +note: inside `Z` + --> $DIR/const_fn_ptr_fail2.rs:15:18 + | +LL | const Z: usize = bar(double, 2); // FIXME: should fail to typeck someday + | ^^^^^^^^^^^^^^ + +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/const_fn_ptr_fail2.rs:9:5 + | +LL | x(y) + | ^^^^ + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/const_let.rs b/tests/ui/consts/const-eval/const_let.rs new file mode 100644 index 000000000..1e2bcc55b --- /dev/null +++ b/tests/ui/consts/const-eval/const_let.rs @@ -0,0 +1,29 @@ +fn main() {} + +struct FakeNeedsDrop; + +impl Drop for FakeNeedsDrop { + fn drop(&mut self) {} +} + +// ok +const X: FakeNeedsDrop = { let x = FakeNeedsDrop; x }; + +// ok (used to incorrectly error, see #62273) +const X2: FakeNeedsDrop = { let x; x = FakeNeedsDrop; x }; + +// error +const Y: FakeNeedsDrop = { let mut x = FakeNeedsDrop; x = FakeNeedsDrop; x }; +//~^ ERROR destructor of + +// error +const Y2: FakeNeedsDrop = { let mut x; x = FakeNeedsDrop; x = FakeNeedsDrop; x }; +//~^ ERROR destructor of + +// error +const Z: () = { let mut x = None; x = Some(FakeNeedsDrop); }; +//~^ ERROR destructor of + +// error +const Z2: () = { let mut x; x = None; x = Some(FakeNeedsDrop); }; +//~^ ERROR destructor of diff --git a/tests/ui/consts/const-eval/const_let.stderr b/tests/ui/consts/const-eval/const_let.stderr new file mode 100644 index 000000000..63442f557 --- /dev/null +++ b/tests/ui/consts/const-eval/const_let.stderr @@ -0,0 +1,35 @@ +error[E0493]: destructor of `FakeNeedsDrop` cannot be evaluated at compile-time + --> $DIR/const_let.rs:16:32 + | +LL | const Y: FakeNeedsDrop = { let mut x = FakeNeedsDrop; x = FakeNeedsDrop; x }; + | ^^^^^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constants + +error[E0493]: destructor of `FakeNeedsDrop` cannot be evaluated at compile-time + --> $DIR/const_let.rs:20:33 + | +LL | const Y2: FakeNeedsDrop = { let mut x; x = FakeNeedsDrop; x = FakeNeedsDrop; x }; + | ^^^^^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constants + +error[E0493]: destructor of `Option<FakeNeedsDrop>` cannot be evaluated at compile-time + --> $DIR/const_let.rs:24:21 + | +LL | const Z: () = { let mut x = None; x = Some(FakeNeedsDrop); }; + | ^^^^^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constants + +error[E0493]: destructor of `Option<FakeNeedsDrop>` cannot be evaluated at compile-time + --> $DIR/const_let.rs:28:22 + | +LL | const Z2: () = { let mut x; x = None; x = Some(FakeNeedsDrop); }; + | ^^^^^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constants + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/const-eval/const_panic.rs b/tests/ui/consts/const-eval/const_panic.rs new file mode 100644 index 000000000..5b9a8f8e2 --- /dev/null +++ b/tests/ui/consts/const-eval/const_panic.rs @@ -0,0 +1,40 @@ +#![allow(non_fmt_panics)] +#![crate_type = "lib"] + +const MSG: &str = "hello"; + +const Z: () = std::panic!("cheese"); +//~^ ERROR evaluation of constant value failed + +const Z2: () = std::panic!(); +//~^ ERROR evaluation of constant value failed + +const Y: () = std::unreachable!(); +//~^ ERROR evaluation of constant value failed + +const X: () = std::unimplemented!(); +//~^ ERROR evaluation of constant value failed + +const W: () = std::panic!(MSG); +//~^ ERROR evaluation of constant value failed + +const W2: () = std::panic!("{}", MSG); +//~^ ERROR evaluation of constant value failed + +const Z_CORE: () = core::panic!("cheese"); +//~^ ERROR evaluation of constant value failed + +const Z2_CORE: () = core::panic!(); +//~^ ERROR evaluation of constant value failed + +const Y_CORE: () = core::unreachable!(); +//~^ ERROR evaluation of constant value failed + +const X_CORE: () = core::unimplemented!(); +//~^ ERROR evaluation of constant value failed + +const W_CORE: () = core::panic!(MSG); +//~^ ERROR evaluation of constant value failed + +const W2_CORE: () = core::panic!("{}", MSG); +//~^ ERROR evaluation of constant value failed diff --git a/tests/ui/consts/const-eval/const_panic.stderr b/tests/ui/consts/const-eval/const_panic.stderr new file mode 100644 index 000000000..0f7be4607 --- /dev/null +++ b/tests/ui/consts/const-eval/const_panic.stderr @@ -0,0 +1,99 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic.rs:6:15 + | +LL | const Z: () = std::panic!("cheese"); + | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'cheese', $DIR/const_panic.rs:6:15 + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `std::panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic.rs:9:16 + | +LL | const Z2: () = std::panic!(); + | ^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:9:16 + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `std::panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic.rs:12:15 + | +LL | const Y: () = std::unreachable!(); + | ^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:12:15 + | + = note: this error originates in the macro `$crate::panic::unreachable_2015` which comes from the expansion of the macro `std::unreachable` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic.rs:15:15 + | +LL | const X: () = std::unimplemented!(); + | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:15:15 + | + = note: this error originates in the macro `std::unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic.rs:18:15 + | +LL | const W: () = std::panic!(MSG); + | ^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:18:15 + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `std::panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic.rs:21:16 + | +LL | const W2: () = std::panic!("{}", MSG); + | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:21:16 + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `std::panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic.rs:24:20 + | +LL | const Z_CORE: () = core::panic!("cheese"); + | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'cheese', $DIR/const_panic.rs:24:20 + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `core::panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic.rs:27:21 + | +LL | const Z2_CORE: () = core::panic!(); + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:27:21 + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `core::panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic.rs:30:20 + | +LL | const Y_CORE: () = core::unreachable!(); + | ^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:30:20 + | + = note: this error originates in the macro `$crate::panic::unreachable_2015` which comes from the expansion of the macro `core::unreachable` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic.rs:33:20 + | +LL | const X_CORE: () = core::unimplemented!(); + | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:33:20 + | + = note: this error originates in the macro `core::unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic.rs:36:20 + | +LL | const W_CORE: () = core::panic!(MSG); + | ^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:36:20 + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `core::panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic.rs:39:21 + | +LL | const W2_CORE: () = core::panic!("{}", MSG); + | ^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:39:21 + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `core::panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 12 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/const_panic_2021.rs b/tests/ui/consts/const-eval/const_panic_2021.rs new file mode 100644 index 000000000..4702aa2f5 --- /dev/null +++ b/tests/ui/consts/const-eval/const_panic_2021.rs @@ -0,0 +1,34 @@ +// edition:2021 +#![crate_type = "lib"] + +const MSG: &str = "hello"; + +const A: () = std::panic!("blåhaj"); +//~^ ERROR evaluation of constant value failed + +const B: () = std::panic!(); +//~^ ERROR evaluation of constant value failed + +const C: () = std::unreachable!(); +//~^ ERROR evaluation of constant value failed + +const D: () = std::unimplemented!(); +//~^ ERROR evaluation of constant value failed + +const E: () = std::panic!("{}", MSG); +//~^ ERROR evaluation of constant value failed + +const A_CORE: () = core::panic!("shark"); +//~^ ERROR evaluation of constant value failed + +const B_CORE: () = core::panic!(); +//~^ ERROR evaluation of constant value failed + +const C_CORE: () = core::unreachable!(); +//~^ ERROR evaluation of constant value failed + +const D_CORE: () = core::unimplemented!(); +//~^ ERROR evaluation of constant value failed + +const E_CORE: () = core::panic!("{}", MSG); +//~^ ERROR evaluation of constant value failed diff --git a/tests/ui/consts/const-eval/const_panic_2021.stderr b/tests/ui/consts/const-eval/const_panic_2021.stderr new file mode 100644 index 000000000..192fa3a12 --- /dev/null +++ b/tests/ui/consts/const-eval/const_panic_2021.stderr @@ -0,0 +1,83 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_2021.rs:6:15 + | +LL | const A: () = std::panic!("blåhaj"); + | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'blåhaj', $DIR/const_panic_2021.rs:6:15 + | + = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `std::panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_2021.rs:9:15 + | +LL | const B: () = std::panic!(); + | ^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic_2021.rs:9:15 + | + = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `std::panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_2021.rs:12:15 + | +LL | const C: () = std::unreachable!(); + | ^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_2021.rs:12:15 + | + = note: this error originates in the macro `$crate::panic::unreachable_2021` which comes from the expansion of the macro `std::unreachable` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_2021.rs:15:15 + | +LL | const D: () = std::unimplemented!(); + | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_2021.rs:15:15 + | + = note: this error originates in the macro `std::unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_2021.rs:18:15 + | +LL | const E: () = std::panic!("{}", MSG); + | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic_2021.rs:18:15 + | + = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `std::panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_2021.rs:21:20 + | +LL | const A_CORE: () = core::panic!("shark"); + | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'shark', $DIR/const_panic_2021.rs:21:20 + | + = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `core::panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_2021.rs:24:20 + | +LL | const B_CORE: () = core::panic!(); + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic_2021.rs:24:20 + | + = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `core::panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_2021.rs:27:20 + | +LL | const C_CORE: () = core::unreachable!(); + | ^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_2021.rs:27:20 + | + = note: this error originates in the macro `$crate::panic::unreachable_2021` which comes from the expansion of the macro `core::unreachable` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_2021.rs:30:20 + | +LL | const D_CORE: () = core::unimplemented!(); + | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_2021.rs:30:20 + | + = note: this error originates in the macro `core::unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_2021.rs:33:20 + | +LL | const E_CORE: () = core::panic!("{}", MSG); + | ^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic_2021.rs:33:20 + | + = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `core::panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/const_panic_libcore_bin.rs b/tests/ui/consts/const-eval/const_panic_libcore_bin.rs new file mode 100644 index 000000000..d4dc1a51d --- /dev/null +++ b/tests/ui/consts/const-eval/const_panic_libcore_bin.rs @@ -0,0 +1,25 @@ +#![crate_type = "bin"] +#![feature(lang_items)] +#![no_main] +#![no_std] + +use core::panic::PanicInfo; + +const Z: () = panic!("cheese"); +//~^ ERROR evaluation of constant value failed + +const Y: () = unreachable!(); +//~^ ERROR evaluation of constant value failed + +const X: () = unimplemented!(); +//~^ ERROR evaluation of constant value failed + +#[lang = "eh_personality"] +fn eh() {} +#[lang = "eh_catch_typeinfo"] +static EH_CATCH_TYPEINFO: u8 = 0; + +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + loop {} +} diff --git a/tests/ui/consts/const-eval/const_panic_libcore_bin.stderr b/tests/ui/consts/const-eval/const_panic_libcore_bin.stderr new file mode 100644 index 000000000..df19ed4a8 --- /dev/null +++ b/tests/ui/consts/const-eval/const_panic_libcore_bin.stderr @@ -0,0 +1,27 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_libcore_bin.rs:8:15 + | +LL | const Z: () = panic!("cheese"); + | ^^^^^^^^^^^^^^^^ the evaluated program panicked at 'cheese', $DIR/const_panic_libcore_bin.rs:8:15 + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_libcore_bin.rs:11:15 + | +LL | const Y: () = unreachable!(); + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_libcore_bin.rs:11:15 + | + = note: this error originates in the macro `$crate::panic::unreachable_2015` which comes from the expansion of the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_libcore_bin.rs:14:15 + | +LL | const X: () = unimplemented!(); + | ^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_libcore_bin.rs:14:15 + | + = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/const_panic_stability.e2018.stderr b/tests/ui/consts/const-eval/const_panic_stability.e2018.stderr new file mode 100644 index 000000000..3553a18d3 --- /dev/null +++ b/tests/ui/consts/const-eval/const_panic_stability.e2018.stderr @@ -0,0 +1,16 @@ +warning: panic message is not a string literal + --> $DIR/const_panic_stability.rs:14:12 + | +LL | panic!({ "foo" }); + | ^^^^^^^^^ + | + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> + = note: `#[warn(non_fmt_panics)]` on by default +help: add a "{}" format string to `Display` the message + | +LL | panic!("{}", { "foo" }); + | +++++ + +warning: 1 warning emitted + diff --git a/tests/ui/consts/const-eval/const_panic_stability.e2021.stderr b/tests/ui/consts/const-eval/const_panic_stability.e2021.stderr new file mode 100644 index 000000000..9e8179181 --- /dev/null +++ b/tests/ui/consts/const-eval/const_panic_stability.e2021.stderr @@ -0,0 +1,13 @@ +error: format argument must be a string literal + --> $DIR/const_panic_stability.rs:14:12 + | +LL | panic!({ "foo" }); + | ^^^^^^^^^ + | +help: you might be missing a string literal to format with + | +LL | panic!("{}", { "foo" }); + | +++++ + +error: aborting due to previous error + diff --git a/tests/ui/consts/const-eval/const_panic_stability.rs b/tests/ui/consts/const-eval/const_panic_stability.rs new file mode 100644 index 000000000..1aee6f27e --- /dev/null +++ b/tests/ui/consts/const-eval/const_panic_stability.rs @@ -0,0 +1,17 @@ +// revisions: e2018 e2021 +//[e2018] edition:2018 +//[e2021] edition:2021 +//[e2018] check-pass +#![crate_type = "lib"] +#![stable(feature = "foo", since = "1.0.0")] +#![feature(staged_api)] + +#[stable(feature = "foo", since = "1.0.0")] +#[rustc_const_stable(feature = "foo", since = "1.0.0")] +const fn foo() { + assert!(false); + assert!(false, "foo"); + panic!({ "foo" }); + //[e2018]~^ WARNING panic message is not a string literal + //[e2021]~^^ ERROR format argument must be a string literal +} diff --git a/tests/ui/consts/const-eval/const_panic_track_caller.rs b/tests/ui/consts/const-eval/const_panic_track_caller.rs new file mode 100644 index 000000000..9cf7a3ba7 --- /dev/null +++ b/tests/ui/consts/const-eval/const_panic_track_caller.rs @@ -0,0 +1,22 @@ +#![allow(non_fmt_panics)] +#![crate_type = "lib"] + +#[track_caller] +const fn a() -> u32 { + panic!("hey") +} + +#[track_caller] +const fn b() -> u32 { + a() +} + +const fn c() -> u32 { + b() + //~^ ERROR evaluation of constant value failed + //~| NOTE the evaluated program panicked + //~| NOTE inside +} + +const X: u32 = c(); +//~^ NOTE inside diff --git a/tests/ui/consts/const-eval/const_panic_track_caller.stderr b/tests/ui/consts/const-eval/const_panic_track_caller.stderr new file mode 100644 index 000000000..846458176 --- /dev/null +++ b/tests/ui/consts/const-eval/const_panic_track_caller.stderr @@ -0,0 +1,20 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_track_caller.rs:15:5 + | +LL | b() + | ^^^ the evaluated program panicked at 'hey', $DIR/const_panic_track_caller.rs:15:5 + | +note: inside `c` + --> $DIR/const_panic_track_caller.rs:15:5 + | +LL | b() + | ^^^ +note: inside `X` + --> $DIR/const_panic_track_caller.rs:21:16 + | +LL | const X: u32 = c(); + | ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/const_prop_errors.rs b/tests/ui/consts/const-eval/const_prop_errors.rs new file mode 100644 index 000000000..f9a36d379 --- /dev/null +++ b/tests/ui/consts/const-eval/const_prop_errors.rs @@ -0,0 +1,14 @@ +// check-pass + +pub trait Foo { + fn foo(self) -> u32; +} + +impl<T> Foo for T { + fn foo(self) -> u32 { + fn bar<T>() { loop {} } + bar::<T> as u32 + } +} + +fn main() {} diff --git a/tests/ui/consts/const-eval/const_raw_ptr_ops.rs b/tests/ui/consts/const-eval/const_raw_ptr_ops.rs new file mode 100644 index 000000000..cd7c98007 --- /dev/null +++ b/tests/ui/consts/const-eval/const_raw_ptr_ops.rs @@ -0,0 +1,6 @@ +fn main() {} + +// unconst and bad, will thus error in miri +const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR can't compare +// unconst and bad, will thus error in miri +const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR can't compare diff --git a/tests/ui/consts/const-eval/const_raw_ptr_ops.stderr b/tests/ui/consts/const-eval/const_raw_ptr_ops.stderr new file mode 100644 index 000000000..12244450e --- /dev/null +++ b/tests/ui/consts/const-eval/const_raw_ptr_ops.stderr @@ -0,0 +1,29 @@ +error[E0277]: can't compare `*const i32` with `_` in const contexts + --> $DIR/const_raw_ptr_ops.rs:4:43 + | +LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; + | ^^ no implementation for `*const i32 == _` + | + = help: the trait `~const PartialEq<_>` is not implemented for `*const i32` +note: the trait `PartialEq<_>` is implemented for `*const i32`, but that implementation is not `const` + --> $DIR/const_raw_ptr_ops.rs:4:43 + | +LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; + | ^^ + +error[E0277]: can't compare `*const i32` with `_` in const contexts + --> $DIR/const_raw_ptr_ops.rs:6:44 + | +LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; + | ^^ no implementation for `*const i32 == _` + | + = help: the trait `~const PartialEq<_>` is not implemented for `*const i32` +note: the trait `PartialEq<_>` is implemented for `*const i32`, but that implementation is not `const` + --> $DIR/const_raw_ptr_ops.rs:6:44 + | +LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; + | ^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/const-eval/const_raw_ptr_ops2.rs b/tests/ui/consts/const-eval/const_raw_ptr_ops2.rs new file mode 100644 index 000000000..ec5508a1e --- /dev/null +++ b/tests/ui/consts/const-eval/const_raw_ptr_ops2.rs @@ -0,0 +1,10 @@ +fn main() {} + +// fine +const Z: i32 = unsafe { *(&1 as *const i32) }; + +// bad, will thus error in miri +const Z2: i32 = unsafe { *(42 as *const i32) }; //~ ERROR evaluation of constant value failed +//~| is a dangling pointer +const Z3: i32 = unsafe { *(44 as *const i32) }; //~ ERROR evaluation of constant value failed +//~| is a dangling pointer diff --git a/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr b/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr new file mode 100644 index 000000000..e41dea873 --- /dev/null +++ b/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr @@ -0,0 +1,15 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const_raw_ptr_ops2.rs:7:26 + | +LL | const Z2: i32 = unsafe { *(42 as *const i32) }; + | ^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0x2a[noalloc] is a dangling pointer (it has no provenance) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_raw_ptr_ops2.rs:9:26 + | +LL | const Z3: i32 = unsafe { *(44 as *const i32) }; + | ^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0x2c[noalloc] is a dangling pointer (it has no provenance) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/const_signed_pat.rs b/tests/ui/consts/const-eval/const_signed_pat.rs new file mode 100644 index 000000000..c61239bb6 --- /dev/null +++ b/tests/ui/consts/const-eval/const_signed_pat.rs @@ -0,0 +1,9 @@ +// check-pass + +fn main() { + const MIN: i8 = -5; + match 5i8 { + MIN..=-1 => {}, + _ => {}, + } +} diff --git a/tests/ui/consts/const-eval/dangling.rs b/tests/ui/consts/const-eval/dangling.rs new file mode 100644 index 000000000..4fcf87921 --- /dev/null +++ b/tests/ui/consts/const-eval/dangling.rs @@ -0,0 +1,10 @@ +use std::mem; + +// Make sure we error with the right kind of error on a too large slice. +const TEST: () = { unsafe { + let slice: *const [u8] = mem::transmute((1usize, usize::MAX)); + let _val = &*slice; //~ ERROR: evaluation of constant value failed + //~| slice is bigger than largest supported object +} }; + +fn main() {} diff --git a/tests/ui/consts/const-eval/dangling.stderr b/tests/ui/consts/const-eval/dangling.stderr new file mode 100644 index 000000000..92d70573d --- /dev/null +++ b/tests/ui/consts/const-eval/dangling.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/dangling.rs:6:16 + | +LL | let _val = &*slice; + | ^^^^^^^ invalid metadata in wide pointer: slice is bigger than largest supported object + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.rs b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.rs new file mode 100644 index 000000000..4b3cf7073 --- /dev/null +++ b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.rs @@ -0,0 +1,24 @@ +#![unstable(feature = "humans", + reason = "who ever let humans program computers, + we're apparently really bad at it", + issue = "none")] + +#![feature(staged_api)] + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature="foo", issue = "none")] +const fn foo() -> u32 { 42 } + +fn meh() -> u32 { 42 } + +const fn bar() -> u32 { foo() } //~ ERROR `foo` is not yet stable as a const fn + +fn a() { + let _: &'static u32 = &foo(); //~ ERROR temporary value dropped while borrowed +} + +fn main() { + let _: &'static u32 = &meh(); //~ ERROR temporary value dropped while borrowed + let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis(); + //~^ ERROR temporary value dropped while borrowed +} diff --git a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr new file mode 100644 index 000000000..2e697b219 --- /dev/null +++ b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr @@ -0,0 +1,43 @@ +error: `foo` is not yet stable as a const fn + --> $DIR/dont_promote_unstable_const_fn.rs:14:25 + | +LL | const fn bar() -> u32 { foo() } + | ^^^^^ + | + = help: add `#![feature(foo)]` to the crate attributes to enable + +error[E0716]: temporary value dropped while borrowed + --> $DIR/dont_promote_unstable_const_fn.rs:17:28 + | +LL | let _: &'static u32 = &foo(); + | ------------ ^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/dont_promote_unstable_const_fn.rs:21:28 + | +LL | let _: &'static u32 = &meh(); + | ------------ ^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/dont_promote_unstable_const_fn.rs:22:26 + | +LL | let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis(); + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.rs b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.rs new file mode 100644 index 000000000..ea35f4680 --- /dev/null +++ b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.rs @@ -0,0 +1,10 @@ +// aux-build:stability.rs + +extern crate stability; + +use stability::foo; + +fn main() { + let _: &'static u32 = &foo(); //~ ERROR temporary value dropped while borrowed + let _x: &'static u32 = &foo(); //~ ERROR temporary value dropped while borrowed +} diff --git a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.stderr b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.stderr new file mode 100644 index 000000000..aa742d784 --- /dev/null +++ b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.stderr @@ -0,0 +1,24 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/dont_promote_unstable_const_fn_cross_crate.rs:8:28 + | +LL | let _: &'static u32 = &foo(); + | ------------ ^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | let _x: &'static u32 = &foo(); +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/dont_promote_unstable_const_fn_cross_crate.rs:9:29 + | +LL | let _x: &'static u32 = &foo(); + | ------------ ^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/const-eval/double_check.rs b/tests/ui/consts/const-eval/double_check.rs new file mode 100644 index 000000000..56ca0aa1f --- /dev/null +++ b/tests/ui/consts/const-eval/double_check.rs @@ -0,0 +1,25 @@ +// check-pass + +enum Foo { + A = 5, + B = 42, +} +enum Bar { + C = 42, + D = 99, +} +#[repr(C)] +union Union { + foo: &'static Foo, + bar: &'static Bar, + u8: &'static u8, +} +static BAR: u8 = 42; +static FOO: (&Foo, &Bar) = unsafe {( + Union { u8: &BAR }.foo, + Union { u8: &BAR }.bar, +)}; + +static FOO2: (&Foo, &Bar) = unsafe {(std::mem::transmute(&BAR), std::mem::transmute(&BAR))}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/double_check2.rs b/tests/ui/consts/const-eval/double_check2.rs new file mode 100644 index 000000000..81f5dde45 --- /dev/null +++ b/tests/ui/consts/const-eval/double_check2.rs @@ -0,0 +1,32 @@ +// check-pass + +// This test exhibits undefined behavior, but it is very expensive and complex to check for such +// UB in constants. +// Thus, we do not detect it if you create references to statics in ways that are UB. + +enum Foo { + A = 5, + B = 42, +} +enum Bar { + C = 42, + D = 99, +} +#[repr(C)] +union Union { + foo: &'static Foo, + bar: &'static Bar, + u8: &'static u8, +} +static BAR: u8 = 5; +static FOO: (&Foo, &Bar) = unsafe { + ( + // undefined behavior + Union { u8: &BAR }.foo, + Union { u8: &BAR }.bar, + ) +}; +static FOO2: (&Foo, &Bar) = unsafe { (std::mem::transmute(&BAR), std::mem::transmute(&BAR)) }; +//^ undefined behavior + +fn main() {} diff --git a/tests/ui/consts/const-eval/duration_conversion.rs b/tests/ui/consts/const-eval/duration_conversion.rs new file mode 100644 index 000000000..87b12937d --- /dev/null +++ b/tests/ui/consts/const-eval/duration_conversion.rs @@ -0,0 +1,16 @@ +// check-pass + +use std::time::Duration; + +fn main() { + const _ONE_SECOND: Duration = Duration::from_nanos(1_000_000_000); + const _ONE_MILLISECOND: Duration = Duration::from_nanos(1_000_000); + const _ONE_MICROSECOND: Duration = Duration::from_nanos(1_000); + const _ONE_NANOSECOND: Duration = Duration::from_nanos(1); + const _ONE: usize = _ONE_SECOND.as_secs() as usize; + const _TWO: usize = _ONE_MILLISECOND.subsec_millis() as usize; + const _THREE: usize = _ONE_MICROSECOND.subsec_micros() as usize; + const _FOUR: usize = _ONE_NANOSECOND.subsec_nanos() as usize; + const _0: [[u8; _ONE]; _TWO] = [[1; _ONE]; _TWO]; + const _1: [[u8; _THREE]; _FOUR] = [[3; _THREE]; _FOUR]; +} diff --git a/tests/ui/consts/const-eval/enum_discr.rs b/tests/ui/consts/const-eval/enum_discr.rs new file mode 100644 index 000000000..e09258f11 --- /dev/null +++ b/tests/ui/consts/const-eval/enum_discr.rs @@ -0,0 +1,25 @@ +// run-pass + +enum Foo { + X = 42, + Y = Foo::X as isize - 3, +} + +enum Bar { + X, + Y = Bar::X as isize + 2, +} + +enum Boo { + X = Boo::Y as isize * 2, + Y = 9, +} + +fn main() { + assert_eq!(Foo::X as isize, 42); + assert_eq!(Foo::Y as isize, 39); + assert_eq!(Bar::X as isize, 0); + assert_eq!(Bar::Y as isize, 2); + assert_eq!(Boo::X as isize, 18); + assert_eq!(Boo::Y as isize, 9); +} diff --git a/tests/ui/consts/const-eval/erroneous-const.rs b/tests/ui/consts/const-eval/erroneous-const.rs new file mode 100644 index 000000000..e0fd057a2 --- /dev/null +++ b/tests/ui/consts/const-eval/erroneous-const.rs @@ -0,0 +1,21 @@ +//! Make sure we error on erroneous consts even if they are unused. +#![allow(unconditional_panic)] + +struct PrintName<T>(T); +impl<T> PrintName<T> { + const VOID: () = [()][2]; //~ERROR evaluation of `PrintName::<i32>::VOID` failed +} + +const fn no_codegen<T>() { + if false { + // This bad constant is only used in dead code in a no-codegen function... and yet we still + // must make sure that the build fails. + let _ = PrintName::<T>::VOID; //~ constant + } +} + +pub static FOO: () = no_codegen::<i32>(); + +fn main() { + FOO +} diff --git a/tests/ui/consts/const-eval/erroneous-const.stderr b/tests/ui/consts/const-eval/erroneous-const.stderr new file mode 100644 index 000000000..03030392a --- /dev/null +++ b/tests/ui/consts/const-eval/erroneous-const.stderr @@ -0,0 +1,15 @@ +error[E0080]: evaluation of `PrintName::<i32>::VOID` failed + --> $DIR/erroneous-const.rs:6:22 + | +LL | const VOID: () = [()][2]; + | ^^^^^^^ index out of bounds: the length is 1 but the index is 2 + +note: erroneous constant used + --> $DIR/erroneous-const.rs:13:17 + | +LL | let _ = PrintName::<T>::VOID; + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/erroneous-const2.rs b/tests/ui/consts/const-eval/erroneous-const2.rs new file mode 100644 index 000000000..15c0f9107 --- /dev/null +++ b/tests/ui/consts/const-eval/erroneous-const2.rs @@ -0,0 +1,19 @@ +//! Make sure we error on erroneous consts even if they are unused. +#![allow(unconditional_panic)] + +struct PrintName<T>(T); +impl<T> PrintName<T> { + const VOID: () = [()][2]; //~ERROR evaluation of `PrintName::<i32>::VOID` failed +} + +pub static FOO: () = { + if false { + // This bad constant is only used in dead code in a static initializer... and yet we still + // must make sure that the build fails. + let _ = PrintName::<i32>::VOID; //~ constant + } +}; + +fn main() { + FOO +} diff --git a/tests/ui/consts/const-eval/erroneous-const2.stderr b/tests/ui/consts/const-eval/erroneous-const2.stderr new file mode 100644 index 000000000..8626f4d78 --- /dev/null +++ b/tests/ui/consts/const-eval/erroneous-const2.stderr @@ -0,0 +1,15 @@ +error[E0080]: evaluation of `PrintName::<i32>::VOID` failed + --> $DIR/erroneous-const2.rs:6:22 + | +LL | const VOID: () = [()][2]; + | ^^^^^^^ index out of bounds: the length is 1 but the index is 2 + +note: erroneous constant used + --> $DIR/erroneous-const2.rs:13:17 + | +LL | let _ = PrintName::<i32>::VOID; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/extern_fat_pointer.rs b/tests/ui/consts/const-eval/extern_fat_pointer.rs new file mode 100644 index 000000000..d91d07827 --- /dev/null +++ b/tests/ui/consts/const-eval/extern_fat_pointer.rs @@ -0,0 +1,13 @@ +// check-pass + +#![feature(extern_types)] + +extern "C" { + type Opaque; +} + +const FOO: *const u8 = &42 as *const _ as *const Opaque as *const u8; + +fn main() { + let _foo = FOO; +} diff --git a/tests/ui/consts/const-eval/format.rs b/tests/ui/consts/const-eval/format.rs new file mode 100644 index 000000000..0d8b7c12d --- /dev/null +++ b/tests/ui/consts/const-eval/format.rs @@ -0,0 +1,13 @@ +const fn failure() { + panic!("{:?}", 0); + //~^ ERROR cannot call non-const formatting macro in constant functions +} + +const fn print() { + println!("{:?}", 0); + //~^ ERROR cannot call non-const formatting macro in constant functions + //~| ERROR `Arguments::<'a>::new_v1` is not yet stable as a const fn + //~| ERROR cannot call non-const fn `_print` in constant functions +} + +fn main() {} diff --git a/tests/ui/consts/const-eval/format.stderr b/tests/ui/consts/const-eval/format.stderr new file mode 100644 index 000000000..4bf39db58 --- /dev/null +++ b/tests/ui/consts/const-eval/format.stderr @@ -0,0 +1,95 @@ +error[E0015]: cannot call non-const formatting macro in constant functions + --> $DIR/format.rs:2:20 + | +LL | panic!("{:?}", 0); + | ^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = note: this error originates in the macro `$crate::const_format_args` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0015]: cannot call non-const formatting macro in constant functions + --> $DIR/format.rs:7:22 + | +LL | println!("{:?}", 0); + | ^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `Arguments::<'a>::new_v1` is not yet stable as a const fn + --> $DIR/format.rs:7:5 + | +LL | println!("{:?}", 0); + | ^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(const_fmt_arguments_new)]` to the crate attributes to enable + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0015]: cannot call non-const fn `_print` in constant functions + --> $DIR/format.rs:7:5 + | +LL | println!("{:?}", 0); + | ^^^^^^^^^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: erroneous constant used + --> $DIR/format.rs:2:12 + | +LL | panic!("{:?}", 0); + | ^^^^^^ + +note: erroneous constant used + --> $DIR/format.rs:2:12 + | +LL | panic!("{:?}", 0); + | ^^^^^^ + +note: erroneous constant used + --> $DIR/format.rs:2:20 + | +LL | panic!("{:?}", 0); + | ^ + | + = note: this note originates in the macro `$crate::const_format_args` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: erroneous constant used + --> $DIR/format.rs:2:20 + | +LL | panic!("{:?}", 0); + | ^ + | + = note: this note originates in the macro `$crate::const_format_args` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: erroneous constant used + --> $DIR/format.rs:7:14 + | +LL | println!("{:?}", 0); + | ^^^^^^ + +note: erroneous constant used + --> $DIR/format.rs:7:14 + | +LL | println!("{:?}", 0); + | ^^^^^^ + +note: erroneous constant used + --> $DIR/format.rs:7:22 + | +LL | println!("{:?}", 0); + | ^ + | + = note: this note originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: erroneous constant used + --> $DIR/format.rs:7:22 + | +LL | println!("{:?}", 0); + | ^ + | + = note: this note originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/const-eval/generic-slice.rs b/tests/ui/consts/const-eval/generic-slice.rs new file mode 100644 index 000000000..21360a1c4 --- /dev/null +++ b/tests/ui/consts/const-eval/generic-slice.rs @@ -0,0 +1,31 @@ +// Several variants of #64945. + +// This struct is not important, we just use it to put `T` and `'a` in scope for our associated +// consts. +struct Generic<'a, T>(std::marker::PhantomData<&'a T>); + +impl<'a, T: 'static> Generic<'a, T> { + const EMPTY_SLICE: &'a [T] = { + let x: &'a [T] = &[]; + x + }; + + const EMPTY_SLICE_REF: &'a &'static [T] = { + let x: &'static [T] = &[]; + &x + //~^ ERROR `x` does not live long enough + }; +} + +static mut INTERIOR_MUT_AND_DROP: &'static [std::cell::RefCell<Vec<i32>>] = { + let x: &[_] = &[]; + x +}; + +static mut INTERIOR_MUT_AND_DROP_REF: &'static &'static [std::cell::RefCell<Vec<i32>>] = { + let x: &[_] = &[]; + &x + //~^ ERROR `x` does not live long enough +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/generic-slice.stderr b/tests/ui/consts/const-eval/generic-slice.stderr new file mode 100644 index 000000000..c38088df4 --- /dev/null +++ b/tests/ui/consts/const-eval/generic-slice.stderr @@ -0,0 +1,30 @@ +error[E0597]: `x` does not live long enough + --> $DIR/generic-slice.rs:15:9 + | +LL | impl<'a, T: 'static> Generic<'a, T> { + | -- lifetime `'a` defined here +... +LL | &x + | ^^ + | | + | borrowed value does not live long enough + | using this value as a constant requires that `x` is borrowed for `'a` +LL | +LL | }; + | - `x` dropped here while still borrowed + +error[E0597]: `x` does not live long enough + --> $DIR/generic-slice.rs:27:5 + | +LL | &x + | ^^ + | | + | borrowed value does not live long enough + | using this value as a static requires that `x` is borrowed for `'static` +LL | +LL | }; + | - `x` dropped here while still borrowed + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs new file mode 100644 index 000000000..ac9e8b64b --- /dev/null +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs @@ -0,0 +1,15 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_mut_refs)] +use std::intrinsics; + +const FOO: i32 = foo(); +const fn foo() -> i32 { + unsafe { + let _ = intrinsics::const_allocate(4, 3) as *mut i32; + //~^ error: evaluation of constant value failed + } + 1 +} + +fn main() {} diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr new file mode 100644 index 000000000..8f3b3d5f7 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr @@ -0,0 +1,20 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/alloc_intrinsic_errors.rs:9:17 + | +LL | let _ = intrinsics::const_allocate(4, 3) as *mut i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ align has to be a power of 2, `3` is not a power of 2 + | +note: inside `foo` + --> $DIR/alloc_intrinsic_errors.rs:9:17 + | +LL | let _ = intrinsics::const_allocate(4, 3) as *mut i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: inside `FOO` + --> $DIR/alloc_intrinsic_errors.rs:6:18 + | +LL | const FOO: i32 = foo(); + | ^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs new file mode 100644 index 000000000..0a8fc7bca --- /dev/null +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs @@ -0,0 +1,19 @@ +// run-pass +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_mut_refs)] +use std::intrinsics; + +const FOO: &i32 = foo(); + +const fn foo() -> &'static i32 { + let t = unsafe { + let i = intrinsics::const_allocate(4, 4) as * mut i32; + *i = 20; + i + }; + unsafe { &*t } +} +fn main() { + assert_eq!(*FOO, 20) +} diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.rs new file mode 100644 index 000000000..f746f2700 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.rs @@ -0,0 +1,18 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_mut_refs)] +use std::intrinsics; + +const FOO: *const i32 = foo(); +//~^ ERROR untyped pointers are not allowed in constant + +const fn foo() -> &'static i32 { + let t = unsafe { + let i = intrinsics::const_allocate(4, 4) as * mut i32; + *i = 20; + i + }; + unsafe { &*t } +} +fn main() { +} diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.stderr new file mode 100644 index 000000000..00ab0dfc5 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.stderr @@ -0,0 +1,8 @@ +error: untyped pointers are not allowed in constant + --> $DIR/alloc_intrinsic_nontransient_fail.rs:6:1 + | +LL | const FOO: *const i32 = foo(); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_transient.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_transient.rs new file mode 100644 index 000000000..92193bb33 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_transient.rs @@ -0,0 +1,19 @@ +// run-pass +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_mut_refs)] +use std::intrinsics; + +const FOO: i32 = foo(); + +const fn foo() -> i32 { + let t = unsafe { + let i = intrinsics::const_allocate(4, 4) as * mut i32; + *i = 20; + i + }; + unsafe { *t } +} +fn main() { + assert_eq!(FOO, 20); +} diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr new file mode 100644 index 000000000..a0f4519ea --- /dev/null +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr @@ -0,0 +1,14 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/alloc_intrinsic_uninit.rs:8:1 + | +LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; + | ^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized memory, but expected an integer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + ╾─alloc2──╼ │ ╾──╼ + } + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr new file mode 100644 index 000000000..d2bffa425 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr @@ -0,0 +1,14 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/alloc_intrinsic_uninit.rs:8:1 + | +LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; + | ^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized memory, but expected an integer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + ╾───────alloc2────────╼ │ ╾──────╼ + } + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs new file mode 100644 index 000000000..b53c9ac7a --- /dev/null +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs @@ -0,0 +1,10 @@ +// stderr-per-bitwidth +// compile-test +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_mut_refs)] +use std::intrinsics; + +const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; +//~^ error: it is undefined behavior to use this value +fn main() {} diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs new file mode 100644 index 000000000..77871c394 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs @@ -0,0 +1,9 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_mut_refs)] +use std::intrinsics; + +const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32}; +//~^ error: untyped pointers are not allowed in constant + +fn main() {} diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr new file mode 100644 index 000000000..36002b850 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr @@ -0,0 +1,8 @@ +error: untyped pointers are not allowed in constant + --> $DIR/alloc_intrinsic_untyped.rs:6:1 + | +LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32}; + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs new file mode 100644 index 000000000..407e69d41 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs @@ -0,0 +1,16 @@ +// run-pass +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(inline_const)] + +use std::intrinsics; + +struct ZST; + +fn main() { + const { + unsafe { + let _ = intrinsics::const_allocate(0, 0) as *mut ZST; + } + } +} diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic.rs b/tests/ui/consts/const-eval/heap/dealloc_intrinsic.rs new file mode 100644 index 000000000..aac90cd54 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic.rs @@ -0,0 +1,36 @@ +// run-pass +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_mut_refs)] + +use std::intrinsics; + +const _X: () = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + intrinsics::const_deallocate(ptr, 4, 4); +}; + +const Y: &u32 = unsafe { + let ptr = intrinsics::const_allocate(4, 4) as *mut u32; + *ptr = 42; + &*ptr +}; + +const Z: &u32 = &42; + +const _Z: () = unsafe { + let ptr1 = Y as *const _ as *mut u8; + intrinsics::const_deallocate(ptr1, 4, 4); // nop + intrinsics::const_deallocate(ptr1, 2, 4); // nop + intrinsics::const_deallocate(ptr1, 4, 2); // nop + + let ptr2 = Z as *const _ as *mut u8; + intrinsics::const_deallocate(ptr2, 4, 4); // nop + intrinsics::const_deallocate(ptr2, 2, 4); // nop + intrinsics::const_deallocate(ptr2, 4, 2); // nop +}; + +fn main() { + assert_eq!(*Y, 42); + assert_eq!(*Z, 42); +} diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs new file mode 100644 index 000000000..b6d89a58d --- /dev/null +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs @@ -0,0 +1,22 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_mut_refs)] + +use std::intrinsics; + +const _X: &'static u8 = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + intrinsics::const_deallocate(ptr, 4, 4); + &*ptr + //~^ error: evaluation of constant value failed +}; + +const _Y: u8 = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + let reference = &*ptr; + intrinsics::const_deallocate(ptr, 4, 4); + *reference + //~^ error: evaluation of constant value failed +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr new file mode 100644 index 000000000..4eb1c42e1 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr @@ -0,0 +1,15 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/dealloc_intrinsic_dangling.rs:10:5 + | +LL | &*ptr + | ^^^^^ pointer to alloc2 was dereferenced after this allocation got freed + +error[E0080]: evaluation of constant value failed + --> $DIR/dealloc_intrinsic_dangling.rs:18:5 + | +LL | *reference + | ^^^^^^^^^^ pointer to alloc4 was dereferenced after this allocation got freed + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs new file mode 100644 index 000000000..4010b4769 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs @@ -0,0 +1,13 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] + +use std::intrinsics; + +const _X: () = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + intrinsics::const_deallocate(ptr, 4, 4); + intrinsics::const_deallocate(ptr, 4, 4); + //~^ error: evaluation of constant value failed +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr new file mode 100644 index 000000000..8177a0850 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/dealloc_intrinsic_duplicate.rs:9:5 + | +LL | intrinsics::const_deallocate(ptr, 4, 4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to alloc2 was dereferenced after this allocation got freed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs new file mode 100644 index 000000000..031d70fdc --- /dev/null +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs @@ -0,0 +1,29 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] + +use std::intrinsics; + +const _X: () = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + intrinsics::const_deallocate(ptr, 4, 2); + //~^ error: evaluation of constant value failed +}; +const _Y: () = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + intrinsics::const_deallocate(ptr, 2, 4); + //~^ error: evaluation of constant value failed +}; + +const _Z: () = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + intrinsics::const_deallocate(ptr, 3, 4); + //~^ error: evaluation of constant value failed +}; + +const _W: () = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + intrinsics::const_deallocate(ptr, 4, 3); + //~^ error: evaluation of constant value failed +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr new file mode 100644 index 000000000..650b409b1 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr @@ -0,0 +1,27 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/dealloc_intrinsic_incorrect_layout.rs:8:5 + | +LL | intrinsics::const_deallocate(ptr, 4, 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: alloc2 has size 4 and alignment 4, but gave size 4 and alignment 2 + +error[E0080]: evaluation of constant value failed + --> $DIR/dealloc_intrinsic_incorrect_layout.rs:13:5 + | +LL | intrinsics::const_deallocate(ptr, 2, 4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: alloc4 has size 4 and alignment 4, but gave size 2 and alignment 4 + +error[E0080]: evaluation of constant value failed + --> $DIR/dealloc_intrinsic_incorrect_layout.rs:19:5 + | +LL | intrinsics::const_deallocate(ptr, 3, 4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: alloc6 has size 4 and alignment 4, but gave size 3 and alignment 4 + +error[E0080]: evaluation of constant value failed + --> $DIR/dealloc_intrinsic_incorrect_layout.rs:25:5 + | +LL | intrinsics::const_deallocate(ptr, 4, 3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ align has to be a power of 2, `3` is not a power of 2 + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs new file mode 100644 index 000000000..84fb4d2ea --- /dev/null +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs @@ -0,0 +1,17 @@ +// run-pass +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(inline_const)] + +use std::intrinsics; + +fn main() { + const { + unsafe { + let ptr1 = intrinsics::const_allocate(0, 0); + let ptr2 = intrinsics::const_allocate(0, 0); + intrinsics::const_deallocate(ptr1, 0, 0); + intrinsics::const_deallocate(ptr2, 0, 0); + } + } +} diff --git a/tests/ui/consts/const-eval/ice-generic-assoc-const.rs b/tests/ui/consts/const-eval/ice-generic-assoc-const.rs new file mode 100644 index 000000000..e514682af --- /dev/null +++ b/tests/ui/consts/const-eval/ice-generic-assoc-const.rs @@ -0,0 +1,16 @@ +// build-pass (tests post-monomorphisation failure) +#![crate_type = "lib"] + +pub trait Nullable { + const NULL: Self; + + fn is_null(&self) -> bool; +} + +impl<T> Nullable for *const T { + const NULL: Self = core::ptr::null::<T>(); + + fn is_null(&self) -> bool { + *self == Self::NULL + } +} diff --git a/tests/ui/consts/const-eval/ice-packed.rs b/tests/ui/consts/const-eval/ice-packed.rs new file mode 100644 index 000000000..4758a5a9d --- /dev/null +++ b/tests/ui/consts/const-eval/ice-packed.rs @@ -0,0 +1,21 @@ +// Regression test for #50356: Compiler panic when using repr(packed) +// associated constant in a match arm + +// check-pass +#[derive(Copy, Clone, PartialEq, Eq)] +#[repr(packed)] +pub struct Num(u64); + +impl Num { + pub const ZERO: Self = Num(0); +} + +pub fn decrement(a: Num) -> Num { + match a { + Num::ZERO => Num::ZERO, + a => Num(a.0 - 1) + } +} + +fn main() { +} diff --git a/tests/ui/consts/const-eval/index-out-of-bounds-never-type.rs b/tests/ui/consts/const-eval/index-out-of-bounds-never-type.rs new file mode 100644 index 000000000..bc2ea3f18 --- /dev/null +++ b/tests/ui/consts/const-eval/index-out-of-bounds-never-type.rs @@ -0,0 +1,21 @@ +// build-fail + +// Regression test for #66975 +#![warn(unconditional_panic)] +#![feature(never_type)] + +struct PrintName<T>(T); + +impl<T> PrintName<T> { + const VOID: ! = { let x = 0 * std::mem::size_of::<T>(); [][x] }; + //~^ ERROR evaluation of `PrintName::<()>::VOID` failed + +} + +fn f<T>() { + let _ = PrintName::<T>::VOID; +} + +pub fn main() { + f::<()>(); +} diff --git a/tests/ui/consts/const-eval/index-out-of-bounds-never-type.stderr b/tests/ui/consts/const-eval/index-out-of-bounds-never-type.stderr new file mode 100644 index 000000000..8bcd03005 --- /dev/null +++ b/tests/ui/consts/const-eval/index-out-of-bounds-never-type.stderr @@ -0,0 +1,15 @@ +error[E0080]: evaluation of `PrintName::<()>::VOID` failed + --> $DIR/index-out-of-bounds-never-type.rs:10:61 + | +LL | const VOID: ! = { let x = 0 * std::mem::size_of::<T>(); [][x] }; + | ^^^^^ index out of bounds: the length is 0 but the index is 0 + +note: the above error was encountered while instantiating `fn f::<()>` + --> $DIR/index-out-of-bounds-never-type.rs:20:5 + | +LL | f::<()>(); + | ^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/index_out_of_bounds.rs b/tests/ui/consts/const-eval/index_out_of_bounds.rs new file mode 100644 index 000000000..80e0d28fe --- /dev/null +++ b/tests/ui/consts/const-eval/index_out_of_bounds.rs @@ -0,0 +1,4 @@ +static FOO: i32 = [][0]; +//~^ ERROR E0080 + +fn main() {} diff --git a/tests/ui/consts/const-eval/index_out_of_bounds.stderr b/tests/ui/consts/const-eval/index_out_of_bounds.stderr new file mode 100644 index 000000000..8bb3a0c67 --- /dev/null +++ b/tests/ui/consts/const-eval/index_out_of_bounds.stderr @@ -0,0 +1,9 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/index_out_of_bounds.rs:1:19 + | +LL | static FOO: i32 = [][0]; + | ^^^^^ index out of bounds: the length is 0 but the index is 0 + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/index_out_of_bounds_propagated.rs b/tests/ui/consts/const-eval/index_out_of_bounds_propagated.rs new file mode 100644 index 000000000..608e6e112 --- /dev/null +++ b/tests/ui/consts/const-eval/index_out_of_bounds_propagated.rs @@ -0,0 +1,6 @@ +// build-fail + +fn main() { + let array = [std::env::args().len()]; + array[1]; //~ ERROR operation will panic +} diff --git a/tests/ui/consts/const-eval/index_out_of_bounds_propagated.stderr b/tests/ui/consts/const-eval/index_out_of_bounds_propagated.stderr new file mode 100644 index 000000000..d247d691d --- /dev/null +++ b/tests/ui/consts/const-eval/index_out_of_bounds_propagated.stderr @@ -0,0 +1,10 @@ +error: this operation will panic at runtime + --> $DIR/index_out_of_bounds_propagated.rs:5:5 + | +LL | array[1]; + | ^^^^^^^^ index out of bounds: the length is 1 but the index is 1 + | + = note: `#[deny(unconditional_panic)]` on by default + +error: aborting due to previous error + diff --git a/tests/ui/consts/const-eval/infinite_loop.rs b/tests/ui/consts/const-eval/infinite_loop.rs new file mode 100644 index 000000000..4babc9a28 --- /dev/null +++ b/tests/ui/consts/const-eval/infinite_loop.rs @@ -0,0 +1,12 @@ +fn main() { + // Tests the Collatz conjecture with an incorrect base case (0 instead of 1). + // The value of `n` will loop indefinitely (4 - 2 - 1 - 4). + let _ = [(); { + let mut n = 113383; // #20 in https://oeis.org/A006884 + while n != 0 { + //~^ ERROR evaluation of constant value failed + n = if n % 2 == 0 { n/2 } else { 3*n + 1 }; + } + n + }]; +} diff --git a/tests/ui/consts/const-eval/infinite_loop.stderr b/tests/ui/consts/const-eval/infinite_loop.stderr new file mode 100644 index 000000000..8b58cb279 --- /dev/null +++ b/tests/ui/consts/const-eval/infinite_loop.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/infinite_loop.rs:6:15 + | +LL | while n != 0 { + | ^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/issue-100878.rs b/tests/ui/consts/const-eval/issue-100878.rs new file mode 100644 index 000000000..353ce5050 --- /dev/null +++ b/tests/ui/consts/const-eval/issue-100878.rs @@ -0,0 +1,8 @@ +// This checks that the const-eval ICE in issue #100878 does not recur. +// +// build-pass +pub fn bitshift_data(data: [u8; 1]) -> u8 { + data[0] << 8 +} + +fn main() {} diff --git a/tests/ui/consts/const-eval/issue-104390.rs b/tests/ui/consts/const-eval/issue-104390.rs new file mode 100644 index 000000000..602d81824 --- /dev/null +++ b/tests/ui/consts/const-eval/issue-104390.rs @@ -0,0 +1,10 @@ +fn f1() -> impl Sized { & 2E } //~ ERROR expected at least one digit in exponent +fn f2() -> impl Sized { && 2E } //~ ERROR expected at least one digit in exponent +fn f3() -> impl Sized { &'a 2E } //~ ERROR expected at least one digit in exponent +//~^ ERROR borrow expressions cannot be annotated with lifetimes +fn f4() -> impl Sized { &'static 2E } //~ ERROR expected at least one digit in exponent +//~^ ERROR borrow expressions cannot be annotated with lifetimes +fn f5() -> impl Sized { *& 2E } //~ ERROR expected at least one digit in exponent +fn f6() -> impl Sized { &'_ 2E } //~ ERROR expected at least one digit in exponent +//~^ ERROR borrow expressions cannot be annotated with lifetimes +fn main() {} diff --git a/tests/ui/consts/const-eval/issue-104390.stderr b/tests/ui/consts/const-eval/issue-104390.stderr new file mode 100644 index 000000000..865b9996e --- /dev/null +++ b/tests/ui/consts/const-eval/issue-104390.stderr @@ -0,0 +1,65 @@ +error: expected at least one digit in exponent + --> $DIR/issue-104390.rs:1:27 + | +LL | fn f1() -> impl Sized { & 2E } + | ^^ + +error: expected at least one digit in exponent + --> $DIR/issue-104390.rs:2:28 + | +LL | fn f2() -> impl Sized { && 2E } + | ^^ + +error: expected at least one digit in exponent + --> $DIR/issue-104390.rs:3:29 + | +LL | fn f3() -> impl Sized { &'a 2E } + | ^^ + +error: expected at least one digit in exponent + --> $DIR/issue-104390.rs:5:34 + | +LL | fn f4() -> impl Sized { &'static 2E } + | ^^ + +error: expected at least one digit in exponent + --> $DIR/issue-104390.rs:7:28 + | +LL | fn f5() -> impl Sized { *& 2E } + | ^^ + +error: expected at least one digit in exponent + --> $DIR/issue-104390.rs:8:29 + | +LL | fn f6() -> impl Sized { &'_ 2E } + | ^^ + +error: borrow expressions cannot be annotated with lifetimes + --> $DIR/issue-104390.rs:3:25 + | +LL | fn f3() -> impl Sized { &'a 2E } + | ^--^^^ + | | + | annotated with lifetime here + | help: remove the lifetime annotation + +error: borrow expressions cannot be annotated with lifetimes + --> $DIR/issue-104390.rs:5:25 + | +LL | fn f4() -> impl Sized { &'static 2E } + | ^-------^^^ + | | + | annotated with lifetime here + | help: remove the lifetime annotation + +error: borrow expressions cannot be annotated with lifetimes + --> $DIR/issue-104390.rs:8:25 + | +LL | fn f6() -> impl Sized { &'_ 2E } + | ^--^^^ + | | + | annotated with lifetime here + | help: remove the lifetime annotation + +error: aborting due to 9 previous errors + diff --git a/tests/ui/consts/const-eval/issue-43197.rs b/tests/ui/consts/const-eval/issue-43197.rs new file mode 100644 index 000000000..145463f0a --- /dev/null +++ b/tests/ui/consts/const-eval/issue-43197.rs @@ -0,0 +1,11 @@ +const fn foo(x: u32) -> u32 { + x +} + +fn main() { + const X: u32 = 0 - 1; + //~^ ERROR constant + const Y: u32 = foo(0 - 1); + //~^ ERROR constant + println!("{} {}", X, Y); +} diff --git a/tests/ui/consts/const-eval/issue-43197.stderr b/tests/ui/consts/const-eval/issue-43197.stderr new file mode 100644 index 000000000..c59f13e48 --- /dev/null +++ b/tests/ui/consts/const-eval/issue-43197.stderr @@ -0,0 +1,15 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/issue-43197.rs:6:20 + | +LL | const X: u32 = 0 - 1; + | ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow + +error[E0080]: evaluation of constant value failed + --> $DIR/issue-43197.rs:8:24 + | +LL | const Y: u32 = foo(0 - 1); + | ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/issue-44578.rs b/tests/ui/consts/const-eval/issue-44578.rs new file mode 100644 index 000000000..e4dcc6230 --- /dev/null +++ b/tests/ui/consts/const-eval/issue-44578.rs @@ -0,0 +1,27 @@ +// build-fail + +trait Foo { + const AMT: usize; +} + +enum Bar<A, B> { + First(A), + Second(B), +} + +impl<A: Foo, B: Foo> Foo for Bar<A, B> { + const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize]; //~ERROR evaluation of `<Bar<u16, u8> as Foo>::AMT` failed +} + +impl Foo for u8 { + const AMT: usize = 1; +} + +impl Foo for u16 { + const AMT: usize = 2; +} + +fn main() { + println!("{}", <Bar<u16, u8> as Foo>::AMT); + //~^ constant +} diff --git a/tests/ui/consts/const-eval/issue-44578.stderr b/tests/ui/consts/const-eval/issue-44578.stderr new file mode 100644 index 000000000..0cbf54480 --- /dev/null +++ b/tests/ui/consts/const-eval/issue-44578.stderr @@ -0,0 +1,39 @@ +error[E0080]: evaluation of `<Bar<u16, u8> as Foo>::AMT` failed + --> $DIR/issue-44578.rs:13:24 + | +LL | const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1 + +note: erroneous constant used + --> $DIR/issue-44578.rs:25:20 + | +LL | println!("{}", <Bar<u16, u8> as Foo>::AMT); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: erroneous constant used + --> $DIR/issue-44578.rs:25:20 + | +LL | println!("{}", <Bar<u16, u8> as Foo>::AMT); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this note originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: erroneous constant used + --> $DIR/issue-44578.rs:25:20 + | +LL | println!("{}", <Bar<u16, u8> as Foo>::AMT); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this note originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: erroneous constant used + --> $DIR/issue-44578.rs:25:20 + | +LL | println!("{}", <Bar<u16, u8> as Foo>::AMT); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this note originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/issue-47971.rs b/tests/ui/consts/const-eval/issue-47971.rs new file mode 100644 index 000000000..b98e76031 --- /dev/null +++ b/tests/ui/consts/const-eval/issue-47971.rs @@ -0,0 +1,9 @@ +// check-pass + +struct S(pub &'static u32, pub u32); + +const fn g(ss: &S) -> &u32 { &ss.1 } + +static T: S = S(g(&T), 0); + +fn main () { } diff --git a/tests/ui/consts/const-eval/issue-49296.rs b/tests/ui/consts/const-eval/issue-49296.rs new file mode 100644 index 000000000..917777a32 --- /dev/null +++ b/tests/ui/consts/const-eval/issue-49296.rs @@ -0,0 +1,14 @@ +// issue-49296: Unsafe shenigans in constants can result in missing errors + +use std::mem::transmute; + +const fn wat(x: u64) -> &'static u64 { + unsafe { transmute(&x) } +} + +const X: u64 = *wat(42); +//~^ ERROR evaluation of constant value failed + +fn main() { + println!("{}", X); +} diff --git a/tests/ui/consts/const-eval/issue-49296.stderr b/tests/ui/consts/const-eval/issue-49296.stderr new file mode 100644 index 000000000..cc4f1594c --- /dev/null +++ b/tests/ui/consts/const-eval/issue-49296.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/issue-49296.rs:9:16 + | +LL | const X: u64 = *wat(42); + | ^^^^^^^^ pointer to alloc3 was dereferenced after this allocation got freed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/issue-50706.rs b/tests/ui/consts/const-eval/issue-50706.rs new file mode 100644 index 000000000..a13c27f2e --- /dev/null +++ b/tests/ui/consts/const-eval/issue-50706.rs @@ -0,0 +1,37 @@ +// check-pass + +pub struct Stats; + +#[derive(PartialEq, Eq)] +pub struct StatVariant { + pub id: u8, + _priv: (), +} + +#[derive(PartialEq, Eq)] +pub struct Stat { + pub variant: StatVariant, + pub index: usize, + _priv: (), +} + +impl Stats { + pub const TEST: StatVariant = StatVariant{id: 0, _priv: (),}; + #[allow(non_upper_case_globals)] + pub const A: Stat = Stat{ + variant: Self::TEST, + index: 0, + _priv: (),}; +} + +impl Stat { + pub fn from_index(variant: StatVariant, index: usize) -> Option<Stat> { + let stat = Stat{variant, index, _priv: (),}; + match stat { + Stats::A => Some(Stats::A), + _ => None, + } + } +} + +fn main() {} diff --git a/tests/ui/consts/const-eval/issue-50814-2.rs b/tests/ui/consts/const-eval/issue-50814-2.rs new file mode 100644 index 000000000..53eb7b149 --- /dev/null +++ b/tests/ui/consts/const-eval/issue-50814-2.rs @@ -0,0 +1,34 @@ +// build-fail + +trait C { + const BOO: usize; +} + +trait Foo<T> { + const BAR: usize; +} + +struct A<T>(T); + +impl<T: C> Foo<T> for A<T> { + const BAR: usize = [5, 6, 7][T::BOO]; //~ ERROR evaluation of `<A<()> as Foo<()>>::BAR` failed +} + +fn foo<T: C>() -> &'static usize { + &<A<T> as Foo<T>>::BAR //~ constant +} + +impl C for () { + const BOO: usize = 42; +} + +impl C for u32 { + const BOO: usize = 1; +} + +fn main() { + println!("{:x}", foo::<()>() as *const usize as usize); + println!("{:x}", foo::<u32>() as *const usize as usize); + println!("{:x}", foo::<()>()); + println!("{:x}", foo::<u32>()); +} diff --git a/tests/ui/consts/const-eval/issue-50814-2.stderr b/tests/ui/consts/const-eval/issue-50814-2.stderr new file mode 100644 index 000000000..956f7aec9 --- /dev/null +++ b/tests/ui/consts/const-eval/issue-50814-2.stderr @@ -0,0 +1,21 @@ +error[E0080]: evaluation of `<A<()> as Foo<()>>::BAR` failed + --> $DIR/issue-50814-2.rs:14:24 + | +LL | const BAR: usize = [5, 6, 7][T::BOO]; + | ^^^^^^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 42 + +note: erroneous constant used + --> $DIR/issue-50814-2.rs:18:6 + | +LL | &<A<T> as Foo<T>>::BAR + | ^^^^^^^^^^^^^^^^^^^^^ + +note: the above error was encountered while instantiating `fn foo::<()>` + --> $DIR/issue-50814-2.rs:30:22 + | +LL | println!("{:x}", foo::<()>() as *const usize as usize); + | ^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/issue-50814.rs b/tests/ui/consts/const-eval/issue-50814.rs new file mode 100644 index 000000000..374ed1d93 --- /dev/null +++ b/tests/ui/consts/const-eval/issue-50814.rs @@ -0,0 +1,26 @@ +// build-fail + +trait Unsigned { + const MAX: u8; +} + +struct U8(u8); +impl Unsigned for U8 { + const MAX: u8 = 0xff; +} + +struct Sum<A, B>(A, B); + +impl<A: Unsigned, B: Unsigned> Unsigned for Sum<A, B> { + const MAX: u8 = A::MAX + B::MAX; + //~^ ERROR evaluation of `<Sum<U8, U8> as Unsigned>::MAX` failed +} + +fn foo<T>(_: T) -> &'static u8 { + &Sum::<U8, U8>::MAX + //~^ constant +} + +fn main() { + foo(0); +} diff --git a/tests/ui/consts/const-eval/issue-50814.stderr b/tests/ui/consts/const-eval/issue-50814.stderr new file mode 100644 index 000000000..05b6271f4 --- /dev/null +++ b/tests/ui/consts/const-eval/issue-50814.stderr @@ -0,0 +1,21 @@ +error[E0080]: evaluation of `<Sum<U8, U8> as Unsigned>::MAX` failed + --> $DIR/issue-50814.rs:15:21 + | +LL | const MAX: u8 = A::MAX + B::MAX; + | ^^^^^^^^^^^^^^^ attempt to compute `u8::MAX + u8::MAX`, which would overflow + +note: erroneous constant used + --> $DIR/issue-50814.rs:20:6 + | +LL | &Sum::<U8, U8>::MAX + | ^^^^^^^^^^^^^^^^^^ + +note: the above error was encountered while instantiating `fn foo::<i32>` + --> $DIR/issue-50814.rs:25:5 + | +LL | foo(0); + | ^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/issue-51300.rs b/tests/ui/consts/const-eval/issue-51300.rs new file mode 100644 index 000000000..8e68e8c91 --- /dev/null +++ b/tests/ui/consts/const-eval/issue-51300.rs @@ -0,0 +1,31 @@ +// check-pass +// https://github.com/rust-lang/rust/issues/51300 + +#[derive(PartialEq, Eq, Clone, Copy)] +pub struct Stat { + pub id: u8, + pub index: usize, +} + +impl Stat { + pub const STUDENT_HAPPINESS: Stat = Stat{ + id: 0, + index: 0, + }; + pub const STUDENT_HUNGER: Stat = Stat{ + id: 0, + index: Self::STUDENT_HAPPINESS.index + 1, + }; + +} + +pub fn from_index(id: u8, index: usize) -> Option<Stat> { + let stat = Stat{id, index}; + match stat { + Stat::STUDENT_HAPPINESS => Some(Stat::STUDENT_HAPPINESS), + Stat::STUDENT_HUNGER => Some(Stat::STUDENT_HUNGER), + _ => None, + } +} + +fn main() { } diff --git a/tests/ui/consts/const-eval/issue-52475.rs b/tests/ui/consts/const-eval/issue-52475.rs new file mode 100644 index 000000000..ce65407bb --- /dev/null +++ b/tests/ui/consts/const-eval/issue-52475.rs @@ -0,0 +1,11 @@ +fn main() { + let _ = [(); { + let mut x = &0; + let mut n = 0; + while n < 5 { + n = (n + 1) % 5; //~ ERROR evaluation of constant value failed + x = &0; // Materialize a new AllocId + } + 0 + }]; +} diff --git a/tests/ui/consts/const-eval/issue-52475.stderr b/tests/ui/consts/const-eval/issue-52475.stderr new file mode 100644 index 000000000..8536ff02c --- /dev/null +++ b/tests/ui/consts/const-eval/issue-52475.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/issue-52475.rs:6:17 + | +LL | n = (n + 1) % 5; + | ^^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/issue-53157.rs b/tests/ui/consts/const-eval/issue-53157.rs new file mode 100644 index 000000000..850338625 --- /dev/null +++ b/tests/ui/consts/const-eval/issue-53157.rs @@ -0,0 +1,13 @@ +// check-pass + +macro_rules! m { + () => {{ + fn f(_: impl Sized) {} + f + }} +} + +fn main() { + fn f() -> impl Sized {}; + m!()(f()); +} diff --git a/tests/ui/consts/const-eval/issue-53401.rs b/tests/ui/consts/const-eval/issue-53401.rs new file mode 100644 index 000000000..31c946c3c --- /dev/null +++ b/tests/ui/consts/const-eval/issue-53401.rs @@ -0,0 +1,11 @@ +// check-pass + +pub const STATIC_TRAIT: &dyn Test = &(); + +fn main() {} + +pub trait Test { + fn test() where Self: Sized {} +} + +impl Test for () {} diff --git a/tests/ui/consts/const-eval/issue-55541.rs b/tests/ui/consts/const-eval/issue-55541.rs new file mode 100644 index 000000000..fa5a493ab --- /dev/null +++ b/tests/ui/consts/const-eval/issue-55541.rs @@ -0,0 +1,27 @@ +// check-pass + +// Test that we can handle newtypes wrapping extern types + +#![feature(extern_types)] + +use std::marker::PhantomData; + +extern "C" { + pub type ExternType; +} +unsafe impl Sync for ExternType {} +static MAGIC_FFI_STATIC: u8 = 42; + +#[repr(transparent)] +pub struct Wrapper(ExternType); +pub static MAGIC_FFI_REF: &'static Wrapper = unsafe { + std::mem::transmute(&MAGIC_FFI_STATIC) +}; + +#[repr(transparent)] +pub struct Wrapper2(PhantomData<Vec<i32>>, ExternType); +pub static MAGIC_FFI_REF2: &'static Wrapper2 = unsafe { + std::mem::transmute(&MAGIC_FFI_STATIC) +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/issue-64908.rs b/tests/ui/consts/const-eval/issue-64908.rs new file mode 100644 index 000000000..d2e095072 --- /dev/null +++ b/tests/ui/consts/const-eval/issue-64908.rs @@ -0,0 +1,20 @@ +// run-pass + +// This test verifies that the `ConstProp` pass doesn't cause an ICE when evaluating polymorphic +// promoted MIR. + +pub trait ArrowPrimitiveType { + type Native; +} + +pub fn new<T: ArrowPrimitiveType>() { + assert_eq!(0, std::mem::size_of::<T::Native>()); +} + +impl ArrowPrimitiveType for () { + type Native = (); +} + +fn main() { + new::<()>(); +} diff --git a/tests/ui/consts/const-eval/issue-64970.rs b/tests/ui/consts/const-eval/issue-64970.rs new file mode 100644 index 000000000..ba530438f --- /dev/null +++ b/tests/ui/consts/const-eval/issue-64970.rs @@ -0,0 +1,15 @@ +// run-pass + +fn main() { + foo(10); +} + +fn foo(mut n: i32) { + if false { + n = 0i32; + } + + if n > 0i32 { + let _ = 1i32 / n; + } +} diff --git a/tests/ui/consts/const-eval/issue-65394.rs b/tests/ui/consts/const-eval/issue-65394.rs new file mode 100644 index 000000000..e6639826c --- /dev/null +++ b/tests/ui/consts/const-eval/issue-65394.rs @@ -0,0 +1,13 @@ +// This test originated from #65394. We conservatively assume that `x` is still `LiveDrop` even +// after it has been moved because a mutable reference to it exists at some point in the const body. +// +// We will likely have to change this behavior before we allow `&mut` in a `const`. + +const _: Vec<i32> = { + let mut x = Vec::<i32>::new(); //~ ERROR destructor of + let r = &mut x; //~ ERROR mutable references are not allowed in constants + let y = x; + y +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/issue-65394.stderr b/tests/ui/consts/const-eval/issue-65394.stderr new file mode 100644 index 000000000..ae6f0e937 --- /dev/null +++ b/tests/ui/consts/const-eval/issue-65394.stderr @@ -0,0 +1,22 @@ +error[E0658]: mutable references are not allowed in constants + --> $DIR/issue-65394.rs:8:13 + | +LL | let r = &mut x; + | ^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0493]: destructor of `Vec<i32>` cannot be evaluated at compile-time + --> $DIR/issue-65394.rs:7:9 + | +LL | let mut x = Vec::<i32>::new(); + | ^^^^^ the destructor for this type cannot be evaluated in constants +... +LL | }; + | - value is dropped here + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0493, E0658. +For more information about an error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/const-eval/issue-70723.rs b/tests/ui/consts/const-eval/issue-70723.rs new file mode 100644 index 000000000..3c81afa67 --- /dev/null +++ b/tests/ui/consts/const-eval/issue-70723.rs @@ -0,0 +1,3 @@ +static _X: () = loop {}; //~ ERROR could not evaluate static initializer + +fn main() {} diff --git a/tests/ui/consts/const-eval/issue-70723.stderr b/tests/ui/consts/const-eval/issue-70723.stderr new file mode 100644 index 000000000..09fb3e060 --- /dev/null +++ b/tests/ui/consts/const-eval/issue-70723.stderr @@ -0,0 +1,9 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/issue-70723.rs:1:17 + | +LL | static _X: () = loop {}; + | ^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/issue-70804-fn-subtyping.rs b/tests/ui/consts/const-eval/issue-70804-fn-subtyping.rs new file mode 100644 index 000000000..abd1d32ab --- /dev/null +++ b/tests/ui/consts/const-eval/issue-70804-fn-subtyping.rs @@ -0,0 +1,9 @@ +// check-pass + +const fn nested(x: (for<'a> fn(&'a ()), String)) -> (fn(&'static ()), String) { + x +} + +pub const TEST: (fn(&'static ()), String) = nested((|_x| (), String::new())); + +fn main() {} diff --git a/tests/ui/consts/const-eval/issue-84957-const-str-as-bytes.rs b/tests/ui/consts/const-eval/issue-84957-const-str-as-bytes.rs new file mode 100644 index 000000000..7e235c491 --- /dev/null +++ b/tests/ui/consts/const-eval/issue-84957-const-str-as-bytes.rs @@ -0,0 +1,28 @@ +// build-pass + +trait Foo {} + +struct Bar { + bytes: &'static [u8], + func: fn(&Box<dyn Foo>), +} +fn example(_: &Box<dyn Foo>) {} + +const BARS: &[Bar] = &[ + Bar { + bytes: "0".as_bytes(), + func: example, + }, + Bar { + bytes: "0".as_bytes(), + func: example, + }, +]; + +fn main() { + let x = todo!(); + + for bar in BARS { + (bar.func)(&x); + } +} diff --git a/tests/ui/consts/const-eval/issue-85155.rs b/tests/ui/consts/const-eval/issue-85155.rs new file mode 100644 index 000000000..c3216d53d --- /dev/null +++ b/tests/ui/consts/const-eval/issue-85155.rs @@ -0,0 +1,21 @@ +// This is a test with a setup similar to issue 85155, which triggers a const eval error: a const +// argument value is outside the range expected by the `stdarch` intrinsic. +// +// It's not the exact code mentioned in that issue because it depends both on `stdarch` intrinsics +// only available on x64, and internal implementation details of `stdarch`. But mostly because these +// are not important to trigger the diagnostics issue: it's specifically about the lack of context +// in the diagnostics of post-monomorphization errors (PMEs) for consts, happening in a dependency. +// Therefore, its setup is reproduced with an aux crate, which will similarly trigger a PME +// depending on the const argument value, like the `stdarch` intrinsics would. +// +// aux-build: post_monomorphization_error.rs +// build-fail: this is a post-monomorphization error, it passes check runs and requires building +// to actually fail. + +extern crate post_monomorphization_error; + +fn main() { + // This function triggers a PME whenever the const argument does not fit in 1-bit. + post_monomorphization_error::stdarch_intrinsic::<2>(); + //~^ NOTE the above error was encountered while instantiating +} diff --git a/tests/ui/consts/const-eval/issue-85155.stderr b/tests/ui/consts/const-eval/issue-85155.stderr new file mode 100644 index 000000000..3d2c76b7e --- /dev/null +++ b/tests/ui/consts/const-eval/issue-85155.stderr @@ -0,0 +1,15 @@ +error[E0080]: evaluation of `post_monomorphization_error::ValidateConstImm::<2, 0, 1>::VALID` failed + --> $DIR/auxiliary/post_monomorphization_error.rs:7:17 + | +LL | let _ = 1 / ((IMM >= MIN && IMM <= MAX) as usize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to divide `1_usize` by zero + +note: the above error was encountered while instantiating `fn post_monomorphization_error::stdarch_intrinsic::<2>` + --> $DIR/issue-85155.rs:19:5 + | +LL | post_monomorphization_error::stdarch_intrinsic::<2>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/issue-85907.rs b/tests/ui/consts/const-eval/issue-85907.rs new file mode 100644 index 000000000..6ae40ae6d --- /dev/null +++ b/tests/ui/consts/const-eval/issue-85907.rs @@ -0,0 +1,7 @@ +const fn hey() -> usize { + panic!(123); //~ ERROR argument to `panic!()` in a const context must have type `&str` +} + +fn main() { + let _: [u8; hey()] = todo!(); +} diff --git a/tests/ui/consts/const-eval/issue-85907.stderr b/tests/ui/consts/const-eval/issue-85907.stderr new file mode 100644 index 000000000..fd7b40572 --- /dev/null +++ b/tests/ui/consts/const-eval/issue-85907.stderr @@ -0,0 +1,10 @@ +error: argument to `panic!()` in a const context must have type `&str` + --> $DIR/issue-85907.rs:2:5 + | +LL | panic!(123); + | ^^^^^^^^^^^ + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/tests/ui/consts/const-eval/issue-91827-extern-types.rs b/tests/ui/consts/const-eval/issue-91827-extern-types.rs new file mode 100644 index 000000000..43c99799f --- /dev/null +++ b/tests/ui/consts/const-eval/issue-91827-extern-types.rs @@ -0,0 +1,56 @@ +// run-pass +// +// Test that we can handle unsized types with an extern type tail part. +// Regression test for issue #91827. + +#![feature(extern_types)] + +use std::ptr::addr_of; + +extern "C" { + type Opaque; +} + +unsafe impl Sync for Opaque {} + +#[repr(C)] +pub struct List<T> { + len: usize, + data: [T; 0], + tail: Opaque, +} + +#[repr(C)] +pub struct ListImpl<T, const N: usize> { + len: usize, + data: [T; N], +} + +impl<T> List<T> { + const fn as_slice(&self) -> &[T] { + unsafe { std::slice::from_raw_parts(self.data.as_ptr(), self.len) } + } +} + +impl<T, const N: usize> ListImpl<T, N> { + const fn as_list(&self) -> &List<T> { + unsafe { std::mem::transmute(self) } + } +} + +pub static A: ListImpl<u128, 3> = ListImpl { + len: 3, + data: [5, 6, 7], +}; +pub static A_REF: &'static List<u128> = A.as_list(); +pub static A_TAIL_OFFSET: isize = tail_offset(A.as_list()); + +const fn tail_offset<T>(list: &List<T>) -> isize { + unsafe { (addr_of!(list.tail) as *const u8).offset_from(list as *const List<T> as *const u8) } +} + +fn main() { + assert_eq!(A_REF.as_slice(), &[5, 6, 7]); + // Check that interpreter and code generation agree about the position of the tail field. + assert_eq!(A_TAIL_OFFSET, tail_offset(A_REF)); +} diff --git a/tests/ui/consts/const-eval/livedrop.rs b/tests/ui/consts/const-eval/livedrop.rs new file mode 100644 index 000000000..543f1f0ec --- /dev/null +++ b/tests/ui/consts/const-eval/livedrop.rs @@ -0,0 +1,17 @@ +const _: Option<Vec<i32>> = { + let mut never_returned = Some(Vec::new()); + let mut always_returned = None; //~ ERROR destructor of + + let mut i = 0; + loop { + always_returned = never_returned; + never_returned = None; + + i += 1; + if i == 10 { + break always_returned; + } + } +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/livedrop.stderr b/tests/ui/consts/const-eval/livedrop.stderr new file mode 100644 index 000000000..d04fdb70e --- /dev/null +++ b/tests/ui/consts/const-eval/livedrop.stderr @@ -0,0 +1,12 @@ +error[E0493]: destructor of `Option<Vec<i32>>` cannot be evaluated at compile-time + --> $DIR/livedrop.rs:3:9 + | +LL | let mut always_returned = None; + | ^^^^^^^^^^^^^^^^^^^ the destructor for this type cannot be evaluated in constants +... +LL | always_returned = never_returned; + | --------------- value is dropped here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/const-eval/match-test-ptr-null.rs b/tests/ui/consts/const-eval/match-test-ptr-null.rs new file mode 100644 index 000000000..4af97b548 --- /dev/null +++ b/tests/ui/consts/const-eval/match-test-ptr-null.rs @@ -0,0 +1,12 @@ +fn main() { + // Make sure match uses the usual pointer comparison code path -- i.e., it should complain + // that pointer comparison is disallowed, not that parts of a pointer are accessed as raw + // bytes. + let _: [u8; 0] = [4; { + match &1 as *const i32 as usize { + //~^ ERROR pointers cannot be cast to integers during const eval + 0 => 42, + n => n, + } + }]; +} diff --git a/tests/ui/consts/const-eval/match-test-ptr-null.stderr b/tests/ui/consts/const-eval/match-test-ptr-null.stderr new file mode 100644 index 000000000..05c3951c1 --- /dev/null +++ b/tests/ui/consts/const-eval/match-test-ptr-null.stderr @@ -0,0 +1,11 @@ +error: pointers cannot be cast to integers during const eval + --> $DIR/match-test-ptr-null.rs:6:15 + | +LL | match &1 as *const i32 as usize { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: at compile-time, pointers do not have an integer value + = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior + +error: aborting due to previous error + diff --git a/tests/ui/consts/const-eval/mod-static-with-const-fn.rs b/tests/ui/consts/const-eval/mod-static-with-const-fn.rs new file mode 100644 index 000000000..b6b74e67d --- /dev/null +++ b/tests/ui/consts/const-eval/mod-static-with-const-fn.rs @@ -0,0 +1,22 @@ +// New test for #53818: modifying static memory at compile-time is not allowed. +// The test should never compile successfully + +#![feature(const_mut_refs)] + +use std::cell::UnsafeCell; + +struct Foo(UnsafeCell<u32>); + +unsafe impl Send for Foo {} +unsafe impl Sync for Foo {} + +static FOO: Foo = Foo(UnsafeCell::new(42)); + +static BAR: () = unsafe { + *FOO.0.get() = 5; + //~^ ERROR could not evaluate static initializer +}; + +fn main() { + println!("{}", unsafe { *FOO.0.get() }); +} diff --git a/tests/ui/consts/const-eval/mod-static-with-const-fn.stderr b/tests/ui/consts/const-eval/mod-static-with-const-fn.stderr new file mode 100644 index 000000000..d127d1d45 --- /dev/null +++ b/tests/ui/consts/const-eval/mod-static-with-const-fn.stderr @@ -0,0 +1,9 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/mod-static-with-const-fn.rs:16:5 + | +LL | *FOO.0.get() = 5; + | ^^^^^^^^^^^^^^^^ modifying a static's initial value from another static's initializer + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/no_lint_for_statically_known_error.rs b/tests/ui/consts/const-eval/no_lint_for_statically_known_error.rs new file mode 100644 index 000000000..910ca3c4b --- /dev/null +++ b/tests/ui/consts/const-eval/no_lint_for_statically_known_error.rs @@ -0,0 +1,18 @@ +// check-pass + +// if `X` were used instead of `x`, `X - 10` would result in a lint. +// This file should never produce a lint, no matter how the const +// propagator is improved. + +#![deny(warnings)] + +const X: u32 = 5; + +fn main() { + let x = X; + if x > 10 { + println!("{}", x - 10); + } else { + println!("{}", 10 - x); + } +} diff --git a/tests/ui/consts/const-eval/nrvo.rs b/tests/ui/consts/const-eval/nrvo.rs new file mode 100644 index 000000000..1d2c6acc0 --- /dev/null +++ b/tests/ui/consts/const-eval/nrvo.rs @@ -0,0 +1,26 @@ +// run-pass + +// When the NRVO is applied, the return place (`_0`) gets treated like a normal local. For example, +// its address may be taken and it may be written to indirectly. Ensure that MIRI can handle this. + +#![feature(const_mut_refs)] + +#[inline(never)] // Try to ensure that MIR optimizations don't optimize this away. +const fn init(buf: &mut [u8; 1024]) { + buf[33] = 3; + buf[444] = 4; +} + +const fn nrvo() -> [u8; 1024] { + let mut buf = [0; 1024]; + init(&mut buf); + buf +} + +const BUF: [u8; 1024] = nrvo(); + +fn main() { + assert_eq!(BUF[33], 3); + assert_eq!(BUF[19], 0); + assert_eq!(BUF[444], 4); +} diff --git a/tests/ui/consts/const-eval/panic-assoc-never-type.rs b/tests/ui/consts/const-eval/panic-assoc-never-type.rs new file mode 100644 index 000000000..28edf5144 --- /dev/null +++ b/tests/ui/consts/const-eval/panic-assoc-never-type.rs @@ -0,0 +1,15 @@ +// build-fail + +// Regression test for #66975 +#![feature(never_type)] + +struct PrintName; + +impl PrintName { + const VOID: ! = panic!(); + //~^ ERROR evaluation of constant value failed +} + +fn main() { + let _ = PrintName::VOID; //~ constant +} diff --git a/tests/ui/consts/const-eval/panic-assoc-never-type.stderr b/tests/ui/consts/const-eval/panic-assoc-never-type.stderr new file mode 100644 index 000000000..7c36a3a42 --- /dev/null +++ b/tests/ui/consts/const-eval/panic-assoc-never-type.stderr @@ -0,0 +1,23 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/panic-assoc-never-type.rs:9:21 + | +LL | const VOID: ! = panic!(); + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/panic-assoc-never-type.rs:9:21 + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: erroneous constant used + --> $DIR/panic-assoc-never-type.rs:14:13 + | +LL | let _ = PrintName::VOID; + | ^^^^^^^^^^^^^^^ + +note: erroneous constant used + --> $DIR/panic-assoc-never-type.rs:14:13 + | +LL | let _ = PrintName::VOID; + | ^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/panic-never-type.rs b/tests/ui/consts/const-eval/panic-never-type.rs new file mode 100644 index 000000000..a9e9026d9 --- /dev/null +++ b/tests/ui/consts/const-eval/panic-never-type.rs @@ -0,0 +1,9 @@ +// Regression test for #66975 +#![feature(never_type)] + +const VOID: ! = panic!(); +//~^ ERROR evaluation of constant value failed + +fn main() { + let _ = VOID; +} diff --git a/tests/ui/consts/const-eval/panic-never-type.stderr b/tests/ui/consts/const-eval/panic-never-type.stderr new file mode 100644 index 000000000..6bff14a45 --- /dev/null +++ b/tests/ui/consts/const-eval/panic-never-type.stderr @@ -0,0 +1,11 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/panic-never-type.rs:4:17 + | +LL | const VOID: ! = panic!(); + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/panic-never-type.rs:4:17 + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/partial_ptr_overwrite.rs b/tests/ui/consts/const-eval/partial_ptr_overwrite.rs new file mode 100644 index 000000000..d6c768868 --- /dev/null +++ b/tests/ui/consts/const-eval/partial_ptr_overwrite.rs @@ -0,0 +1,14 @@ +// Test for the behavior described in <https://github.com/rust-lang/rust/issues/87184>. +#![feature(const_mut_refs)] + +const PARTIAL_OVERWRITE: () = { + let mut p = &42; + unsafe { + let ptr: *mut _ = &mut p; + *(ptr as *mut u8) = 123; //~ ERROR constant + //~| unable to overwrite parts of a pointer + } + let x = *p; +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr b/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr new file mode 100644 index 000000000..13ca4379b --- /dev/null +++ b/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr @@ -0,0 +1,12 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/partial_ptr_overwrite.rs:8:9 + | +LL | *(ptr as *mut u8) = 123; + | ^^^^^^^^^^^^^^^^^^^^^^^ unable to overwrite parts of a pointer in memory at alloc4 + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/promote-static.rs b/tests/ui/consts/const-eval/promote-static.rs new file mode 100644 index 000000000..d3c663c53 --- /dev/null +++ b/tests/ui/consts/const-eval/promote-static.rs @@ -0,0 +1,14 @@ +// regression test for #67609. + +// check-pass + +static NONE: Option<String> = None; + +static NONE_REF_REF: &&Option<String> = { + let x = &&NONE; + x +}; + +fn main() { + println!("{:?}", NONE_REF_REF); +} diff --git a/tests/ui/consts/const-eval/promote_mutable_zst_mir_borrowck.rs b/tests/ui/consts/const-eval/promote_mutable_zst_mir_borrowck.rs new file mode 100644 index 000000000..edda10e6e --- /dev/null +++ b/tests/ui/consts/const-eval/promote_mutable_zst_mir_borrowck.rs @@ -0,0 +1,5 @@ +// check-pass + +pub fn main() { + let y: &'static mut [u8; 0] = &mut []; +} diff --git a/tests/ui/consts/const-eval/promoted_const_fn_fail.rs b/tests/ui/consts/const-eval/promoted_const_fn_fail.rs new file mode 100644 index 000000000..656dd33e1 --- /dev/null +++ b/tests/ui/consts/const-eval/promoted_const_fn_fail.rs @@ -0,0 +1,20 @@ +#[repr(C)] +union Bar { + a: &'static u8, + b: usize, +} + +const fn bar() -> u8 { + unsafe { + // this will error as long as this test + // is run on a system whose pointers need more + // than 8 bits + Bar { a: &42 }.b as u8 + } +} + +fn main() { + let x: &'static u8 = &(bar() + 1); //~ ERROR temporary value dropped while borrowed + let y = *x; + unreachable!(); +} diff --git a/tests/ui/consts/const-eval/promoted_const_fn_fail.stderr b/tests/ui/consts/const-eval/promoted_const_fn_fail.stderr new file mode 100644 index 000000000..2d4e7c83d --- /dev/null +++ b/tests/ui/consts/const-eval/promoted_const_fn_fail.stderr @@ -0,0 +1,14 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_fn_fail.rs:17:27 + | +LL | let x: &'static u8 = &(bar() + 1); + | ----------- ^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs b/tests/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs new file mode 100644 index 000000000..5009dbcb9 --- /dev/null +++ b/tests/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs @@ -0,0 +1,22 @@ +#[repr(C)] +union Bar { + a: &'static u8, + b: usize, +} + +const fn bar() -> u8 { + unsafe { + // This will error as long as this test is run on a system whose + // pointers need more than 8 bits. + Bar { a: &42 }.b as u8 + } +} + +fn main() { + // This will compile, but then hard-abort at runtime. + // FIXME(oli-obk): this should instead panic (not hard-abort) at runtime. + let x: &'static u8 = &(bar() + 1); + //~^ ERROR temporary value dropped while borrowed + let y = *x; + unreachable!(); +} diff --git a/tests/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.stderr b/tests/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.stderr new file mode 100644 index 000000000..9ebae3a18 --- /dev/null +++ b/tests/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.stderr @@ -0,0 +1,14 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_fn_fail_deny_const_err.rs:18:27 + | +LL | let x: &'static u8 = &(bar() + 1); + | ----------- ^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/const-eval/promoted_errors.noopt.stderr b/tests/ui/consts/const-eval/promoted_errors.noopt.stderr new file mode 100644 index 000000000..2a254bfde --- /dev/null +++ b/tests/ui/consts/const-eval/promoted_errors.noopt.stderr @@ -0,0 +1,44 @@ +warning: this arithmetic operation will overflow + --> $DIR/promoted_errors.rs:15:5 + | +LL | 0 - 1 + | ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:11:9 + | +LL | #![warn(arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:19:5 + | +LL | 1 / 0 + | ^^^^^ attempt to divide `1_i32` by zero + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:11:30 + | +LL | #![warn(arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:23:5 + | +LL | 1 / (1 - 1) + | ^^^^^^^^^^^ attempt to divide `1_i32` by zero + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:27:5 + | +LL | 1 / (false as i32) + | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_i32` by zero + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:31:5 + | +LL | [1, 2, 3][4] + | ^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4 + +warning: 5 warnings emitted + diff --git a/tests/ui/consts/const-eval/promoted_errors.opt.stderr b/tests/ui/consts/const-eval/promoted_errors.opt.stderr new file mode 100644 index 000000000..2a254bfde --- /dev/null +++ b/tests/ui/consts/const-eval/promoted_errors.opt.stderr @@ -0,0 +1,44 @@ +warning: this arithmetic operation will overflow + --> $DIR/promoted_errors.rs:15:5 + | +LL | 0 - 1 + | ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:11:9 + | +LL | #![warn(arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:19:5 + | +LL | 1 / 0 + | ^^^^^ attempt to divide `1_i32` by zero + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:11:30 + | +LL | #![warn(arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:23:5 + | +LL | 1 / (1 - 1) + | ^^^^^^^^^^^ attempt to divide `1_i32` by zero + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:27:5 + | +LL | 1 / (false as i32) + | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_i32` by zero + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:31:5 + | +LL | [1, 2, 3][4] + | ^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4 + +warning: 5 warnings emitted + diff --git a/tests/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr b/tests/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr new file mode 100644 index 000000000..2a254bfde --- /dev/null +++ b/tests/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr @@ -0,0 +1,44 @@ +warning: this arithmetic operation will overflow + --> $DIR/promoted_errors.rs:15:5 + | +LL | 0 - 1 + | ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:11:9 + | +LL | #![warn(arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:19:5 + | +LL | 1 / 0 + | ^^^^^ attempt to divide `1_i32` by zero + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:11:30 + | +LL | #![warn(arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:23:5 + | +LL | 1 / (1 - 1) + | ^^^^^^^^^^^ attempt to divide `1_i32` by zero + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:27:5 + | +LL | 1 / (false as i32) + | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_i32` by zero + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:31:5 + | +LL | [1, 2, 3][4] + | ^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4 + +warning: 5 warnings emitted + diff --git a/tests/ui/consts/const-eval/promoted_errors.rs b/tests/ui/consts/const-eval/promoted_errors.rs new file mode 100644 index 000000000..2c42d0356 --- /dev/null +++ b/tests/ui/consts/const-eval/promoted_errors.rs @@ -0,0 +1,52 @@ +// revisions: noopt opt opt_with_overflow_checks +//[noopt]compile-flags: -C opt-level=0 +//[opt]compile-flags: -O +//[opt_with_overflow_checks]compile-flags: -C overflow-checks=on -O + +// build-pass +// ignore-pass (test emits codegen-time warnings and verifies that they are not errors) + +//! This test ensures that when we promote code that fails to evaluate, the build still succeeds. + +#![warn(arithmetic_overflow, unconditional_panic)] + +// The only way to have promoteds that fail is in `const fn` called from `const`/`static`. +const fn overflow() -> u32 { + 0 - 1 + //~^ WARN this arithmetic operation will overflow +} +const fn div_by_zero1() -> i32 { + 1 / 0 + //~^ WARN this operation will panic at runtime +} +const fn div_by_zero2() -> i32 { + 1 / (1 - 1) + //~^ WARN this operation will panic at runtime +} +const fn div_by_zero3() -> i32 { + 1 / (false as i32) + //~^ WARN this operation will panic at runtime +} +const fn oob() -> i32 { + [1, 2, 3][4] + //~^ WARN this operation will panic at runtime +} + +const fn mk_false() -> bool { false } + +// An actually used constant referencing failing promoteds in dead code. +// This needs to always work. +const Y: () = { + if mk_false() { + let _x: &'static u32 = &overflow(); + let _x: &'static i32 = &div_by_zero1(); + let _x: &'static i32 = &div_by_zero2(); + let _x: &'static i32 = &div_by_zero3(); + let _x: &'static i32 = &oob(); + } + () +}; + +fn main() { + let _y = Y; +} diff --git a/tests/ui/consts/const-eval/promoted_raw_ptr_ops.rs b/tests/ui/consts/const-eval/promoted_raw_ptr_ops.rs new file mode 100644 index 000000000..1800b0a97 --- /dev/null +++ b/tests/ui/consts/const-eval/promoted_raw_ptr_ops.rs @@ -0,0 +1,10 @@ +fn main() { + let x: &'static bool = &(42 as *const i32 == 43 as *const i32); + //~^ ERROR temporary value dropped while borrowed + let y: &'static usize = &(&1 as *const i32 as usize + 1); + //~^ ERROR temporary value dropped while borrowed + let z: &'static i32 = &(unsafe { *(42 as *const i32) }); + //~^ ERROR temporary value dropped while borrowed + let a: &'static bool = &(main as fn() == main as fn()); + //~^ ERROR temporary value dropped while borrowed +} diff --git a/tests/ui/consts/const-eval/promoted_raw_ptr_ops.stderr b/tests/ui/consts/const-eval/promoted_raw_ptr_ops.stderr new file mode 100644 index 000000000..01fcf2ec2 --- /dev/null +++ b/tests/ui/consts/const-eval/promoted_raw_ptr_ops.stderr @@ -0,0 +1,47 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_raw_ptr_ops.rs:2:29 + | +LL | let x: &'static bool = &(42 as *const i32 == 43 as *const i32); + | ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_raw_ptr_ops.rs:4:30 + | +LL | let y: &'static usize = &(&1 as *const i32 as usize + 1); + | -------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_raw_ptr_ops.rs:6:28 + | +LL | let z: &'static i32 = &(unsafe { *(42 as *const i32) }); + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_raw_ptr_ops.rs:8:29 + | +LL | let a: &'static bool = &(main as fn() == main as fn()); + | ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr new file mode 100644 index 000000000..91a426580 --- /dev/null +++ b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr @@ -0,0 +1,596 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:20:1 + | +LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x00000001, but expected a valid enum tag + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + 01 00 00 00 │ .... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:28:1 + | +LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x00000000, but expected a valid enum tag + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + 00 00 00 00 │ .... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:42:1 + | +LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(B)>.0: encountered a value of the never type `!` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 1, align: 1) { + 01 │ . + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:44:1 + | +LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(D)>.0: encountered a value of uninhabited type Never + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 1, align: 1) { + 03 │ . + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:50:1 + | +LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + 78 00 00 00 ff ff ff ff │ x....... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:54:1 + | +LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + 00 00 00 00 │ .... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:57:1 + | +LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 1, align: 1) { + 00 │ . + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:59:1 + | +LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + 00 00 00 00 │ .... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:65:1 + | +LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 42, but expected something in the range 10..=30 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + 2a 00 00 00 │ *... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:71:1 + | +LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + 14 00 00 00 │ .... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:74:1 + | +LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + 00 00 00 00 ╾ALLOC_ID╼ │ ....╾──╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:82:1 + | +LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + ╾ALLOC_ID╼ │ ╾──╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:86:1 + | +LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + ╾ALLOC_ID╼ │ ╾──╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:90:1 + | +LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + 00 00 00 00 │ .... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:93:1 + | +LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + 00 00 00 00 │ .... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:96:1 + | +LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x539 is unallocated) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + 39 05 00 00 │ 9... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:99:1 + | +LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (address 0x539 is unallocated) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + 39 05 00 00 │ 9... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:102:1 + | +LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + 00 00 00 00 │ .... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:104:1 + | +LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + 0d 00 00 00 │ .... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:106:1 + | +LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a function pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + ╾ALLOC_ID╼ │ ╾──╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:112:1 + | +LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type Bar + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + 01 00 00 00 │ .... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:137:1 + | +LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC_ID╼ e7 03 00 00 │ ╾──╼.... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:139:1 + | +LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC_ID╼ ff ff ff ff │ ╾──╼.... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:141:1 + | +LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC_ID╼ ff ff ff ff │ ╾──╼.... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:144:1 + | +LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼.... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:146:1 + | +LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼.... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:148:1 + | +LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼.... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:152:1 + | +LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC_ID╼ e7 03 00 00 │ ╾──╼.... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:154:1 + | +LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC_ID╼ ff ff ff 7f │ ╾──╼.... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:157:1 + | +LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC_ID╼ e7 03 00 00 │ ╾──╼.... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:160:1 + | +LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + ╾ALLOC_ID╼ │ ╾──╼ + } + +note: erroneous constant used + --> $DIR/raw-bytes.rs:160:40 + | +LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:166:1 + | +LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + ╾ALLOC_ID╼ │ ╾──╼ + } + +note: erroneous constant used + --> $DIR/raw-bytes.rs:166:42 + | +LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:170:1 + | +LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + ╾ALLOC_ID╼ │ ╾──╼ + } + +note: erroneous constant used + --> $DIR/raw-bytes.rs:170:42 + | +LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:175:1 + | +LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:179:1 + | +LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:183:1 + | +LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼.... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:186:1 + | +LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:190:1 + | +LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:194:1 + | +LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC_ID╼ 00 00 00 00 │ ╾──╼.... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:196:1 + | +LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:201:1 + | +LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x00000000, but expected a valid enum tag + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + 00 10 00 00 00 00 00 00 │ ........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:205:1 + | +LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x00000003, but expected a valid enum tag + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + 09 00 00 00 03 00 00 00 │ ........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:209:1 + | +LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; + | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1] + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + 01 00 00 00 │ .... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:210:1 + | +LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; + | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + 01 00 00 00 01 00 00 00 │ ........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:211:1 + | +LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; + | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + 01 00 00 00 2a 00 00 00 │ ....*... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:215:1 + | +LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼.... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:218:1 + | +LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) }; + | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼.... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:221:1 + | +LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼.... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:225:1 + | +LL | pub static S7: &[u16] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized bytes + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC_ID+0x2╼ 04 00 00 00 │ ╾──╼.... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:232:1 + | +LL | pub static R4: &[u8] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼.... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:237:1 + | +LL | pub static R5: &[u8] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼.... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:242:1 + | +LL | pub static R6: &[bool] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼.... + } + +error: aborting due to 52 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr new file mode 100644 index 000000000..e4c5e62f6 --- /dev/null +++ b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr @@ -0,0 +1,596 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:20:1 + | +LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x0000000000000001, but expected a valid enum tag + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + 01 00 00 00 00 00 00 00 │ ........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:28:1 + | +LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + 00 00 00 00 00 00 00 00 │ ........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:42:1 + | +LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(B)>.0: encountered a value of the never type `!` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 1, align: 1) { + 01 │ . + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:44:1 + | +LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(D)>.0: encountered a value of uninhabited type Never + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 1, align: 1) { + 03 │ . + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:50:1 + | +LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + 78 00 00 00 ff ff ff ff │ x....... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:54:1 + | +LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + 00 00 00 00 00 00 00 00 │ ........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:57:1 + | +LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 1, align: 1) { + 00 │ . + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:59:1 + | +LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + 00 00 00 00 00 00 00 00 │ ........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:65:1 + | +LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 42, but expected something in the range 10..=30 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + 2a 00 00 00 │ *... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:71:1 + | +LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + 14 00 00 00 │ .... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:74:1 + | +LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + 00 00 00 00 00 00 00 00 ╾ALLOC_ID╼ │ ........╾──────╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:82:1 + | +LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + ╾ALLOC_ID╼ │ ╾──────╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:86:1 + | +LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + ╾ALLOC_ID╼ │ ╾──────╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:90:1 + | +LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + 00 00 00 00 00 00 00 00 │ ........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:93:1 + | +LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + 00 00 00 00 00 00 00 00 │ ........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:96:1 + | +LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x539 is unallocated) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + 39 05 00 00 00 00 00 00 │ 9....... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:99:1 + | +LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (address 0x539 is unallocated) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + 39 05 00 00 00 00 00 00 │ 9....... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:102:1 + | +LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + 00 00 00 00 00 00 00 00 │ ........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:104:1 + | +LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + 0d 00 00 00 00 00 00 00 │ ........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:106:1 + | +LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a function pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + ╾ALLOC_ID╼ │ ╾──────╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:112:1 + | +LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type Bar + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + 01 00 00 00 00 00 00 00 │ ........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:137:1 + | +LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:139:1 + | +LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC_ID╼ ff ff ff ff ff ff ff ff │ ╾──────╼........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:141:1 + | +LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC_ID╼ ff ff ff ff ff ff ff ff │ ╾──────╼........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:144:1 + | +LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:146:1 + | +LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:148:1 + | +LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:152:1 + | +LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:154:1 + | +LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC_ID╼ ff ff ff ff ff ff ff 7f │ ╾──────╼........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:157:1 + | +LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:160:1 + | +LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + ╾ALLOC_ID╼ │ ╾──────╼ + } + +note: erroneous constant used + --> $DIR/raw-bytes.rs:160:40 + | +LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:166:1 + | +LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + ╾ALLOC_ID╼ │ ╾──────╼ + } + +note: erroneous constant used + --> $DIR/raw-bytes.rs:166:42 + | +LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:170:1 + | +LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + ╾ALLOC_ID╼ │ ╾──────╼ + } + +note: erroneous constant used + --> $DIR/raw-bytes.rs:170:42 + | +LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:175:1 + | +LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:179:1 + | +LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:183:1 + | +LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:186:1 + | +LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:190:1 + | +LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:194:1 + | +LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC_ID╼ 00 00 00 00 00 00 00 00 │ ╾──────╼........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:196:1 + | +LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:201:1 + | +LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:205:1 + | +LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x0000000000000003, but expected a valid enum tag + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + 09 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 │ ................ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:209:1 + | +LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; + | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1] + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + 01 00 00 00 00 00 00 00 │ ........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:210:1 + | +LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; + | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:211:1 + | +LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; + | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + 01 00 00 00 00 00 00 00 2a 00 00 00 00 00 00 00 │ ........*....... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:215:1 + | +LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:218:1 + | +LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) }; + | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:221:1 + | +LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:225:1 + | +LL | pub static S7: &[u16] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized bytes + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC_ID+0x2╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:232:1 + | +LL | pub static R4: &[u8] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:237:1 + | +LL | pub static R5: &[u8] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/raw-bytes.rs:242:1 + | +LL | pub static R6: &[bool] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ + } + +error: aborting due to 52 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/raw-bytes.rs b/tests/ui/consts/const-eval/raw-bytes.rs new file mode 100644 index 000000000..6c1238c0a --- /dev/null +++ b/tests/ui/consts/const-eval/raw-bytes.rs @@ -0,0 +1,263 @@ +// stderr-per-bitwidth +// ignore-endian-big +// ignore-tidy-linelength +// normalize-stderr-test "╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼" -> "╾ALLOC_ID$2╼" +// normalize-stderr-test "alloc\d+" -> "allocN" +#![feature(never_type, rustc_attrs, ptr_metadata, slice_from_ptr_range, const_slice_from_ptr_range)] +#![allow(invalid_value)] + +use std::mem; +use std::alloc::Layout; +use std::ptr::NonNull; +use std::num::{NonZeroU8, NonZeroUsize}; +use std::slice::{from_ptr_range, from_raw_parts}; + +#[repr(usize)] +#[derive(Copy, Clone)] +enum Enum { + A = 0, +} +const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; +//~^ ERROR is undefined behavior + +#[repr(usize)] +#[derive(Copy, Clone)] +enum Enum2 { + A = 2, +} +const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; +//~^ ERROR is undefined behavior + +#[derive(Copy, Clone)] +enum Never {} + +// An enum with 3 variants of which some are uninhabited -- so the uninhabited variants *do* +// have a discriminant. +enum UninhDiscriminant { + A, + B(!), + C, + D(Never), +} +const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; +//~^ ERROR is undefined behavior +const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; +//~^ ERROR is undefined behavior + +// Invalid enum field content (mostly to test printing of paths for enum tuple +// variants and tuples). +// Need to create something which does not clash with enum layout optimizations. +const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); +//~^ ERROR is undefined behavior + + +const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) }; +//~^ ERROR it is undefined behavior to use this value + +const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; +//~^ ERROR it is undefined behavior to use this value +const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; +//~^ ERROR it is undefined behavior to use this value + +#[rustc_layout_scalar_valid_range_start(10)] +#[rustc_layout_scalar_valid_range_end(30)] +struct RestrictedRange1(u32); +const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; +//~^ ERROR it is undefined behavior to use this value + +#[rustc_layout_scalar_valid_range_start(30)] +#[rustc_layout_scalar_valid_range_end(10)] +struct RestrictedRange2(u32); +const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; +//~^ ERROR it is undefined behavior to use this value + +const NULL_FAT_PTR: NonNull<dyn Send> = unsafe { +//~^ ERROR it is undefined behavior to use this value + let x: &dyn Send = &42; + let meta = std::ptr::metadata(x); + mem::transmute((0_usize, meta)) +}; + + +const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; +//~^ ERROR it is undefined behavior to use this value +//~| constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) + +const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) }; +//~^ ERROR it is undefined behavior to use this value +//~| constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) + +const NULL: &u16 = unsafe { mem::transmute(0usize) }; +//~^ ERROR it is undefined behavior to use this value + +const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) }; +//~^ ERROR it is undefined behavior to use this value + +const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; +//~^ ERROR it is undefined behavior to use this value + +const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) }; +//~^ ERROR it is undefined behavior to use this value + +const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; +//~^ ERROR it is undefined behavior to use this value +const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; +//~^ ERROR it is undefined behavior to use this value +const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; +//~^ ERROR it is undefined behavior to use this value + +#[derive(Copy, Clone)] +enum Bar {} + +const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; +//~^ ERROR it is undefined behavior to use this value + + +/// A newtype wrapper to prevent MIR generation from inserting reborrows that would affect the error +/// message. +#[repr(transparent)] +struct W<T>(T); + +#[repr(C)] +union MaybeUninit<T: Copy> { + uninit: (), + init: T, +} + +trait Trait {} +impl Trait for bool {} + +// custom unsized type +struct MyStr(str); + +// custom unsized type with sized fields +struct MySlice<T: ?Sized>(bool, T); +type MySliceBool = MySlice<[bool]>; + +const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; +//~^ ERROR it is undefined behavior to use this value +const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); +//~^ ERROR it is undefined behavior to use this value +const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; +//~^ ERROR it is undefined behavior to use this value + +const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; +//~^ ERROR it is undefined behavior to use this value +const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; +//~^ ERROR it is undefined behavior to use this value +const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; +//~^ ERROR: it is undefined behavior to use this value + +// # slice +const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; +//~^ ERROR it is undefined behavior to use this value +const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; +//~^ ERROR it is undefined behavior to use this value +// bad slice box: length too big +const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; +//~^ ERROR it is undefined behavior to use this value +// bad data *inside* the slice +const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; +//~^ ERROR it is undefined behavior to use this value +//~| constant + + +// bad: sized field is not okay +const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); +//~^ ERROR it is undefined behavior to use this value +//~| constant +// bad: unsized part is not okay +const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); +//~^ ERROR it is undefined behavior to use this value +//~| constant + +// bad trait object +const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; +//~^ ERROR it is undefined behavior to use this value +//~| expected a vtable +// bad trait object +const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; +//~^ ERROR it is undefined behavior to use this value +//~| expected a vtable +// bad trait object +const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; +//~^ ERROR it is undefined behavior to use this value +//~| expected a vtable +const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; +//~^ ERROR it is undefined behavior to use this value +//~| expected a vtable +// bad data *inside* the trait object +const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; +//~^ ERROR it is undefined behavior to use this value +//~| expected a boolean + +const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; +//~^ ERROR it is undefined behavior to use this value +const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; +//~^ ERROR it is undefined behavior to use this value + + +// not ok, since alignment needs to be non-zero. +const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) }; +//~^ ERROR it is undefined behavior to use this value + +// not ok, since alignment needs to be a power of two. +const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) }; +//~^ ERROR it is undefined behavior to use this value + + +const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior +const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior +const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; //~ ERROR undefined behavior + + +// Reading uninitialized data +pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; +//~^ ERROR: it is undefined behavior to use this value +// Reinterpret pointers as integers (UB in CTFE.) +pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) }; +//~^ ERROR: it is undefined behavior to use this value +// Layout mismatch +pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; +//~^ ERROR: it is undefined behavior to use this value + +// Reading padding is not ok +pub static S7: &[u16] = unsafe { + //~^ ERROR: it is undefined behavior to use this value + let ptr = (&D2 as *const Struct as *const u16).add(1); + + from_raw_parts(ptr, 4) +}; + +pub static R4: &[u8] = unsafe { + //~^ ERROR: it is undefined behavior to use this value + let ptr = (&D1) as *const mem::MaybeUninit<&u32> as *const u8; + from_ptr_range(ptr..ptr.add(1)) +}; +pub static R5: &[u8] = unsafe { + //~^ ERROR: it is undefined behavior to use this value + let ptr = &D3 as *const &u32; + from_ptr_range(ptr.cast()..ptr.add(1).cast()) +}; +pub static R6: &[bool] = unsafe { + //~^ ERROR: it is undefined behavior to use this value + let ptr = &D0 as *const u32 as *const bool; + from_ptr_range(ptr..ptr.add(4)) +}; + +const D0: u32 = 0x11111111; // Constant chosen for endianness-independent behavior. +const D1: mem::MaybeUninit<&u32> = mem::MaybeUninit::uninit(); +const D2: Struct = Struct { a: 1, b: 2, c: 3, d: 4 }; +const D3: &u32 = &42; + +#[repr(C)] +struct Struct { + a: u8, + // _pad: [mem::MaybeUninit<u8>; 3] + b: u32, + c: u16, + d: u8, + // _pad: [mem::MaybeUninit<u8>; 1] +} + +fn main() {} diff --git a/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr b/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr new file mode 100644 index 000000000..032ceb246 --- /dev/null +++ b/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr @@ -0,0 +1,24 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/ref_to_int_match.rs:25:27 + | +LL | const BAR: Int = unsafe { Foo { r: &42 }.f }; + | ^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error: could not evaluate constant pattern + --> $DIR/ref_to_int_match.rs:7:14 + | +LL | 10..=BAR => {}, + | ^^^ + +error: could not evaluate constant pattern + --> $DIR/ref_to_int_match.rs:7:14 + | +LL | 10..=BAR => {}, + | ^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr b/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr new file mode 100644 index 000000000..032ceb246 --- /dev/null +++ b/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr @@ -0,0 +1,24 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/ref_to_int_match.rs:25:27 + | +LL | const BAR: Int = unsafe { Foo { r: &42 }.f }; + | ^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error: could not evaluate constant pattern + --> $DIR/ref_to_int_match.rs:7:14 + | +LL | 10..=BAR => {}, + | ^^^ + +error: could not evaluate constant pattern + --> $DIR/ref_to_int_match.rs:7:14 + | +LL | 10..=BAR => {}, + | ^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/ref_to_int_match.rs b/tests/ui/consts/const-eval/ref_to_int_match.rs new file mode 100644 index 000000000..70c6e7d94 --- /dev/null +++ b/tests/ui/consts/const-eval/ref_to_int_match.rs @@ -0,0 +1,26 @@ +// stderr-per-bitwidth + +fn main() { + let n: Int = 40; + match n { + 0..=10 => {}, + 10..=BAR => {}, //~ ERROR could not evaluate constant pattern + //~| ERROR could not evaluate constant pattern + _ => {}, + } +} + +#[repr(C)] +union Foo { + f: Int, + r: &'static u32, +} + +#[cfg(target_pointer_width="64")] +type Int = u64; + +#[cfg(target_pointer_width="32")] +type Int = u32; + +const BAR: Int = unsafe { Foo { r: &42 }.f }; +//~^ ERROR constant diff --git a/tests/ui/consts/const-eval/shift_overflow.rs b/tests/ui/consts/const-eval/shift_overflow.rs new file mode 100644 index 000000000..e843584b6 --- /dev/null +++ b/tests/ui/consts/const-eval/shift_overflow.rs @@ -0,0 +1,9 @@ +enum Foo { + // test that we detect overflows for non-u32 discriminants + X = 1 << ((u32::MAX as u64) + 1), //~ ERROR E0080 + Y = 42, +} + + +fn main() { +} diff --git a/tests/ui/consts/const-eval/shift_overflow.stderr b/tests/ui/consts/const-eval/shift_overflow.stderr new file mode 100644 index 000000000..e8d4076a6 --- /dev/null +++ b/tests/ui/consts/const-eval/shift_overflow.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/shift_overflow.rs:3:9 + | +LL | X = 1 << ((u32::MAX as u64) + 1), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to shift left by `4294967296_u64`, which would overflow + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/simd/insert_extract.rs b/tests/ui/consts/const-eval/simd/insert_extract.rs new file mode 100644 index 000000000..3472c05d1 --- /dev/null +++ b/tests/ui/consts/const-eval/simd/insert_extract.rs @@ -0,0 +1,70 @@ +// run-pass +#![feature(repr_simd)] +#![feature(platform_intrinsics)] +#![feature(staged_api)] +#![stable(feature = "foo", since = "1.3.37")] +#![allow(non_camel_case_types)] + +#[repr(simd)] struct i8x1(i8); +#[repr(simd)] struct u16x2(u16, u16); +// Make some of them array types to ensure those also work. +#[repr(simd)] struct i8x1_arr([i8; 1]); +#[repr(simd)] struct f32x4([f32; 4]); + +extern "platform-intrinsic" { + #[rustc_const_stable(feature = "foo", since = "1.3.37")] + fn simd_insert<T, U>(x: T, idx: u32, val: U) -> T; + #[rustc_const_stable(feature = "foo", since = "1.3.37")] + fn simd_extract<T, U>(x: T, idx: u32) -> U; +} + +fn main() { + { + const U: i8x1 = i8x1(13); + const V: i8x1 = unsafe { simd_insert(U, 0_u32, 42_i8) }; + const X0: i8 = V.0; + const Y0: i8 = unsafe { simd_extract(V, 0) }; + assert_eq!(X0, 42); + assert_eq!(Y0, 42); + } + { + const U: i8x1_arr = i8x1_arr([13]); + const V: i8x1_arr = unsafe { simd_insert(U, 0_u32, 42_i8) }; + const X0: i8 = V.0[0]; + const Y0: i8 = unsafe { simd_extract(V, 0) }; + assert_eq!(X0, 42); + assert_eq!(Y0, 42); + } + { + const U: u16x2 = u16x2(13, 14); + const V: u16x2 = unsafe { simd_insert(U, 1_u32, 42_u16) }; + const X0: u16 = V.0; + const X1: u16 = V.1; + const Y0: u16 = unsafe { simd_extract(V, 0) }; + const Y1: u16 = unsafe { simd_extract(V, 1) }; + assert_eq!(X0, 13); + assert_eq!(X1, 42); + assert_eq!(Y0, 13); + assert_eq!(Y1, 42); + } + { + const U: f32x4 = f32x4([13., 14., 15., 16.]); + const V: f32x4 = unsafe { simd_insert(U, 1_u32, 42_f32) }; + const X0: f32 = V.0[0]; + const X1: f32 = V.0[1]; + const X2: f32 = V.0[2]; + const X3: f32 = V.0[3]; + const Y0: f32 = unsafe { simd_extract(V, 0) }; + const Y1: f32 = unsafe { simd_extract(V, 1) }; + const Y2: f32 = unsafe { simd_extract(V, 2) }; + const Y3: f32 = unsafe { simd_extract(V, 3) }; + assert_eq!(X0, 13.); + assert_eq!(X1, 42.); + assert_eq!(X2, 15.); + assert_eq!(X3, 16.); + assert_eq!(Y0, 13.); + assert_eq!(Y1, 42.); + assert_eq!(Y2, 15.); + assert_eq!(Y3, 16.); + } +} diff --git a/tests/ui/consts/const-eval/simple_with_undef.rs b/tests/ui/consts/const-eval/simple_with_undef.rs new file mode 100644 index 000000000..1a416dd46 --- /dev/null +++ b/tests/ui/consts/const-eval/simple_with_undef.rs @@ -0,0 +1,6 @@ +// check-pass + +const PARSE_BOOL: Option<&'static str> = None; +static FOO: (Option<&str>, u32) = (PARSE_BOOL, 42); + +fn main() {} diff --git a/tests/ui/consts/const-eval/size-of-t.rs b/tests/ui/consts/const-eval/size-of-t.rs new file mode 100644 index 000000000..efbdeec70 --- /dev/null +++ b/tests/ui/consts/const-eval/size-of-t.rs @@ -0,0 +1,13 @@ +// https://github.com/rust-lang/rust/issues/69228 +// Used to give bogus suggestion about T not being Sized. + +use std::mem::size_of; + +fn foo<T>() { + let _arr: [u8; size_of::<T>()]; + //~^ ERROR generic parameters may not be used in const operations + //~| NOTE cannot perform const operation + //~| NOTE type parameters may not be used in const expressions +} + +fn main() {} diff --git a/tests/ui/consts/const-eval/size-of-t.stderr b/tests/ui/consts/const-eval/size-of-t.stderr new file mode 100644 index 000000000..abe641046 --- /dev/null +++ b/tests/ui/consts/const-eval/size-of-t.stderr @@ -0,0 +1,11 @@ +error: generic parameters may not be used in const operations + --> $DIR/size-of-t.rs:7:30 + | +LL | let _arr: [u8; size_of::<T>()]; + | ^ cannot perform const operation using `T` + | + = note: type parameters may not be used in const expressions + = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: aborting due to previous error + diff --git a/tests/ui/consts/const-eval/strlen.rs b/tests/ui/consts/const-eval/strlen.rs new file mode 100644 index 000000000..7b14a5235 --- /dev/null +++ b/tests/ui/consts/const-eval/strlen.rs @@ -0,0 +1,31 @@ +// run-pass + +const S: &str = "foo"; +pub const B: &[u8] = S.as_bytes(); +pub const C: usize = B.len(); +pub const D: bool = B.is_empty(); +pub const E: bool = S.is_empty(); +pub const F: usize = S.len(); + +pub fn foo() -> [u8; S.len()] { + let mut buf = [0; S.len()]; + for (i, &c) in S.as_bytes().iter().enumerate() { + buf[i] = c; + } + buf +} + +fn main() { + assert_eq!(&foo()[..], b"foo"); + assert_eq!(foo().len(), S.len()); + const LEN: usize = S.len(); + assert_eq!(LEN, S.len()); + assert_eq!(B, foo()); + assert_eq!(B, b"foo"); + assert_eq!(C, 3); + assert_eq!(F, 3); + assert!(!D); + assert!(!E); + const EMPTY: bool = "".is_empty(); + assert!(EMPTY); +} diff --git a/tests/ui/consts/const-eval/transmute-const-promotion.rs b/tests/ui/consts/const-eval/transmute-const-promotion.rs new file mode 100644 index 000000000..1f0240d4b --- /dev/null +++ b/tests/ui/consts/const-eval/transmute-const-promotion.rs @@ -0,0 +1,6 @@ +use std::mem; + +fn main() { + let x: &'static u32 = unsafe { &mem::transmute(3.0f32) }; + //~^ ERROR temporary value dropped while borrowed +} diff --git a/tests/ui/consts/const-eval/transmute-const-promotion.stderr b/tests/ui/consts/const-eval/transmute-const-promotion.stderr new file mode 100644 index 000000000..434a957f6 --- /dev/null +++ b/tests/ui/consts/const-eval/transmute-const-promotion.stderr @@ -0,0 +1,14 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/transmute-const-promotion.rs:4:37 + | +LL | let x: &'static u32 = unsafe { &mem::transmute(3.0f32) }; + | ------------ ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/const-eval/transmute-const.32bit.stderr b/tests/ui/consts/const-eval/transmute-const.32bit.stderr new file mode 100644 index 000000000..09fd79986 --- /dev/null +++ b/tests/ui/consts/const-eval/transmute-const.32bit.stderr @@ -0,0 +1,14 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/transmute-const.rs:4:1 + | +LL | static FOO: bool = unsafe { mem::transmute(3u8) }; + | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 1, align: 1) { + 03 │ . + } + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/transmute-const.64bit.stderr b/tests/ui/consts/const-eval/transmute-const.64bit.stderr new file mode 100644 index 000000000..09fd79986 --- /dev/null +++ b/tests/ui/consts/const-eval/transmute-const.64bit.stderr @@ -0,0 +1,14 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/transmute-const.rs:4:1 + | +LL | static FOO: bool = unsafe { mem::transmute(3u8) }; + | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 1, align: 1) { + 03 │ . + } + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/transmute-const.rs b/tests/ui/consts/const-eval/transmute-const.rs new file mode 100644 index 000000000..d9d0a3aea --- /dev/null +++ b/tests/ui/consts/const-eval/transmute-const.rs @@ -0,0 +1,7 @@ +// stderr-per-bitwidth +use std::mem; + +static FOO: bool = unsafe { mem::transmute(3u8) }; +//~^ ERROR it is undefined behavior to use this value + +fn main() {} diff --git a/tests/ui/consts/const-eval/ub-enum-overwrite.rs b/tests/ui/consts/const-eval/ub-enum-overwrite.rs new file mode 100644 index 000000000..086a1001d --- /dev/null +++ b/tests/ui/consts/const-eval/ub-enum-overwrite.rs @@ -0,0 +1,18 @@ +#![feature(const_mut_refs)] + +enum E { + A(u8), + B, +} + +const _: u8 = { + let mut e = E::A(1); + let p = if let E::A(x) = &mut e { x as *mut u8 } else { unreachable!() }; + // Make sure overwriting `e` uninitializes other bytes + e = E::B; + unsafe { *p } + //~^ ERROR evaluation of constant value failed + //~| uninitialized +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/ub-enum-overwrite.stderr b/tests/ui/consts/const-eval/ub-enum-overwrite.stderr new file mode 100644 index 000000000..5750212b4 --- /dev/null +++ b/tests/ui/consts/const-eval/ub-enum-overwrite.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/ub-enum-overwrite.rs:13:14 + | +LL | unsafe { *p } + | ^^ using uninitialized data, but this operation requires initialized memory + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/ub-enum.32bit.stderr b/tests/ui/consts/const-eval/ub-enum.32bit.stderr new file mode 100644 index 000000000..2d86bd88f --- /dev/null +++ b/tests/ui/consts/const-eval/ub-enum.32bit.stderr @@ -0,0 +1,121 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:27:1 + | +LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x00000001, but expected a valid enum tag + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-enum.rs:30:1 + | +LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-enum.rs:33:1 + | +LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:45:1 + | +LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x00000000, but expected a valid enum tag + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-enum.rs:47:1 + | +LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-enum.rs:50:1 + | +LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-enum.rs:59:42 + | +LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-enum.rs:64:1 + | +LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:81:1 + | +LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(B)>.0: encountered a value of the never type `!` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:83:1 + | +LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(D)>.0: encountered a value of uninhabited type Never + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:91:1 + | +LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-enum.rs:96:77 + | +LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) }; + | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-enum.rs:98:77 + | +LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; + | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + +error: aborting due to 13 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/ub-enum.64bit.stderr b/tests/ui/consts/const-eval/ub-enum.64bit.stderr new file mode 100644 index 000000000..a89d7ec5f --- /dev/null +++ b/tests/ui/consts/const-eval/ub-enum.64bit.stderr @@ -0,0 +1,121 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:27:1 + | +LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x0000000000000001, but expected a valid enum tag + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-enum.rs:30:1 + | +LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-enum.rs:33:1 + | +LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:45:1 + | +LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-enum.rs:47:1 + | +LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-enum.rs:50:1 + | +LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-enum.rs:59:42 + | +LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-enum.rs:64:1 + | +LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:81:1 + | +LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(B)>.0: encountered a value of the never type `!` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:83:1 + | +LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(D)>.0: encountered a value of uninhabited type Never + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:91:1 + | +LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-enum.rs:96:77 + | +LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) }; + | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-enum.rs:98:77 + | +LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; + | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + +error: aborting due to 13 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/ub-enum.rs b/tests/ui/consts/const-eval/ub-enum.rs new file mode 100644 index 000000000..8f26d9a00 --- /dev/null +++ b/tests/ui/consts/const-eval/ub-enum.rs @@ -0,0 +1,102 @@ +// stderr-per-bitwidth +// Strip out raw byte dumps to make comparison platform-independent: +// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" +// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" +#![feature(never_type)] +#![allow(invalid_value)] + +use std::mem; + +#[repr(transparent)] +#[derive(Copy, Clone)] +struct Wrap<T>(T); + +#[derive(Copy, Clone)] +enum Never {} + +// # simple enum with discriminant 0 + +#[repr(usize)] +#[derive(Copy, Clone)] +enum Enum { + A = 0, +} + +const GOOD_ENUM: Enum = unsafe { mem::transmute(0usize) }; + +const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; +//~^ ERROR is undefined behavior + +const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; +//~^ ERROR evaluation of constant value failed + +const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) }; +//~^ ERROR evaluation of constant value failed + +// # simple enum with discriminant 2 + +// (Potentially) invalid enum discriminant +#[repr(usize)] +#[derive(Copy, Clone)] +enum Enum2 { + A = 2, +} + +const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; +//~^ ERROR is undefined behavior +const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; +//~^ ERROR evaluation of constant value failed +// something wrapping the enum so that we test layout first, not enum +const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) }; +//~^ ERROR evaluation of constant value failed + +// Undef enum discriminant. +#[repr(C)] +union MaybeUninit<T: Copy> { + uninit: (), + init: T, +} +const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init }; +//~^ ERROR evaluation of constant value failed +//~| uninitialized + +// Pointer value in an enum with a niche that is not just 0. +const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) }; +//~^ ERROR evaluation of constant value failed + +// # valid discriminant for uninhabited variant + +// An enum with 3 variants of which some are uninhabited -- so the uninhabited variants *do* +// have a discriminant. +enum UninhDiscriminant { + A, + B(!), + C, + D(Never), +} + +const GOOD_INHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(0u8) }; // variant A +const GOOD_INHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(2u8) }; // variant C + +const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; +//~^ ERROR is undefined behavior +const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; +//~^ ERROR is undefined behavior + +// # other + +// Invalid enum field content (mostly to test printing of paths for enum tuple +// variants and tuples). +// Need to create something which does not clash with enum layout optimizations. +const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); +//~^ ERROR is undefined behavior + +// All variants are uninhabited but also have data. +// Use `0` as constant to make behavior endianness-independent. +const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) }; +//~^ ERROR evaluation of constant value failed +const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; +//~^ ERROR evaluation of constant value failed + +fn main() { +} diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr b/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr new file mode 100644 index 000000000..965256de2 --- /dev/null +++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr @@ -0,0 +1,59 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/ub-incorrect-vtable.rs:19:14 + | +LL | unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-incorrect-vtable.rs:24:14 + | +LL | unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-incorrect-vtable.rs:33:1 + | +LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾─allocN─╼ ╾─allocN─╼ │ ╾──╼╾──╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-incorrect-vtable.rs:38:1 + | +LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾─allocN─╼ ╾─allocN─╼ │ ╾──╼╾──╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-incorrect-vtable.rs:44:1 + | +LL | const INVALID_VTABLE_UB: W<&dyn Trait> = + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾─allocN─╼ ╾─allocN─╼ │ ╾──╼╾──╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-incorrect-vtable.rs:91:1 + | +LL | const G: Wide = unsafe { Transmute { t: FOO }.u }; + | ^^^^^^^^^^^^^ constructing invalid value at .1: encountered a dangling reference (going beyond the bounds of its allocation) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾─allocN─╼ ╾─allocN─╼ │ ╾──╼╾──╼ + } + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr b/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr new file mode 100644 index 000000000..bd542a7a5 --- /dev/null +++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr @@ -0,0 +1,59 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/ub-incorrect-vtable.rs:19:14 + | +LL | unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-incorrect-vtable.rs:24:14 + | +LL | unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-incorrect-vtable.rs:33:1 + | +LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-incorrect-vtable.rs:38:1 + | +LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-incorrect-vtable.rs:44:1 + | +LL | const INVALID_VTABLE_UB: W<&dyn Trait> = + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-incorrect-vtable.rs:91:1 + | +LL | const G: Wide = unsafe { Transmute { t: FOO }.u }; + | ^^^^^^^^^^^^^ constructing invalid value at .1: encountered a dangling reference (going beyond the bounds of its allocation) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼ + } + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.rs b/tests/ui/consts/const-eval/ub-incorrect-vtable.rs new file mode 100644 index 000000000..4bb30b75b --- /dev/null +++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.rs @@ -0,0 +1,96 @@ +// This test contains code with incorrect vtables in a const context: +// - from issue 86132: a trait object with invalid alignment caused an ICE in const eval, and now +// triggers an error +// - a similar test that triggers a previously-untested const UB error: emitted close to the above +// error, it checks the correctness of the size +// +// As is, this code will only hard error when the constants are used, and the errors are emitted via +// the `#[allow]`-able `const_err` lint. However, if the transparent wrapper technique to prevent +// reborrows is used -- from `ub-wide-ptr.rs` -- these two errors reach validation and would trigger +// ICEs as tracked by #86193. So we also use the transparent wrapper to verify proper validation +// errors are emitted instead of ICEs. + +// stderr-per-bitwidth +// normalize-stderr-test "alloc\d+" -> "allocN" + +trait Trait {} + +const INVALID_VTABLE_ALIGNMENT: &dyn Trait = + unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; +//~^ ERROR evaluation of constant value failed +//~| does not point to a vtable + +const INVALID_VTABLE_SIZE: &dyn Trait = + unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; +//~^ ERROR evaluation of constant value failed +//~| does not point to a vtable + +#[repr(transparent)] +struct W<T>(T); + +fn drop_me(_: *mut usize) {} + +const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = + unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1000usize))) }; +//~^^ ERROR it is undefined behavior to use this value +//~| expected a vtable pointer + +const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = + unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), usize::MAX, 1usize))) }; +//~^^ ERROR it is undefined behavior to use this value +//~| expected a vtable pointer + +// Even if the vtable has a fn ptr and a reasonable size+align, it still does not work. +const INVALID_VTABLE_UB: W<&dyn Trait> = + unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1usize))) }; +//~^^ ERROR it is undefined behavior to use this value +//~| expected a vtable pointer + +// Trying to access the data in a vtable does not work, either. + +#[derive(Copy, Clone)] +struct Wide<'a>(&'a Foo, &'static VTable); + +struct VTable { + drop: Option<for<'a> fn(&'a mut Foo)>, + size: usize, + align: usize, + bar: for<'a> fn(&'a Foo) -> u32, +} + +trait Bar { + fn bar(&self) -> u32; +} + +struct Foo { + foo: u32, + bar: bool, +} + +impl Bar for Foo { + fn bar(&self) -> u32 { + self.foo + } +} + +impl Drop for Foo { + fn drop(&mut self) { + assert!(!self.bar); + self.bar = true; + println!("dropping Foo"); + } +} + +#[repr(C)] +union Transmute<T: Copy, U: Copy> { + t: T, + u: U, +} + +const FOO: &dyn Bar = &Foo { foo: 128, bar: false }; +const G: Wide = unsafe { Transmute { t: FOO }.u }; +//~^ ERROR it is undefined behavior to use this value +//~| encountered a dangling reference +// (it is dangling because vtables do not contain memory that can be dereferenced) + +fn main() {} diff --git a/tests/ui/consts/const-eval/ub-int-array.32bit.stderr b/tests/ui/consts/const-eval/ub-int-array.32bit.stderr new file mode 100644 index 000000000..edcde13b0 --- /dev/null +++ b/tests/ui/consts/const-eval/ub-int-array.32bit.stderr @@ -0,0 +1,21 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/ub-int-array.rs:15:9 + | +LL | MaybeUninit { uninit: () }.init, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-int-array.rs:30:13 + | +LL | MaybeUninit { uninit: () }.init, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-int-array.rs:56:13 + | +LL | MaybeUninit { uninit: () }.init, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/ub-int-array.64bit.stderr b/tests/ui/consts/const-eval/ub-int-array.64bit.stderr new file mode 100644 index 000000000..edcde13b0 --- /dev/null +++ b/tests/ui/consts/const-eval/ub-int-array.64bit.stderr @@ -0,0 +1,21 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/ub-int-array.rs:15:9 + | +LL | MaybeUninit { uninit: () }.init, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-int-array.rs:30:13 + | +LL | MaybeUninit { uninit: () }.init, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-int-array.rs:56:13 + | +LL | MaybeUninit { uninit: () }.init, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/ub-int-array.rs b/tests/ui/consts/const-eval/ub-int-array.rs new file mode 100644 index 000000000..a68d3fb17 --- /dev/null +++ b/tests/ui/consts/const-eval/ub-int-array.rs @@ -0,0 +1,63 @@ +// stderr-per-bitwidth +//! Test the "array of int" fast path in validity checking, and in particular whether it +//! points at the right array element. + +use std::mem; + +#[repr(C)] +union MaybeUninit<T: Copy> { + uninit: (), + init: T, +} + +const UNINIT_INT_0: [u32; 3] = unsafe { + [ + MaybeUninit { uninit: () }.init, + //~^ ERROR evaluation of constant value failed + //~| uninitialized + 1, + 2, + ] +}; +const UNINIT_INT_1: [u32; 3] = unsafe { + mem::transmute( + [ + 0u8, + 0u8, + 0u8, + 0u8, + 1u8, + MaybeUninit { uninit: () }.init, + //~^ ERROR evaluation of constant value failed + //~| uninitialized + 1u8, + 1u8, + 2u8, + 2u8, + MaybeUninit { uninit: () }.init, + 2u8, + ] + ) +}; +const UNINIT_INT_2: [u32; 3] = unsafe { + mem::transmute( + [ + 0u8, + 0u8, + 0u8, + 0u8, + 1u8, + 1u8, + 1u8, + 1u8, + 2u8, + 2u8, + 2u8, + MaybeUninit { uninit: () }.init, + //~^ ERROR evaluation of constant value failed + //~| uninitialized + ] + ) +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/ub-nonnull.chalk.64bit.stderr b/tests/ui/consts/const-eval/ub-nonnull.chalk.64bit.stderr new file mode 100644 index 000000000..2a4b6f3b7 --- /dev/null +++ b/tests/ui/consts/const-eval/ub-nonnull.chalk.64bit.stderr @@ -0,0 +1,9 @@ +error[E0284]: type annotations needed: cannot satisfy `<usize as SliceIndex<[u8]>>::Output == _` + --> $DIR/ub-nonnull.rs:19:30 + | +LL | let out_of_bounds_ptr = &ptr[255]; + | ^^^^^^^^ cannot satisfy `<usize as SliceIndex<[u8]>>::Output == _` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/consts/const-eval/ub-nonnull.rs b/tests/ui/consts/const-eval/ub-nonnull.rs new file mode 100644 index 000000000..a64b3a74c --- /dev/null +++ b/tests/ui/consts/const-eval/ub-nonnull.rs @@ -0,0 +1,59 @@ +// Strip out raw byte dumps to make comparison platform-independent: +// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" +// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" +#![feature(rustc_attrs, ptr_metadata)] +#![allow(invalid_value)] // make sure we cannot allow away the errors tested here + +use std::mem; +use std::ptr::NonNull; +use std::num::{NonZeroU8, NonZeroUsize}; + +const NON_NULL: NonNull<u8> = unsafe { mem::transmute(1usize) }; +const NON_NULL_PTR: NonNull<u8> = unsafe { mem::transmute(&1) }; + +const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) }; +//~^ ERROR it is undefined behavior to use this value + +const OUT_OF_BOUNDS_PTR: NonNull<u8> = { unsafe { + let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle + // Use address-of-element for pointer arithmetic. This could wrap around to null! + let out_of_bounds_ptr = &ptr[255]; //~ ERROR evaluation of constant value failed + mem::transmute(out_of_bounds_ptr) +} }; + +const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; +//~^ ERROR it is undefined behavior to use this value +const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; +//~^ ERROR it is undefined behavior to use this value + +#[repr(C)] +union MaybeUninit<T: Copy> { + uninit: (), + init: T, +} +const UNINIT: NonZeroU8 = unsafe { MaybeUninit { uninit: () }.init }; +//~^ ERROR evaluation of constant value failed +//~| uninitialized + +// Also test other uses of rustc_layout_scalar_valid_range_start + +#[rustc_layout_scalar_valid_range_start(10)] +#[rustc_layout_scalar_valid_range_end(30)] +struct RestrictedRange1(u32); +const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; +//~^ ERROR it is undefined behavior to use this value + +#[rustc_layout_scalar_valid_range_start(30)] +#[rustc_layout_scalar_valid_range_end(10)] +struct RestrictedRange2(u32); +const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; +//~^ ERROR it is undefined behavior to use this value + +const NULL_FAT_PTR: NonNull<dyn Send> = unsafe { +//~^ ERROR it is undefined behavior to use this value + let x: &dyn Send = &42; + let meta = std::ptr::metadata(x); + mem::transmute((0_usize, meta)) +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/ub-nonnull.stderr b/tests/ui/consts/const-eval/ub-nonnull.stderr new file mode 100644 index 000000000..961648708 --- /dev/null +++ b/tests/ui/consts/const-eval/ub-nonnull.stderr @@ -0,0 +1,81 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-nonnull.rs:14:1 + | +LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-nonnull.rs:20:30 + | +LL | let out_of_bounds_ptr = &ptr[255]; + | ^^^^^^^^ dereferencing pointer failed: alloc11 has size 1, so pointer to 256 bytes starting at offset 0 is out-of-bounds + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-nonnull.rs:24:1 + | +LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-nonnull.rs:26:1 + | +LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-nonnull.rs:34:36 + | +LL | const UNINIT: NonZeroU8 = unsafe { MaybeUninit { uninit: () }.init }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-nonnull.rs:43:1 + | +LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 42, but expected something in the range 10..=30 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-nonnull.rs:49:1 + | +LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-nonnull.rs:52:1 + | +LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.rs b/tests/ui/consts/const-eval/ub-ref-ptr.rs new file mode 100644 index 000000000..369e45194 --- /dev/null +++ b/tests/ui/consts/const-eval/ub-ref-ptr.rs @@ -0,0 +1,71 @@ +// ignore-tidy-linelength +// Strip out raw byte dumps to make comparison platform-independent: +// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" +// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" +#![allow(invalid_value)] +#![feature(const_ptr_read)] + +use std::mem; + +#[repr(C)] +union MaybeUninit<T: Copy> { + uninit: (), + init: T, +} + +const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; +//~^ ERROR it is undefined behavior to use this value +//~| constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) + +const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) }; +//~^ ERROR it is undefined behavior to use this value +//~| constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) + +const NULL: &u16 = unsafe { mem::transmute(0usize) }; +//~^ ERROR it is undefined behavior to use this value + +const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) }; +//~^ ERROR it is undefined behavior to use this value + + +// It is very important that we reject this: We do promote `&(4 * REF_AS_USIZE)`, +// but that would fail to compile; so we ended up breaking user code that would +// have worked fine had we not promoted. +const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; +//~^ ERROR evaluation of constant value failed + +const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; +//~^ ERROR evaluation of constant value failed + +const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; +//~^ ERROR evaluation of constant value failed + +const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; +//~^ ERROR it is undefined behavior to use this value + +const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) }; +//~^ ERROR it is undefined behavior to use this value + +const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init }; +//~^ ERROR evaluation of constant value failed +//~| uninitialized + +const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; +//~^ ERROR it is undefined behavior to use this value +const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init }; +//~^ ERROR evaluation of constant value failed +//~| uninitialized +const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; +//~^ ERROR it is undefined behavior to use this value +const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; +//~^ ERROR it is undefined behavior to use this value + + +const UNALIGNED_READ: () = unsafe { + let x = &[0u8; 4]; + let ptr = x.as_ptr().cast::<u32>(); + ptr.read(); //~ inside `UNALIGNED_READ` +}; + + +fn main() {} diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.stderr b/tests/ui/consts/const-eval/ub-ref-ptr.stderr new file mode 100644 index 000000000..ce618802b --- /dev/null +++ b/tests/ui/consts/const-eval/ub-ref-ptr.stderr @@ -0,0 +1,186 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-ref-ptr.rs:16:1 + | +LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-ref-ptr.rs:20:1 + | +LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-ref-ptr.rs:24:1 + | +LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-ref-ptr.rs:27:1 + | +LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-ref-ptr.rs:34:1 + | +LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-ref-ptr.rs:37:39 + | +LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +note: erroneous constant used + --> $DIR/ub-ref-ptr.rs:37:38 + | +LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-ref-ptr.rs:40:86 + | +LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; + | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +note: erroneous constant used + --> $DIR/ub-ref-ptr.rs:40:85 + | +LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-ref-ptr.rs:43:1 + | +LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x539 is unallocated) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-ref-ptr.rs:46:1 + | +LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (address 0x539 is unallocated) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-ref-ptr.rs:49:41 + | +LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-ref-ptr.rs:53:1 + | +LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-ref-ptr.rs:55:38 + | +LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-ref-ptr.rs:58:1 + | +LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-ref-ptr.rs:60:1 + | +LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered alloc41, but expected a function pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error: accessing memory with alignment 1, but alignment 4 is required + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/104616> +note: inside `std::ptr::read::<u32>` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL +note: inside `ptr::const_ptr::<impl *const u32>::read` + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL +note: inside `UNALIGNED_READ` + --> $DIR/ub-ref-ptr.rs:67:5 + | +LL | ptr.read(); + | ^^^^^^^^^^ + = note: `#[deny(invalid_alignment)]` on by default + +error: aborting due to 15 previous errors + +For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +error: accessing memory with alignment 1, but alignment 4 is required + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/104616> +note: inside `std::ptr::read::<u32>` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL +note: inside `ptr::const_ptr::<impl *const u32>::read` + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL +note: inside `UNALIGNED_READ` + --> $DIR/ub-ref-ptr.rs:67:5 + | +LL | ptr.read(); + | ^^^^^^^^^^ + = note: `#[deny(invalid_alignment)]` on by default + diff --git a/tests/ui/consts/const-eval/ub-uninhabit.rs b/tests/ui/consts/const-eval/ub-uninhabit.rs new file mode 100644 index 000000000..4c4ef216d --- /dev/null +++ b/tests/ui/consts/const-eval/ub-uninhabit.rs @@ -0,0 +1,25 @@ +// Strip out raw byte dumps to make comparison platform-independent: +// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" +// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" + +use std::mem; + +#[derive(Copy, Clone)] +enum Bar {} + +#[repr(C)] +union MaybeUninit<T: Copy> { + uninit: (), + init: T, +} + +const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init }; +//~^ ERROR it is undefined behavior to use this value + +const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; +//~^ ERROR it is undefined behavior to use this value + +const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init }; +//~^ ERROR it is undefined behavior to use this value + +fn main() {} diff --git a/tests/ui/consts/const-eval/ub-uninhabit.stderr b/tests/ui/consts/const-eval/ub-uninhabit.stderr new file mode 100644 index 000000000..0ae376d03 --- /dev/null +++ b/tests/ui/consts/const-eval/ub-uninhabit.stderr @@ -0,0 +1,32 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-uninhabit.rs:16:1 + | +LL | const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init }; + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Bar + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {} + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-uninhabit.rs:19:1 + | +LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type Bar + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-uninhabit.rs:22:1 + | +LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered a value of uninhabited type Bar + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {} + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/ub-upvars.32bit.stderr b/tests/ui/consts/const-eval/ub-upvars.32bit.stderr new file mode 100644 index 000000000..f7898e55e --- /dev/null +++ b/tests/ui/consts/const-eval/ub-upvars.32bit.stderr @@ -0,0 +1,14 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-upvars.rs:6:1 + | +LL | const BAD_UPVAR: &dyn FnOnce() = &{ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>: encountered a null reference + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾─alloc3──╼ ╾─alloc4──╼ │ ╾──╼╾──╼ + } + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/ub-upvars.64bit.stderr b/tests/ui/consts/const-eval/ub-upvars.64bit.stderr new file mode 100644 index 000000000..60432380e --- /dev/null +++ b/tests/ui/consts/const-eval/ub-upvars.64bit.stderr @@ -0,0 +1,14 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-upvars.rs:6:1 + | +LL | const BAD_UPVAR: &dyn FnOnce() = &{ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>: encountered a null reference + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾───────alloc3────────╼ ╾───────alloc4────────╼ │ ╾──────╼╾──────╼ + } + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/ub-upvars.rs b/tests/ui/consts/const-eval/ub-upvars.rs new file mode 100644 index 000000000..ceac59870 --- /dev/null +++ b/tests/ui/consts/const-eval/ub-upvars.rs @@ -0,0 +1,12 @@ +// stderr-per-bitwidth +#![allow(invalid_value)] // make sure we cannot allow away the errors tested here + +use std::mem; + +const BAD_UPVAR: &dyn FnOnce() = &{ //~ ERROR it is undefined behavior to use this value + let bad_ref: &'static u16 = unsafe { mem::transmute(0usize) }; + let another_var = 13; + move || { let _ = bad_ref; let _ = another_var; } +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.chalk.64bit.stderr b/tests/ui/consts/const-eval/ub-wide-ptr.chalk.64bit.stderr new file mode 100644 index 000000000..39352ca84 --- /dev/null +++ b/tests/ui/consts/const-eval/ub-wide-ptr.chalk.64bit.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/ub-wide-ptr.rs:90:67 + | +LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); + | ^^^^^^^^^^^^^^ cannot infer type for type parameter `U` declared on the function `transmute` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.rs b/tests/ui/consts/const-eval/ub-wide-ptr.rs new file mode 100644 index 000000000..a765dc712 --- /dev/null +++ b/tests/ui/consts/const-eval/ub-wide-ptr.rs @@ -0,0 +1,159 @@ +// ignore-tidy-linelength +#![allow(unused)] + +use std::mem; + +// Strip out raw byte dumps to make comparison platform-independent: +// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" +// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" +// normalize-stderr-test "offset \d+" -> "offset N" +// normalize-stderr-test "alloc\d+" -> "allocN" +// normalize-stderr-test "size \d+" -> "size N" + +/// A newtype wrapper to prevent MIR generation from inserting reborrows that would affect the error +/// message. +#[repr(transparent)] +struct W<T>(T); + +#[repr(C)] +union MaybeUninit<T: Copy> { + uninit: (), + init: T, +} + +trait Trait {} +impl Trait for bool {} + +// custom unsized type +struct MyStr(str); + +// custom unsized type with sized fields +struct MySlice<T: ?Sized>(bool, T); +type MySliceBool = MySlice<[bool]>; + +// # str +// OK +const STR_VALID: &str = unsafe { mem::transmute((&42u8, 1usize)) }; +// bad str +const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; +//~^ ERROR it is undefined behavior to use this value +const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); +//~^ ERROR it is undefined behavior to use this value +// bad str +const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) }; +//~^ ERROR evaluation of constant value failed +// bad str in user-defined unsized type +const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) }; +//~^ ERROR evaluation of constant value failed +const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; +//~^ ERROR it is undefined behavior to use this value + +// uninitialized byte +const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; +//~^ ERROR it is undefined behavior to use this value +// uninitialized byte in user-defined str-like +const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; +//~^ ERROR it is undefined behavior to use this value + +// # slice +// OK +const SLICE_VALID: &[u8] = unsafe { mem::transmute((&42u8, 1usize)) }; +// bad slice: length uninit +const SLICE_LENGTH_UNINIT: &[u8] = unsafe { +//~^ ERROR evaluation of constant value failed +//~| uninitialized + let uninit_len = MaybeUninit::<usize> { uninit: () }; + mem::transmute((42, uninit_len)) +}; +// bad slice: length too big +const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; +//~^ ERROR it is undefined behavior to use this value +// bad slice: length computation overflows +const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; +//~^ ERROR it is undefined behavior to use this value +// bad slice: length not an int +const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; +//~^ ERROR evaluation of constant value failed +// bad slice box: length too big +const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; +//~^ ERROR it is undefined behavior to use this value +// bad slice box: length not an int +const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) }; +//~^ ERROR evaluation of constant value failed + +// bad data *inside* the slice +const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; +//~^ ERROR it is undefined behavior to use this value +//~| constant + +// good MySliceBool +const MYSLICE_GOOD: &MySliceBool = &MySlice(true, [false]); +// bad: sized field is not okay +const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); +//~^ ERROR it is undefined behavior to use this value +//~| constant +// bad: unsized part is not okay +const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); +//~^ ERROR it is undefined behavior to use this value +//~| constant + +// # raw slice +const RAW_SLICE_VALID: *const [u8] = unsafe { mem::transmute((&42u8, 1usize)) }; // ok +const RAW_SLICE_TOO_LONG: *const [u8] = unsafe { mem::transmute((&42u8, 999usize)) }; // ok because raw +const RAW_SLICE_MUCH_TOO_LONG: *const [u8] = unsafe { mem::transmute((&42u8, usize::MAX)) }; // ok because raw +const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { +//~^ ERROR evaluation of constant value failed +//~| uninitialized + let uninit_len = MaybeUninit::<usize> { uninit: () }; + mem::transmute((42, uninit_len)) +}; + +// # trait object +// bad trait object +const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; +//~^ ERROR it is undefined behavior to use this value +//~| expected a vtable +// bad trait object +const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; +//~^ ERROR it is undefined behavior to use this value +//~| expected a vtable +// bad trait object +const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; +//~^ ERROR it is undefined behavior to use this value +//~| expected a vtable +const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; +//~^ ERROR evaluation of constant value failed +//~| does not point to a vtable +const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; +//~^ ERROR evaluation of constant value failed +//~| does not point to a vtable +const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; +//~^ ERROR evaluation of constant value failed +//~| does not point to a vtable +const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; +//~^ ERROR it is undefined behavior to use this value +//~| expected a vtable + +// bad data *inside* the trait object +const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; +//~^ ERROR it is undefined behavior to use this value +//~| expected a boolean + +// # raw trait object +const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; +//~^ ERROR it is undefined behavior to use this value +const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; +//~^ ERROR it is undefined behavior to use this value +const RAW_TRAIT_OBJ_CONTENT_INVALID: *const dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) } as *const dyn Trait; // ok because raw + +// Const eval fails for these, so they need to be statics to error. +static mut RAW_TRAIT_OBJ_VTABLE_NULL_THROUGH_REF: *const dyn Trait = unsafe { + mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) + //~^ ERROR could not evaluate static initializer +}; +static mut RAW_TRAIT_OBJ_VTABLE_INVALID_THROUGH_REF: *const dyn Trait = unsafe { + mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) + //~^ ERROR could not evaluate static initializer +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.stderr b/tests/ui/consts/const-eval/ub-wide-ptr.stderr new file mode 100644 index 000000000..f38e7916b --- /dev/null +++ b/tests/ui/consts/const-eval/ub-wide-ptr.stderr @@ -0,0 +1,297 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:38:1 + | +LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:40:1 + | +LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-wide-ptr.rs:43:1 + | +LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-wide-ptr.rs:46:1 + | +LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:48:1 + | +LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:52:1 + | +LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:55:1 + | +LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-wide-ptr.rs:62:1 + | +LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:69:1 + | +LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:72:1 + | +LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-wide-ptr.rs:75:1 + | +LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:78:1 + | +LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-wide-ptr.rs:81:1 + | +LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:85:1 + | +LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +note: erroneous constant used + --> $DIR/ub-wide-ptr.rs:85:40 + | +LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:92:1 + | +LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +note: erroneous constant used + --> $DIR/ub-wide-ptr.rs:92:42 + | +LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:96:1 + | +LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +note: erroneous constant used + --> $DIR/ub-wide-ptr.rs:96:42 + | +LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-wide-ptr.rs:104:1 + | +LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:113:1 + | +LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:117:1 + | +LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:121:1 + | +LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-wide-ptr.rs:124:57 + | +LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-wide-ptr.rs:127:57 + | +LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + +error[E0080]: evaluation of constant value failed + --> $DIR/ub-wide-ptr.rs:130:56 + | +LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:133:1 + | +LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:138:1 + | +LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:143:1 + | +LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:145:1 + | +LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: could not evaluate static initializer + --> $DIR/ub-wide-ptr.rs:151:5 + | +LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) + +error[E0080]: could not evaluate static initializer + --> $DIR/ub-wide-ptr.rs:155:5 + | +LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + +error: aborting due to 29 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/union-const-eval-field.rs b/tests/ui/consts/const-eval/union-const-eval-field.rs new file mode 100644 index 000000000..a94fcbbfa --- /dev/null +++ b/tests/ui/consts/const-eval/union-const-eval-field.rs @@ -0,0 +1,38 @@ +// only-x86_64 + +type Field1 = i32; +type Field2 = f32; +type Field3 = i64; + +#[repr(C)] +union DummyUnion { + field1: Field1, + field2: Field2, + field3: Field3, +} + +const FLOAT1_AS_I32: i32 = 1065353216; +const UNION: DummyUnion = DummyUnion { field1: FLOAT1_AS_I32 }; + +const fn read_field1() -> Field1 { + const FIELD1: Field1 = unsafe { UNION.field1 }; + FIELD1 +} + +const fn read_field2() -> Field2 { + const FIELD2: Field2 = unsafe { UNION.field2 }; + FIELD2 +} + +const fn read_field3() -> Field3 { + const FIELD3: Field3 = unsafe { UNION.field3 }; + //~^ ERROR evaluation of constant value failed + //~| uninitialized + FIELD3 +} + +fn main() { + assert_eq!(read_field1(), FLOAT1_AS_I32); + assert_eq!(read_field2(), 1.0); + assert_eq!(read_field3(), unsafe { UNION.field3 }); +} diff --git a/tests/ui/consts/const-eval/union-const-eval-field.stderr b/tests/ui/consts/const-eval/union-const-eval-field.stderr new file mode 100644 index 000000000..9899c56c0 --- /dev/null +++ b/tests/ui/consts/const-eval/union-const-eval-field.stderr @@ -0,0 +1,21 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/union-const-eval-field.rs:28:37 + | +LL | const FIELD3: Field3 = unsafe { UNION.field3 }; + | ^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +note: erroneous constant used + --> $DIR/union-const-eval-field.rs:31:5 + | +LL | FIELD3 + | ^^^^^^ + +note: erroneous constant used + --> $DIR/union-const-eval-field.rs:31:5 + | +LL | FIELD3 + | ^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/union-ice.rs b/tests/ui/consts/const-eval/union-ice.rs new file mode 100644 index 000000000..dd970a355 --- /dev/null +++ b/tests/ui/consts/const-eval/union-ice.rs @@ -0,0 +1,48 @@ +// only-x86_64 + +type Field1 = i32; +type Field3 = i64; + +#[repr(C)] +union DummyUnion { + field1: Field1, + field3: Field3, +} + +const UNION: DummyUnion = DummyUnion { field1: 1065353216 }; + +const FIELD3: Field3 = unsafe { UNION.field3 }; +//~^ ERROR evaluation of constant value failed +//~| uninitialized + +const FIELD_PATH: Struct = Struct { + a: 42, + b: unsafe { UNION.field3 }, + //~^ ERROR evaluation of constant value failed + //~| uninitialized +}; + +struct Struct { + a: u8, + b: Field3, +} + +const FIELD_PATH2: Struct2 = Struct2 { + b: [ + 21, + unsafe { UNION.field3 }, + //~^ ERROR evaluation of constant value failed + //~| uninitialized + 23, + 24, + ], + a: 42, +}; + +struct Struct2 { + b: [Field3; 4], + a: u8, +} + +fn main() { +} diff --git a/tests/ui/consts/const-eval/union-ice.stderr b/tests/ui/consts/const-eval/union-ice.stderr new file mode 100644 index 000000000..bd39a0551 --- /dev/null +++ b/tests/ui/consts/const-eval/union-ice.stderr @@ -0,0 +1,21 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/union-ice.rs:14:33 + | +LL | const FIELD3: Field3 = unsafe { UNION.field3 }; + | ^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +error[E0080]: evaluation of constant value failed + --> $DIR/union-ice.rs:20:17 + | +LL | b: unsafe { UNION.field3 }, + | ^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +error[E0080]: evaluation of constant value failed + --> $DIR/union-ice.rs:33:18 + | +LL | unsafe { UNION.field3 }, + | ^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/union-ub.32bit.stderr b/tests/ui/consts/const-eval/union-ub.32bit.stderr new file mode 100644 index 000000000..e5c8f88be --- /dev/null +++ b/tests/ui/consts/const-eval/union-ub.32bit.stderr @@ -0,0 +1,20 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/union-ub.rs:32:1 + | +LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool}; + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x2a, but expected a boolean + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 1, align: 1) { + 2a │ * + } + +error[E0080]: evaluation of constant value failed + --> $DIR/union-ub.rs:34:36 + | +LL | const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/union-ub.64bit.stderr b/tests/ui/consts/const-eval/union-ub.64bit.stderr new file mode 100644 index 000000000..e5c8f88be --- /dev/null +++ b/tests/ui/consts/const-eval/union-ub.64bit.stderr @@ -0,0 +1,20 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/union-ub.rs:32:1 + | +LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool}; + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x2a, but expected a boolean + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 1, align: 1) { + 2a │ * + } + +error[E0080]: evaluation of constant value failed + --> $DIR/union-ub.rs:34:36 + | +LL | const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/union-ub.rs b/tests/ui/consts/const-eval/union-ub.rs new file mode 100644 index 000000000..043870c9c --- /dev/null +++ b/tests/ui/consts/const-eval/union-ub.rs @@ -0,0 +1,43 @@ +// stderr-per-bitwidth + +#[repr(C)] +union DummyUnion { + unit: (), + u8: u8, + bool: bool, +} + +#[repr(C)] +#[derive(Copy, Clone)] +enum Enum { + A, + B, + C, +} + +#[derive(Copy, Clone)] +#[repr(C)] +union Foo { + a: bool, + b: Enum, +} + +#[repr(C)] +union Bar { + foo: Foo, + u8: u8, +} + +// the value is not valid for bools +const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool}; +//~^ ERROR it is undefined behavior to use this value +const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool}; +//~^ ERROR evaluation of constant value failed +//~| uninitialized + +// The value is not valid for any union variant, but that's fine +// unions are just a convenient way to transmute bits around +const BAD_UNION: Foo = unsafe { Bar { u8: 42 }.foo }; + + +fn main() {} diff --git a/tests/ui/consts/const-eval/union_promotion.rs b/tests/ui/consts/const-eval/union_promotion.rs new file mode 100644 index 000000000..18894c45f --- /dev/null +++ b/tests/ui/consts/const-eval/union_promotion.rs @@ -0,0 +1,11 @@ +#[repr(C)] +union Foo { + a: &'static u32, + b: usize, +} + +fn main() { + let x: &'static bool = &unsafe { //~ temporary value dropped while borrowed + Foo { a: &1 }.b == Foo { a: &2 }.b + }; +} diff --git a/tests/ui/consts/const-eval/union_promotion.stderr b/tests/ui/consts/const-eval/union_promotion.stderr new file mode 100644 index 000000000..42f17de20 --- /dev/null +++ b/tests/ui/consts/const-eval/union_promotion.stderr @@ -0,0 +1,16 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/union_promotion.rs:8:29 + | +LL | let x: &'static bool = &unsafe { + | ____________-------------____^ + | | | + | | type annotation requires that borrow lasts for `'static` +LL | | Foo { a: &1 }.b == Foo { a: &2 }.b +LL | | }; + | |_____^ creates a temporary value which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/const-eval/unused-broken-const.rs b/tests/ui/consts/const-eval/unused-broken-const.rs new file mode 100644 index 000000000..0d2776bc2 --- /dev/null +++ b/tests/ui/consts/const-eval/unused-broken-const.rs @@ -0,0 +1,8 @@ +// make sure that an *unused* broken const triggers an error even in a check build + +// compile-flags: --emit=dep-info,metadata + +const FOO: i32 = [][0]; +//~^ ERROR evaluation of constant value failed + +fn main() {} diff --git a/tests/ui/consts/const-eval/unused-broken-const.stderr b/tests/ui/consts/const-eval/unused-broken-const.stderr new file mode 100644 index 000000000..fbb10feb7 --- /dev/null +++ b/tests/ui/consts/const-eval/unused-broken-const.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/unused-broken-const.rs:5:18 + | +LL | const FOO: i32 = [][0]; + | ^^^^^ index out of bounds: the length is 0 but the index is 0 + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/unwind-abort.rs b/tests/ui/consts/const-eval/unwind-abort.rs new file mode 100644 index 000000000..2b0e58166 --- /dev/null +++ b/tests/ui/consts/const-eval/unwind-abort.rs @@ -0,0 +1,12 @@ +#![feature(c_unwind, const_extern_fn)] + +const extern "C" fn foo() { + panic!() //~ ERROR evaluation of constant value failed +} + +const _: () = foo(); +// Ensure that the CTFE engine handles calls to `extern "C"` aborting gracefully + +fn main() { + let _ = foo(); +} diff --git a/tests/ui/consts/const-eval/unwind-abort.stderr b/tests/ui/consts/const-eval/unwind-abort.stderr new file mode 100644 index 000000000..759ce15ab --- /dev/null +++ b/tests/ui/consts/const-eval/unwind-abort.stderr @@ -0,0 +1,21 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/unwind-abort.rs:4:5 + | +LL | panic!() + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/unwind-abort.rs:4:5 + | +note: inside `foo` + --> $DIR/unwind-abort.rs:4:5 + | +LL | panic!() + | ^^^^^^^^ +note: inside `_` + --> $DIR/unwind-abort.rs:7:15 + | +LL | const _: () = foo(); + | ^^^^^ + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/valid-const.rs b/tests/ui/consts/const-eval/valid-const.rs new file mode 100644 index 000000000..5f47d1c4f --- /dev/null +++ b/tests/ui/consts/const-eval/valid-const.rs @@ -0,0 +1,17 @@ +// check-pass + +// Some constants that *are* valid + +use std::mem; +use std::ptr::NonNull; +use std::num::{NonZeroU8, NonZeroUsize}; + +const NON_NULL_PTR1: NonNull<u8> = unsafe { mem::transmute(1usize) }; +const NON_NULL_PTR2: NonNull<u8> = unsafe { mem::transmute(&0) }; + +const NON_NULL_U8: NonZeroU8 = unsafe { mem::transmute(1u8) }; +const NON_NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(1usize) }; + +const UNIT: () = (); + +fn main() {} diff --git a/tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr b/tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr new file mode 100644 index 000000000..9710bf476 --- /dev/null +++ b/tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr @@ -0,0 +1,61 @@ +warning: the type `!` does not permit zero-initialization + --> $DIR/validate_uninhabited_zsts.rs:4:14 + | +LL | unsafe { std::mem::transmute(()) } + | ^^^^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done + | + = note: the `!` type has no valid value + = note: `#[warn(invalid_value)]` on by default + +error[E0080]: evaluation of constant value failed + --> $DIR/validate_uninhabited_zsts.rs:4:14 + | +LL | unsafe { std::mem::transmute(()) } + | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | +note: inside `foo` + --> $DIR/validate_uninhabited_zsts.rs:4:14 + | +LL | unsafe { std::mem::transmute(()) } + | ^^^^^^^^^^^^^^^^^^^^^^^ +note: inside `FOO` + --> $DIR/validate_uninhabited_zsts.rs:19:33 + | +LL | const FOO: [empty::Empty; 3] = [foo(); 3]; + | ^^^^^ + +error[E0080]: it is undefined behavior to use this value + --> $DIR/validate_uninhabited_zsts.rs:21:1 + | +LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0].0: encountered a value of uninhabited type empty::Void + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 0, align: 1) {} + +warning: the type `empty::Empty` does not permit zero-initialization + --> $DIR/validate_uninhabited_zsts.rs:21:42 + | +LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done + | +note: in this struct field + --> $DIR/validate_uninhabited_zsts.rs:16:22 + | +LL | pub struct Empty(Void); + | ^^^^ +note: enums with no inhabited variants have no valid value + --> $DIR/validate_uninhabited_zsts.rs:13:5 + | +LL | enum Void {} + | ^^^^^^^^^ + +error: aborting due to 2 previous errors; 2 warnings emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr b/tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr new file mode 100644 index 000000000..9710bf476 --- /dev/null +++ b/tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr @@ -0,0 +1,61 @@ +warning: the type `!` does not permit zero-initialization + --> $DIR/validate_uninhabited_zsts.rs:4:14 + | +LL | unsafe { std::mem::transmute(()) } + | ^^^^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done + | + = note: the `!` type has no valid value + = note: `#[warn(invalid_value)]` on by default + +error[E0080]: evaluation of constant value failed + --> $DIR/validate_uninhabited_zsts.rs:4:14 + | +LL | unsafe { std::mem::transmute(()) } + | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | +note: inside `foo` + --> $DIR/validate_uninhabited_zsts.rs:4:14 + | +LL | unsafe { std::mem::transmute(()) } + | ^^^^^^^^^^^^^^^^^^^^^^^ +note: inside `FOO` + --> $DIR/validate_uninhabited_zsts.rs:19:33 + | +LL | const FOO: [empty::Empty; 3] = [foo(); 3]; + | ^^^^^ + +error[E0080]: it is undefined behavior to use this value + --> $DIR/validate_uninhabited_zsts.rs:21:1 + | +LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0].0: encountered a value of uninhabited type empty::Void + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 0, align: 1) {} + +warning: the type `empty::Empty` does not permit zero-initialization + --> $DIR/validate_uninhabited_zsts.rs:21:42 + | +LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done + | +note: in this struct field + --> $DIR/validate_uninhabited_zsts.rs:16:22 + | +LL | pub struct Empty(Void); + | ^^^^ +note: enums with no inhabited variants have no valid value + --> $DIR/validate_uninhabited_zsts.rs:13:5 + | +LL | enum Void {} + | ^^^^^^^^^ + +error: aborting due to 2 previous errors; 2 warnings emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/validate_uninhabited_zsts.rs b/tests/ui/consts/const-eval/validate_uninhabited_zsts.rs new file mode 100644 index 000000000..c0b326215 --- /dev/null +++ b/tests/ui/consts/const-eval/validate_uninhabited_zsts.rs @@ -0,0 +1,28 @@ +// stderr-per-bitwidth + +const fn foo() -> ! { + unsafe { std::mem::transmute(()) } + //~^ ERROR evaluation of constant value failed + //~| WARN the type `!` does not permit zero-initialization [invalid_value] +} + +// Type defined in a submodule, so that it is not "visibly" +// uninhabited (which would change interpreter behavior). +pub mod empty { + #[derive(Clone, Copy)] + enum Void {} + + #[derive(Clone, Copy)] + pub struct Empty(Void); +} + +const FOO: [empty::Empty; 3] = [foo(); 3]; + +const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; +//~^ ERROR it is undefined behavior to use this value +//~| WARN the type `empty::Empty` does not permit zero-initialization + +fn main() { + FOO; + BAR; +} diff --git a/tests/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs b/tests/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs new file mode 100644 index 000000000..cccb7879f --- /dev/null +++ b/tests/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs @@ -0,0 +1,28 @@ +// run-pass + +#![allow(dead_code)] + +enum Empty { } +enum Test1 { + A(u8), + B(Empty), +} +enum Test2 { + A(u8), + B(Empty), + C, +} + +fn bar() -> Option<Empty> { + None +} + +fn main() { + if let Some(x) = bar() { + Test1::B(x); + } + + if let Some(x) = bar() { + Test2::B(x); + } +} diff --git a/tests/ui/consts/const-eval/zst_operand_eval.rs b/tests/ui/consts/const-eval/zst_operand_eval.rs new file mode 100644 index 000000000..5f7ddf7f7 --- /dev/null +++ b/tests/ui/consts/const-eval/zst_operand_eval.rs @@ -0,0 +1,5 @@ +// check-pass + +static ASSERT: () = [()][!(std::mem::size_of::<u32>() == 4) as usize]; + +fn main() {} diff --git a/tests/ui/consts/const-expr-addr-operator.rs b/tests/ui/consts/const-expr-addr-operator.rs new file mode 100644 index 000000000..37bf24c2f --- /dev/null +++ b/tests/ui/consts/const-expr-addr-operator.rs @@ -0,0 +1,11 @@ +// Encountered while testing #44614. +// build-pass (FIXME(62277): could be check-pass?) + +pub fn main() { + // Constant of generic type (int) + const X: &'static u32 = &22; + assert_eq!(0, match &22 { + X => 0, + _ => 1, + }); +} diff --git a/tests/ui/consts/const-expr-in-fixed-length-vec.rs b/tests/ui/consts/const-expr-in-fixed-length-vec.rs new file mode 100644 index 000000000..a9960b455 --- /dev/null +++ b/tests/ui/consts/const-expr-in-fixed-length-vec.rs @@ -0,0 +1,12 @@ +// run-pass +// Check that constant expressions can be used for declaring the +// type of a fixed length vector. + +// pretty-expanded FIXME #23616 + +pub fn main() { + + const FOO: usize = 2; + let _v: [isize; FOO*3]; + +} diff --git a/tests/ui/consts/const-expr-in-vec-repeat.rs b/tests/ui/consts/const-expr-in-vec-repeat.rs new file mode 100644 index 000000000..4eaef2505 --- /dev/null +++ b/tests/ui/consts/const-expr-in-vec-repeat.rs @@ -0,0 +1,11 @@ +// run-pass +// Check that constant expressions can be used in vec repeat syntax. + +// pretty-expanded FIXME #23616 + +pub fn main() { + + const FOO: usize = 2; + let _v = [0; FOO*3*2/2]; + +} diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs b/tests/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs new file mode 100644 index 000000000..eccda49db --- /dev/null +++ b/tests/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs @@ -0,0 +1,23 @@ +#![feature(const_extern_fn)] + +extern "C" { + fn regular_in_block(); +} + +const extern "C" fn bar() { + unsafe { + regular_in_block(); + //~^ ERROR: cannot call non-const fn + } +} + +extern "C" fn regular() {} + +const extern "C" fn foo() { + unsafe { + regular(); + //~^ ERROR: cannot call non-const fn + } +} + +fn main() {} diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr b/tests/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr new file mode 100644 index 000000000..5acf22e4b --- /dev/null +++ b/tests/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr @@ -0,0 +1,19 @@ +error[E0015]: cannot call non-const fn `regular_in_block` in constant functions + --> $DIR/const-extern-fn-call-extern-fn.rs:9:9 + | +LL | regular_in_block(); + | ^^^^^^^^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error[E0015]: cannot call non-const fn `regular` in constant functions + --> $DIR/const-extern-fn-call-extern-fn.rs:18:9 + | +LL | regular(); + | ^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs b/tests/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs new file mode 100644 index 000000000..c7078e46f --- /dev/null +++ b/tests/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs @@ -0,0 +1,11 @@ +#![feature(const_extern_fn)] + +const extern "C" fn unsize(x: &[u8; 3]) -> &[u8] { x } +const unsafe extern "C" fn closure() -> fn() { || {} } +const unsafe extern "C" fn use_float() { 1.0 + 1.0; } +//~^ ERROR floating point arithmetic +const extern "C" fn ptr_cast(val: *const u8) { val as usize; } +//~^ ERROR pointers cannot be cast to integers + + +fn main() {} diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr b/tests/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr new file mode 100644 index 000000000..4bab466fb --- /dev/null +++ b/tests/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr @@ -0,0 +1,21 @@ +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const-extern-fn-min-const-fn.rs:5:42 + | +LL | const unsafe extern "C" fn use_float() { 1.0 + 1.0; } + | ^^^^^^^^^ + | + = note: see issue #57241 <https://github.com/rust-lang/rust/issues/57241> for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error: pointers cannot be cast to integers during const eval + --> $DIR/const-extern-fn-min-const-fn.rs:7:48 + | +LL | const extern "C" fn ptr_cast(val: *const u8) { val as usize; } + | ^^^^^^^^^^^^ + | + = note: at compile-time, pointers do not have an integer value + = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.mir.stderr b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.mir.stderr new file mode 100644 index 000000000..34ec8aadb --- /dev/null +++ b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.mir.stderr @@ -0,0 +1,19 @@ +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/const-extern-fn-requires-unsafe.rs:12:5 + | +LL | foo(); + | ^^^^^ 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/const-extern-fn-requires-unsafe.rs:9:17 + | +LL | let a: [u8; foo()]; + | ^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs new file mode 100644 index 000000000..afe645ae8 --- /dev/null +++ b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs @@ -0,0 +1,14 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + +#![feature(const_extern_fn)] + +const unsafe extern "C" fn foo() -> usize { 5 } + +fn main() { + let a: [u8; foo()]; + //[mir]~^ call to unsafe function is unsafe and requires unsafe function or block + //[thir]~^^ call to unsafe function `foo` is unsafe and requires unsafe function or block + foo(); + //[mir]~^ ERROR call to unsafe function is unsafe and requires unsafe function or block +} diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr new file mode 100644 index 000000000..b313f0653 --- /dev/null +++ b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: call to unsafe function `foo` is unsafe and requires unsafe function or block + --> $DIR/const-extern-fn-requires-unsafe.rs:9:17 + | +LL | let a: [u8; foo()]; + | ^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn.rs b/tests/ui/consts/const-extern-fn/const-extern-fn.rs new file mode 100644 index 000000000..2ce2eafd5 --- /dev/null +++ b/tests/ui/consts/const-extern-fn/const-extern-fn.rs @@ -0,0 +1,35 @@ +// run-pass +#![feature(const_extern_fn)] + +const extern "C" fn foo1(val: u8) -> u8 { + val + 1 +} + +const extern "C" fn foo2(val: u8) -> u8 { + val + 1 +} + +const unsafe extern "C" fn bar1(val: bool) -> bool { + !val +} + +const unsafe extern "C" fn bar2(val: bool) -> bool { + !val +} + + +fn main() { + let a: [u8; foo1(25) as usize] = [0; 26]; + let b: [u8; foo2(25) as usize] = [0; 26]; + assert_eq!(a, b); + + let bar1_res = unsafe { bar1(false) }; + let bar2_res = unsafe { bar2(false) }; + assert!(bar1_res); + assert_eq!(bar1_res, bar2_res); + + let _foo1_cast: extern "C" fn(u8) -> u8 = foo1; + let _foo2_cast: extern "C" fn(u8) -> u8 = foo2; + let _bar1_cast: unsafe extern "C" fn(bool) -> bool = bar1; + let _bar2_cast: unsafe extern "C" fn(bool) -> bool = bar2; +} diff --git a/tests/ui/consts/const-extern-fn/feature-gate-const_extern_fn.rs b/tests/ui/consts/const-extern-fn/feature-gate-const_extern_fn.rs new file mode 100644 index 000000000..f7bed91b0 --- /dev/null +++ b/tests/ui/consts/const-extern-fn/feature-gate-const_extern_fn.rs @@ -0,0 +1,13 @@ +// Check that `const extern fn` and `const unsafe extern fn` are feature-gated +// for certain ABIs. + +const extern fn foo1() {} +const extern "C" fn foo2() {} +const extern "Rust" fn foo3() {} +const extern "cdecl" fn foo4() {} //~ ERROR `cdecl` as a `const fn` ABI is unstable +const unsafe extern fn bar1() {} +const unsafe extern "C" fn bar2() {} +const unsafe extern "Rust" fn bar3() {} +const unsafe extern "cdecl" fn bar4() {} //~ ERROR `cdecl` as a `const fn` ABI is unstable + +fn main() {} diff --git a/tests/ui/consts/const-extern-fn/feature-gate-const_extern_fn.stderr b/tests/ui/consts/const-extern-fn/feature-gate-const_extern_fn.stderr new file mode 100644 index 000000000..f8c3107bd --- /dev/null +++ b/tests/ui/consts/const-extern-fn/feature-gate-const_extern_fn.stderr @@ -0,0 +1,21 @@ +error[E0658]: `cdecl` as a `const fn` ABI is unstable + --> $DIR/feature-gate-const_extern_fn.rs:7:14 + | +LL | const extern "cdecl" fn foo4() {} + | ^^^^^^^ + | + = note: see issue #64926 <https://github.com/rust-lang/rust/issues/64926> for more information + = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable + +error[E0658]: `cdecl` as a `const fn` ABI is unstable + --> $DIR/feature-gate-const_extern_fn.rs:11:21 + | +LL | const unsafe extern "cdecl" fn bar4() {} + | ^^^^^^^ + | + = note: see issue #64926 <https://github.com/rust-lang/rust/issues/64926> for more information + = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs b/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs new file mode 100644 index 000000000..7ced24808 --- /dev/null +++ b/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs @@ -0,0 +1,7 @@ +fn main() {} + +#[cfg(FALSE)] +fn container() { + const unsafe WhereIsFerris Now() {} + //~^ ERROR expected one of `extern` or `fn` +} diff --git a/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.stderr b/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.stderr new file mode 100644 index 000000000..5ec9e2a91 --- /dev/null +++ b/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.stderr @@ -0,0 +1,8 @@ +error: expected one of `extern` or `fn`, found `WhereIsFerris` + --> $DIR/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs:5:18 + | +LL | const unsafe WhereIsFerris Now() {} + | ^^^^^^^^^^^^^ expected one of `extern` or `fn` + +error: aborting due to previous error + diff --git a/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs b/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs new file mode 100644 index 000000000..6f575d055 --- /dev/null +++ b/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs @@ -0,0 +1,7 @@ +fn main() {} + +#[cfg(FALSE)] +fn container() { + const extern "Rust" PUT_ANYTHING_YOU_WANT_HERE bug() -> usize { 1 } + //~^ ERROR expected `fn` +} diff --git a/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.stderr b/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.stderr new file mode 100644 index 000000000..ec415ec9d --- /dev/null +++ b/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.stderr @@ -0,0 +1,8 @@ +error: expected `fn`, found `PUT_ANYTHING_YOU_WANT_HERE` + --> $DIR/issue-68062-const-extern-fns-dont-need-fn-specifier.rs:5:25 + | +LL | const extern "Rust" PUT_ANYTHING_YOU_WANT_HERE bug() -> usize { 1 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `fn` + +error: aborting due to previous error + diff --git a/tests/ui/consts/const-extern-function.rs b/tests/ui/consts/const-extern-function.rs new file mode 100644 index 000000000..01f487a7d --- /dev/null +++ b/tests/ui/consts/const-extern-function.rs @@ -0,0 +1,16 @@ +// run-pass +#![allow(non_upper_case_globals)] + +extern "C" fn foopy() {} + +static f: extern "C" fn() = foopy; +static s: S = S { f: foopy }; + +struct S { + f: extern "C" fn() +} + +pub fn main() { + assert!(foopy as extern "C" fn() == f); + assert!(f == s.f); +} diff --git a/tests/ui/consts/const-external-macro-const-err.rs b/tests/ui/consts/const-external-macro-const-err.rs new file mode 100644 index 000000000..5bd84330b --- /dev/null +++ b/tests/ui/consts/const-external-macro-const-err.rs @@ -0,0 +1,13 @@ +// edition:2018 +// aux-build:external_macro.rs + +// Ensure that CONST_ERR lint errors +// are not silenced in external macros. +// https://github.com/rust-lang/rust/issues/65300 + +extern crate external_macro; +use external_macro::static_assert; + +fn main() { + static_assert!(2 + 2 == 5); //~ ERROR constant +} diff --git a/tests/ui/consts/const-external-macro-const-err.stderr b/tests/ui/consts/const-external-macro-const-err.stderr new file mode 100644 index 000000000..81f6c09ff --- /dev/null +++ b/tests/ui/consts/const-external-macro-const-err.stderr @@ -0,0 +1,11 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-external-macro-const-err.rs:12:5 + | +LL | static_assert!(2 + 2 == 5); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1 + | + = note: this error originates in the macro `static_assert` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-fields-and-indexing.rs b/tests/ui/consts/const-fields-and-indexing.rs new file mode 100644 index 000000000..bb13bebf4 --- /dev/null +++ b/tests/ui/consts/const-fields-and-indexing.rs @@ -0,0 +1,28 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_upper_case_globals)] + +const x : [isize; 4] = [1,2,3,4]; +static p : isize = x[2]; +const y : &'static [isize] = &[1,2,3,4]; +static q : isize = y[2]; + +struct S {a: isize, b: isize} + +const s : S = S {a: 10, b: 20}; +static t : isize = s.b; + +struct K {a: isize, b: isize, c: D} +struct D { d: isize, e: isize } + +const k : K = K {a: 10, b: 20, c: D {d: 30, e: 40}}; +static m : isize = k.c.e; + +pub fn main() { + println!("{}", p); + println!("{}", q); + println!("{}", t); + assert_eq!(p, 3); + assert_eq!(q, 3); + assert_eq!(t, 20); +} diff --git a/tests/ui/consts/const-float-bits-conv.rs b/tests/ui/consts/const-float-bits-conv.rs new file mode 100644 index 000000000..fd5e42ef1 --- /dev/null +++ b/tests/ui/consts/const-float-bits-conv.rs @@ -0,0 +1,63 @@ +// compile-flags: -Zmir-opt-level=0 +// run-pass + +#![feature(const_float_bits_conv)] +#![feature(const_float_classify)] +#![allow(unused_macro_rules)] + +// Don't promote +const fn nop<T>(x: T) -> T { x } + +macro_rules! const_assert { + ($a:expr) => { + { + const _: () = assert!($a); + assert!(nop($a)); + } + }; + ($a:expr, $b:expr) => { + { + const _: () = assert!($a == $b); + assert_eq!(nop($a), nop($b)); + } + }; +} + +fn f32() { + const_assert!((1f32).to_bits(), 0x3f800000); + const_assert!(u32::from_be_bytes(1f32.to_be_bytes()), 0x3f800000); + const_assert!((12.5f32).to_bits(), 0x41480000); + const_assert!(u32::from_le_bytes(12.5f32.to_le_bytes()), 0x41480000); + const_assert!((1337f32).to_bits(), 0x44a72000); + const_assert!(u32::from_ne_bytes(1337f32.to_ne_bytes()), 0x44a72000); + const_assert!((-14.25f32).to_bits(), 0xc1640000); + const_assert!(f32::from_bits(0x3f800000), 1.0); + const_assert!(f32::from_be_bytes(0x3f800000u32.to_be_bytes()), 1.0); + const_assert!(f32::from_bits(0x41480000), 12.5); + const_assert!(f32::from_le_bytes(0x41480000u32.to_le_bytes()), 12.5); + const_assert!(f32::from_bits(0x44a72000), 1337.0); + const_assert!(f32::from_ne_bytes(0x44a72000u32.to_ne_bytes()), 1337.0); + const_assert!(f32::from_bits(0xc1640000), -14.25); +} + +fn f64() { + const_assert!((1f64).to_bits(), 0x3ff0000000000000); + const_assert!(u64::from_be_bytes(1f64.to_be_bytes()), 0x3ff0000000000000); + const_assert!((12.5f64).to_bits(), 0x4029000000000000); + const_assert!(u64::from_le_bytes(12.5f64.to_le_bytes()), 0x4029000000000000); + const_assert!((1337f64).to_bits(), 0x4094e40000000000); + const_assert!(u64::from_ne_bytes(1337f64.to_ne_bytes()), 0x4094e40000000000); + const_assert!((-14.25f64).to_bits(), 0xc02c800000000000); + const_assert!(f64::from_bits(0x3ff0000000000000), 1.0); + const_assert!(f64::from_be_bytes(0x3ff0000000000000u64.to_be_bytes()), 1.0); + const_assert!(f64::from_bits(0x4029000000000000), 12.5); + const_assert!(f64::from_le_bytes(0x4029000000000000u64.to_le_bytes()), 12.5); + const_assert!(f64::from_bits(0x4094e40000000000), 1337.0); + const_assert!(f64::from_ne_bytes(0x4094e40000000000u64.to_ne_bytes()), 1337.0); + const_assert!(f64::from_bits(0xc02c800000000000), -14.25); +} + +fn main() { + f32(); + f64(); +} diff --git a/tests/ui/consts/const-float-bits-reject-conv.rs b/tests/ui/consts/const-float-bits-reject-conv.rs new file mode 100644 index 000000000..c77e99abb --- /dev/null +++ b/tests/ui/consts/const-float-bits-reject-conv.rs @@ -0,0 +1,68 @@ +// compile-flags: -Zmir-opt-level=0 +// error-pattern: cannot use f32::to_bits on a NaN +#![feature(const_float_bits_conv)] +#![feature(const_float_classify)] + +// Don't promote +const fn nop<T>(x: T) -> T { x } + +macro_rules! const_assert { + ($a:expr) => { + { + const _: () = assert!($a); + assert!(nop($a)); + } + }; + ($a:expr, $b:expr) => { + { + const _: () = assert!($a == $b); + assert_eq!(nop($a), nop($b)); + } + }; +} + +fn f32() { + // Check that NaNs roundtrip their bits regardless of signalingness + // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits + // ...actually, let's just check that these break. :D + const MASKED_NAN1: u32 = f32::NAN.to_bits() ^ 0x002A_AAAA; + //~^ inside + const MASKED_NAN2: u32 = f32::NAN.to_bits() ^ 0x0055_5555; + //~^ inside + + // The rest of the code is dead because the constants already fail to evaluate. + + const_assert!(f32::from_bits(MASKED_NAN1).is_nan()); + const_assert!(f32::from_bits(MASKED_NAN1).is_nan()); + + // LLVM does not guarantee that loads and stores of NaNs preserve their exact bit pattern. + // In practice, this seems to only cause a problem on x86, since the most widely used calling + // convention mandates that floating point values are returned on the x87 FPU stack. See #73328. + // However, during CTFE we still preserve bit patterns (though that is not a guarantee). + const_assert!(f32::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1); + const_assert!(f32::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2); +} + +fn f64() { + // Check that NaNs roundtrip their bits regardless of signalingness + // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits + // ...actually, let's just check that these break. :D + const MASKED_NAN1: u64 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA; + //~^ inside + const MASKED_NAN2: u64 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555; + //~^ inside + + // The rest of the code is dead because the constants already fail to evaluate. + + const_assert!(f64::from_bits(MASKED_NAN1).is_nan()); + const_assert!(f64::from_bits(MASKED_NAN1).is_nan()); + + // See comment above. + const_assert!(f64::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1); + const_assert!(f64::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2); +} + +fn main() { + f32(); + f64(); +} diff --git a/tests/ui/consts/const-float-bits-reject-conv.stderr b/tests/ui/consts/const-float-bits-reject-conv.stderr new file mode 100644 index 000000000..7ad022520 --- /dev/null +++ b/tests/ui/consts/const-float-bits-reject-conv.stderr @@ -0,0 +1,115 @@ +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/num/f32.rs:LL:COL + | + = note: the evaluated program panicked at 'const-eval error: cannot use f32::to_bits on a NaN', $SRC_DIR/core/src/num/f32.rs:LL:COL + | +note: inside `core::f32::<impl f32>::to_bits::ct_f32_to_u32` + --> $SRC_DIR/core/src/num/f32.rs:LL:COL +note: inside `core::f32::<impl f32>::to_bits` + --> $SRC_DIR/core/src/num/f32.rs:LL:COL +note: inside `f32::MASKED_NAN1` + --> $DIR/const-float-bits-reject-conv.rs:28:30 + | +LL | const MASKED_NAN1: u32 = f32::NAN.to_bits() ^ 0x002A_AAAA; + | ^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/num/f32.rs:LL:COL + | + = note: the evaluated program panicked at 'const-eval error: cannot use f32::to_bits on a NaN', $SRC_DIR/core/src/num/f32.rs:LL:COL + | +note: inside `core::f32::<impl f32>::to_bits::ct_f32_to_u32` + --> $SRC_DIR/core/src/num/f32.rs:LL:COL +note: inside `core::f32::<impl f32>::to_bits` + --> $SRC_DIR/core/src/num/f32.rs:LL:COL +note: inside `f32::MASKED_NAN2` + --> $DIR/const-float-bits-reject-conv.rs:30:30 + | +LL | const MASKED_NAN2: u32 = f32::NAN.to_bits() ^ 0x0055_5555; + | ^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: erroneous constant used + --> $DIR/const-float-bits-reject-conv.rs:35:34 + | +LL | const_assert!(f32::from_bits(MASKED_NAN1).is_nan()); + | ^^^^^^^^^^^ + +note: erroneous constant used + --> $DIR/const-float-bits-reject-conv.rs:36:34 + | +LL | const_assert!(f32::from_bits(MASKED_NAN1).is_nan()); + | ^^^^^^^^^^^ + +note: erroneous constant used + --> $DIR/const-float-bits-reject-conv.rs:42:34 + | +LL | const_assert!(f32::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1); + | ^^^^^^^^^^^ + +note: erroneous constant used + --> $DIR/const-float-bits-reject-conv.rs:43:34 + | +LL | const_assert!(f32::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2); + | ^^^^^^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/num/f64.rs:LL:COL + | + = note: the evaluated program panicked at 'const-eval error: cannot use f64::to_bits on a NaN', $SRC_DIR/core/src/num/f64.rs:LL:COL + | +note: inside `core::f64::<impl f64>::to_bits::ct_f64_to_u64` + --> $SRC_DIR/core/src/num/f64.rs:LL:COL +note: inside `core::f64::<impl f64>::to_bits` + --> $SRC_DIR/core/src/num/f64.rs:LL:COL +note: inside `f64::MASKED_NAN1` + --> $DIR/const-float-bits-reject-conv.rs:50:30 + | +LL | const MASKED_NAN1: u64 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA; + | ^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/num/f64.rs:LL:COL + | + = note: the evaluated program panicked at 'const-eval error: cannot use f64::to_bits on a NaN', $SRC_DIR/core/src/num/f64.rs:LL:COL + | +note: inside `core::f64::<impl f64>::to_bits::ct_f64_to_u64` + --> $SRC_DIR/core/src/num/f64.rs:LL:COL +note: inside `core::f64::<impl f64>::to_bits` + --> $SRC_DIR/core/src/num/f64.rs:LL:COL +note: inside `f64::MASKED_NAN2` + --> $DIR/const-float-bits-reject-conv.rs:52:30 + | +LL | const MASKED_NAN2: u64 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555; + | ^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: erroneous constant used + --> $DIR/const-float-bits-reject-conv.rs:57:34 + | +LL | const_assert!(f64::from_bits(MASKED_NAN1).is_nan()); + | ^^^^^^^^^^^ + +note: erroneous constant used + --> $DIR/const-float-bits-reject-conv.rs:58:34 + | +LL | const_assert!(f64::from_bits(MASKED_NAN1).is_nan()); + | ^^^^^^^^^^^ + +note: erroneous constant used + --> $DIR/const-float-bits-reject-conv.rs:61:34 + | +LL | const_assert!(f64::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1); + | ^^^^^^^^^^^ + +note: erroneous constant used + --> $DIR/const-float-bits-reject-conv.rs:62:34 + | +LL | const_assert!(f64::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2); + | ^^^^^^^^^^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-float-classify.rs b/tests/ui/consts/const-float-classify.rs new file mode 100644 index 000000000..74238d0dd --- /dev/null +++ b/tests/ui/consts/const-float-classify.rs @@ -0,0 +1,78 @@ +// compile-flags: -Zmir-opt-level=0 +// run-pass + +#![feature(const_float_bits_conv)] +#![feature(const_float_classify)] +#![feature(const_trait_impl)] + +// Don't promote +const fn nop<T>(x: T) -> T { x } + +macro_rules! const_assert { + ($a:expr, $b:expr) => { + { + const _: () = assert!($a == $b); + assert_eq!(nop($a), nop($b)); + } + }; +} + +macro_rules! suite { + ( $( $tt:tt )* ) => { + fn f32() { + suite_inner!(f32 $($tt)*); + } + + fn f64() { + suite_inner!(f64 $($tt)*); + } + } + +} + +macro_rules! suite_inner { + ( + $ty:ident [$( $fn:ident ),*] + $val:expr => [$($out:ident),*] + + $( $tail:tt )* + ) => { + $( const_assert!($ty::$fn($val), $out); )* + suite_inner!($ty [$($fn),*] $($tail)*) + }; + + ( $ty:ident [$( $fn:ident ),*]) => {}; +} + +#[derive(Debug)] +struct NonDet; + +impl const PartialEq<NonDet> for bool { + fn eq(&self, _: &NonDet) -> bool { + true + } + fn ne(&self, _: &NonDet) -> bool { + false + } +} + +// The result of the `is_sign` methods are not checked for correctness, since LLVM does not +// guarantee anything about the signedness of NaNs. See +// https://github.com/rust-lang/rust/issues/55131. + +suite! { + [is_nan, is_infinite, is_finite, is_normal, is_sign_positive, is_sign_negative] + -0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] + 0.0 / 0.0 => [ true, false, false, false, NonDet, NonDet] + 1.0 => [ false, false, true, true, true, false] + -1.0 => [ false, false, true, true, false, true] + 0.0 => [ false, false, true, false, true, false] + -0.0 => [ false, false, true, false, false, true] + 1.0 / 0.0 => [ false, true, false, false, true, false] + -1.0 / 0.0 => [ false, true, false, false, false, true] +} + +fn main() { + f32(); + f64(); +} diff --git a/tests/ui/consts/const-fn-const-eval.rs b/tests/ui/consts/const-fn-const-eval.rs new file mode 100644 index 000000000..d4da99081 --- /dev/null +++ b/tests/ui/consts/const-fn-const-eval.rs @@ -0,0 +1,10 @@ +// run-pass +#![allow(dead_code)] + +const fn add(x: usize, y: usize) -> usize { + x + y +} + +const ARR: [i32; add(1, 2)] = [5, 6, 7]; + +pub fn main() {} diff --git a/tests/ui/consts/const-fn-destructuring-arg.rs b/tests/ui/consts/const-fn-destructuring-arg.rs new file mode 100644 index 000000000..ea5c9ddc7 --- /dev/null +++ b/tests/ui/consts/const-fn-destructuring-arg.rs @@ -0,0 +1,7 @@ +// check-pass + +const fn i((a, b): (u32, u32)) -> u32 { + a + b +} + +fn main() {} diff --git a/tests/ui/consts/const-fn-error.rs b/tests/ui/consts/const-fn-error.rs new file mode 100644 index 000000000..50b7ce1f8 --- /dev/null +++ b/tests/ui/consts/const-fn-error.rs @@ -0,0 +1,18 @@ +const X : usize = 2; + +const fn f(x: usize) -> usize { + let mut sum = 0; + for i in 0..x { + //~^ ERROR cannot convert + //~| ERROR `for` is not allowed in a `const fn` + //~| ERROR mutable references are not allowed in constant functions + //~| ERROR cannot call non-const fn + sum += i; + } + sum +} + +#[allow(unused_variables)] +fn main() { + let a : [i32; f(X)]; +} diff --git a/tests/ui/consts/const-fn-error.stderr b/tests/ui/consts/const-fn-error.stderr new file mode 100644 index 000000000..f735b3d53 --- /dev/null +++ b/tests/ui/consts/const-fn-error.stderr @@ -0,0 +1,48 @@ +error[E0658]: `for` is not allowed in a `const fn` + --> $DIR/const-fn-error.rs:5:5 + | +LL | / for i in 0..x { +LL | | +LL | | +LL | | +LL | | +LL | | sum += i; +LL | | } + | |_____^ + | + = note: see issue #87575 <https://github.com/rust-lang/rust/issues/87575> for more information + = help: add `#![feature(const_for)]` to the crate attributes to enable + +error[E0015]: cannot convert `std::ops::Range<usize>` into an iterator in constant functions + --> $DIR/const-fn-error.rs:5:14 + | +LL | for i in 0..x { + | ^^^^ + | +note: impl defined here, but it is not `const` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/const-fn-error.rs:5:14 + | +LL | for i in 0..x { + | ^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0015]: cannot call non-const fn `<std::ops::Range<usize> as Iterator>::next` in constant functions + --> $DIR/const-fn-error.rs:5:14 + | +LL | for i in 0..x { + | ^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0015, E0658. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/const-fn-in-vec.rs b/tests/ui/consts/const-fn-in-vec.rs new file mode 100644 index 000000000..a40290eca --- /dev/null +++ b/tests/ui/consts/const-fn-in-vec.rs @@ -0,0 +1,7 @@ +fn main() { + // should hint to create an inline `const` block + // or to create a new `const` item + let strings: [String; 5] = [String::new(); 5]; + //~^ ERROR the trait bound `String: Copy` is not satisfied + println!("{:?}", strings); +} diff --git a/tests/ui/consts/const-fn-in-vec.stderr b/tests/ui/consts/const-fn-in-vec.stderr new file mode 100644 index 000000000..9eb7524b5 --- /dev/null +++ b/tests/ui/consts/const-fn-in-vec.stderr @@ -0,0 +1,13 @@ +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/const-fn-in-vec.rs:4:33 + | +LL | let strings: [String; 5] = [String::new(); 5]; + | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` + | + = note: the `Copy` trait is required because this value will be copied for each element of the array + = help: consider creating a new `const` item and initializing it with the result of the function call to be used in the repeat position, like `const VAL: Type = const_fn();` and `let x = [VAL; 42];` + = help: create an inline `const` block, see RFC #2920 <https://github.com/rust-lang/rfcs/pull/2920> for more information + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/const-fn-method.rs b/tests/ui/consts/const-fn-method.rs new file mode 100644 index 000000000..002646db9 --- /dev/null +++ b/tests/ui/consts/const-fn-method.rs @@ -0,0 +1,16 @@ +// run-pass + +struct Foo { value: u32 } + +impl Foo { + const fn new() -> Foo { + Foo { value: 22 } + } +} + +const FOO: Foo = Foo::new(); + +pub fn main() { + assert_eq!(FOO.value, 22); + let _: [&'static str; Foo::new().value as usize] = ["hey"; 22]; +} diff --git a/tests/ui/consts/const-fn-mismatch.rs b/tests/ui/consts/const-fn-mismatch.rs new file mode 100644 index 000000000..3107b8128 --- /dev/null +++ b/tests/ui/consts/const-fn-mismatch.rs @@ -0,0 +1,17 @@ +// Test that we can't declare a const fn in an impl -- right now it's +// just not allowed at all, though eventually it'd make sense to allow +// it if the trait fn is const (but right now no trait fns can be +// const). + +trait Foo { + fn f() -> u32; +} + +impl Foo for u32 { + const fn f() -> u32 { + //~^ ERROR functions in traits cannot be declared const + 22 + } +} + +fn main() {} diff --git a/tests/ui/consts/const-fn-mismatch.stderr b/tests/ui/consts/const-fn-mismatch.stderr new file mode 100644 index 000000000..a86a06b3e --- /dev/null +++ b/tests/ui/consts/const-fn-mismatch.stderr @@ -0,0 +1,9 @@ +error[E0379]: functions in traits cannot be declared const + --> $DIR/const-fn-mismatch.rs:11:5 + | +LL | const fn f() -> u32 { + | ^^^^^ functions in traits cannot be const + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0379`. diff --git a/tests/ui/consts/const-fn-nested.rs b/tests/ui/consts/const-fn-nested.rs new file mode 100644 index 000000000..ef5598bf9 --- /dev/null +++ b/tests/ui/consts/const-fn-nested.rs @@ -0,0 +1,12 @@ +// run-pass +// Test a call whose argument is the result of another call. + +const fn sub(x: u32, y: u32) -> u32 { + x - y +} + +const X: u32 = sub(sub(88, 44), 22); + +fn main() { + assert_eq!(X, 22); +} diff --git a/tests/ui/consts/const-fn-not-in-trait.rs b/tests/ui/consts/const-fn-not-in-trait.rs new file mode 100644 index 000000000..00bae3f3b --- /dev/null +++ b/tests/ui/consts/const-fn-not-in-trait.rs @@ -0,0 +1,13 @@ +// Test that const fn is illegal in a trait declaration, whether or +// not a default is provided, and even with the feature gate. + +trait Foo { + const fn f() -> u32; + //~^ ERROR functions in traits cannot be declared const + const fn g() -> u32 { + //~^ ERROR functions in traits cannot be declared const + 0 + } +} + +fn main() {} diff --git a/tests/ui/consts/const-fn-not-in-trait.stderr b/tests/ui/consts/const-fn-not-in-trait.stderr new file mode 100644 index 000000000..5d364eb88 --- /dev/null +++ b/tests/ui/consts/const-fn-not-in-trait.stderr @@ -0,0 +1,15 @@ +error[E0379]: functions in traits cannot be declared const + --> $DIR/const-fn-not-in-trait.rs:5:5 + | +LL | const fn f() -> u32; + | ^^^^^ functions in traits cannot be const + +error[E0379]: functions in traits cannot be declared const + --> $DIR/const-fn-not-in-trait.rs:7:5 + | +LL | const fn g() -> u32 { + | ^^^^^ functions in traits cannot be const + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0379`. diff --git a/tests/ui/consts/const-fn-not-safe-for-const.rs b/tests/ui/consts/const-fn-not-safe-for-const.rs new file mode 100644 index 000000000..b2fe73ae9 --- /dev/null +++ b/tests/ui/consts/const-fn-not-safe-for-const.rs @@ -0,0 +1,35 @@ +// Test that we can't call random fns in a const fn or do other bad things. + +use std::mem::transmute; + +fn random() -> u32 { + 0 +} + +const fn sub(x: &u32) -> usize { + unsafe { transmute(x) } +} + +const fn sub1() -> u32 { + random() //~ ERROR E0015 +} + +static Y: u32 = 0; + +const fn get_Y() -> u32 { + Y + //~^ ERROR E0013 +} + +const fn get_Y_addr() -> &'static u32 { + &Y + //~^ ERROR E0013 +} + +const fn get() -> u32 { + let x = 22; + let y = 44; + x + y +} + +fn main() {} diff --git a/tests/ui/consts/const-fn-not-safe-for-const.stderr b/tests/ui/consts/const-fn-not-safe-for-const.stderr new file mode 100644 index 000000000..4c7effc0d --- /dev/null +++ b/tests/ui/consts/const-fn-not-safe-for-const.stderr @@ -0,0 +1,28 @@ +error[E0015]: cannot call non-const fn `random` in constant functions + --> $DIR/const-fn-not-safe-for-const.rs:14:5 + | +LL | random() + | ^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error[E0013]: constant functions cannot refer to statics + --> $DIR/const-fn-not-safe-for-const.rs:20:5 + | +LL | Y + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error[E0013]: constant functions cannot refer to statics + --> $DIR/const-fn-not-safe-for-const.rs:25:6 + | +LL | &Y + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0013, E0015. +For more information about an error, try `rustc --explain E0013`. diff --git a/tests/ui/consts/const-fn-ptr.rs b/tests/ui/consts/const-fn-ptr.rs new file mode 100644 index 000000000..b1befdf06 --- /dev/null +++ b/tests/ui/consts/const-fn-ptr.rs @@ -0,0 +1,16 @@ +const fn make_fn_ptr() -> fn() { + || {} +} + +static STAT: () = make_fn_ptr()(); +//~^ ERROR function pointer + +const CONST: () = make_fn_ptr()(); +//~^ ERROR function pointer + +const fn call_ptr() { + make_fn_ptr()(); + //~^ ERROR function pointer +} + +fn main() {} diff --git a/tests/ui/consts/const-fn-ptr.stderr b/tests/ui/consts/const-fn-ptr.stderr new file mode 100644 index 000000000..84b02a25e --- /dev/null +++ b/tests/ui/consts/const-fn-ptr.stderr @@ -0,0 +1,20 @@ +error: function pointer calls are not allowed in statics + --> $DIR/const-fn-ptr.rs:5:19 + | +LL | static STAT: () = make_fn_ptr()(); + | ^^^^^^^^^^^^^^^ + +error: function pointer calls are not allowed in constants + --> $DIR/const-fn-ptr.rs:8:19 + | +LL | const CONST: () = make_fn_ptr()(); + | ^^^^^^^^^^^^^^^ + +error: function pointer calls are not allowed in constant functions + --> $DIR/const-fn-ptr.rs:12:5 + | +LL | make_fn_ptr()(); + | ^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/consts/const-fn-stability-calls-3.rs b/tests/ui/consts/const-fn-stability-calls-3.rs new file mode 100644 index 000000000..b831dee58 --- /dev/null +++ b/tests/ui/consts/const-fn-stability-calls-3.rs @@ -0,0 +1,12 @@ +// Test use of const fn from another crate without a feature gate. + +// check-pass +// aux-build:const_fn_lib.rs + +extern crate const_fn_lib; + +use const_fn_lib::foo; + +fn main() { + let x = foo(); // use outside a constant is ok +} diff --git a/tests/ui/consts/const-fn-stability-calls.rs b/tests/ui/consts/const-fn-stability-calls.rs new file mode 100644 index 000000000..138679048 --- /dev/null +++ b/tests/ui/consts/const-fn-stability-calls.rs @@ -0,0 +1,27 @@ +// run-pass +#![allow(dead_code)] +#![allow(unused_variables)] +// Test use of const fn from another crate without a feature gate. + +// aux-build:const_fn_lib.rs + +extern crate const_fn_lib; + +use const_fn_lib::foo; + +static FOO: usize = foo(); +const BAR: usize = foo(); + +macro_rules! constant { + ($n:ident: $t:ty = $v:expr) => { + const $n: $t = $v; + } +} + +constant! { + BAZ: usize = foo() +} + +fn main() { + let x: [usize; foo()] = [42; foo()]; +} diff --git a/tests/ui/consts/const-fn-type-name-any.rs b/tests/ui/consts/const-fn-type-name-any.rs new file mode 100644 index 000000000..448c4fc04 --- /dev/null +++ b/tests/ui/consts/const-fn-type-name-any.rs @@ -0,0 +1,28 @@ +// run-pass + +#![feature(const_type_name)] +#![allow(dead_code)] + +const fn type_name_wrapper<T>(_: &T) -> &'static str { + std::any::type_name::<T>() +} + +struct Struct<TA, TB, TC> { + a: TA, + b: TB, + c: TC, +} + +type StructInstantiation = Struct<i8, f64, bool>; + +const CONST_STRUCT: StructInstantiation = StructInstantiation { a: 12, b: 13.7, c: false }; + +const CONST_STRUCT_NAME: &'static str = type_name_wrapper(&CONST_STRUCT); + +fn main() { + let non_const_struct = StructInstantiation { a: 87, b: 65.99, c: true }; + + let non_const_struct_name = type_name_wrapper(&non_const_struct); + + assert_eq!(CONST_STRUCT_NAME, non_const_struct_name); +} diff --git a/tests/ui/consts/const-fn-type-name.rs b/tests/ui/consts/const-fn-type-name.rs new file mode 100644 index 000000000..fd4f60cb8 --- /dev/null +++ b/tests/ui/consts/const-fn-type-name.rs @@ -0,0 +1,37 @@ +// run-pass + +#![feature(core_intrinsics)] +#![feature(const_type_name)] +#![allow(dead_code)] + +const fn type_name_wrapper<T>(_: &T) -> &'static str { + core::intrinsics::type_name::<T>() +} + +struct Struct<TA, TB, TC> { + a: TA, + b: TB, + c: TC, +} + +type StructInstantiation = Struct<i8, f64, bool>; + +const CONST_STRUCT: StructInstantiation = StructInstantiation { + a: 12, + b: 13.7, + c: false, +}; + +const CONST_STRUCT_NAME: &'static str = type_name_wrapper(&CONST_STRUCT); + +fn main() { + let non_const_struct = StructInstantiation { + a: 87, + b: 65.99, + c: true, + }; + + let non_const_struct_name = type_name_wrapper(&non_const_struct); + + assert_eq!(CONST_STRUCT_NAME, non_const_struct_name); +} diff --git a/tests/ui/consts/const-fn-val.rs b/tests/ui/consts/const-fn-val.rs new file mode 100644 index 000000000..e5bf4757e --- /dev/null +++ b/tests/ui/consts/const-fn-val.rs @@ -0,0 +1,15 @@ +// run-pass +#![allow(non_upper_case_globals)] +#![allow(overflowing_literals)] + +fn foo() -> isize { + return 0xca7f000d; +} + +struct Bar<F> where F: FnMut() -> isize { f: F } + +static mut b : Bar<fn() -> isize> = Bar { f: foo as fn() -> isize}; + +pub fn main() { + unsafe { assert_eq!((b.f)(), 0xca7f000d); } +} diff --git a/tests/ui/consts/const-fn-zst-args.rs b/tests/ui/consts/const-fn-zst-args.rs new file mode 100644 index 000000000..82c27b375 --- /dev/null +++ b/tests/ui/consts/const-fn-zst-args.rs @@ -0,0 +1,14 @@ +// build-pass + +// Check that the evaluation of const-functions with +// zero-sized types as arguments compiles successfully + +struct Zst {} + +const fn foo(val: Zst) -> Zst { val } + +const FOO: Zst = foo(Zst {}); + +fn main() { + const _: Zst = FOO; +} diff --git a/tests/ui/consts/const-fn.rs b/tests/ui/consts/const-fn.rs new file mode 100644 index 000000000..59680e6e4 --- /dev/null +++ b/tests/ui/consts/const-fn.rs @@ -0,0 +1,42 @@ +// run-pass +#![allow(stable_features)] + +// A very basic test of const fn functionality. + +#![feature(const_indexing)] + +const fn add(x: u32, y: u32) -> u32 { + x + y +} + +const fn sub(x: u32, y: u32) -> u32 { + x - y +} + +const unsafe fn div(x: u32, y: u32) -> u32 { + x / y +} + +const fn generic<T>(t: T) -> T { + t +} + +const fn generic_arr<T: Copy>(t: [T; 1]) -> T { + t[0] +} + +const SUM: u32 = add(44, 22); +const DIFF: u32 = sub(44, 22); +const DIV: u32 = unsafe{div(44, 22)}; + +fn main() { + assert_eq!(SUM, 66); + assert!(SUM != 88); + + assert_eq!(DIFF, 22); + assert_eq!(DIV, 2); + + let _: [&'static str; sub(100, 99) as usize] = ["hi"]; + let _: [&'static str; generic(1)] = ["hi"]; + let _: [&'static str; generic_arr([1])] = ["hi"]; +} diff --git a/tests/ui/consts/const-for-feature-gate.rs b/tests/ui/consts/const-for-feature-gate.rs new file mode 100644 index 000000000..bec7b8089 --- /dev/null +++ b/tests/ui/consts/const-for-feature-gate.rs @@ -0,0 +1,8 @@ +// gate-test-const_for + +const _: () = { + for _ in 0..5 {} + //~^ error: `for` is not allowed in a `const` +}; + +fn main() {} diff --git a/tests/ui/consts/const-for-feature-gate.stderr b/tests/ui/consts/const-for-feature-gate.stderr new file mode 100644 index 000000000..2ea377e09 --- /dev/null +++ b/tests/ui/consts/const-for-feature-gate.stderr @@ -0,0 +1,12 @@ +error[E0658]: `for` is not allowed in a `const` + --> $DIR/const-for-feature-gate.rs:4:5 + | +LL | for _ in 0..5 {} + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #87575 <https://github.com/rust-lang/rust/issues/87575> for more information + = help: add `#![feature(const_for)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/const-for.rs b/tests/ui/consts/const-for.rs new file mode 100644 index 000000000..8db248535 --- /dev/null +++ b/tests/ui/consts/const-for.rs @@ -0,0 +1,10 @@ +#![feature(const_for)] +#![feature(const_mut_refs)] + +const _: () = { + for _ in 0..5 {} + //~^ error: cannot call + //~| error: cannot convert +}; + +fn main() {} diff --git a/tests/ui/consts/const-for.stderr b/tests/ui/consts/const-for.stderr new file mode 100644 index 000000000..3fb9787c0 --- /dev/null +++ b/tests/ui/consts/const-for.stderr @@ -0,0 +1,23 @@ +error[E0015]: cannot convert `std::ops::Range<i32>` into an iterator in constants + --> $DIR/const-for.rs:5:14 + | +LL | for _ in 0..5 {} + | ^^^^ + | +note: impl defined here, but it is not `const` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + +error[E0015]: cannot call non-const fn `<std::ops::Range<i32> as Iterator>::next` in constants + --> $DIR/const-for.rs:5:14 + | +LL | for _ in 0..5 {} + | ^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/const-index-feature-gate.rs b/tests/ui/consts/const-index-feature-gate.rs new file mode 100644 index 000000000..3537a1790 --- /dev/null +++ b/tests/ui/consts/const-index-feature-gate.rs @@ -0,0 +1,7 @@ +// run-pass +#![allow(dead_code)] +const ARR: [usize; 1] = [2]; +const ARR2: [i32; ARR[0]] = [5, 6]; + +fn main() { +} diff --git a/tests/ui/consts/const-int-arithmetic-overflow.rs b/tests/ui/consts/const-int-arithmetic-overflow.rs new file mode 100644 index 000000000..6446e9451 --- /dev/null +++ b/tests/ui/consts/const-int-arithmetic-overflow.rs @@ -0,0 +1,25 @@ +// run-pass +// compile-flags: -O + +// Make sure arithmetic unary/binary ops actually return the right result, even when overflowing. +// We have to put them in `const fn` and turn on optimizations to avoid overflow checks. + +const fn add(x: i8, y: i8) -> i8 { x+y } +const fn sub(x: i8, y: i8) -> i8 { x-y } +const fn mul(x: i8, y: i8) -> i8 { x*y } +// div and rem are always checked, so we cannot test their result in case of overflow. +const fn neg(x: i8) -> i8 { -x } + +fn main() { + const ADD_OFLOW: i8 = add(100, 100); + assert_eq!(ADD_OFLOW, -56); + + const SUB_OFLOW: i8 = sub(100, -100); + assert_eq!(SUB_OFLOW, -56); + + const MUL_OFLOW: i8 = mul(-100, -2); + assert_eq!(MUL_OFLOW, -56); + + const NEG_OFLOW: i8 = neg(-128); + assert_eq!(NEG_OFLOW, -128); +} diff --git a/tests/ui/consts/const-int-arithmetic.rs b/tests/ui/consts/const-int-arithmetic.rs new file mode 100644 index 000000000..b9096648f --- /dev/null +++ b/tests/ui/consts/const-int-arithmetic.rs @@ -0,0 +1,138 @@ +// run-pass + +macro_rules! suite { + ($( + $fn:ident -> $ty:ty { $( $label:ident : $expr:expr, $result:expr; )* } + )*) => { $( + fn $fn() { + $( + const $label: $ty = $expr; + assert_eq!($label, $result); + )* + } + )* } +} + +suite!( + checked -> Option<i8> { + // `const_checked_int_methods` + C1: 5i8.checked_add(2), Some(7); + C2: 127i8.checked_add(2), None; + + C3: 5i8.checked_sub(2), Some(3); + C4: (-127i8).checked_sub(2), None; + + C5: 1i8.checked_mul(3), Some(3); + C6: 5i8.checked_mul(122), None; + C7: (-127i8).checked_mul(-99), None; + + C8: (i8::MIN + 1).checked_div(-1), Some(127); + C9: i8::MIN.checked_div(-1), None; + C10: 1i8.checked_div(0), None; + + C11: 5i8.checked_rem(2), Some(1); + C12: 5i8.checked_rem(0), None; + C13: i8::MIN.checked_rem(-1), None; + + C14: 5i8.checked_neg(), Some(-5); + C15: i8::MIN.checked_neg(), None; + + C16: 0x1i8.checked_shl(4), Some(0x10); + C17: 0x1i8.checked_shl(129), None; + + C18: 0x10i8.checked_shr(4), Some(0x1); + C19: 0x10i8.checked_shr(128), None; + + + C20: (-5i8).checked_abs(), Some(5); + C21: i8::MIN.checked_abs(), None; + + // `const_euclidean_int_methods` + C22: (i8::MIN + 1).checked_div_euclid(-1), Some(127); + C23: i8::MIN.checked_div_euclid(-1), None; + C24: (1i8).checked_div_euclid(0), None; + + C25: 5i8.checked_rem_euclid(2), Some(1); + C26: 5i8.checked_rem_euclid(0), None; + C27: i8::MIN.checked_rem_euclid(-1), None; + } + checked_i128 -> Option<i128> { + CHK_ADD_I128: i128::MAX.checked_add(1), None; + CHK_MUL_I128: i128::MIN.checked_mul(-1), None; + } + + saturating_and_wrapping -> i8 { + // `const_saturating_int_methods` + C28: 100i8.saturating_add(1), 101; + C29: i8::MAX.saturating_add(100), i8::MAX; + C30: i8::MIN.saturating_add(-1), i8::MIN; + + C31: 100i8.saturating_sub(127), -27; + C32: i8::MIN.saturating_sub(100), i8::MIN; + C33: i8::MAX.saturating_sub(-1), i8::MAX; + + C34: 10i8.saturating_mul(12), 120; + C35: i8::MAX.saturating_mul(10), i8::MAX; + C36: i8::MIN.saturating_mul(10), i8::MIN; + + C37: 100i8.saturating_neg(), -100; + C38: (-100i8).saturating_neg(), 100; + C39: i8::MIN.saturating_neg(), i8::MAX; + C40: i8::MAX.saturating_neg(), i8::MIN + 1; + + C57: 100i8.saturating_abs(), 100; + C58: (-100i8).saturating_abs(), 100; + C59: i8::MIN.saturating_abs(), i8::MAX; + C60: (i8::MIN + 1).saturating_abs(), i8::MAX; + + // `const_wrapping_int_methods` + C41: 100i8.wrapping_div(10), 10; + C42: (-128i8).wrapping_div(-1), -128; + + C43: 100i8.wrapping_rem(10), 0; + C44: (-128i8).wrapping_rem(-1), 0; + + // `const_euclidean_int_methods` + C45: 100i8.wrapping_div_euclid(10), 10; + C46: (-128i8).wrapping_div_euclid(-1), -128; + + C47: 100i8.wrapping_rem_euclid(10), 0; + C48: (-128i8).wrapping_rem_euclid(-1), 0; + } + saturating_and_wrapping_i128 -> i128 { + SAT_ADD_I128: i128::MAX.saturating_add(1), i128::MAX; + SAT_MUL_I128: i128::MAX.saturating_mul(2), i128::MAX; + + WRP_ADD_I128: i128::MAX.wrapping_add(1), i128::MIN; + WRP_MUL_I128: i128::MAX.wrapping_mul(3), i128::MAX-2; + } + + overflowing -> (i8, bool) { + // `const_overflowing_int_methods` + C49: 5i8.overflowing_div(2), (2, false); + C50: i8::MIN.overflowing_div(-1), (i8::MIN, true); + + C51: 5i8.overflowing_rem(2), (1, false); + C52: i8::MIN.overflowing_rem(-1), (0, true); + + // `const_euclidean_int_methods` + C53: 5i8.overflowing_div_euclid(2), (2, false); + C54: i8::MIN.overflowing_div_euclid(-1), (i8::MIN, true); + + C55: 5i8.overflowing_rem_euclid(2), (1, false); + C56: i8::MIN.overflowing_rem_euclid(-1), (0, true); + } + overflowing_i128 -> (i128, bool) { + OFL_ADD_I128: i128::MAX.overflowing_add(1), (i128::MIN, true); + OFL_MUL_I128: i128::MAX.overflowing_mul(3), (i128::MAX-2, true); + } +); + +fn main() { + checked(); + checked_i128(); + saturating_and_wrapping(); + saturating_and_wrapping_i128(); + overflowing(); + overflowing_i128(); +} diff --git a/tests/ui/consts/const-int-conversion-rpass.rs b/tests/ui/consts/const-int-conversion-rpass.rs new file mode 100644 index 000000000..4aaeeaa38 --- /dev/null +++ b/tests/ui/consts/const-int-conversion-rpass.rs @@ -0,0 +1,19 @@ +// run-pass + +const REVERSE: u32 = 0x12345678_u32.reverse_bits(); +const FROM_BE_BYTES: i32 = i32::from_be_bytes([0x12, 0x34, 0x56, 0x78]); +const FROM_LE_BYTES: i32 = i32::from_le_bytes([0x12, 0x34, 0x56, 0x78]); +const FROM_NE_BYTES: i32 = i32::from_be(i32::from_ne_bytes([0x80, 0, 0, 0])); +const TO_BE_BYTES: [u8; 4] = 0x12_34_56_78_i32.to_be_bytes(); +const TO_LE_BYTES: [u8; 4] = 0x12_34_56_78_i32.to_le_bytes(); +const TO_NE_BYTES: [u8; 4] = i32::MIN.to_be().to_ne_bytes(); + +fn main() { + assert_eq!(REVERSE, 0x1e6a2c48); + assert_eq!(FROM_BE_BYTES, 0x12_34_56_78); + assert_eq!(FROM_LE_BYTES, 0x78_56_34_12); + assert_eq!(FROM_NE_BYTES, i32::MIN); + assert_eq!(TO_BE_BYTES, [0x12, 0x34, 0x56, 0x78]); + assert_eq!(TO_LE_BYTES, [0x78, 0x56, 0x34, 0x12]); + assert_eq!(TO_NE_BYTES, [0x80, 0, 0, 0]); +} diff --git a/tests/ui/consts/const-int-conversion.rs b/tests/ui/consts/const-int-conversion.rs new file mode 100644 index 000000000..5a05a2b35 --- /dev/null +++ b/tests/ui/consts/const-int-conversion.rs @@ -0,0 +1,16 @@ +fn main() { + let x: &'static i32 = &(5_i32.reverse_bits()); + //~^ ERROR temporary value dropped while borrowed + let y: &'static i32 = &(i32::from_be_bytes([0x12, 0x34, 0x56, 0x78])); + //~^ ERROR temporary value dropped while borrowed + let z: &'static i32 = &(i32::from_le_bytes([0x12, 0x34, 0x56, 0x78])); + //~^ ERROR temporary value dropped while borrowed + let a: &'static i32 = &(i32::from_be(i32::from_ne_bytes([0x80, 0, 0, 0]))); + //~^ ERROR temporary value dropped while borrowed + let b: &'static [u8] = &(0x12_34_56_78_i32.to_be_bytes()); + //~^ ERROR temporary value dropped while borrowed + let c: &'static [u8] = &(0x12_34_56_78_i32.to_le_bytes()); + //~^ ERROR temporary value dropped while borrowed + let d: &'static [u8] = &(i32::MIN.to_be().to_ne_bytes()); + //~^ ERROR temporary value dropped while borrowed +} diff --git a/tests/ui/consts/const-int-conversion.stderr b/tests/ui/consts/const-int-conversion.stderr new file mode 100644 index 000000000..5dd757e3f --- /dev/null +++ b/tests/ui/consts/const-int-conversion.stderr @@ -0,0 +1,80 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:2:28 + | +LL | let x: &'static i32 = &(5_i32.reverse_bits()); + | ------------ ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:4:28 + | +LL | let y: &'static i32 = &(i32::from_be_bytes([0x12, 0x34, 0x56, 0x78])); + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:6:28 + | +LL | let z: &'static i32 = &(i32::from_le_bytes([0x12, 0x34, 0x56, 0x78])); + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:8:28 + | +LL | let a: &'static i32 = &(i32::from_be(i32::from_ne_bytes([0x80, 0, 0, 0]))); + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:10:29 + | +LL | let b: &'static [u8] = &(0x12_34_56_78_i32.to_be_bytes()); + | ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:12:29 + | +LL | let c: &'static [u8] = &(0x12_34_56_78_i32.to_le_bytes()); + | ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:14:29 + | +LL | let d: &'static [u8] = &(i32::MIN.to_be().to_ne_bytes()); + | ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/const-int-overflowing-rpass.rs b/tests/ui/consts/const-int-overflowing-rpass.rs new file mode 100644 index 000000000..75e77fdf1 --- /dev/null +++ b/tests/ui/consts/const-int-overflowing-rpass.rs @@ -0,0 +1,47 @@ +// run-pass + +const ADD_A: (u32, bool) = 5u32.overflowing_add(2); +const ADD_B: (u32, bool) = u32::MAX.overflowing_add(1); + +const SUB_A: (u32, bool) = 5u32.overflowing_sub(2); +const SUB_B: (u32, bool) = 0u32.overflowing_sub(1); + +const MUL_A: (u32, bool) = 5u32.overflowing_mul(2); +const MUL_B: (u32, bool) = 1_000_000_000u32.overflowing_mul(10); + +const SHL_A: (u32, bool) = 0x1u32.overflowing_shl(4); +const SHL_B: (u32, bool) = 0x1u32.overflowing_shl(132); + +const SHR_A: (u32, bool) = 0x10u32.overflowing_shr(4); +const SHR_B: (u32, bool) = 0x10u32.overflowing_shr(132); + +const NEG_A: (u32, bool) = 0u32.overflowing_neg(); +const NEG_B: (u32, bool) = u32::MAX.overflowing_neg(); + +const ABS_POS: (i32, bool) = 10i32.overflowing_abs(); +const ABS_NEG: (i32, bool) = (-10i32).overflowing_abs(); +const ABS_MIN: (i32, bool) = i32::MIN.overflowing_abs(); + +fn main() { + assert_eq!(ADD_A, (7, false)); + assert_eq!(ADD_B, (0, true)); + + assert_eq!(SUB_A, (3, false)); + assert_eq!(SUB_B, (u32::MAX, true)); + + assert_eq!(MUL_A, (10, false)); + assert_eq!(MUL_B, (1410065408, true)); + + assert_eq!(SHL_A, (0x10, false)); + assert_eq!(SHL_B, (0x10, true)); + + assert_eq!(SHR_A, (0x1, false)); + assert_eq!(SHR_B, (0x1, true)); + + assert_eq!(NEG_A, (0, false)); + assert_eq!(NEG_B, (1, true)); + + assert_eq!(ABS_POS, (10, false)); + assert_eq!(ABS_NEG, (10, false)); + assert_eq!(ABS_MIN, (i32::MIN, true)); +} diff --git a/tests/ui/consts/const-int-overflowing.rs b/tests/ui/consts/const-int-overflowing.rs new file mode 100644 index 000000000..cd74c9990 --- /dev/null +++ b/tests/ui/consts/const-int-overflowing.rs @@ -0,0 +1,8 @@ +fn main() { + let x: &'static (i32, bool) = &(5_i32.overflowing_add(3)); + //~^ ERROR temporary value dropped while borrowed + let y: &'static (i32, bool) = &(5_i32.overflowing_sub(3)); + //~^ ERROR temporary value dropped while borrowed + let z: &'static (i32, bool) = &(5_i32.overflowing_mul(3)); + //~^ ERROR temporary value dropped while borrowed +} diff --git a/tests/ui/consts/const-int-overflowing.stderr b/tests/ui/consts/const-int-overflowing.stderr new file mode 100644 index 000000000..7d3689e6e --- /dev/null +++ b/tests/ui/consts/const-int-overflowing.stderr @@ -0,0 +1,36 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-overflowing.rs:2:36 + | +LL | let x: &'static (i32, bool) = &(5_i32.overflowing_add(3)); + | -------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-overflowing.rs:4:36 + | +LL | let y: &'static (i32, bool) = &(5_i32.overflowing_sub(3)); + | -------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-overflowing.rs:6:36 + | +LL | let z: &'static (i32, bool) = &(5_i32.overflowing_mul(3)); + | -------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/const-int-pow-rpass.rs b/tests/ui/consts/const-int-pow-rpass.rs new file mode 100644 index 000000000..30bcb78bc --- /dev/null +++ b/tests/ui/consts/const-int-pow-rpass.rs @@ -0,0 +1,47 @@ +// run-pass + +#![feature(wrapping_next_power_of_two)] + +const IS_POWER_OF_TWO_A: bool = 0u32.is_power_of_two(); +const IS_POWER_OF_TWO_B: bool = 32u32.is_power_of_two(); +const IS_POWER_OF_TWO_C: bool = 33u32.is_power_of_two(); + +const POW: u8 = 3u8.pow(5); + +const CHECKED_POW_OK: Option<u8> = 3u8.checked_pow(5); +const CHECKED_POW_OVERFLOW: Option<u8> = 3u8.checked_pow(6); + +const WRAPPING_POW: u8 = 3u8.wrapping_pow(6); +const OVERFLOWING_POW: (u8, bool) = 3u8.overflowing_pow(6); +const SATURATING_POW: u8 = 3u8.saturating_pow(6); + +const NEXT_POWER_OF_TWO: u32 = 3u32.next_power_of_two(); + +const CHECKED_NEXT_POWER_OF_TWO_OK: Option<u32> = 3u32.checked_next_power_of_two(); +const CHECKED_NEXT_POWER_OF_TWO_OVERFLOW: Option<u32> = + u32::MAX.checked_next_power_of_two(); + +const WRAPPING_NEXT_POWER_OF_TWO: u32 = + u32::MAX.wrapping_next_power_of_two(); + +fn main() { + assert!(!IS_POWER_OF_TWO_A); + assert!(IS_POWER_OF_TWO_B); + assert!(!IS_POWER_OF_TWO_C); + + assert_eq!(POW, 243); + + assert_eq!(CHECKED_POW_OK, Some(243)); + assert_eq!(CHECKED_POW_OVERFLOW, None); + + assert_eq!(WRAPPING_POW, 217); + assert_eq!(OVERFLOWING_POW, (217, true)); + assert_eq!(SATURATING_POW, u8::MAX); + + assert_eq!(NEXT_POWER_OF_TWO, 4); + + assert_eq!(CHECKED_NEXT_POWER_OF_TWO_OK, Some(4)); + assert_eq!(CHECKED_NEXT_POWER_OF_TWO_OVERFLOW, None); + + assert_eq!(WRAPPING_NEXT_POWER_OF_TWO, 0); +} diff --git a/tests/ui/consts/const-int-rotate-rpass.rs b/tests/ui/consts/const-int-rotate-rpass.rs new file mode 100644 index 000000000..14f34f76c --- /dev/null +++ b/tests/ui/consts/const-int-rotate-rpass.rs @@ -0,0 +1,43 @@ +// run-pass + +const LEFT: u32 = 0x10000b3u32.rotate_left(8); +const RIGHT: u32 = 0xb301u32.rotate_right(8); + +// Rotating these should make no difference +// +// We test using 124 bits because to ensure that overlong bit shifts do +// not cause undefined behaviour. See #10183. +const LEFT_OVERFLOW: i16 = 0i16.rotate_left(124); +const RIGHT_OVERFLOW: i16 = 0i16.rotate_right(124); +const ONE_LEFT_OVERFLOW: u16 = 1u16.rotate_left(124); +const ONE_RIGHT_OVERFLOW: u16 = 1u16.rotate_right(124); + +const NON_ZERO_LEFT_OVERFLOW: u16 = 0b10u16.rotate_left(124); +const NON_ZERO_RIGHT_OVERFLOW: u16 = 0b10u16.rotate_right(124); + +// Rotating by 0 should have no effect +const ZERO_ROTATE_LEFT: i8 = 0b0010_0001i8.rotate_left(0); +const ZERO_ROTATE_RIGHT: i8 = 0b0111_1001i8.rotate_right(0); + +// Rotating by a multiple of word size should also have no effect +const MULTIPLE_ROTATE_LEFT: i32 = 0b0010_0001i32.rotate_left(128); +const MULTIPLE_ROTATE_RIGHT: i32 = 0b0010_0001i32.rotate_right(128); + +fn main() { + assert_eq!(LEFT, 0xb301); + assert_eq!(RIGHT, 0x0100_00b3); + + assert_eq!(LEFT_OVERFLOW, 0); + assert_eq!(RIGHT_OVERFLOW, 0); + assert_eq!(ONE_LEFT_OVERFLOW, 0b0001_0000_0000_0000); + assert_eq!(ONE_RIGHT_OVERFLOW, 0b0001_0000); + + assert_eq!(NON_ZERO_LEFT_OVERFLOW, 0b0010_0000_0000_0000); + assert_eq!(NON_ZERO_RIGHT_OVERFLOW, 0b0000_0000_0010_0000); + + assert_eq!(ZERO_ROTATE_LEFT, 0b0010_0001); + assert_eq!(ZERO_ROTATE_RIGHT, 0b0111_1001); + + assert_eq!(MULTIPLE_ROTATE_LEFT, 0b0010_0001); + assert_eq!(MULTIPLE_ROTATE_RIGHT, 0b0010_0001); +} diff --git a/tests/ui/consts/const-int-rotate.rs b/tests/ui/consts/const-int-rotate.rs new file mode 100644 index 000000000..3aacf854d --- /dev/null +++ b/tests/ui/consts/const-int-rotate.rs @@ -0,0 +1,6 @@ +fn main() { + let x: &'static i32 = &(5_i32.rotate_left(3)); + //~^ ERROR temporary value dropped while borrowed + let y: &'static i32 = &(5_i32.rotate_right(3)); + //~^ ERROR temporary value dropped while borrowed +} diff --git a/tests/ui/consts/const-int-rotate.stderr b/tests/ui/consts/const-int-rotate.stderr new file mode 100644 index 000000000..039da1c31 --- /dev/null +++ b/tests/ui/consts/const-int-rotate.stderr @@ -0,0 +1,25 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-rotate.rs:2:28 + | +LL | let x: &'static i32 = &(5_i32.rotate_left(3)); + | ------------ ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-rotate.rs:4:28 + | +LL | let y: &'static i32 = &(5_i32.rotate_right(3)); + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/const-int-saturating-arith.rs b/tests/ui/consts/const-int-saturating-arith.rs new file mode 100644 index 000000000..7edbdd4ce --- /dev/null +++ b/tests/ui/consts/const-int-saturating-arith.rs @@ -0,0 +1,33 @@ +// run-pass + +const INT_U32_NO: u32 = (42 as u32).saturating_add(2); +const INT_U32: u32 = u32::MAX.saturating_add(1); +const INT_U128: u128 = u128::MAX.saturating_add(1); +const INT_I128: i128 = i128::MAX.saturating_add(1); +const INT_I128_NEG: i128 = i128::MIN.saturating_add(-1); + +const INT_U32_NO_SUB: u32 = (42 as u32).saturating_sub(2); +const INT_U32_SUB: u32 = (1 as u32).saturating_sub(2); +const INT_I32_NO_SUB: i32 = (-42 as i32).saturating_sub(2); +const INT_I32_NEG_SUB: i32 = i32::MIN.saturating_sub(1); +const INT_I32_POS_SUB: i32 = i32::MAX.saturating_sub(-1); +const INT_U128_SUB: u128 = (0 as u128).saturating_sub(1); +const INT_I128_NEG_SUB: i128 = i128::MIN.saturating_sub(1); +const INT_I128_POS_SUB: i128 = i128::MAX.saturating_sub(-1); + +fn main() { + assert_eq!(INT_U32_NO, 44); + assert_eq!(INT_U32, u32::MAX); + assert_eq!(INT_U128, u128::MAX); + assert_eq!(INT_I128, i128::MAX); + assert_eq!(INT_I128_NEG, i128::MIN); + + assert_eq!(INT_U32_NO_SUB, 40); + assert_eq!(INT_U32_SUB, 0); + assert_eq!(INT_I32_NO_SUB, -44); + assert_eq!(INT_I32_NEG_SUB, i32::MIN); + assert_eq!(INT_I32_POS_SUB, i32::MAX); + assert_eq!(INT_U128_SUB, 0); + assert_eq!(INT_I128_NEG_SUB, i128::MIN); + assert_eq!(INT_I128_POS_SUB, i128::MAX); +} diff --git a/tests/ui/consts/const-int-sign-rpass.rs b/tests/ui/consts/const-int-sign-rpass.rs new file mode 100644 index 000000000..63c191d42 --- /dev/null +++ b/tests/ui/consts/const-int-sign-rpass.rs @@ -0,0 +1,27 @@ +// run-pass + +const NEGATIVE_A: bool = (-10i32).is_negative(); +const NEGATIVE_B: bool = 10i32.is_negative(); +const POSITIVE_A: bool = (-10i32).is_positive(); +const POSITIVE_B: bool = 10i32.is_positive(); + +const SIGNUM_POS: i32 = 10i32.signum(); +const SIGNUM_NIL: i32 = 0i32.signum(); +const SIGNUM_NEG: i32 = (-42i32).signum(); + +const ABS_A: i32 = 10i32.abs(); +const ABS_B: i32 = (-10i32).abs(); + +fn main() { + assert!(NEGATIVE_A); + assert!(!NEGATIVE_B); + assert!(!POSITIVE_A); + assert!(POSITIVE_B); + + assert_eq!(SIGNUM_POS, 1); + assert_eq!(SIGNUM_NIL, 0); + assert_eq!(SIGNUM_NEG, -1); + + assert_eq!(ABS_A, 10); + assert_eq!(ABS_B, 10); +} diff --git a/tests/ui/consts/const-int-sign.rs b/tests/ui/consts/const-int-sign.rs new file mode 100644 index 000000000..c3111ddf5 --- /dev/null +++ b/tests/ui/consts/const-int-sign.rs @@ -0,0 +1,6 @@ +fn main() { + let x: &'static bool = &(5_i32.is_negative()); + //~^ ERROR temporary value dropped while borrowed + let y: &'static bool = &(5_i32.is_positive()); + //~^ ERROR temporary value dropped while borrowed +} diff --git a/tests/ui/consts/const-int-sign.stderr b/tests/ui/consts/const-int-sign.stderr new file mode 100644 index 000000000..fc23d9d2b --- /dev/null +++ b/tests/ui/consts/const-int-sign.stderr @@ -0,0 +1,25 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-sign.rs:2:29 + | +LL | let x: &'static bool = &(5_i32.is_negative()); + | ------------- ^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-sign.rs:4:29 + | +LL | let y: &'static bool = &(5_i32.is_positive()); + | ------------- ^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/const-int-unchecked.rs b/tests/ui/consts/const-int-unchecked.rs new file mode 100644 index 000000000..902a66848 --- /dev/null +++ b/tests/ui/consts/const-int-unchecked.rs @@ -0,0 +1,149 @@ +#![feature(core_intrinsics)] +#![feature(const_int_unchecked_arith)] + +use std::intrinsics; + +// The documentation of `unchecked_shl` states that it: +// +// Performs an unchecked left shift, resulting in undefined behavior when +// y < 0 or y >= N, where N is the width of T in bits. +// +// So we check this for a few `y`. + +// unsigned types: + +const SHL_U8: u8 = unsafe { intrinsics::unchecked_shl(5_u8, 8) }; +//~^ ERROR evaluation of constant value failed +const SHL_U16: u16 = unsafe { intrinsics::unchecked_shl(5_u16, 16) }; +//~^ ERROR evaluation of constant value failed +const SHL_U32: u32 = unsafe { intrinsics::unchecked_shl(5_u32, 32) }; +//~^ ERROR evaluation of constant value failed +const SHL_U64: u64 = unsafe { intrinsics::unchecked_shl(5_u64, 64) }; +//~^ ERROR evaluation of constant value failed +const SHL_U128: u128 = unsafe { intrinsics::unchecked_shl(5_u128, 128) }; +//~^ ERROR evaluation of constant value failed + +// signed types: + +const SHL_I8: i8 = unsafe { intrinsics::unchecked_shl(5_i8, 8) }; +//~^ ERROR evaluation of constant value failed +const SHL_I16: i16 = unsafe { intrinsics::unchecked_shl(5_16, 16) }; +//~^ ERROR evaluation of constant value failed +const SHL_I32: i32 = unsafe { intrinsics::unchecked_shl(5_i32, 32) }; +//~^ ERROR evaluation of constant value failed +const SHL_I64: i64 = unsafe { intrinsics::unchecked_shl(5_i64, 64) }; +//~^ ERROR evaluation of constant value failed +const SHL_I128: i128 = unsafe { intrinsics::unchecked_shl(5_i128, 128) }; +//~^ ERROR evaluation of constant value failed + +// and make sure we capture y < 0: + +const SHL_I8_NEG: i8 = unsafe { intrinsics::unchecked_shl(5_i8, -1) }; +//~^ ERROR evaluation of constant value failed +const SHL_I16_NEG: i16 = unsafe { intrinsics::unchecked_shl(5_16, -1) }; +//~^ ERROR evaluation of constant value failed +const SHL_I32_NEG: i32 = unsafe { intrinsics::unchecked_shl(5_i32, -1) }; +//~^ ERROR evaluation of constant value failed +const SHL_I64_NEG: i64 = unsafe { intrinsics::unchecked_shl(5_i64, -1) }; +//~^ ERROR evaluation of constant value failed +const SHL_I128_NEG: i128 = unsafe { intrinsics::unchecked_shl(5_i128, -1) }; +//~^ ERROR evaluation of constant value failed + +// and that there's no special relation to the value -1 by picking some +// negative values at random: + +const SHL_I8_NEG_RANDOM: i8 = unsafe { intrinsics::unchecked_shl(5_i8, -6) }; +//~^ ERROR evaluation of constant value failed +const SHL_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shl(5_16, -13) }; +//~^ ERROR evaluation of constant value failed +const SHL_I32_NEG_RANDOM: i32 = unsafe { intrinsics::unchecked_shl(5_i32, -25) }; +//~^ ERROR evaluation of constant value failed +const SHL_I64_NEG_RANDOM: i64 = unsafe { intrinsics::unchecked_shl(5_i64, -30) }; +//~^ ERROR evaluation of constant value failed +const SHL_I128_NEG_RANDOM: i128 = unsafe { intrinsics::unchecked_shl(5_i128, -93) }; +//~^ ERROR evaluation of constant value failed + +// Repeat it all over for `unchecked_shr` + +// unsigned types: + +const SHR_U8: u8 = unsafe { intrinsics::unchecked_shr(5_u8, 8) }; +//~^ ERROR evaluation of constant value failed +const SHR_U16: u16 = unsafe { intrinsics::unchecked_shr(5_u16, 16) }; +//~^ ERROR evaluation of constant value failed +const SHR_U32: u32 = unsafe { intrinsics::unchecked_shr(5_u32, 32) }; +//~^ ERROR evaluation of constant value failed +const SHR_U64: u64 = unsafe { intrinsics::unchecked_shr(5_u64, 64) }; +//~^ ERROR evaluation of constant value failed +const SHR_U128: u128 = unsafe { intrinsics::unchecked_shr(5_u128, 128) }; +//~^ ERROR evaluation of constant value failed + +// signed types: + +const SHR_I8: i8 = unsafe { intrinsics::unchecked_shr(5_i8, 8) }; +//~^ ERROR evaluation of constant value failed +const SHR_I16: i16 = unsafe { intrinsics::unchecked_shr(5_16, 16) }; +//~^ ERROR evaluation of constant value failed +const SHR_I32: i32 = unsafe { intrinsics::unchecked_shr(5_i32, 32) }; +//~^ ERROR evaluation of constant value failed +const SHR_I64: i64 = unsafe { intrinsics::unchecked_shr(5_i64, 64) }; +//~^ ERROR evaluation of constant value failed +const SHR_I128: i128 = unsafe { intrinsics::unchecked_shr(5_i128, 128) }; +//~^ ERROR evaluation of constant value failed + +// and make sure we capture y < 0: + +const SHR_I8_NEG: i8 = unsafe { intrinsics::unchecked_shr(5_i8, -1) }; +//~^ ERROR evaluation of constant value failed +const SHR_I16_NEG: i16 = unsafe { intrinsics::unchecked_shr(5_16, -1) }; +//~^ ERROR evaluation of constant value failed +const SHR_I32_NEG: i32 = unsafe { intrinsics::unchecked_shr(5_i32, -1) }; +//~^ ERROR evaluation of constant value failed +const SHR_I64_NEG: i64 = unsafe { intrinsics::unchecked_shr(5_i64, -1) }; +//~^ ERROR evaluation of constant value failed +const SHR_I128_NEG: i128 = unsafe { intrinsics::unchecked_shr(5_i128, -1) }; +//~^ ERROR evaluation of constant value failed + +// and that there's no special relation to the value -1 by picking some +// negative values at random: + +const SHR_I8_NEG_RANDOM: i8 = unsafe { intrinsics::unchecked_shr(5_i8, -6) }; +//~^ ERROR evaluation of constant value failed +const SHR_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shr(5_16, -13) }; +//~^ ERROR evaluation of constant value failed +const SHR_I32_NEG_RANDOM: i32 = unsafe { intrinsics::unchecked_shr(5_i32, -25) }; +//~^ ERROR evaluation of constant value failed +const SHR_I64_NEG_RANDOM: i64 = unsafe { intrinsics::unchecked_shr(5_i64, -30) }; +//~^ ERROR evaluation of constant value failed +const SHR_I128_NEG_RANDOM: i128 = unsafe { intrinsics::unchecked_shr(5_i128, -93) }; +//~^ ERROR evaluation of constant value failed + +// Other arithmetic functions: + +const _: u16 = unsafe { std::intrinsics::unchecked_add(40000u16, 30000) }; +//~^ ERROR evaluation of constant value failed + +const _: u32 = unsafe { std::intrinsics::unchecked_sub(14u32, 22) }; +//~^ ERROR evaluation of constant value failed + +const _: u16 = unsafe { std::intrinsics::unchecked_mul(300u16, 250u16) }; +//~^ ERROR evaluation of constant value failed + +const _: i32 = unsafe { std::intrinsics::unchecked_div(1, 0) }; +//~^ ERROR evaluation of constant value failed +const _: i32 = unsafe { std::intrinsics::unchecked_div(i32::MIN, -1) }; +//~^ ERROR evaluation of constant value failed + +const _: i32 = unsafe { std::intrinsics::unchecked_rem(1, 0) }; +//~^ ERROR evaluation of constant value failed +const _: i32 = unsafe { std::intrinsics::unchecked_rem(i32::MIN, -1) }; +//~^ ERROR evaluation of constant value failed + +// capture fault with zero value + +const _: u32 = unsafe { std::intrinsics::ctlz_nonzero(0) }; +//~^ ERROR evaluation of constant value failed +const _: u32 = unsafe { std::intrinsics::cttz_nonzero(0) }; +//~^ ERROR evaluation of constant value failed + +fn main() {} diff --git a/tests/ui/consts/const-int-unchecked.stderr b/tests/ui/consts/const-int-unchecked.stderr new file mode 100644 index 000000000..ad880d56d --- /dev/null +++ b/tests/ui/consts/const-int-unchecked.stderr @@ -0,0 +1,297 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:15:29 + | +LL | const SHL_U8: u8 = unsafe { intrinsics::unchecked_shl(5_u8, 8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 8 in `unchecked_shl` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:17:31 + | +LL | const SHL_U16: u16 = unsafe { intrinsics::unchecked_shl(5_u16, 16) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 16 in `unchecked_shl` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:19:31 + | +LL | const SHL_U32: u32 = unsafe { intrinsics::unchecked_shl(5_u32, 32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 32 in `unchecked_shl` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:21:31 + | +LL | const SHL_U64: u64 = unsafe { intrinsics::unchecked_shl(5_u64, 64) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 64 in `unchecked_shl` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:23:33 + | +LL | const SHL_U128: u128 = unsafe { intrinsics::unchecked_shl(5_u128, 128) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 128 in `unchecked_shl` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:28:29 + | +LL | const SHL_I8: i8 = unsafe { intrinsics::unchecked_shl(5_i8, 8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 8 in `unchecked_shl` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:30:31 + | +LL | const SHL_I16: i16 = unsafe { intrinsics::unchecked_shl(5_16, 16) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 16 in `unchecked_shl` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:32:31 + | +LL | const SHL_I32: i32 = unsafe { intrinsics::unchecked_shl(5_i32, 32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 32 in `unchecked_shl` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:34:31 + | +LL | const SHL_I64: i64 = unsafe { intrinsics::unchecked_shl(5_i64, 64) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 64 in `unchecked_shl` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:36:33 + | +LL | const SHL_I128: i128 = unsafe { intrinsics::unchecked_shl(5_i128, 128) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 128 in `unchecked_shl` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:41:33 + | +LL | const SHL_I8_NEG: i8 = unsafe { intrinsics::unchecked_shl(5_i8, -1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 255 in `unchecked_shl` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:43:35 + | +LL | const SHL_I16_NEG: i16 = unsafe { intrinsics::unchecked_shl(5_16, -1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 65535 in `unchecked_shl` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:45:35 + | +LL | const SHL_I32_NEG: i32 = unsafe { intrinsics::unchecked_shl(5_i32, -1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 4294967295 in `unchecked_shl` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:47:35 + | +LL | const SHL_I64_NEG: i64 = unsafe { intrinsics::unchecked_shl(5_i64, -1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 18446744073709551615 in `unchecked_shl` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:49:37 + | +LL | const SHL_I128_NEG: i128 = unsafe { intrinsics::unchecked_shl(5_i128, -1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 340282366920938463463374607431768211455 in `unchecked_shl` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:55:40 + | +LL | const SHL_I8_NEG_RANDOM: i8 = unsafe { intrinsics::unchecked_shl(5_i8, -6) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 250 in `unchecked_shl` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:57:42 + | +LL | const SHL_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shl(5_16, -13) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 65523 in `unchecked_shl` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:59:42 + | +LL | const SHL_I32_NEG_RANDOM: i32 = unsafe { intrinsics::unchecked_shl(5_i32, -25) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 4294967271 in `unchecked_shl` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:61:42 + | +LL | const SHL_I64_NEG_RANDOM: i64 = unsafe { intrinsics::unchecked_shl(5_i64, -30) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 18446744073709551586 in `unchecked_shl` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:63:44 + | +LL | const SHL_I128_NEG_RANDOM: i128 = unsafe { intrinsics::unchecked_shl(5_i128, -93) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 340282366920938463463374607431768211363 in `unchecked_shl` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:70:29 + | +LL | const SHR_U8: u8 = unsafe { intrinsics::unchecked_shr(5_u8, 8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 8 in `unchecked_shr` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:72:31 + | +LL | const SHR_U16: u16 = unsafe { intrinsics::unchecked_shr(5_u16, 16) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 16 in `unchecked_shr` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:74:31 + | +LL | const SHR_U32: u32 = unsafe { intrinsics::unchecked_shr(5_u32, 32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 32 in `unchecked_shr` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:76:31 + | +LL | const SHR_U64: u64 = unsafe { intrinsics::unchecked_shr(5_u64, 64) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 64 in `unchecked_shr` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:78:33 + | +LL | const SHR_U128: u128 = unsafe { intrinsics::unchecked_shr(5_u128, 128) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 128 in `unchecked_shr` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:83:29 + | +LL | const SHR_I8: i8 = unsafe { intrinsics::unchecked_shr(5_i8, 8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 8 in `unchecked_shr` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:85:31 + | +LL | const SHR_I16: i16 = unsafe { intrinsics::unchecked_shr(5_16, 16) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 16 in `unchecked_shr` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:87:31 + | +LL | const SHR_I32: i32 = unsafe { intrinsics::unchecked_shr(5_i32, 32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 32 in `unchecked_shr` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:89:31 + | +LL | const SHR_I64: i64 = unsafe { intrinsics::unchecked_shr(5_i64, 64) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 64 in `unchecked_shr` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:91:33 + | +LL | const SHR_I128: i128 = unsafe { intrinsics::unchecked_shr(5_i128, 128) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 128 in `unchecked_shr` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:96:33 + | +LL | const SHR_I8_NEG: i8 = unsafe { intrinsics::unchecked_shr(5_i8, -1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 255 in `unchecked_shr` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:98:35 + | +LL | const SHR_I16_NEG: i16 = unsafe { intrinsics::unchecked_shr(5_16, -1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 65535 in `unchecked_shr` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:100:35 + | +LL | const SHR_I32_NEG: i32 = unsafe { intrinsics::unchecked_shr(5_i32, -1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 4294967295 in `unchecked_shr` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:102:35 + | +LL | const SHR_I64_NEG: i64 = unsafe { intrinsics::unchecked_shr(5_i64, -1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 18446744073709551615 in `unchecked_shr` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:104:37 + | +LL | const SHR_I128_NEG: i128 = unsafe { intrinsics::unchecked_shr(5_i128, -1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 340282366920938463463374607431768211455 in `unchecked_shr` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:110:40 + | +LL | const SHR_I8_NEG_RANDOM: i8 = unsafe { intrinsics::unchecked_shr(5_i8, -6) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 250 in `unchecked_shr` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:112:42 + | +LL | const SHR_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shr(5_16, -13) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 65523 in `unchecked_shr` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:114:42 + | +LL | const SHR_I32_NEG_RANDOM: i32 = unsafe { intrinsics::unchecked_shr(5_i32, -25) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 4294967271 in `unchecked_shr` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:116:42 + | +LL | const SHR_I64_NEG_RANDOM: i64 = unsafe { intrinsics::unchecked_shr(5_i64, -30) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 18446744073709551586 in `unchecked_shr` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:118:44 + | +LL | const SHR_I128_NEG_RANDOM: i128 = unsafe { intrinsics::unchecked_shr(5_i128, -93) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 340282366920938463463374607431768211363 in `unchecked_shr` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:123:25 + | +LL | const _: u16 = unsafe { std::intrinsics::unchecked_add(40000u16, 30000) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_add` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:126:25 + | +LL | const _: u32 = unsafe { std::intrinsics::unchecked_sub(14u32, 22) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_sub` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:129:25 + | +LL | const _: u16 = unsafe { std::intrinsics::unchecked_mul(300u16, 250u16) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_mul` + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:132:25 + | +LL | const _: i32 = unsafe { std::intrinsics::unchecked_div(1, 0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dividing by zero + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:134:25 + | +LL | const _: i32 = unsafe { std::intrinsics::unchecked_div(i32::MIN, -1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:137:25 + | +LL | const _: i32 = unsafe { std::intrinsics::unchecked_rem(1, 0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calculating the remainder with a divisor of zero + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:139:25 + | +LL | const _: i32 = unsafe { std::intrinsics::unchecked_rem(i32::MIN, -1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:144:25 + | +LL | const _: u32 = unsafe { std::intrinsics::ctlz_nonzero(0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ctlz_nonzero` called on 0 + +error[E0080]: evaluation of constant value failed + --> $DIR/const-int-unchecked.rs:146:25 + | +LL | const _: u32 = unsafe { std::intrinsics::cttz_nonzero(0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `cttz_nonzero` called on 0 + +error: aborting due to 49 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-int-wrapping-rpass.rs b/tests/ui/consts/const-int-wrapping-rpass.rs new file mode 100644 index 000000000..225d1e939 --- /dev/null +++ b/tests/ui/consts/const-int-wrapping-rpass.rs @@ -0,0 +1,47 @@ +// run-pass + +const ADD_A: u32 = 200u32.wrapping_add(55); +const ADD_B: u32 = 200u32.wrapping_add(u32::MAX); + +const SUB_A: u32 = 100u32.wrapping_sub(100); +const SUB_B: u32 = 100u32.wrapping_sub(u32::MAX); + +const MUL_A: u8 = 10u8.wrapping_mul(12); +const MUL_B: u8 = 25u8.wrapping_mul(12); + +const SHL_A: u32 = 1u32.wrapping_shl(7); +const SHL_B: u32 = 1u32.wrapping_shl(128); + +const SHR_A: u32 = 128u32.wrapping_shr(7); +const SHR_B: u32 = 128u32.wrapping_shr(128); + +const NEG_A: u32 = 5u32.wrapping_neg(); +const NEG_B: u32 = 1234567890u32.wrapping_neg(); + +const ABS_POS: i32 = 10i32.wrapping_abs(); +const ABS_NEG: i32 = (-10i32).wrapping_abs(); +const ABS_MIN: i32 = i32::MIN.wrapping_abs(); + +fn main() { + assert_eq!(ADD_A, 255); + assert_eq!(ADD_B, 199); + + assert_eq!(SUB_A, 0); + assert_eq!(SUB_B, 101); + + assert_eq!(MUL_A, 120); + assert_eq!(MUL_B, 44); + + assert_eq!(SHL_A, 128); + assert_eq!(SHL_B, 1); + + assert_eq!(SHR_A, 1); + assert_eq!(SHR_B, 128); + + assert_eq!(NEG_A, 4294967291); + assert_eq!(NEG_B, 3060399406); + + assert_eq!(ABS_POS, 10); + assert_eq!(ABS_NEG, 10); + assert_eq!(ABS_MIN, i32::MIN); +} diff --git a/tests/ui/consts/const-int-wrapping.rs b/tests/ui/consts/const-int-wrapping.rs new file mode 100644 index 000000000..50d04f964 --- /dev/null +++ b/tests/ui/consts/const-int-wrapping.rs @@ -0,0 +1,12 @@ +fn main() { + let x: &'static i32 = &(5_i32.wrapping_add(3)); + //~^ ERROR temporary value dropped while borrowed + let y: &'static i32 = &(5_i32.wrapping_sub(3)); + //~^ ERROR temporary value dropped while borrowed + let z: &'static i32 = &(5_i32.wrapping_mul(3)); + //~^ ERROR temporary value dropped while borrowed + let a: &'static i32 = &(5_i32.wrapping_shl(3)); + //~^ ERROR temporary value dropped while borrowed + let b: &'static i32 = &(5_i32.wrapping_shr(3)); + //~^ ERROR temporary value dropped while borrowed +} diff --git a/tests/ui/consts/const-int-wrapping.stderr b/tests/ui/consts/const-int-wrapping.stderr new file mode 100644 index 000000000..1342fadc4 --- /dev/null +++ b/tests/ui/consts/const-int-wrapping.stderr @@ -0,0 +1,58 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-wrapping.rs:2:28 + | +LL | let x: &'static i32 = &(5_i32.wrapping_add(3)); + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-wrapping.rs:4:28 + | +LL | let y: &'static i32 = &(5_i32.wrapping_sub(3)); + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-wrapping.rs:6:28 + | +LL | let z: &'static i32 = &(5_i32.wrapping_mul(3)); + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-wrapping.rs:8:28 + | +LL | let a: &'static i32 = &(5_i32.wrapping_shl(3)); + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-int-wrapping.rs:10:28 + | +LL | let b: &'static i32 = &(5_i32.wrapping_shr(3)); + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/const-integer-bool-ops.rs b/tests/ui/consts/const-integer-bool-ops.rs new file mode 100644 index 000000000..4110ae3e4 --- /dev/null +++ b/tests/ui/consts/const-integer-bool-ops.rs @@ -0,0 +1,85 @@ +const X: usize = 42 && 39; +//~^ ERROR mismatched types +//~| expected `bool`, found integer +//~| ERROR mismatched types +//~| expected `bool`, found integer +//~| ERROR mismatched types +//~| expected `usize`, found `bool` +const ARR: [i32; X] = [99; 34]; +//~^ constant + +const X1: usize = 42 || 39; +//~^ ERROR mismatched types +//~| expected `bool`, found integer +//~| ERROR mismatched types +//~| expected `bool`, found integer +//~| ERROR mismatched types +//~| expected `usize`, found `bool` +const ARR1: [i32; X1] = [99; 47]; +//~^ constant + +const X2: usize = -42 || -39; +//~^ ERROR mismatched types +//~| expected `bool`, found integer +//~| ERROR mismatched types +//~| expected `bool`, found integer +//~| ERROR mismatched types +//~| expected `usize`, found `bool` +const ARR2: [i32; X2] = [99; 18446744073709551607]; +//~^ constant + +const X3: usize = -42 && -39; +//~^ ERROR mismatched types +//~| expected `bool`, found integer +//~| ERROR mismatched types +//~| expected `bool`, found integer +//~| ERROR mismatched types +//~| expected `usize`, found `bool` +const ARR3: [i32; X3] = [99; 6]; +//~^ constant + +const Y: usize = 42.0 == 42.0; +//~^ ERROR mismatched types +//~| expected `usize`, found `bool` +const ARRR: [i32; Y] = [99; 1]; +//~^ constant + +const Y1: usize = 42.0 >= 42.0; +//~^ ERROR mismatched types +//~| expected `usize`, found `bool` +const ARRR1: [i32; Y1] = [99; 1]; +//~^ constant + +const Y2: usize = 42.0 <= 42.0; +//~^ ERROR mismatched types +//~| expected `usize`, found `bool` +const ARRR2: [i32; Y2] = [99; 1]; +//~^ constant + +const Y3: usize = 42.0 > 42.0; +//~^ ERROR mismatched types +//~| expected `usize`, found `bool` +const ARRR3: [i32; Y3] = [99; 0]; +//~^ constant + +const Y4: usize = 42.0 < 42.0; +//~^ ERROR mismatched types +//~| expected `usize`, found `bool` +const ARRR4: [i32; Y4] = [99; 0]; +//~^ constant + +const Y5: usize = 42.0 != 42.0; +//~^ ERROR mismatched types +//~| expected `usize`, found `bool` +const ARRR5: [i32; Y5] = [99; 0]; +//~^ constant + +fn main() { + let _ = ARR; + let _ = ARRR; + let _ = ARRR1; + let _ = ARRR2; + let _ = ARRR3; + let _ = ARRR4; + let _ = ARRR5; +} diff --git a/tests/ui/consts/const-integer-bool-ops.stderr b/tests/ui/consts/const-integer-bool-ops.stderr new file mode 100644 index 000000000..b5c3b22fd --- /dev/null +++ b/tests/ui/consts/const-integer-bool-ops.stderr @@ -0,0 +1,171 @@ +error[E0308]: mismatched types + --> $DIR/const-integer-bool-ops.rs:1:18 + | +LL | const X: usize = 42 && 39; + | ^^ expected `bool`, found integer + +error[E0308]: mismatched types + --> $DIR/const-integer-bool-ops.rs:1:24 + | +LL | const X: usize = 42 && 39; + | ^^ expected `bool`, found integer + +error[E0308]: mismatched types + --> $DIR/const-integer-bool-ops.rs:1:18 + | +LL | const X: usize = 42 && 39; + | ^^^^^^^^ expected `usize`, found `bool` + +note: erroneous constant used + --> $DIR/const-integer-bool-ops.rs:8:18 + | +LL | const ARR: [i32; X] = [99; 34]; + | ^ + +error[E0308]: mismatched types + --> $DIR/const-integer-bool-ops.rs:11:19 + | +LL | const X1: usize = 42 || 39; + | ^^ expected `bool`, found integer + +error[E0308]: mismatched types + --> $DIR/const-integer-bool-ops.rs:11:25 + | +LL | const X1: usize = 42 || 39; + | ^^ expected `bool`, found integer + +error[E0308]: mismatched types + --> $DIR/const-integer-bool-ops.rs:11:19 + | +LL | const X1: usize = 42 || 39; + | ^^^^^^^^ expected `usize`, found `bool` + +note: erroneous constant used + --> $DIR/const-integer-bool-ops.rs:18:19 + | +LL | const ARR1: [i32; X1] = [99; 47]; + | ^^ + +error[E0308]: mismatched types + --> $DIR/const-integer-bool-ops.rs:21:19 + | +LL | const X2: usize = -42 || -39; + | ^^^ expected `bool`, found integer + +error[E0308]: mismatched types + --> $DIR/const-integer-bool-ops.rs:21:26 + | +LL | const X2: usize = -42 || -39; + | ^^^ expected `bool`, found integer + +error[E0308]: mismatched types + --> $DIR/const-integer-bool-ops.rs:21:19 + | +LL | const X2: usize = -42 || -39; + | ^^^^^^^^^^ expected `usize`, found `bool` + +note: erroneous constant used + --> $DIR/const-integer-bool-ops.rs:28:19 + | +LL | const ARR2: [i32; X2] = [99; 18446744073709551607]; + | ^^ + +error[E0308]: mismatched types + --> $DIR/const-integer-bool-ops.rs:31:19 + | +LL | const X3: usize = -42 && -39; + | ^^^ expected `bool`, found integer + +error[E0308]: mismatched types + --> $DIR/const-integer-bool-ops.rs:31:26 + | +LL | const X3: usize = -42 && -39; + | ^^^ expected `bool`, found integer + +error[E0308]: mismatched types + --> $DIR/const-integer-bool-ops.rs:31:19 + | +LL | const X3: usize = -42 && -39; + | ^^^^^^^^^^ expected `usize`, found `bool` + +note: erroneous constant used + --> $DIR/const-integer-bool-ops.rs:38:19 + | +LL | const ARR3: [i32; X3] = [99; 6]; + | ^^ + +error[E0308]: mismatched types + --> $DIR/const-integer-bool-ops.rs:41:18 + | +LL | const Y: usize = 42.0 == 42.0; + | ^^^^^^^^^^^^ expected `usize`, found `bool` + +note: erroneous constant used + --> $DIR/const-integer-bool-ops.rs:44:19 + | +LL | const ARRR: [i32; Y] = [99; 1]; + | ^ + +error[E0308]: mismatched types + --> $DIR/const-integer-bool-ops.rs:47:19 + | +LL | const Y1: usize = 42.0 >= 42.0; + | ^^^^^^^^^^^^ expected `usize`, found `bool` + +note: erroneous constant used + --> $DIR/const-integer-bool-ops.rs:50:20 + | +LL | const ARRR1: [i32; Y1] = [99; 1]; + | ^^ + +error[E0308]: mismatched types + --> $DIR/const-integer-bool-ops.rs:53:19 + | +LL | const Y2: usize = 42.0 <= 42.0; + | ^^^^^^^^^^^^ expected `usize`, found `bool` + +note: erroneous constant used + --> $DIR/const-integer-bool-ops.rs:56:20 + | +LL | const ARRR2: [i32; Y2] = [99; 1]; + | ^^ + +error[E0308]: mismatched types + --> $DIR/const-integer-bool-ops.rs:59:19 + | +LL | const Y3: usize = 42.0 > 42.0; + | ^^^^^^^^^^^ expected `usize`, found `bool` + +note: erroneous constant used + --> $DIR/const-integer-bool-ops.rs:62:20 + | +LL | const ARRR3: [i32; Y3] = [99; 0]; + | ^^ + +error[E0308]: mismatched types + --> $DIR/const-integer-bool-ops.rs:65:19 + | +LL | const Y4: usize = 42.0 < 42.0; + | ^^^^^^^^^^^ expected `usize`, found `bool` + +note: erroneous constant used + --> $DIR/const-integer-bool-ops.rs:68:20 + | +LL | const ARRR4: [i32; Y4] = [99; 0]; + | ^^ + +error[E0308]: mismatched types + --> $DIR/const-integer-bool-ops.rs:71:19 + | +LL | const Y5: usize = 42.0 != 42.0; + | ^^^^^^^^^^^^ expected `usize`, found `bool` + +note: erroneous constant used + --> $DIR/const-integer-bool-ops.rs:74:20 + | +LL | const ARRR5: [i32; Y5] = [99; 0]; + | ^^ + +error: aborting due to 18 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/const-labeled-break.rs b/tests/ui/consts/const-labeled-break.rs new file mode 100644 index 000000000..6864f7247 --- /dev/null +++ b/tests/ui/consts/const-labeled-break.rs @@ -0,0 +1,11 @@ +// run-pass + +// Using labeled break in a while loop has caused an illegal instruction being +// generated, and an ICE later. +// +// See https://github.com/rust-lang/rust/issues/51350 for more information. + +#[allow(unreachable_code)] +const _: () = 'a: while break 'a {}; + +fn main() {} diff --git a/tests/ui/consts/const-len-underflow-separate-spans.rs b/tests/ui/consts/const-len-underflow-separate-spans.rs new file mode 100644 index 000000000..4544c8876 --- /dev/null +++ b/tests/ui/consts/const-len-underflow-separate-spans.rs @@ -0,0 +1,13 @@ +// Check that a constant-evaluation underflow highlights the correct +// spot (where the underflow occurred), while also providing the +// overall context for what caused the evaluation. + +const ONE: usize = 1; +const TWO: usize = 2; +const LEN: usize = ONE - TWO; +//~^ ERROR constant + +fn main() { + let a: [i8; LEN] = unimplemented!(); +//~^ constant +} diff --git a/tests/ui/consts/const-len-underflow-separate-spans.stderr b/tests/ui/consts/const-len-underflow-separate-spans.stderr new file mode 100644 index 000000000..269553631 --- /dev/null +++ b/tests/ui/consts/const-len-underflow-separate-spans.stderr @@ -0,0 +1,15 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-len-underflow-separate-spans.rs:7:20 + | +LL | const LEN: usize = ONE - TWO; + | ^^^^^^^^^ attempt to compute `1_usize - 2_usize`, which would overflow + +note: erroneous constant used + --> $DIR/const-len-underflow-separate-spans.rs:11:17 + | +LL | let a: [i8; LEN] = unimplemented!(); + | ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-len-underflow-subspans.rs b/tests/ui/consts/const-len-underflow-subspans.rs new file mode 100644 index 000000000..ed77e9078 --- /dev/null +++ b/tests/ui/consts/const-len-underflow-subspans.rs @@ -0,0 +1,11 @@ +// Check that a constant-evaluation underflow highlights the correct +// spot (where the underflow occurred). + +const ONE: usize = 1; +const TWO: usize = 2; + +fn main() { + let a: [i8; ONE - TWO] = unimplemented!(); + //~^ ERROR evaluation of constant value failed + //~| attempt to compute `1_usize - 2_usize`, which would overflow +} diff --git a/tests/ui/consts/const-len-underflow-subspans.stderr b/tests/ui/consts/const-len-underflow-subspans.stderr new file mode 100644 index 000000000..68e958b37 --- /dev/null +++ b/tests/ui/consts/const-len-underflow-subspans.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-len-underflow-subspans.rs:8:17 + | +LL | let a: [i8; ONE - TWO] = unimplemented!(); + | ^^^^^^^^^ attempt to compute `1_usize - 2_usize`, which would overflow + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-match-check.eval1.stderr b/tests/ui/consts/const-match-check.eval1.stderr new file mode 100644 index 000000000..08fcd1dea --- /dev/null +++ b/tests/ui/consts/const-match-check.eval1.stderr @@ -0,0 +1,21 @@ +error[E0005]: refutable pattern in local binding + --> $DIR/const-match-check.rs:25:15 + | +LL | A = { let 0 = 0; 0 }, + | ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html + = note: the matched value is of type `i32` +help: you might want to use `if let` to ignore the variants that aren't matched + | +LL | A = { if let 0 = 0 { todo!() } 0 }, + | ++ ~~~~~~~~~~~ +help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits + | +LL | A = { let _0 = 0; 0 }, + | + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0005`. diff --git a/tests/ui/consts/const-match-check.eval2.stderr b/tests/ui/consts/const-match-check.eval2.stderr new file mode 100644 index 000000000..5d86ca4bf --- /dev/null +++ b/tests/ui/consts/const-match-check.eval2.stderr @@ -0,0 +1,21 @@ +error[E0005]: refutable pattern in local binding + --> $DIR/const-match-check.rs:31:24 + | +LL | let x: [i32; { let 0 = 0; 0 }] = []; + | ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html + = note: the matched value is of type `i32` +help: you might want to use `if let` to ignore the variants that aren't matched + | +LL | let x: [i32; { if let 0 = 0 { todo!() } 0 }] = []; + | ++ ~~~~~~~~~~~ +help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits + | +LL | let x: [i32; { let _0 = 0; 0 }] = []; + | + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0005`. diff --git a/tests/ui/consts/const-match-check.matchck.stderr b/tests/ui/consts/const-match-check.matchck.stderr new file mode 100644 index 000000000..c8f66bb0f --- /dev/null +++ b/tests/ui/consts/const-match-check.matchck.stderr @@ -0,0 +1,75 @@ +error[E0005]: refutable pattern in local binding + --> $DIR/const-match-check.rs:4:22 + | +LL | const X: i32 = { let 0 = 0; 0 }; + | ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html + = note: the matched value is of type `i32` +help: you might want to use `if let` to ignore the variants that aren't matched + | +LL | const X: i32 = { if let 0 = 0 { todo!() } 0 }; + | ++ ~~~~~~~~~~~ +help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits + | +LL | const X: i32 = { let _0 = 0; 0 }; + | + + +error[E0005]: refutable pattern in local binding + --> $DIR/const-match-check.rs:8:23 + | +LL | static Y: i32 = { let 0 = 0; 0 }; + | ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html + = note: the matched value is of type `i32` +help: you might want to use `if let` to ignore the variants that aren't matched + | +LL | static Y: i32 = { if let 0 = 0 { todo!() } 0 }; + | ++ ~~~~~~~~~~~ +help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits + | +LL | static Y: i32 = { let _0 = 0; 0 }; + | + + +error[E0005]: refutable pattern in local binding + --> $DIR/const-match-check.rs:13:26 + | +LL | const X: i32 = { let 0 = 0; 0 }; + | ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html + = note: the matched value is of type `i32` +help: you might want to use `if let` to ignore the variants that aren't matched + | +LL | const X: i32 = { if let 0 = 0 { todo!() } 0 }; + | ++ ~~~~~~~~~~~ +help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits + | +LL | const X: i32 = { let _0 = 0; 0 }; + | + + +error[E0005]: refutable pattern in local binding + --> $DIR/const-match-check.rs:19:26 + | +LL | const X: i32 = { let 0 = 0; 0 }; + | ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html + = note: the matched value is of type `i32` +help: you might want to use `if let` to ignore the variants that aren't matched + | +LL | const X: i32 = { if let 0 = 0 { todo!() } 0 }; + | ++ ~~~~~~~~~~~ +help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits + | +LL | const X: i32 = { let _0 = 0; 0 }; + | + + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0005`. diff --git a/tests/ui/consts/const-match-check.rs b/tests/ui/consts/const-match-check.rs new file mode 100644 index 000000000..60f60fa40 --- /dev/null +++ b/tests/ui/consts/const-match-check.rs @@ -0,0 +1,33 @@ +// revisions: matchck eval1 eval2 + +#[cfg(matchck)] +const X: i32 = { let 0 = 0; 0 }; +//[matchck]~^ ERROR refutable pattern in local binding + +#[cfg(matchck)] +static Y: i32 = { let 0 = 0; 0 }; +//[matchck]~^ ERROR refutable pattern in local binding + +#[cfg(matchck)] +trait Bar { + const X: i32 = { let 0 = 0; 0 }; + //[matchck]~^ ERROR refutable pattern in local binding +} + +#[cfg(matchck)] +impl Bar for () { + const X: i32 = { let 0 = 0; 0 }; + //[matchck]~^ ERROR refutable pattern in local binding +} + +#[cfg(eval1)] +enum Foo { + A = { let 0 = 0; 0 }, + //[eval1]~^ ERROR refutable pattern in local binding +} + +fn main() { + #[cfg(eval2)] + let x: [i32; { let 0 = 0; 0 }] = []; + //[eval2]~^ ERROR refutable pattern in local binding +} diff --git a/tests/ui/consts/const-match-pattern-arm.rs b/tests/ui/consts/const-match-pattern-arm.rs new file mode 100644 index 000000000..90680c019 --- /dev/null +++ b/tests/ui/consts/const-match-pattern-arm.rs @@ -0,0 +1,15 @@ +// check-pass + +const _: bool = match Some(true) { + Some(value) => true, + _ => false +}; + +const _: bool = { + match Some(true) { + Some(value) => true, + _ => false + } +}; + +fn main() {} diff --git a/tests/ui/consts/const-meth-pattern.rs b/tests/ui/consts/const-meth-pattern.rs new file mode 100644 index 000000000..1544d760a --- /dev/null +++ b/tests/ui/consts/const-meth-pattern.rs @@ -0,0 +1,18 @@ +// run-pass + +struct A; + +impl A { + const fn banana() -> bool { + true + } +} + +const ABANANA: bool = A::banana(); + +fn main() { + match true { + ABANANA => {}, + _ => panic!("what?") + } +} diff --git a/tests/ui/consts/const-multi-ref.rs b/tests/ui/consts/const-multi-ref.rs new file mode 100644 index 000000000..7e0f1a812 --- /dev/null +++ b/tests/ui/consts/const-multi-ref.rs @@ -0,0 +1,24 @@ +// Ensure that we point the user to the erroneous borrow but not to any subsequent borrows of that +// initial one. + +const _: i32 = { + let mut a = 5; + let p = &mut a; //~ ERROR mutable references are not allowed in constants + + let reborrow = {p}; + let pp = &reborrow; + let ppp = &pp; + ***ppp +}; + +const _: std::cell::Cell<i32> = { + let mut a = std::cell::Cell::new(5); + let p = &a; //~ ERROR borrowed element may contain interior mutability + + let reborrow = {p}; + let pp = &reborrow; + let ppp = &pp; + a +}; + +fn main() {} diff --git a/tests/ui/consts/const-multi-ref.stderr b/tests/ui/consts/const-multi-ref.stderr new file mode 100644 index 000000000..dd5cadfe2 --- /dev/null +++ b/tests/ui/consts/const-multi-ref.stderr @@ -0,0 +1,21 @@ +error[E0658]: mutable references are not allowed in constants + --> $DIR/const-multi-ref.rs:6:13 + | +LL | let p = &mut a; + | ^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability + --> $DIR/const-multi-ref.rs:16:13 + | +LL | let p = &a; + | ^^ + | + = note: see issue #80384 <https://github.com/rust-lang/rust/issues/80384> for more information + = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/const-mut-refs/const_mut_address_of.rs b/tests/ui/consts/const-mut-refs/const_mut_address_of.rs new file mode 100644 index 000000000..03b2f9e3c --- /dev/null +++ b/tests/ui/consts/const-mut-refs/const_mut_address_of.rs @@ -0,0 +1,28 @@ +// check-pass +#![feature(const_mut_refs)] +#![feature(raw_ref_op)] + +struct Foo { + x: usize +} + +const fn foo() -> Foo { + Foo { x: 0 } +} + +impl Foo { + const fn bar(&mut self) -> *mut usize { + &raw mut self.x + } +} + +const fn baz(foo: &mut Foo)-> *mut usize { + &raw mut foo.x +} + +const _: () = { + foo().bar(); + baz(&mut foo()); +}; + +fn main() {} diff --git a/tests/ui/consts/const-mut-refs/const_mut_refs.rs b/tests/ui/consts/const-mut-refs/const_mut_refs.rs new file mode 100644 index 000000000..544458dfc --- /dev/null +++ b/tests/ui/consts/const-mut-refs/const_mut_refs.rs @@ -0,0 +1,35 @@ +// check-pass +#![feature(const_mut_refs)] + +struct Foo { + x: usize +} + +const fn foo() -> Foo { + Foo { x: 0 } +} + +impl Foo { + const fn bar(&mut self) -> usize { + self.x = 1; + self.x + } + +} + +const fn baz(foo: &mut Foo) -> usize { + let x = &mut foo.x; + *x = 2; + *x +} + +const fn bazz(foo: &mut Foo) -> usize { + foo.x = 3; + foo.x +} + +fn main() { + let _: [(); foo().bar()] = [(); 1]; + let _: [(); baz(&mut foo())] = [(); 2]; + let _: [(); bazz(&mut foo())] = [(); 3]; +} diff --git a/tests/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs b/tests/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs new file mode 100644 index 000000000..ce9be4ac5 --- /dev/null +++ b/tests/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs @@ -0,0 +1,8 @@ +fn main() { + foo(&mut 5); +} + +const fn foo(x: &mut i32) -> i32 { //~ ERROR mutable references + *x + 1 + +} diff --git a/tests/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr b/tests/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr new file mode 100644 index 000000000..3f9bd3705 --- /dev/null +++ b/tests/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr @@ -0,0 +1,12 @@ +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/feature-gate-const_mut_refs.rs:5:14 + | +LL | const fn foo(x: &mut i32) -> i32 { + | ^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/const-mut-refs/issue-76510.32bit.stderr b/tests/ui/consts/const-mut-refs/issue-76510.32bit.stderr new file mode 100644 index 000000000..109d15a8e --- /dev/null +++ b/tests/ui/consts/const-mut-refs/issue-76510.32bit.stderr @@ -0,0 +1,31 @@ +error[E0764]: mutable references are not allowed in the final value of constants + --> $DIR/issue-76510.rs:5:29 + | +LL | const S: &'static mut str = &mut " hello "; + | ^^^^^^^^^^^^^^ + +error[E0658]: mutation through a reference is not allowed in constants + --> $DIR/issue-76510.rs:5:29 + | +LL | const S: &'static mut str = &mut " hello "; + | ^^^^^^^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/issue-76510.rs:5:29 + | +LL | const S: &'static mut str = &mut " hello "; + | ^^^^^^^^^^^^^^ cannot borrow as mutable + +note: erroneous constant used + --> $DIR/issue-76510.rs:11:70 + | +LL | let s = transmute::<(*const u8, usize), &ManuallyDrop<str>>((S.as_ptr(), 3)); + | ^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0596, E0658, E0764. +For more information about an error, try `rustc --explain E0596`. diff --git a/tests/ui/consts/const-mut-refs/issue-76510.64bit.stderr b/tests/ui/consts/const-mut-refs/issue-76510.64bit.stderr new file mode 100644 index 000000000..109d15a8e --- /dev/null +++ b/tests/ui/consts/const-mut-refs/issue-76510.64bit.stderr @@ -0,0 +1,31 @@ +error[E0764]: mutable references are not allowed in the final value of constants + --> $DIR/issue-76510.rs:5:29 + | +LL | const S: &'static mut str = &mut " hello "; + | ^^^^^^^^^^^^^^ + +error[E0658]: mutation through a reference is not allowed in constants + --> $DIR/issue-76510.rs:5:29 + | +LL | const S: &'static mut str = &mut " hello "; + | ^^^^^^^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/issue-76510.rs:5:29 + | +LL | const S: &'static mut str = &mut " hello "; + | ^^^^^^^^^^^^^^ cannot borrow as mutable + +note: erroneous constant used + --> $DIR/issue-76510.rs:11:70 + | +LL | let s = transmute::<(*const u8, usize), &ManuallyDrop<str>>((S.as_ptr(), 3)); + | ^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0596, E0658, E0764. +For more information about an error, try `rustc --explain E0596`. diff --git a/tests/ui/consts/const-mut-refs/issue-76510.rs b/tests/ui/consts/const-mut-refs/issue-76510.rs new file mode 100644 index 000000000..b853e2737 --- /dev/null +++ b/tests/ui/consts/const-mut-refs/issue-76510.rs @@ -0,0 +1,18 @@ +// stderr-per-bitwidth + +use std::mem::{transmute, ManuallyDrop}; + +const S: &'static mut str = &mut " hello "; +//~^ ERROR: mutable references are not allowed in the final value of constants +//~| ERROR: mutation through a reference is not allowed in constants +//~| ERROR: cannot borrow data in a `&` reference as mutable + +const fn trigger() -> [(); unsafe { + let s = transmute::<(*const u8, usize), &ManuallyDrop<str>>((S.as_ptr(), 3)); + //~^ constant + 0 + }] { + [(); 0] +} + +fn main() {} diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs b/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs new file mode 100644 index 000000000..a7d329f12 --- /dev/null +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final.rs @@ -0,0 +1,55 @@ +#![feature(const_mut_refs)] +#![feature(raw_ref_op)] + +const NULL: *mut i32 = std::ptr::null_mut(); +const A: *const i32 = &4; + +// It could be made sound to allow it to compile, +// but we do not want to allow this to compile, +// as that would be an enormous footgun in oli-obk's opinion. +const B: *mut i32 = &mut 4; //~ ERROR mutable references are not allowed + +// Ok, no actual mutable allocation exists +const B2: Option<&mut i32> = None; + +// Not ok, can't prove that no mutable allocation ends up in final value +const B3: Option<&mut i32> = Some(&mut 42); //~ ERROR temporary value dropped while borrowed + +const fn helper(x: &mut i32) -> Option<&mut i32> { Some(x) } +const B4: Option<&mut i32> = helper(&mut 42); //~ ERROR temporary value dropped while borrowed + +// Ok, because no references to mutable data exist here, since the `{}` moves +// its value and then takes a reference to that. +const C: *const i32 = &{ + let mut x = 42; + x += 3; + x +}; + +use std::cell::UnsafeCell; +struct NotAMutex<T>(UnsafeCell<T>); + +unsafe impl<T> Sync for NotAMutex<T> {} + +const FOO: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); +//~^ ERROR temporary value dropped while borrowed + +static FOO2: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); +//~^ ERROR temporary value dropped while borrowed + +static mut FOO3: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); +//~^ ERROR temporary value dropped while borrowed + +// `BAR` works, because `&42` promotes immediately instead of relying on +// the enclosing scope rule. +const BAR: NotAMutex<&i32> = NotAMutex(UnsafeCell::new(&42)); + +fn main() { + println!("{}", unsafe { *A }); + unsafe { *B = 4 } // Bad news + + unsafe { + **FOO.0.get() = 99; + assert_eq!(**FOO.0.get(), 99); + } +} diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr b/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr new file mode 100644 index 000000000..78c58b5ab --- /dev/null +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr @@ -0,0 +1,60 @@ +error[E0764]: mutable references are not allowed in the final value of constants + --> $DIR/mut_ref_in_final.rs:10:21 + | +LL | const B: *mut i32 = &mut 4; + | ^^^^^^ + +error[E0716]: temporary value dropped while borrowed + --> $DIR/mut_ref_in_final.rs:16:40 + | +LL | const B3: Option<&mut i32> = Some(&mut 42); + | ----------^^- + | | | | + | | | temporary value is freed at the end of this statement + | | creates a temporary value which is freed while still in use + | using this value as a constant requires that borrow lasts for `'static` + +error[E0716]: temporary value dropped while borrowed + --> $DIR/mut_ref_in_final.rs:19:42 + | +LL | const B4: Option<&mut i32> = helper(&mut 42); + | ------------^^- + | | | | + | | | temporary value is freed at the end of this statement + | | creates a temporary value which is freed while still in use + | using this value as a constant requires that borrow lasts for `'static` + +error[E0716]: temporary value dropped while borrowed + --> $DIR/mut_ref_in_final.rs:34:65 + | +LL | const FOO: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); + | -------------------------------^^-- + | | | | + | | | temporary value is freed at the end of this statement + | | creates a temporary value which is freed while still in use + | using this value as a constant requires that borrow lasts for `'static` + +error[E0716]: temporary value dropped while borrowed + --> $DIR/mut_ref_in_final.rs:37:67 + | +LL | static FOO2: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); + | -------------------------------^^-- + | | | | + | | | temporary value is freed at the end of this statement + | | creates a temporary value which is freed while still in use + | using this value as a static requires that borrow lasts for `'static` + +error[E0716]: temporary value dropped while borrowed + --> $DIR/mut_ref_in_final.rs:40:71 + | +LL | static mut FOO3: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); + | -------------------------------^^-- + | | | | + | | | temporary value is freed at the end of this statement + | | creates a temporary value which is freed while still in use + | using this value as a static requires that borrow lasts for `'static` + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0716, E0764. +For more information about an error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs new file mode 100644 index 000000000..074beaab2 --- /dev/null +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs @@ -0,0 +1,27 @@ +#![feature(const_mut_refs)] +#![feature(raw_ref_op)] + +// This file checks that our dynamic checks catch things that the static checks miss. +// We do not have static checks for these, because we do not look into function bodies. +// We treat all functions as not returning a mutable reference, because there is no way to +// do that without causing the borrow checker to complain (see the B4/helper test in +// mut_ref_in_final.rs). + +const fn helper() -> Option<&'static mut i32> { unsafe { + // Undefined behaviour (integer as pointer), who doesn't love tests like this. + // This code never gets executed, because the static checks fail before that. + Some(&mut *(42 as *mut i32)) //~ ERROR evaluation of constant value failed + //~| 0x2a[noalloc] is a dangling pointer +} } +// The error is an evaluation error and not a validation error, so the error is reported +// directly at the site where it occurs. +const A: Option<&mut i32> = helper(); + +const fn helper2() -> Option<&'static mut i32> { unsafe { + // Undefined behaviour (dangling pointer), who doesn't love tests like this. + // This code never gets executed, because the static checks fail before that. + Some(&mut *(&mut 42 as *mut i32)) +} } +const B: Option<&mut i32> = helper2(); //~ ERROR encountered dangling pointer in final constant + +fn main() {} diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr new file mode 100644 index 000000000..6e110dbdd --- /dev/null +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr @@ -0,0 +1,26 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/mut_ref_in_final_dynamic_check.rs:13:10 + | +LL | Some(&mut *(42 as *mut i32)) + | ^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0x2a[noalloc] is a dangling pointer (it has no provenance) + | +note: inside `helper` + --> $DIR/mut_ref_in_final_dynamic_check.rs:13:10 + | +LL | Some(&mut *(42 as *mut i32)) + | ^^^^^^^^^^^^^^^^^^^^^^ +note: inside `A` + --> $DIR/mut_ref_in_final_dynamic_check.rs:18:29 + | +LL | const A: Option<&mut i32> = helper(); + | ^^^^^^^^ + +error: encountered dangling pointer in final constant + --> $DIR/mut_ref_in_final_dynamic_check.rs:25:1 + | +LL | const B: Option<&mut i32> = helper2(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-needs_drop-monomorphic.rs b/tests/ui/consts/const-needs_drop-monomorphic.rs new file mode 100644 index 000000000..7402c6809 --- /dev/null +++ b/tests/ui/consts/const-needs_drop-monomorphic.rs @@ -0,0 +1,17 @@ +// Check that evaluation of needs_drop<T> fails when T is not monomorphic. +#![feature(generic_const_exprs)] +#![allow(const_evaluatable_unchecked)] +#![allow(incomplete_features)] + +struct Bool<const B: bool> {} +impl Bool<true> { + fn assert() {} +} +fn f<T>() { + Bool::<{ std::mem::needs_drop::<T>() }>::assert(); + //~^ ERROR no function or associated item named `assert` found + //~| ERROR unconstrained generic constant +} +fn main() { + f::<u32>(); +} diff --git a/tests/ui/consts/const-needs_drop-monomorphic.stderr b/tests/ui/consts/const-needs_drop-monomorphic.stderr new file mode 100644 index 000000000..0874a70ce --- /dev/null +++ b/tests/ui/consts/const-needs_drop-monomorphic.stderr @@ -0,0 +1,20 @@ +error[E0599]: no function or associated item named `assert` found for struct `Bool<{ std::mem::needs_drop::<T>() }>` in the current scope + --> $DIR/const-needs_drop-monomorphic.rs:11:46 + | +LL | struct Bool<const B: bool> {} + | -------------------------- function or associated item `assert` not found for this struct +... +LL | Bool::<{ std::mem::needs_drop::<T>() }>::assert(); + | ^^^^^^ function or associated item cannot be called on `Bool<{ std::mem::needs_drop::<T>() }>` due to unsatisfied trait bounds + +error: unconstrained generic constant + --> $DIR/const-needs_drop-monomorphic.rs:11:5 + | +LL | Bool::<{ std::mem::needs_drop::<T>() }>::assert(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); { std::mem::needs_drop::<T>() }]:` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/consts/const-needs_drop.rs b/tests/ui/consts/const-needs_drop.rs new file mode 100644 index 000000000..11ee7084c --- /dev/null +++ b/tests/ui/consts/const-needs_drop.rs @@ -0,0 +1,31 @@ +// run-pass + +use std::mem; + +#[allow(unused_tuple_struct_fields)] +struct Trivial(u8, f32); + +#[allow(unused_tuple_struct_fields)] +struct NonTrivial(u8, String); + +const CONST_U8: bool = mem::needs_drop::<u8>(); +const CONST_STRING: bool = mem::needs_drop::<String>(); +const CONST_TRIVIAL: bool = mem::needs_drop::<Trivial>(); +const CONST_NON_TRIVIAL: bool = mem::needs_drop::<NonTrivial>(); + +static STATIC_U8: bool = mem::needs_drop::<u8>(); +static STATIC_STRING: bool = mem::needs_drop::<String>(); +static STATIC_TRIVIAL: bool = mem::needs_drop::<Trivial>(); +static STATIC_NON_TRIVIAL: bool = mem::needs_drop::<NonTrivial>(); + +fn main() { + assert!(!CONST_U8); + assert!(CONST_STRING); + assert!(!CONST_TRIVIAL); + assert!(CONST_NON_TRIVIAL); + + assert!(!STATIC_U8); + assert!(STATIC_STRING); + assert!(!STATIC_TRIVIAL); + assert!(STATIC_NON_TRIVIAL); +} diff --git a/tests/ui/consts/const-negation.rs b/tests/ui/consts/const-negation.rs new file mode 100644 index 000000000..18bcdfb01 --- /dev/null +++ b/tests/ui/consts/const-negation.rs @@ -0,0 +1,33 @@ +// run-pass +#![allow(overflowing_literals)] + +fn main() { + #[cfg(target_pointer_width = "32")] + const I: isize = -2147483648isize; + #[cfg(target_pointer_width = "64")] + const I: isize = -9223372036854775808isize; + assert_eq!(i32::MIN as u64, 0xffffffff80000000); + assert_eq!(-2147483648isize as u64, 0xffffffff80000000); + assert_eq!(-2147483648i32 as u64, 0xffffffff80000000); + assert_eq!(i64::MIN as u64, 0x8000000000000000); + #[cfg(target_pointer_width = "64")] + assert_eq!(-9223372036854775808isize as u64, 0x8000000000000000); + #[cfg(target_pointer_width = "32")] + assert_eq!(-9223372036854775808isize as u64, 0); + assert_eq!(-9223372036854775808i32 as u64, 0); + const J: usize = i32::MAX as usize; + const K: usize = -1i32 as u32 as usize; + const L: usize = i32::MIN as usize; + const M: usize = i64::MIN as usize; + match 5 { + J => {}, + K => {}, + L => {}, + M => {}, + _ => {} + } + match 5 { + I => {}, + _ => {} + } +} diff --git a/tests/ui/consts/const-negative.rs b/tests/ui/consts/const-negative.rs new file mode 100644 index 000000000..1cb560936 --- /dev/null +++ b/tests/ui/consts/const-negative.rs @@ -0,0 +1,9 @@ +// run-pass +// Issue #358 +#![allow(non_upper_case_globals)] + +static toplevel_mod: isize = -1; + +pub fn main() { + assert_eq!(toplevel_mod, -1); +} diff --git a/tests/ui/consts/const-nullary-enum.rs b/tests/ui/consts/const-nullary-enum.rs new file mode 100644 index 000000000..b6574dce6 --- /dev/null +++ b/tests/ui/consts/const-nullary-enum.rs @@ -0,0 +1,23 @@ +// run-pass +#![allow(dead_code)] + +enum Foo { + Bar, + Baz, + Boo, +} + +static X: Foo = Foo::Bar; + +pub fn main() { + match X { + Foo::Bar => {} + Foo::Baz | Foo::Boo => panic!() + } + match Y { + Foo::Baz => {} + Foo::Bar | Foo::Boo => panic!() + } +} + +static Y: Foo = Foo::Baz; diff --git a/tests/ui/consts/const-nullary-univariant-enum.rs b/tests/ui/consts/const-nullary-univariant-enum.rs new file mode 100644 index 000000000..51349ad31 --- /dev/null +++ b/tests/ui/consts/const-nullary-univariant-enum.rs @@ -0,0 +1,15 @@ +// run-pass + +#[derive(Copy, Clone)] +enum Foo { + Bar = 0xDEADBEE +} + +static X: Foo = Foo::Bar; + +pub fn main() { + assert_eq!((X as usize), 0xDEADBEE); + assert_eq!((Y as usize), 0xDEADBEE); +} + +static Y: Foo = Foo::Bar; diff --git a/tests/ui/consts/const-pattern-irrefutable.rs b/tests/ui/consts/const-pattern-irrefutable.rs new file mode 100644 index 000000000..61bdf57ff --- /dev/null +++ b/tests/ui/consts/const-pattern-irrefutable.rs @@ -0,0 +1,28 @@ +mod foo { + pub const b: u8 = 2; + pub const d: u8 = 2; +} + +use foo::b as c; +use foo::d; + +const a: u8 = 2; + +fn main() { + let a = 4; + //~^ ERROR refutable pattern in local binding + //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered + //~| missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable + //~| HELP introduce a variable instead + let c = 4; + //~^ ERROR refutable pattern in local binding + //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered + //~| missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable + //~| HELP introduce a variable instead + let d = 4; + //~^ ERROR refutable pattern in local binding + //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered + //~| missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable + //~| HELP introduce a variable instead + fn f() {} // Check that the `NOTE`s still work with an item here (cf. issue #35115). +} diff --git a/tests/ui/consts/const-pattern-irrefutable.stderr b/tests/ui/consts/const-pattern-irrefutable.stderr new file mode 100644 index 000000000..c156ea161 --- /dev/null +++ b/tests/ui/consts/const-pattern-irrefutable.stderr @@ -0,0 +1,48 @@ +error[E0005]: refutable pattern in local binding + --> $DIR/const-pattern-irrefutable.rs:12:9 + | +LL | const a: u8 = 2; + | ----------- constant defined here +... +LL | let a = 4; + | ^ + | | + | patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered + | missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable + | help: introduce a variable instead: `a_var` + | + = note: the matched value is of type `u8` + +error[E0005]: refutable pattern in local binding + --> $DIR/const-pattern-irrefutable.rs:17:9 + | +LL | pub const b: u8 = 2; + | --------------- constant defined here +... +LL | let c = 4; + | ^ + | | + | patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered + | missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable + | help: introduce a variable instead: `c_var` + | + = note: the matched value is of type `u8` + +error[E0005]: refutable pattern in local binding + --> $DIR/const-pattern-irrefutable.rs:22:9 + | +LL | pub const d: u8 = 2; + | --------------- constant defined here +... +LL | let d = 4; + | ^ + | | + | patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered + | missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable + | help: introduce a variable instead: `d_var` + | + = note: the matched value is of type `u8` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0005`. diff --git a/tests/ui/consts/const-pattern-not-const-evaluable.rs b/tests/ui/consts/const-pattern-not-const-evaluable.rs new file mode 100644 index 000000000..dae5343fe --- /dev/null +++ b/tests/ui/consts/const-pattern-not-const-evaluable.rs @@ -0,0 +1,30 @@ +// build-pass (FIXME(62277): could be check-pass?) + +#[derive(PartialEq, Eq)] +enum Cake { + BlackForest, + Marmor, +} +use Cake::*; + +struct Pair<A, B>(A, B); + +const BOO: Pair<Cake, Cake> = Pair(Marmor, BlackForest); +const FOO: Cake = BOO.1; + +const fn foo() -> Cake { + Marmor +} + +const WORKS: Cake = Marmor; + +const GOO: Cake = foo(); + +fn main() { + match BlackForest { + FOO => println!("hi"), + GOO => println!("meh"), + WORKS => println!("möp"), + _ => println!("bye"), + } +} diff --git a/tests/ui/consts/const-pattern-variant.rs b/tests/ui/consts/const-pattern-variant.rs new file mode 100644 index 000000000..80f749ed7 --- /dev/null +++ b/tests/ui/consts/const-pattern-variant.rs @@ -0,0 +1,29 @@ +// run-pass +#![allow(unreachable_patterns)] + +#[derive(PartialEq, Eq)] +enum Cake { + BlackForest, + Marmor, +} +use Cake::*; + +const BOO: (Cake, Cake) = (Marmor, BlackForest); +const FOO: Cake = BOO.1; + +const fn foo() -> Cake { + Marmor +} + +const WORKS: Cake = Marmor; + +const GOO: Cake = foo(); + +fn main() { + match BlackForest { + FOO => println!("hi"), + GOO => println!("meh"), + WORKS => println!("möp"), + _ => println!("bye"), + } +} diff --git a/tests/ui/consts/const-points-to-static.32bit.stderr b/tests/ui/consts/const-points-to-static.32bit.stderr new file mode 100644 index 000000000..c7a435a1e --- /dev/null +++ b/tests/ui/consts/const-points-to-static.32bit.stderr @@ -0,0 +1,22 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/const-points-to-static.rs:6:1 + | +LL | const TEST: &u8 = &MY_STATIC; + | ^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + ╾─alloc1──╼ │ ╾──╼ + } + +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/const-points-to-static.rs:6:20 + | +LL | const TEST: &u8 = &MY_STATIC; + | ^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-points-to-static.64bit.stderr b/tests/ui/consts/const-points-to-static.64bit.stderr new file mode 100644 index 000000000..4d5b8eac5 --- /dev/null +++ b/tests/ui/consts/const-points-to-static.64bit.stderr @@ -0,0 +1,22 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/const-points-to-static.rs:6:1 + | +LL | const TEST: &u8 = &MY_STATIC; + | ^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + ╾───────alloc1────────╼ │ ╾──────╼ + } + +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/const-points-to-static.rs:6:20 + | +LL | const TEST: &u8 = &MY_STATIC; + | ^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-points-to-static.rs b/tests/ui/consts/const-points-to-static.rs new file mode 100644 index 000000000..ca825a1f5 --- /dev/null +++ b/tests/ui/consts/const-points-to-static.rs @@ -0,0 +1,13 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you +// stderr-per-bitwidth + +#![allow(dead_code)] + +const TEST: &u8 = &MY_STATIC; +//~^ ERROR it is undefined behavior to use this value +//~| encountered a reference pointing to a static variable + +static MY_STATIC: u8 = 4; + +fn main() { +} diff --git a/tests/ui/consts/const-prop-ice.rs b/tests/ui/consts/const-prop-ice.rs new file mode 100644 index 000000000..5bffe0206 --- /dev/null +++ b/tests/ui/consts/const-prop-ice.rs @@ -0,0 +1,5 @@ +// build-fail + +fn main() { + [0; 3][3u64 as usize]; //~ ERROR this operation will panic at runtime +} diff --git a/tests/ui/consts/const-prop-ice.stderr b/tests/ui/consts/const-prop-ice.stderr new file mode 100644 index 000000000..3bcf2b2de --- /dev/null +++ b/tests/ui/consts/const-prop-ice.stderr @@ -0,0 +1,10 @@ +error: this operation will panic at runtime + --> $DIR/const-prop-ice.rs:4:5 + | +LL | [0; 3][3u64 as usize]; + | ^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 3 + | + = note: `#[deny(unconditional_panic)]` on by default + +error: aborting due to previous error + diff --git a/tests/ui/consts/const-prop-ice2.rs b/tests/ui/consts/const-prop-ice2.rs new file mode 100644 index 000000000..d533e394c --- /dev/null +++ b/tests/ui/consts/const-prop-ice2.rs @@ -0,0 +1,7 @@ +// build-fail + +fn main() { + enum Enum { One=1 } + let xs=[0;1 as usize]; + println!("{}", xs[Enum::One as usize]); //~ ERROR this operation will panic at runtime +} diff --git a/tests/ui/consts/const-prop-ice2.stderr b/tests/ui/consts/const-prop-ice2.stderr new file mode 100644 index 000000000..2b65ffc2d --- /dev/null +++ b/tests/ui/consts/const-prop-ice2.stderr @@ -0,0 +1,10 @@ +error: this operation will panic at runtime + --> $DIR/const-prop-ice2.rs:6:20 + | +LL | println!("{}", xs[Enum::One as usize]); + | ^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1 + | + = note: `#[deny(unconditional_panic)]` on by default + +error: aborting due to previous error + diff --git a/tests/ui/consts/const-prop-ice3.rs b/tests/ui/consts/const-prop-ice3.rs new file mode 100644 index 000000000..8ab011661 --- /dev/null +++ b/tests/ui/consts/const-prop-ice3.rs @@ -0,0 +1,7 @@ +// run-pass (ensure that const-prop is run) + +struct A<T: ?Sized>(T); + +fn main() { + let _x = &(&A([2, 3]) as &A<[i32]>).0 as *const [i32] as *const i32; +} diff --git a/tests/ui/consts/const-prop-overflowing-casts.rs b/tests/ui/consts/const-prop-overflowing-casts.rs new file mode 100644 index 000000000..8cc5b9825 --- /dev/null +++ b/tests/ui/consts/const-prop-overflowing-casts.rs @@ -0,0 +1,15 @@ +// check-pass + +enum Foo { + Bar = -42, + Baz = 42, +} + +fn main() { + let _ = 0u8 as u32; + let _ = (1u32 << 31) as u16; + let _ = (1u16 << 15) as u8; + let _ = (!0u16) as u8; + let _ = (-1i16) as i8; + let _ = (Foo::Bar) as i8; +} diff --git a/tests/ui/consts/const-prop-read-static-in-const.rs b/tests/ui/consts/const-prop-read-static-in-const.rs new file mode 100644 index 000000000..214262059 --- /dev/null +++ b/tests/ui/consts/const-prop-read-static-in-const.rs @@ -0,0 +1,10 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you + +#![allow(dead_code)] + +const TEST: u8 = MY_STATIC; //~ ERROR constant + +static MY_STATIC: u8 = 4; + +fn main() { +} diff --git a/tests/ui/consts/const-prop-read-static-in-const.stderr b/tests/ui/consts/const-prop-read-static-in-const.stderr new file mode 100644 index 000000000..793da6285 --- /dev/null +++ b/tests/ui/consts/const-prop-read-static-in-const.stderr @@ -0,0 +1,17 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-prop-read-static-in-const.rs:5:18 + | +LL | const TEST: u8 = MY_STATIC; + | ^^^^^^^^^ constant accesses static + +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/const-prop-read-static-in-const.rs:5:18 + | +LL | const TEST: u8 = MY_STATIC; + | ^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-ptr-nonnull-rpass.rs b/tests/ui/consts/const-ptr-nonnull-rpass.rs new file mode 100644 index 000000000..67d52ad08 --- /dev/null +++ b/tests/ui/consts/const-ptr-nonnull-rpass.rs @@ -0,0 +1,17 @@ +// run-pass + +#![feature(ptr_internals, test)] + +extern crate test; +use test::black_box as b; // prevent promotion of the argument and const-propagation of the result + +use std::ptr::NonNull; + +const DANGLING: NonNull<u32> = NonNull::dangling(); +const CASTED: NonNull<u32> = NonNull::cast(NonNull::<i32>::dangling()); + +pub fn main() { + // Be super-extra paranoid and cast the fn items to fn pointers before blackboxing them. + assert_eq!(DANGLING, b::<fn() -> _>(NonNull::dangling)()); + assert_eq!(CASTED, b::<fn() -> _>(NonNull::dangling)()); +} diff --git a/tests/ui/consts/const-ptr-nonnull.rs b/tests/ui/consts/const-ptr-nonnull.rs new file mode 100644 index 000000000..25cf6cf4a --- /dev/null +++ b/tests/ui/consts/const-ptr-nonnull.rs @@ -0,0 +1,11 @@ +use std::ptr::NonNull; + +fn main() { + let x: &'static NonNull<u32> = &(NonNull::dangling()); + //~^ ERROR temporary value dropped while borrowed + + let mut i: i32 = 10; + let non_null = NonNull::new(&mut i).unwrap(); + let x: &'static NonNull<u32> = &(non_null.cast()); + //~^ ERROR temporary value dropped while borrowed +} diff --git a/tests/ui/consts/const-ptr-nonnull.stderr b/tests/ui/consts/const-ptr-nonnull.stderr new file mode 100644 index 000000000..dbcb0c860 --- /dev/null +++ b/tests/ui/consts/const-ptr-nonnull.stderr @@ -0,0 +1,25 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-ptr-nonnull.rs:4:37 + | +LL | let x: &'static NonNull<u32> = &(NonNull::dangling()); + | --------------------- ^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-ptr-nonnull.rs:9:37 + | +LL | let x: &'static NonNull<u32> = &(non_null.cast()); + | --------------------- ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/const-ptr-unique-rpass.rs b/tests/ui/consts/const-ptr-unique-rpass.rs new file mode 100644 index 000000000..fc13bb98b --- /dev/null +++ b/tests/ui/consts/const-ptr-unique-rpass.rs @@ -0,0 +1,16 @@ +// run-pass + +#![feature(ptr_internals, test)] + +extern crate test; +use test::black_box as b; // prevent promotion of the argument and const-propagation of the result + +use std::ptr::Unique; + + +const PTR: *mut u32 = Unique::dangling().as_ptr(); + +pub fn main() { + // Be super-extra paranoid and cast the fn items to fn pointers before blackboxing them. + assert_eq!(PTR, b::<fn() -> _>(Unique::<u32>::dangling)().as_ptr()); +} diff --git a/tests/ui/consts/const-ptr-unique.rs b/tests/ui/consts/const-ptr-unique.rs new file mode 100644 index 000000000..252c5d1a9 --- /dev/null +++ b/tests/ui/consts/const-ptr-unique.rs @@ -0,0 +1,10 @@ +#![feature(ptr_internals)] + +use std::ptr::Unique; + +fn main() { + let mut i: u32 = 10; + let unique = Unique::new(&mut i).unwrap(); + let x: &'static *mut u32 = &(unique.as_ptr()); + //~^ ERROR temporary value dropped while borrowed +} diff --git a/tests/ui/consts/const-ptr-unique.stderr b/tests/ui/consts/const-ptr-unique.stderr new file mode 100644 index 000000000..83448c3e8 --- /dev/null +++ b/tests/ui/consts/const-ptr-unique.stderr @@ -0,0 +1,14 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-ptr-unique.rs:8:33 + | +LL | let x: &'static *mut u32 = &(unique.as_ptr()); + | ----------------- ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/const-rec-and-tup.rs b/tests/ui/consts/const-rec-and-tup.rs new file mode 100644 index 000000000..0bddaf75d --- /dev/null +++ b/tests/ui/consts/const-rec-and-tup.rs @@ -0,0 +1,20 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_upper_case_globals)] +#![allow(overflowing_literals)] + +struct Pair { a: f64, b: f64 } + +struct AnotherPair { x: (i64, i64), y: Pair } + +static x : (i32,i32) = (0xfeedf00dd,0xca11ab1e); +static y : AnotherPair = AnotherPair{ x: (0xf0f0f0f0_f0f0f0f0, + 0xabababab_abababab), + y: Pair { a: 3.14159265358979323846, + b: 2.7182818284590452354 }}; + +pub fn main() { + let (p, _) = y.x; + assert_eq!(p, - 1085102592571150096); + println!("{:#x}", p); +} diff --git a/tests/ui/consts/const-region-ptrs-noncopy.rs b/tests/ui/consts/const-region-ptrs-noncopy.rs new file mode 100644 index 000000000..10b9ce896 --- /dev/null +++ b/tests/ui/consts/const-region-ptrs-noncopy.rs @@ -0,0 +1,12 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_upper_case_globals)] + +type Big = [u64; 8]; +struct Pair<'a> { a: isize, b: &'a Big } +const x: &'static Big = &([13, 14, 10, 13, 11, 14, 14, 15]); +const y: &'static Pair<'static> = &Pair {a: 15, b: x}; + +pub fn main() { + assert_eq!(x as *const Big, y.b as *const Big); +} diff --git a/tests/ui/consts/const-region-ptrs.rs b/tests/ui/consts/const-region-ptrs.rs new file mode 100644 index 000000000..9b94a2b11 --- /dev/null +++ b/tests/ui/consts/const-region-ptrs.rs @@ -0,0 +1,15 @@ +// run-pass +#![allow(non_upper_case_globals)] + +struct Pair<'a> { a: isize, b: &'a isize } + +const x: &'static isize = &10; + +const y: &'static Pair<'static> = &Pair {a: 15, b: x}; + +pub fn main() { + println!("x = {}", *x); + println!("y = {{a: {}, b: {}}}", y.a, *(y.b)); + assert_eq!(*x, 10); + assert_eq!(*(y.b), 10); +} diff --git a/tests/ui/consts/const-repeated-values.rs b/tests/ui/consts/const-repeated-values.rs new file mode 100644 index 000000000..27efb5ba2 --- /dev/null +++ b/tests/ui/consts/const-repeated-values.rs @@ -0,0 +1,10 @@ +// run-pass +const FOO: isize = 42; + +enum Bar { + Boo = *[&FOO; 4][3], +} + +fn main() { + assert_eq!(Bar::Boo as isize, 42); +} diff --git a/tests/ui/consts/const-size_of-align_of.rs b/tests/ui/consts/const-size_of-align_of.rs new file mode 100644 index 000000000..0c63dc84a --- /dev/null +++ b/tests/ui/consts/const-size_of-align_of.rs @@ -0,0 +1,51 @@ +// run-pass +#![allow(dead_code)] + +use std::mem; + +// Get around the limitations of CTFE in today's Rust. +const fn choice_u64(c: bool, a: u64, b: u64) -> u64 { + (-(c as i64) as u64) & a | (-(!c as i64) as u64) & b +} + +const fn max_usize(a: usize, b: usize) -> usize { + choice_u64(a > b, a as u64, b as u64) as usize +} + +const fn align_to(size: usize, align: usize) -> usize { + (size + (align - 1)) & !(align - 1) +} + +const fn packed_union_size_of<A, B>() -> usize { + max_usize(mem::size_of::<A>(), mem::size_of::<B>()) +} + +const fn union_align_of<A, B>() -> usize { + max_usize(mem::align_of::<A>(), mem::align_of::<B>()) +} + +const fn union_size_of<A, B>() -> usize { + align_to(packed_union_size_of::<A, B>(), union_align_of::<A, B>()) +} + +macro_rules! fake_union { + ($name:ident { $a:ty, $b:ty }) => ( + struct $name { + _align: ([$a; 0], [$b; 0]), + _bytes: [u8; union_size_of::<$a, $b>()] + } + ) +} + +// Check that we can (poorly) emulate unions by +// calling size_of and align_of at compile-time. +fake_union!(U { u16, [u8; 3] }); + +fn test(u: U) { + assert_eq!(mem::size_of_val(&u._bytes), 4); +} + +fn main() { + assert_eq!(mem::size_of::<U>(), 4); + assert_eq!(mem::align_of::<U>(), 2); +} diff --git a/tests/ui/consts/const-size_of-cycle.rs b/tests/ui/consts/const-size_of-cycle.rs new file mode 100644 index 000000000..1f56c8bd8 --- /dev/null +++ b/tests/ui/consts/const-size_of-cycle.rs @@ -0,0 +1,7 @@ +// error-pattern: cycle detected + +struct Foo { + bytes: [u8; std::mem::size_of::<Foo>()] +} + +fn main() {} diff --git a/tests/ui/consts/const-size_of-cycle.stderr b/tests/ui/consts/const-size_of-cycle.stderr new file mode 100644 index 000000000..17088d999 --- /dev/null +++ b/tests/ui/consts/const-size_of-cycle.stderr @@ -0,0 +1,29 @@ +error[E0391]: cycle detected when evaluating type-level constant + --> $DIR/const-size_of-cycle.rs:4:17 + | +LL | bytes: [u8; std::mem::size_of::<Foo>()] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`... + --> $DIR/const-size_of-cycle.rs:4:17 + | +LL | bytes: [u8; std::mem::size_of::<Foo>()] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`... + --> $DIR/const-size_of-cycle.rs:4:17 + | +LL | bytes: [u8; std::mem::size_of::<Foo>()] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which requires computing layout of `Foo`... + = note: ...which requires computing layout of `[u8; std::mem::size_of::<Foo>()]`... + = note: ...which requires normalizing `[u8; std::mem::size_of::<Foo>()]`... + = note: ...which again requires evaluating type-level constant, completing the cycle +note: cycle used when checking that `Foo` is well-formed + --> $DIR/const-size_of-cycle.rs:3:1 + | +LL | struct Foo { + | ^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs new file mode 100644 index 000000000..4df3a793b --- /dev/null +++ b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs @@ -0,0 +1,14 @@ +#![feature(extern_types)] +#![feature(core_intrinsics)] +#![feature(const_size_of_val, const_align_of_val)] + +use std::intrinsics::{min_align_of_val, size_of_val}; + +extern "C" { + type Opaque; +} + +const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) }; //~ ERROR constant +const _ALIGN: usize = unsafe { min_align_of_val(&4 as *const i32 as *const Opaque) }; //~ ERROR constant + +fn main() {} diff --git a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr new file mode 100644 index 000000000..ad2de0f4d --- /dev/null +++ b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr @@ -0,0 +1,15 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-size_of_val-align_of_val-extern-type.rs:11:31 + | +LL | const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `extern type` does not have known layout + +error[E0080]: evaluation of constant value failed + --> $DIR/const-size_of_val-align_of_val-extern-type.rs:12:32 + | +LL | const _ALIGN: usize = unsafe { min_align_of_val(&4 as *const i32 as *const Opaque) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `extern type` does not have known layout + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-size_of_val-align_of_val.rs b/tests/ui/consts/const-size_of_val-align_of_val.rs new file mode 100644 index 000000000..e8323e4ae --- /dev/null +++ b/tests/ui/consts/const-size_of_val-align_of_val.rs @@ -0,0 +1,55 @@ +// run-pass + +#![feature(const_size_of_val, const_align_of_val)] +#![feature(const_size_of_val_raw, const_align_of_val_raw, layout_for_ptr)] + +use std::{mem, ptr}; + +struct Foo(#[allow(unused_tuple_struct_fields)] u32); + +#[derive(Clone, Copy)] +struct Bar { + _x: u8, + _y: u16, + _z: u8, +} + +union Ugh { + _a: [u8; 3], + _b: Bar, +} + +const FOO: Foo = Foo(4); +const BAR: Bar = Bar { _x: 4, _y: 1, _z: 2 }; +const UGH: Ugh = Ugh { _a: [0; 3] }; + +const SIZE_OF_FOO: usize = mem::size_of_val(&FOO); +const SIZE_OF_BAR: usize = mem::size_of_val(&BAR); +const SIZE_OF_UGH: usize = mem::size_of_val(&UGH); + +const ALIGN_OF_FOO: usize = mem::align_of_val(&FOO); +const ALIGN_OF_BAR: usize = mem::align_of_val(&BAR); +const ALIGN_OF_UGH: usize = mem::align_of_val(&UGH); + +const SIZE_OF_SLICE: usize = mem::size_of_val("foobar".as_bytes()); + +const SIZE_OF_DANGLING: usize = unsafe { mem::size_of_val_raw(0x100 as *const i32) }; +const SIZE_OF_BIG: usize = + unsafe { mem::size_of_val_raw(ptr::slice_from_raw_parts(0 as *const u8, isize::MAX as usize)) }; +const ALIGN_OF_DANGLING: usize = unsafe { mem::align_of_val_raw(0x100 as *const i16) }; + +fn main() { + assert_eq!(SIZE_OF_FOO, mem::size_of::<Foo>()); + assert_eq!(SIZE_OF_BAR, mem::size_of::<Bar>()); + assert_eq!(SIZE_OF_UGH, mem::size_of::<Ugh>()); + + assert_eq!(ALIGN_OF_FOO, mem::align_of::<Foo>()); + assert_eq!(ALIGN_OF_BAR, mem::align_of::<Bar>()); + assert_eq!(ALIGN_OF_UGH, mem::align_of::<Ugh>()); + + assert_eq!(SIZE_OF_DANGLING, mem::size_of::<i32>()); + assert_eq!(SIZE_OF_BIG, isize::MAX as usize); + assert_eq!(ALIGN_OF_DANGLING, mem::align_of::<i16>()); + + assert_eq!(SIZE_OF_SLICE, "foobar".len()); +} diff --git a/tests/ui/consts/const-slice-oob.rs b/tests/ui/consts/const-slice-oob.rs new file mode 100644 index 000000000..429b97821 --- /dev/null +++ b/tests/ui/consts/const-slice-oob.rs @@ -0,0 +1,8 @@ +const FOO: &'static[u32] = &[1, 2, 3]; +const BAR: u32 = FOO[5]; +//~^ index out of bounds: the length is 3 but the index is 5 +//~| ERROR evaluation of constant value failed + +fn main() { + let _ = BAR; +} diff --git a/tests/ui/consts/const-slice-oob.stderr b/tests/ui/consts/const-slice-oob.stderr new file mode 100644 index 000000000..746883a79 --- /dev/null +++ b/tests/ui/consts/const-slice-oob.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-slice-oob.rs:2:18 + | +LL | const BAR: u32 = FOO[5]; + | ^^^^^^ index out of bounds: the length is 3 but the index is 5 + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-struct-offsets.rs b/tests/ui/consts/const-struct-offsets.rs new file mode 100644 index 000000000..26a008320 --- /dev/null +++ b/tests/ui/consts/const-struct-offsets.rs @@ -0,0 +1,18 @@ +// run-pass +#![allow(dead_code)] +// pretty-expanded FIXME #23616 +#![allow(non_upper_case_globals)] + +enum Foo { + IntVal(i32), + Int64Val(i64) +} + +struct Bar { + i: i32, + v: Foo +} + +static bar: Bar = Bar { i: 0, v: Foo::IntVal(0) }; + +pub fn main() {} diff --git a/tests/ui/consts/const-struct.rs b/tests/ui/consts/const-struct.rs new file mode 100644 index 000000000..db397a891 --- /dev/null +++ b/tests/ui/consts/const-struct.rs @@ -0,0 +1,32 @@ +// run-pass +#![allow(non_camel_case_types)] +#![allow(non_upper_case_globals)] + +use std::cmp; + +#[derive(Debug)] +struct foo { a: isize, b: isize, c: isize } + +impl cmp::PartialEq for foo { + fn eq(&self, other: &foo) -> bool { + (*self).a == (*other).a && + (*self).b == (*other).b && + (*self).c == (*other).c + } + fn ne(&self, other: &foo) -> bool { !(*self).eq(other) } +} + +const x : foo = foo { a:1, b:2, c: 3 }; +const y : foo = foo { b:2, c:3, a: 1 }; +const z : &'static foo = &foo { a: 10, b: 22, c: 12 }; +const w : foo = foo { a:5, ..x }; + +pub fn main() { + assert_eq!(x.b, 2); + assert_eq!(x, y); + assert_eq!(z.b, 22); + assert_eq!(w.a, 5); + assert_eq!(w.c, 3); + println!("{:#x}", x.b); + println!("{:#x}", z.c); +} diff --git a/tests/ui/consts/const-suggest-feature.rs b/tests/ui/consts/const-suggest-feature.rs new file mode 100644 index 000000000..d76d01a3d --- /dev/null +++ b/tests/ui/consts/const-suggest-feature.rs @@ -0,0 +1,7 @@ +const WRITE: () = unsafe { + *std::ptr::null_mut() = 0; + //~^ ERROR dereferencing raw mutable pointers in constants is unstable + //~| HELP add `#![feature(const_mut_refs)]` to the crate attributes to enable +}; + +fn main() {} diff --git a/tests/ui/consts/const-suggest-feature.stderr b/tests/ui/consts/const-suggest-feature.stderr new file mode 100644 index 000000000..3bc1eacf3 --- /dev/null +++ b/tests/ui/consts/const-suggest-feature.stderr @@ -0,0 +1,12 @@ +error[E0658]: dereferencing raw mutable pointers in constants is unstable + --> $DIR/const-suggest-feature.rs:2:5 + | +LL | *std::ptr::null_mut() = 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/const-trait-to-trait.rs b/tests/ui/consts/const-trait-to-trait.rs new file mode 100644 index 000000000..12a2999d7 --- /dev/null +++ b/tests/ui/consts/const-trait-to-trait.rs @@ -0,0 +1,24 @@ +// run-pass +#![allow(dead_code)] +#![allow(unused_variables)] +// Issue #24644 - block causes a &Trait -> &Trait coercion: +trait Trait {} + +struct Bar; +impl Trait for Bar {} + +fn main() { + let x: &[&dyn Trait] = &[{ &Bar }]; +} + +// Issue #25748 - the cast causes an &Encoding -> &Encoding coercion: +pub struct UTF8Encoding; +pub const UTF_8: &'static UTF8Encoding = &UTF8Encoding; +pub trait Encoding {} +impl Encoding for UTF8Encoding {} +pub fn f() -> &'static dyn Encoding { UTF_8 as &'static dyn Encoding } + +// Root of the problem: &Trait -> &Trait coercions: +const FOO: &'static dyn Trait = &Bar; +const BAR: &'static dyn Trait = FOO; +fn foo() { let _x = BAR; } diff --git a/tests/ui/consts/const-try-feature-gate.rs b/tests/ui/consts/const-try-feature-gate.rs new file mode 100644 index 000000000..0839c23a0 --- /dev/null +++ b/tests/ui/consts/const-try-feature-gate.rs @@ -0,0 +1,9 @@ +// gate-test-const_try + +const fn t() -> Option<()> { + Some(())?; + //~^ error: `?` is not allowed in a `const fn` + None +} + +fn main() {} diff --git a/tests/ui/consts/const-try-feature-gate.stderr b/tests/ui/consts/const-try-feature-gate.stderr new file mode 100644 index 000000000..cd1a06304 --- /dev/null +++ b/tests/ui/consts/const-try-feature-gate.stderr @@ -0,0 +1,12 @@ +error[E0658]: `?` is not allowed in a `const fn` + --> $DIR/const-try-feature-gate.rs:4:5 + | +LL | Some(())?; + | ^^^^^^^^^ + | + = note: see issue #74935 <https://github.com/rust-lang/rust/issues/74935> for more information + = help: add `#![feature(const_try)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/const-try.rs b/tests/ui/consts/const-try.rs new file mode 100644 index 000000000..e199fd9ff --- /dev/null +++ b/tests/ui/consts/const-try.rs @@ -0,0 +1,39 @@ +// check-pass + +// Demonstrates what's needed to make use of `?` in const contexts. + +#![crate_type = "lib"] +#![feature(try_trait_v2)] +#![feature(const_trait_impl)] +#![feature(const_try)] + +use std::ops::{ControlFlow, FromResidual, Try}; + +struct TryMe; +struct Error; + +impl const FromResidual<Error> for TryMe { + fn from_residual(residual: Error) -> Self { + TryMe + } +} + +impl const Try for TryMe { + type Output = (); + type Residual = Error; + fn from_output(output: Self::Output) -> Self { + TryMe + } + fn branch(self) -> ControlFlow<Self::Residual, Self::Output> { + ControlFlow::Break(Error) + } +} + +const fn t() -> TryMe { + TryMe?; + TryMe +} + +const _: () = { + t(); +}; diff --git a/tests/ui/consts/const-tup-index-span.rs b/tests/ui/consts/const-tup-index-span.rs new file mode 100644 index 000000000..778a21224 --- /dev/null +++ b/tests/ui/consts/const-tup-index-span.rs @@ -0,0 +1,10 @@ +// Test spans of errors + +const TUP: (usize,) = 5usize << 64; +//~^ ERROR mismatched types +//~| expected tuple, found `usize` +const ARR: [i32; TUP.0] = []; +//~^ constant + +fn main() { +} diff --git a/tests/ui/consts/const-tup-index-span.stderr b/tests/ui/consts/const-tup-index-span.stderr new file mode 100644 index 000000000..ad8468056 --- /dev/null +++ b/tests/ui/consts/const-tup-index-span.stderr @@ -0,0 +1,22 @@ +error[E0308]: mismatched types + --> $DIR/const-tup-index-span.rs:3:23 + | +LL | const TUP: (usize,) = 5usize << 64; + | ^^^^^^^^^^^^ expected tuple, found `usize` + | + = note: expected tuple `(usize,)` + found type `usize` +help: use a trailing comma to create a tuple with one element + | +LL | const TUP: (usize,) = (5usize << 64,); + | + ++ + +note: erroneous constant used + --> $DIR/const-tup-index-span.rs:6:18 + | +LL | const ARR: [i32; TUP.0] = []; + | ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/const-tuple-struct.rs b/tests/ui/consts/const-tuple-struct.rs new file mode 100644 index 000000000..0144afaac --- /dev/null +++ b/tests/ui/consts/const-tuple-struct.rs @@ -0,0 +1,14 @@ +// run-pass + +struct Bar(isize, isize); + +static X: Bar = Bar(1, 2); + +pub fn main() { + match X { + Bar(x, y) => { + assert_eq!(x, 1); + assert_eq!(y, 2); + } + } +} diff --git a/tests/ui/consts/const-type-mismatch.rs b/tests/ui/consts/const-type-mismatch.rs new file mode 100644 index 000000000..6e56c046f --- /dev/null +++ b/tests/ui/consts/const-type-mismatch.rs @@ -0,0 +1,11 @@ +// `const`s shouldn't suggest `.into()` + +const TEN: u8 = 10; +const TWELVE: u16 = TEN + 2; +//~^ ERROR mismatched types [E0308] + +fn main() { + const TEN: u8 = 10; + const ALSO_TEN: u16 = TEN; + //~^ ERROR mismatched types [E0308] +} diff --git a/tests/ui/consts/const-type-mismatch.stderr b/tests/ui/consts/const-type-mismatch.stderr new file mode 100644 index 000000000..17bb27d4b --- /dev/null +++ b/tests/ui/consts/const-type-mismatch.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/const-type-mismatch.rs:4:21 + | +LL | const TWELVE: u16 = TEN + 2; + | ^^^^^^^ expected `u16`, found `u8` + +error[E0308]: mismatched types + --> $DIR/const-type-mismatch.rs:9:27 + | +LL | const ALSO_TEN: u16 = TEN; + | ^^^ expected `u16`, found `u8` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/const-typeid-of-rpass.rs b/tests/ui/consts/const-typeid-of-rpass.rs new file mode 100644 index 000000000..89d57ae4f --- /dev/null +++ b/tests/ui/consts/const-typeid-of-rpass.rs @@ -0,0 +1,34 @@ +// run-pass +#![feature(const_type_id)] +#![feature(core_intrinsics)] + +use std::any::TypeId; + +struct A; + +static ID_ISIZE: TypeId = TypeId::of::<isize>(); + +pub fn main() { + assert_eq!(ID_ISIZE, TypeId::of::<isize>()); + + // sanity test of TypeId + const T: (TypeId, TypeId, TypeId) = (TypeId::of::<usize>(), + TypeId::of::<&'static str>(), + TypeId::of::<A>()); + let (d, e, f) = (TypeId::of::<usize>(), TypeId::of::<&'static str>(), + TypeId::of::<A>()); + + assert!(T.0 != T.1); + assert!(T.0 != T.2); + assert!(T.1 != T.2); + + assert_eq!(T.0, d); + assert_eq!(T.1, e); + assert_eq!(T.2, f); + + // Check fn pointer against collisions + const F: (TypeId, TypeId) = (TypeId::of::<fn(fn(A) -> A) -> A>(), + TypeId::of::<fn(fn() -> A, A) -> A>()); + + assert!(F.0 != F.1); +} diff --git a/tests/ui/consts/const-unit-struct.rs b/tests/ui/consts/const-unit-struct.rs new file mode 100644 index 000000000..1c9e0e8d3 --- /dev/null +++ b/tests/ui/consts/const-unit-struct.rs @@ -0,0 +1,12 @@ +// run-pass +// pretty-expanded FIXME #23616 + +struct Foo; + +static X: Foo = Foo; + +pub fn main() { + match X { + Foo => {} + } +} diff --git a/tests/ui/consts/const-unsafe-fn.rs b/tests/ui/consts/const-unsafe-fn.rs new file mode 100644 index 000000000..72ce73f74 --- /dev/null +++ b/tests/ui/consts/const-unsafe-fn.rs @@ -0,0 +1,21 @@ +// run-pass +#![allow(dead_code)] +// A quick test of 'unsafe const fn' functionality + +const unsafe fn dummy(v: u32) -> u32 { + !v +} + +struct Type; +impl Type { + const unsafe fn new() -> Type { + Type + } +} + +const VAL: u32 = unsafe { dummy(0xFFFF) }; +const TYPE_INST: Type = unsafe { Type::new() }; + +fn main() { + assert_eq!(VAL, 0xFFFF0000); +} diff --git a/tests/ui/consts/const-unsized.rs b/tests/ui/consts/const-unsized.rs new file mode 100644 index 000000000..319b8ef97 --- /dev/null +++ b/tests/ui/consts/const-unsized.rs @@ -0,0 +1,17 @@ +use std::fmt::Debug; + +const CONST_0: dyn Debug + Sync = *(&0 as &(dyn Debug + Sync)); +//~^ ERROR the size for values of type + +const CONST_FOO: str = *"foo"; +//~^ ERROR the size for values of type + +static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync)); +//~^ ERROR the size for values of type + +static STATIC_BAR: str = *"bar"; +//~^ ERROR the size for values of type + +fn main() { + println!("{:?} {:?} {:?} {:?}", &CONST_0, &CONST_FOO, &STATIC_1, &STATIC_BAR); +} diff --git a/tests/ui/consts/const-unsized.stderr b/tests/ui/consts/const-unsized.stderr new file mode 100644 index 000000000..27b200648 --- /dev/null +++ b/tests/ui/consts/const-unsized.stderr @@ -0,0 +1,35 @@ +error[E0277]: the size for values of type `(dyn Debug + Sync + 'static)` cannot be known at compilation time + --> $DIR/const-unsized.rs:3:16 + | +LL | const CONST_0: dyn Debug + Sync = *(&0 as &(dyn Debug + Sync)); + | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Debug + Sync + 'static)` + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/const-unsized.rs:6:18 + | +LL | const CONST_FOO: str = *"foo"; + | ^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + +error[E0277]: the size for values of type `(dyn Debug + Sync + 'static)` cannot be known at compilation time + --> $DIR/const-unsized.rs:9:18 + | +LL | static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync)); + | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Debug + Sync + 'static)` + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/const-unsized.rs:12:20 + | +LL | static STATIC_BAR: str = *"bar"; + | ^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/const-unwrap.rs b/tests/ui/consts/const-unwrap.rs new file mode 100644 index 000000000..729ae535c --- /dev/null +++ b/tests/ui/consts/const-unwrap.rs @@ -0,0 +1,13 @@ +// check-fail + +#![feature(const_option)] + +const FOO: i32 = Some(42i32).unwrap(); + +const BAR: i32 = Option::<i32>::None.unwrap(); +//~^ERROR: evaluation of constant value failed + +fn main() { + println!("{}", FOO); + println!("{}", BAR); +} diff --git a/tests/ui/consts/const-unwrap.stderr b/tests/ui/consts/const-unwrap.stderr new file mode 100644 index 000000000..d2cbe4550 --- /dev/null +++ b/tests/ui/consts/const-unwrap.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-unwrap.rs:7:18 + | +LL | const BAR: i32 = Option::<i32>::None.unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'called `Option::unwrap()` on a `None` value', $DIR/const-unwrap.rs:7:38 + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-validation-fail-55455.rs b/tests/ui/consts/const-validation-fail-55455.rs new file mode 100644 index 000000000..583074888 --- /dev/null +++ b/tests/ui/consts/const-validation-fail-55455.rs @@ -0,0 +1,9 @@ +// https://github.com/rust-lang/rust/issues/55454 +// build-pass (FIXME(62277): could be check-pass?) + +struct This<T>(T); + +const C: This<Option<&i32>> = This(Some(&1)); + +fn main() { +} diff --git a/tests/ui/consts/const-variant-count.rs b/tests/ui/consts/const-variant-count.rs new file mode 100644 index 000000000..50eaeeb46 --- /dev/null +++ b/tests/ui/consts/const-variant-count.rs @@ -0,0 +1,47 @@ +// run-pass +#![allow(dead_code, enum_intrinsics_non_enums)] +#![feature(variant_count)] +#![feature(never_type)] + +use std::mem::variant_count; + +enum Void {} + +enum Foo { + A, + B, + C, +} + +enum Bar { + A, + B, + C, + D(usize), + E { field_1: usize, field_2: Foo }, +} + +struct Baz { + a: u32, + b: *const u8, +} + +const TEST_VOID: usize = variant_count::<Void>(); +const TEST_FOO: usize = variant_count::<Foo>(); +const TEST_BAR: usize = variant_count::<Bar>(); + +const NO_ICE_STRUCT: usize = variant_count::<Baz>(); +const NO_ICE_BOOL: usize = variant_count::<bool>(); +const NO_ICE_PRIM: usize = variant_count::<*const u8>(); + +fn main() { + assert_eq!(TEST_VOID, 0); + assert_eq!(TEST_FOO, 3); + assert_eq!(TEST_BAR, 5); + assert_eq!(variant_count::<Void>(), 0); + assert_eq!(variant_count::<Foo>(), 3); + assert_eq!(variant_count::<Bar>(), 5); + assert_eq!(variant_count::<Option<char>>(), 2); + assert_eq!(variant_count::<Option<!>>(), 2); + assert_eq!(variant_count::<Result<!, !>>(), 2); +} diff --git a/tests/ui/consts/const-vec-of-fns.rs b/tests/ui/consts/const-vec-of-fns.rs new file mode 100644 index 000000000..6d90b066b --- /dev/null +++ b/tests/ui/consts/const-vec-of-fns.rs @@ -0,0 +1,25 @@ +// run-pass +// pretty-expanded FIXME #23616 +#![allow(non_upper_case_globals)] + +/*! + * Try to double-check that static fns have the right size (with or + * without dummy env ptr, as appropriate) by iterating a size-2 array. + * If the static size differs from the runtime size, the second element + * should be read as a null or otherwise wrong pointer and crash. + */ + +fn f() { } +static bare_fns: &'static [fn()] = &[f, f]; +struct S<F: FnOnce()>(F); +static mut closures: &'static mut [S<fn()>] = &mut [S(f as fn()), S(f as fn())]; + +pub fn main() { + unsafe { + for &bare_fn in bare_fns { bare_fn() } + for closure in &mut *closures { + let S(ref mut closure) = *closure; + (*closure)() + } + } +} diff --git a/tests/ui/consts/const-vec-syntax.rs b/tests/ui/consts/const-vec-syntax.rs new file mode 100644 index 000000000..61246e44e --- /dev/null +++ b/tests/ui/consts/const-vec-syntax.rs @@ -0,0 +1,9 @@ +// run-pass +// pretty-expanded FIXME #23616 + +fn f(_: &[isize]) {} + +pub fn main() { + let v = [ 1, 2, 3 ]; + f(&v); +} diff --git a/tests/ui/consts/const-vecs-and-slices.rs b/tests/ui/consts/const-vecs-and-slices.rs new file mode 100644 index 000000000..1cdc33b7a --- /dev/null +++ b/tests/ui/consts/const-vecs-and-slices.rs @@ -0,0 +1,23 @@ +// run-pass +#![allow(non_upper_case_globals)] + +static x : [isize; 4] = [1,2,3,4]; +static y : &'static [isize] = &[1,2,3,4]; +static z : &'static [isize; 4] = &[1,2,3,4]; +static zz : &'static [isize] = &[1,2,3,4]; + +pub fn main() { + println!("{}", x[1]); + println!("{}", y[1]); + println!("{}", z[1]); + println!("{}", zz[1]); + assert_eq!(x[1], 2); + assert_eq!(x[3], 4); + assert_eq!(x[3], y[3]); + assert_eq!(z[1], 2); + assert_eq!(z[3], 4); + assert_eq!(z[3], y[3]); + assert_eq!(zz[1], 2); + assert_eq!(zz[3], 4); + assert_eq!(zz[3], y[3]); +} diff --git a/tests/ui/consts/const.rs b/tests/ui/consts/const.rs new file mode 100644 index 000000000..71fbadfa8 --- /dev/null +++ b/tests/ui/consts/const.rs @@ -0,0 +1,6 @@ +// run-pass +#![allow(non_upper_case_globals)] + +static i: isize = 10; + +pub fn main() { println!("{}", i); } diff --git a/tests/ui/consts/const_cmp_type_id.rs b/tests/ui/consts/const_cmp_type_id.rs new file mode 100644 index 000000000..f10d1c24f --- /dev/null +++ b/tests/ui/consts/const_cmp_type_id.rs @@ -0,0 +1,12 @@ +// run-pass +#![feature(const_type_id)] +#![feature(const_trait_impl)] + +use std::any::TypeId; + +const fn main() { + assert!(TypeId::of::<u8>() == TypeId::of::<u8>()); + assert!(TypeId::of::<()>() != TypeId::of::<u8>()); + const _A: bool = TypeId::of::<u8>() < TypeId::of::<u16>(); + // can't assert `_A` because it is not deterministic +} diff --git a/tests/ui/consts/const_constructor/const-construct-call.rs b/tests/ui/consts/const_constructor/const-construct-call.rs new file mode 100644 index 000000000..cb735d7b3 --- /dev/null +++ b/tests/ui/consts/const_constructor/const-construct-call.rs @@ -0,0 +1,110 @@ +// Test that constructors are considered to be const fns + +// run-pass + +// Ctor(..) is transformed to Ctor { 0: ... } in THIR lowering, so directly +// calling constructors doesn't require them to be const. + +type ExternalType = std::panic::AssertUnwindSafe<(Option<i32>, Result<i32, bool>)>; + +const fn call_external_constructors_in_local_vars() -> ExternalType { + let f = Some; + let g = Err; + let h = std::panic::AssertUnwindSafe; + let x = f(5); + let y = g(false); + let z = h((x, y)); + z +} + +const CALL_EXTERNAL_CONSTRUCTORS_IN_LOCAL_VARS: ExternalType = { + let f = Some; + let g = Err; + let h = std::panic::AssertUnwindSafe; + let x = f(5); + let y = g(false); + let z = h((x, y)); + z +}; + +const fn call_external_constructors_in_temps() -> ExternalType { + let x = { Some }(5); + let y = (*&Err)(false); + let z = [std::panic::AssertUnwindSafe][0]((x, y)); + z +} + +const CALL_EXTERNAL_CONSTRUCTORS_IN_TEMPS: ExternalType = { + let x = { Some }(5); + let y = (*&Err)(false); + let z = [std::panic::AssertUnwindSafe][0]((x, y)); + z +}; + +#[derive(Debug, PartialEq)] +enum LocalOption<T> { + Some(T), + _None, +} + +#[derive(Debug, PartialEq)] +enum LocalResult<T, E> { + _Ok(T), + Err(E), +} + +#[derive(Debug, PartialEq)] +struct LocalAssertUnwindSafe<T>(T); + +type LocalType = LocalAssertUnwindSafe<(LocalOption<i32>, LocalResult<i32, bool>)>; + +const fn call_local_constructors_in_local_vars() -> LocalType { + let f = LocalOption::Some; + let g = LocalResult::Err; + let h = LocalAssertUnwindSafe; + let x = f(5); + let y = g(false); + let z = h((x, y)); + z +} + +const CALL_LOCAL_CONSTRUCTORS_IN_LOCAL_VARS: LocalType = { + let f = LocalOption::Some; + let g = LocalResult::Err; + let h = LocalAssertUnwindSafe; + let x = f(5); + let y = g(false); + let z = h((x, y)); + z +}; + +const fn call_local_constructors_in_temps() -> LocalType { + let x = { LocalOption::Some }(5); + let y = (*&LocalResult::Err)(false); + let z = [LocalAssertUnwindSafe][0]((x, y)); + z +} + +const CALL_LOCAL_CONSTRUCTORS_IN_TEMPS: LocalType = { + let x = { LocalOption::Some }(5); + let y = (*&LocalResult::Err)(false); + let z = [LocalAssertUnwindSafe][0]((x, y)); + z +}; + +fn main() { + assert_eq!( + ( + call_external_constructors_in_local_vars().0, + call_external_constructors_in_temps().0, + call_local_constructors_in_local_vars(), + call_local_constructors_in_temps(), + ), + ( + CALL_EXTERNAL_CONSTRUCTORS_IN_LOCAL_VARS.0, + CALL_EXTERNAL_CONSTRUCTORS_IN_TEMPS.0, + CALL_LOCAL_CONSTRUCTORS_IN_LOCAL_VARS, + CALL_LOCAL_CONSTRUCTORS_IN_TEMPS, + ) + ); +} diff --git a/tests/ui/consts/const_constructor/const_constructor_qpath.rs b/tests/ui/consts/const_constructor/const_constructor_qpath.rs new file mode 100644 index 000000000..7c55f470f --- /dev/null +++ b/tests/ui/consts/const_constructor/const_constructor_qpath.rs @@ -0,0 +1,37 @@ +// run-pass + +trait ConstDefault { + const DEFAULT: Self; +} + +#[derive(PartialEq)] +enum E { + V(i32), + W(usize), +} + +impl ConstDefault for E { + const DEFAULT: Self = Self::V(23); +} + +impl ConstDefault for Option<i32> { + const DEFAULT: Self = Self::Some(23); +} + +impl E { + const NON_DEFAULT: Self = Self::W(12); + const fn local_fn() -> Self { + Self::V(23) + } +} + +const fn explicit_qpath() -> E { + let _x = <Option<usize>>::Some(23); + <E>::W(12) +} + +fn main() { + assert!(E::DEFAULT == E::local_fn()); + assert!(Option::DEFAULT == Some(23)); + assert!(E::NON_DEFAULT == explicit_qpath()); +} diff --git a/tests/ui/consts/const_discriminant.rs b/tests/ui/consts/const_discriminant.rs new file mode 100644 index 000000000..79e68590e --- /dev/null +++ b/tests/ui/consts/const_discriminant.rs @@ -0,0 +1,42 @@ +// run-pass +#![feature(const_discriminant)] +#![allow(dead_code)] + +use std::mem::{discriminant, Discriminant}; +use std::hint::black_box; + +enum Test { + A(u8), + B, + C { a: u8, b: u8 }, +} + +const TEST_A: Discriminant<Test> = discriminant(&Test::A(5)); +const TEST_A_OTHER: Discriminant<Test> = discriminant(&Test::A(17)); +const TEST_B: Discriminant<Test> = discriminant(&Test::B); + +enum Void {} + +enum SingleVariant { + V, + Never(Void), +} + +const TEST_V: Discriminant<SingleVariant> = discriminant(&SingleVariant::V); + +pub const TEST_VOID: () = { + // This is UB, but CTFE does not check validity so it does not detect this. + // This is a regression test for https://github.com/rust-lang/rust/issues/89765. + unsafe { std::mem::discriminant(&*(&() as *const () as *const Void)); }; +}; + + +fn main() { + assert_eq!(TEST_A, TEST_A_OTHER); + assert_eq!(TEST_A, discriminant(black_box(&Test::A(17)))); + assert_eq!(TEST_B, discriminant(black_box(&Test::B))); + assert_ne!(TEST_A, TEST_B); + assert_ne!(TEST_B, discriminant(black_box(&Test::C { a: 42, b: 7 }))); + + assert_eq!(TEST_V, discriminant(black_box(&SingleVariant::V))); +} diff --git a/tests/ui/consts/const_fn_floating_point_arithmetic.gated.stderr b/tests/ui/consts/const_fn_floating_point_arithmetic.gated.stderr new file mode 100644 index 000000000..ae24f8f65 --- /dev/null +++ b/tests/ui/consts/const_fn_floating_point_arithmetic.gated.stderr @@ -0,0 +1,8 @@ +error: fatal error triggered by #[rustc_error] + --> $DIR/const_fn_floating_point_arithmetic.rs:20:1 + | +LL | fn main() {} + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/consts/const_fn_floating_point_arithmetic.rs b/tests/ui/consts/const_fn_floating_point_arithmetic.rs new file mode 100644 index 000000000..5e32482b2 --- /dev/null +++ b/tests/ui/consts/const_fn_floating_point_arithmetic.rs @@ -0,0 +1,20 @@ +// gate-test-const_fn_floating_point_arithmetic + +// revisions: stock gated + +#![feature(rustc_attrs)] +#![cfg_attr(gated, feature(const_fn_floating_point_arithmetic))] + +const fn add(f: f32) -> f32 { f + 2.0 } +//[stock]~^ floating point arithmetic +const fn sub(f: f32) -> f32 { 2.0 - f } +//[stock]~^ floating point arithmetic +const fn mul(f: f32, g: f32) -> f32 { f * g } +//[stock]~^ floating point arithmetic +const fn div(f: f32, g: f32) -> f32 { f / g } +//[stock]~^ floating point arithmetic +const fn neg(f: f32) -> f32 { -f } +//[stock]~^ floating point arithmetic + +#[rustc_error] +fn main() {} //[gated]~ fatal error triggered by #[rustc_error] diff --git a/tests/ui/consts/const_fn_floating_point_arithmetic.stock.stderr b/tests/ui/consts/const_fn_floating_point_arithmetic.stock.stderr new file mode 100644 index 000000000..ef7a60faf --- /dev/null +++ b/tests/ui/consts/const_fn_floating_point_arithmetic.stock.stderr @@ -0,0 +1,48 @@ +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:8:31 + | +LL | const fn add(f: f32) -> f32 { f + 2.0 } + | ^^^^^^^ + | + = note: see issue #57241 <https://github.com/rust-lang/rust/issues/57241> for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:10:31 + | +LL | const fn sub(f: f32) -> f32 { 2.0 - f } + | ^^^^^^^ + | + = note: see issue #57241 <https://github.com/rust-lang/rust/issues/57241> for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:12:39 + | +LL | const fn mul(f: f32, g: f32) -> f32 { f * g } + | ^^^^^ + | + = note: see issue #57241 <https://github.com/rust-lang/rust/issues/57241> for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:14:39 + | +LL | const fn div(f: f32, g: f32) -> f32 { f / g } + | ^^^^^ + | + = note: see issue #57241 <https://github.com/rust-lang/rust/issues/57241> for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:16:31 + | +LL | const fn neg(f: f32) -> f32 { -f } + | ^^ + | + = note: see issue #57241 <https://github.com/rust-lang/rust/issues/57241> for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/const_fn_return_nested_fn_ptr.rs b/tests/ui/consts/const_fn_return_nested_fn_ptr.rs new file mode 100644 index 000000000..d22c78960 --- /dev/null +++ b/tests/ui/consts/const_fn_return_nested_fn_ptr.rs @@ -0,0 +1,10 @@ +// build-pass (FIXME(62277): could be check-pass?) +// aux-build:const_fn_lib.rs + +extern crate const_fn_lib; + +fn main() { + const_fn_lib::bar()(); + const_fn_lib::bar_inlined()(); + const_fn_lib::bar_inlined_always()(); +} diff --git a/tests/ui/consts/const_fn_unsize.rs b/tests/ui/consts/const_fn_unsize.rs new file mode 100644 index 000000000..01da57320 --- /dev/null +++ b/tests/ui/consts/const_fn_unsize.rs @@ -0,0 +1,21 @@ +// run-pass +#![feature(slice_ptr_len)] + +use std::ptr::NonNull; + +#[allow(unused)] +const fn test() { + let _x = NonNull::<[i32; 0]>::dangling() as NonNull<[i32]>; +} + +// Regression test for #75118. +pub const fn dangling_slice<T>() -> NonNull<[T]> { + NonNull::<[T; 1]>::dangling() +} + +const C: NonNull<[i32]> = dangling_slice(); + +fn main() { + assert_eq!(C.as_ptr(), NonNull::<[i32; 1]>::dangling().as_ptr() as *mut _); + assert_eq!(C.as_ptr().len(), 1); +} diff --git a/tests/ui/consts/const_forget.rs b/tests/ui/consts/const_forget.rs new file mode 100644 index 000000000..ec7dde8c9 --- /dev/null +++ b/tests/ui/consts/const_forget.rs @@ -0,0 +1,20 @@ +// check-pass + +use std::mem::forget; + +const _: () = forget(0i32); +const _: () = forget(Vec::<Vec<Box<i32>>>::new()); + +// Writing this function signature without const-forget +// triggers compiler errors: +// 1) That we use a non-const fn inside a const fn +// 2) without the forget, it complains about the destructor of Box +// +// FIXME: this method cannot be called in const-eval yet, as Box isn't +// const constructable +#[allow(unused)] +const fn const_forget_box<T: ?Sized>(b: Box<T>) { + forget(b); +} + +fn main() {} diff --git a/tests/ui/consts/const_in_pattern/accept_structural.rs b/tests/ui/consts/const_in_pattern/accept_structural.rs new file mode 100644 index 000000000..1f56f581c --- /dev/null +++ b/tests/ui/consts/const_in_pattern/accept_structural.rs @@ -0,0 +1,66 @@ +// run-pass + +#![warn(indirect_structural_match)] + +// This test is checking our logic for structural match checking by enumerating +// the different kinds of const expressions. This test is collecting cases where +// we have accepted the const expression as a pattern in the past and wish to +// continue doing so. +// +// Even if a non-structural-match type is part of an expression in a const's +// definition, that does not necessarily disqualify the const from being a match +// pattern: in principle, we just need the types involved in the final value to +// be structurally matchable. + +// See also RFC 1445 + +#![feature(type_ascription)] + +#[derive(Copy, Clone, Debug)] +struct NoPartialEq(u32); + +#[derive(Copy, Clone, Debug)] +struct NoDerive(u32); + +// This impl makes `NoDerive` irreflexive. +impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } +impl Eq for NoDerive { } + +type OND = Option<NoDerive>; + +fn main() { + const FIELD1: u32 = NoPartialEq(1).0; + match 1 { FIELD1 => dbg!(FIELD1), _ => panic!("whoops"), }; + const FIELD2: u32 = NoDerive(1).0; + match 1 { FIELD2 => dbg!(FIELD2), _ => panic!("whoops"), }; + + enum CLike { One = 1, #[allow(dead_code)] Two = 2, } + const ONE_CAST: u32 = CLike::One as u32; + match 1 { ONE_CAST => dbg!(ONE_CAST), _ => panic!("whoops"), }; + + const NO_DERIVE_NONE: OND = None; + const INDIRECT: OND = NO_DERIVE_NONE; + match None { INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), }; + + const TUPLE: (OND, OND) = (None, None); + match (None, None) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), }; + + const TYPE_ASCRIPTION: OND = type_ascribe!(None, OND); + match None { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), }; + + const ARRAY: [OND; 2] = [None, None]; + match [None; 2] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), }; + + const REPEAT: [OND; 2] = [None; 2]; + match [None, None] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; + + trait Trait: Sized { const ASSOC: Option<Self>; } + impl Trait for NoDerive { const ASSOC: Option<NoDerive> = None; } + match None { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; + + const BLOCK: OND = { NoDerive(10); None }; + match None { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), }; + + const ADDR_OF: &OND = &None; + match &None { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), }; +} diff --git a/tests/ui/consts/const_in_pattern/auxiliary/consts.rs b/tests/ui/consts/const_in_pattern/auxiliary/consts.rs new file mode 100644 index 000000000..b438bcd9f --- /dev/null +++ b/tests/ui/consts/const_in_pattern/auxiliary/consts.rs @@ -0,0 +1,16 @@ +pub struct CustomEq; + +impl Eq for CustomEq {} +impl PartialEq for CustomEq { + fn eq(&self, _: &Self) -> bool { + false + } +} + +pub const NONE: Option<CustomEq> = None; +pub const SOME: Option<CustomEq> = Some(CustomEq); + +pub trait AssocConst { + const NONE: Option<CustomEq> = None; + const SOME: Option<CustomEq> = Some(CustomEq); +} diff --git a/tests/ui/consts/const_in_pattern/cross-crate-fail.rs b/tests/ui/consts/const_in_pattern/cross-crate-fail.rs new file mode 100644 index 000000000..ab297f54d --- /dev/null +++ b/tests/ui/consts/const_in_pattern/cross-crate-fail.rs @@ -0,0 +1,25 @@ +// aux-build:consts.rs + +#![warn(indirect_structural_match)] + +extern crate consts; + +struct Defaulted; +impl consts::AssocConst for Defaulted {} + +fn main() { + let _ = Defaulted; + match None { + consts::SOME => panic!(), + //~^ must be annotated with `#[derive(PartialEq, Eq)]` + + _ => {} + } + + match None { + <Defaulted as consts::AssocConst>::SOME => panic!(), + //~^ must be annotated with `#[derive(PartialEq, Eq)]` + + _ => {} + } +} diff --git a/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr b/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr new file mode 100644 index 000000000..a8066a88c --- /dev/null +++ b/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr @@ -0,0 +1,14 @@ +error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/cross-crate-fail.rs:13:9 + | +LL | consts::SOME => panic!(), + | ^^^^^^^^^^^^ + +error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/cross-crate-fail.rs:20:9 + | +LL | <Defaulted as consts::AssocConst>::SOME => panic!(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/consts/const_in_pattern/cross-crate-pass.rs b/tests/ui/consts/const_in_pattern/cross-crate-pass.rs new file mode 100644 index 000000000..1d8ecf8ae --- /dev/null +++ b/tests/ui/consts/const_in_pattern/cross-crate-pass.rs @@ -0,0 +1,23 @@ +// run-pass +// aux-build:consts.rs + +#![warn(indirect_structural_match)] + +extern crate consts; +use consts::CustomEq; + +struct Defaulted; +impl consts::AssocConst for Defaulted {} + +fn main() { + let _ = Defaulted; + match Some(CustomEq) { + consts::NONE => panic!(), + _ => {} + } + + match Some(CustomEq) { + <Defaulted as consts::AssocConst>::NONE => panic!(), + _ => {} + } +} diff --git a/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs b/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs new file mode 100644 index 000000000..a38731ceb --- /dev/null +++ b/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs @@ -0,0 +1,32 @@ +// run-pass + +#![warn(indirect_structural_match)] + +struct CustomEq; + +impl Eq for CustomEq {} +impl PartialEq for CustomEq { + fn eq(&self, _: &Self) -> bool { + false + } +} + +#[derive(PartialEq, Eq)] +enum Foo { + Bar, + Baz, + Qux(CustomEq), +} + +const BAR_BAZ: Foo = if 42 == 42 { + Foo::Bar +} else { + Foo::Baz +}; + +fn main() { + match Foo::Qux(CustomEq) { + BAR_BAZ => panic!(), + _ => {} + } +} diff --git a/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs b/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs new file mode 100644 index 000000000..856d20417 --- /dev/null +++ b/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs @@ -0,0 +1,36 @@ +// check-pass + +struct CustomEq; + +impl Eq for CustomEq {} +impl PartialEq for CustomEq { + fn eq(&self, _: &Self) -> bool { + false + } +} + +#[derive(PartialEq, Eq)] +enum Foo { + Bar, + Baz, + Qux(CustomEq), +} + +// We know that `BAR_BAZ` will always be `Foo::Bar` and thus eligible for structural matching, but +// dataflow will be more conservative. +const BAR_BAZ: Foo = if 42 == 42 { + Foo::Bar +} else { + Foo::Qux(CustomEq) +}; + +fn main() { + match Foo::Qux(CustomEq) { + BAR_BAZ => panic!(), + //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~| WARN this was previously accepted + //~| NOTE see issue #73448 + //~| NOTE `#[warn(nontrivial_structural_match)]` on by default + _ => {} + } +} diff --git a/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr b/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr new file mode 100644 index 000000000..223482722 --- /dev/null +++ b/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr @@ -0,0 +1,12 @@ +warning: to use a constant of type `CustomEq` in a pattern, the constant's initializer must be trivial or `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/custom-eq-branch-warn.rs:29:9 + | +LL | BAR_BAZ => panic!(), + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/73448> + = note: `#[warn(nontrivial_structural_match)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/consts/const_in_pattern/incomplete-slice.rs b/tests/ui/consts/const_in_pattern/incomplete-slice.rs new file mode 100644 index 000000000..e1ccda71d --- /dev/null +++ b/tests/ui/consts/const_in_pattern/incomplete-slice.rs @@ -0,0 +1,15 @@ +#[derive(PartialEq)] +enum E { + A, +} + +const E_SL: &[E] = &[E::A]; + +fn main() { + match &[][..] { + //~^ ERROR non-exhaustive patterns: `&_` not covered [E0004] + E_SL => {} + //~^ WARN to use a constant of type `E` in a pattern, `E` must be annotated with `#[derive(PartialEq, Eq)]` + //~| WARN this was previously accepted by the compiler but is being phased out + } +} diff --git a/tests/ui/consts/const_in_pattern/incomplete-slice.stderr b/tests/ui/consts/const_in_pattern/incomplete-slice.stderr new file mode 100644 index 000000000..ddc576ced --- /dev/null +++ b/tests/ui/consts/const_in_pattern/incomplete-slice.stderr @@ -0,0 +1,26 @@ +warning: to use a constant of type `E` in a pattern, `E` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/incomplete-slice.rs:11:9 + | +LL | E_SL => {} + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411> + = note: `#[warn(indirect_structural_match)]` on by default + +error[E0004]: non-exhaustive patterns: `&_` not covered + --> $DIR/incomplete-slice.rs:9:11 + | +LL | match &[][..] { + | ^^^^^^^ pattern `&_` not covered + | + = note: the matched value is of type `&[E]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ E_SL => {} +LL + &_ => todo!() + | + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/consts/const_in_pattern/issue-44333.rs b/tests/ui/consts/const_in_pattern/issue-44333.rs new file mode 100644 index 000000000..96e8795e5 --- /dev/null +++ b/tests/ui/consts/const_in_pattern/issue-44333.rs @@ -0,0 +1,25 @@ +// run-pass + +#![warn(pointer_structural_match)] + +type Func = fn(usize, usize) -> usize; + +fn foo(a: usize, b: usize) -> usize { a + b } +fn bar(a: usize, b: usize) -> usize { a * b } +fn test(x: usize) -> Func { + if x % 2 == 0 { foo } + else { bar } +} + +const FOO: Func = foo; +const BAR: Func = bar; + +fn main() { + match test(std::env::consts::ARCH.len()) { + FOO => println!("foo"), //~ WARN pointers in patterns behave unpredictably + //~^ WARN will become a hard error + BAR => println!("bar"), //~ WARN pointers in patterns behave unpredictably + //~^ WARN will become a hard error + _ => unreachable!(), + } +} diff --git a/tests/ui/consts/const_in_pattern/issue-44333.stderr b/tests/ui/consts/const_in_pattern/issue-44333.stderr new file mode 100644 index 000000000..731ef509c --- /dev/null +++ b/tests/ui/consts/const_in_pattern/issue-44333.stderr @@ -0,0 +1,25 @@ +warning: function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-44333.rs:19:9 + | +LL | FOO => println!("foo"), + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861> +note: the lint level is defined here + --> $DIR/issue-44333.rs:3:9 + | +LL | #![warn(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-44333.rs:21:9 + | +LL | BAR => println!("bar"), + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861> + +warning: 2 warnings emitted + diff --git a/tests/ui/consts/const_in_pattern/issue-53708.rs b/tests/ui/consts/const_in_pattern/issue-53708.rs new file mode 100644 index 000000000..355ba6379 --- /dev/null +++ b/tests/ui/consts/const_in_pattern/issue-53708.rs @@ -0,0 +1,11 @@ +// check-pass +// https://github.com/rust-lang/rust/issues/53708 +#[derive(PartialEq, Eq)] +struct S; + +fn main() { + const C: &S = &S; + match C { + C => {} + } +} diff --git a/tests/ui/consts/const_in_pattern/issue-62614.rs b/tests/ui/consts/const_in_pattern/issue-62614.rs new file mode 100644 index 000000000..4ea9a2836 --- /dev/null +++ b/tests/ui/consts/const_in_pattern/issue-62614.rs @@ -0,0 +1,24 @@ +// run-pass + +struct Sum(u32, u32); + +impl PartialEq for Sum { + fn eq(&self, other: &Self) -> bool { self.0 + self.1 == other.0 + other.1 } +} + +impl Eq for Sum { } + +#[derive(PartialEq, Eq)] +enum Eek { + TheConst, + UnusedByTheConst(Sum) +} + +const THE_CONST: Eek = Eek::TheConst; + +pub fn main() { + match Eek::UnusedByTheConst(Sum(1,2)) { + THE_CONST => { panic!(); } + _ => {} + } +} diff --git a/tests/ui/consts/const_in_pattern/issue-65466.rs b/tests/ui/consts/const_in_pattern/issue-65466.rs new file mode 100644 index 000000000..2b421f4c7 --- /dev/null +++ b/tests/ui/consts/const_in_pattern/issue-65466.rs @@ -0,0 +1,21 @@ +#![deny(indirect_structural_match)] + +// check-pass + +#[derive(PartialEq, Eq)] +enum O<T> { + Some(*const T), // Can also use PhantomData<T> + None, +} + +struct B; + +const C: &[O<B>] = &[O::None]; + +fn main() { + let x = O::None; + match &[x][..] { + C => (), + _ => (), + } +} diff --git a/tests/ui/consts/const_in_pattern/issue-73431.rs b/tests/ui/consts/const_in_pattern/issue-73431.rs new file mode 100644 index 000000000..fa18a3af1 --- /dev/null +++ b/tests/ui/consts/const_in_pattern/issue-73431.rs @@ -0,0 +1,29 @@ +// run-pass + +// Regression test for https://github.com/rust-lang/rust/issues/73431. + +pub trait Zero { + const ZERO: Self; +} + +impl Zero for usize { + const ZERO: Self = 0; +} + +impl<T: Zero> Zero for Wrapper<T> { + const ZERO: Self = Wrapper(T::ZERO); +} + +#[derive(Debug, PartialEq, Eq)] +pub struct Wrapper<T>(T); + +fn is_zero(x: Wrapper<usize>) -> bool { + match x { + Zero::ZERO => true, + _ => false, + } +} + +fn main() { + let _ = is_zero(Wrapper(42)); +} diff --git a/tests/ui/consts/const_in_pattern/issue-73431.stderr b/tests/ui/consts/const_in_pattern/issue-73431.stderr new file mode 100644 index 000000000..c82dea4aa --- /dev/null +++ b/tests/ui/consts/const_in_pattern/issue-73431.stderr @@ -0,0 +1 @@ +WARN rustc_mir_build::thir::pattern::const_to_pat MIR const-checker found novel structural match violation. See #73448. diff --git a/tests/ui/consts/const_in_pattern/issue-78057.rs b/tests/ui/consts/const_in_pattern/issue-78057.rs new file mode 100644 index 000000000..69cf8404d --- /dev/null +++ b/tests/ui/consts/const_in_pattern/issue-78057.rs @@ -0,0 +1,17 @@ +#![deny(unreachable_patterns)] + +#[derive(PartialEq)] +struct Opaque(i32); + +impl Eq for Opaque {} + +const FOO: Opaque = Opaque(42); + +fn main() { + match FOO { + FOO => {}, + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + _ => {} + //~^ ERROR unreachable pattern + } +} diff --git a/tests/ui/consts/const_in_pattern/issue-78057.stderr b/tests/ui/consts/const_in_pattern/issue-78057.stderr new file mode 100644 index 000000000..35619594f --- /dev/null +++ b/tests/ui/consts/const_in_pattern/issue-78057.stderr @@ -0,0 +1,23 @@ +error: to use a constant of type `Opaque` in a pattern, `Opaque` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/issue-78057.rs:12:9 + | +LL | FOO => {}, + | ^^^ + +error: unreachable pattern + --> $DIR/issue-78057.rs:14:9 + | +LL | FOO => {}, + | --- matches any value +LL | +LL | _ => {} + | ^ unreachable pattern + | +note: the lint level is defined here + --> $DIR/issue-78057.rs:1:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/consts/const_in_pattern/no-eq-branch-fail.rs b/tests/ui/consts/const_in_pattern/no-eq-branch-fail.rs new file mode 100644 index 000000000..fc80d51c7 --- /dev/null +++ b/tests/ui/consts/const_in_pattern/no-eq-branch-fail.rs @@ -0,0 +1,25 @@ +#![warn(indirect_structural_match)] + +struct NoEq; + +enum Foo { + Bar, + Baz, + Qux(NoEq), +} + +// Even though any of these values can be compared structurally, we still disallow it in a pattern +// because `Foo` does not impl `PartialEq`. +const BAR_BAZ: Foo = if 42 == 42 { + Foo::Baz +} else { + Foo::Bar +}; + +fn main() { + match Foo::Qux(NoEq) { + BAR_BAZ => panic!(), + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + _ => {} + } +} diff --git a/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr b/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr new file mode 100644 index 000000000..e505dad69 --- /dev/null +++ b/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr @@ -0,0 +1,8 @@ +error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/no-eq-branch-fail.rs:21:9 + | +LL | BAR_BAZ => panic!(), + | ^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs new file mode 100644 index 000000000..a8216901c --- /dev/null +++ b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs @@ -0,0 +1,32 @@ +// This test is illustrating the difference between how failing to derive +// `PartialEq` is handled compared to failing to implement it at all. + +// See also RFC 1445 + +#[derive(PartialEq, Eq)] +struct Structural(u32); + +struct NoPartialEq(u32); + +struct NoDerive(u32); + +// This impl makes NoDerive irreflexive. +impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + +impl Eq for NoDerive { } + +const NO_DERIVE_NONE: Option<NoDerive> = None; +const NO_PARTIAL_EQ_NONE: Option<NoPartialEq> = None; + +fn main() { + match None { + NO_DERIVE_NONE => println!("NO_DERIVE_NONE"), + _ => panic!("whoops"), + } + + match None { + NO_PARTIAL_EQ_NONE => println!("NO_PARTIAL_EQ_NONE"), + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + _ => panic!("whoops"), + } +} diff --git a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr new file mode 100644 index 000000000..95cfa4a9e --- /dev/null +++ b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr @@ -0,0 +1,8 @@ +error: to use a constant of type `NoPartialEq` in a pattern, `NoPartialEq` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/reject_non_partial_eq.rs:28:9 + | +LL | NO_PARTIAL_EQ_NONE => println!("NO_PARTIAL_EQ_NONE"), + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.rs b/tests/ui/consts/const_in_pattern/reject_non_structural.rs new file mode 100644 index 000000000..75fde0d92 --- /dev/null +++ b/tests/ui/consts/const_in_pattern/reject_non_structural.rs @@ -0,0 +1,83 @@ +// This test of structural match checking enumerates the different kinds of +// const definitions, collecting cases where the const pattern is rejected. +// +// Note: Even if a non-structural-match type is part of an expression in a +// const's definition, that does not necessarily disqualify the const from being +// a match pattern: in principle, we just need the types involved in the final +// value to be structurally matchable. + +// See also RFC 1445 + +#![feature(type_ascription)] +#![warn(indirect_structural_match)] +//~^ NOTE lint level is defined here + +#[derive(Copy, Clone, Debug)] +struct NoPartialEq; + +#[derive(Copy, Clone, Debug)] +struct NoDerive; + +// This impl makes `NoDerive` irreflexive. +impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + +impl Eq for NoDerive { } + +type OND = Option<NoDerive>; + +struct TrivialEq(OND); + +// This impl makes `TrivialEq` trivial. +impl PartialEq for TrivialEq { fn eq(&self, _: &Self) -> bool { true } } + +impl Eq for TrivialEq { } + +fn main() { + #[derive(PartialEq, Eq, Debug)] + enum Derive<X> { Some(X), None, } + + const ENUM: Derive<NoDerive> = Derive::Some(NoDerive); + match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"), }; + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + + const FIELD: OND = TrivialEq(Some(NoDerive)).0; + match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), }; + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + + const NO_DERIVE_SOME: OND = Some(NoDerive); + const INDIRECT: OND = NO_DERIVE_SOME; + match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), }; + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + + const TUPLE: (OND, OND) = (None, Some(NoDerive)); + match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), }; + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + + const TYPE_ASCRIPTION: OND = type_ascribe!(Some(NoDerive), OND); + match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), }; + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + + const ARRAY: [OND; 2] = [None, Some(NoDerive)]; + match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), }; + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + + const REPEAT: [OND; 2] = [Some(NoDerive); 2]; + match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` + + trait Trait: Sized { const ASSOC: Option<Self>; } + impl Trait for NoDerive { const ASSOC: Option<NoDerive> = Some(NoDerive); } + match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + + const BLOCK: OND = { NoDerive; Some(NoDerive) }; + match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), }; + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + + const ADDR_OF: &OND = &Some(NoDerive); + match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), }; + //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~| WARN previously accepted by the compiler but is being phased out + //~| NOTE for more information, see issue #62411 +} diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr new file mode 100644 index 000000000..660198349 --- /dev/null +++ b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr @@ -0,0 +1,76 @@ +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/reject_non_structural.rs:40:36 + | +LL | match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"), }; + | ^^^^ + +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/reject_non_structural.rs:44:28 + | +LL | match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), }; + | ^^^^^ + +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/reject_non_structural.rs:49:27 + | +LL | match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), }; + | ^^^^^^^^ + +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/reject_non_structural.rs:53:36 + | +LL | match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), }; + | ^^^^^ + +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/reject_non_structural.rs:57:28 + | +LL | match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), }; + | ^^^^^^^^^^^^^^^ + +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/reject_non_structural.rs:61:36 + | +LL | match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), }; + | ^^^^^ + +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/reject_non_structural.rs:65:33 + | +LL | match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; + | ^^^^^^ + +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/reject_non_structural.rs:65:33 + | +LL | match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; + | ^^^^^^ + +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/reject_non_structural.rs:71:28 + | +LL | match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; + | ^^^^^^^^^^^^^^^ + +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/reject_non_structural.rs:75:28 + | +LL | match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), }; + | ^^^^^ + +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/reject_non_structural.rs:79:29 + | +LL | match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), }; + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411> +note: the lint level is defined here + --> $DIR/reject_non_structural.rs:12:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 10 previous errors; 1 warning emitted + diff --git a/tests/ui/consts/const_in_pattern/warn_corner_cases.rs b/tests/ui/consts/const_in_pattern/warn_corner_cases.rs new file mode 100644 index 000000000..15cf3c84d --- /dev/null +++ b/tests/ui/consts/const_in_pattern/warn_corner_cases.rs @@ -0,0 +1,41 @@ +// run-pass + +// This test is checking our logic for structural match checking by enumerating +// the different kinds of const expressions. This test is collecting cases where +// we have accepted the const expression as a pattern in the past but we want +// to begin warning the user that a future version of Rust may start rejecting +// such const expressions. + +// The specific corner cases we are exploring here are instances where the +// const-evaluator computes a value that *does* meet the conditions for +// structural-match, but the const expression itself has abstractions (like +// calls to const functions) that may fit better with a type-based analysis +// rather than a commitment to a specific value. + +#![warn(indirect_structural_match)] + +#[derive(Copy, Clone, Debug)] +struct NoDerive(#[allow(unused_tuple_struct_fields)] u32); + +// This impl makes `NoDerive` irreflexive. +impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } +impl Eq for NoDerive { } + +fn main() { + const INDEX: Option<NoDerive> = [None, Some(NoDerive(10))][0]; + match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), }; + //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~| WARN this was previously accepted + + const fn build() -> Option<NoDerive> { None } + const CALL: Option<NoDerive> = build(); + match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), }; + //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~| WARN this was previously accepted + + impl NoDerive { const fn none() -> Option<NoDerive> { None } } + const METHOD_CALL: Option<NoDerive> = NoDerive::none(); + match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CALL), }; + //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~| WARN this was previously accepted +} diff --git a/tests/ui/consts/const_in_pattern/warn_corner_cases.stderr b/tests/ui/consts/const_in_pattern/warn_corner_cases.stderr new file mode 100644 index 000000000..e957a43a1 --- /dev/null +++ b/tests/ui/consts/const_in_pattern/warn_corner_cases.stderr @@ -0,0 +1,30 @@ +warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/warn_corner_cases.rs:26:47 + | +LL | match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), }; + | ^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/73448> + = note: `#[warn(nontrivial_structural_match)]` on by default + +warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/warn_corner_cases.rs:32:47 + | +LL | match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), }; + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/73448> + +warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/warn_corner_cases.rs:38:47 + | +LL | match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CALL), }; + | ^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/73448> + +warning: 3 warnings emitted + diff --git a/tests/ui/consts/const_let_assign.rs b/tests/ui/consts/const_let_assign.rs new file mode 100644 index 000000000..b83acfb73 --- /dev/null +++ b/tests/ui/consts/const_let_assign.rs @@ -0,0 +1,10 @@ +// check-pass + +struct S(i32); + +const A: () = { + let mut s = S(0); + s.0 = 1; +}; + +fn main() {} diff --git a/tests/ui/consts/const_let_assign2.rs b/tests/ui/consts/const_let_assign2.rs new file mode 100644 index 000000000..28265c85d --- /dev/null +++ b/tests/ui/consts/const_let_assign2.rs @@ -0,0 +1,22 @@ +// check-pass + +pub struct AA { + pub data: [u8; 10], +} + +impl AA { + pub const fn new() -> Self { + let mut res: AA = AA { data: [0; 10] }; + res.data[0] = 5; + res + } +} + +static mut BB: AA = AA::new(); + +fn main() { + let ptr = unsafe { &mut BB }; + for a in ptr.data.iter() { + println!("{}", a); + } +} diff --git a/tests/ui/consts/const_let_assign3.rs b/tests/ui/consts/const_let_assign3.rs new file mode 100644 index 000000000..1f68de8ee --- /dev/null +++ b/tests/ui/consts/const_let_assign3.rs @@ -0,0 +1,27 @@ +struct S { + state: u32, +} + +impl S { + const fn foo(&mut self, x: u32) { + //~^ ERROR mutable reference + self.state = x; + } +} + +const FOO: S = { + let mut s = S { state: 42 }; + s.foo(3); //~ ERROR mutable reference + s +}; + +type Array = [u32; { + let mut x = 2; + let y = &mut x; //~ ERROR mutable reference + *y = 42; + *y +}]; + +fn main() { + assert_eq!(FOO.state, 3); +} diff --git a/tests/ui/consts/const_let_assign3.stderr b/tests/ui/consts/const_let_assign3.stderr new file mode 100644 index 000000000..b550ac545 --- /dev/null +++ b/tests/ui/consts/const_let_assign3.stderr @@ -0,0 +1,30 @@ +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/const_let_assign3.rs:6:18 + | +LL | const fn foo(&mut self, x: u32) { + | ^^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constants + --> $DIR/const_let_assign3.rs:14:5 + | +LL | s.foo(3); + | ^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constants + --> $DIR/const_let_assign3.rs:20:13 + | +LL | let y = &mut x; + | ^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/const_let_eq.rs b/tests/ui/consts/const_let_eq.rs new file mode 100644 index 000000000..818819f9f --- /dev/null +++ b/tests/ui/consts/const_let_eq.rs @@ -0,0 +1,469 @@ +// run-pass + +struct Foo<T>(T); +struct Bar<T> { x: T } +struct W(u32); +struct A { a: u32 } + +#[allow(redundant_semicolons)] +const fn basics((a,): (u32,)) -> u32 { + // Deferred assignment: + let b: u32; + b = a + 1; + + // Immediate assignment: + let c: u32 = b + 1; + + // Mutables: + let mut d: u32 = c + 1; + d = d + 1; + // +4 so far. + + // No effect statements work: + ; ; + 1; + + // Array projection + let mut arr: [u32; 1] = [0]; + arr[0] = 1; + d = d + arr[0]; + // +5 + + // Field projection: + let mut foo: Foo<u32> = Foo(0); + let mut bar: Bar<u32> = Bar { x: 0 }; + foo.0 = 1; + bar.x = 1; + d = d + foo.0 + bar.x; + // +7 + + // Array + Field projection: + let mut arr: [Foo<u32>; 1] = [Foo(0)]; + arr[0].0 = 1; + d = d + arr[0].0; + let mut arr: [Bar<u32>; 1] = [Bar { x: 0 }]; + arr[0].x = 1; + d = d + arr[0].x; + // +9 + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([0]); + (arr.0)[0] = 1; + d = d + (arr.0)[0]; + let mut arr: Bar<[u32; 1]> = Bar { x: [0] }; + arr.x[0] = 1; + d = d + arr.x[0]; + // +11 + + d +} + +const fn add_assign(W(a): W) -> u32 { + // Mutables: + let mut d: u32 = a + 1; + d += 1; + // +2 so far. + + // Array projection + let mut arr: [u32; 1] = [0]; + arr[0] += 1; + d += arr[0]; + // +3 + + // Field projection: + let mut foo: Foo<u32> = Foo(0); + let mut bar: Bar<u32> = Bar { x: 0 }; + foo.0 += 1; + bar.x += 1; + d += foo.0 + bar.x; + // +5 + + // Array + Field projection: + let mut arr: [Foo<u32>; 1] = [Foo(0)]; + arr[0].0 += 1; + d += arr[0].0; + let mut arr: [Bar<u32>; 1] = [Bar { x: 0 }]; + arr[0].x += 1; + d += arr[0].x; + // +7 + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([0]); + (arr.0)[0] += 1; + d += (arr.0)[0]; + let mut arr: Bar<[u32; 1]> = Bar { x: [0] }; + arr.x[0] += 1; + d += arr.x[0]; + // +9 + + d +} + +const fn mul_assign(A { a }: A) -> u32 { + // Mutables: + let mut d: u32 = a + 1; + d *= 2; + // 2^1 * (a + 1) + + // Array projection + let mut arr: [u32; 1] = [1]; + arr[0] *= 2; + d *= arr[0]; + // 2^2 * (a + 1) + + // Field projection: + let mut foo: Foo<u32> = Foo(1); + let mut bar: Bar<u32> = Bar { x: 1 }; + foo.0 *= 2; + bar.x *= 2; + d *= foo.0 + bar.x; + // 2^4 * (a + 1) + + // Array + Field projection: + let mut arr: [Foo<u32>; 1] = [Foo(1)]; + arr[0].0 *= 2; + d *= arr[0].0; + let mut arr: [Bar<u32>; 1] = [Bar { x: 1 }]; + arr[0].x *= 2; + d *= arr[0].x; + // 2^6 * (a + 1) + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([1]); + (arr.0)[0] *= 2; + d *= (arr.0)[0]; + let mut arr: Bar<[u32; 1]> = Bar { x: [1] }; + arr.x[0] *= 2; + d *= arr.x[0]; + // 2^8 * (a + 1) + + d +} + +const fn div_assign(a: [u32; 1]) -> u32 { + let a = a[0]; + // Mutables: + let mut d: u32 = 1024 * a; + d /= 2; + // 512 + + // Array projection + let mut arr: [u32; 1] = [4]; + arr[0] /= 2; + d /= arr[0]; + // 256 + + // Field projection: + let mut foo: Foo<u32> = Foo(4); + let mut bar: Bar<u32> = Bar { x: 4 }; + foo.0 /= 2; + bar.x /= 2; + d /= foo.0; + d /= bar.x; + // 64 + + // Array + Field projection: + let mut arr: [Foo<u32>; 1] = [Foo(4)]; + arr[0].0 /= 2; + d /= arr[0].0; + let mut arr: [Bar<u32>; 1] = [Bar { x: 4 }]; + arr[0].x /= 2; + d /= arr[0].x; + // 16 + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([4]); + (arr.0)[0] /= 2; + d /= (arr.0)[0]; + let mut arr: Bar<[u32; 1]> = Bar { x: [4] }; + arr.x[0] /= 2; + d /= arr.x[0]; + // 4 + + d +} + +const fn rem_assign(W(a): W) -> u32 { + // Mutables: + let mut d: u32 = a; + d %= 10; + d += 10; + + // Array projection + let mut arr: [u32; 1] = [3]; + arr[0] %= 2; + d %= 9 + arr[0]; + d += 10; + + // Field projection: + let mut foo: Foo<u32> = Foo(5); + let mut bar: Bar<u32> = Bar { x: 7 }; + foo.0 %= 2; + bar.x %= 2; + d %= 8 + foo.0 + bar.x; + d += 10; + + // Array + Field projection: + let mut arr: [Foo<u32>; 1] = [Foo(4)]; + arr[0].0 %= 3; + d %= 9 + arr[0].0; + d += 10; + let mut arr: [Bar<u32>; 1] = [Bar { x: 7 }]; + arr[0].x %= 3; + d %= 9 + arr[0].x; + d += 10; + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([6]); + (arr.0)[0] %= 5; + d %= 9 + (arr.0)[0]; + let mut arr: Bar<[u32; 1]> = Bar { x: [11] }; + arr.x[0] %= 5; + d %= 9 + arr.x[0]; + + d +} + +const fn sub_assign(W(a): W) -> u32 { + // Mutables: + let mut d: u32 = a; + d -= 1; + + // Array projection + let mut arr: [u32; 1] = [2]; + arr[0] -= 1; + d -= arr[0]; + + // Field projection: + let mut foo: Foo<u32> = Foo(2); + let mut bar: Bar<u32> = Bar { x: 2 }; + foo.0 -= 1; + bar.x -= 1; + d -= foo.0 + bar.x; + + // Array + Field projection: + let mut arr: [Foo<u32>; 1] = [Foo(2)]; + arr[0].0 -= 1; + d -= arr[0].0; + let mut arr: [Bar<u32>; 1] = [Bar { x: 2 }]; + arr[0].x -= 1; + d -= arr[0].x; + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([2]); + (arr.0)[0] -= 1; + d -= (arr.0)[0]; + let mut arr: Bar<[u32; 1]> = Bar { x: [2] }; + arr.x[0] -= 1; + d -= arr.x[0]; + + d +} + +const fn shl_assign(W(a): W) -> u32 { + // Mutables: + let mut d: u32 = a; + d <<= 1; // 10 + + // Array projection + let mut arr: [u32; 1] = [1]; + arr[0] <<= 1; + d <<= arr[0]; // 10 << 2 + + // Field projection: + let mut foo: Foo<u32> = Foo(1); + let mut bar: Bar<u32> = Bar { x: 1 }; + foo.0 <<= 1; + bar.x <<= 1; + d <<= foo.0 + bar.x; // 1000 << 4 + + // Array + Field projection: + let mut arr: [Foo<u32>; 1] = [Foo(1)]; + arr[0].0 <<= 1; + d <<= arr[0].0; // 1000_0000 << 2 + let mut arr: [Bar<u32>; 1] = [Bar { x: 1 }]; + arr[0].x <<= 1; + d <<= arr[0].x; // 1000_0000_00 << 2 + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([1]); + (arr.0)[0] <<= 1; + d <<= (arr.0)[0]; // 1000_0000_0000 << 2 + let mut arr: Bar<[u32; 1]> = Bar { x: [1] }; + arr.x[0] <<= 1; + d <<= arr.x[0]; // 1000_0000_0000_00 << 2 + + d +} + +const fn shr_assign(W(a): W) -> u32 { + // Mutables: + let mut d: u32 = a; + d >>= 1; // /= 2 + + // Array projection + let mut arr: [u32; 1] = [2]; + arr[0] >>= 1; + d >>= arr[0]; // /= 4 + + // Field projection: + let mut foo: Foo<u32> = Foo(2); + let mut bar: Bar<u32> = Bar { x: 2 }; + foo.0 >>= 1; + bar.x >>= 1; + d >>= foo.0 + bar.x; // /= 16 + + // Array + Field projection: + let mut arr: [Foo<u32>; 1] = [Foo(2)]; + arr[0].0 >>= 1; + d >>= arr[0].0; // /= 32 + let mut arr: [Bar<u32>; 1] = [Bar { x: 2 }]; + arr[0].x >>= 1; + d >>= arr[0].x; // /= 64 + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([2]); + (arr.0)[0] >>= 1; + d >>= (arr.0)[0]; // /= 128 + let mut arr: Bar<[u32; 1]> = Bar { x: [2] }; + arr.x[0] >>= 1; + d >>= arr.x[0]; // /= 256 + + d +} + +const fn bit_and_assign(W(a): W) -> u32 { + let f = 0b1111_1111_1111_1111; + + // Mutables: + let mut d: u32 = a; + d &= 0b1111_1111_1111_1110; + + // Array projection + let mut arr: [u32; 1] = [f]; + arr[0] &= 0b1111_1111_1111_1101; + d &= arr[0]; + + // Field projection: + let mut foo: Foo<u32> = Foo(f); + let mut bar: Bar<u32> = Bar { x: f }; + foo.0 &= 0b1111_1111_1111_0111; + bar.x &= 0b1111_1111_1101_1111; + d &= foo.0 & bar.x; + + // Array + Field projection: + let mut arr: [Foo<u32>; 1] = [Foo(f)]; + arr[0].0 &= 0b1111_1110_1111_1111; + d &= arr[0].0; + let mut arr: [Bar<u32>; 1] = [Bar { x: f }]; + arr[0].x &= 0b1111_1101_1111_1111; + d &= arr[0].x; + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([f]); + (arr.0)[0] &= 0b1011_1111_1111_1111; + d &= (arr.0)[0]; + let mut arr: Bar<[u32; 1]> = Bar { x: [f] }; + arr.x[0] &= 0b0111_1111_1111_1111; + d &= arr.x[0]; + + d +} + +const fn bit_or_assign(W(a): W) -> u32 { + let f = 0b0000_0000_0000_0000; + + // Mutables: + let mut d: u32 = a; + d |= 0b0000_0000_0000_0001; + + // Array projection + let mut arr: [u32; 1] = [f]; + arr[0] |= 0b0000_0000_0000_1001; + d |= arr[0]; + + // Field projection: + let mut foo: Foo<u32> = Foo(f); + let mut bar: Bar<u32> = Bar { x: f }; + foo.0 |= 0b0000_0000_0001_0000; + bar.x |= 0b0000_0000_0100_0000; + d |= foo.0 | bar.x; + + // Array + Field projection: + let mut arr: [Foo<u32>; 1] = [Foo(f)]; + arr[0].0 |= 0b0000_0001_0000_0000; + d |= arr[0].0; + let mut arr: [Bar<u32>; 1] = [Bar { x: f }]; + arr[0].x |= 0b0000_0010_0000_0000; + d |= arr[0].x; + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([f]); + (arr.0)[0] |= 0b1000_0000_0000_0000; + d |= (arr.0)[0]; // /= 128 + let mut arr: Bar<[u32; 1]> = Bar { x: [f] }; + arr.x[0] |= 0b1100_0000_0000_0000; + d |= arr.x[0]; // /= 256 + + d +} + +const fn bit_xor_assign(W(a): W) -> u32 { + let f = 0b0000_0000_0000_0000; + + // Mutables: + let mut d: u32 = a; + d ^= 0b0000_0000_0000_0001; + + // Array projection + let mut arr: [u32; 1] = [f]; + arr[0] ^= 0b0000_0000_0000_0010; + d ^= arr[0]; + + // Field projection: + let mut foo: Foo<u32> = Foo(f); + let mut bar: Bar<u32> = Bar { x: f }; + foo.0 ^= 0b0000_0000_0001_0000; + bar.x ^= 0b0000_0000_1000_0000; + d ^= foo.0 ^ bar.x; + + // Array + Field projection: + let mut arr: [Foo<u32>; 1] = [Foo(f)]; + arr[0].0 ^= 0b0000_0001_0000_0000; + d ^= arr[0].0; + let mut arr: [Bar<u32>; 1] = [Bar { x: f }]; + arr[0].x ^= 0b0000_0010_0000_0000; + d ^= arr[0].x; + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([f]); + (arr.0)[0] ^= 0b0100_0000_0000_0000; + d ^= (arr.0)[0]; + let mut arr: Bar<[u32; 1]> = Bar { x: [f] }; + arr.x[0] ^= 0b1000_0000_0000_0000; + d ^= arr.x[0]; + + d +} + +macro_rules! test { + ($c:ident, $e:expr, $r:expr) => { + const $c: u32 = $e; + assert_eq!($c, $r); + assert_eq!($e, $r); + } +} + +fn main() { + test!(BASICS, basics((2,)), 13); + test!(ADD, add_assign(W(1)), 10); + test!(MUL, mul_assign(A { a: 0 }), 256); + test!(DIV, div_assign([1]), 4); + test!(REM, rem_assign(W(5)), 5); + test!(SUB, sub_assign(W(8)), 0); + test!(SHL, shl_assign(W(1)), 0b1000_0000_0000_0000); + test!(SHR, shr_assign(W(256)), 1); + test!(AND, bit_and_assign(W(0b1011_1111_1111_1111_1111)), 0b0011_1100_1101_0100); + test!(OR, bit_or_assign(W(0b1011_0000_0000_0000)), 0b1111_0011_0101_1001); + test!(XOR, bit_xor_assign(W(0b0000_0000_0000_0000)), 0b1100_0011_1001_0011); +} diff --git a/tests/ui/consts/const_let_eq_float.rs b/tests/ui/consts/const_let_eq_float.rs new file mode 100644 index 000000000..e15f4b804 --- /dev/null +++ b/tests/ui/consts/const_let_eq_float.rs @@ -0,0 +1,280 @@ +// run-pass + +#![feature(const_fn_floating_point_arithmetic)] + +struct Foo<T>(T); +struct Bar<T> { x: T } +struct W(f32); +struct A { a: f32 } + +#[allow(redundant_semicolons)] +const fn basics((a,): (f32,)) -> f32 { + // Deferred assignment: + let b: f32; + b = a + 1.0; + + // Immediate assignment: + let c: f32 = b + 1.0; + + // Mutables: + let mut d: f32 = c + 1.0; + d = d + 1.0; + // +4 so far. + + // No effect statements work: + ; ; + 1; + + // Array projection + let mut arr: [f32; 1] = [0.0]; + arr[0] = 1.0; + d = d + arr[0]; + // +5 + + // Field projection: + let mut foo: Foo<f32> = Foo(0.0); + let mut bar: Bar<f32> = Bar { x: 0.0 }; + foo.0 = 1.0; + bar.x = 1.0; + d = d + foo.0 + bar.x; + // +7 + + // Array + Field projection: + let mut arr: [Foo<f32>; 1] = [Foo(0.0)]; + arr[0].0 = 1.0; + d = d + arr[0].0; + let mut arr: [Bar<f32>; 1] = [Bar { x: 0.0 }]; + arr[0].x = 1.0; + d = d + arr[0].x; + // +9 + + // Field + Array projection: + let mut arr: Foo<[f32; 1]> = Foo([0.0]); + (arr.0)[0] = 1.0; + d = d + (arr.0)[0]; + let mut arr: Bar<[f32; 1]> = Bar { x: [0.0] }; + arr.x[0] = 1.0; + d = d + arr.x[0]; + // +11 + + d +} + +const fn add_assign(W(a): W) -> f32 { + // Mutables: + let mut d: f32 = a + 1.0; + d += 1.0; + // +2 so far. + + // Array projection + let mut arr: [f32; 1] = [0.0]; + arr[0] += 1.0; + d += arr[0]; + // +3 + + // Field projection: + let mut foo: Foo<f32> = Foo(0.0); + let mut bar: Bar<f32> = Bar { x: 0.0 }; + foo.0 += 1.0; + bar.x += 1.0; + d += foo.0 + bar.x; + // +5 + + // Array + Field projection: + let mut arr: [Foo<f32>; 1] = [Foo(0.0)]; + arr[0].0 += 1.0; + d += arr[0].0; + let mut arr: [Bar<f32>; 1] = [Bar { x: 0.0 }]; + arr[0].x += 1.0; + d += arr[0].x; + // +7 + + // Field + Array projection: + let mut arr: Foo<[f32; 1]> = Foo([0.0]); + (arr.0)[0] += 1.0; + d += (arr.0)[0]; + let mut arr: Bar<[f32; 1]> = Bar { x: [0.0] }; + arr.x[0] += 1.0; + d += arr.x[0]; + // +9 + + d +} + +const fn mul_assign(A { a }: A) -> f32 { + // Mutables: + let mut d: f32 = a + 1.0; + d *= 2.0; + // 2^1 * (a + 1) + + // Array projection + let mut arr: [f32; 1] = [1.0]; + arr[0] *= 2.0; + d *= arr[0]; + // 2^2 * (a + 1) + + // Field projection: + let mut foo: Foo<f32> = Foo(1.0); + let mut bar: Bar<f32> = Bar { x: 1.0 }; + foo.0 *= 2.0; + bar.x *= 2.0; + d *= foo.0 + bar.x; + // 2^4 * (a + 1) + + // Array + Field projection: + let mut arr: [Foo<f32>; 1] = [Foo(1.0)]; + arr[0].0 *= 2.0; + d *= arr[0].0; + let mut arr: [Bar<f32>; 1] = [Bar { x: 1.0 }]; + arr[0].x *= 2.0; + d *= arr[0].x; + // 2^6 * (a + 1) + + // Field + Array projection: + let mut arr: Foo<[f32; 1]> = Foo([1.0]); + (arr.0)[0] *= 2.0; + d *= (arr.0)[0]; + let mut arr: Bar<[f32; 1]> = Bar { x: [1.0] }; + arr.x[0] *= 2.0; + d *= arr.x[0]; + // 2^8 * (a + 1) + + d +} + +const fn div_assign(a: [f32; 1]) -> f32 { + let a = a[0]; + // Mutables: + let mut d: f32 = 1024.0 * a; + d /= 2.0; + // 512 + + // Array projection + let mut arr: [f32; 1] = [4.0]; + arr[0] /= 2.0; + d /= arr[0]; + // 256 + + // Field projection: + let mut foo: Foo<f32> = Foo(4.0); + let mut bar: Bar<f32> = Bar { x: 4.0 }; + foo.0 /= 2.0; + bar.x /= 2.0; + d /= foo.0; + d /= bar.x; + // 64 + + // Array + Field projection: + let mut arr: [Foo<f32>; 1] = [Foo(4.0)]; + arr[0].0 /= 2.0; + d /= arr[0].0; + let mut arr: [Bar<f32>; 1] = [Bar { x: 4.0 }]; + arr[0].x /= 2.0; + d /= arr[0].x; + // 16 + + // Field + Array projection: + let mut arr: Foo<[f32; 1]> = Foo([4.0]); + (arr.0)[0] /= 2.0; + d /= (arr.0)[0]; + let mut arr: Bar<[f32; 1]> = Bar { x: [4.0] }; + arr.x[0] /= 2.0; + d /= arr.x[0]; + // 4 + + d +} + +const fn rem_assign(W(a): W) -> f32 { + // Mutables: + let mut d: f32 = a; + d %= 10.0; + d += 10.0; + + // Array projection + let mut arr: [f32; 1] = [3.0]; + arr[0] %= 2.0; + d %= 9.0 + arr[0]; + d += 10.0; + + // Field projection: + let mut foo: Foo<f32> = Foo(5.0); + let mut bar: Bar<f32> = Bar { x: 7.0 }; + foo.0 %= 2.0; + bar.x %= 2.0; + d %= 8.0 + foo.0 + bar.x; + d += 10.0; + + // Array + Field projection: + let mut arr: [Foo<f32>; 1] = [Foo(4.0)]; + arr[0].0 %= 3.0; + d %= 9.0 + arr[0].0; + d += 10.0; + let mut arr: [Bar<f32>; 1] = [Bar { x: 7.0 }]; + arr[0].x %= 3.0; + d %= 9.0 + arr[0].x; + d += 10.0; + + // Field + Array projection: + let mut arr: Foo<[f32; 1]> = Foo([6.0]); + (arr.0)[0] %= 5.0; + d %= 9.0 + (arr.0)[0]; + let mut arr: Bar<[f32; 1]> = Bar { x: [11.0] }; + arr.x[0] %= 5.0; + d %= 9.0 + arr.x[0]; + + d +} + +const fn sub_assign(W(a): W) -> f32 { + // Mutables: + let mut d: f32 = a; + d -= 1.0; + + // Array projection + let mut arr: [f32; 1] = [2.0]; + arr[0] -= 1.0; + d -= arr[0]; + + // Field projection: + let mut foo: Foo<f32> = Foo(2.0); + let mut bar: Bar<f32> = Bar { x: 2.0 }; + foo.0 -= 1.0; + bar.x -= 1.0; + d -= foo.0 + bar.x; + + // Array + Field projection: + let mut arr: [Foo<f32>; 1] = [Foo(2.0)]; + arr[0].0 -= 1.0; + d -= arr[0].0; + let mut arr: [Bar<f32>; 1] = [Bar { x: 2.0 }]; + arr[0].x -= 1.0; + d -= arr[0].x; + + // Field + Array projection: + let mut arr: Foo<[f32; 1]> = Foo([2.0]); + (arr.0)[0] -= 1.0; + d -= (arr.0)[0]; + let mut arr: Bar<[f32; 1]> = Bar { x: [2.0] }; + arr.x[0] -= 1.0; + d -= arr.x[0]; + + d +} + +macro_rules! test { + ($c:ident, $e:expr, $r:expr) => { + const $c: f32 = $e; + assert_eq!($c, $r); + assert_eq!($e, $r); + } +} + +fn main() { + test!(BASICS, basics((2.0,)), 13.0); + test!(ADD, add_assign(W(1.0)), 10.0); + test!(MUL, mul_assign(A { a: 0.0 }), 256.0); + test!(DIV, div_assign([1.0]), 4.0); + test!(REM, rem_assign(W(5.0)), 5.0); + test!(SUB, sub_assign(W(8.0)), 0.0); +} diff --git a/tests/ui/consts/const_let_irrefutable.rs b/tests/ui/consts/const_let_irrefutable.rs new file mode 100644 index 000000000..e889abf4a --- /dev/null +++ b/tests/ui/consts/const_let_irrefutable.rs @@ -0,0 +1,11 @@ +// build-pass (FIXME(62277): could be check-pass?) + +fn main() {} + +const fn tup((a, b): (i32, i32)) -> i32 { + a + b +} + +const fn array([a, b]: [i32; 2]) -> i32 { + a + b +} diff --git a/tests/ui/consts/const_let_promote.rs b/tests/ui/consts/const_let_promote.rs new file mode 100644 index 000000000..f4661e9e4 --- /dev/null +++ b/tests/ui/consts/const_let_promote.rs @@ -0,0 +1,17 @@ +// run-pass + +use std::cell::Cell; + +const X: Option<Cell<i32>> = None; + +const Y: Option<Cell<i32>> = { + let x = None; + x +}; + +// Ensure that binding the final value of a `const` to a variable does not affect promotion. +#[allow(unused)] +fn main() { + let x: &'static _ = &X; + let y: &'static _ = &Y; +} diff --git a/tests/ui/consts/const_let_refutable.rs b/tests/ui/consts/const_let_refutable.rs new file mode 100644 index 000000000..efb134d2e --- /dev/null +++ b/tests/ui/consts/const_let_refutable.rs @@ -0,0 +1,6 @@ +fn main() {} + +const fn slice(&[a, b]: &[i32]) -> i32 { + //~^ ERROR refutable pattern in function argument + a + b +} diff --git a/tests/ui/consts/const_let_refutable.stderr b/tests/ui/consts/const_let_refutable.stderr new file mode 100644 index 000000000..d6119028f --- /dev/null +++ b/tests/ui/consts/const_let_refutable.stderr @@ -0,0 +1,11 @@ +error[E0005]: refutable pattern in function argument + --> $DIR/const_let_refutable.rs:3:16 + | +LL | const fn slice(&[a, b]: &[i32]) -> i32 { + | ^^^^^^^ patterns `&[]`, `&[_]` and `&[_, _, _, ..]` not covered + | + = note: the matched value is of type `&[i32]` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0005`. diff --git a/tests/ui/consts/const_limit/const_eval_limit_not_reached.rs b/tests/ui/consts/const_limit/const_eval_limit_not_reached.rs new file mode 100644 index 000000000..629d1f02a --- /dev/null +++ b/tests/ui/consts/const_limit/const_eval_limit_not_reached.rs @@ -0,0 +1,20 @@ +// check-pass + +#![feature(const_eval_limit)] + +// This needs to be higher than the number of loop iterations since each pass through the loop may +// hit more than one terminator. +#![const_eval_limit="4000"] + +const X: usize = { + let mut x = 0; + while x != 1000 { + x += 1; + } + + x +}; + +fn main() { + assert_eq!(X, 1000); +} diff --git a/tests/ui/consts/const_limit/const_eval_limit_overflow.rs b/tests/ui/consts/const_limit/const_eval_limit_overflow.rs new file mode 100644 index 000000000..1c49593cd --- /dev/null +++ b/tests/ui/consts/const_limit/const_eval_limit_overflow.rs @@ -0,0 +1,15 @@ +#![feature(const_eval_limit)] +#![const_eval_limit="18_446_744_073_709_551_615"] +//~^ ERROR `limit` must be a non-negative integer + +const CONSTANT: usize = limit(); + +fn main() { + assert_eq!(CONSTANT, 1764); +} + +const fn limit() -> usize { + let x = 42; + + x * 42 +} diff --git a/tests/ui/consts/const_limit/const_eval_limit_overflow.stderr b/tests/ui/consts/const_limit/const_eval_limit_overflow.stderr new file mode 100644 index 000000000..7f5d5e6cd --- /dev/null +++ b/tests/ui/consts/const_limit/const_eval_limit_overflow.stderr @@ -0,0 +1,10 @@ +error: `limit` must be a non-negative integer + --> $DIR/const_eval_limit_overflow.rs:2:1 + | +LL | #![const_eval_limit="18_446_744_073_709_551_615"] + | ^^^^^^^^^^^^^^^^^^^^----------------------------^ + | | + | not a valid integer + +error: aborting due to previous error + diff --git a/tests/ui/consts/const_limit/const_eval_limit_reached.rs b/tests/ui/consts/const_limit/const_eval_limit_reached.rs new file mode 100644 index 000000000..3ce038c1d --- /dev/null +++ b/tests/ui/consts/const_limit/const_eval_limit_reached.rs @@ -0,0 +1,16 @@ +#![feature(const_eval_limit)] +#![const_eval_limit = "500"] + +const X: usize = { + let mut x = 0; + while x != 1000 { + //~^ ERROR evaluation of constant value failed + x += 1; + } + + x +}; + +fn main() { + assert_eq!(X, 1000); +} diff --git a/tests/ui/consts/const_limit/const_eval_limit_reached.stderr b/tests/ui/consts/const_limit/const_eval_limit_reached.stderr new file mode 100644 index 000000000..850aebdfb --- /dev/null +++ b/tests/ui/consts/const_limit/const_eval_limit_reached.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const_eval_limit_reached.rs:6:11 + | +LL | while x != 1000 { + | ^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const_limit/feature-gate-const_eval_limit.rs b/tests/ui/consts/const_limit/feature-gate-const_eval_limit.rs new file mode 100644 index 000000000..61119d751 --- /dev/null +++ b/tests/ui/consts/const_limit/feature-gate-const_eval_limit.rs @@ -0,0 +1,14 @@ +#![const_eval_limit="42"] +//~^ ERROR the `#[const_eval_limit]` attribute is an experimental feature [E0658] + +const CONSTANT: usize = limit(); + +fn main() { + assert_eq!(CONSTANT, 1764); +} + +const fn limit() -> usize { + let x = 42; + + x * 42 +} diff --git a/tests/ui/consts/const_limit/feature-gate-const_eval_limit.stderr b/tests/ui/consts/const_limit/feature-gate-const_eval_limit.stderr new file mode 100644 index 000000000..5bd29c7df --- /dev/null +++ b/tests/ui/consts/const_limit/feature-gate-const_eval_limit.stderr @@ -0,0 +1,12 @@ +error[E0658]: the `#[const_eval_limit]` attribute is an experimental feature + --> $DIR/feature-gate-const_eval_limit.rs:1:1 + | +LL | #![const_eval_limit="42"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #67217 <https://github.com/rust-lang/rust/issues/67217> for more information + = help: add `#![feature(const_eval_limit)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/const_prop_slice_pat_ice.rs b/tests/ui/consts/const_prop_slice_pat_ice.rs new file mode 100644 index 000000000..60b06a497 --- /dev/null +++ b/tests/ui/consts/const_prop_slice_pat_ice.rs @@ -0,0 +1,8 @@ +// check-pass + +fn main() { + match &[0, 1] as &[i32] { + [a @ .., x] => {} + &[] => {} + } +} diff --git a/tests/ui/consts/const_short_circuit.rs b/tests/ui/consts/const_short_circuit.rs new file mode 100644 index 000000000..6403fbb17 --- /dev/null +++ b/tests/ui/consts/const_short_circuit.rs @@ -0,0 +1,14 @@ +// check-pass + +const _: bool = false && false; +const _: bool = true && false; +const _: bool = { + let mut x = true && false; + x +}; +const _: bool = { + let x = true && false; + x +}; + +fn main() {} diff --git a/tests/ui/consts/const_unsafe_unreachable.rs b/tests/ui/consts/const_unsafe_unreachable.rs new file mode 100644 index 000000000..1c3baec5d --- /dev/null +++ b/tests/ui/consts/const_unsafe_unreachable.rs @@ -0,0 +1,14 @@ +// run-pass + +const unsafe fn foo(x: bool) -> bool { + match x { + true => true, + false => std::hint::unreachable_unchecked(), + } +} + +const BAR: bool = unsafe { foo(true) }; + +fn main() { + assert_eq!(BAR, true); +} diff --git a/tests/ui/consts/const_unsafe_unreachable_ub.rs b/tests/ui/consts/const_unsafe_unreachable_ub.rs new file mode 100644 index 000000000..b418fea61 --- /dev/null +++ b/tests/ui/consts/const_unsafe_unreachable_ub.rs @@ -0,0 +1,14 @@ +// error-pattern: evaluation of constant value failed + +const unsafe fn foo(x: bool) -> bool { + match x { + true => true, + false => std::hint::unreachable_unchecked(), + } +} + +const BAR: bool = unsafe { foo(false) }; + +fn main() { + assert_eq!(BAR, true); +} diff --git a/tests/ui/consts/const_unsafe_unreachable_ub.stderr b/tests/ui/consts/const_unsafe_unreachable_ub.stderr new file mode 100644 index 000000000..593a51bfe --- /dev/null +++ b/tests/ui/consts/const_unsafe_unreachable_ub.stderr @@ -0,0 +1,21 @@ +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/hint.rs:LL:COL + | + = note: entering unreachable code + | +note: inside `unreachable_unchecked` + --> $SRC_DIR/core/src/hint.rs:LL:COL +note: inside `foo` + --> $DIR/const_unsafe_unreachable_ub.rs:6:18 + | +LL | false => std::hint::unreachable_unchecked(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: inside `BAR` + --> $DIR/const_unsafe_unreachable_ub.rs:10:28 + | +LL | const BAR: bool = unsafe { foo(false) }; + | ^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/constifconst-call-in-const-position.rs b/tests/ui/consts/constifconst-call-in-const-position.rs new file mode 100644 index 000000000..fcf01d5bc --- /dev/null +++ b/tests/ui/consts/constifconst-call-in-const-position.rs @@ -0,0 +1,22 @@ +// known-bug: #102498 + +#![feature(const_trait_impl, generic_const_exprs)] + +#[const_trait] +pub trait Tr { + fn a() -> usize; +} + +impl Tr for () { + fn a() -> usize { + 1 + } +} + +const fn foo<T: ~const Tr>() -> [u8; T::a()] { + [0; T::a()] +} + +fn main() { + foo::<()>(); +} diff --git a/tests/ui/consts/constifconst-call-in-const-position.stderr b/tests/ui/consts/constifconst-call-in-const-position.stderr new file mode 100644 index 000000000..d4a445120 --- /dev/null +++ b/tests/ui/consts/constifconst-call-in-const-position.stderr @@ -0,0 +1,18 @@ +warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/constifconst-call-in-const-position.rs:3:30 + | +LL | #![feature(const_trait_impl, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0080]: evaluation of `foo::<()>::{constant#0}` failed + --> $DIR/constifconst-call-in-const-position.rs:16:38 + | +LL | const fn foo<T: ~const Tr>() -> [u8; T::a()] { + | ^^^^^^ calling non-const function `<() as Tr>::a` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/consts-in-patterns.rs b/tests/ui/consts/consts-in-patterns.rs new file mode 100644 index 000000000..0295204c8 --- /dev/null +++ b/tests/ui/consts/consts-in-patterns.rs @@ -0,0 +1,28 @@ +// run-pass + +const FOO: isize = 10; +const BAR: isize = 3; +const ZST: &() = unsafe { std::mem::transmute(1usize) }; +const ZST_ARR: &[u8; 0] = unsafe { std::mem::transmute(1usize) }; + +const fn foo() -> isize { 4 } +const BOO: isize = foo(); + +pub fn main() { + let x: isize = 3; + let y = match x { + FOO => 1, + BAR => 2, + BOO => 4, + _ => 3 + }; + assert_eq!(y, 2); + let z = match &() { + ZST => 9, + }; + assert_eq!(z, 9); + let z = match b"" { + ZST_ARR => 10, + }; + assert_eq!(z, 10); +} diff --git a/tests/ui/consts/control-flow/assert.rs b/tests/ui/consts/control-flow/assert.rs new file mode 100644 index 000000000..9d17f65b9 --- /dev/null +++ b/tests/ui/consts/control-flow/assert.rs @@ -0,0 +1,8 @@ +// Test that `assert` works in consts. + +const _: () = assert!(true); + +const _: () = assert!(false); +//~^ ERROR evaluation of constant value failed + +fn main() {} diff --git a/tests/ui/consts/control-flow/assert.stderr b/tests/ui/consts/control-flow/assert.stderr new file mode 100644 index 000000000..8b1ca183d --- /dev/null +++ b/tests/ui/consts/control-flow/assert.stderr @@ -0,0 +1,11 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/assert.rs:5:15 + | +LL | const _: () = assert!(false); + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: false', $DIR/assert.rs:5:15 + | + = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/control-flow/basics.rs b/tests/ui/consts/control-flow/basics.rs new file mode 100644 index 000000000..02e5501f1 --- /dev/null +++ b/tests/ui/consts/control-flow/basics.rs @@ -0,0 +1,82 @@ +// Test basic functionality of control flow in a const context. + +// run-pass + +const X: u32 = 4; +const Y: u32 = 5; + +const ABS_DIFF: u32 = if X < Y { + Y - X +} else { + X - Y +}; + +const fn abs_diff(a: u32, b: u32) -> u32 { + match (a, b) { + (big, little) if big > little => big - little, + (little, big) => big - little, + } +} + +const fn gcd(a: u32, b: u32) -> u32 { + if b == 0 { + return a; + } + + gcd(b, a % b) +} + +const fn fib(n: u64) -> u64 { + if n == 0 { + return 0; + } + + let mut fib = (0, 1); + let mut i = 1; + while i < n { + fib = (fib.1, fib.0 + fib.1); + i += 1; + } + + fib.1 +} + +const fn is_prime(n: u64) -> bool { + if n % 2 == 0 { + return false; + } + + let mut div = 3; + loop { + if n % div == 0 { + return false; + } + + if div * div > n { + return true; + } + + div += 2; + } +} + +macro_rules! const_assert { + ($expr:expr) => { + const _: () = assert!($expr); + assert!($expr); + } +} + +fn main() { + const_assert!(abs_diff(4, 5) == abs_diff(5, 4)); + const_assert!(ABS_DIFF == abs_diff(5, 4)); + + const_assert!(gcd(48, 18) == 6); + const_assert!(gcd(18, 48) == 6); + + const_assert!(fib(2) == 1); + const_assert!(fib(8) == 21); + + const_assert!(is_prime(113)); + const_assert!(!is_prime(117)); +} diff --git a/tests/ui/consts/control-flow/drop-fail.precise.stderr b/tests/ui/consts/control-flow/drop-fail.precise.stderr new file mode 100644 index 000000000..93b5f257e --- /dev/null +++ b/tests/ui/consts/control-flow/drop-fail.precise.stderr @@ -0,0 +1,15 @@ +error[E0493]: destructor of `Option<Vec<i32>>` cannot be evaluated at compile-time + --> $DIR/drop-fail.rs:8:9 + | +LL | let x = Some(Vec::new()); + | ^ the destructor for this type cannot be evaluated in constants + +error[E0493]: destructor of `Option<Vec<i32>>` cannot be evaluated at compile-time + --> $DIR/drop-fail.rs:39:9 + | +LL | let mut tmp = None; + | ^^^^^^^ the destructor for this type cannot be evaluated in constants + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/control-flow/drop-fail.rs b/tests/ui/consts/control-flow/drop-fail.rs new file mode 100644 index 000000000..41341f312 --- /dev/null +++ b/tests/ui/consts/control-flow/drop-fail.rs @@ -0,0 +1,62 @@ +// revisions: stock precise + +#![cfg_attr(precise, feature(const_precise_live_drops))] + +// `x` is *not* always moved into the final value and may be dropped inside the initializer. +const _: Option<Vec<i32>> = { + let y: Option<Vec<i32>> = None; + let x = Some(Vec::new()); + //[stock,precise]~^ ERROR destructor of + + if true { + x + } else { + y + } +}; + +// We only clear `NeedsDrop` if a local is moved from in entirely. This is a shortcoming of the +// existing analysis. +const _: Vec<i32> = { + let vec_tuple = (Vec::new(),); + //[stock]~^ ERROR destructor of + + vec_tuple.0 +}; + +// This applies to single-field enum variants as well. +const _: Vec<i32> = { + let x: Result<_, Vec<i32>> = Ok(Vec::new()); + //[stock]~^ ERROR destructor of + + match x { + Ok(x) | Err(x) => x, + } +}; + +const _: Option<Vec<i32>> = { + let mut some = Some(Vec::new()); + let mut tmp = None; + //[stock,precise]~^ ERROR destructor of + + let mut i = 0; + while i < 10 { + tmp = some; + some = None; + + // We can escape the loop with `Some` still in `tmp`, + // which would require that it be dropped at the end of the block. + if i > 100 { + break; + } + + some = tmp; + tmp = None; + + i += 1; + } + + some +}; + +fn main() {} diff --git a/tests/ui/consts/control-flow/drop-fail.stock.stderr b/tests/ui/consts/control-flow/drop-fail.stock.stderr new file mode 100644 index 000000000..2cc856802 --- /dev/null +++ b/tests/ui/consts/control-flow/drop-fail.stock.stderr @@ -0,0 +1,39 @@ +error[E0493]: destructor of `Option<Vec<i32>>` cannot be evaluated at compile-time + --> $DIR/drop-fail.rs:8:9 + | +LL | let x = Some(Vec::new()); + | ^ the destructor for this type cannot be evaluated in constants +... +LL | }; + | - value is dropped here + +error[E0493]: destructor of `(Vec<i32>,)` cannot be evaluated at compile-time + --> $DIR/drop-fail.rs:21:9 + | +LL | let vec_tuple = (Vec::new(),); + | ^^^^^^^^^ the destructor for this type cannot be evaluated in constants +... +LL | }; + | - value is dropped here + +error[E0493]: destructor of `Result<Vec<i32>, Vec<i32>>` cannot be evaluated at compile-time + --> $DIR/drop-fail.rs:29:9 + | +LL | let x: Result<_, Vec<i32>> = Ok(Vec::new()); + | ^ the destructor for this type cannot be evaluated in constants +... +LL | }; + | - value is dropped here + +error[E0493]: destructor of `Option<Vec<i32>>` cannot be evaluated at compile-time + --> $DIR/drop-fail.rs:39:9 + | +LL | let mut tmp = None; + | ^^^^^^^ the destructor for this type cannot be evaluated in constants +... +LL | }; + | - value is dropped here + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/control-flow/drop-pass.rs b/tests/ui/consts/control-flow/drop-pass.rs new file mode 100644 index 000000000..2a6d12768 --- /dev/null +++ b/tests/ui/consts/control-flow/drop-pass.rs @@ -0,0 +1,46 @@ +// run-pass +// revisions: stock precise + +#![allow(unused)] +#![cfg_attr(precise, feature(const_precise_live_drops))] + +// `x` is always moved into the final value and is not dropped inside the initializer. +const _: Option<Vec<i32>> = { + let y: Option<Vec<i32>> = None; + let x = Some(Vec::new()); + + if true { + x + } else { + x + } +}; + +const _: Option<Vec<i32>> = { + let x = Some(Vec::new()); + match () { + () => x, + } +}; + +const _: Option<Vec<i32>> = { + let mut some = Some(Vec::new()); + let mut tmp = None; + + let mut i = 0; + while i < 10 { + tmp = some; + some = None; + + // We can never exit the loop with `Some` in `tmp`. + + some = tmp; + tmp = None; + + i += 1; + } + + some +}; + +fn main() {} diff --git a/tests/ui/consts/control-flow/drop-precise.rs b/tests/ui/consts/control-flow/drop-precise.rs new file mode 100644 index 000000000..4ecc5ef78 --- /dev/null +++ b/tests/ui/consts/control-flow/drop-precise.rs @@ -0,0 +1,18 @@ +// run-pass +// gate-test-const_precise_live_drops + +#![feature(const_precise_live_drops)] + +const _: Vec<i32> = { + let vec_tuple = (Vec::new(),); + vec_tuple.0 +}; + +const _: Vec<i32> = { + let x: Result<_, Vec<i32>> = Ok(Vec::new()); + match x { + Ok(x) | Err(x) => x, + } +}; + +fn main() {} diff --git a/tests/ui/consts/control-flow/exhaustive-c-like-enum-match.rs b/tests/ui/consts/control-flow/exhaustive-c-like-enum-match.rs new file mode 100644 index 000000000..4320133df --- /dev/null +++ b/tests/ui/consts/control-flow/exhaustive-c-like-enum-match.rs @@ -0,0 +1,29 @@ +// Test for <https://github.com/rust-lang/rust/issues/66756> + +// check-pass + +enum E { + A, + B, + C +} + +const fn f(e: E) { + match e { + E::A => {} + E::B => {} + E::C => {} + } +} + +const fn g(e: E) -> usize { + match e { + _ => 0 + } +} + +fn main() { + const X: usize = g(E::C); + assert_eq!(X, 0); + assert_eq!(g(E::A), 0); +} diff --git a/tests/ui/consts/control-flow/feature-gate-const-if-match.rs b/tests/ui/consts/control-flow/feature-gate-const-if-match.rs new file mode 100644 index 000000000..cb66bc753 --- /dev/null +++ b/tests/ui/consts/control-flow/feature-gate-const-if-match.rs @@ -0,0 +1,96 @@ +// check-pass + +const _: i32 = if true { 5 } else { 6 }; + +const _: i32 = if let Some(true) = Some(false) { 0 } else { 1 }; + +const _: i32 = match 1 { + 2 => 3, + 4 => 5, + _ => 0, +}; + +static FOO: i32 = { + let x = if true { 0 } else { 1 }; + let x = match x { + 0 => 1, + _ => 0, + }; + if let Some(x) = Some(x) { x } else { 1 } +}; + +static mut BAR: i32 = { + let x = if true { 0 } else { 1 }; + let x = match x { + 0 => 1, + _ => 0, + }; + if let Some(x) = Some(x) { x } else { 1 } +}; + +const fn if_() -> i32 { + if true { 5 } else { 6 } +} + +const fn if_let(a: Option<bool>) -> i32 { + if let Some(true) = a { 0 } else { 1 } +} + +const fn match_(i: i32) -> i32 { + match i { + i if i > 10 => i, + 1 => 2, + _ => 0, + } +} + +pub trait Foo { + const IF: i32 = if true { 5 } else { 6 }; + const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 }; + const MATCH: i32 = match 0 { + 1 => 2, + _ => 0, + }; +} + +impl Foo for () { + const IF: i32 = if true { 5 } else { 6 }; + const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 }; + const MATCH: i32 = match 0 { + 1 => 2, + _ => 0, + }; +} + +fn non_const_outside() { + const fn const_inside(y: bool) -> i32 { + let x = if y { 0 } else { 1 }; + let x = match x { + 0 => 1, + _ => 0, + }; + if let Some(x) = Some(x) { x } else { 1 } + } +} + +const fn const_outside() { + fn non_const_inside(y: bool) -> i32 { + let x = if y { 0 } else { 1 }; + let x = match x { + 0 => 1, + _ => 0, + }; + if let Some(x) = Some(x) { x } else { 1 } + } +} + +fn main() { + let _ = [0; { + let x = if false { 0 } else { 1 }; + let x = match x { + 0 => 1, + _ => 0, + }; + if let Some(x) = Some(x) { x } else { 1 } + }]; +} diff --git a/tests/ui/consts/control-flow/interior-mutability.rs b/tests/ui/consts/control-flow/interior-mutability.rs new file mode 100644 index 000000000..a6d44237b --- /dev/null +++ b/tests/ui/consts/control-flow/interior-mutability.rs @@ -0,0 +1,43 @@ +// Ensure that *any* assignment to the return place of a value with interior mutability +// disqualifies it from promotion. + +use std::cell::Cell; + +const X: Option<Cell<i32>> = { + let mut x = None; + if false { + x = Some(Cell::new(4)); + } + x +}; + +const Y: Option<Cell<i32>> = { + let mut y = Some(Cell::new(4)); + if true { + y = None; + } + y +}; + +const Z: Option<Cell<i32>> = { + let mut z = None; + let mut i = 0; + while i < 10 { + if i == 8 { + z = Some(Cell::new(4)); + } + + if i == 9 { + z = None; + } + + i += 1; + } + z +}; + +fn main() { + let x: &'static _ = &X; //~ ERROR temporary value dropped while borrowed + let y: &'static _ = &Y; //~ ERROR temporary value dropped while borrowed + let z: &'static _ = &Z; //~ ERROR temporary value dropped while borrowed +} diff --git a/tests/ui/consts/control-flow/interior-mutability.stderr b/tests/ui/consts/control-flow/interior-mutability.stderr new file mode 100644 index 000000000..db2ffb91b --- /dev/null +++ b/tests/ui/consts/control-flow/interior-mutability.stderr @@ -0,0 +1,35 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/interior-mutability.rs:40:26 + | +LL | let x: &'static _ = &X; + | ---------- ^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/interior-mutability.rs:41:26 + | +LL | let y: &'static _ = &Y; + | ---------- ^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | let z: &'static _ = &Z; +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/interior-mutability.rs:42:26 + | +LL | let z: &'static _ = &Z; + | ---------- ^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/control-flow/issue-46843.rs b/tests/ui/consts/control-flow/issue-46843.rs new file mode 100644 index 000000000..ddddc8505 --- /dev/null +++ b/tests/ui/consts/control-flow/issue-46843.rs @@ -0,0 +1,16 @@ +enum Thing { + This, + That, +} + +fn non_const() -> Thing { + Thing::This +} + +pub const Q: i32 = match non_const() { + //~^ ERROR cannot call non-const fn + Thing::This => 1, + Thing::That => 0 +}; + +fn main() {} diff --git a/tests/ui/consts/control-flow/issue-46843.stderr b/tests/ui/consts/control-flow/issue-46843.stderr new file mode 100644 index 000000000..66227f61e --- /dev/null +++ b/tests/ui/consts/control-flow/issue-46843.stderr @@ -0,0 +1,11 @@ +error[E0015]: cannot call non-const fn `non_const` in constants + --> $DIR/issue-46843.rs:10:26 + | +LL | pub const Q: i32 = match non_const() { + | ^^^^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/control-flow/issue-50577.rs b/tests/ui/consts/control-flow/issue-50577.rs new file mode 100644 index 000000000..beb9a44fc --- /dev/null +++ b/tests/ui/consts/control-flow/issue-50577.rs @@ -0,0 +1,6 @@ +fn main() { + enum Foo { + Drop = assert_eq!(1, 1), + //~^ ERROR `if` may be missing an `else` clause + } +} diff --git a/tests/ui/consts/control-flow/issue-50577.stderr b/tests/ui/consts/control-flow/issue-50577.stderr new file mode 100644 index 000000000..a931c89f4 --- /dev/null +++ b/tests/ui/consts/control-flow/issue-50577.stderr @@ -0,0 +1,13 @@ +error[E0317]: `if` may be missing an `else` clause + --> $DIR/issue-50577.rs:3:16 + | +LL | Drop = assert_eq!(1, 1), + | ^^^^^^^^^^^^^^^^ expected `isize`, found `()` + | + = note: `if` expressions without `else` evaluate to `()` + = help: consider adding an `else` block that evaluates to the expected type + = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0317`. diff --git a/tests/ui/consts/control-flow/loop.rs b/tests/ui/consts/control-flow/loop.rs new file mode 100644 index 000000000..2b8561a26 --- /dev/null +++ b/tests/ui/consts/control-flow/loop.rs @@ -0,0 +1,89 @@ +const _: () = loop { break (); }; + +static FOO: i32 = loop { break 4; }; + +const fn foo() { + loop {} +} + +pub trait Foo { + const BAR: i32 = loop { break 4; }; +} + +impl Foo for () { + const BAR: i32 = loop { break 4; }; +} + +fn non_const_outside() { + const fn const_inside() { + loop {} + } +} + +const fn const_outside() { + fn non_const_inside() { + loop {} + } +} + +fn main() { + let x = [0; { + while false {} + 4 + }]; +} + +const _: i32 = { + let mut x = 0; + + while x < 4 { + x += 1; + } + + while x < 8 { + x += 1; + } + + x +}; + +const _: i32 = { + let mut x = 0; + + for i in 0..4 { //~ ERROR `for` is not allowed in a `const` + x += i; + } + + for i in 0..4 { //~ ERROR `for` is not allowed in a `const` + x += i; + } + + x +}; + +const _: i32 = { + let mut x = 0; + + loop { + x += 1; + if x == 4 { + break; + } + } + + loop { + x += 1; + if x == 8 { + break; + } + } + + x +}; + +const _: i32 = { + let mut x = 0; + while let None = Some(x) { } + while let None = Some(x) { } + x +}; diff --git a/tests/ui/consts/control-flow/loop.stderr b/tests/ui/consts/control-flow/loop.stderr new file mode 100644 index 000000000..5f6ad8c10 --- /dev/null +++ b/tests/ui/consts/control-flow/loop.stderr @@ -0,0 +1,25 @@ +error[E0658]: `for` is not allowed in a `const` + --> $DIR/loop.rs:53:5 + | +LL | / for i in 0..4 { +LL | | x += i; +LL | | } + | |_____^ + | + = note: see issue #87575 <https://github.com/rust-lang/rust/issues/87575> for more information + = help: add `#![feature(const_for)]` to the crate attributes to enable + +error[E0658]: `for` is not allowed in a `const` + --> $DIR/loop.rs:57:5 + | +LL | / for i in 0..4 { +LL | | x += i; +LL | | } + | |_____^ + | + = note: see issue #87575 <https://github.com/rust-lang/rust/issues/87575> for more information + = help: add `#![feature(const_for)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/control-flow/short-circuit-let.rs b/tests/ui/consts/control-flow/short-circuit-let.rs new file mode 100644 index 000000000..8a58d06ac --- /dev/null +++ b/tests/ui/consts/control-flow/short-circuit-let.rs @@ -0,0 +1,36 @@ +// `&&` and `||` were previously forbidden in constants alongside let bindings. + +// run-pass + +const X: i32 = { + let mut x = 0; + let _ = true && { x = 1; false }; + x +}; + +const Y: bool = { + let x = true && false || true; + x +}; + +const fn truthy() -> bool { + let x = true || return false; + x +} + +const fn falsy() -> bool { + let x = true && return false; + x +} + +fn main() { + const _: () = assert!(Y); + assert!(Y); + + const _: () = assert!(X == 1); + assert_eq!(X, 1); + + const _: () = assert!(truthy()); + const _: () = assert!(!falsy()); + assert!(truthy() && !falsy()); +} diff --git a/tests/ui/consts/control-flow/short-circuit.rs b/tests/ui/consts/control-flow/short-circuit.rs new file mode 100644 index 000000000..6abe10785 --- /dev/null +++ b/tests/ui/consts/control-flow/short-circuit.rs @@ -0,0 +1,12 @@ +// run-pass + +// Test that both `&&` and `||` actually short-circuit. +// Formerly, both sides were evaluated unconditionally + +const TRUE: bool = true || panic!(); +const FALSE: bool = false && panic!(); + +fn main() { + assert!(TRUE); + assert!(!FALSE); +} diff --git a/tests/ui/consts/control-flow/single_variant_match_ice.rs b/tests/ui/consts/control-flow/single_variant_match_ice.rs new file mode 100644 index 000000000..b59be00ff --- /dev/null +++ b/tests/ui/consts/control-flow/single_variant_match_ice.rs @@ -0,0 +1,25 @@ +// check-pass + +enum Foo { + Prob, +} + +const FOO: u32 = match Foo::Prob { + Foo::Prob => 42, +}; + +const BAR: u32 = match Foo::Prob { + x => 42, +}; + +impl Foo { + pub const fn as_val(&self) -> u8 { + use self::Foo::*; + + match *self { + Prob => 0x1, + } + } +} + +fn main() {} diff --git a/tests/ui/consts/control-flow/try.rs b/tests/ui/consts/control-flow/try.rs new file mode 100644 index 000000000..7d85a412b --- /dev/null +++ b/tests/ui/consts/control-flow/try.rs @@ -0,0 +1,10 @@ +// The `?` operator is still not const-evaluatable because it calls `From::from` on the error +// variant. + +const fn opt() -> Option<i32> { + let x = Some(2); + x?; //~ ERROR `?` is not allowed in a `const fn` + None +} + +fn main() {} diff --git a/tests/ui/consts/control-flow/try.stderr b/tests/ui/consts/control-flow/try.stderr new file mode 100644 index 000000000..5aeec8fbf --- /dev/null +++ b/tests/ui/consts/control-flow/try.stderr @@ -0,0 +1,12 @@ +error[E0658]: `?` is not allowed in a `const fn` + --> $DIR/try.rs:6:5 + | +LL | x?; + | ^^ + | + = note: see issue #74935 <https://github.com/rust-lang/rust/issues/74935> for more information + = help: add `#![feature(const_try)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/copy-intrinsic.rs b/tests/ui/consts/copy-intrinsic.rs new file mode 100644 index 000000000..94d7bdc6b --- /dev/null +++ b/tests/ui/consts/copy-intrinsic.rs @@ -0,0 +1,52 @@ +#![stable(feature = "dummy", since = "1.0.0")] + +// ignore-tidy-linelength +#![feature(intrinsics, staged_api)] +#![feature(const_mut_refs)] +use std::mem; + +extern "rust-intrinsic" { + #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] + fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize); + + #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] + fn copy<T>(src: *const T, dst: *mut T, count: usize); +} + +const COPY_ZERO: () = unsafe { + // Since we are not copying anything, this should be allowed. + let src = (); + let mut dst = (); + copy_nonoverlapping(&src as *const _ as *const u8, &mut dst as *mut _ as *mut u8, 0); +}; + +const COPY_OOB_1: () = unsafe { + let mut x = 0i32; + let dangle = (&mut x as *mut i32).wrapping_add(10); + // Even if the first ptr is an int ptr and this is a ZST copy, we should detect dangling 2nd ptrs. + copy_nonoverlapping(0x100 as *const i32, dangle, 0); //~ ERROR evaluation of constant value failed [E0080] + //~| pointer at offset 40 is out-of-bounds +}; +const COPY_OOB_2: () = unsafe { + let x = 0i32; + let dangle = (&x as *const i32).wrapping_add(10); + // Even if the second ptr is an int ptr and this is a ZST copy, we should detect dangling 1st ptrs. + copy_nonoverlapping(dangle, 0x100 as *mut i32, 0); //~ ERROR evaluation of constant value failed [E0080] + //~| pointer at offset 40 is out-of-bounds +}; + +const COPY_SIZE_OVERFLOW: () = unsafe { + let x = 0; + let mut y = 0; + copy(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1)); //~ ERROR evaluation of constant value failed [E0080] + //~| overflow computing total size of `copy` +}; +const COPY_NONOVERLAPPING_SIZE_OVERFLOW: () = unsafe { + let x = 0; + let mut y = 0; + copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1)); //~ evaluation of constant value failed [E0080] + //~| overflow computing total size of `copy_nonoverlapping` +}; + +fn main() { +} diff --git a/tests/ui/consts/copy-intrinsic.stderr b/tests/ui/consts/copy-intrinsic.stderr new file mode 100644 index 000000000..be41c2db3 --- /dev/null +++ b/tests/ui/consts/copy-intrinsic.stderr @@ -0,0 +1,27 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/copy-intrinsic.rs:27:5 + | +LL | copy_nonoverlapping(0x100 as *const i32, dangle, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: alloc5 has size 4, so pointer at offset 40 is out-of-bounds + +error[E0080]: evaluation of constant value failed + --> $DIR/copy-intrinsic.rs:34:5 + | +LL | copy_nonoverlapping(dangle, 0x100 as *mut i32, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: alloc7 has size 4, so pointer at offset 40 is out-of-bounds + +error[E0080]: evaluation of constant value failed + --> $DIR/copy-intrinsic.rs:41:5 + | +LL | copy(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy` + +error[E0080]: evaluation of constant value failed + --> $DIR/copy-intrinsic.rs:47:5 + | +LL | copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy_nonoverlapping` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/ct-var-in-collect_all_mismatches.rs b/tests/ui/consts/ct-var-in-collect_all_mismatches.rs new file mode 100644 index 000000000..5fb633de9 --- /dev/null +++ b/tests/ui/consts/ct-var-in-collect_all_mismatches.rs @@ -0,0 +1,20 @@ +struct Foo<T, const N: usize> { + array: [T; N], +} + +trait Bar<const N: usize> {} + +impl<T, const N: usize> Foo<T, N> { + fn trigger(self) { + self.unsatisfied() + //~^ ERROR the trait bound `T: Bar<N>` is not satisfied + } + + fn unsatisfied(self) + where + T: Bar<N>, + { + } +} + +fn main() {} diff --git a/tests/ui/consts/ct-var-in-collect_all_mismatches.stderr b/tests/ui/consts/ct-var-in-collect_all_mismatches.stderr new file mode 100644 index 000000000..43fba2573 --- /dev/null +++ b/tests/ui/consts/ct-var-in-collect_all_mismatches.stderr @@ -0,0 +1,22 @@ +error[E0277]: the trait bound `T: Bar<N>` is not satisfied + --> $DIR/ct-var-in-collect_all_mismatches.rs:9:14 + | +LL | self.unsatisfied() + | ^^^^^^^^^^^ the trait `Bar<N>` is not implemented for `T` + | +note: required by a bound in `Foo::<T, N>::unsatisfied` + --> $DIR/ct-var-in-collect_all_mismatches.rs:15:12 + | +LL | fn unsatisfied(self) + | ----------- required by a bound in this +LL | where +LL | T: Bar<N>, + | ^^^^^^ required by this bound in `Foo::<T, N>::unsatisfied` +help: consider restricting type parameter `T` + | +LL | impl<T: Bar<N>, const N: usize> Foo<T, N> { + | ++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/dangling-alloc-id-ice.rs b/tests/ui/consts/dangling-alloc-id-ice.rs new file mode 100644 index 000000000..d591bfc73 --- /dev/null +++ b/tests/ui/consts/dangling-alloc-id-ice.rs @@ -0,0 +1,14 @@ +// https://github.com/rust-lang/rust/issues/55223 + +union Foo<'a> { + y: &'a (), + long_live_the_unit: &'static (), +} + +const FOO: &() = { +//~^ ERROR encountered dangling pointer in final constant + let y = (); + unsafe { Foo { y: &y }.long_live_the_unit } +}; + +fn main() {} diff --git a/tests/ui/consts/dangling-alloc-id-ice.stderr b/tests/ui/consts/dangling-alloc-id-ice.stderr new file mode 100644 index 000000000..0a1cca4ca --- /dev/null +++ b/tests/ui/consts/dangling-alloc-id-ice.stderr @@ -0,0 +1,8 @@ +error: encountered dangling pointer in final constant + --> $DIR/dangling-alloc-id-ice.rs:8:1 + | +LL | const FOO: &() = { + | ^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/consts/dangling_raw_ptr.rs b/tests/ui/consts/dangling_raw_ptr.rs new file mode 100644 index 000000000..ddd1fb1ba --- /dev/null +++ b/tests/ui/consts/dangling_raw_ptr.rs @@ -0,0 +1,8 @@ +const FOO: *const u32 = { //~ ERROR encountered dangling pointer in final constant + let x = 42; + &x +}; + +fn main() { + let x = FOO; +} diff --git a/tests/ui/consts/dangling_raw_ptr.stderr b/tests/ui/consts/dangling_raw_ptr.stderr new file mode 100644 index 000000000..bdfe1e4ef --- /dev/null +++ b/tests/ui/consts/dangling_raw_ptr.stderr @@ -0,0 +1,8 @@ +error: encountered dangling pointer in final constant + --> $DIR/dangling_raw_ptr.rs:1:1 + | +LL | const FOO: *const u32 = { + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/consts/deref_in_pattern.rs b/tests/ui/consts/deref_in_pattern.rs new file mode 100644 index 000000000..cc47b5b49 --- /dev/null +++ b/tests/ui/consts/deref_in_pattern.rs @@ -0,0 +1,12 @@ +// run-pass + +// https://github.com/rust-lang/rust/issues/25574 + +const A: [u8; 4] = *b"fooo"; + +fn main() { + match *b"xxxx" { + A => {}, + _ => {} + } +} diff --git a/tests/ui/consts/drop_box.rs b/tests/ui/consts/drop_box.rs new file mode 100644 index 000000000..679974130 --- /dev/null +++ b/tests/ui/consts/drop_box.rs @@ -0,0 +1,4 @@ +const fn f<T>(_: Box<T>) {} +//~^ ERROR destructor of + +fn main() {} diff --git a/tests/ui/consts/drop_box.stderr b/tests/ui/consts/drop_box.stderr new file mode 100644 index 000000000..62324939b --- /dev/null +++ b/tests/ui/consts/drop_box.stderr @@ -0,0 +1,11 @@ +error[E0493]: destructor of `Box<T>` cannot be evaluated at compile-time + --> $DIR/drop_box.rs:1:15 + | +LL | const fn f<T>(_: Box<T>) {} + | ^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constant functions + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/drop_none.rs b/tests/ui/consts/drop_none.rs new file mode 100644 index 000000000..9d98d3be8 --- /dev/null +++ b/tests/ui/consts/drop_none.rs @@ -0,0 +1,13 @@ +// build-pass (FIXME(62277): could be check-pass?) +#![allow(dead_code)] +struct A; +impl Drop for A { + fn drop(&mut self) {} +} + +const FOO: Option<A> = None; + +const BAR: () = (FOO, ()).1; + + +fn main() {} diff --git a/tests/ui/consts/drop_zst.rs b/tests/ui/consts/drop_zst.rs new file mode 100644 index 000000000..f7c70d397 --- /dev/null +++ b/tests/ui/consts/drop_zst.rs @@ -0,0 +1,17 @@ +// check-fail + +#![feature(const_precise_live_drops)] + +struct S; + +impl Drop for S { + fn drop(&mut self) { + println!("Hello!"); + } +} + +const fn foo() { + let s = S; //~ destructor +} + +fn main() {} diff --git a/tests/ui/consts/drop_zst.stderr b/tests/ui/consts/drop_zst.stderr new file mode 100644 index 000000000..37758a4cb --- /dev/null +++ b/tests/ui/consts/drop_zst.stderr @@ -0,0 +1,9 @@ +error[E0493]: destructor of `S` cannot be evaluated at compile-time + --> $DIR/drop_zst.rs:14:9 + | +LL | let s = S; + | ^ the destructor for this type cannot be evaluated in constant functions + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/enum-discr-type-err.rs b/tests/ui/consts/enum-discr-type-err.rs new file mode 100644 index 000000000..5adb2fa54 --- /dev/null +++ b/tests/ui/consts/enum-discr-type-err.rs @@ -0,0 +1,30 @@ +// Test that we mark enum discriminant values as having errors, even when the +// diagnostic is deduplicated. + +struct F; +struct T; + +impl F { + const V: i32 = 0; +} + +impl T { + const V: i32 = 0; +} + +macro_rules! mac { + ($( $v: ident = $s: ident,)*) => { + enum E { + $( $v = $s::V, )* + //~^ ERROR mismatched types + //~| ERROR mismatched types + } + } +} + +mac! { + A = F, + B = T, +} + +fn main() {} diff --git a/tests/ui/consts/enum-discr-type-err.stderr b/tests/ui/consts/enum-discr-type-err.stderr new file mode 100644 index 000000000..2f97582be --- /dev/null +++ b/tests/ui/consts/enum-discr-type-err.stderr @@ -0,0 +1,31 @@ +error[E0308]: mismatched types + --> $DIR/enum-discr-type-err.rs:18:21 + | +LL | $( $v = $s::V, )* + | ^^^^^ expected `isize`, found `i32` +... +LL | / mac! { +LL | | A = F, +LL | | B = T, +LL | | } + | |_- in this macro invocation + | + = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> $DIR/enum-discr-type-err.rs:18:21 + | +LL | $( $v = $s::V, )* + | ^^^^^ expected `isize`, found `i32` +... +LL | / mac! { +LL | | A = F, +LL | | B = T, +LL | | } + | |_- in this macro invocation + | + = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/eval-enum.rs b/tests/ui/consts/eval-enum.rs new file mode 100644 index 000000000..551f10e66 --- /dev/null +++ b/tests/ui/consts/eval-enum.rs @@ -0,0 +1,10 @@ +enum Test { + DivZero = 1/0, + //~^ attempt to divide `1_isize` by zero + //~| ERROR evaluation of constant value failed + RemZero = 1%0, + //~^ attempt to calculate the remainder of `1_isize` with a divisor of zero + //~| ERROR evaluation of constant value failed +} + +fn main() {} diff --git a/tests/ui/consts/eval-enum.stderr b/tests/ui/consts/eval-enum.stderr new file mode 100644 index 000000000..fb4d90348 --- /dev/null +++ b/tests/ui/consts/eval-enum.stderr @@ -0,0 +1,15 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/eval-enum.rs:2:15 + | +LL | DivZero = 1/0, + | ^^^ attempt to divide `1_isize` by zero + +error[E0080]: evaluation of constant value failed + --> $DIR/eval-enum.rs:5:15 + | +LL | RemZero = 1%0, + | ^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/extra-const-ub/detect-extra-ub.rs b/tests/ui/consts/extra-const-ub/detect-extra-ub.rs new file mode 100644 index 000000000..e2f814988 --- /dev/null +++ b/tests/ui/consts/extra-const-ub/detect-extra-ub.rs @@ -0,0 +1,31 @@ +// revisions: no_flag with_flag +// [no_flag] check-pass +// [with_flag] compile-flags: -Zextra-const-ub-checks +#![feature(const_ptr_read)] + +use std::mem::transmute; + +const INVALID_BOOL: () = unsafe { + let _x: bool = transmute(3u8); + //[with_flag]~^ ERROR: evaluation of constant value failed + //[with_flag]~| invalid value +}; + +const INVALID_PTR_IN_INT: () = unsafe { + let _x: usize = transmute(&3u8); + //[with_flag]~^ ERROR: evaluation of constant value failed +}; + +const INVALID_SLICE_TO_USIZE_TRANSMUTE: () = unsafe { + let x: &[u8] = &[0; 32]; + let _x: (usize, usize) = transmute(x); + //[with_flag]~^ ERROR: evaluation of constant value failed +}; + +const UNALIGNED_PTR: () = unsafe { + let _x: &u32 = transmute(&[0u8; 4]); + //[with_flag]~^ ERROR: evaluation of constant value failed + //[with_flag]~| invalid value +}; + +fn main() {} diff --git a/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr b/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr new file mode 100644 index 000000000..b2a5fd901 --- /dev/null +++ b/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr @@ -0,0 +1,33 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/detect-extra-ub.rs:9:20 + | +LL | let _x: bool = transmute(3u8); + | ^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean + +error[E0080]: evaluation of constant value failed + --> $DIR/detect-extra-ub.rs:15:21 + | +LL | let _x: usize = transmute(&3u8); + | ^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/detect-extra-ub.rs:21:30 + | +LL | let _x: (usize, usize) = transmute(x); + | ^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/detect-extra-ub.rs:26:20 + | +LL | let _x: &u32 = transmute(&[0u8; 4]); + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 4 byte alignment but found 1) + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/extra-const-ub/issue-100771.rs b/tests/ui/consts/extra-const-ub/issue-100771.rs new file mode 100644 index 000000000..a32960328 --- /dev/null +++ b/tests/ui/consts/extra-const-ub/issue-100771.rs @@ -0,0 +1,20 @@ +// check-pass +// compile-flags: -Zextra-const-ub-checks + +#[derive(PartialEq, Eq, Copy, Clone)] +#[repr(packed)] +struct Foo { + field: (i64, u32, u32, u32), +} + +const FOO: Foo = Foo { + field: (5, 6, 7, 8), +}; + +fn main() { + match FOO { + Foo { field: (5, 6, 7, 8) } => {}, + FOO => unreachable!(), + _ => unreachable!(), + } +} diff --git a/tests/ui/consts/extra-const-ub/issue-101034.rs b/tests/ui/consts/extra-const-ub/issue-101034.rs new file mode 100644 index 000000000..e0de705c4 --- /dev/null +++ b/tests/ui/consts/extra-const-ub/issue-101034.rs @@ -0,0 +1,17 @@ +// check-pass +// compile-flags: -Zextra-const-ub-checks + +#[repr(packed)] +pub struct Foo { + bar: u8, + baa: [u32; 1], +} + +const FOOMP: Foo = Foo { + bar: 0, + baa: [69; 1], +}; + +fn main() { + let _val = FOOMP; +} diff --git a/tests/ui/consts/fn_trait_refs.rs b/tests/ui/consts/fn_trait_refs.rs new file mode 100644 index 000000000..b50749297 --- /dev/null +++ b/tests/ui/consts/fn_trait_refs.rs @@ -0,0 +1,77 @@ +// check-pass + +#![feature(const_fn_trait_ref_impls)] +#![feature(fn_traits)] +#![feature(unboxed_closures)] +#![feature(const_trait_impl)] +#![feature(const_mut_refs)] +#![feature(const_cmp)] +#![feature(const_refs_to_cell)] + +use std::marker::Destruct; + +const fn tester_fn<T>(f: T) -> T::Output +where + T: ~const Fn<()> + ~const Destruct, +{ + f() +} + +const fn tester_fn_mut<T>(mut f: T) -> T::Output +where + T: ~const FnMut<()> + ~const Destruct, +{ + f() +} + +const fn tester_fn_once<T>(f: T) -> T::Output +where + T: ~const FnOnce<()>, +{ + f() +} + +const fn test_fn<T>(mut f: T) -> (T::Output, T::Output, T::Output) +where + T: ~const Fn<()> + ~const Destruct, +{ + ( + // impl<A: Tuple, F: ~const Fn + ?Sized> const Fn<A> for &F + tester_fn(&f), + // impl<A: Tuple, F: ~const Fn + ?Sized> const FnMut<A> for &F + tester_fn_mut(&f), + // impl<A: Tuple, F: ~const Fn + ?Sized> const FnOnce<A> for &F + tester_fn_once(&f), + ) +} + +const fn test_fn_mut<T>(mut f: T) -> (T::Output, T::Output) +where + T: ~const FnMut<()> + ~const Destruct, +{ + ( + // impl<A: Tuple, F: ~const FnMut + ?Sized> const FnMut<A> for &mut F + tester_fn_mut(&mut f), + // impl<A: Tuple, F: ~const FnMut + ?Sized> const FnOnce<A> for &mut F + tester_fn_once(&mut f), + ) +} +const fn test(i: i32) -> i32 { + i + 1 +} + +fn main() { + const fn one() -> i32 { + 1 + }; + const fn two() -> i32 { + 2 + }; + const _: () = { + let test_one = test_fn(one); + assert!(test_one == (1, 1, 1)); + + let test_two = test_fn_mut(two); + assert!(test_two == (2, 2)); + }; +} diff --git a/tests/ui/consts/huge-values.rs b/tests/ui/consts/huge-values.rs new file mode 100644 index 000000000..70a5b10e9 --- /dev/null +++ b/tests/ui/consts/huge-values.rs @@ -0,0 +1,17 @@ +// build-pass +// ignore-32bit + +// This test is a canary test that will essentially not compile in a reasonable time frame +// (so it'll take hours) if any of the optimizations regress. With the optimizations, these compile +// in milliseconds just as if the length were set to `1`. + +#[derive(Clone, Copy)] +struct Foo; + +fn main() { + let _ = [(); 4_000_000_000]; + let _ = [0u8; 4_000_000_000]; + let _ = [Foo; 4_000_000_000]; + let _ = [(Foo, (), Foo, ((), Foo, [0; 0])); 4_000_000_000]; + let _ = [[0; 0]; 4_000_000_000]; +} diff --git a/tests/ui/consts/ice-48279.rs b/tests/ui/consts/ice-48279.rs new file mode 100644 index 000000000..d1d90df24 --- /dev/null +++ b/tests/ui/consts/ice-48279.rs @@ -0,0 +1,26 @@ +// run-pass +#![allow(dead_code)] +#![allow(unused_unsafe)] + +// https://github.com/rust-lang/rust/issues/48279 + +#[derive(PartialEq, Eq)] +pub struct NonZeroU32 { + value: u32 +} + +impl NonZeroU32 { + const unsafe fn new_unchecked(value: u32) -> Self { + NonZeroU32 { value } + } +} + +//pub const FOO_ATOM: NonZeroU32 = unsafe { NonZeroU32::new_unchecked(7) }; +pub const FOO_ATOM: NonZeroU32 = unsafe { NonZeroU32 { value: 7 } }; + +fn main() { + match None { + Some(FOO_ATOM) => {} + _ => {} + } +} diff --git a/tests/ui/consts/ice-zst-static-access.rs b/tests/ui/consts/ice-zst-static-access.rs new file mode 100644 index 000000000..b68e442a5 --- /dev/null +++ b/tests/ui/consts/ice-zst-static-access.rs @@ -0,0 +1,32 @@ +// check-pass + +// This is a regression test for ICEs from +// https://github.com/rust-lang/rust/issues/71612 +// and +// https://github.com/rust-lang/rust/issues/71709 + +#[derive(Copy, Clone)] +pub struct Glfw; + +static mut GLFW: Option<Glfw> = None; +pub fn new() -> Glfw { + unsafe { + if let Some(glfw) = GLFW { + return glfw; + } else { + todo!() + } + }; +} + +extern "C" { + static _dispatch_queue_attr_concurrent: [u8; 0]; +} + +static DISPATCH_QUEUE_CONCURRENT: &'static [u8; 0] = + unsafe { &_dispatch_queue_attr_concurrent }; + +fn main() { + *DISPATCH_QUEUE_CONCURRENT; + new(); +} diff --git a/tests/ui/consts/inline_asm.rs b/tests/ui/consts/inline_asm.rs new file mode 100644 index 000000000..4cd7e2717 --- /dev/null +++ b/tests/ui/consts/inline_asm.rs @@ -0,0 +1,8 @@ +// needs-asm-support + +use std::arch::asm; + +const _: () = unsafe { asm!("nop") }; +//~^ ERROR inline assembly + +fn main() {} diff --git a/tests/ui/consts/inline_asm.stderr b/tests/ui/consts/inline_asm.stderr new file mode 100644 index 000000000..65a828d11 --- /dev/null +++ b/tests/ui/consts/inline_asm.stderr @@ -0,0 +1,9 @@ +error[E0015]: inline assembly is not allowed in constants + --> $DIR/inline_asm.rs:5:24 + | +LL | const _: () = unsafe { asm!("nop") }; + | ^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/int_ptr_for_zst_slices.rs b/tests/ui/consts/int_ptr_for_zst_slices.rs new file mode 100644 index 000000000..34e5bb322 --- /dev/null +++ b/tests/ui/consts/int_ptr_for_zst_slices.rs @@ -0,0 +1,5 @@ +// check-pass + +const FOO: &str = unsafe { &*(1_usize as *const [u8; 0] as *const [u8] as *const str) }; + +fn main() {} diff --git a/tests/ui/consts/intrinsic_without_const_stab.rs b/tests/ui/consts/intrinsic_without_const_stab.rs new file mode 100644 index 000000000..40ec65d51 --- /dev/null +++ b/tests/ui/consts/intrinsic_without_const_stab.rs @@ -0,0 +1,17 @@ +#![feature(intrinsics, staged_api)] +#![stable(feature = "core", since = "1.6.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] +#[inline] +pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) { + // Const stability attributes are not inherited from parent items. + extern "rust-intrinsic" { + fn copy<T>(src: *const T, dst: *mut T, count: usize); + } + + unsafe { copy(src, dst, count) } + //~^ ERROR cannot call non-const fn +} + +fn main() {} diff --git a/tests/ui/consts/intrinsic_without_const_stab.stderr b/tests/ui/consts/intrinsic_without_const_stab.stderr new file mode 100644 index 000000000..b32b6398e --- /dev/null +++ b/tests/ui/consts/intrinsic_without_const_stab.stderr @@ -0,0 +1,11 @@ +error[E0015]: cannot call non-const fn `copy::copy::<T>` in constant functions + --> $DIR/intrinsic_without_const_stab.rs:13:14 + | +LL | unsafe { copy(src, dst, count) } + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/intrinsic_without_const_stab_fail.rs b/tests/ui/consts/intrinsic_without_const_stab_fail.rs new file mode 100644 index 000000000..2b0745b3c --- /dev/null +++ b/tests/ui/consts/intrinsic_without_const_stab_fail.rs @@ -0,0 +1,15 @@ +#![feature(intrinsics, staged_api)] +#![stable(feature = "core", since = "1.6.0")] + +extern "rust-intrinsic" { + fn copy<T>(src: *const T, dst: *mut T, count: usize); +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] +#[inline] +pub const unsafe fn stuff<T>(src: *const T, dst: *mut T, count: usize) { + unsafe { copy(src, dst, count) } //~ ERROR cannot call non-const fn +} + +fn main() {} diff --git a/tests/ui/consts/intrinsic_without_const_stab_fail.stderr b/tests/ui/consts/intrinsic_without_const_stab_fail.stderr new file mode 100644 index 000000000..fcbb37245 --- /dev/null +++ b/tests/ui/consts/intrinsic_without_const_stab_fail.stderr @@ -0,0 +1,11 @@ +error[E0015]: cannot call non-const fn `copy::<T>` in constant functions + --> $DIR/intrinsic_without_const_stab_fail.rs:12:14 + | +LL | unsafe { copy(src, dst, count) } + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/invalid-const-in-body.rs b/tests/ui/consts/invalid-const-in-body.rs new file mode 100644 index 000000000..f0fa3bb7b --- /dev/null +++ b/tests/ui/consts/invalid-const-in-body.rs @@ -0,0 +1,6 @@ +fn f() -> impl Sized { + 2.0E + //~^ ERROR expected at least one digit in exponent +} + +fn main() {} diff --git a/tests/ui/consts/invalid-const-in-body.stderr b/tests/ui/consts/invalid-const-in-body.stderr new file mode 100644 index 000000000..3be658359 --- /dev/null +++ b/tests/ui/consts/invalid-const-in-body.stderr @@ -0,0 +1,8 @@ +error: expected at least one digit in exponent + --> $DIR/invalid-const-in-body.rs:2:5 + | +LL | 2.0E + | ^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/consts/invalid-inline-const-in-match-arm.rs b/tests/ui/consts/invalid-inline-const-in-match-arm.rs new file mode 100644 index 000000000..4d2d8fb13 --- /dev/null +++ b/tests/ui/consts/invalid-inline-const-in-match-arm.rs @@ -0,0 +1,9 @@ +#![allow(incomplete_features)] +#![feature(inline_const_pat)] + +fn main() { + match () { + const { (|| {})() } => {} + //~^ ERROR cannot call non-const closure in constants + } +} diff --git a/tests/ui/consts/invalid-inline-const-in-match-arm.stderr b/tests/ui/consts/invalid-inline-const-in-match-arm.stderr new file mode 100644 index 000000000..257ecd7f3 --- /dev/null +++ b/tests/ui/consts/invalid-inline-const-in-match-arm.stderr @@ -0,0 +1,13 @@ +error[E0015]: cannot call non-const closure in constants + --> $DIR/invalid-inline-const-in-match-arm.rs:6:17 + | +LL | const { (|| {})() } => {} + | ^^^^^^^^^ + | + = note: closures need an RFC before allowed to be called in constants + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/invalid-union.32bit.stderr b/tests/ui/consts/invalid-union.32bit.stderr new file mode 100644 index 000000000..0dd18a557 --- /dev/null +++ b/tests/ui/consts/invalid-union.32bit.stderr @@ -0,0 +1,26 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/invalid-union.rs:41:1 + | +LL | fn main() { + | ^^^^^^^^^ constructing invalid value at .<deref>.y.<enum-variant(B)>.0: encountered `UnsafeCell` in a `const` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + ╾─alloc7──╼ │ ╾──╼ + } + +note: erroneous constant used + --> $DIR/invalid-union.rs:43:25 + | +LL | let _: &'static _ = &C; + | ^^ + +note: erroneous constant used + --> $DIR/invalid-union.rs:43:25 + | +LL | let _: &'static _ = &C; + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/invalid-union.64bit.stderr b/tests/ui/consts/invalid-union.64bit.stderr new file mode 100644 index 000000000..07f36ee28 --- /dev/null +++ b/tests/ui/consts/invalid-union.64bit.stderr @@ -0,0 +1,26 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/invalid-union.rs:41:1 + | +LL | fn main() { + | ^^^^^^^^^ constructing invalid value at .<deref>.y.<enum-variant(B)>.0: encountered `UnsafeCell` in a `const` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + ╾───────alloc7────────╼ │ ╾──────╼ + } + +note: erroneous constant used + --> $DIR/invalid-union.rs:43:25 + | +LL | let _: &'static _ = &C; + | ^^ + +note: erroneous constant used + --> $DIR/invalid-union.rs:43:25 + | +LL | let _: &'static _ = &C; + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/invalid-union.rs b/tests/ui/consts/invalid-union.rs new file mode 100644 index 000000000..28706b4a9 --- /dev/null +++ b/tests/ui/consts/invalid-union.rs @@ -0,0 +1,44 @@ +// Check that constants with interior mutability inside unions are rejected +// during validation. +// +// Note that this test case relies on undefined behaviour to construct a +// constant with interior mutability that is "invisible" to the static checks. +// If for some reason this approach no longer works, it is should be fine to +// remove the test case. +// +// build-fail +// stderr-per-bitwidth +#![feature(const_mut_refs)] + +use std::cell::Cell; +use std::mem::ManuallyDrop; + +#[repr(C)] +struct S { + x: u32, + y: E, +} + +#[repr(u32)] +enum E { + A, + B(U) +} + +union U { + cell: ManuallyDrop<Cell<u32>>, +} + +const C: S = { + let s = S { x: 0, y: E::A }; + // Go through an &u32 reference which is definitely not allowed to mutate anything. + let p = &s.x as *const u32 as *mut u32; + // Change enum tag to E::B. + unsafe { *p.add(1) = 1 }; + s +}; + +fn main() { //~ ERROR it is undefined behavior to use this value + // FIXME the span here is wrong, sould be pointing at the line below, not above. + let _: &'static _ = &C; +} diff --git a/tests/ui/consts/invalid_promotion.rs b/tests/ui/consts/invalid_promotion.rs new file mode 100644 index 000000000..a31eaf40e --- /dev/null +++ b/tests/ui/consts/invalid_promotion.rs @@ -0,0 +1,18 @@ +// build-pass (FIXME(62277): could be check-pass?) +// note this was only reproducible with lib crates +// compile-flags: --crate-type=lib + +pub struct Hz; + +impl Hz { + pub const fn num(&self) -> u32 { + 42 + } + pub const fn normalized(&self) -> Hz { + Hz + } + + pub const fn as_u32(&self) -> u32 { + self.normalized().num() // this used to promote the `self.normalized()` + } +} diff --git a/tests/ui/consts/issue-102117.rs b/tests/ui/consts/issue-102117.rs new file mode 100644 index 000000000..3ed90aed2 --- /dev/null +++ b/tests/ui/consts/issue-102117.rs @@ -0,0 +1,30 @@ +#![feature(inline_const, const_type_id)] + +use std::alloc::Layout; +use std::any::TypeId; +use std::mem::transmute; +use std::ptr::drop_in_place; + +pub struct VTable { + layout: Layout, + type_id: TypeId, + drop_in_place: unsafe fn(*mut ()), +} + +impl VTable { + pub fn new<T>() -> &'static Self { + const { + &VTable { + layout: Layout::new::<T>(), + type_id: TypeId::of::<T>(), + //~^ ERROR the parameter type `T` may not live long enough + //~| ERROR the parameter type `T` may not live long enough + drop_in_place: unsafe { + transmute::<unsafe fn(*mut T), unsafe fn(*mut ())>(drop_in_place::<T>) + }, + } + } + } +} + +fn main() {} diff --git a/tests/ui/consts/issue-102117.stderr b/tests/ui/consts/issue-102117.stderr new file mode 100644 index 000000000..f42bcf90f --- /dev/null +++ b/tests/ui/consts/issue-102117.stderr @@ -0,0 +1,25 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/issue-102117.rs:19:26 + | +LL | type_id: TypeId::of::<T>(), + | ^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | pub fn new<T: 'static>() -> &'static Self { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/issue-102117.rs:19:26 + | +LL | type_id: TypeId::of::<T>(), + | ^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | pub fn new<T: 'static>() -> &'static Self { + | +++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0310`. diff --git a/tests/ui/consts/issue-103790.rs b/tests/ui/consts/issue-103790.rs new file mode 100644 index 000000000..ea3cac605 --- /dev/null +++ b/tests/ui/consts/issue-103790.rs @@ -0,0 +1,10 @@ +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +struct S<const S: (), const S: S = { S }>; +//~^ ERROR the name `S` is already used for a generic parameter in this item's generic parameters +//~| ERROR missing generics for struct `S` +//~| ERROR cycle detected when computing type of `S::S` +//~| ERROR cycle detected when computing type of `S` + +fn main() {} diff --git a/tests/ui/consts/issue-103790.stderr b/tests/ui/consts/issue-103790.stderr new file mode 100644 index 000000000..34d8ee281 --- /dev/null +++ b/tests/ui/consts/issue-103790.stderr @@ -0,0 +1,65 @@ +error[E0403]: the name `S` is already used for a generic parameter in this item's generic parameters + --> $DIR/issue-103790.rs:4:29 + | +LL | struct S<const S: (), const S: S = { S }>; + | - ^ already used + | | + | first use of `S` + +error[E0107]: missing generics for struct `S` + --> $DIR/issue-103790.rs:4:32 + | +LL | struct S<const S: (), const S: S = { S }>; + | ^ expected at least 1 generic argument + | +note: struct defined here, with at least 1 generic parameter: `S` + --> $DIR/issue-103790.rs:4:8 + | +LL | struct S<const S: (), const S: S = { S }>; + | ^ ----------- +help: add missing generic argument + | +LL | struct S<const S: (), const S: S<S> = { S }>; + | +++ + +error[E0391]: cycle detected when computing type of `S::S` + --> $DIR/issue-103790.rs:4:32 + | +LL | struct S<const S: (), const S: S = { S }>; + | ^ + | + = note: ...which immediately requires computing type of `S::S` again +note: cycle used when computing type of `S` + --> $DIR/issue-103790.rs:4:1 + | +LL | struct S<const S: (), const S: S = { S }>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0391]: cycle detected when computing type of `S` + --> $DIR/issue-103790.rs:4:1 + | +LL | struct S<const S: (), const S: S = { S }>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires computing type of `S::S`... + --> $DIR/issue-103790.rs:4:32 + | +LL | struct S<const S: (), const S: S = { S }>; + | ^ + = note: ...which again requires computing type of `S`, completing the cycle +note: cycle used when collecting item types in top-level module + --> $DIR/issue-103790.rs:1:1 + | +LL | / #![feature(generic_const_exprs)] +LL | | #![allow(incomplete_features)] +LL | | +LL | | struct S<const S: (), const S: S = { S }>; +... | +LL | | +LL | | fn main() {} + | |____________^ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0107, E0391, E0403. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/consts/issue-104155.rs b/tests/ui/consts/issue-104155.rs new file mode 100644 index 000000000..1cc8f81b0 --- /dev/null +++ b/tests/ui/consts/issue-104155.rs @@ -0,0 +1,5 @@ +// check-pass +const _: () = core::mem::forget(Box::<u32>::default); +const _: () = core::mem::forget(|| Box::<u32>::default()); + +fn main() {} diff --git a/tests/ui/consts/issue-104396.rs b/tests/ui/consts/issue-104396.rs new file mode 100644 index 000000000..315b0cf0f --- /dev/null +++ b/tests/ui/consts/issue-104396.rs @@ -0,0 +1,36 @@ +// compile-flags: -Zmir-opt-level=3 +// check-pass + +#![feature(generic_const_exprs)] +//~^ WARN the feature `generic_const_exprs` is incomplete + +#[inline(always)] +fn from_fn_1<const N: usize, F: FnMut(usize) -> f32>(mut f: F) -> [f32; N] { + let mut result = [0.0; N]; + let mut i = 0; + while i < N { + result[i] = f(i); + i += 1; + } + result +} + +pub struct TestArray<const N: usize> +where + [(); N / 2]:, +{ + array: [f32; N / 2], +} + +impl<const N: usize> TestArray<N> +where + [(); N / 2]:, +{ + fn from_fn_2<F: FnMut(usize) -> f32>(f: F) -> Self { + Self { array: from_fn_1(f) } + } +} + +fn main() { + TestArray::<4>::from_fn_2(|i| 0.0); +} diff --git a/tests/ui/consts/issue-104396.stderr b/tests/ui/consts/issue-104396.stderr new file mode 100644 index 000000000..5856bee09 --- /dev/null +++ b/tests/ui/consts/issue-104396.stderr @@ -0,0 +1,11 @@ +warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-104396.rs:4:12 + | +LL | #![feature(generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/consts/issue-104609.rs b/tests/ui/consts/issue-104609.rs new file mode 100644 index 000000000..01fd1c48c --- /dev/null +++ b/tests/ui/consts/issue-104609.rs @@ -0,0 +1,10 @@ +fn foo() { + oops; + //~^ ERROR: cannot find value `oops` in this scope +} + +unsafe fn bar() { + std::mem::transmute::<_, *mut _>(1_u8); +} + +fn main() {} diff --git a/tests/ui/consts/issue-104609.stderr b/tests/ui/consts/issue-104609.stderr new file mode 100644 index 000000000..00360c44d --- /dev/null +++ b/tests/ui/consts/issue-104609.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `oops` in this scope + --> $DIR/issue-104609.rs:2:5 + | +LL | oops; + | ^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/consts/issue-104768.rs b/tests/ui/consts/issue-104768.rs new file mode 100644 index 000000000..3192daafa --- /dev/null +++ b/tests/ui/consts/issue-104768.rs @@ -0,0 +1,4 @@ +const A: &_ = 0_u32; +//~^ ERROR: the placeholder `_` is not allowed within types on item signatures for constants + +fn main() {} diff --git a/tests/ui/consts/issue-104768.stderr b/tests/ui/consts/issue-104768.stderr new file mode 100644 index 000000000..55b2b6f04 --- /dev/null +++ b/tests/ui/consts/issue-104768.stderr @@ -0,0 +1,12 @@ +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants + --> $DIR/issue-104768.rs:1:10 + | +LL | const A: &_ = 0_u32; + | ^^ + | | + | not allowed in type signatures + | help: replace with the correct type: `u32` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0121`. diff --git a/tests/ui/consts/issue-13837.rs b/tests/ui/consts/issue-13837.rs new file mode 100644 index 000000000..645b1c0eb --- /dev/null +++ b/tests/ui/consts/issue-13837.rs @@ -0,0 +1,13 @@ +// check-pass +#![allow(dead_code)] +// pretty-expanded FIXME #23616 + +struct TestStruct { + x: *const [isize; 2] +} + +unsafe impl Sync for TestStruct {} + +static TEST_VALUE : TestStruct = TestStruct{x: 0x1234 as *const [isize; 2]}; + +fn main() {} diff --git a/tests/ui/consts/issue-13902.rs b/tests/ui/consts/issue-13902.rs new file mode 100644 index 000000000..1afde0ebe --- /dev/null +++ b/tests/ui/consts/issue-13902.rs @@ -0,0 +1,16 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +const JSVAL_TAG_CLEAR: u32 = 0xFFFFFF80; +const JSVAL_TYPE_INT32: u8 = 0x01; +const JSVAL_TYPE_UNDEFINED: u8 = 0x02; +#[repr(u32)] +enum ValueTag { + JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | (JSVAL_TYPE_INT32 as u32), + JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | (JSVAL_TYPE_UNDEFINED as u32), +} + +fn main() { + let _ = ValueTag::JSVAL_TAG_INT32; +} diff --git a/tests/ui/consts/issue-17074.rs b/tests/ui/consts/issue-17074.rs new file mode 100644 index 000000000..0ed81132e --- /dev/null +++ b/tests/ui/consts/issue-17074.rs @@ -0,0 +1,15 @@ +// run-pass +#![allow(dead_code)] + +static X2: u64 = !0 as u16 as u64; +static Y2: u64 = !0 as u32 as u64; +const X: u64 = !0 as u16 as u64; +const Y: u64 = !0 as u32 as u64; + +fn main() { + assert_eq!(match 1 { + X => unreachable!(), + Y => unreachable!(), + _ => 1 + }, 1); +} diff --git a/tests/ui/consts/issue-17458.rs b/tests/ui/consts/issue-17458.rs new file mode 100644 index 000000000..44125a1c3 --- /dev/null +++ b/tests/ui/consts/issue-17458.rs @@ -0,0 +1,6 @@ +static X: usize = unsafe { core::ptr::null::<usize>() as usize }; +//~^ ERROR: pointers cannot be cast to integers during const eval + +fn main() { + assert_eq!(X, 0); +} diff --git a/tests/ui/consts/issue-17458.stderr b/tests/ui/consts/issue-17458.stderr new file mode 100644 index 000000000..8936c8d84 --- /dev/null +++ b/tests/ui/consts/issue-17458.stderr @@ -0,0 +1,11 @@ +error: pointers cannot be cast to integers during const eval + --> $DIR/issue-17458.rs:1:28 + | +LL | static X: usize = unsafe { core::ptr::null::<usize>() as usize }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: at compile-time, pointers do not have an integer value + = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior + +error: aborting due to previous error + diff --git a/tests/ui/consts/issue-17718-borrow-interior.rs b/tests/ui/consts/issue-17718-borrow-interior.rs new file mode 100644 index 000000000..5861f2186 --- /dev/null +++ b/tests/ui/consts/issue-17718-borrow-interior.rs @@ -0,0 +1,19 @@ +// run-pass +#![allow(dead_code)] +struct S { a: usize } + +static A: S = S { a: 3 }; +static B: &'static usize = &A.a; +static C: &'static usize = &(A.a); + +static D: [usize; 1] = [1]; +static E: usize = D[0]; +static F: &'static usize = &D[0]; + +fn main() { + assert_eq!(*B, A.a); + assert_eq!(*B, A.a); + + assert_eq!(E, D[0]); + assert_eq!(*F, D[0]); +} diff --git a/tests/ui/consts/issue-17718-const-bad-values.rs b/tests/ui/consts/issue-17718-const-bad-values.rs new file mode 100644 index 000000000..62bbb3b56 --- /dev/null +++ b/tests/ui/consts/issue-17718-const-bad-values.rs @@ -0,0 +1,9 @@ +const C1: &'static mut [usize] = &mut []; +//~^ ERROR: mutable references are not allowed + +static mut S: usize = 3; +const C2: &'static mut usize = unsafe { &mut S }; +//~^ ERROR: constants cannot refer to statics +//~| ERROR: constants cannot refer to statics + +fn main() {} diff --git a/tests/ui/consts/issue-17718-const-bad-values.stderr b/tests/ui/consts/issue-17718-const-bad-values.stderr new file mode 100644 index 000000000..ce60aaa07 --- /dev/null +++ b/tests/ui/consts/issue-17718-const-bad-values.stderr @@ -0,0 +1,26 @@ +error[E0764]: mutable references are not allowed in the final value of constants + --> $DIR/issue-17718-const-bad-values.rs:1:34 + | +LL | const C1: &'static mut [usize] = &mut []; + | ^^^^^^^ + +error[E0013]: constants cannot refer to statics + --> $DIR/issue-17718-const-bad-values.rs:5:46 + | +LL | const C2: &'static mut usize = unsafe { &mut S }; + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error[E0013]: constants cannot refer to statics + --> $DIR/issue-17718-const-bad-values.rs:5:46 + | +LL | const C2: &'static mut usize = unsafe { &mut S }; + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0013, E0764. +For more information about an error, try `rustc --explain E0013`. diff --git a/tests/ui/consts/issue-17718-const-borrow.rs b/tests/ui/consts/issue-17718-const-borrow.rs new file mode 100644 index 000000000..89316dbd5 --- /dev/null +++ b/tests/ui/consts/issue-17718-const-borrow.rs @@ -0,0 +1,14 @@ +use std::cell::UnsafeCell; + +const A: UnsafeCell<usize> = UnsafeCell::new(1); +const B: &'static UnsafeCell<usize> = &A; +//~^ ERROR: cannot refer to interior mutable + +struct C { a: UnsafeCell<usize> } +const D: C = C { a: UnsafeCell::new(1) }; +const E: &'static UnsafeCell<usize> = &D.a; +//~^ ERROR: cannot refer to interior mutable +const F: &'static C = &D; +//~^ ERROR: cannot refer to interior mutable + +fn main() {} diff --git a/tests/ui/consts/issue-17718-const-borrow.stderr b/tests/ui/consts/issue-17718-const-borrow.stderr new file mode 100644 index 000000000..e3ff6c923 --- /dev/null +++ b/tests/ui/consts/issue-17718-const-borrow.stderr @@ -0,0 +1,21 @@ +error[E0492]: constants cannot refer to interior mutable data + --> $DIR/issue-17718-const-borrow.rs:4:39 + | +LL | const B: &'static UnsafeCell<usize> = &A; + | ^^ this borrow of an interior mutable value may end up in the final value + +error[E0492]: constants cannot refer to interior mutable data + --> $DIR/issue-17718-const-borrow.rs:9:39 + | +LL | const E: &'static UnsafeCell<usize> = &D.a; + | ^^^^ this borrow of an interior mutable value may end up in the final value + +error[E0492]: constants cannot refer to interior mutable data + --> $DIR/issue-17718-const-borrow.rs:11:23 + | +LL | const F: &'static C = &D; + | ^^ this borrow of an interior mutable value may end up in the final value + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0492`. diff --git a/tests/ui/consts/issue-17718-constants-not-static.rs b/tests/ui/consts/issue-17718-constants-not-static.rs new file mode 100644 index 000000000..2e6aff161 --- /dev/null +++ b/tests/ui/consts/issue-17718-constants-not-static.rs @@ -0,0 +1,9 @@ +fn id<T>(x: T) -> T { x } + +const FOO: usize = 3; + +fn foo() -> &'static usize { &id(FOO) } +//~^ ERROR: cannot return reference to temporary value + +fn main() { +} diff --git a/tests/ui/consts/issue-17718-constants-not-static.stderr b/tests/ui/consts/issue-17718-constants-not-static.stderr new file mode 100644 index 000000000..8f3acae71 --- /dev/null +++ b/tests/ui/consts/issue-17718-constants-not-static.stderr @@ -0,0 +1,12 @@ +error[E0515]: cannot return reference to temporary value + --> $DIR/issue-17718-constants-not-static.rs:5:30 + | +LL | fn foo() -> &'static usize { &id(FOO) } + | ^------- + | || + | |temporary value created here + | returns a reference to data owned by the current function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0515`. diff --git a/tests/ui/consts/issue-17718-references.rs b/tests/ui/consts/issue-17718-references.rs new file mode 100644 index 000000000..03d5f8bb3 --- /dev/null +++ b/tests/ui/consts/issue-17718-references.rs @@ -0,0 +1,24 @@ +#![allow(warnings)] + +struct Struct { a: usize } + +const C: usize = 1; +static S: usize = 1; + +const T1: &'static usize = &C; +const T2: &'static usize = &S; //~ ERROR: constants cannot refer to statics +static T3: &'static usize = &C; +static T4: &'static usize = &S; + +const T5: usize = C; +const T6: usize = S; //~ ERROR: constants cannot refer to statics +static T7: usize = C; +static T8: usize = S; + +const T9: Struct = Struct { a: C }; +const T10: Struct = Struct { a: S }; +//~^ ERROR: constants cannot refer to statics +static T11: Struct = Struct { a: C }; +static T12: Struct = Struct { a: S }; + +fn main() {} diff --git a/tests/ui/consts/issue-17718-references.stderr b/tests/ui/consts/issue-17718-references.stderr new file mode 100644 index 000000000..e3c3b369f --- /dev/null +++ b/tests/ui/consts/issue-17718-references.stderr @@ -0,0 +1,27 @@ +error[E0013]: constants cannot refer to statics + --> $DIR/issue-17718-references.rs:9:29 + | +LL | const T2: &'static usize = &S; + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error[E0013]: constants cannot refer to statics + --> $DIR/issue-17718-references.rs:14:19 + | +LL | const T6: usize = S; + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error[E0013]: constants cannot refer to statics + --> $DIR/issue-17718-references.rs:19:33 + | +LL | const T10: Struct = Struct { a: S }; + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0013`. diff --git a/tests/ui/consts/issue-17718.rs b/tests/ui/consts/issue-17718.rs new file mode 100644 index 000000000..c6341d808 --- /dev/null +++ b/tests/ui/consts/issue-17718.rs @@ -0,0 +1,75 @@ +// run-pass +#![allow(dead_code)] +// aux-build:issue-17718-aux.rs + +extern crate issue_17718_aux as other; + +use std::sync::atomic::{AtomicUsize, Ordering}; + +const C1: usize = 1; +const C2: AtomicUsize = AtomicUsize::new(0); +const C3: fn() = foo; +const C4: usize = C1 * C1 + C1 / C1; +const C5: &'static usize = &C4; +const C6: usize = { + const C: usize = 3; + C +}; + +static S1: usize = 3; +static S2: AtomicUsize = AtomicUsize::new(0); + +mod test { + static A: usize = 4; + static B: &'static usize = &A; + static C: &'static usize = &(A); +} + +fn foo() {} + +fn main() { + assert_eq!(C1, 1); + assert_eq!(C3(), ()); + assert_eq!(C2.fetch_add(1, Ordering::SeqCst), 0); + assert_eq!(C2.fetch_add(1, Ordering::SeqCst), 0); + assert_eq!(C4, 2); + assert_eq!(*C5, 2); + assert_eq!(C6, 3); + assert_eq!(S1, 3); + assert_eq!(S2.fetch_add(1, Ordering::SeqCst), 0); + assert_eq!(S2.fetch_add(1, Ordering::SeqCst), 1); + + match 1 { + C1 => {} + _ => unreachable!(), + } + + let _a = C1; + let _a = C2; + let _a = C3; + let _a = C4; + let _a = C5; + let _a = C6; + let _a = S1; + + assert_eq!(other::C1, 1); + assert_eq!(other::C3(), ()); + assert_eq!(other::C2.fetch_add(1, Ordering::SeqCst), 0); + assert_eq!(other::C2.fetch_add(1, Ordering::SeqCst), 0); + assert_eq!(other::C4, 2); + assert_eq!(*other::C5, 2); + assert_eq!(other::S1, 3); + assert_eq!(other::S2.fetch_add(1, Ordering::SeqCst), 0); + assert_eq!(other::S2.fetch_add(1, Ordering::SeqCst), 1); + + let _a = other::C1; + let _a = other::C2; + let _a = other::C3; + let _a = other::C4; + let _a = other::C5; + + match 1 { + other::C1 => {} + _ => unreachable!(), + } +} diff --git a/tests/ui/consts/issue-17756.rs b/tests/ui/consts/issue-17756.rs new file mode 100644 index 000000000..1835b177f --- /dev/null +++ b/tests/ui/consts/issue-17756.rs @@ -0,0 +1,8 @@ +// run-pass +#![allow(unused_variables)] +#![allow(non_upper_case_globals)] + +const count : usize = 2 as usize; +fn main() { + let larger : [usize; count*2]; +} diff --git a/tests/ui/consts/issue-18294.rs b/tests/ui/consts/issue-18294.rs new file mode 100644 index 000000000..77355f0d7 --- /dev/null +++ b/tests/ui/consts/issue-18294.rs @@ -0,0 +1,5 @@ +fn main() { + const X: u32 = 1; + const Y: usize = unsafe { &X as *const u32 as usize }; //~ ERROR pointers cannot be cast to integers + println!("{}", Y); +} diff --git a/tests/ui/consts/issue-18294.stderr b/tests/ui/consts/issue-18294.stderr new file mode 100644 index 000000000..e0cbd2a21 --- /dev/null +++ b/tests/ui/consts/issue-18294.stderr @@ -0,0 +1,11 @@ +error: pointers cannot be cast to integers during const eval + --> $DIR/issue-18294.rs:3:31 + | +LL | const Y: usize = unsafe { &X as *const u32 as usize }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: at compile-time, pointers do not have an integer value + = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior + +error: aborting due to previous error + diff --git a/tests/ui/consts/issue-19244.rs b/tests/ui/consts/issue-19244.rs new file mode 100644 index 000000000..44d9748fd --- /dev/null +++ b/tests/ui/consts/issue-19244.rs @@ -0,0 +1,34 @@ +// run-pass + +struct MyStruct { field: usize } +struct Nested { nested: MyStruct } +struct Mix2 { nested: ((usize,),) } + +const STRUCT: MyStruct = MyStruct { field: 42 }; +const TUP: (usize,) = (43,); +const NESTED_S: Nested = Nested { nested: MyStruct { field: 5 } }; +const NESTED_T: ((usize,),) = ((4,),); +const MIX_1: ((Nested,),) = ((Nested { nested: MyStruct { field: 3 } },),); +const MIX_2: Mix2 = Mix2 { nested: ((2,),) }; +const INSTANT_1: usize = (MyStruct { field: 1 }).field; +const INSTANT_2: usize = (0,).0; + +fn main() { + let a = [0; STRUCT.field]; + let b = [0; TUP.0]; + let c = [0; NESTED_S.nested.field]; + let d = [0; (NESTED_T.0).0]; + let e = [0; (MIX_1.0).0.nested.field]; + let f = [0; (MIX_2.nested.0).0]; + let g = [0; INSTANT_1]; + let h = [0; INSTANT_2]; + + assert_eq!(a.len(), 42); + assert_eq!(b.len(), 43); + assert_eq!(c.len(), 5); + assert_eq!(d.len(), 4); + assert_eq!(e.len(), 3); + assert_eq!(f.len(), 2); + assert_eq!(g.len(), 1); + assert_eq!(h.len(), 0); +} diff --git a/tests/ui/consts/issue-21562.rs b/tests/ui/consts/issue-21562.rs new file mode 100644 index 000000000..a47d739c6 --- /dev/null +++ b/tests/ui/consts/issue-21562.rs @@ -0,0 +1,19 @@ +// build-pass +#![allow(dead_code)] +#![allow(non_upper_case_globals)] + +extern crate core; +use core::marker::Sync; + +static SARRAY: [i32; 1] = [11]; + +struct MyStruct { + pub arr: *const [i32], +} +unsafe impl Sync for MyStruct {} + +static mystruct: MyStruct = MyStruct { + arr: &SARRAY +}; + +fn main() {} diff --git a/tests/ui/consts/issue-21721.rs b/tests/ui/consts/issue-21721.rs new file mode 100644 index 000000000..4c1411e1e --- /dev/null +++ b/tests/ui/consts/issue-21721.rs @@ -0,0 +1,9 @@ +// run-pass + +fn main() { + static NONE: Option<((), &'static u8)> = None; + let ptr = unsafe { + *(&NONE as *const _ as *const *const u8) + }; + assert!(ptr.is_null()); +} diff --git a/tests/ui/consts/issue-23833.rs b/tests/ui/consts/issue-23833.rs new file mode 100644 index 000000000..d4128fa54 --- /dev/null +++ b/tests/ui/consts/issue-23833.rs @@ -0,0 +1,15 @@ +// run-pass +#![allow(unused_imports)] +use std::fmt; + +const A_I8_T + : [u32; (i8::MAX as i8 - 1i8) as usize] + = [0; (i8::MAX as usize) - 1]; + +fn main() { + foo(&A_I8_T[..]); +} + +fn foo<T:fmt::Debug>(x: T) { + println!("{:?}", x); +} diff --git a/tests/ui/consts/issue-23968-const-not-overflow.rs b/tests/ui/consts/issue-23968-const-not-overflow.rs new file mode 100644 index 000000000..b95930212 --- /dev/null +++ b/tests/ui/consts/issue-23968-const-not-overflow.rs @@ -0,0 +1,12 @@ +// run-pass +const U8_MAX_HALF: u8 = !0u8 / 2; +const U16_MAX_HALF: u16 = !0u16 / 2; +const U32_MAX_HALF: u32 = !0u32 / 2; +const U64_MAX_HALF: u64 = !0u64 / 2; + +fn main() { + assert_eq!(U8_MAX_HALF, 0x7f); + assert_eq!(U16_MAX_HALF, 0x7fff); + assert_eq!(U32_MAX_HALF, 0x7fff_ffff); + assert_eq!(U64_MAX_HALF, 0x7fff_ffff_ffff_ffff); +} diff --git a/tests/ui/consts/issue-25826.rs b/tests/ui/consts/issue-25826.rs new file mode 100644 index 000000000..c340c30a1 --- /dev/null +++ b/tests/ui/consts/issue-25826.rs @@ -0,0 +1,6 @@ +fn id<T>(t: T) -> T { t } +fn main() { + const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () }; + //~^ ERROR can't compare + println!("{}", A); +} diff --git a/tests/ui/consts/issue-25826.stderr b/tests/ui/consts/issue-25826.stderr new file mode 100644 index 000000000..905c5ee6e --- /dev/null +++ b/tests/ui/consts/issue-25826.stderr @@ -0,0 +1,16 @@ +error[E0277]: can't compare `*const ()` with `*const ()` in const contexts + --> $DIR/issue-25826.rs:3:52 + | +LL | const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () }; + | ^ no implementation for `*const () < *const ()` and `*const () > *const ()` + | + = help: the trait `~const PartialOrd` is not implemented for `*const ()` +note: the trait `PartialOrd` is implemented for `*const ()`, but that implementation is not `const` + --> $DIR/issue-25826.rs:3:52 + | +LL | const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () }; + | ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/issue-27890.rs b/tests/ui/consts/issue-27890.rs new file mode 100644 index 000000000..9f8547338 --- /dev/null +++ b/tests/ui/consts/issue-27890.rs @@ -0,0 +1,7 @@ +// run-pass +static PLUS_ONE: &'static (dyn Fn(i32) -> i32 + Sync) = (&|x: i32| { x + 1 }) + as &'static (dyn Fn(i32) -> i32 + Sync); + +fn main() { + assert_eq!(PLUS_ONE(2), 3); +} diff --git a/tests/ui/consts/issue-28113.rs b/tests/ui/consts/issue-28113.rs new file mode 100644 index 000000000..f8131c9f3 --- /dev/null +++ b/tests/ui/consts/issue-28113.rs @@ -0,0 +1,8 @@ +#![allow(warnings)] + +const X: u8 = + || -> u8 { 5 }() + //~^ ERROR cannot call non-const closure +; + +fn main() {} diff --git a/tests/ui/consts/issue-28113.stderr b/tests/ui/consts/issue-28113.stderr new file mode 100644 index 000000000..1294cc99b --- /dev/null +++ b/tests/ui/consts/issue-28113.stderr @@ -0,0 +1,13 @@ +error[E0015]: cannot call non-const closure in constants + --> $DIR/issue-28113.rs:4:5 + | +LL | || -> u8 { 5 }() + | ^^^^^^^^^^^^^^^^ + | + = note: closures need an RFC before allowed to be called in constants + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/issue-29914-2.rs b/tests/ui/consts/issue-29914-2.rs new file mode 100644 index 000000000..626de269d --- /dev/null +++ b/tests/ui/consts/issue-29914-2.rs @@ -0,0 +1,6 @@ +// run-pass +const ARR: [usize; 5] = [5, 4, 3, 2, 1]; + +fn main() { + assert_eq!(3, ARR[ARR[3]]); +} diff --git a/tests/ui/consts/issue-29914-3.rs b/tests/ui/consts/issue-29914-3.rs new file mode 100644 index 000000000..1c6c64eb3 --- /dev/null +++ b/tests/ui/consts/issue-29914-3.rs @@ -0,0 +1,7 @@ +// run-pass +const ARR: [usize; 5] = [5, 4, 3, 2, 1]; +const BLA: usize = ARR[ARR[3]]; + +fn main() { + assert_eq!(3, BLA); +} diff --git a/tests/ui/consts/issue-29914.rs b/tests/ui/consts/issue-29914.rs new file mode 100644 index 000000000..6da63664d --- /dev/null +++ b/tests/ui/consts/issue-29914.rs @@ -0,0 +1,10 @@ +// run-pass +#![allow(stable_features)] + +#![feature(const_indexing)] + +const ARR: [usize; 5] = [5, 4, 3, 2, 1]; + +fn main() { + assert_eq!(3, ARR[ARR[3]]); +} diff --git a/tests/ui/consts/issue-29927-1.rs b/tests/ui/consts/issue-29927-1.rs new file mode 100644 index 000000000..a236e4913 --- /dev/null +++ b/tests/ui/consts/issue-29927-1.rs @@ -0,0 +1,11 @@ +// run-pass +#![allow(dead_code)] +const fn f() -> usize { + 5 +} +struct A { + field: usize, +} +fn main() { + let _ = [0; f()]; +} diff --git a/tests/ui/consts/issue-29927.rs b/tests/ui/consts/issue-29927.rs new file mode 100644 index 000000000..3385e4e6e --- /dev/null +++ b/tests/ui/consts/issue-29927.rs @@ -0,0 +1,11 @@ +// run-pass +#![allow(dead_code)] +struct A { + field: usize, +} +const fn f() -> usize { + 5 +} +fn main() { + let _ = [0; f()]; +} diff --git a/tests/ui/consts/issue-32829-2.rs b/tests/ui/consts/issue-32829-2.rs new file mode 100644 index 000000000..d70b5a8c4 --- /dev/null +++ b/tests/ui/consts/issue-32829-2.rs @@ -0,0 +1,71 @@ +const bad : u32 = { + { + 5; + 0 + } +}; + +const bad_two : u32 = { + { + invalid(); + //~^ ERROR: cannot call non-const fn `invalid` + 0 + } +}; + +const bad_three : u32 = { + { + valid(); + 0 + } +}; + +static bad_four : u32 = { + { + 5; + 0 + } +}; + +static bad_five : u32 = { + { + invalid(); + //~^ ERROR: cannot call non-const fn `invalid` + 0 + } +}; + +static bad_six : u32 = { + { + valid(); + 0 + } +}; + +static mut bad_seven : u32 = { + { + 5; + 0 + } +}; + +static mut bad_eight : u32 = { + { + invalid(); + //~^ ERROR: cannot call non-const fn `invalid` + 0 + } +}; + +static mut bad_nine : u32 = { + { + valid(); + 0 + } +}; + + +fn invalid() {} +const fn valid() {} + +fn main() {} diff --git a/tests/ui/consts/issue-32829-2.stderr b/tests/ui/consts/issue-32829-2.stderr new file mode 100644 index 000000000..0fec35818 --- /dev/null +++ b/tests/ui/consts/issue-32829-2.stderr @@ -0,0 +1,29 @@ +error[E0015]: cannot call non-const fn `invalid` in constants + --> $DIR/issue-32829-2.rs:10:9 + | +LL | invalid(); + | ^^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + +error[E0015]: cannot call non-const fn `invalid` in statics + --> $DIR/issue-32829-2.rs:32:9 + | +LL | invalid(); + | ^^^^^^^^^ + | + = note: calls in statics are limited to constant functions, tuple structs and tuple variants + = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell + +error[E0015]: cannot call non-const fn `invalid` in statics + --> $DIR/issue-32829-2.rs:54:9 + | +LL | invalid(); + | ^^^^^^^^^ + | + = note: calls in statics are limited to constant functions, tuple structs and tuple variants + = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/issue-32829.rs b/tests/ui/consts/issue-32829.rs new file mode 100644 index 000000000..25f323b98 --- /dev/null +++ b/tests/ui/consts/issue-32829.rs @@ -0,0 +1,6 @@ +static S : u64 = { { panic!("foo"); 0 } }; +//~^ ERROR could not evaluate static initializer + +fn main() { + println!("{:?}", S); +} diff --git a/tests/ui/consts/issue-32829.stderr b/tests/ui/consts/issue-32829.stderr new file mode 100644 index 000000000..cae5163f0 --- /dev/null +++ b/tests/ui/consts/issue-32829.stderr @@ -0,0 +1,11 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/issue-32829.rs:1:22 + | +LL | static S : u64 = { { panic!("foo"); 0 } }; + | ^^^^^^^^^^^^^ the evaluated program panicked at 'foo', $DIR/issue-32829.rs:1:22 + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/issue-33537.rs b/tests/ui/consts/issue-33537.rs new file mode 100644 index 000000000..3539aa647 --- /dev/null +++ b/tests/ui/consts/issue-33537.rs @@ -0,0 +1,14 @@ +// run-pass + +const fn foo() -> *const i8 { + b"foo" as *const _ as *const i8 +} + +const fn bar() -> i32 { + *&{(1, 2, 3).1} +} + +fn main() { + assert_eq!(foo(), b"foo" as *const _ as *const i8); + assert_eq!(bar(), 2); +} diff --git a/tests/ui/consts/issue-34784.rs b/tests/ui/consts/issue-34784.rs new file mode 100644 index 000000000..98d943470 --- /dev/null +++ b/tests/ui/consts/issue-34784.rs @@ -0,0 +1,21 @@ +// run-pass + +#![warn(pointer_structural_match)] +#![allow(dead_code)] +const C: *const u8 = &0; + +fn foo(x: *const u8) { + match x { + C => {} + _ => {} + } +} + +const D: *const [u8; 4] = b"abcd"; + +fn main() { + match D { + D => {} + _ => {} + } +} diff --git a/tests/ui/consts/issue-3521.fixed b/tests/ui/consts/issue-3521.fixed new file mode 100644 index 000000000..f76106dff --- /dev/null +++ b/tests/ui/consts/issue-3521.fixed @@ -0,0 +1,13 @@ +// run-rustfix +fn main() { + #[allow(non_upper_case_globals)] + const foo: isize = 100; + + #[derive(Debug)] + enum Stuff { + Bar = foo + //~^ ERROR attempt to use a non-constant value in a constant + } + + println!("{:?}", Stuff::Bar); +} diff --git a/tests/ui/consts/issue-3521.rs b/tests/ui/consts/issue-3521.rs new file mode 100644 index 000000000..c425a22df --- /dev/null +++ b/tests/ui/consts/issue-3521.rs @@ -0,0 +1,13 @@ +// run-rustfix +fn main() { + #[allow(non_upper_case_globals)] + let foo: isize = 100; + + #[derive(Debug)] + enum Stuff { + Bar = foo + //~^ ERROR attempt to use a non-constant value in a constant + } + + println!("{:?}", Stuff::Bar); +} diff --git a/tests/ui/consts/issue-3521.stderr b/tests/ui/consts/issue-3521.stderr new file mode 100644 index 000000000..aa42772f1 --- /dev/null +++ b/tests/ui/consts/issue-3521.stderr @@ -0,0 +1,12 @@ +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/issue-3521.rs:8:15 + | +LL | let foo: isize = 100; + | ------- help: consider using `const` instead of `let`: `const foo` +... +LL | Bar = foo + | ^^^ non-constant value + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0435`. diff --git a/tests/ui/consts/issue-36163.rs b/tests/ui/consts/issue-36163.rs new file mode 100644 index 000000000..340d2c399 --- /dev/null +++ b/tests/ui/consts/issue-36163.rs @@ -0,0 +1,7 @@ +const A: isize = Foo::B as isize; + +enum Foo { + B = A, //~ ERROR E0391 +} + +fn main() {} diff --git a/tests/ui/consts/issue-36163.stderr b/tests/ui/consts/issue-36163.stderr new file mode 100644 index 000000000..7137c0538 --- /dev/null +++ b/tests/ui/consts/issue-36163.stderr @@ -0,0 +1,21 @@ +error[E0391]: cycle detected when const-evaluating + checking `Foo::B::{constant#0}` + --> $DIR/issue-36163.rs:4:9 + | +LL | B = A, + | ^ + | +note: ...which requires const-evaluating + checking `A`... + --> $DIR/issue-36163.rs:1:18 + | +LL | const A: isize = Foo::B as isize; + | ^^^^^^^^^^^^^^^ + = note: ...which again requires const-evaluating + checking `Foo::B::{constant#0}`, completing the cycle +note: cycle used when simplifying constant for the type system `Foo::B::{constant#0}` + --> $DIR/issue-36163.rs:4:9 + | +LL | B = A, + | ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/consts/issue-37222.rs b/tests/ui/consts/issue-37222.rs new file mode 100644 index 000000000..8ea5f6b7a --- /dev/null +++ b/tests/ui/consts/issue-37222.rs @@ -0,0 +1,17 @@ +// run-pass +#![allow(dead_code)] +#[derive(Debug, PartialEq)] +enum Bar { + A(i64), + B(i32), + C, +} + +#[derive(Debug, PartialEq)] +struct Foo(Bar, u8); + +static FOO: [Foo; 2] = [Foo(Bar::C, 0), Foo(Bar::C, 0xFF)]; + +fn main() { + assert_eq!(&FOO[1], &Foo(Bar::C, 0xFF)); +} diff --git a/tests/ui/consts/issue-37550-1.rs b/tests/ui/consts/issue-37550-1.rs new file mode 100644 index 000000000..4d00ac7fd --- /dev/null +++ b/tests/ui/consts/issue-37550-1.rs @@ -0,0 +1,8 @@ +// check-pass + +const fn x() { + let t = true; + let x = || t; +} + +fn main() {} diff --git a/tests/ui/consts/issue-37550.rs b/tests/ui/consts/issue-37550.rs new file mode 100644 index 000000000..724eb2829 --- /dev/null +++ b/tests/ui/consts/issue-37550.rs @@ -0,0 +1,10 @@ +// run-pass +#![allow(dead_code)] +#![allow(unused_variables)] + +const fn x() { + let t = true; + let x = || t; +} + +fn main() {} diff --git a/tests/ui/consts/issue-37991.rs b/tests/ui/consts/issue-37991.rs new file mode 100644 index 000000000..a6ac4d5ca --- /dev/null +++ b/tests/ui/consts/issue-37991.rs @@ -0,0 +1,17 @@ +// run-pass + +const fn foo() -> i64 { + 3 +} + +const fn bar(x: i64) -> i64 { + x*2 +} + +fn main() { + let val = &(foo() % 2); + assert_eq!(*val, 1); + + let val2 = &(bar(1+1) % 3); + assert_eq!(*val2, 1); +} diff --git a/tests/ui/consts/issue-39161-bogus-error.rs b/tests/ui/consts/issue-39161-bogus-error.rs new file mode 100644 index 000000000..a954385da --- /dev/null +++ b/tests/ui/consts/issue-39161-bogus-error.rs @@ -0,0 +1,13 @@ +// check-pass + +pub struct X { + pub a: i32, + pub b: i32, +} + +fn main() { + const DX: X = X { a: 0, b: 0 }; + const _X1: X = X { a: 1, ..DX }; + let _x2 = X { a: 1, b: 2, ..DX }; + const _X3: X = X { a: 1, b: 2, ..DX }; +} diff --git a/tests/ui/consts/issue-39974.rs b/tests/ui/consts/issue-39974.rs new file mode 100644 index 000000000..503647ef4 --- /dev/null +++ b/tests/ui/consts/issue-39974.rs @@ -0,0 +1,11 @@ +const LENGTH: f64 = 2; + +struct Thing { + f: [[f64; 2]; LENGTH], + //~^ ERROR mismatched types + //~| expected `usize`, found `f64` +} + +fn main() { + let _t = Thing { f: [[0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0]] }; +} diff --git a/tests/ui/consts/issue-39974.stderr b/tests/ui/consts/issue-39974.stderr new file mode 100644 index 000000000..56365e51e --- /dev/null +++ b/tests/ui/consts/issue-39974.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/issue-39974.rs:4:19 + | +LL | f: [[f64; 2]; LENGTH], + | ^^^^^^ expected `usize`, found `f64` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/issue-43105.rs b/tests/ui/consts/issue-43105.rs new file mode 100644 index 000000000..cac12b909 --- /dev/null +++ b/tests/ui/consts/issue-43105.rs @@ -0,0 +1,13 @@ +fn xyz() -> u8 { 42 } + +const NUM: u8 = xyz(); +//~^ ERROR cannot call non-const fn + +fn main() { + match 1 { + NUM => unimplemented!(), + //~^ ERROR could not evaluate constant pattern + //~| ERROR could not evaluate constant pattern + _ => unimplemented!(), + } +} diff --git a/tests/ui/consts/issue-43105.stderr b/tests/ui/consts/issue-43105.stderr new file mode 100644 index 000000000..2d1174af7 --- /dev/null +++ b/tests/ui/consts/issue-43105.stderr @@ -0,0 +1,23 @@ +error[E0015]: cannot call non-const fn `xyz` in constants + --> $DIR/issue-43105.rs:3:17 + | +LL | const NUM: u8 = xyz(); + | ^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + +error: could not evaluate constant pattern + --> $DIR/issue-43105.rs:8:9 + | +LL | NUM => unimplemented!(), + | ^^^ + +error: could not evaluate constant pattern + --> $DIR/issue-43105.rs:8:9 + | +LL | NUM => unimplemented!(), + | ^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/issue-44415.rs b/tests/ui/consts/issue-44415.rs new file mode 100644 index 000000000..d93b451be --- /dev/null +++ b/tests/ui/consts/issue-44415.rs @@ -0,0 +1,11 @@ +#![feature(core_intrinsics)] + +use std::intrinsics; + +struct Foo { + bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }], + //~^ ERROR cycle detected when evaluating type-level constant + x: usize, +} + +fn main() {} diff --git a/tests/ui/consts/issue-44415.stderr b/tests/ui/consts/issue-44415.stderr new file mode 100644 index 000000000..ec64b956d --- /dev/null +++ b/tests/ui/consts/issue-44415.stderr @@ -0,0 +1,29 @@ +error[E0391]: cycle detected when evaluating type-level constant + --> $DIR/issue-44415.rs:6:17 + | +LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }], + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`... + --> $DIR/issue-44415.rs:6:17 + | +LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }], + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`... + --> $DIR/issue-44415.rs:6:17 + | +LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }], + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which requires computing layout of `Foo`... + = note: ...which requires computing layout of `[u8; unsafe { intrinsics::size_of::<Foo>() }]`... + = note: ...which requires normalizing `[u8; unsafe { intrinsics::size_of::<Foo>() }]`... + = note: ...which again requires evaluating type-level constant, completing the cycle +note: cycle used when checking that `Foo` is well-formed + --> $DIR/issue-44415.rs:5:1 + | +LL | struct Foo { + | ^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/consts/issue-46553.rs b/tests/ui/consts/issue-46553.rs new file mode 100644 index 000000000..abeaf10f2 --- /dev/null +++ b/tests/ui/consts/issue-46553.rs @@ -0,0 +1,21 @@ +// run-pass + +pub struct Data<T> { + function: fn() -> T, +} + +impl<T> Data<T> { + pub const fn new(function: fn() -> T) -> Data<T> { + Data { + function: function, + } + } +} + +pub static DATA: Data<i32> = Data::new(|| { + 413i32 +}); + +fn main() { + print!("{:?}", (DATA.function)()); +} diff --git a/tests/ui/consts/issue-47789.rs b/tests/ui/consts/issue-47789.rs new file mode 100644 index 000000000..32dd909b2 --- /dev/null +++ b/tests/ui/consts/issue-47789.rs @@ -0,0 +1,10 @@ +// check-pass +#![allow(non_upper_case_globals)] + +static mut x: &'static u32 = &0; + +fn foo() { + unsafe { x = &1; } +} + +fn main() { } diff --git a/tests/ui/consts/issue-50439.rs b/tests/ui/consts/issue-50439.rs new file mode 100644 index 000000000..0be7c4054 --- /dev/null +++ b/tests/ui/consts/issue-50439.rs @@ -0,0 +1,29 @@ +#![feature(specialization)] +#![allow(incomplete_features)] + +pub trait ReflectDrop { + const REFLECT_DROP: bool = false; +} + +impl<T> ReflectDrop for T where T: Clone {} + +pub trait PinDropInternal { + fn is_valid() + where + Self: ReflectDrop; +} + +struct Bears<T>(T); + +default impl<T> ReflectDrop for Bears<T> {} + +impl<T: Sized> PinDropInternal for Bears<T> { + fn is_valid() + where + Self: ReflectDrop, + { + let _ = [(); 0 - !!(<Bears<T> as ReflectDrop>::REFLECT_DROP) as usize]; //~ ERROR constant expression depends on a generic parameter + } +} + +fn main() {} diff --git a/tests/ui/consts/issue-50439.stderr b/tests/ui/consts/issue-50439.stderr new file mode 100644 index 000000000..3fbdf33b2 --- /dev/null +++ b/tests/ui/consts/issue-50439.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-50439.rs:25:22 + | +LL | let _ = [(); 0 - !!(<Bears<T> as ReflectDrop>::REFLECT_DROP) as usize]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/tests/ui/consts/issue-52023-array-size-pointer-cast.rs b/tests/ui/consts/issue-52023-array-size-pointer-cast.rs new file mode 100644 index 000000000..2249d9879 --- /dev/null +++ b/tests/ui/consts/issue-52023-array-size-pointer-cast.rs @@ -0,0 +1,3 @@ +fn main() { + let _ = [0; (&0 as *const i32) as usize]; //~ ERROR pointers cannot be cast to integers during const eval +} diff --git a/tests/ui/consts/issue-52023-array-size-pointer-cast.stderr b/tests/ui/consts/issue-52023-array-size-pointer-cast.stderr new file mode 100644 index 000000000..9a3d5716e --- /dev/null +++ b/tests/ui/consts/issue-52023-array-size-pointer-cast.stderr @@ -0,0 +1,11 @@ +error: pointers cannot be cast to integers during const eval + --> $DIR/issue-52023-array-size-pointer-cast.rs:2:17 + | +LL | let _ = [0; (&0 as *const i32) as usize]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: at compile-time, pointers do not have an integer value + = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior + +error: aborting due to previous error + diff --git a/tests/ui/consts/issue-52060.rs b/tests/ui/consts/issue-52060.rs new file mode 100644 index 000000000..13b914c03 --- /dev/null +++ b/tests/ui/consts/issue-52060.rs @@ -0,0 +1,7 @@ +// Regression test for https://github.com/rust-lang/rust/issues/52060 +// The compiler shouldn't ICE in this case +static A: &'static [u32] = &[1]; +static B: [u32; 1] = [0; A.len()]; +//~^ ERROR [E0013] + +fn main() {} diff --git a/tests/ui/consts/issue-52060.stderr b/tests/ui/consts/issue-52060.stderr new file mode 100644 index 000000000..95e5f2a82 --- /dev/null +++ b/tests/ui/consts/issue-52060.stderr @@ -0,0 +1,11 @@ +error[E0013]: constants cannot refer to statics + --> $DIR/issue-52060.rs:4:26 + | +LL | static B: [u32; 1] = [0; A.len()]; + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0013`. diff --git a/tests/ui/consts/issue-54224.rs b/tests/ui/consts/issue-54224.rs new file mode 100644 index 000000000..f1947933d --- /dev/null +++ b/tests/ui/consts/issue-54224.rs @@ -0,0 +1,12 @@ +const FOO: Option<&[[u8; 3]]> = Some(&[*b"foo"]); //~ ERROR temporary value dropped while borrowed + +use std::borrow::Cow; + +pub const X: [u8; 3] = *b"ABC"; +pub const Y: Cow<'static, [ [u8; 3] ]> = Cow::Borrowed(&[X]); + + +pub const Z: Cow<'static, [ [u8; 3] ]> = Cow::Borrowed(&[*b"ABC"]); +//~^ ERROR temporary value dropped while borrowed + +fn main() {} diff --git a/tests/ui/consts/issue-54224.stderr b/tests/ui/consts/issue-54224.stderr new file mode 100644 index 000000000..55fe55759 --- /dev/null +++ b/tests/ui/consts/issue-54224.stderr @@ -0,0 +1,23 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/issue-54224.rs:1:39 + | +LL | const FOO: Option<&[[u8; 3]]> = Some(&[*b"foo"]); + | ------^^^^^^^^^- + | | | | + | | | temporary value is freed at the end of this statement + | | creates a temporary value which is freed while still in use + | using this value as a constant requires that borrow lasts for `'static` + +error[E0716]: temporary value dropped while borrowed + --> $DIR/issue-54224.rs:9:57 + | +LL | pub const Z: Cow<'static, [ [u8; 3] ]> = Cow::Borrowed(&[*b"ABC"]); + | ---------------^^^^^^^^^- + | | | | + | | | temporary value is freed at the end of this statement + | | creates a temporary value which is freed while still in use + | using this value as a constant requires that borrow lasts for `'static` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/issue-54348.rs b/tests/ui/consts/issue-54348.rs new file mode 100644 index 000000000..5c38d7c42 --- /dev/null +++ b/tests/ui/consts/issue-54348.rs @@ -0,0 +1,7 @@ +// build-fail + +fn main() { + [1][0u64 as usize]; + [1][1.5 as usize]; //~ ERROR operation will panic + [1][1u64 as usize]; //~ ERROR operation will panic +} diff --git a/tests/ui/consts/issue-54348.stderr b/tests/ui/consts/issue-54348.stderr new file mode 100644 index 000000000..eb85f3498 --- /dev/null +++ b/tests/ui/consts/issue-54348.stderr @@ -0,0 +1,16 @@ +error: this operation will panic at runtime + --> $DIR/issue-54348.rs:5:5 + | +LL | [1][1.5 as usize]; + | ^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1 + | + = note: `#[deny(unconditional_panic)]` on by default + +error: this operation will panic at runtime + --> $DIR/issue-54348.rs:6:5 + | +LL | [1][1u64 as usize]; + | ^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1 + +error: aborting due to 2 previous errors + diff --git a/tests/ui/consts/issue-54387.rs b/tests/ui/consts/issue-54387.rs new file mode 100644 index 000000000..60e3a02f4 --- /dev/null +++ b/tests/ui/consts/issue-54387.rs @@ -0,0 +1,12 @@ +// check-pass + +pub struct GstRc { + _obj: *const (), + _borrowed: bool, +} + +const FOO: Option<GstRc> = None; + +fn main() { + let _meh = FOO; +} diff --git a/tests/ui/consts/issue-54954.rs b/tests/ui/consts/issue-54954.rs new file mode 100644 index 000000000..520bf508f --- /dev/null +++ b/tests/ui/consts/issue-54954.rs @@ -0,0 +1,19 @@ +const ARR_LEN: usize = Tt::const_val::<[i8; 123]>(); +//~^ ERROR E0790 + +trait Tt { + const fn const_val<T: Sized>() -> usize { + //~^ ERROR functions in traits cannot be declared const + core::mem::size_of::<T>() + } +} + +fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] { + //~^ constant + //~| constant + z +} + +fn main() { + let _ = f([1f32; ARR_LEN]); +} diff --git a/tests/ui/consts/issue-54954.stderr b/tests/ui/consts/issue-54954.stderr new file mode 100644 index 000000000..850558287 --- /dev/null +++ b/tests/ui/consts/issue-54954.stderr @@ -0,0 +1,34 @@ +error[E0379]: functions in traits cannot be declared const + --> $DIR/issue-54954.rs:5:5 + | +LL | const fn const_val<T: Sized>() -> usize { + | ^^^^^ functions in traits cannot be const + +error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type + --> $DIR/issue-54954.rs:1:24 + | +LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait +... +LL | / const fn const_val<T: Sized>() -> usize { +LL | | +LL | | core::mem::size_of::<T>() +LL | | } + | |_____- `Tt::const_val` defined here + +note: erroneous constant used + --> $DIR/issue-54954.rs:11:15 + | +LL | fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] { + | ^^^^^^^ + +note: erroneous constant used + --> $DIR/issue-54954.rs:11:34 + | +LL | fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] { + | ^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0379, E0790. +For more information about an error, try `rustc --explain E0379`. diff --git a/tests/ui/consts/issue-56164.rs b/tests/ui/consts/issue-56164.rs new file mode 100644 index 000000000..22c257d0b --- /dev/null +++ b/tests/ui/consts/issue-56164.rs @@ -0,0 +1,10 @@ +const fn foo() { (||{})() } +//~^ ERROR cannot call non-const closure + +const fn bad(input: fn()) { + input() + //~^ ERROR function pointer calls are not allowed +} + +fn main() { +} diff --git a/tests/ui/consts/issue-56164.stderr b/tests/ui/consts/issue-56164.stderr new file mode 100644 index 000000000..845b23d5d --- /dev/null +++ b/tests/ui/consts/issue-56164.stderr @@ -0,0 +1,31 @@ +error[E0015]: cannot call non-const closure in constant functions + --> $DIR/issue-56164.rs:1:18 + | +LL | const fn foo() { (||{})() } + | ^^^^^^^^ + | + = note: closures need an RFC before allowed to be called in constant functions + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + +error: function pointer calls are not allowed in constant functions + --> $DIR/issue-56164.rs:5:5 + | +LL | input() + | ^^^^^^^ + +note: erroneous constant used + --> $DIR/issue-56164.rs:1:18 + | +LL | const fn foo() { (||{})() } + | ^^^^^^ + +note: erroneous constant used + --> $DIR/issue-56164.rs:1:18 + | +LL | const fn foo() { (||{})() } + | ^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/issue-58435-ice-with-assoc-const.rs b/tests/ui/consts/issue-58435-ice-with-assoc-const.rs new file mode 100644 index 000000000..fac727d2d --- /dev/null +++ b/tests/ui/consts/issue-58435-ice-with-assoc-const.rs @@ -0,0 +1,18 @@ +// run-pass +// The const-evaluator was at one point ICE'ing while trying to +// evaluate the body of `fn id` during the `s.id()` call in main. + +struct S<T>(T); + +impl<T> S<T> { + const ID: fn(&S<T>) -> &S<T> = |s| s; + pub fn id(&self) -> &Self { + Self::ID(self) // This, plus call below ... + } +} + +fn main() { + let s = S(10u32); + assert!(S::<u32>::ID(&s).0 == 10); // Works fine + assert!(s.id().0 == 10); // ... causes compiler to panic +} diff --git a/tests/ui/consts/issue-62045.rs b/tests/ui/consts/issue-62045.rs new file mode 100644 index 000000000..5abed374a --- /dev/null +++ b/tests/ui/consts/issue-62045.rs @@ -0,0 +1,5 @@ +// check-pass + +fn main() { + assert_eq!(&mut [0; 1][..], &mut []); +} diff --git a/tests/ui/consts/issue-63226.rs b/tests/ui/consts/issue-63226.rs new file mode 100644 index 000000000..deec44990 --- /dev/null +++ b/tests/ui/consts/issue-63226.rs @@ -0,0 +1,12 @@ +// aux-build:issue-63226.rs +// compile-flags:--extern issue_63226 +// edition:2018 +// build-pass +// A regression test for issue #63226. +// Checks if `const fn` is marked as reachable. + +use issue_63226::VTable; + +static ICE_ICE:&'static VTable=VTable::vtable(); + +fn main() {} diff --git a/tests/ui/consts/issue-63952.32bit.stderr b/tests/ui/consts/issue-63952.32bit.stderr new file mode 100644 index 000000000..755c7fb7d --- /dev/null +++ b/tests/ui/consts/issue-63952.32bit.stderr @@ -0,0 +1,14 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/issue-63952.rs:17:1 + | +LL | const SLICE_WAY_TOO_LONG: &[u8] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾─alloc4──╼ ff ff ff ff │ ╾──╼.... + } + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/issue-63952.64bit.stderr b/tests/ui/consts/issue-63952.64bit.stderr new file mode 100644 index 000000000..abdb9a4f7 --- /dev/null +++ b/tests/ui/consts/issue-63952.64bit.stderr @@ -0,0 +1,14 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/issue-63952.rs:17:1 + | +LL | const SLICE_WAY_TOO_LONG: &[u8] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾───────alloc4────────╼ ff ff ff ff ff ff ff ff │ ╾──────╼........ + } + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/issue-63952.rs b/tests/ui/consts/issue-63952.rs new file mode 100644 index 000000000..5c83e6f45 --- /dev/null +++ b/tests/ui/consts/issue-63952.rs @@ -0,0 +1,27 @@ +// Regression test for #63952, shouldn't hang. +// stderr-per-bitwidth + +#[repr(C)] +#[derive(Copy, Clone)] +struct SliceRepr { + ptr: *const u8, + len: usize, +} + +union SliceTransmute { + repr: SliceRepr, + slice: &'static [u8], +} + +// bad slice: length too big to even exist anywhere +const SLICE_WAY_TOO_LONG: &[u8] = unsafe { //~ ERROR: it is undefined behavior to use this value + SliceTransmute { + repr: SliceRepr { + ptr: &42, + len: usize::MAX, + }, + } + .slice +}; + +fn main() {} diff --git a/tests/ui/consts/issue-64059.rs b/tests/ui/consts/issue-64059.rs new file mode 100644 index 000000000..02c8b7250 --- /dev/null +++ b/tests/ui/consts/issue-64059.rs @@ -0,0 +1,10 @@ +// revisions: noopt opt opt_with_overflow_checks +//[noopt]compile-flags: -C opt-level=0 +//[opt]compile-flags: -O +//[opt_with_overflow_checks]compile-flags: -C overflow-checks=on -O + +// run-pass + +fn main() { + let _ = -(-0.0); +} diff --git a/tests/ui/consts/issue-64506.rs b/tests/ui/consts/issue-64506.rs new file mode 100644 index 000000000..db3e85a7b --- /dev/null +++ b/tests/ui/consts/issue-64506.rs @@ -0,0 +1,20 @@ +// check-pass + +#[derive(Copy, Clone)] +pub struct ChildStdin { + inner: AnonPipe, +} + +#[derive(Copy, Clone)] +enum AnonPipe {} + +const FOO: () = { + union Foo { + a: ChildStdin, + b: (), + } + let x = unsafe { Foo { b: () }.a }; + let x = &x.inner; +}; + +fn main() {} diff --git a/tests/ui/consts/issue-64662.rs b/tests/ui/consts/issue-64662.rs new file mode 100644 index 000000000..e3a8c8583 --- /dev/null +++ b/tests/ui/consts/issue-64662.rs @@ -0,0 +1,10 @@ +enum Foo { + A = foo(), //~ ERROR: type annotations needed + B = foo(), //~ ERROR: type annotations needed +} + +const fn foo<T>() -> isize { + 0 +} + +fn main() {} diff --git a/tests/ui/consts/issue-64662.stderr b/tests/ui/consts/issue-64662.stderr new file mode 100644 index 000000000..21a419711 --- /dev/null +++ b/tests/ui/consts/issue-64662.stderr @@ -0,0 +1,25 @@ +error[E0282]: type annotations needed + --> $DIR/issue-64662.rs:2:9 + | +LL | A = foo(), + | ^^^ cannot infer type of the type parameter `T` declared on the function `foo` + | +help: consider specifying the generic argument + | +LL | A = foo::<T>(), + | +++++ + +error[E0282]: type annotations needed + --> $DIR/issue-64662.rs:3:9 + | +LL | B = foo(), + | ^^^ cannot infer type of the type parameter `T` declared on the function `foo` + | +help: consider specifying the generic argument + | +LL | B = foo::<T>(), + | +++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/consts/issue-65348.rs b/tests/ui/consts/issue-65348.rs new file mode 100644 index 000000000..5eafa831d --- /dev/null +++ b/tests/ui/consts/issue-65348.rs @@ -0,0 +1,23 @@ +// check-pass + +struct Generic<T>(T); + +impl<T> Generic<T> { + const ARRAY: [T; 0] = []; + const NEWTYPE_ARRAY: Generic<[T; 0]> = Generic([]); + const ARRAY_FIELD: Generic<(i32, [T; 0])> = Generic((0, [])); +} + +pub const fn array<T>() -> &'static T { + &Generic::<T>::ARRAY[0] +} + +pub const fn newtype_array<T>() -> &'static T { + &Generic::<T>::NEWTYPE_ARRAY.0[0] +} + +pub const fn array_field<T>() -> &'static T { + &(Generic::<T>::ARRAY_FIELD.0).1[0] +} + +fn main() {} diff --git a/tests/ui/consts/issue-66342.rs b/tests/ui/consts/issue-66342.rs new file mode 100644 index 000000000..417f69041 --- /dev/null +++ b/tests/ui/consts/issue-66342.rs @@ -0,0 +1,12 @@ +// check-pass +// only-x86_64 + +// Checks that the compiler does not actually try to allocate 4 TB during compilation and OOM crash. + +fn foo() -> [u8; 4 * 1024 * 1024 * 1024 * 1024] { + unimplemented!() +} + +fn main() { + foo(); +} diff --git a/tests/ui/consts/issue-66345.rs b/tests/ui/consts/issue-66345.rs new file mode 100644 index 000000000..4971d9647 --- /dev/null +++ b/tests/ui/consts/issue-66345.rs @@ -0,0 +1,24 @@ +// run-pass +// compile-flags: -Z mir-opt-level=4 + +// Checks that the compiler does not ICE when passing references to field of by-value struct +// with -Z mir-opt-level=4 + +fn do_nothing(_: &()) {} + +pub struct Foo { + bar: (), +} + +pub fn by_value_1(foo: Foo) { + do_nothing(&foo.bar); +} + +pub fn by_value_2<T>(foo: Foo) { + do_nothing(&foo.bar); +} + +fn main() { + by_value_1(Foo { bar: () }); + by_value_2::<()>(Foo { bar: () }); +} diff --git a/tests/ui/consts/issue-66397.rs b/tests/ui/consts/issue-66397.rs new file mode 100644 index 000000000..1b4aff43b --- /dev/null +++ b/tests/ui/consts/issue-66397.rs @@ -0,0 +1,8 @@ +// check-pass +// only-x86_64 + +// Checks that the compiler does not actually try to allocate 4 TB during compilation and OOM crash. + +fn main() { + [0; 4 * 1024 * 1024 * 1024 * 1024]; +} diff --git a/tests/ui/consts/issue-66693-panic-in-array-len.rs b/tests/ui/consts/issue-66693-panic-in-array-len.rs new file mode 100644 index 000000000..fc0dcd7a4 --- /dev/null +++ b/tests/ui/consts/issue-66693-panic-in-array-len.rs @@ -0,0 +1,15 @@ +// This is a separate test from `issue-66693.rs` because array lengths are evaluated +// in a separate stage before `const`s and `statics` and so the error below is hit and +// the compiler exits before generating errors for the others. + +fn main() { + let _ = [0i32; panic!(2f32)]; + //~^ ERROR: argument to `panic!()` in a const context must have type `&str` + + // ensure that conforming panics are handled correctly + let _ = [false; panic!()]; + //~^ ERROR: evaluation of constant value failed + + // typechecking halts before getting to this one + let _ = ['a', panic!("panic in array len")]; +} diff --git a/tests/ui/consts/issue-66693-panic-in-array-len.stderr b/tests/ui/consts/issue-66693-panic-in-array-len.stderr new file mode 100644 index 000000000..1585ea317 --- /dev/null +++ b/tests/ui/consts/issue-66693-panic-in-array-len.stderr @@ -0,0 +1,19 @@ +error: argument to `panic!()` in a const context must have type `&str` + --> $DIR/issue-66693-panic-in-array-len.rs:6:20 + | +LL | let _ = [0i32; panic!(2f32)]; + | ^^^^^^^^^^^^ + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/issue-66693-panic-in-array-len.rs:10:21 + | +LL | let _ = [false; panic!()]; + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/issue-66693-panic-in-array-len.rs:10:21 + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/issue-66693.rs b/tests/ui/consts/issue-66693.rs new file mode 100644 index 000000000..df45d01ec --- /dev/null +++ b/tests/ui/consts/issue-66693.rs @@ -0,0 +1,23 @@ +// Tests that the compiler does not ICE when const-evaluating a `panic!()` invocation with a +// non-`&str` argument. + +const _: () = panic!(1); +//~^ ERROR: argument to `panic!()` in a const context must have type `&str` + +static _FOO: () = panic!(true); +//~^ ERROR: argument to `panic!()` in a const context must have type `&str` + +const fn _foo() { + panic!(&1); + //~^ ERROR: argument to `panic!()` in a const context must have type `&str` +} + +// ensure that conforming panics don't cause an error +const _: () = panic!(); +static _BAR: () = panic!("panic in static"); + +const fn _bar() { + panic!("panic in const fn"); +} + +fn main() {} diff --git a/tests/ui/consts/issue-66693.stderr b/tests/ui/consts/issue-66693.stderr new file mode 100644 index 000000000..e9a3fced6 --- /dev/null +++ b/tests/ui/consts/issue-66693.stderr @@ -0,0 +1,38 @@ +error: argument to `panic!()` in a const context must have type `&str` + --> $DIR/issue-66693.rs:4:15 + | +LL | const _: () = panic!(1); + | ^^^^^^^^^ + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: argument to `panic!()` in a const context must have type `&str` + --> $DIR/issue-66693.rs:7:19 + | +LL | static _FOO: () = panic!(true); + | ^^^^^^^^^^^^ + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: argument to `panic!()` in a const context must have type `&str` + --> $DIR/issue-66693.rs:11:5 + | +LL | panic!(&1); + | ^^^^^^^^^^ + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: erroneous constant used + --> $DIR/issue-66693.rs:11:12 + | +LL | panic!(&1); + | ^^ + +note: erroneous constant used + --> $DIR/issue-66693.rs:11:12 + | +LL | panic!(&1); + | ^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/consts/issue-66787.rs b/tests/ui/consts/issue-66787.rs new file mode 100644 index 000000000..612b795eb --- /dev/null +++ b/tests/ui/consts/issue-66787.rs @@ -0,0 +1,39 @@ +// build-pass +// compile-flags: --crate-type lib + +// Regression test for ICE which occurred when const propagating an enum with three variants +// one of which is uninhabited. + +pub enum ApiError {} +#[allow(dead_code)] +pub struct TokioError { + b: bool, +} +pub enum Error { + Api { + source: ApiError, + }, + Ethereum, + Tokio { + source: TokioError, + }, +} +struct Api; +impl IntoError<Error> for Api +{ + type Source = ApiError; + fn into_error(self, error: Self::Source) -> Error { + Error::Api { + source: (|v| v)(error), + } + } +} + +pub trait IntoError<E> +{ + /// The underlying error + type Source; + + /// Combine the information to produce the error + fn into_error(self, source: Self::Source) -> E; +} diff --git a/tests/ui/consts/issue-67529.rs b/tests/ui/consts/issue-67529.rs new file mode 100644 index 000000000..dd24c2d27 --- /dev/null +++ b/tests/ui/consts/issue-67529.rs @@ -0,0 +1,11 @@ +// compile-flags: -Z mir-opt-level=3 +// run-pass + +struct Baz<T: ?Sized> { + a: T +} + +fn main() { + let d : Baz<[i32; 4]> = Baz { a: [1,2,3,4] }; + assert_eq!([1, 2, 3, 4], d.a); +} diff --git a/tests/ui/consts/issue-67640.rs b/tests/ui/consts/issue-67640.rs new file mode 100644 index 000000000..4c71a2e02 --- /dev/null +++ b/tests/ui/consts/issue-67640.rs @@ -0,0 +1,24 @@ +// compile-flags: -Z mir-opt-level=4 +// run-pass + +struct X { + x: isize +} + +fn f1(a: &mut X, b: &mut isize, c: isize) -> isize { + let r = a.x + *b + c; + a.x = 0; + *b = 10; + return r; +} + +fn f2<F>(a: isize, f: F) -> isize where F: FnOnce(isize) { f(1); return a; } + +pub fn main() { + let mut a = X {x: 1}; + let mut b = 2; + let c = 3; + assert_eq!(f1(&mut a, &mut b, c), 6); + assert_eq!(a.x, 0); + assert_eq!(f2(a.x, |_| a.x = 50), 0); +} diff --git a/tests/ui/consts/issue-67641.rs b/tests/ui/consts/issue-67641.rs new file mode 100644 index 000000000..e5a74f156 --- /dev/null +++ b/tests/ui/consts/issue-67641.rs @@ -0,0 +1,24 @@ +// compile-flags: -Z mir-opt-level=3 +// run-pass + +use std::cell::Cell; + +#[derive(Debug)] +struct B<'a> { + a: [Cell<Option<&'a B<'a>>>; 2] +} + +impl<'a> B<'a> { + fn new() -> B<'a> { + B { a: [Cell::new(None), Cell::new(None)] } + } +} + +fn f() { + let b2 = B::new(); + b2.a[0].set(Some(&b2)); +} + +fn main() { + f(); +} diff --git a/tests/ui/consts/issue-67696-const-prop-ice.rs b/tests/ui/consts/issue-67696-const-prop-ice.rs new file mode 100644 index 000000000..ad52608b3 --- /dev/null +++ b/tests/ui/consts/issue-67696-const-prop-ice.rs @@ -0,0 +1,20 @@ +// check-pass +// compile-flags: --emit=mir,link +// Checks that we don't ICE due to attempting to run const prop +// on a function with unsatisifable 'where' clauses + +#![allow(unused)] + +trait A { + fn foo(&self) -> Self where Self: Copy; +} + +impl A for [fn(&())] { + fn foo(&self) -> Self where Self: Copy { *(&[] as &[_]) } +} + +impl A for i32 { + fn foo(&self) -> Self { 3 } +} + +fn main() {} diff --git a/tests/ui/consts/issue-67862.rs b/tests/ui/consts/issue-67862.rs new file mode 100644 index 000000000..b9e96a87f --- /dev/null +++ b/tests/ui/consts/issue-67862.rs @@ -0,0 +1,18 @@ +// compile-flags: -Z mir-opt-level=3 +// run-pass + +fn e220() -> (i64, i64) { + #[inline(never)] + fn get_displacement() -> [i64; 2] { + [139776, 963904] + } + + let res = get_displacement(); + match (&res[0], &res[1]) { + (arg0, arg1) => (*arg0, *arg1), + } +} + +fn main() { + assert_eq!(e220(), (139776, 963904)); +} diff --git a/tests/ui/consts/issue-68264-overflow.rs b/tests/ui/consts/issue-68264-overflow.rs new file mode 100644 index 000000000..8f21e0648 --- /dev/null +++ b/tests/ui/consts/issue-68264-overflow.rs @@ -0,0 +1,43 @@ +// check-pass +// compile-flags: --emit=mir,link +// Regression test for issue #68264 +// Checks that we don't encounter overflow +// when running const-prop on functions with +// complicated bounds +pub trait Query {} + +pub trait AsQuery { + type Query: Query; +} +pub trait Table: AsQuery + Sized {} + +pub trait LimitDsl { + type Output; +} + +pub(crate) trait LoadQuery<Conn, U>: RunQueryDsl<Conn> {} + +impl<T: Query> AsQuery for T { + type Query = Self; +} + +impl<T> LimitDsl for T +where + T: Table, + T::Query: LimitDsl, +{ + type Output = <T::Query as LimitDsl>::Output; +} + +pub(crate) trait RunQueryDsl<Conn>: Sized { + fn first<U>(self, _conn: &Conn) -> U + where + Self: LimitDsl, + Self::Output: LoadQuery<Conn, U>, + { + // Overflow is caused by this function body + unimplemented!() + } +} + +fn main() {} diff --git a/tests/ui/consts/issue-68542-closure-in-array-len.rs b/tests/ui/consts/issue-68542-closure-in-array-len.rs new file mode 100644 index 000000000..37958e791 --- /dev/null +++ b/tests/ui/consts/issue-68542-closure-in-array-len.rs @@ -0,0 +1,9 @@ +// Regression test for issue #68542 +// Tests that we don't ICE when a closure appears +// in the length part of an array. + +struct Bug { + a: [(); (|| { 0 })()] //~ ERROR cannot call non-const closure +} + +fn main() {} diff --git a/tests/ui/consts/issue-68542-closure-in-array-len.stderr b/tests/ui/consts/issue-68542-closure-in-array-len.stderr new file mode 100644 index 000000000..d23513ed7 --- /dev/null +++ b/tests/ui/consts/issue-68542-closure-in-array-len.stderr @@ -0,0 +1,13 @@ +error[E0015]: cannot call non-const closure in constants + --> $DIR/issue-68542-closure-in-array-len.rs:6:13 + | +LL | a: [(); (|| { 0 })()] + | ^^^^^^^^^^^^ + | + = note: closures need an RFC before allowed to be called in constants + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/issue-68684.rs b/tests/ui/consts/issue-68684.rs new file mode 100644 index 000000000..c98f199b6 --- /dev/null +++ b/tests/ui/consts/issue-68684.rs @@ -0,0 +1,15 @@ +// check-pass + +enum _Enum { + A(), +} + +type _E = _Enum; + +const fn _a() -> _Enum { + _E::A() +} + +const _A: _Enum = _a(); + +fn main() {} diff --git a/tests/ui/consts/issue-69191-ice-on-uninhabited-enum-field.rs b/tests/ui/consts/issue-69191-ice-on-uninhabited-enum-field.rs new file mode 100644 index 000000000..5b7c7be42 --- /dev/null +++ b/tests/ui/consts/issue-69191-ice-on-uninhabited-enum-field.rs @@ -0,0 +1,91 @@ +// build-pass +// +// (this is deliberately *not* check-pass; I have confirmed that the bug in +// question does not replicate when one uses `cargo check` alone.) + +pub enum Void {} + +enum UninhabitedUnivariant { + _Variant(Void), +} + +enum UninhabitedMultivariant2 { + _Variant(Void), + _Warriont(Void), +} + +enum UninhabitedMultivariant3 { + _Variant(Void), + _Warriont(Void), + _Worrynot(Void), +} + +#[repr(C)] +enum UninhabitedUnivariantC { + _Variant(Void), +} + +#[repr(i32)] +enum UninhabitedUnivariant32 { + _Variant(Void), +} + +fn main() { + let _seed: UninhabitedUnivariant = None.unwrap(); + match _seed { + UninhabitedUnivariant::_Variant(_x) => {} + } + + let _seed: UninhabitedMultivariant2 = None.unwrap(); + match _seed { + UninhabitedMultivariant2::_Variant(_x) => {} + UninhabitedMultivariant2::_Warriont(_x) => {} + } + + let _seed: UninhabitedMultivariant2 = None.unwrap(); + match _seed { + UninhabitedMultivariant2::_Variant(_x) => {} + _ => {} + } + + let _seed: UninhabitedMultivariant2 = None.unwrap(); + match _seed { + UninhabitedMultivariant2::_Warriont(_x) => {} + _ => {} + } + + let _seed: UninhabitedMultivariant3 = None.unwrap(); + match _seed { + UninhabitedMultivariant3::_Variant(_x) => {} + UninhabitedMultivariant3::_Warriont(_x) => {} + UninhabitedMultivariant3::_Worrynot(_x) => {} + } + + let _seed: UninhabitedMultivariant3 = None.unwrap(); + match _seed { + UninhabitedMultivariant3::_Variant(_x) => {} + _ => {} + } + + let _seed: UninhabitedMultivariant3 = None.unwrap(); + match _seed { + UninhabitedMultivariant3::_Warriont(_x) => {} + _ => {} + } + + let _seed: UninhabitedMultivariant3 = None.unwrap(); + match _seed { + UninhabitedMultivariant3::_Worrynot(_x) => {} + _ => {} + } + + let _seed: UninhabitedUnivariantC = None.unwrap(); + match _seed { + UninhabitedUnivariantC::_Variant(_x) => {} + } + + let _seed: UninhabitedUnivariant32 = None.unwrap(); + match _seed { + UninhabitedUnivariant32::_Variant(_x) => {} + } +} diff --git a/tests/ui/consts/issue-69310-array-size-lit-wrong-ty.rs b/tests/ui/consts/issue-69310-array-size-lit-wrong-ty.rs new file mode 100644 index 000000000..f0d5fea8e --- /dev/null +++ b/tests/ui/consts/issue-69310-array-size-lit-wrong-ty.rs @@ -0,0 +1,11 @@ +// This is a regression test for #69310, which was injected by #68118. +// The issue here was that as a performance optimization, +// we call the query `lit_to_const(input);`. +// However, the literal `input.lit` would not be of the type expected by `input.ty`. +// As a result, we immediately called `bug!(...)` instead of bubbling up the problem +// so that it could be handled by the caller of `lit_to_const` (`from_anon_const`). + +fn main() {} + +const A: [(); 0.1] = [()]; //~ ERROR mismatched types +const B: [(); b"a"] = [()]; //~ ERROR mismatched types diff --git a/tests/ui/consts/issue-69310-array-size-lit-wrong-ty.stderr b/tests/ui/consts/issue-69310-array-size-lit-wrong-ty.stderr new file mode 100644 index 000000000..7078b4bd7 --- /dev/null +++ b/tests/ui/consts/issue-69310-array-size-lit-wrong-ty.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/issue-69310-array-size-lit-wrong-ty.rs:10:15 + | +LL | const A: [(); 0.1] = [()]; + | ^^^ expected `usize`, found floating-point number + +error[E0308]: mismatched types + --> $DIR/issue-69310-array-size-lit-wrong-ty.rs:11:15 + | +LL | const B: [(); b"a"] = [()]; + | ^^^^ expected `usize`, found `&[u8; 1]` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/issue-69312.rs b/tests/ui/consts/issue-69312.rs new file mode 100644 index 000000000..413c67520 --- /dev/null +++ b/tests/ui/consts/issue-69312.rs @@ -0,0 +1,10 @@ +// build-pass + +// Verify that the compiler doesn't ICE during const prop while evaluating the index operation. + +#![allow(unconditional_panic)] + +fn main() { + let cols = [0u32; 0]; + cols[0]; +} diff --git a/tests/ui/consts/issue-69488.rs b/tests/ui/consts/issue-69488.rs new file mode 100644 index 000000000..46546eada --- /dev/null +++ b/tests/ui/consts/issue-69488.rs @@ -0,0 +1,34 @@ +// run-pass + +#![feature(const_ptr_write)] +#![feature(const_mut_refs)] + +// Or, equivalently: `MaybeUninit`. +pub union BagOfBits<T: Copy> { + uninit: (), + _storage: T, +} + +pub const fn make_1u8_bag<T: Copy>() -> BagOfBits<T> { + assert!(core::mem::size_of::<T>() >= 1); + let mut bag = BagOfBits { uninit: () }; + unsafe { (&mut bag as *mut _ as *mut u8).write(1); }; + bag +} + +pub fn check_bag<T: Copy>(bag: &BagOfBits<T>) { + let val = unsafe { (bag as *const _ as *const u8).read() }; + assert_eq!(val, 1); +} + +fn main() { + check_bag(&make_1u8_bag::<[usize; 1]>()); // Fine + check_bag(&make_1u8_bag::<usize>()); // Fine + + const CONST_ARRAY_BAG: BagOfBits<[usize; 1]> = make_1u8_bag(); + check_bag(&CONST_ARRAY_BAG); // Fine. + const CONST_USIZE_BAG: BagOfBits<usize> = make_1u8_bag(); + + // Used to panic since CTFE would make the entire `BagOfBits<usize>` uninit + check_bag(&CONST_USIZE_BAG); +} diff --git a/tests/ui/consts/issue-69532.rs b/tests/ui/consts/issue-69532.rs new file mode 100644 index 000000000..0a8917812 --- /dev/null +++ b/tests/ui/consts/issue-69532.rs @@ -0,0 +1,23 @@ +// run-pass + +const fn make_nans() -> (f64, f64, f32, f32) { + let nan1: f64 = unsafe { std::mem::transmute(0x7FF0_0001_0000_0001u64) }; + let nan2: f64 = unsafe { std::mem::transmute(0x7FF0_0000_0000_0001u64) }; + + let nan1_32 = nan1 as f32; + let nan2_32 = nan2 as f32; + + (nan1, nan2, nan1_32, nan2_32) +} + +static NANS: (f64, f64, f32, f32) = make_nans(); + +fn main() { + let (nan1, nan2, nan1_32, nan2_32) = NANS; + + assert!(nan1.is_nan()); + assert!(nan2.is_nan()); + + assert!(nan1_32.is_nan()); + assert!(nan2_32.is_nan()); +} diff --git a/tests/ui/consts/issue-6991.rs b/tests/ui/consts/issue-6991.rs new file mode 100644 index 000000000..f00cd9aef --- /dev/null +++ b/tests/ui/consts/issue-6991.rs @@ -0,0 +1,8 @@ +// check-pass +#![allow(dead_code)] +#![allow(non_upper_case_globals)] + +static x: &'static usize = &1; +static y: usize = *x; + +fn main() {} diff --git a/tests/ui/consts/issue-70773-mir-typeck-lt-norm.rs b/tests/ui/consts/issue-70773-mir-typeck-lt-norm.rs new file mode 100644 index 000000000..dd56faa31 --- /dev/null +++ b/tests/ui/consts/issue-70773-mir-typeck-lt-norm.rs @@ -0,0 +1,16 @@ +// run-pass + +const HASH_LEN: usize = 20; +struct Hash(#[allow(unused_tuple_struct_fields)] [u8; HASH_LEN]); +fn init_hash(_: &mut [u8; HASH_LEN]) {} + +fn foo<'a>() -> &'a () { + Hash([0; HASH_LEN]); + init_hash(&mut [0; HASH_LEN]); + let (_array,) = ([0; HASH_LEN],); + &() +} + +fn main() { + foo(); +} diff --git a/tests/ui/consts/issue-70942-trait-vs-impl-mismatch.rs b/tests/ui/consts/issue-70942-trait-vs-impl-mismatch.rs new file mode 100644 index 000000000..b65f53450 --- /dev/null +++ b/tests/ui/consts/issue-70942-trait-vs-impl-mismatch.rs @@ -0,0 +1,14 @@ +trait Nat { + const VALUE: usize; +} + +struct Zero; + +impl Nat for Zero { + const VALUE: i32 = 0; + //~^ ERROR implemented const `VALUE` has an incompatible type for trait +} + +fn main() { + let _: [i32; Zero::VALUE] = []; +} diff --git a/tests/ui/consts/issue-70942-trait-vs-impl-mismatch.stderr b/tests/ui/consts/issue-70942-trait-vs-impl-mismatch.stderr new file mode 100644 index 000000000..1597120fb --- /dev/null +++ b/tests/ui/consts/issue-70942-trait-vs-impl-mismatch.stderr @@ -0,0 +1,15 @@ +error[E0326]: implemented const `VALUE` has an incompatible type for trait + --> $DIR/issue-70942-trait-vs-impl-mismatch.rs:8:18 + | +LL | const VALUE: i32 = 0; + | ^^^ expected `usize`, found `i32` + | +note: type in trait + --> $DIR/issue-70942-trait-vs-impl-mismatch.rs:2:18 + | +LL | const VALUE: usize; + | ^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0326`. diff --git a/tests/ui/consts/issue-73976-monomorphic.rs b/tests/ui/consts/issue-73976-monomorphic.rs new file mode 100644 index 000000000..addcc1eaa --- /dev/null +++ b/tests/ui/consts/issue-73976-monomorphic.rs @@ -0,0 +1,37 @@ +// check-pass +// +// This test is complement to the test in issue-73976-polymorphic.rs. +// In that test we ensure that polymorphic use of type_id and type_name in patterns +// will be properly rejected. This test will ensure that monomorphic use of these +// would not be wrongly rejected in patterns. + +#![feature(const_type_id)] +#![feature(const_type_name)] +#![feature(const_trait_impl)] + +use std::any::{self, TypeId}; + +pub struct GetTypeId<T>(T); + +impl<T: 'static> GetTypeId<T> { + pub const VALUE: TypeId = TypeId::of::<T>(); +} + +const fn check_type_id<T: 'static>() -> bool { + GetTypeId::<T>::VALUE == GetTypeId::<usize>::VALUE +} + +pub struct GetTypeNameLen<T>(T); + +impl<T: 'static> GetTypeNameLen<T> { + pub const VALUE: usize = any::type_name::<T>().len(); +} + +const fn check_type_name_len<T: 'static>() -> bool { + matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<usize>::VALUE) +} + +fn main() { + assert!(check_type_id::<usize>()); + assert!(check_type_name_len::<usize>()); +} diff --git a/tests/ui/consts/issue-73976-polymorphic.rs b/tests/ui/consts/issue-73976-polymorphic.rs new file mode 100644 index 000000000..787462da9 --- /dev/null +++ b/tests/ui/consts/issue-73976-polymorphic.rs @@ -0,0 +1,40 @@ +// This test is from #73976. We previously did not check if a type is monomorphized +// before calculating its type id, which leads to the bizarre behaviour below that +// TypeId of a generic type does not match itself. +// +// This test case should either run-pass or be rejected at compile time. +// Currently we just disallow this usage and require pattern is monomorphic. + +#![feature(const_type_id)] +#![feature(const_type_name)] + +use std::any::{self, TypeId}; + +pub struct GetTypeId<T>(T); + +impl<T: 'static> GetTypeId<T> { + pub const VALUE: TypeId = TypeId::of::<T>(); +} + +const fn check_type_id<T: 'static>() -> bool { + matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE) + //~^ ERROR constant pattern depends on a generic parameter + //~| ERROR constant pattern depends on a generic parameter +} + +pub struct GetTypeNameLen<T>(T); + +impl<T: 'static> GetTypeNameLen<T> { + pub const VALUE: usize = any::type_name::<T>().len(); +} + +const fn check_type_name_len<T: 'static>() -> bool { + matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE) + //~^ ERROR constant pattern depends on a generic parameter + //~| ERROR constant pattern depends on a generic parameter +} + +fn main() { + assert!(check_type_id::<usize>()); + assert!(check_type_name_len::<usize>()); +} diff --git a/tests/ui/consts/issue-73976-polymorphic.stderr b/tests/ui/consts/issue-73976-polymorphic.stderr new file mode 100644 index 000000000..442ad23f2 --- /dev/null +++ b/tests/ui/consts/issue-73976-polymorphic.stderr @@ -0,0 +1,26 @@ +error: constant pattern depends on a generic parameter + --> $DIR/issue-73976-polymorphic.rs:20:37 + | +LL | matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE) + | ^^^^^^^^^^^^^^^^^^^^^ + +error: constant pattern depends on a generic parameter + --> $DIR/issue-73976-polymorphic.rs:32:42 + | +LL | matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: constant pattern depends on a generic parameter + --> $DIR/issue-73976-polymorphic.rs:20:37 + | +LL | matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE) + | ^^^^^^^^^^^^^^^^^^^^^ + +error: constant pattern depends on a generic parameter + --> $DIR/issue-73976-polymorphic.rs:32:42 + | +LL | matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/consts/issue-76064.rs b/tests/ui/consts/issue-76064.rs new file mode 100644 index 000000000..3c153ad72 --- /dev/null +++ b/tests/ui/consts/issue-76064.rs @@ -0,0 +1,3 @@ +struct Bug([u8; panic!("panic")]); //~ ERROR evaluation of constant value failed + +fn main() {} diff --git a/tests/ui/consts/issue-76064.stderr b/tests/ui/consts/issue-76064.stderr new file mode 100644 index 000000000..67b2e90db --- /dev/null +++ b/tests/ui/consts/issue-76064.stderr @@ -0,0 +1,11 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/issue-76064.rs:1:17 + | +LL | struct Bug([u8; panic!("panic")]); + | ^^^^^^^^^^^^^^^ the evaluated program panicked at 'panic', $DIR/issue-76064.rs:1:17 + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/issue-77062-large-zst-array.rs b/tests/ui/consts/issue-77062-large-zst-array.rs new file mode 100644 index 000000000..0566b802e --- /dev/null +++ b/tests/ui/consts/issue-77062-large-zst-array.rs @@ -0,0 +1,5 @@ +// build-pass + +fn main() { + let _ = &[(); usize::MAX]; +} diff --git a/tests/ui/consts/issue-78655.rs b/tests/ui/consts/issue-78655.rs new file mode 100644 index 000000000..82d2d7c21 --- /dev/null +++ b/tests/ui/consts/issue-78655.rs @@ -0,0 +1,10 @@ +const FOO: *const u32 = { + let x; + &x //~ ERROR E0381 +}; + +fn main() { + let FOO = FOO; + //~^ ERROR could not evaluate constant pattern + //~| ERROR could not evaluate constant pattern +} diff --git a/tests/ui/consts/issue-78655.stderr b/tests/ui/consts/issue-78655.stderr new file mode 100644 index 000000000..6b83fa0e5 --- /dev/null +++ b/tests/ui/consts/issue-78655.stderr @@ -0,0 +1,28 @@ +error[E0381]: used binding `x` isn't initialized + --> $DIR/issue-78655.rs:3:5 + | +LL | let x; + | - binding declared here but left uninitialized +LL | &x + | ^^ `x` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let x = 0; + | +++ + +error: could not evaluate constant pattern + --> $DIR/issue-78655.rs:7:9 + | +LL | let FOO = FOO; + | ^^^ + +error: could not evaluate constant pattern + --> $DIR/issue-78655.rs:7:9 + | +LL | let FOO = FOO; + | ^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/consts/issue-79137-monomorphic.rs b/tests/ui/consts/issue-79137-monomorphic.rs new file mode 100644 index 000000000..58e0c387f --- /dev/null +++ b/tests/ui/consts/issue-79137-monomorphic.rs @@ -0,0 +1,19 @@ +// check-pass + +// Verify that variant count intrinsic can still evaluate for types like `Option<T>`. + +#![feature(variant_count)] + +pub struct GetVariantCount<T>(T); + +impl<T> GetVariantCount<T> { + pub const VALUE: usize = std::mem::variant_count::<T>(); +} + +const fn check_variant_count<T>() -> bool { + matches!(GetVariantCount::<Option<T>>::VALUE, GetVariantCount::<Option<()>>::VALUE) +} + +fn main() { + assert!(check_variant_count::<()>()); +} diff --git a/tests/ui/consts/issue-79137-toogeneric.rs b/tests/ui/consts/issue-79137-toogeneric.rs new file mode 100644 index 000000000..456035458 --- /dev/null +++ b/tests/ui/consts/issue-79137-toogeneric.rs @@ -0,0 +1,19 @@ +// Test that `variant_count` only gets evaluated once the type is concrete enough. + +#![feature(variant_count)] + +pub struct GetVariantCount<T>(T); + +impl<T> GetVariantCount<T> { + pub const VALUE: usize = std::mem::variant_count::<T>(); +} + +const fn check_variant_count<T>() -> bool { + matches!(GetVariantCount::<T>::VALUE, GetVariantCount::<T>::VALUE) + //~^ ERROR constant pattern depends on a generic parameter + //~| ERROR constant pattern depends on a generic parameter +} + +fn main() { + assert!(check_variant_count::<Option<()>>()); +} diff --git a/tests/ui/consts/issue-79137-toogeneric.stderr b/tests/ui/consts/issue-79137-toogeneric.stderr new file mode 100644 index 000000000..579e6aa09 --- /dev/null +++ b/tests/ui/consts/issue-79137-toogeneric.stderr @@ -0,0 +1,14 @@ +error: constant pattern depends on a generic parameter + --> $DIR/issue-79137-toogeneric.rs:12:43 + | +LL | matches!(GetVariantCount::<T>::VALUE, GetVariantCount::<T>::VALUE) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: constant pattern depends on a generic parameter + --> $DIR/issue-79137-toogeneric.rs:12:43 + | +LL | matches!(GetVariantCount::<T>::VALUE, GetVariantCount::<T>::VALUE) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/consts/issue-79152-const-array-index.rs b/tests/ui/consts/issue-79152-const-array-index.rs new file mode 100644 index 000000000..95518e1bb --- /dev/null +++ b/tests/ui/consts/issue-79152-const-array-index.rs @@ -0,0 +1,11 @@ +// check-pass +// Regression test for issue #79152 +// +// Tests that we can index an array in a const function + +const fn foo() { + let mut array = [[0; 1]; 1]; + array[0][0] = 1; +} + +fn main() {} diff --git a/tests/ui/consts/issue-79690.64bit.stderr b/tests/ui/consts/issue-79690.64bit.stderr new file mode 100644 index 000000000..b8798a975 --- /dev/null +++ b/tests/ui/consts/issue-79690.64bit.stderr @@ -0,0 +1,14 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/issue-79690.rs:30:1 + | +LL | const G: Fat = unsafe { Transmute { t: FOO }.u }; + | ^^^^^^^^^^^^ constructing invalid value at .1: encountered a dangling reference (going beyond the bounds of its allocation) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾───────alloc3────────╼ ╾───────alloc4────────╼ │ ╾──────╼╾──────╼ + } + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/issue-79690.rs b/tests/ui/consts/issue-79690.rs new file mode 100644 index 000000000..56747bf5a --- /dev/null +++ b/tests/ui/consts/issue-79690.rs @@ -0,0 +1,33 @@ +// ignore-32bit +// This test gives a different error on 32-bit architectures. +// stderr-per-bitwidth + +union Transmute<T: Copy, U: Copy> { + t: T, + u: U, +} +trait Bar { + fn bar(&self) -> u32; +} +struct Foo { + foo: u32, + bar: bool, +} +impl Bar for Foo { + fn bar(&self) -> u32 { + self.foo + } +} +#[derive(Copy, Clone)] +struct Fat<'a>(&'a Foo, &'static VTable); +struct VTable { + size: Foo, +} +const FOO: &dyn Bar = &Foo { + foo: 128, + bar: false, +}; +const G: Fat = unsafe { Transmute { t: FOO }.u }; +//~^ ERROR it is undefined behavior to use this value + +fn main() {} diff --git a/tests/ui/consts/issue-83182.rs b/tests/ui/consts/issue-83182.rs new file mode 100644 index 000000000..b62f903bd --- /dev/null +++ b/tests/ui/consts/issue-83182.rs @@ -0,0 +1,9 @@ +// Strip out raw byte dumps to make comparison platform-independent: +// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" +// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" + +use std::mem; +struct MyStr(str); +const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; +//~^ ERROR: it is undefined behavior to use this value +fn main() {} diff --git a/tests/ui/consts/issue-83182.stderr b/tests/ui/consts/issue-83182.stderr new file mode 100644 index 000000000..1d578f910 --- /dev/null +++ b/tests/ui/consts/issue-83182.stderr @@ -0,0 +1,15 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/issue-83182.rs:7:1 + | +LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/issue-87046.rs b/tests/ui/consts/issue-87046.rs new file mode 100644 index 000000000..4b8f9f536 --- /dev/null +++ b/tests/ui/consts/issue-87046.rs @@ -0,0 +1,33 @@ +// Regression test for the ICE described in #87046. + +#![crate_type="lib"] +#![allow(unreachable_patterns)] + +#[derive(PartialEq, Eq)] +#[repr(transparent)] +pub struct Username(str); + +pub const ROOT_USER: &Username = Username::from_str("root"); + +impl Username { + pub const fn from_str(raw: &str) -> &Self { + union Transmute<'a> { + raw: &'a str, + typed: &'a Username, + } + + unsafe { Transmute { raw }.typed } + } + + pub const fn as_str(&self) -> &str { + &self.0 + } + + pub fn is_root(&self) -> bool { + match self { + ROOT_USER => true, + //~^ ERROR: cannot use unsized non-slice type `Username` in constant patterns + _ => false, + } + } +} diff --git a/tests/ui/consts/issue-87046.stderr b/tests/ui/consts/issue-87046.stderr new file mode 100644 index 000000000..d0dbb21ce --- /dev/null +++ b/tests/ui/consts/issue-87046.stderr @@ -0,0 +1,8 @@ +error: cannot use unsized non-slice type `Username` in constant patterns + --> $DIR/issue-87046.rs:28:13 + | +LL | ROOT_USER => true, + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/consts/issue-88071.rs b/tests/ui/consts/issue-88071.rs new file mode 100644 index 000000000..f58cdb594 --- /dev/null +++ b/tests/ui/consts/issue-88071.rs @@ -0,0 +1,18 @@ +// check-pass +// +// regression test for #88071 + +use std::collections::BTreeMap; + +pub struct CustomMap<K, V>(BTreeMap<K, V>); + +impl<K, V> CustomMap<K, V> +where + K: Ord, +{ + pub const fn new() -> Self { + CustomMap(BTreeMap::new()) + } +} + +fn main() {} diff --git a/tests/ui/consts/issue-88649.rs b/tests/ui/consts/issue-88649.rs new file mode 100644 index 000000000..43e562b5a --- /dev/null +++ b/tests/ui/consts/issue-88649.rs @@ -0,0 +1,18 @@ +// check-pass +#![crate_type = "lib"] + +enum Foo { + Variant1(bool), + Variant2(bool), +} + +const _: () = { + let mut n = 0; + while n < 2 { + match Foo::Variant1(true) { + Foo::Variant1(x) | Foo::Variant2(x) if x => {} + _ => {} + } + n += 1; + } +}; diff --git a/tests/ui/consts/issue-89088.rs b/tests/ui/consts/issue-89088.rs new file mode 100644 index 000000000..40cc665fb --- /dev/null +++ b/tests/ui/consts/issue-89088.rs @@ -0,0 +1,22 @@ +// Regression test for the ICE described in #89088. + +// check-pass + +#![allow(indirect_structural_match)] +use std::borrow::Cow; + +const FOO: &A = &A::Field(Cow::Borrowed("foo")); + +#[derive(PartialEq, Eq)] +enum A { + Field(Cow<'static, str>) +} + +fn main() { + let var = A::Field(Cow::Borrowed("bar")); + + match &var { + FOO => todo!(), + _ => todo!() + } +} diff --git a/tests/ui/consts/issue-90762.rs b/tests/ui/consts/issue-90762.rs new file mode 100644 index 000000000..78d387386 --- /dev/null +++ b/tests/ui/consts/issue-90762.rs @@ -0,0 +1,31 @@ +// run-pass +#![allow(unreachable_code)] + +use std::sync::atomic::{AtomicBool, Ordering, AtomicUsize}; + +struct Print(usize); + +impl Drop for Print { + fn drop(&mut self) { + println!("{}", self.0); + FOO[self.0].store(true, Ordering::Relaxed); + assert_eq!(BAR.fetch_sub(1, Ordering::Relaxed), self.0); + } +} + +const A: Print = Print(0); +const B: Print = Print(1); + +static FOO: [AtomicBool; 3] = + [AtomicBool::new(false), AtomicBool::new(false), AtomicBool::new(false)]; +static BAR: AtomicUsize = AtomicUsize::new(2); + +fn main() { + loop { + std::mem::forget(({ A }, B, Print(2), break)); + } + for (i, b) in FOO.iter().enumerate() { + assert!(b.load(Ordering::Relaxed), "{} not set", i); + } + assert_eq!(BAR.fetch_add(1, Ordering::Relaxed), usize::max_value()); +} diff --git a/tests/ui/consts/issue-90870.fixed b/tests/ui/consts/issue-90870.fixed new file mode 100644 index 000000000..df44689ef --- /dev/null +++ b/tests/ui/consts/issue-90870.fixed @@ -0,0 +1,37 @@ +// Regression test for issue #90870. + +// run-rustfix + +#![allow(dead_code)] + +const fn f(a: &u8, b: &u8) -> bool { + *a == *b + //~^ ERROR: cannot call non-const operator in constant functions [E0015] + //~| HELP: consider dereferencing here + //~| HELP: add `#![feature(const_trait_impl)]` +} + +const fn g(a: &&&&i64, b: &&&&i64) -> bool { + ****a == ****b + //~^ ERROR: cannot call non-const operator in constant functions [E0015] + //~| HELP: consider dereferencing here + //~| HELP: add `#![feature(const_trait_impl)]` +} + +const fn h(mut a: &[u8], mut b: &[u8]) -> bool { + while let ([l, at @ ..], [r, bt @ ..]) = (a, b) { + if *l == *r { + //~^ ERROR: cannot call non-const operator in constant functions [E0015] + //~| HELP: consider dereferencing here + //~| HELP: add `#![feature(const_trait_impl)]` + a = at; + b = bt; + } else { + return false; + } + } + + a.is_empty() && b.is_empty() +} + +fn main() {} diff --git a/tests/ui/consts/issue-90870.rs b/tests/ui/consts/issue-90870.rs new file mode 100644 index 000000000..676ac73c6 --- /dev/null +++ b/tests/ui/consts/issue-90870.rs @@ -0,0 +1,37 @@ +// Regression test for issue #90870. + +// run-rustfix + +#![allow(dead_code)] + +const fn f(a: &u8, b: &u8) -> bool { + a == b + //~^ ERROR: cannot call non-const operator in constant functions [E0015] + //~| HELP: consider dereferencing here + //~| HELP: add `#![feature(const_trait_impl)]` +} + +const fn g(a: &&&&i64, b: &&&&i64) -> bool { + a == b + //~^ ERROR: cannot call non-const operator in constant functions [E0015] + //~| HELP: consider dereferencing here + //~| HELP: add `#![feature(const_trait_impl)]` +} + +const fn h(mut a: &[u8], mut b: &[u8]) -> bool { + while let ([l, at @ ..], [r, bt @ ..]) = (a, b) { + if l == r { + //~^ ERROR: cannot call non-const operator in constant functions [E0015] + //~| HELP: consider dereferencing here + //~| HELP: add `#![feature(const_trait_impl)]` + a = at; + b = bt; + } else { + return false; + } + } + + a.is_empty() && b.is_empty() +} + +fn main() {} diff --git a/tests/ui/consts/issue-90870.stderr b/tests/ui/consts/issue-90870.stderr new file mode 100644 index 000000000..8825efd14 --- /dev/null +++ b/tests/ui/consts/issue-90870.stderr @@ -0,0 +1,42 @@ +error[E0015]: cannot call non-const operator in constant functions + --> $DIR/issue-90870.rs:8:5 + | +LL | a == b + | ^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable +help: consider dereferencing here + | +LL | *a == *b + | + + + +error[E0015]: cannot call non-const operator in constant functions + --> $DIR/issue-90870.rs:15:5 + | +LL | a == b + | ^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable +help: consider dereferencing here + | +LL | ****a == ****b + | ++++ ++++ + +error[E0015]: cannot call non-const operator in constant functions + --> $DIR/issue-90870.rs:23:12 + | +LL | if l == r { + | ^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable +help: consider dereferencing here + | +LL | if *l == *r { + | + + + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/issue-90878-2.rs b/tests/ui/consts/issue-90878-2.rs new file mode 100644 index 000000000..e5bcecce6 --- /dev/null +++ b/tests/ui/consts/issue-90878-2.rs @@ -0,0 +1,10 @@ + #![l=|x|[b;x ]] //~ ERROR unexpected expression: `|x| [b; x]` +//~^ ERROR cannot find attribute `l` in this scope + +// notice the space at the start, +// we can't attach any attributes to this file because it needs to be at the start + +// this example has been slightly modified (adding ]] at the end), so that it actually works here +// it still produces the same issue though + +fn main() {} diff --git a/tests/ui/consts/issue-90878-2.stderr b/tests/ui/consts/issue-90878-2.stderr new file mode 100644 index 000000000..71b8d21fb --- /dev/null +++ b/tests/ui/consts/issue-90878-2.stderr @@ -0,0 +1,14 @@ +error: unexpected expression: `|x| [b; x]` + --> $DIR/issue-90878-2.rs:1:7 + | +LL | #![l=|x|[b;x ]] + | ^^^^^^^^^ + +error: cannot find attribute `l` in this scope + --> $DIR/issue-90878-2.rs:1:5 + | +LL | #![l=|x|[b;x ]] + | ^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/consts/issue-90878-3.rs b/tests/ui/consts/issue-90878-3.rs new file mode 100644 index 000000000..0e36646eb --- /dev/null +++ b/tests/ui/consts/issue-90878-3.rs @@ -0,0 +1,6 @@ + +fn main() { + |x: usize| [0; x]; //~ ERROR attempt to use a non-constant value in a constant [E0435] + // (note the newline before "fn") +} +// ignore-tidy-leading-newlines diff --git a/tests/ui/consts/issue-90878-3.stderr b/tests/ui/consts/issue-90878-3.stderr new file mode 100644 index 000000000..1bcc0eb37 --- /dev/null +++ b/tests/ui/consts/issue-90878-3.stderr @@ -0,0 +1,11 @@ +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/issue-90878-3.rs:3:20 + | +LL | |x: usize| [0; x]; + | - ^ + | | + | this would need to be a `const` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0435`. diff --git a/tests/ui/consts/issue-90878.rs b/tests/ui/consts/issue-90878.rs new file mode 100644 index 000000000..43f6fe5f3 --- /dev/null +++ b/tests/ui/consts/issue-90878.rs @@ -0,0 +1,4 @@ + fn main() { + |x: usize| [0; x]; //~ ERROR attempt to use a non-constant value in a constant [E0435] + // (note the space before "fn") +} diff --git a/tests/ui/consts/issue-90878.stderr b/tests/ui/consts/issue-90878.stderr new file mode 100644 index 000000000..c038fc622 --- /dev/null +++ b/tests/ui/consts/issue-90878.stderr @@ -0,0 +1,11 @@ +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/issue-90878.rs:2:20 + | +LL | |x: usize| [0; x]; + | - ^ + | | + | this would need to be a `const` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0435`. diff --git a/tests/ui/consts/issue-91434.rs b/tests/ui/consts/issue-91434.rs new file mode 100644 index 000000000..001dc708f --- /dev/null +++ b/tests/ui/consts/issue-91434.rs @@ -0,0 +1,5 @@ +fn main() { + [9; [[9E; h]]]; + //~^ ERROR: expected at least one digit in exponent + //~| ERROR: cannot find value `h` in this scope [E0425] +} diff --git a/tests/ui/consts/issue-91434.stderr b/tests/ui/consts/issue-91434.stderr new file mode 100644 index 000000000..08d3ad770 --- /dev/null +++ b/tests/ui/consts/issue-91434.stderr @@ -0,0 +1,15 @@ +error: expected at least one digit in exponent + --> $DIR/issue-91434.rs:2:11 + | +LL | [9; [[9E; h]]]; + | ^^ + +error[E0425]: cannot find value `h` in this scope + --> $DIR/issue-91434.rs:2:15 + | +LL | [9; [[9E; h]]]; + | ^ not found in this scope + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/consts/issue-91560.fixed b/tests/ui/consts/issue-91560.fixed new file mode 100644 index 000000000..41b9d9573 --- /dev/null +++ b/tests/ui/consts/issue-91560.fixed @@ -0,0 +1,21 @@ +// Regression test for issue #91560. + +// run-rustfix + +#![allow(unused,non_upper_case_globals)] + +fn foo() { + const length: usize = 2; + //~^ HELP: consider using `const` + let arr = [0; length]; + //~^ ERROR: attempt to use a non-constant value in a constant [E0435] +} + +fn bar() { + const length: usize = 2; + //~^ HELP: consider using `const` + let arr = [0; length]; + //~^ ERROR: attempt to use a non-constant value in a constant [E0435] +} + +fn main() {} diff --git a/tests/ui/consts/issue-91560.rs b/tests/ui/consts/issue-91560.rs new file mode 100644 index 000000000..04592feb5 --- /dev/null +++ b/tests/ui/consts/issue-91560.rs @@ -0,0 +1,21 @@ +// Regression test for issue #91560. + +// run-rustfix + +#![allow(unused,non_upper_case_globals)] + +fn foo() { + let mut length: usize = 2; + //~^ HELP: consider using `const` + let arr = [0; length]; + //~^ ERROR: attempt to use a non-constant value in a constant [E0435] +} + +fn bar() { + let length: usize = 2; + //~^ HELP: consider using `const` + let arr = [0; length]; + //~^ ERROR: attempt to use a non-constant value in a constant [E0435] +} + +fn main() {} diff --git a/tests/ui/consts/issue-91560.stderr b/tests/ui/consts/issue-91560.stderr new file mode 100644 index 000000000..e1b5d4cac --- /dev/null +++ b/tests/ui/consts/issue-91560.stderr @@ -0,0 +1,21 @@ +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/issue-91560.rs:10:19 + | +LL | let mut length: usize = 2; + | -------------- help: consider using `const` instead of `let`: `const length` +LL | +LL | let arr = [0; length]; + | ^^^^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/issue-91560.rs:17:19 + | +LL | let length: usize = 2; + | ------------ help: consider using `const` instead of `let`: `const length` +LL | +LL | let arr = [0; length]; + | ^^^^^^ non-constant value + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0435`. diff --git a/tests/ui/consts/issue-94371.rs b/tests/ui/consts/issue-94371.rs new file mode 100644 index 000000000..de9ff730b --- /dev/null +++ b/tests/ui/consts/issue-94371.rs @@ -0,0 +1,16 @@ +// check-pass + +#![feature(const_swap)] +#![feature(const_mut_refs)] + +#[repr(C)] +struct Demo(u64, bool, u64, u32, u64, u64, u64); + +const C: (Demo, Demo) = { + let mut x = Demo(1, true, 3, 4, 5, 6, 7); + let mut y = Demo(10, false, 12, 13, 14, 15, 16); + std::mem::swap(&mut x, &mut y); + (x, y) +}; + +fn main() {} diff --git a/tests/ui/consts/issue-94675.rs b/tests/ui/consts/issue-94675.rs new file mode 100644 index 000000000..ce21ebdb9 --- /dev/null +++ b/tests/ui/consts/issue-94675.rs @@ -0,0 +1,15 @@ +#![feature(const_trait_impl, const_mut_refs)] + +struct Foo<'a> { + bar: &'a mut Vec<usize>, +} + +impl<'a> Foo<'a> { + const fn spam(&mut self, baz: &mut Vec<u32>) { + self.bar[0] = baz.len(); + //~^ the trait bound `Vec<usize>: ~const Index<_>` is not satisfied + //~| the trait bound `Vec<usize>: ~const IndexMut<usize>` is not satisfied + } +} + +fn main() {} diff --git a/tests/ui/consts/issue-94675.stderr b/tests/ui/consts/issue-94675.stderr new file mode 100644 index 000000000..f4683f7f5 --- /dev/null +++ b/tests/ui/consts/issue-94675.stderr @@ -0,0 +1,29 @@ +error[E0277]: the trait bound `Vec<usize>: ~const Index<_>` is not satisfied + --> $DIR/issue-94675.rs:9:9 + | +LL | self.bar[0] = baz.len(); + | ^^^^^^^^^^^ vector indices are of type `usize` or ranges of `usize` + | + = help: the trait `~const Index<_>` is not implemented for `Vec<usize>` +note: the trait `Index<_>` is implemented for `Vec<usize>`, but that implementation is not `const` + --> $DIR/issue-94675.rs:9:9 + | +LL | self.bar[0] = baz.len(); + | ^^^^^^^^^^^ + +error[E0277]: the trait bound `Vec<usize>: ~const IndexMut<usize>` is not satisfied + --> $DIR/issue-94675.rs:9:9 + | +LL | self.bar[0] = baz.len(); + | ^^^^^^^^^^^ vector indices are of type `usize` or ranges of `usize` + | + = help: the trait `~const IndexMut<usize>` is not implemented for `Vec<usize>` +note: the trait `IndexMut<usize>` is implemented for `Vec<usize>`, but that implementation is not `const` + --> $DIR/issue-94675.rs:9:9 + | +LL | self.bar[0] = baz.len(); + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/issue-96169.rs b/tests/ui/consts/issue-96169.rs new file mode 100644 index 000000000..14c0a1399 --- /dev/null +++ b/tests/ui/consts/issue-96169.rs @@ -0,0 +1,18 @@ +// check-pass +// compile-flags: -Zmir-opt-level=4 --emit=mir +#![allow(unused)] +fn a() -> usize { 0 } + +fn bar(_: u32) {} + +fn baz() -> *const dyn Fn(u32) { unimplemented!() } + +fn foo() { + match () { + _ if baz() == &bar as &dyn Fn(u32) => (), + () => (), + } +} + +fn main() { +} diff --git a/tests/ui/consts/issue-broken-mir.rs b/tests/ui/consts/issue-broken-mir.rs new file mode 100644 index 000000000..36f0ff921 --- /dev/null +++ b/tests/ui/consts/issue-broken-mir.rs @@ -0,0 +1,10 @@ +// run-pass + +// https://github.com/rust-lang/rust/issues/27918 + +fn main() { + match b" " { + b"1234" => {}, + _ => {}, + } +} diff --git a/tests/ui/consts/issue-miri-1910.rs b/tests/ui/consts/issue-miri-1910.rs new file mode 100644 index 000000000..29e0ea950 --- /dev/null +++ b/tests/ui/consts/issue-miri-1910.rs @@ -0,0 +1,12 @@ +// error-pattern unable to turn pointer into raw bytes +// normalize-stderr-test: "alloc[0-9]+\+0x[a-z0-9]+" -> "ALLOC" +#![feature(const_ptr_read)] + +const C: () = unsafe { + let foo = Some(&42 as *const i32); + let one_and_a_half_pointers = std::mem::size_of::<*const i32>()/2*3; + (&foo as *const _ as *const u8).add(one_and_a_half_pointers).read(); +}; + +fn main() { +} diff --git a/tests/ui/consts/issue-miri-1910.stderr b/tests/ui/consts/issue-miri-1910.stderr new file mode 100644 index 000000000..61865b1da --- /dev/null +++ b/tests/ui/consts/issue-miri-1910.stderr @@ -0,0 +1,20 @@ +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | + = note: unable to copy parts of a pointer from memory at ALLOC + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported +note: inside `std::ptr::read::<u8>` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL +note: inside `ptr::const_ptr::<impl *const u8>::read` + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL +note: inside `C` + --> $DIR/issue-miri-1910.rs:8:5 + | +LL | (&foo as *const _ as *const u8).add(one_and_a_half_pointers).read(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/large_const_alloc.rs b/tests/ui/consts/large_const_alloc.rs new file mode 100644 index 000000000..54abaab22 --- /dev/null +++ b/tests/ui/consts/large_const_alloc.rs @@ -0,0 +1,18 @@ +// only-64bit +// on 32bit and 16bit platforms it is plausible that the maximum allocation size will succeed + +const FOO: () = { + // 128 TiB, unlikely anyone has that much RAM + let x = [0_u8; (1 << 47) - 1]; + //~^ ERROR evaluation of constant value failed +}; + +static FOO2: () = { + let x = [0_u8; (1 << 47) - 1]; + //~^ ERROR could not evaluate static initializer +}; + +fn main() { + let _ = FOO; + let _ = FOO2; +} diff --git a/tests/ui/consts/large_const_alloc.stderr b/tests/ui/consts/large_const_alloc.stderr new file mode 100644 index 000000000..25d660f12 --- /dev/null +++ b/tests/ui/consts/large_const_alloc.stderr @@ -0,0 +1,15 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/large_const_alloc.rs:6:13 + | +LL | let x = [0_u8; (1 << 47) - 1]; + | ^^^^^^^^^^^^^^^^^^^^^ tried to allocate more memory than available to compiler + +error[E0080]: could not evaluate static initializer + --> $DIR/large_const_alloc.rs:11:13 + | +LL | let x = [0_u8; (1 << 47) - 1]; + | ^^^^^^^^^^^^^^^^^^^^^ tried to allocate more memory than available to compiler + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/locals-in-const-fn.rs b/tests/ui/consts/locals-in-const-fn.rs new file mode 100644 index 000000000..95d50171a --- /dev/null +++ b/tests/ui/consts/locals-in-const-fn.rs @@ -0,0 +1,35 @@ +// run-pass + +// https://github.com/rust-lang/rust/issues/48821 + +const fn foo(i: usize) -> usize { + let x = i; + x +} + +static FOO: usize = foo(42); + +const fn bar(mut i: usize) -> usize { + i += 8; + let x = &i; + *x +} + +static BAR: usize = bar(42); + +const fn boo(mut i: usize) -> usize { + { + let mut x = i; + x += 10; + i = x; + } + i +} + +static BOO: usize = boo(42); + +fn main() { + assert!(FOO == 42); + assert!(BAR == 50); + assert!(BOO == 52); +} diff --git a/tests/ui/consts/match-const-fn-structs.rs b/tests/ui/consts/match-const-fn-structs.rs new file mode 100644 index 000000000..5a68048c4 --- /dev/null +++ b/tests/ui/consts/match-const-fn-structs.rs @@ -0,0 +1,22 @@ +// run-pass +#![allow(unused_variables)] + +// https://github.com/rust-lang/rust/issues/46114 + +#[derive(Eq, PartialEq)] +struct A { value: u32 } + +const fn new(value: u32) -> A { + A { value } +} + +const A_1: A = new(1); +const A_2: A = new(2); + +fn main() { + let a_str = match new(42) { + A_1 => "A 1", + A_2 => "A 2", + _ => "Unknown A", + }; +} diff --git a/tests/ui/consts/match_ice.rs b/tests/ui/consts/match_ice.rs new file mode 100644 index 000000000..632335c84 --- /dev/null +++ b/tests/ui/consts/match_ice.rs @@ -0,0 +1,18 @@ +// https://github.com/rust-lang/rust/issues/53708 + +struct S; + +#[derive(PartialEq, Eq)] +struct T; + +fn main() { + const C: &S = &S; + match C { + C => {} + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + } + const K: &T = &T; + match K { + K => {} + } +} diff --git a/tests/ui/consts/match_ice.stderr b/tests/ui/consts/match_ice.stderr new file mode 100644 index 000000000..699b4a5e2 --- /dev/null +++ b/tests/ui/consts/match_ice.stderr @@ -0,0 +1,8 @@ +error: to use a constant of type `S` in a pattern, `S` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/match_ice.rs:11:9 + | +LL | C => {} + | ^ + +error: aborting due to previous error + diff --git a/tests/ui/consts/min_const_fn/address_of.rs b/tests/ui/consts/min_const_fn/address_of.rs new file mode 100644 index 000000000..40d1882d7 --- /dev/null +++ b/tests/ui/consts/min_const_fn/address_of.rs @@ -0,0 +1,17 @@ +#![feature(raw_ref_op)] + +const fn mutable_address_of_in_const() { + let mut a = 0; + let b = &raw mut a; //~ ERROR mutable reference +} + +struct X; + +impl X { + const fn inherent_mutable_address_of_in_const() { + let mut a = 0; + let b = &raw mut a; //~ ERROR mutable reference + } +} + +fn main() {} diff --git a/tests/ui/consts/min_const_fn/address_of.stderr b/tests/ui/consts/min_const_fn/address_of.stderr new file mode 100644 index 000000000..facc56651 --- /dev/null +++ b/tests/ui/consts/min_const_fn/address_of.stderr @@ -0,0 +1,21 @@ +error[E0658]: raw mutable references are not allowed in constant functions + --> $DIR/address_of.rs:5:13 + | +LL | let b = &raw mut a; + | ^^^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: raw mutable references are not allowed in constant functions + --> $DIR/address_of.rs:13:17 + | +LL | let b = &raw mut a; + | ^^^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/min_const_fn/address_of_const.rs b/tests/ui/consts/min_const_fn/address_of_const.rs new file mode 100644 index 000000000..3db19e9cd --- /dev/null +++ b/tests/ui/consts/min_const_fn/address_of_const.rs @@ -0,0 +1,19 @@ +// check-pass + +#![feature(raw_ref_op)] + +const fn const_address_of_in_const() { + let mut a = 0; + let b = &raw const a; +} + +struct X; + +impl X { + const fn inherent_const_address_of_in_const() { + let mut a = 0; + let b = &raw const a; + } +} + +fn main() {} diff --git a/tests/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs b/tests/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs new file mode 100644 index 000000000..2dbc424d3 --- /dev/null +++ b/tests/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs @@ -0,0 +1,19 @@ +// run-pass +#![feature(rustc_allow_const_fn_unstable)] + +#![feature(rustc_attrs, staged_api)] +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(since="1.0.0", feature = "mep")] +const fn takes_fn_ptr(_: fn()) {} + +const FN: fn() = || (); + +const fn gives_fn_ptr() { + takes_fn_ptr(FN) +} + +fn main() { + gives_fn_ptr(); +} diff --git a/tests/ui/consts/min_const_fn/allow_raw_ptr_dereference_const_fn.rs b/tests/ui/consts/min_const_fn/allow_raw_ptr_dereference_const_fn.rs new file mode 100644 index 000000000..d22115755 --- /dev/null +++ b/tests/ui/consts/min_const_fn/allow_raw_ptr_dereference_const_fn.rs @@ -0,0 +1,9 @@ +// check-pass + +use std::ptr; + +const fn test_fn(x: *const i32) { + let x2 = unsafe { ptr::addr_of!(*x) }; +} + +fn main() {} diff --git a/tests/ui/consts/min_const_fn/bad_const_fn_body_ice.rs b/tests/ui/consts/min_const_fn/bad_const_fn_body_ice.rs new file mode 100644 index 000000000..258997597 --- /dev/null +++ b/tests/ui/consts/min_const_fn/bad_const_fn_body_ice.rs @@ -0,0 +1,7 @@ +const fn foo(a: i32) -> Vec<i32> { + vec![1, 2, 3] + //~^ ERROR allocations are not allowed + //~| ERROR cannot call non-const fn +} + +fn main() {} diff --git a/tests/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr b/tests/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr new file mode 100644 index 000000000..742341089 --- /dev/null +++ b/tests/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr @@ -0,0 +1,21 @@ +error[E0010]: allocations are not allowed in constant functions + --> $DIR/bad_const_fn_body_ice.rs:2:5 + | +LL | vec![1, 2, 3] + | ^^^^^^^^^^^^^ allocation not allowed in constant functions + | + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0015]: cannot call non-const fn `slice::<impl [i32]>::into_vec::<std::alloc::Global>` in constant functions + --> $DIR/bad_const_fn_body_ice.rs:2:5 + | +LL | vec![1, 2, 3] + | ^^^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0010, E0015. +For more information about an error, try `rustc --explain E0010`. diff --git a/tests/ui/consts/min_const_fn/cast_fn.rs b/tests/ui/consts/min_const_fn/cast_fn.rs new file mode 100644 index 000000000..85802a514 --- /dev/null +++ b/tests/ui/consts/min_const_fn/cast_fn.rs @@ -0,0 +1,11 @@ +// check-pass + +fn main() {} + +const fn unsize(x: &[u8; 3]) -> &[u8] { x } +const fn closure() -> fn() { || {} } +const fn closure2() { + (|| {}) as fn(); +} +const fn reify(f: fn()) -> unsafe fn() { f } +const fn reify2() { main as unsafe fn(); } diff --git a/tests/ui/consts/min_const_fn/cmp_fn_pointers.rs b/tests/ui/consts/min_const_fn/cmp_fn_pointers.rs new file mode 100644 index 000000000..9a2775688 --- /dev/null +++ b/tests/ui/consts/min_const_fn/cmp_fn_pointers.rs @@ -0,0 +1,6 @@ +const fn cmp(x: fn(), y: fn()) -> bool { + unsafe { x == y } + //~^ ERROR can't compare +} + +fn main() {} diff --git a/tests/ui/consts/min_const_fn/cmp_fn_pointers.stderr b/tests/ui/consts/min_const_fn/cmp_fn_pointers.stderr new file mode 100644 index 000000000..8a1b20a33 --- /dev/null +++ b/tests/ui/consts/min_const_fn/cmp_fn_pointers.stderr @@ -0,0 +1,16 @@ +error[E0277]: can't compare `fn()` with `_` in const contexts + --> $DIR/cmp_fn_pointers.rs:2:16 + | +LL | unsafe { x == y } + | ^^ no implementation for `fn() == _` + | + = help: the trait `~const PartialEq<_>` is not implemented for `fn()` +note: the trait `PartialEq<_>` is implemented for `fn()`, but that implementation is not `const` + --> $DIR/cmp_fn_pointers.rs:2:16 + | +LL | unsafe { x == y } + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/min_const_fn/min_const_fn.rs b/tests/ui/consts/min_const_fn/min_const_fn.rs new file mode 100644 index 000000000..c2891488c --- /dev/null +++ b/tests/ui/consts/min_const_fn/min_const_fn.rs @@ -0,0 +1,134 @@ +// ok +const fn foo1() {} +const fn foo2(x: i32) -> i32 { x } +const fn foo3<T>(x: T) -> T { x } +const fn foo7() { + ( + foo1(), + foo2(420), + foo3(69), + ).0 +} +const fn foo12<T: Sized>(t: T) -> T { t } +const fn foo13<T: ?Sized>(t: &T) -> &T { t } +const fn foo14<'a, T: 'a>(t: &'a T) -> &'a T { t } +const fn foo15<T>(t: T) -> T where T: Sized { t } +const fn foo15_2<T>(t: &T) -> &T where T: ?Sized { t } +const fn foo16(f: f32) -> f32 { f } +const fn foo17(f: f32) -> u32 { f as u32 } +const fn foo18(i: i32) -> i32 { i * 3 } +const fn foo20(b: bool) -> bool { !b } +const fn foo21<T, U>(t: T, u: U) -> (T, U) { (t, u) } +const fn foo22(s: &[u8], i: usize) -> u8 { s[i] } +const FOO: u32 = 42; +const fn foo23() -> u32 { FOO } +const fn foo24() -> &'static u32 { &FOO } +const fn foo27(x: &u32) -> u32 { *x } +const fn foo28(x: u32) -> u32 { *&x } +const fn foo29(x: u32) -> i32 { x as i32 } +const fn foo31(a: bool, b: bool) -> bool { a & b } +const fn foo32(a: bool, b: bool) -> bool { a | b } +const fn foo33(a: bool, b: bool) -> bool { a & b } +const fn foo34(a: bool, b: bool) -> bool { a | b } +const fn foo35(a: bool, b: bool) -> bool { a ^ b } +struct Foo<T: ?Sized>(T); +impl<T> Foo<T> { + const fn new(t: T) -> Self { Foo(t) } + const fn into_inner(self) -> T { self.0 } //~ destructor of + const fn get(&self) -> &T { &self.0 } + const fn get_mut(&mut self) -> &mut T { &mut self.0 } + //~^ mutable references + //~| mutable references + //~| mutable references +} +impl<'a, T> Foo<T> { + const fn new_lt(t: T) -> Self { Foo(t) } + const fn into_inner_lt(self) -> T { self.0 } //~ destructor of + const fn get_lt(&'a self) -> &T { &self.0 } + const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } + //~^ mutable references + //~| mutable references + //~| mutable references +} +impl<T: Sized> Foo<T> { + const fn new_s(t: T) -> Self { Foo(t) } + const fn into_inner_s(self) -> T { self.0 } //~ ERROR destructor + const fn get_s(&self) -> &T { &self.0 } + const fn get_mut_s(&mut self) -> &mut T { &mut self.0 } + //~^ mutable references + //~| mutable references + //~| mutable references +} +impl<T: ?Sized> Foo<T> { + const fn get_sq(&self) -> &T { &self.0 } + const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 } + //~^ mutable references + //~| mutable references + //~| mutable references +} + + +const fn char_ops(c: char, d: char) -> bool { c == d } +const fn char_ops2(c: char, d: char) -> bool { c < d } +const fn char_ops3(c: char, d: char) -> bool { c != d } +const fn i32_ops(c: i32, d: i32) -> bool { c == d } +const fn i32_ops2(c: i32, d: i32) -> bool { c < d } +const fn i32_ops3(c: i32, d: i32) -> bool { c != d } +const fn i32_ops4(c: i32, d: i32) -> i32 { c + d } +const fn char_cast(u: u8) -> char { u as char } +const unsafe fn ret_i32_no_unsafe() -> i32 { 42 } +const unsafe fn ret_null_ptr_no_unsafe<T>() -> *const T { core::ptr::null() } +const unsafe fn ret_null_mut_ptr_no_unsafe<T>() -> *mut T { core::ptr::null_mut() } + +const fn foo11<T: std::fmt::Display>(t: T) -> T { t } +const fn foo11_2<T: Send>(t: T) -> T { t } + +// not ok + +static BAR: u32 = 42; +const fn foo25() -> u32 { BAR } //~ ERROR cannot refer to statics +const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot refer to statics +const fn foo30(x: *const u32) -> usize { x as usize } +//~^ ERROR pointers cannot be cast to integers +const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } } +//~^ ERROR pointers cannot be cast to integers +const fn foo30_2(x: *mut u32) -> usize { x as usize } +//~^ ERROR pointers cannot be cast to integers +const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } } +//~^ ERROR pointers cannot be cast to integers +const fn foo30_6() -> bool { let x = true; x } +const fn inc(x: &mut i32) { *x += 1 } +//~^ ERROR mutable references + +// ok +const fn foo36(a: bool, b: bool) -> bool { a && b } +const fn foo37(a: bool, b: bool) -> bool { a || b } + +fn main() {} + +impl<T: std::fmt::Debug> Foo<T> { + const fn foo(&self) {} +} + +impl<T: std::fmt::Debug + Sized> Foo<T> { + const fn foo2(&self) {} +} + +impl<T: Sync + Sized> Foo<T> { + const fn foo3(&self) {} +} + +struct AlanTuring<T>(T); +const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {} +//~^ ERROR destructor +const fn no_apit(_x: impl std::fmt::Debug) {} +//~^ ERROR destructor +const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} +const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } + +const fn no_unsafe() { unsafe {} } + +const fn traits_are_ok_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } + +const fn fn_ptrs(_x: fn()) {} +const fn fn_ptrs2() -> fn() { fn foo() {} foo } diff --git a/tests/ui/consts/min_const_fn/min_const_fn.stderr b/tests/ui/consts/min_const_fn/min_const_fn.stderr new file mode 100644 index 000000000..11c79e8e2 --- /dev/null +++ b/tests/ui/consts/min_const_fn/min_const_fn.stderr @@ -0,0 +1,213 @@ +error[E0493]: destructor of `Foo<T>` cannot be evaluated at compile-time + --> $DIR/min_const_fn.rs:37:25 + | +LL | const fn into_inner(self) -> T { self.0 } + | ^^^^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constant functions + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:39:22 + | +LL | const fn get_mut(&mut self) -> &mut T { &mut self.0 } + | ^^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:39:36 + | +LL | const fn get_mut(&mut self) -> &mut T { &mut self.0 } + | ^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:39:45 + | +LL | const fn get_mut(&mut self) -> &mut T { &mut self.0 } + | ^^^^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0493]: destructor of `Foo<T>` cannot be evaluated at compile-time + --> $DIR/min_const_fn.rs:46:28 + | +LL | const fn into_inner_lt(self) -> T { self.0 } + | ^^^^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constant functions + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:48:25 + | +LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } + | ^^^^^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:48:42 + | +LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } + | ^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:48:51 + | +LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } + | ^^^^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0493]: destructor of `Foo<T>` cannot be evaluated at compile-time + --> $DIR/min_const_fn.rs:55:27 + | +LL | const fn into_inner_s(self) -> T { self.0 } + | ^^^^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constant functions + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:57:24 + | +LL | const fn get_mut_s(&mut self) -> &mut T { &mut self.0 } + | ^^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:57:38 + | +LL | const fn get_mut_s(&mut self) -> &mut T { &mut self.0 } + | ^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:57:47 + | +LL | const fn get_mut_s(&mut self) -> &mut T { &mut self.0 } + | ^^^^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:64:25 + | +LL | const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 } + | ^^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:64:39 + | +LL | const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 } + | ^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:64:48 + | +LL | const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 } + | ^^^^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0013]: constant functions cannot refer to statics + --> $DIR/min_const_fn.rs:89:27 + | +LL | const fn foo25() -> u32 { BAR } + | ^^^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error[E0013]: constant functions cannot refer to statics + --> $DIR/min_const_fn.rs:90:37 + | +LL | const fn foo26() -> &'static u32 { &BAR } + | ^^^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error: pointers cannot be cast to integers during const eval + --> $DIR/min_const_fn.rs:91:42 + | +LL | const fn foo30(x: *const u32) -> usize { x as usize } + | ^^^^^^^^^^ + | + = note: at compile-time, pointers do not have an integer value + = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior + +error: pointers cannot be cast to integers during const eval + --> $DIR/min_const_fn.rs:93:63 + | +LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } } + | ^^^^^^^^^^ + | + = note: at compile-time, pointers do not have an integer value + = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior + +error: pointers cannot be cast to integers during const eval + --> $DIR/min_const_fn.rs:95:42 + | +LL | const fn foo30_2(x: *mut u32) -> usize { x as usize } + | ^^^^^^^^^^ + | + = note: at compile-time, pointers do not have an integer value + = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior + +error: pointers cannot be cast to integers during const eval + --> $DIR/min_const_fn.rs:97:63 + | +LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } } + | ^^^^^^^^^^ + | + = note: at compile-time, pointers do not have an integer value + = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:100:14 + | +LL | const fn inc(x: &mut i32) { *x += 1 } + | ^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0493]: destructor of `AlanTuring<impl std::fmt::Debug>` cannot be evaluated at compile-time + --> $DIR/min_const_fn.rs:122:19 + | +LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {} + | ^^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constant functions + +error[E0493]: destructor of `impl std::fmt::Debug` cannot be evaluated at compile-time + --> $DIR/min_const_fn.rs:124:18 + | +LL | const fn no_apit(_x: impl std::fmt::Debug) {} + | ^^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constant functions + +error: aborting due to 24 previous errors + +Some errors have detailed explanations: E0013, E0493, E0658. +For more information about an error, try `rustc --explain E0013`. diff --git a/tests/ui/consts/min_const_fn/min_const_fn_dyn.rs b/tests/ui/consts/min_const_fn/min_const_fn_dyn.rs new file mode 100644 index 000000000..36c888009 --- /dev/null +++ b/tests/ui/consts/min_const_fn/min_const_fn_dyn.rs @@ -0,0 +1,15 @@ +// check-pass + +struct HasDyn { + field: &'static dyn std::fmt::Debug, +} + +struct Hide(HasDyn); + +const fn no_inner_dyn_trait(_x: Hide) {} +const fn no_inner_dyn_trait2(x: Hide) { + x.0.field; +} +const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } + +fn main() {} diff --git a/tests/ui/consts/min_const_fn/min_const_fn_libstd.rs b/tests/ui/consts/min_const_fn/min_const_fn_libstd.rs new file mode 100644 index 000000000..cb8f74186 --- /dev/null +++ b/tests/ui/consts/min_const_fn/min_const_fn_libstd.rs @@ -0,0 +1,26 @@ +// build-pass (FIXME(62277): could be check-pass?) + +use std::cell::UnsafeCell; +use std::sync::atomic::AtomicU32; +pub struct Condvar { + condvar: UnsafeCell<AtomicU32>, +} + +unsafe impl Send for Condvar {} +unsafe impl Sync for Condvar {} + +#[repr(C)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +struct NoWait(u32); + +const CONDVAR_HAS_NO_WAITERS: NoWait = NoWait(42); + +impl Condvar { + pub const fn new() -> Condvar { + Condvar { + condvar: UnsafeCell::new(AtomicU32::new(CONDVAR_HAS_NO_WAITERS.0)), + } + } +} + +fn main() {} diff --git a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs new file mode 100644 index 000000000..bb240fb4a --- /dev/null +++ b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs @@ -0,0 +1,41 @@ +#![unstable(feature = "humans", + reason = "who ever let humans program computers, + we're apparently really bad at it", + issue = "none")] + +#![feature(const_fn_floating_point_arithmetic, foo, foo2)] +#![feature(staged_api)] + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature="foo", issue = "none")] +const fn foo() -> u32 { 42 } + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "rust1", since = "1.0.0")] +// can't call non-min_const_fn +const fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn + +#[unstable(feature = "foo2", issue = "none")] +const fn foo2() -> u32 { 42 } + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "rust1", since = "1.0.0")] +// can't call non-min_const_fn +const fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "rust1", since = "1.0.0")] +// Const-stable functions cannot rely on unstable const-eval features. +const fn bar3() -> u32 { (5f32 + 6f32) as u32 } +//~^ ERROR const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` + +// check whether this function cannot be called even with the feature gate active +#[unstable(feature = "foo2", issue = "none")] +const fn foo2_gated() -> u32 { 42 } + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "rust1", since = "1.0.0")] +// can't call non-min_const_fn +const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR not yet stable as a const fn + +fn main() {} diff --git a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr new file mode 100644 index 000000000..778b0e55f --- /dev/null +++ b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr @@ -0,0 +1,41 @@ +error: `foo` is not yet stable as a const fn + --> $DIR/min_const_fn_libstd_stability.rs:16:25 + | +LL | const fn bar() -> u32 { foo() } + | ^^^^^ + | + = help: const-stable functions can only call other const-stable functions + +error: `foo2` is not yet stable as a const fn + --> $DIR/min_const_fn_libstd_stability.rs:24:26 + | +LL | const fn bar2() -> u32 { foo2() } + | ^^^^^^ + | + = help: const-stable functions can only call other const-stable functions + +error: const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` + --> $DIR/min_const_fn_libstd_stability.rs:29:26 + | +LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 } + | ^^^^^^^^^^^^^ + | +help: if it is not part of the public API, make this function unstably const + | +LL | #[rustc_const_unstable(feature = "...", issue = "...")] + | +help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks + | +LL | #[rustc_allow_const_fn_unstable(const_fn_floating_point_arithmetic)] + | + +error: `foo2_gated` is not yet stable as a const fn + --> $DIR/min_const_fn_libstd_stability.rs:39:32 + | +LL | const fn bar2_gated() -> u32 { foo2_gated() } + | ^^^^^^^^^^^^ + | + = help: const-stable functions can only call other const-stable functions + +error: aborting due to 4 previous errors + diff --git a/tests/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs b/tests/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs new file mode 100644 index 000000000..a6e1788bb --- /dev/null +++ b/tests/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs @@ -0,0 +1,10 @@ +const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { &*x } } +//~^ dereferencing raw mutable pointers in constant functions + +const unsafe fn bad_const_unsafe_deref_raw(x: *mut usize) -> usize { *x } +//~^ dereferencing raw mutable pointers in constant functions + +const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static usize { &*x } +//~^ dereferencing raw mutable pointers in constant functions + +fn main() {} diff --git a/tests/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr b/tests/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr new file mode 100644 index 000000000..820b6433f --- /dev/null +++ b/tests/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr @@ -0,0 +1,30 @@ +error[E0658]: dereferencing raw mutable pointers in constant functions is unstable + --> $DIR/min_const_fn_unsafe_bad.rs:1:77 + | +LL | const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { &*x } } + | ^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: dereferencing raw mutable pointers in constant functions is unstable + --> $DIR/min_const_fn_unsafe_bad.rs:4:70 + | +LL | const unsafe fn bad_const_unsafe_deref_raw(x: *mut usize) -> usize { *x } + | ^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: dereferencing raw mutable pointers in constant functions is unstable + --> $DIR/min_const_fn_unsafe_bad.rs:7:83 + | +LL | const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static usize { &*x } + | ^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/min_const_fn/min_const_fn_unsafe_ok.rs b/tests/ui/consts/min_const_fn/min_const_fn_unsafe_ok.rs new file mode 100644 index 000000000..02c7970de --- /dev/null +++ b/tests/ui/consts/min_const_fn/min_const_fn_unsafe_ok.rs @@ -0,0 +1,44 @@ +// check-pass + +const unsafe fn ret_i32_no_unsafe() -> i32 { 42 } +const unsafe fn ret_null_ptr_no_unsafe<T>() -> *const T { std::ptr::null() } +const unsafe fn ret_null_mut_ptr_no_unsafe<T>() -> *mut T { std::ptr::null_mut() } +const fn no_unsafe() { unsafe {} } + +const fn call_unsafe_const_fn() -> i32 { + unsafe { ret_i32_no_unsafe() } +} +const fn call_unsafe_generic_const_fn() -> *const String { + unsafe { ret_null_ptr_no_unsafe::<String>() } +} +const fn call_unsafe_generic_cell_const_fn() + -> *const Vec<std::cell::Cell<u32>> +{ + unsafe { ret_null_mut_ptr_no_unsafe::<Vec<std::cell::Cell<u32>>>() } +} + +const unsafe fn call_unsafe_const_unsafe_fn() -> i32 { + unsafe { ret_i32_no_unsafe() } +} +const unsafe fn call_unsafe_generic_const_unsafe_fn() -> *const String { + unsafe { ret_null_ptr_no_unsafe::<String>() } +} +const unsafe fn call_unsafe_generic_cell_const_unsafe_fn() + -> *const Vec<std::cell::Cell<u32>> +{ + unsafe { ret_null_mut_ptr_no_unsafe::<Vec<std::cell::Cell<u32>>>() } +} + +const unsafe fn call_unsafe_const_unsafe_fn_immediate() -> i32 { + ret_i32_no_unsafe() +} +const unsafe fn call_unsafe_generic_const_unsafe_fn_immediate() -> *const String { + ret_null_ptr_no_unsafe::<String>() +} +const unsafe fn call_unsafe_generic_cell_const_unsafe_fn_immediate() + -> *const Vec<std::cell::Cell<u32>> +{ + ret_null_mut_ptr_no_unsafe::<Vec<std::cell::Cell<u32>>>() +} + +fn main() {} diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs new file mode 100644 index 000000000..03084c867 --- /dev/null +++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs @@ -0,0 +1,42 @@ +#![unstable(feature = "humans", + reason = "who ever let humans program computers, + we're apparently really bad at it", + issue = "none")] + +#![feature(const_fn_floating_point_arithmetic, foo, foo2)] +#![feature(staged_api)] + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature="foo", issue = "none")] +const unsafe fn foo() -> u32 { 42 } + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "rust1", since = "1.0.0")] +// can't call non-min_const_fn +const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR not yet stable as a const fn + +#[unstable(feature = "foo2", issue = "none")] +const unsafe fn foo2() -> u32 { 42 } + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "rust1", since = "1.0.0")] +// can't call non-min_const_fn +const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR not yet stable as a const fn + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "rust1", since = "1.0.0")] +// conformity is required +const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } +//~^ ERROR const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` + +// check whether this function cannot be called even with the feature gate active +#[unstable(feature = "foo2", issue = "none")] +const unsafe fn foo2_gated() -> u32 { 42 } + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "rust1", since = "1.0.0")] +// can't call non-min_const_fn +const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } +//~^ ERROR not yet stable as a const fn + +fn main() {} diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr new file mode 100644 index 000000000..0174cb77f --- /dev/null +++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr @@ -0,0 +1,41 @@ +error: `foo` is not yet stable as a const fn + --> $DIR/min_const_unsafe_fn_libstd_stability.rs:16:41 + | +LL | const unsafe fn bar() -> u32 { unsafe { foo() } } + | ^^^^^ + | + = help: const-stable functions can only call other const-stable functions + +error: `foo2` is not yet stable as a const fn + --> $DIR/min_const_unsafe_fn_libstd_stability.rs:24:42 + | +LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } + | ^^^^^^ + | + = help: const-stable functions can only call other const-stable functions + +error: const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` + --> $DIR/min_const_unsafe_fn_libstd_stability.rs:29:33 + | +LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } + | ^^^^^^^^^^^^^ + | +help: if it is not part of the public API, make this function unstably const + | +LL | #[rustc_const_unstable(feature = "...", issue = "...")] + | +help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks + | +LL | #[rustc_allow_const_fn_unstable(const_fn_floating_point_arithmetic)] + | + +error: `foo2_gated` is not yet stable as a const fn + --> $DIR/min_const_unsafe_fn_libstd_stability.rs:39:48 + | +LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } + | ^^^^^^^^^^^^ + | + = help: const-stable functions can only call other const-stable functions + +error: aborting due to 4 previous errors + diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs new file mode 100644 index 000000000..94b620713 --- /dev/null +++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs @@ -0,0 +1,35 @@ +#![unstable(feature = "humans", + reason = "who ever let humans program computers, + we're apparently really bad at it", + issue = "none")] + +#![feature(foo, foo2)] +#![feature(staged_api)] + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature="foo", issue = "none")] +const fn foo() -> u32 { 42 } + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "rust1", since = "1.0.0")] +// can't call non-min_const_fn +const unsafe fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn + +#[unstable(feature = "foo2", issue = "none")] +const fn foo2() -> u32 { 42 } + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "rust1", since = "1.0.0")] +// can't call non-min_const_fn +const unsafe fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn + +// check whether this function cannot be called even with the feature gate active +#[unstable(feature = "foo2", issue = "none")] +const fn foo2_gated() -> u32 { 42 } + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "rust1", since = "1.0.0")] +// can't call non-min_const_fn +const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR not yet stable as a const fn + +fn main() {} diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr new file mode 100644 index 000000000..e90ba9b91 --- /dev/null +++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr @@ -0,0 +1,26 @@ +error: `foo` is not yet stable as a const fn + --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:16:32 + | +LL | const unsafe fn bar() -> u32 { foo() } + | ^^^^^ + | + = help: const-stable functions can only call other const-stable functions + +error: `foo2` is not yet stable as a const fn + --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:24:33 + | +LL | const unsafe fn bar2() -> u32 { foo2() } + | ^^^^^^ + | + = help: const-stable functions can only call other const-stable functions + +error: `foo2_gated` is not yet stable as a const fn + --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:39 + | +LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } + | ^^^^^^^^^^^^ + | + = help: const-stable functions can only call other const-stable functions + +error: aborting due to 3 previous errors + diff --git a/tests/ui/consts/min_const_fn/mutable_borrow.rs b/tests/ui/consts/min_const_fn/mutable_borrow.rs new file mode 100644 index 000000000..580b1d50f --- /dev/null +++ b/tests/ui/consts/min_const_fn/mutable_borrow.rs @@ -0,0 +1,17 @@ +const fn mutable_ref_in_const() -> u8 { + let mut a = 0; + let b = &mut a; //~ ERROR mutable references + *b +} + +struct X; + +impl X { + const fn inherent_mutable_ref_in_const() -> u8 { + let mut a = 0; + let b = &mut a; //~ ERROR mutable references + *b + } +} + +fn main() {} diff --git a/tests/ui/consts/min_const_fn/mutable_borrow.stderr b/tests/ui/consts/min_const_fn/mutable_borrow.stderr new file mode 100644 index 000000000..8e95a4c68 --- /dev/null +++ b/tests/ui/consts/min_const_fn/mutable_borrow.stderr @@ -0,0 +1,21 @@ +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/mutable_borrow.rs:3:13 + | +LL | let b = &mut a; + | ^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/mutable_borrow.rs:12:17 + | +LL | let b = &mut a; + | ^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/min_const_fn/promotion.rs b/tests/ui/consts/min_const_fn/promotion.rs new file mode 100644 index 000000000..fbe535c71 --- /dev/null +++ b/tests/ui/consts/min_const_fn/promotion.rs @@ -0,0 +1,17 @@ +use std::cell::Cell; + +const fn foo1() {} +const fn foo2(x: i32) -> i32 { x } +const fn foo3() -> i32 { 42 } +const fn foo4() -> Cell<i32> { Cell::new(42) } +const fn foo5() -> Option<Cell<i32>> { Some(Cell::new(42)) } +const fn foo6() -> Option<Cell<i32>> { None } + +fn main() { + let x: &'static () = &foo1(); //~ ERROR temporary value dropped while borrowed + let y: &'static i32 = &foo2(42); //~ ERROR temporary value dropped while borrowed + let z: &'static i32 = &foo3(); //~ ERROR temporary value dropped while borrowed + let a: &'static Cell<i32> = &foo4(); //~ ERROR temporary value dropped while borrowed + let a: &'static Option<Cell<i32>> = &foo5(); //~ ERROR temporary value dropped while borrowed + let a: &'static Option<Cell<i32>> = &foo6(); //~ ERROR temporary value dropped while borrowed +} diff --git a/tests/ui/consts/min_const_fn/promotion.stderr b/tests/ui/consts/min_const_fn/promotion.stderr new file mode 100644 index 000000000..0b8dc0ce0 --- /dev/null +++ b/tests/ui/consts/min_const_fn/promotion.stderr @@ -0,0 +1,68 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/promotion.rs:11:27 + | +LL | let x: &'static () = &foo1(); + | ----------- ^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promotion.rs:12:28 + | +LL | let y: &'static i32 = &foo2(42); + | ------------ ^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promotion.rs:13:28 + | +LL | let z: &'static i32 = &foo3(); + | ------------ ^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promotion.rs:14:34 + | +LL | let a: &'static Cell<i32> = &foo4(); + | ------------------ ^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promotion.rs:15:42 + | +LL | let a: &'static Option<Cell<i32>> = &foo5(); + | -------------------------- ^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | let a: &'static Option<Cell<i32>> = &foo6(); +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promotion.rs:16:42 + | +LL | let a: &'static Option<Cell<i32>> = &foo6(); + | -------------------------- ^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/mir_check_nonconst.rs b/tests/ui/consts/mir_check_nonconst.rs new file mode 100644 index 000000000..b6f34b922 --- /dev/null +++ b/tests/ui/consts/mir_check_nonconst.rs @@ -0,0 +1,11 @@ +#![allow(dead_code)] + +struct Foo { a: u8 } +fn bar() -> Foo { + Foo { a: 5 } +} + +static foo: Foo = bar(); +//~^ ERROR cannot call non-const fn + +fn main() {} diff --git a/tests/ui/consts/mir_check_nonconst.stderr b/tests/ui/consts/mir_check_nonconst.stderr new file mode 100644 index 000000000..1e0652722 --- /dev/null +++ b/tests/ui/consts/mir_check_nonconst.stderr @@ -0,0 +1,12 @@ +error[E0015]: cannot call non-const fn `bar` in statics + --> $DIR/mir_check_nonconst.rs:8:19 + | +LL | static foo: Foo = bar(); + | ^^^^^ + | + = note: calls in statics are limited to constant functions, tuple structs and tuple variants + = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/miri_unleashed/abi-mismatch.rs b/tests/ui/consts/miri_unleashed/abi-mismatch.rs new file mode 100644 index 000000000..205f7183b --- /dev/null +++ b/tests/ui/consts/miri_unleashed/abi-mismatch.rs @@ -0,0 +1,18 @@ +// Checks that we report ABI mismatches for "const extern fn" +// compile-flags: -Z unleash-the-miri-inside-of-you + +#![feature(const_extern_fn)] + +const extern "C" fn c_fn() {} + +const fn call_rust_fn(my_fn: extern "Rust" fn()) { + my_fn(); + //~^ ERROR could not evaluate static initializer + //~| NOTE calling a function with calling convention C using calling convention Rust + //~| NOTE inside `call_rust_fn` +} + +static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn()) }); +//~^ NOTE inside `VAL` + +fn main() {} diff --git a/tests/ui/consts/miri_unleashed/abi-mismatch.stderr b/tests/ui/consts/miri_unleashed/abi-mismatch.stderr new file mode 100644 index 000000000..cf3fd88d0 --- /dev/null +++ b/tests/ui/consts/miri_unleashed/abi-mismatch.stderr @@ -0,0 +1,28 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/abi-mismatch.rs:9:5 + | +LL | my_fn(); + | ^^^^^^^ calling a function with calling convention C using calling convention Rust + | +note: inside `call_rust_fn` + --> $DIR/abi-mismatch.rs:9:5 + | +LL | my_fn(); + | ^^^^^^^ +note: inside `VAL` + --> $DIR/abi-mismatch.rs:15:18 + | +LL | static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn()) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/abi-mismatch.rs:9:5 + | +LL | my_fn(); + | ^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/assoc_const.rs b/tests/ui/consts/miri_unleashed/assoc_const.rs new file mode 100644 index 000000000..7bb0c1b77 --- /dev/null +++ b/tests/ui/consts/miri_unleashed/assoc_const.rs @@ -0,0 +1,30 @@ +// build-fail +// compile-flags: -Zunleash-the-miri-inside-of-you + +// a test demonstrating why we do need to run static const qualification on associated constants +// instead of just checking the final constant + +trait Foo<T> { + const X: T; +} + +trait Bar<T, U: Foo<T>> { + const F: u32 = (U::X, 42).1; +} + +impl Foo<u32> for () { + const X: u32 = 42; +} +impl Foo<Vec<u32>> for String { + const X: Vec<u32> = Vec::new(); +} + +impl Bar<u32, ()> for () {} +impl Bar<Vec<u32>, String> for String {} + +fn main() { + // this is fine, but would have been forbidden by the static checks on `F` + let x = <() as Bar<u32, ()>>::F; + // this test only causes errors due to the line below, so post-monomorphization + let y = <String as Bar<Vec<u32>, String>>::F; //~ constant +} diff --git a/tests/ui/consts/miri_unleashed/assoc_const.stderr b/tests/ui/consts/miri_unleashed/assoc_const.stderr new file mode 100644 index 000000000..e1da43c3a --- /dev/null +++ b/tests/ui/consts/miri_unleashed/assoc_const.stderr @@ -0,0 +1,44 @@ +error[E0080]: evaluation of `<std::string::String as Bar<std::vec::Vec<u32>, std::string::String>>::F` failed + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | + = note: calling non-const function `<Vec<u32> as Drop>::drop` + | +note: inside `std::ptr::drop_in_place::<Vec<u32>> - shim(Some(Vec<u32>))` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL +note: inside `std::ptr::drop_in_place::<(Vec<u32>, u32)> - shim(Some((Vec<u32>, u32)))` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL +note: inside `<String as Bar<Vec<u32>, String>>::F` + --> $DIR/assoc_const.rs:12:31 + | +LL | const F: u32 = (U::X, 42).1; + | ^ + +note: erroneous constant used + --> $DIR/assoc_const.rs:29:13 + | +LL | let y = <String as Bar<Vec<u32>, String>>::F; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: erroneous constant used + --> $DIR/assoc_const.rs:29:13 + | +LL | let y = <String as Bar<Vec<u32>, String>>::F; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: erroneous constant used + --> $DIR/assoc_const.rs:29:13 + | +LL | let y = <String as Bar<Vec<u32>, String>>::F; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/assoc_const.rs:12:20 + | +LL | const F: u32 = (U::X, 42).1; + | ^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/assoc_const_2.rs b/tests/ui/consts/miri_unleashed/assoc_const_2.rs new file mode 100644 index 000000000..aad5b3460 --- /dev/null +++ b/tests/ui/consts/miri_unleashed/assoc_const_2.rs @@ -0,0 +1,28 @@ +// build-fail + +// a test demonstrating that const qualification cannot prevent monomorphization time errors + +trait Foo { + const X: u32; +} + +trait Bar<U: Foo> { + const F: u32 = 100 / U::X; //~ ERROR evaluation of `<std::string::String as Bar<std::string::String>>::F` failed +} + +impl Foo for () { + const X: u32 = 42; +} + +impl Foo for String { + const X: u32 = 0; +} + +impl Bar<()> for () {} +impl Bar<String> for String {} + +fn main() { + let x = <() as Bar<()>>::F; + // this test only causes errors due to the line below, so post-monomorphization + let y = <String as Bar<String>>::F; //~ constant +} diff --git a/tests/ui/consts/miri_unleashed/assoc_const_2.stderr b/tests/ui/consts/miri_unleashed/assoc_const_2.stderr new file mode 100644 index 000000000..fc4b18056 --- /dev/null +++ b/tests/ui/consts/miri_unleashed/assoc_const_2.stderr @@ -0,0 +1,27 @@ +error[E0080]: evaluation of `<std::string::String as Bar<std::string::String>>::F` failed + --> $DIR/assoc_const_2.rs:10:20 + | +LL | const F: u32 = 100 / U::X; + | ^^^^^^^^^^ attempt to divide `100_u32` by zero + +note: erroneous constant used + --> $DIR/assoc_const_2.rs:27:13 + | +LL | let y = <String as Bar<String>>::F; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: erroneous constant used + --> $DIR/assoc_const_2.rs:27:13 + | +LL | let y = <String as Bar<String>>::F; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: erroneous constant used + --> $DIR/assoc_const_2.rs:27:13 + | +LL | let y = <String as Bar<String>>::F; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/auxiliary/static_cross_crate.rs b/tests/ui/consts/miri_unleashed/auxiliary/static_cross_crate.rs new file mode 100644 index 000000000..4fc6ae66a --- /dev/null +++ b/tests/ui/consts/miri_unleashed/auxiliary/static_cross_crate.rs @@ -0,0 +1,3 @@ +pub static mut ZERO: [u8; 1] = [0]; +pub static ZERO_REF: &[u8; 1] = unsafe { &ZERO }; +pub static mut OPT_ZERO: Option<u8> = Some(0); diff --git a/tests/ui/consts/miri_unleashed/box.rs b/tests/ui/consts/miri_unleashed/box.rs new file mode 100644 index 000000000..c2a260aa1 --- /dev/null +++ b/tests/ui/consts/miri_unleashed/box.rs @@ -0,0 +1,12 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you +#![feature(box_syntax)] + +use std::mem::ManuallyDrop; + +fn main() {} + +static TEST_BAD: &mut i32 = { + &mut *(box 0) + //~^ ERROR could not evaluate static initializer + //~| NOTE calling non-const function `alloc::alloc::exchange_malloc` +}; diff --git a/tests/ui/consts/miri_unleashed/box.stderr b/tests/ui/consts/miri_unleashed/box.stderr new file mode 100644 index 000000000..bc5d4a257 --- /dev/null +++ b/tests/ui/consts/miri_unleashed/box.stderr @@ -0,0 +1,32 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/box.rs:9:11 + | +LL | &mut *(box 0) + | ^^^^^^^ calling non-const function `alloc::alloc::exchange_malloc` + +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/box.rs:9:11 + | +LL | &mut *(box 0) + | ^^^^^^^ +help: skipping check for `const_mut_refs` feature + --> $DIR/box.rs:9:16 + | +LL | &mut *(box 0) + | ^ +help: skipping check for `const_mut_refs` feature + --> $DIR/box.rs:9:5 + | +LL | &mut *(box 0) + | ^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/box.rs:9:5 + | +LL | &mut *(box 0) + | ^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr new file mode 100644 index 000000000..a6f467b9e --- /dev/null +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr @@ -0,0 +1,81 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const_refers_to_static.rs:9:5 + | +LL | FOO.fetch_add(1, Ordering::Relaxed) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling non-const function `AtomicUsize::fetch_add` + +error[E0080]: evaluation of constant value failed + --> $DIR/const_refers_to_static.rs:14:14 + | +LL | unsafe { *(&FOO as *const _ as *const usize) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static + +error[E0080]: evaluation of constant value failed + --> $DIR/const_refers_to_static.rs:18:32 + | +LL | const READ_MUT: u32 = unsafe { MUTABLE }; + | ^^^^^^^ constant accesses static + +error[E0080]: it is undefined behavior to use this value + --> $DIR/const_refers_to_static.rs:20:1 + | +LL | const REF_INTERIOR_MUT: &usize = { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + ╾─alloc4──╼ │ ╾──╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/const_refers_to_static.rs:27:1 + | +LL | const READ_IMMUT: &usize = { + | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + ╾─alloc5──╼ │ ╾──╼ + } + +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static.rs:9:5 + | +LL | FOO.fetch_add(1, Ordering::Relaxed) + | ^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static.rs:9:5 + | +LL | FOO.fetch_add(1, Ordering::Relaxed) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static.rs:14:17 + | +LL | unsafe { *(&FOO as *const _ as *const usize) } + | ^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static.rs:18:32 + | +LL | const READ_MUT: u32 = unsafe { MUTABLE }; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static.rs:18:32 + | +LL | const READ_MUT: u32 = unsafe { MUTABLE }; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static.rs:23:18 + | +LL | unsafe { &*(&FOO as *const _ as *const usize) } + | ^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static.rs:30:6 + | +LL | &FOO + | ^^^ + +error: aborting due to 5 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr new file mode 100644 index 000000000..cfaf31a6e --- /dev/null +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr @@ -0,0 +1,81 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const_refers_to_static.rs:9:5 + | +LL | FOO.fetch_add(1, Ordering::Relaxed) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling non-const function `AtomicUsize::fetch_add` + +error[E0080]: evaluation of constant value failed + --> $DIR/const_refers_to_static.rs:14:14 + | +LL | unsafe { *(&FOO as *const _ as *const usize) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static + +error[E0080]: evaluation of constant value failed + --> $DIR/const_refers_to_static.rs:18:32 + | +LL | const READ_MUT: u32 = unsafe { MUTABLE }; + | ^^^^^^^ constant accesses static + +error[E0080]: it is undefined behavior to use this value + --> $DIR/const_refers_to_static.rs:20:1 + | +LL | const REF_INTERIOR_MUT: &usize = { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + ╾───────alloc4────────╼ │ ╾──────╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/const_refers_to_static.rs:27:1 + | +LL | const READ_IMMUT: &usize = { + | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + ╾───────alloc5────────╼ │ ╾──────╼ + } + +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static.rs:9:5 + | +LL | FOO.fetch_add(1, Ordering::Relaxed) + | ^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static.rs:9:5 + | +LL | FOO.fetch_add(1, Ordering::Relaxed) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static.rs:14:17 + | +LL | unsafe { *(&FOO as *const _ as *const usize) } + | ^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static.rs:18:32 + | +LL | const READ_MUT: u32 = unsafe { MUTABLE }; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static.rs:18:32 + | +LL | const READ_MUT: u32 = unsafe { MUTABLE }; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static.rs:23:18 + | +LL | unsafe { &*(&FOO as *const _ as *const usize) } + | ^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static.rs:30:6 + | +LL | &FOO + | ^^^ + +error: aborting due to 5 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.rs b/tests/ui/consts/miri_unleashed/const_refers_to_static.rs new file mode 100644 index 000000000..7ed5a48d9 --- /dev/null +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.rs @@ -0,0 +1,33 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you +// stderr-per-bitwidth + +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; + +const MUTATE_INTERIOR_MUT: usize = { + static FOO: AtomicUsize = AtomicUsize::new(0); + FOO.fetch_add(1, Ordering::Relaxed) //~ERROR evaluation of constant value failed +}; + +const READ_INTERIOR_MUT: usize = { + static FOO: AtomicUsize = AtomicUsize::new(0); + unsafe { *(&FOO as *const _ as *const usize) } //~ERROR evaluation of constant value failed +}; + +static mut MUTABLE: u32 = 0; +const READ_MUT: u32 = unsafe { MUTABLE }; //~ERROR evaluation of constant value failed + +const REF_INTERIOR_MUT: &usize = { //~ ERROR undefined behavior to use this value +//~| encountered a reference pointing to a static variable + static FOO: AtomicUsize = AtomicUsize::new(0); + unsafe { &*(&FOO as *const _ as *const usize) } +}; + +// ok some day perhaps +const READ_IMMUT: &usize = { //~ ERROR it is undefined behavior to use this value +//~| encountered a reference pointing to a static variable + static FOO: usize = 0; + &FOO +}; + +fn main() {} diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr new file mode 100644 index 000000000..6df2fe3d0 --- /dev/null +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr @@ -0,0 +1,138 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/const_refers_to_static_cross_crate.rs:10:1 + | +LL | const SLICE_MUT: &[u8; 1] = { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + ╾─alloc1──╼ │ ╾──╼ + } + +error: could not evaluate constant pattern + --> $DIR/const_refers_to_static_cross_crate.rs:34:9 + | +LL | SLICE_MUT => true, + | ^^^^^^^^^ + +error[E0080]: it is undefined behavior to use this value + --> $DIR/const_refers_to_static_cross_crate.rs:15:1 + | +LL | const U8_MUT: &u8 = { + | ^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + ╾─alloc1──╼ │ ╾──╼ + } + +error: could not evaluate constant pattern + --> $DIR/const_refers_to_static_cross_crate.rs:43:9 + | +LL | U8_MUT => true, + | ^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $DIR/const_refers_to_static_cross_crate.rs:22:15 + | +LL | unsafe { &(*static_cross_crate::ZERO_REF)[0] } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static + +error: could not evaluate constant pattern + --> $DIR/const_refers_to_static_cross_crate.rs:54:9 + | +LL | U8_MUT2 => true, + | ^^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + | +LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static + +error: could not evaluate constant pattern + --> $DIR/const_refers_to_static_cross_crate.rs:62:9 + | +LL | U8_MUT3 => true, + | ^^^^^^^ + +error: could not evaluate constant pattern + --> $DIR/const_refers_to_static_cross_crate.rs:34:9 + | +LL | SLICE_MUT => true, + | ^^^^^^^^^ + +error: could not evaluate constant pattern + --> $DIR/const_refers_to_static_cross_crate.rs:43:9 + | +LL | U8_MUT => true, + | ^^^^^^ + +error: could not evaluate constant pattern + --> $DIR/const_refers_to_static_cross_crate.rs:54:9 + | +LL | U8_MUT2 => true, + | ^^^^^^^ + +error: could not evaluate constant pattern + --> $DIR/const_refers_to_static_cross_crate.rs:62:9 + | +LL | U8_MUT3 => true, + | ^^^^^^^ + +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static_cross_crate.rs:12:15 + | +LL | unsafe { &static_cross_crate::ZERO } + | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static_cross_crate.rs:12:15 + | +LL | unsafe { &static_cross_crate::ZERO } + | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static_cross_crate.rs:17:15 + | +LL | unsafe { &static_cross_crate::ZERO[0] } + | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static_cross_crate.rs:17:15 + | +LL | unsafe { &static_cross_crate::ZERO[0] } + | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static_cross_crate.rs:17:15 + | +LL | unsafe { &static_cross_crate::ZERO[0] } + | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static_cross_crate.rs:22:17 + | +LL | unsafe { &(*static_cross_crate::ZERO_REF)[0] } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + | +LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + | +LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + | +LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + | +LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr new file mode 100644 index 000000000..8802f3ada --- /dev/null +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr @@ -0,0 +1,138 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/const_refers_to_static_cross_crate.rs:10:1 + | +LL | const SLICE_MUT: &[u8; 1] = { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + ╾───────alloc1────────╼ │ ╾──────╼ + } + +error: could not evaluate constant pattern + --> $DIR/const_refers_to_static_cross_crate.rs:34:9 + | +LL | SLICE_MUT => true, + | ^^^^^^^^^ + +error[E0080]: it is undefined behavior to use this value + --> $DIR/const_refers_to_static_cross_crate.rs:15:1 + | +LL | const U8_MUT: &u8 = { + | ^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + ╾───────alloc1────────╼ │ ╾──────╼ + } + +error: could not evaluate constant pattern + --> $DIR/const_refers_to_static_cross_crate.rs:43:9 + | +LL | U8_MUT => true, + | ^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $DIR/const_refers_to_static_cross_crate.rs:22:15 + | +LL | unsafe { &(*static_cross_crate::ZERO_REF)[0] } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static + +error: could not evaluate constant pattern + --> $DIR/const_refers_to_static_cross_crate.rs:54:9 + | +LL | U8_MUT2 => true, + | ^^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + | +LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static + +error: could not evaluate constant pattern + --> $DIR/const_refers_to_static_cross_crate.rs:62:9 + | +LL | U8_MUT3 => true, + | ^^^^^^^ + +error: could not evaluate constant pattern + --> $DIR/const_refers_to_static_cross_crate.rs:34:9 + | +LL | SLICE_MUT => true, + | ^^^^^^^^^ + +error: could not evaluate constant pattern + --> $DIR/const_refers_to_static_cross_crate.rs:43:9 + | +LL | U8_MUT => true, + | ^^^^^^ + +error: could not evaluate constant pattern + --> $DIR/const_refers_to_static_cross_crate.rs:54:9 + | +LL | U8_MUT2 => true, + | ^^^^^^^ + +error: could not evaluate constant pattern + --> $DIR/const_refers_to_static_cross_crate.rs:62:9 + | +LL | U8_MUT3 => true, + | ^^^^^^^ + +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static_cross_crate.rs:12:15 + | +LL | unsafe { &static_cross_crate::ZERO } + | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static_cross_crate.rs:12:15 + | +LL | unsafe { &static_cross_crate::ZERO } + | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static_cross_crate.rs:17:15 + | +LL | unsafe { &static_cross_crate::ZERO[0] } + | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static_cross_crate.rs:17:15 + | +LL | unsafe { &static_cross_crate::ZERO[0] } + | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static_cross_crate.rs:17:15 + | +LL | unsafe { &static_cross_crate::ZERO[0] } + | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static_cross_crate.rs:22:17 + | +LL | unsafe { &(*static_cross_crate::ZERO_REF)[0] } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + | +LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + | +LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + | +LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + | +LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs new file mode 100644 index 000000000..bf4f14f4d --- /dev/null +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs @@ -0,0 +1,76 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you +// aux-build:static_cross_crate.rs +// stderr-per-bitwidth +#![feature(exclusive_range_pattern, half_open_range_patterns_in_slices)] + +extern crate static_cross_crate; + +// Sneaky: reference to a mutable static. +// Allowing this would be a disaster for pattern matching, we could violate exhaustiveness checking! +const SLICE_MUT: &[u8; 1] = { //~ ERROR undefined behavior to use this value +//~| encountered a reference pointing to a static variable + unsafe { &static_cross_crate::ZERO } +}; + +const U8_MUT: &u8 = { //~ ERROR undefined behavior to use this value +//~| encountered a reference pointing to a static variable + unsafe { &static_cross_crate::ZERO[0] } +}; + +// Also test indirection that reads from other static. +const U8_MUT2: &u8 = { + unsafe { &(*static_cross_crate::ZERO_REF)[0] } + //~^ ERROR evaluation of constant value failed + //~| constant accesses static +}; +const U8_MUT3: &u8 = { + unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } + //~^ ERROR evaluation of constant value failed + //~| constant accesses static +}; + +pub fn test(x: &[u8; 1]) -> bool { + match x { + SLICE_MUT => true, + //~^ ERROR could not evaluate constant pattern + //~| ERROR could not evaluate constant pattern + &[1..] => false, + } +} + +pub fn test2(x: &u8) -> bool { + match x { + U8_MUT => true, + //~^ ERROR could not evaluate constant pattern + //~| ERROR could not evaluate constant pattern + &(1..) => false, + } +} + +// We need to use these *in a pattern* to trigger the failure... likely because +// the errors above otherwise stop compilation too early? +pub fn test3(x: &u8) -> bool { + match x { + U8_MUT2 => true, + //~^ ERROR could not evaluate constant pattern + //~| ERROR could not evaluate constant pattern + &(1..) => false, + } +} +pub fn test4(x: &u8) -> bool { + match x { + U8_MUT3 => true, + //~^ ERROR could not evaluate constant pattern + //~| ERROR could not evaluate constant pattern + &(1..) => false, + } +} + +fn main() { + unsafe { + static_cross_crate::ZERO[0] = 1; + } + // Now the pattern is not exhaustive any more! + test(&[0]); + test2(&0); +} diff --git a/tests/ui/consts/miri_unleashed/drop.rs b/tests/ui/consts/miri_unleashed/drop.rs new file mode 100644 index 000000000..3942e7ef7 --- /dev/null +++ b/tests/ui/consts/miri_unleashed/drop.rs @@ -0,0 +1,17 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you +// error-pattern: calling non-const function `<Vec<i32> as Drop>::drop` + +use std::mem::ManuallyDrop; + +fn main() {} + +static TEST_OK: () = { + let v: Vec<i32> = Vec::new(); + let _v = ManuallyDrop::new(v); +}; + +// Make sure we catch executing bad drop functions. +// The actual error is tested by the error-pattern above. +static TEST_BAD: () = { + let _v: Vec<i32> = Vec::new(); +}; diff --git a/tests/ui/consts/miri_unleashed/drop.stderr b/tests/ui/consts/miri_unleashed/drop.stderr new file mode 100644 index 000000000..4f60b8820 --- /dev/null +++ b/tests/ui/consts/miri_unleashed/drop.stderr @@ -0,0 +1,24 @@ +error[E0080]: could not evaluate static initializer + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | + = note: calling non-const function `<Vec<i32> as Drop>::drop` + | +note: inside `std::ptr::drop_in_place::<Vec<i32>> - shim(Some(Vec<i32>))` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL +note: inside `TEST_BAD` + --> $DIR/drop.rs:17:1 + | +LL | }; + | ^ + +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/drop.rs:16:9 + | +LL | let _v: Vec<i32> = Vec::new(); + | ^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.rs b/tests/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.rs new file mode 100644 index 000000000..c24d3338e --- /dev/null +++ b/tests/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.rs @@ -0,0 +1,26 @@ +// a test demonstrating why we do need to run static const qualification on associated constants +// instead of just checking the final constant + +trait Foo<T> { + const X: T; +} + +trait Bar<T, U: Foo<T>> { + const F: u32 = (U::X, 42).1; //~ ERROR destructor of +} + +impl Foo<u32> for () { + const X: u32 = 42; +} + +impl Foo<Vec<u32>> for String { + const X: Vec<u32> = Vec::new(); +} + +impl Bar<u32, ()> for () {} +impl Bar<Vec<u32>, String> for String {} + +fn main() { + let x = <() as Bar<u32, ()>>::F; + let y = <String as Bar<Vec<u32>, String>>::F; +} diff --git a/tests/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr b/tests/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr new file mode 100644 index 000000000..45ed88b1b --- /dev/null +++ b/tests/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr @@ -0,0 +1,11 @@ +error[E0493]: destructor of `(T, u32)` cannot be evaluated at compile-time + --> $DIR/feature-gate-unleash_the_miri_inside_of_you.rs:9:20 + | +LL | const F: u32 = (U::X, 42).1; + | ^^^^^^^^^^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constants + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/miri_unleashed/inline_asm.rs b/tests/ui/consts/miri_unleashed/inline_asm.rs new file mode 100644 index 000000000..6fd52ceb2 --- /dev/null +++ b/tests/ui/consts/miri_unleashed/inline_asm.rs @@ -0,0 +1,13 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you +// only-x86_64 + +use std::arch::asm; + +fn main() {} + +// Make sure we catch executing inline assembly. +static TEST_BAD: () = { + unsafe { asm!("nop"); } + //~^ ERROR could not evaluate static initializer + //~| NOTE inline assembly is not supported +}; diff --git a/tests/ui/consts/miri_unleashed/inline_asm.stderr b/tests/ui/consts/miri_unleashed/inline_asm.stderr new file mode 100644 index 000000000..6317cd882 --- /dev/null +++ b/tests/ui/consts/miri_unleashed/inline_asm.stderr @@ -0,0 +1,17 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/inline_asm.rs:10:14 + | +LL | unsafe { asm!("nop"); } + | ^^^^^^^^^^^ inline assembly is not supported + +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/inline_asm.rs:10:14 + | +LL | unsafe { asm!("nop"); } + | ^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/mutable_references.rs b/tests/ui/consts/miri_unleashed/mutable_references.rs new file mode 100644 index 000000000..4e9964647 --- /dev/null +++ b/tests/ui/consts/miri_unleashed/mutable_references.rs @@ -0,0 +1,36 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you + +use std::cell::UnsafeCell; + +// a test demonstrating what things we could allow with a smarter const qualification + +// this is fine because is not possible to mutate through an immutable reference. +static FOO: &&mut u32 = &&mut 42; + +// this is fine because accessing an immutable static `BAR` is equivalent to accessing `*&BAR` +// which puts the mutable reference behind an immutable one. +static BAR: &mut () = &mut (); + +struct Foo<T>(T); + +// this is fine for the same reason as `BAR`. +static BOO: &mut Foo<()> = &mut Foo(()); + +// interior mutability is fine +struct Meh { + x: &'static UnsafeCell<i32>, +} +unsafe impl Sync for Meh {} +static MEH: Meh = Meh { + x: &UnsafeCell::new(42), +}; + +// this is fine for the same reason as `BAR`. +static OH_YES: &mut i32 = &mut 42; + +fn main() { + unsafe { + *MEH.x.get() = 99; + } + *OH_YES = 99; //~ ERROR cannot assign to `*OH_YES`, as `OH_YES` is an immutable static item +} diff --git a/tests/ui/consts/miri_unleashed/mutable_references.stderr b/tests/ui/consts/miri_unleashed/mutable_references.stderr new file mode 100644 index 000000000..3ed96701a --- /dev/null +++ b/tests/ui/consts/miri_unleashed/mutable_references.stderr @@ -0,0 +1,37 @@ +error[E0594]: cannot assign to `*OH_YES`, as `OH_YES` is an immutable static item + --> $DIR/mutable_references.rs:35:5 + | +LL | *OH_YES = 99; + | ^^^^^^^^^^^^ cannot assign + +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references.rs:8:26 + | +LL | static FOO: &&mut u32 = &&mut 42; + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references.rs:12:23 + | +LL | static BAR: &mut () = &mut (); + | ^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references.rs:17:28 + | +LL | static BOO: &mut Foo<()> = &mut Foo(()); + | ^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references.rs:25:8 + | +LL | x: &UnsafeCell::new(42), + | ^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references.rs:29:27 + | +LL | static OH_YES: &mut i32 = &mut 42; + | ^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0594`. diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr b/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr new file mode 100644 index 000000000..0ea179240 --- /dev/null +++ b/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr @@ -0,0 +1,54 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/mutable_references_err.rs:15:1 + | +LL | const MUH: Meh = Meh { + | ^^^^^^^^^^^^^^ constructing invalid value at .x.<deref>: encountered `UnsafeCell` in a `const` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + ╾─alloc3──╼ │ ╾──╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/mutable_references_err.rs:25:1 + | +LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>.x: encountered `UnsafeCell` in a `const` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾─alloc7──╼ ╾─alloc8──╼ │ ╾──╼╾──╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/mutable_references_err.rs:29:1 + | +LL | const BLUNT: &mut i32 = &mut 42; + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference in a `const` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + ╾─alloc10─╼ │ ╾──╼ + } + +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:16:8 + | +LL | x: &UnsafeCell::new(42), + | ^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:25:27 + | +LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:29:25 + | +LL | const BLUNT: &mut i32 = &mut 42; + | ^^^^^^^ + +error: aborting due to 3 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr b/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr new file mode 100644 index 000000000..67959d256 --- /dev/null +++ b/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr @@ -0,0 +1,54 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/mutable_references_err.rs:15:1 + | +LL | const MUH: Meh = Meh { + | ^^^^^^^^^^^^^^ constructing invalid value at .x.<deref>: encountered `UnsafeCell` in a `const` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + ╾───────alloc3────────╼ │ ╾──────╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/mutable_references_err.rs:25:1 + | +LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>.x: encountered `UnsafeCell` in a `const` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾───────alloc7────────╼ ╾───────alloc8────────╼ │ ╾──────╼╾──────╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/mutable_references_err.rs:29:1 + | +LL | const BLUNT: &mut i32 = &mut 42; + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference in a `const` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + ╾───────alloc10───────╼ │ ╾──────╼ + } + +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:16:8 + | +LL | x: &UnsafeCell::new(42), + | ^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:25:27 + | +LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/mutable_references_err.rs:29:25 + | +LL | const BLUNT: &mut i32 = &mut 42; + | ^^^^^^^ + +error: aborting due to 3 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.rs b/tests/ui/consts/miri_unleashed/mutable_references_err.rs new file mode 100644 index 000000000..6399b122b --- /dev/null +++ b/tests/ui/consts/miri_unleashed/mutable_references_err.rs @@ -0,0 +1,36 @@ +// stderr-per-bitwidth +// compile-flags: -Zunleash-the-miri-inside-of-you + +use std::cell::UnsafeCell; + +// this test ensures that our mutability story is sound + +struct Meh { + x: &'static UnsafeCell<i32>, +} +unsafe impl Sync for Meh {} + +// the following will never be ok! no interior mut behind consts, because +// all allocs interned here will be marked immutable. +const MUH: Meh = Meh { //~ ERROR: it is undefined behavior to use this value + x: &UnsafeCell::new(42), +}; + +struct Synced { + x: UnsafeCell<i32>, +} +unsafe impl Sync for Synced {} + +// Make sure we also catch this behind a type-erased `dyn Trait` reference. +const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; +//~^ ERROR: it is undefined behavior to use this value + +// Make sure we also catch mutable references. +const BLUNT: &mut i32 = &mut 42; +//~^ ERROR: it is undefined behavior to use this value + +fn main() { + unsafe { + *MUH.x.get() = 99; + } +} diff --git a/tests/ui/consts/miri_unleashed/mutating_global.rs b/tests/ui/consts/miri_unleashed/mutating_global.rs new file mode 100644 index 000000000..231f4af0a --- /dev/null +++ b/tests/ui/consts/miri_unleashed/mutating_global.rs @@ -0,0 +1,15 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you + +// Make sure we cannot mutate globals. + +static mut GLOBAL: i32 = 0; + +static MUTATING_GLOBAL: () = { + unsafe { + GLOBAL = 99 + //~^ ERROR could not evaluate static initializer + //~| NOTE modifying a static's initial value + } +}; + +fn main() {} diff --git a/tests/ui/consts/miri_unleashed/mutating_global.stderr b/tests/ui/consts/miri_unleashed/mutating_global.stderr new file mode 100644 index 000000000..c8770c8d7 --- /dev/null +++ b/tests/ui/consts/miri_unleashed/mutating_global.stderr @@ -0,0 +1,9 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/mutating_global.rs:9:9 + | +LL | GLOBAL = 99 + | ^^^^^^^^^^^ modifying a static's initial value from another static's initializer + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/non_const_fn.rs b/tests/ui/consts/miri_unleashed/non_const_fn.rs new file mode 100644 index 000000000..44ab60dca --- /dev/null +++ b/tests/ui/consts/miri_unleashed/non_const_fn.rs @@ -0,0 +1,11 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you + +// A test demonstrating that we prevent calling non-const fn during CTFE. + +fn foo() {} + +static C: () = foo(); +//~^ ERROR could not evaluate static initializer +//~| NOTE calling non-const function `foo` + +fn main() {} diff --git a/tests/ui/consts/miri_unleashed/non_const_fn.stderr b/tests/ui/consts/miri_unleashed/non_const_fn.stderr new file mode 100644 index 000000000..57836f796 --- /dev/null +++ b/tests/ui/consts/miri_unleashed/non_const_fn.stderr @@ -0,0 +1,17 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/non_const_fn.rs:7:16 + | +LL | static C: () = foo(); + | ^^^^^ calling non-const function `foo` + +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/non_const_fn.rs:7:16 + | +LL | static C: () = foo(); + | ^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/ptr_arith.rs b/tests/ui/consts/miri_unleashed/ptr_arith.rs new file mode 100644 index 000000000..4d12960b8 --- /dev/null +++ b/tests/ui/consts/miri_unleashed/ptr_arith.rs @@ -0,0 +1,24 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you +#![feature(core_intrinsics)] + +// During CTFE, we prevent pointer-to-int casts. +// Pointer comparisons are prevented in the trait system. + +static PTR_INT_CAST: () = { + let x = &0 as *const _ as usize; + //~^ ERROR could not evaluate static initializer + //~| exposing pointers + let _v = x == x; +}; + +static PTR_INT_TRANSMUTE: () = unsafe { + let x: usize = std::mem::transmute(&0); + let _v = x + 0; + //~^ ERROR could not evaluate static initializer + //~| unable to turn pointer into raw bytes +}; + +// I'd love to test pointer comparison, but that is not possible since +// their `PartialEq` impl is non-`const`. + +fn main() {} diff --git a/tests/ui/consts/miri_unleashed/ptr_arith.stderr b/tests/ui/consts/miri_unleashed/ptr_arith.stderr new file mode 100644 index 000000000..30fd3a55e --- /dev/null +++ b/tests/ui/consts/miri_unleashed/ptr_arith.stderr @@ -0,0 +1,26 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/ptr_arith.rs:8:13 + | +LL | let x = &0 as *const _ as usize; + | ^^^^^^^^^^^^^^^^^^^^^^^ exposing pointers is not possible at compile-time + +error[E0080]: could not evaluate static initializer + --> $DIR/ptr_arith.rs:16:14 + | +LL | let _v = x + 0; + | ^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/ptr_arith.rs:8:13 + | +LL | let x = &0 as *const _ as usize; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/raw_mutable_const.rs b/tests/ui/consts/miri_unleashed/raw_mutable_const.rs new file mode 100644 index 000000000..5f8ec4e6e --- /dev/null +++ b/tests/ui/consts/miri_unleashed/raw_mutable_const.rs @@ -0,0 +1,8 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you + +use std::cell::UnsafeCell; + +const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; +//~^ ERROR: untyped pointers are not allowed in constant + +fn main() {} diff --git a/tests/ui/consts/miri_unleashed/raw_mutable_const.stderr b/tests/ui/consts/miri_unleashed/raw_mutable_const.stderr new file mode 100644 index 000000000..f8dc11d69 --- /dev/null +++ b/tests/ui/consts/miri_unleashed/raw_mutable_const.stderr @@ -0,0 +1,16 @@ +error: untyped pointers are not allowed in constant + --> $DIR/raw_mutable_const.rs:5:1 + | +LL | const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/raw_mutable_const.rs:5:38 + | +LL | const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/ui/consts/miri_unleashed/slice_eq.rs b/tests/ui/consts/miri_unleashed/slice_eq.rs new file mode 100644 index 000000000..83e10bf12 --- /dev/null +++ b/tests/ui/consts/miri_unleashed/slice_eq.rs @@ -0,0 +1,13 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you +// run-pass + +#![feature(const_raw_ptr_comparison)] + +const EMPTY_SLICE: &[i32] = &[]; +const EMPTY_EQ: Option<bool> = EMPTY_SLICE.as_ptr().guaranteed_eq(&[] as *const _); +const EMPTY_EQ2: Option<bool> = EMPTY_SLICE.as_ptr().guaranteed_eq(&[1] as *const _); + +fn main() { + assert!(EMPTY_EQ.is_none()); + assert!(EMPTY_EQ2.is_none()); +} diff --git a/tests/ui/consts/miri_unleashed/tls.rs b/tests/ui/consts/miri_unleashed/tls.rs new file mode 100644 index 000000000..d06d7cf19 --- /dev/null +++ b/tests/ui/consts/miri_unleashed/tls.rs @@ -0,0 +1,23 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you +#![feature(thread_local)] + +use std::thread; + +#[thread_local] +static A: u8 = 0; + +// Make sure we catch accessing thread-local storage. +static TEST_BAD: () = { + unsafe { let _val = A; } + //~^ ERROR could not evaluate static initializer + //~| NOTE cannot access thread local static +}; + +// Make sure we catch taking a reference to thread-local storage. +static TEST_BAD_REF: () = { + unsafe { let _val = &A; } + //~^ ERROR could not evaluate static initializer + //~| NOTE cannot access thread local static +}; + +fn main() {} diff --git a/tests/ui/consts/miri_unleashed/tls.stderr b/tests/ui/consts/miri_unleashed/tls.stderr new file mode 100644 index 000000000..7aaeadd04 --- /dev/null +++ b/tests/ui/consts/miri_unleashed/tls.stderr @@ -0,0 +1,28 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/tls.rs:11:25 + | +LL | unsafe { let _val = A; } + | ^ cannot access thread local static (DefId(0:4 ~ tls[78b0]::A)) + +error[E0080]: could not evaluate static initializer + --> $DIR/tls.rs:18:26 + | +LL | unsafe { let _val = &A; } + | ^ cannot access thread local static (DefId(0:4 ~ tls[78b0]::A)) + +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/tls.rs:11:25 + | +LL | unsafe { let _val = A; } + | ^ +help: skipping check that does not even have a feature gate + --> $DIR/tls.rs:18:26 + | +LL | unsafe { let _val = &A; } + | ^ + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/missing_span_in_backtrace.rs b/tests/ui/consts/missing_span_in_backtrace.rs new file mode 100644 index 000000000..dd2b81c5a --- /dev/null +++ b/tests/ui/consts/missing_span_in_backtrace.rs @@ -0,0 +1,27 @@ +// compile-flags: -Z ui-testing=no +// normalize-stderr-test "alloc[0-9]+" -> "ALLOC_ID" + +#![feature(const_swap)] +#![feature(const_mut_refs)] +use std::{ + mem::{self, MaybeUninit}, + ptr, +}; + +const X: () = { + let mut ptr1 = &1; + let mut ptr2 = &2; + + // Swap them, bytewise. + unsafe { + ptr::swap_nonoverlapping( + &mut ptr1 as *mut _ as *mut MaybeUninit<u8>, + &mut ptr2 as *mut _ as *mut MaybeUninit<u8>, + mem::size_of::<&i32>(), + ); + } +}; + +fn main() { + X +} diff --git a/tests/ui/consts/missing_span_in_backtrace.stderr b/tests/ui/consts/missing_span_in_backtrace.stderr new file mode 100644 index 000000000..e6d3d5199 --- /dev/null +++ b/tests/ui/consts/missing_span_in_backtrace.stderr @@ -0,0 +1,28 @@ +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | + = note: unable to copy parts of a pointer from memory at ALLOC_ID + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported +note: inside `std::ptr::read::<MaybeUninit<MaybeUninit<u8>>>` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL +note: inside `mem::swap_simple::<MaybeUninit<MaybeUninit<u8>>>` + --> $SRC_DIR/core/src/mem/mod.rs:LL:COL +note: inside `ptr::swap_nonoverlapping_simple_untyped::<MaybeUninit<u8>>` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL +note: inside `swap_nonoverlapping::<MaybeUninit<u8>>` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL +note: inside `X` + --> $DIR/missing_span_in_backtrace.rs:17:9 + | +17 | / ptr::swap_nonoverlapping( +18 | | &mut ptr1 as *mut _ as *mut MaybeUninit<u8>, +19 | | &mut ptr2 as *mut _ as *mut MaybeUninit<u8>, +20 | | mem::size_of::<&i32>(), +21 | | ); + | |_________^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/mozjs-error.rs b/tests/ui/consts/mozjs-error.rs new file mode 100644 index 000000000..7edcadbf2 --- /dev/null +++ b/tests/ui/consts/mozjs-error.rs @@ -0,0 +1,31 @@ +// run-pass +#![allow(dead_code)] +#![allow(non_upper_case_globals)] + +struct CustomAutoRooterVFTable { + trace: unsafe extern "C" fn(this: *mut i32, trc: *mut u32), +} + +unsafe trait CustomAutoTraceable: Sized { + const vftable: CustomAutoRooterVFTable = CustomAutoRooterVFTable { + trace: Self::trace, + }; + + unsafe extern "C" fn trace(this: *mut i32, trc: *mut u32) { + let this = this as *const Self; + let this = this.as_ref().unwrap(); + Self::do_trace(this, trc); + } + + fn do_trace(&self, trc: *mut u32); +} + +unsafe impl CustomAutoTraceable for () { + fn do_trace(&self, _: *mut u32) { + // nop + } +} + +fn main() { + let _ = <()>::vftable; +} diff --git a/tests/ui/consts/nested_erroneous_ctfe.rs b/tests/ui/consts/nested_erroneous_ctfe.rs new file mode 100644 index 000000000..1ec271401 --- /dev/null +++ b/tests/ui/consts/nested_erroneous_ctfe.rs @@ -0,0 +1,4 @@ +fn main() { + [9; || [9; []]]; + //~^ ERROR: mismatched types +} diff --git a/tests/ui/consts/nested_erroneous_ctfe.stderr b/tests/ui/consts/nested_erroneous_ctfe.stderr new file mode 100644 index 000000000..d579a54e9 --- /dev/null +++ b/tests/ui/consts/nested_erroneous_ctfe.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/nested_erroneous_ctfe.rs:2:16 + | +LL | [9; || [9; []]]; + | ^^ expected `usize`, found array of 0 elements + | + = note: expected type `usize` + found array `[_; 0]` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/non-const-value-in-const.rs b/tests/ui/consts/non-const-value-in-const.rs new file mode 100644 index 000000000..1a20b1e09 --- /dev/null +++ b/tests/ui/consts/non-const-value-in-const.rs @@ -0,0 +1,7 @@ +fn main() { + let x = 5; + const Y: i32 = x; //~ ERROR attempt to use a non-constant value in a constant [E0435] + + let x = 5; + let _ = [0; x]; //~ ERROR attempt to use a non-constant value in a constant [E0435] +} diff --git a/tests/ui/consts/non-const-value-in-const.stderr b/tests/ui/consts/non-const-value-in-const.stderr new file mode 100644 index 000000000..0ce4b4b70 --- /dev/null +++ b/tests/ui/consts/non-const-value-in-const.stderr @@ -0,0 +1,20 @@ +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/non-const-value-in-const.rs:3:20 + | +LL | const Y: i32 = x; + | ------- ^ non-constant value + | | + | help: consider using `let` instead of `const`: `let Y` + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/non-const-value-in-const.rs:6:17 + | +LL | let x = 5; + | ----- help: consider using `const` instead of `let`: `const x` +... +LL | let _ = [0; x]; + | ^ non-constant value + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0435`. diff --git a/tests/ui/consts/non-scalar-cast.rs b/tests/ui/consts/non-scalar-cast.rs new file mode 100644 index 000000000..671366c90 --- /dev/null +++ b/tests/ui/consts/non-scalar-cast.rs @@ -0,0 +1,9 @@ +// run-pass + +// https://github.com/rust-lang/rust/issues/37448 + +fn main() { + struct A; + const FOO: &A = &(A as A); + let _x = FOO; +} diff --git a/tests/ui/consts/offset.rs b/tests/ui/consts/offset.rs new file mode 100644 index 000000000..b2c663fe6 --- /dev/null +++ b/tests/ui/consts/offset.rs @@ -0,0 +1,112 @@ +// run-pass +use std::ptr; + +#[repr(C)] +struct Struct { + a: u32, + b: u32, + c: u32, +} +static S: Struct = Struct { a: 0, b: 0, c: 0 }; + +// For these tests we use offset_from to check that two pointers are equal. +// Rust doesn't currently support comparing pointers in const fn. + +static OFFSET_NO_CHANGE: bool = unsafe { + let p1 = &S.b as *const u32; + let p2 = p1.offset(2).offset(-2); + p1.offset_from(p2) == 0 +}; +static OFFSET_MIDDLE: bool = unsafe { + let p1 = (&S.a as *const u32).offset(1); + let p2 = (&S.c as *const u32).offset(-1); + p1.offset_from(p2) == 0 +}; +// Pointing to the end of the allocation is OK +static OFFSET_END: bool = unsafe { + let p1 = (&S.a as *const u32).offset(3); + let p2 = (&S.c as *const u32).offset(1); + p1.offset_from(p2) == 0 +}; +// Casting though a differently sized type is OK +static OFFSET_U8_PTR: bool = unsafe { + let p1 = (&S.a as *const u32 as *const u8).offset(5); + let p2 = (&S.c as *const u32 as *const u8).offset(-3); + p1.offset_from(p2) == 0 +}; +// Any offset with a ZST does nothing +const OFFSET_ZST: bool = unsafe { + let pz = &() as *const (); + // offset_from can't work with ZSTs, so cast to u8 ptr + let p1 = pz.offset(5) as *const u8; + let p2 = pz.offset(isize::MIN) as *const u8; + p1.offset_from(p2) == 0 +}; +const OFFSET_ZERO: bool = unsafe { + let p = [0u8; 0].as_ptr(); + p.offset(0).offset_from(p) == 0 +}; +const OFFSET_ONE: bool = unsafe { + let p = &42u32 as *const u32; + p.offset(1).offset_from(p) == 1 +}; +const OFFSET_DANGLING: bool = unsafe { + let p = ptr::NonNull::<u8>::dangling().as_ptr(); + p.offset(0).offset_from(p) == 0 +}; +const OFFSET_UNALIGNED: bool = unsafe { + let arr = [0u8; 32]; + let p1 = arr.as_ptr(); + let p2 = (p1.offset(2) as *const u32).offset(1); + (p2 as *const u8).offset_from(p1) == 6 +}; + +const WRAP_OFFSET_NO_CHANGE: bool = unsafe { + let p1 = &42u32 as *const u32; + let p2 = p1.wrapping_offset(1000).wrapping_offset(-1000); + let p3 = p1.wrapping_offset(-1000).wrapping_offset(1000); + (p1.offset_from(p2) == 0) & (p1.offset_from(p3) == 0) +}; +const WRAP_ADDRESS_SPACE: bool = unsafe { + let p1 = &42u8 as *const u8; + let p2 = p1.wrapping_offset(isize::MIN).wrapping_offset(isize::MIN); + p1.offset_from(p2) == 0 +}; +// Wrap on the count*size_of::<T>() calculation. +const WRAP_SIZE_OF: bool = unsafe { + // Make sure that if p1 moves backwards, we are still in range + let arr = [0u32; 2]; + let p = &arr[1] as *const u32; + // With wrapping arithmetic, isize::MAX * 4 == -4 + let wrapped = p.wrapping_offset(isize::MAX); + let backward = p.wrapping_offset(-1); + wrapped.offset_from(backward) == 0 +}; +const WRAP_INTEGER_POINTER: bool = unsafe { + let p1 = (0x42 as *const u32).wrapping_offset(4); + let p2 = 0x52 as *const u32; + p1.offset_from(p2) == 0 +}; +const WRAP_NULL: bool = unsafe { + let p1 = ptr::null::<u32>().wrapping_offset(1); + let p2 = 0x4 as *const u32; + p1.offset_from(p2) == 0 +}; + +fn main() { + assert!(OFFSET_NO_CHANGE); + assert!(OFFSET_MIDDLE); + assert!(OFFSET_END); + assert!(OFFSET_U8_PTR); + assert!(OFFSET_ZST); + assert!(OFFSET_ZERO); + assert!(OFFSET_ONE); + assert!(OFFSET_DANGLING); + assert!(OFFSET_UNALIGNED); + + assert!(WRAP_OFFSET_NO_CHANGE); + assert!(WRAP_ADDRESS_SPACE); + assert!(WRAP_SIZE_OF); + assert!(WRAP_INTEGER_POINTER); + assert!(WRAP_NULL); +} diff --git a/tests/ui/consts/offset_from.rs b/tests/ui/consts/offset_from.rs new file mode 100644 index 000000000..465147041 --- /dev/null +++ b/tests/ui/consts/offset_from.rs @@ -0,0 +1,59 @@ +// run-pass + +#![feature(const_ptr_sub_ptr)] +#![feature(ptr_sub_ptr)] + +struct Struct { + field: (), +} + +#[repr(C)] +struct Struct2 { + data: u8, + field: u8, +} + +pub const OFFSET: usize = { + let uninit = std::mem::MaybeUninit::<Struct>::uninit(); + let base_ptr: *const Struct = &uninit as *const _ as *const Struct; + // The following statement is UB (taking the address of an uninitialized field). + // Const eval doesn't detect this right now, but it may stop compiling at some point + // in the future. + let field_ptr = unsafe { &(*base_ptr).field as *const () as *const u8 }; + let offset = unsafe { field_ptr.offset_from(base_ptr as *const u8) }; + offset as usize +}; + +pub const OFFSET_2: usize = { + let uninit = std::mem::MaybeUninit::<Struct2>::uninit(); + let base_ptr: *const Struct2 = &uninit as *const _ as *const Struct2; + let field_ptr = unsafe { &(*base_ptr).field as *const u8 }; + let offset = unsafe { field_ptr.offset_from(base_ptr as *const u8) }; + offset as usize +}; + +pub const OVERFLOW: isize = { + let uninit = std::mem::MaybeUninit::<Struct2>::uninit(); + let base_ptr: *const Struct2 = &uninit as *const _ as *const Struct2; + let field_ptr = unsafe { &(*base_ptr).field as *const u8 }; + unsafe { (base_ptr as *const u8).offset_from(field_ptr) } +}; + +pub const OFFSET_EQUAL_INTS: isize = { + let ptr = 1 as *const u8; + unsafe { ptr.offset_from(ptr) } +}; + +pub const OFFSET_UNSIGNED: usize = { + let a = ['a', 'b', 'c']; + let ptr = a.as_ptr(); + unsafe { ptr.add(2).sub_ptr(ptr) } +}; + +fn main() { + assert_eq!(OFFSET, 0); + assert_eq!(OFFSET_2, 1); + assert_eq!(OVERFLOW, -1); + assert_eq!(OFFSET_EQUAL_INTS, 0); + assert_eq!(OFFSET_UNSIGNED, 2); +} diff --git a/tests/ui/consts/offset_from_ub.rs b/tests/ui/consts/offset_from_ub.rs new file mode 100644 index 000000000..51163e650 --- /dev/null +++ b/tests/ui/consts/offset_from_ub.rs @@ -0,0 +1,125 @@ +#![feature(const_ptr_sub_ptr)] +#![feature(core_intrinsics)] + +use std::intrinsics::{ptr_offset_from, ptr_offset_from_unsigned}; +use std::ptr; + +#[repr(C)] +struct Struct { + data: u8, + field: u8, +} + +pub const DIFFERENT_ALLOC: usize = { + let uninit = std::mem::MaybeUninit::<Struct>::uninit(); + let base_ptr: *const Struct = &uninit as *const _ as *const Struct; + let uninit2 = std::mem::MaybeUninit::<Struct>::uninit(); + let field_ptr: *const Struct = &uninit2 as *const _ as *const Struct; + let offset = unsafe { ptr_offset_from(field_ptr, base_ptr) }; //~ERROR evaluation of constant value failed + //~| pointers into different allocations + offset as usize +}; + +pub const NOT_PTR: usize = { + unsafe { (42 as *const u8).offset_from(&5u8) as usize } +}; + +pub const NOT_MULTIPLE_OF_SIZE: isize = { + let data = [5u8, 6, 7]; + let base_ptr = data.as_ptr(); + let field_ptr = &data[1] as *const u8 as *const u16; + unsafe { ptr_offset_from(field_ptr, base_ptr as *const u16) } //~ERROR evaluation of constant value failed + //~| 1_isize cannot be divided by 2_isize without remainder +}; + +pub const OFFSET_FROM_NULL: isize = { + let ptr = 0 as *const u8; + unsafe { ptr_offset_from(ptr, ptr) } //~ERROR evaluation of constant value failed + //~| null pointer is a dangling pointer +}; + +pub const DIFFERENT_INT: isize = { // offset_from with two different integers: like DIFFERENT_ALLOC + let ptr1 = 8 as *const u8; + let ptr2 = 16 as *const u8; + unsafe { ptr_offset_from(ptr2, ptr1) } //~ERROR evaluation of constant value failed + //~| 0x8[noalloc] is a dangling pointer +}; + +const OUT_OF_BOUNDS_1: isize = { + let start_ptr = &4 as *const _ as *const u8; + let length = 10; + let end_ptr = (start_ptr).wrapping_add(length); + // First ptr is out of bounds + unsafe { ptr_offset_from(end_ptr, start_ptr) } //~ERROR evaluation of constant value failed + //~| pointer to 10 bytes starting at offset 0 is out-of-bounds +}; + +const OUT_OF_BOUNDS_2: isize = { + let start_ptr = &4 as *const _ as *const u8; + let length = 10; + let end_ptr = (start_ptr).wrapping_add(length); + // Second ptr is out of bounds + unsafe { ptr_offset_from(start_ptr, end_ptr) } //~ERROR evaluation of constant value failed + //~| pointer to 10 bytes starting at offset 0 is out-of-bounds +}; + +const OUT_OF_BOUNDS_SAME: isize = { + let start_ptr = &4 as *const _ as *const u8; + let length = 10; + let end_ptr = (start_ptr).wrapping_add(length); + unsafe { ptr_offset_from(end_ptr, end_ptr) } //~ERROR evaluation of constant value failed + //~| pointer at offset 10 is out-of-bounds +}; + +pub const DIFFERENT_ALLOC_UNSIGNED: usize = { + let uninit = std::mem::MaybeUninit::<Struct>::uninit(); + let base_ptr: *const Struct = &uninit as *const _ as *const Struct; + let uninit2 = std::mem::MaybeUninit::<Struct>::uninit(); + let field_ptr: *const Struct = &uninit2 as *const _ as *const Struct; + unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) } //~ERROR evaluation of constant value failed + //~| pointers into different allocations +}; + +pub const TOO_FAR_APART1: isize = { + let ptr1 = ptr::null::<u8>(); + let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42); + unsafe { ptr_offset_from(ptr2, ptr1) } //~ERROR evaluation of constant value failed + //~| too far ahead +}; +pub const TOO_FAR_APART2: isize = { + let ptr1 = ptr::null::<u8>(); + let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42); + unsafe { ptr_offset_from(ptr1, ptr2) } //~ERROR evaluation of constant value failed + //~| too far before +}; + +const WRONG_ORDER_UNSIGNED: usize = { + let a = ['a', 'b', 'c']; + let p = a.as_ptr(); + unsafe { ptr_offset_from_unsigned(p, p.add(2) ) } //~ERROR evaluation of constant value failed + //~| first pointer has smaller offset than second: 0 < 8 +}; +pub const TOO_FAR_APART_UNSIGNED: usize = { + let ptr1 = ptr::null::<u8>(); + let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42); + // This would fit into a `usize` but we still don't allow it. + unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } //~ERROR evaluation of constant value failed + //~| too far ahead +}; + +// These do NOT complain that pointers are too far apart; they pass that check (to then fail the +// next one). +pub const OFFSET_VERY_FAR1: isize = { + let ptr1 = ptr::null::<u8>(); + let ptr2 = ptr1.wrapping_offset(isize::MAX); + unsafe { ptr2.offset_from(ptr1) } + //~^ inside +}; +pub const OFFSET_VERY_FAR2: isize = { + let ptr1 = ptr::null::<u8>(); + let ptr2 = ptr1.wrapping_offset(isize::MAX); + unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) } + //~^ inside +}; + +fn main() {} diff --git a/tests/ui/consts/offset_from_ub.stderr b/tests/ui/consts/offset_from_ub.stderr new file mode 100644 index 000000000..fff472968 --- /dev/null +++ b/tests/ui/consts/offset_from_ub.stderr @@ -0,0 +1,114 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/offset_from_ub.rs:18:27 + | +LL | let offset = unsafe { ptr_offset_from(field_ptr, base_ptr) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on pointers into different allocations + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | + = note: `ptr_offset_from` called on pointers into different allocations + | +note: inside `ptr::const_ptr::<impl *const u8>::offset_from` + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL +note: inside `NOT_PTR` + --> $DIR/offset_from_ub.rs:24:14 + | +LL | unsafe { (42 as *const u8).offset_from(&5u8) as usize } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $DIR/offset_from_ub.rs:31:14 + | +LL | unsafe { ptr_offset_from(field_ptr, base_ptr as *const u16) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: 1_isize cannot be divided by 2_isize without remainder + +error[E0080]: evaluation of constant value failed + --> $DIR/offset_from_ub.rs:37:14 + | +LL | unsafe { ptr_offset_from(ptr, ptr) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance) + +error[E0080]: evaluation of constant value failed + --> $DIR/offset_from_ub.rs:44:14 + | +LL | unsafe { ptr_offset_from(ptr2, ptr1) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: 0x8[noalloc] is a dangling pointer (it has no provenance) + +error[E0080]: evaluation of constant value failed + --> $DIR/offset_from_ub.rs:53:14 + | +LL | unsafe { ptr_offset_from(end_ptr, start_ptr) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc18 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds + +error[E0080]: evaluation of constant value failed + --> $DIR/offset_from_ub.rs:62:14 + | +LL | unsafe { ptr_offset_from(start_ptr, end_ptr) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc21 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds + +error[E0080]: evaluation of constant value failed + --> $DIR/offset_from_ub.rs:70:14 + | +LL | unsafe { ptr_offset_from(end_ptr, end_ptr) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc24 has size 4, so pointer at offset 10 is out-of-bounds + +error[E0080]: evaluation of constant value failed + --> $DIR/offset_from_ub.rs:79:14 + | +LL | unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on pointers into different allocations + +error[E0080]: evaluation of constant value failed + --> $DIR/offset_from_ub.rs:86:14 + | +LL | unsafe { ptr_offset_from(ptr2, ptr1) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far ahead of second + +error[E0080]: evaluation of constant value failed + --> $DIR/offset_from_ub.rs:92:14 + | +LL | unsafe { ptr_offset_from(ptr1, ptr2) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second + +error[E0080]: evaluation of constant value failed + --> $DIR/offset_from_ub.rs:99:14 + | +LL | unsafe { ptr_offset_from_unsigned(p, p.add(2) ) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 8 + +error[E0080]: evaluation of constant value failed + --> $DIR/offset_from_ub.rs:106:14 + | +LL | unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer is too far ahead of second + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | + = note: out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance) + | +note: inside `ptr::const_ptr::<impl *const u8>::offset_from` + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL +note: inside `OFFSET_VERY_FAR1` + --> $DIR/offset_from_ub.rs:115:14 + | +LL | unsafe { ptr2.offset_from(ptr1) } + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | + = note: out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance) + | +note: inside `ptr::const_ptr::<impl *const u8>::offset_from` + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL +note: inside `OFFSET_VERY_FAR2` + --> $DIR/offset_from_ub.rs:121:14 + | +LL | unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 15 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/offset_ub.rs b/tests/ui/consts/offset_ub.rs new file mode 100644 index 000000000..1b01e4fd1 --- /dev/null +++ b/tests/ui/consts/offset_ub.rs @@ -0,0 +1,26 @@ +use std::ptr; + +// normalize-stderr-test "alloc\d+" -> "allocN" +// normalize-stderr-test "0x7f+" -> "0x7f..f" + + +pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; //~NOTE +pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; //~NOTE +pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; //~NOTE + +pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; //~NOTE +pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; //~NOTE +pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) }; //~NOTE +pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; //~NOTE +pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; //~NOTE + +pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; //~NOTE +pub const DANGLING: *const u8 = unsafe { ptr::NonNull::<u8>::dangling().as_ptr().offset(4) }; //~NOTE + +// Right now, a zero offset from null is UB +pub const NULL_OFFSET_ZERO: *const u8 = unsafe { ptr::null::<u8>().offset(0) }; //~NOTE + +// Make sure that we don't panic when computing abs(offset*size_of::<T>()) +pub const UNDERFLOW_ABS: *const u8 = unsafe { (usize::MAX as *const u8).offset(isize::MIN) }; //~NOTE + +fn main() {} diff --git a/tests/ui/consts/offset_ub.stderr b/tests/ui/consts/offset_ub.stderr new file mode 100644 index 000000000..c0c851df5 --- /dev/null +++ b/tests/ui/consts/offset_ub.stderr @@ -0,0 +1,159 @@ +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | + = note: overflowing in-bounds pointer arithmetic + | +note: inside `ptr::const_ptr::<impl *const u8>::offset` + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL +note: inside `BEFORE_START` + --> $DIR/offset_ub.rs:7:46 + | +LL | pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | + = note: out-of-bounds pointer arithmetic: allocN has size 1, so pointer to 2 bytes starting at offset 0 is out-of-bounds + | +note: inside `ptr::const_ptr::<impl *const u8>::offset` + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL +note: inside `AFTER_END` + --> $DIR/offset_ub.rs:8:43 + | +LL | pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | + = note: out-of-bounds pointer arithmetic: allocN has size 100, so pointer to 101 bytes starting at offset 0 is out-of-bounds + | +note: inside `ptr::const_ptr::<impl *const u8>::offset` + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL +note: inside `AFTER_ARRAY` + --> $DIR/offset_ub.rs:9:45 + | +LL | pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | + = note: overflowing in-bounds pointer arithmetic + | +note: inside `ptr::const_ptr::<impl *const u16>::offset` + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL +note: inside `OVERFLOW` + --> $DIR/offset_ub.rs:11:43 + | +LL | pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | + = note: overflowing in-bounds pointer arithmetic + | +note: inside `ptr::const_ptr::<impl *const u16>::offset` + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL +note: inside `UNDERFLOW` + --> $DIR/offset_ub.rs:12:44 + | +LL | pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | + = note: overflowing in-bounds pointer arithmetic + | +note: inside `ptr::const_ptr::<impl *const u8>::offset` + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL +note: inside `OVERFLOW_ADDRESS_SPACE` + --> $DIR/offset_ub.rs:13:56 + | +LL | pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | + = note: overflowing in-bounds pointer arithmetic + | +note: inside `ptr::const_ptr::<impl *const u8>::offset` + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL +note: inside `UNDERFLOW_ADDRESS_SPACE` + --> $DIR/offset_ub.rs:14:57 + | +LL | pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | + = note: out-of-bounds pointer arithmetic: allocN has size 1, so pointer to 2 bytes starting at offset -4 is out-of-bounds + | +note: inside `ptr::const_ptr::<impl *const u8>::offset` + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL +note: inside `NEGATIVE_OFFSET` + --> $DIR/offset_ub.rs:15:49 + | +LL | pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | + = note: out-of-bounds pointer arithmetic: allocN has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds + | +note: inside `ptr::const_ptr::<impl *const u8>::offset` + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL +note: inside `ZERO_SIZED_ALLOC` + --> $DIR/offset_ub.rs:17:50 + | +LL | pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + | + = note: out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) + | +note: inside `ptr::mut_ptr::<impl *mut u8>::offset` + --> $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL +note: inside `DANGLING` + --> $DIR/offset_ub.rs:18:42 + | +LL | pub const DANGLING: *const u8 = unsafe { ptr::NonNull::<u8>::dangling().as_ptr().offset(4) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | + = note: out-of-bounds pointer arithmetic: null pointer is a dangling pointer (it has no provenance) + | +note: inside `ptr::const_ptr::<impl *const u8>::offset` + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL +note: inside `NULL_OFFSET_ZERO` + --> $DIR/offset_ub.rs:21:50 + | +LL | pub const NULL_OFFSET_ZERO: *const u8 = unsafe { ptr::null::<u8>().offset(0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | + = note: out-of-bounds pointer arithmetic: 0x7f..f[noalloc] is a dangling pointer (it has no provenance) + | +note: inside `ptr::const_ptr::<impl *const u8>::offset` + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL +note: inside `UNDERFLOW_ABS` + --> $DIR/offset_ub.rs:24:47 + | +LL | pub const UNDERFLOW_ABS: *const u8 = unsafe { (usize::MAX as *const u8).offset(isize::MIN) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/packed_pattern.rs b/tests/ui/consts/packed_pattern.rs new file mode 100644 index 000000000..370fec6fb --- /dev/null +++ b/tests/ui/consts/packed_pattern.rs @@ -0,0 +1,19 @@ +// run-pass + +#[derive(PartialEq, Eq, Copy, Clone)] +#[repr(packed)] +struct Foo { + field: (i64, u32, u32, u32), +} + +const FOO: Foo = Foo { + field: (5, 6, 7, 8), +}; + +fn main() { + match FOO { + Foo { field: (5, 6, 7, 8) } => {}, + FOO => unreachable!(), //~ WARNING unreachable pattern + _ => unreachable!(), + } +} diff --git a/tests/ui/consts/packed_pattern.stderr b/tests/ui/consts/packed_pattern.stderr new file mode 100644 index 000000000..9ca50a95e --- /dev/null +++ b/tests/ui/consts/packed_pattern.stderr @@ -0,0 +1,10 @@ +warning: unreachable pattern + --> $DIR/packed_pattern.rs:16:9 + | +LL | FOO => unreachable!(), + | ^^^ + | + = note: `#[warn(unreachable_patterns)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/consts/packed_pattern2.rs b/tests/ui/consts/packed_pattern2.rs new file mode 100644 index 000000000..ef68d9e51 --- /dev/null +++ b/tests/ui/consts/packed_pattern2.rs @@ -0,0 +1,27 @@ +// run-pass + +#[derive(PartialEq, Eq, Copy, Clone)] +#[repr(packed)] +struct Foo { + field: (u8, u16), +} + +#[derive(PartialEq, Eq, Copy, Clone)] +#[repr(align(2))] +struct Bar { + a: Foo, +} + +const FOO: Bar = Bar { + a: Foo { + field: (5, 6), + } +}; + +fn main() { + match FOO { + Bar { a: Foo { field: (5, 6) } } => {}, + FOO => unreachable!(), //~ WARNING unreachable pattern + _ => unreachable!(), + } +} diff --git a/tests/ui/consts/packed_pattern2.stderr b/tests/ui/consts/packed_pattern2.stderr new file mode 100644 index 000000000..4dc54461e --- /dev/null +++ b/tests/ui/consts/packed_pattern2.stderr @@ -0,0 +1,10 @@ +warning: unreachable pattern + --> $DIR/packed_pattern2.rs:24:9 + | +LL | FOO => unreachable!(), + | ^^^ + | + = note: `#[warn(unreachable_patterns)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/consts/partial_qualif.rs b/tests/ui/consts/partial_qualif.rs new file mode 100644 index 000000000..7c28b8b8a --- /dev/null +++ b/tests/ui/consts/partial_qualif.rs @@ -0,0 +1,9 @@ +use std::cell::Cell; + +const FOO: &(Cell<usize>, bool) = { + let mut a = (Cell::new(0), false); + a.1 = true; // sets `qualif(a)` to `qualif(a) | qualif(true)` + &{a} //~ ERROR cannot refer to interior mutable +}; + +fn main() {} diff --git a/tests/ui/consts/partial_qualif.stderr b/tests/ui/consts/partial_qualif.stderr new file mode 100644 index 000000000..32c25be21 --- /dev/null +++ b/tests/ui/consts/partial_qualif.stderr @@ -0,0 +1,9 @@ +error[E0492]: constants cannot refer to interior mutable data + --> $DIR/partial_qualif.rs:6:5 + | +LL | &{a} + | ^^^^ this borrow of an interior mutable value may end up in the final value + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0492`. diff --git a/tests/ui/consts/precise-drop-with-coverage.rs b/tests/ui/consts/precise-drop-with-coverage.rs new file mode 100644 index 000000000..275cb3869 --- /dev/null +++ b/tests/ui/consts/precise-drop-with-coverage.rs @@ -0,0 +1,16 @@ +// Checks that code coverage doesn't interfere with const_precise_live_drops. +// Regression test for issue #93848. +// +// check-pass +// compile-flags: --crate-type=lib -Cinstrument-coverage -Zno-profiler-runtime + +#![feature(const_precise_live_drops)] + +#[inline] +pub const fn transpose<T, E>(this: Option<Result<T, E>>) -> Result<Option<T>, E> { + match this { + Some(Ok(x)) => Ok(Some(x)), + Some(Err(e)) => Err(e), + None => Ok(None), + } +} diff --git a/tests/ui/consts/precise-drop-with-promoted.rs b/tests/ui/consts/precise-drop-with-promoted.rs new file mode 100644 index 000000000..6f2317a5a --- /dev/null +++ b/tests/ui/consts/precise-drop-with-promoted.rs @@ -0,0 +1,9 @@ +// Regression test for issue #89938. +// check-pass +// compile-flags: --crate-type=lib +#![feature(const_precise_live_drops)] + +pub const fn f() { + let _: Option<String> = None; + let _: &'static Option<String> = &None; +} diff --git a/tests/ui/consts/promote-not.rs b/tests/ui/consts/promote-not.rs new file mode 100644 index 000000000..907617052 --- /dev/null +++ b/tests/ui/consts/promote-not.rs @@ -0,0 +1,68 @@ +// ignore-tidy-linelength +// Test various things that we do not want to promote. +#![allow(unconditional_panic)] + +use std::cell::Cell; + +// We do not promote mutable references. +static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); //~ ERROR temporary value dropped while borrowed + +static mut TEST2: &'static mut [i32] = { + let x = &mut [1,2,3]; //~ ERROR temporary value dropped while borrowed + x +}; + +// We do not promote fn calls in `fn`, including `const fn`. +pub const fn promote_cal(b: bool) -> i32 { + const fn foo() { [()][42] } + + if b { + let _x: &'static () = &foo(); //~ ERROR temporary value dropped while borrowed + } + 13 +} + +// We do not promote union field accesses in `fn. +union U { x: i32, y: i32 } +pub const fn promote_union() { + let _x: &'static i32 = &unsafe { U { x: 0 }.x }; //~ ERROR temporary value dropped while borrowed +} + +// We do not promote union field accesses in `const`, either. +const TEST_UNION: () = { + let _x: &'static i32 = &unsafe { U { x: 0 }.x }; //~ ERROR temporary value dropped while borrowed +}; + +// In a `const`, we do not promote things with interior mutability. Not even if we "project it away". +const TEST_INTERIOR_MUT: () = { + // The "0." case is already ruled out by not permitting any interior mutability in `const`. + let _val: &'static _ = &(Cell::new(1), 2).1; //~ ERROR temporary value dropped while borrowed +}; + +const TEST_DROP: String = String::new(); + +fn main() { + // We must not promote things with interior mutability. Not even if we "project it away". + let _val: &'static _ = &(Cell::new(1), 2).0; //~ ERROR temporary value dropped while borrowed + let _val: &'static _ = &(Cell::new(1), 2).1; //~ ERROR temporary value dropped while borrowed + + // No promotion of fallible operations. + let _val: &'static _ = &(1/0); //~ ERROR temporary value dropped while borrowed + let _val: &'static _ = &(1/(1-1)); //~ ERROR temporary value dropped while borrowed + let _val: &'static _ = &(1%0); //~ ERROR temporary value dropped while borrowed + let _val: &'static _ = &(1%(1-1)); //~ ERROR temporary value dropped while borrowed + let _val: &'static _ = &([1,2,3][4]+1); //~ ERROR temporary value dropped while borrowed + + // No promotion of temporaries that need to be dropped. + let _val: &'static _ = &TEST_DROP; + //~^ ERROR temporary value dropped while borrowed + let _val: &'static _ = &&TEST_DROP; + //~^ ERROR temporary value dropped while borrowed + //~| ERROR temporary value dropped while borrowed + let _val: &'static _ = &(&TEST_DROP,); + //~^ ERROR temporary value dropped while borrowed + //~| ERROR temporary value dropped while borrowed + let _val: &'static _ = &[&TEST_DROP; 1]; + //~^ ERROR temporary value dropped while borrowed + //~| ERROR temporary value dropped while borrowed +} diff --git a/tests/ui/consts/promote-not.stderr b/tests/ui/consts/promote-not.stderr new file mode 100644 index 000000000..b93358e8d --- /dev/null +++ b/tests/ui/consts/promote-not.stderr @@ -0,0 +1,215 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:8:50 + | +LL | static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); + | ----------^^^^^^^^^- + | | | | + | | | temporary value is freed at the end of this statement + | | creates a temporary value which is freed while still in use + | using this value as a static requires that borrow lasts for `'static` + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:11:18 + | +LL | let x = &mut [1,2,3]; + | ^^^^^^^ creates a temporary value which is freed while still in use +LL | x + | - using this value as a static requires that borrow lasts for `'static` +LL | }; + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:20:32 + | +LL | let _x: &'static () = &foo(); + | ----------- ^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:28:29 + | +LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x }; + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:33:29 + | +LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x }; + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | }; + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:39:29 + | +LL | let _val: &'static _ = &(Cell::new(1), 2).1; + | ---------- ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | }; + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:46:29 + | +LL | let _val: &'static _ = &(Cell::new(1), 2).0; + | ---------- ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:47:29 + | +LL | let _val: &'static _ = &(Cell::new(1), 2).1; + | ---------- ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:50:29 + | +LL | let _val: &'static _ = &(1/0); + | ---------- ^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:51:29 + | +LL | let _val: &'static _ = &(1/(1-1)); + | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:52:29 + | +LL | let _val: &'static _ = &(1%0); + | ---------- ^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:53:29 + | +LL | let _val: &'static _ = &(1%(1-1)); + | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:54:29 + | +LL | let _val: &'static _ = &([1,2,3][4]+1); + | ---------- ^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:57:29 + | +LL | let _val: &'static _ = &TEST_DROP; + | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:59:29 + | +LL | let _val: &'static _ = &&TEST_DROP; + | ---------- ^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:59:30 + | +LL | let _val: &'static _ = &&TEST_DROP; + | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:62:29 + | +LL | let _val: &'static _ = &(&TEST_DROP,); + | ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:62:31 + | +LL | let _val: &'static _ = &(&TEST_DROP,); + | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:65:29 + | +LL | let _val: &'static _ = &[&TEST_DROP; 1]; + | ---------- ^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:65:31 + | +LL | let _val: &'static _ = &[&TEST_DROP; 1]; + | ---------- ^^^^^^^^^ - temporary value is freed at the end of this statement + | | | + | | creates a temporary value which is freed while still in use + | type annotation requires that borrow lasts for `'static` + +error: aborting due to 20 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/promote_borrowed_field.rs b/tests/ui/consts/promote_borrowed_field.rs new file mode 100644 index 000000000..c4841b46f --- /dev/null +++ b/tests/ui/consts/promote_borrowed_field.rs @@ -0,0 +1,12 @@ +// run-pass + +// From https://github.com/rust-lang/rust/issues/65727 + +const _: &i32 = { + let x = &(5, false).0; + x +}; + +fn main() { + let _: &'static i32 = &(5, false).0; +} diff --git a/tests/ui/consts/promote_const_let.rs b/tests/ui/consts/promote_const_let.rs new file mode 100644 index 000000000..51a0fec2e --- /dev/null +++ b/tests/ui/consts/promote_const_let.rs @@ -0,0 +1,10 @@ +fn main() { + let x: &'static u32 = { + let y = 42; + &y //~ ERROR does not live long enough + }; + let x: &'static u32 = &{ //~ ERROR temporary value dropped while borrowed + let y = 42; + y + }; +} diff --git a/tests/ui/consts/promote_const_let.stderr b/tests/ui/consts/promote_const_let.stderr new file mode 100644 index 000000000..975a235a6 --- /dev/null +++ b/tests/ui/consts/promote_const_let.stderr @@ -0,0 +1,29 @@ +error[E0597]: `y` does not live long enough + --> $DIR/promote_const_let.rs:4:9 + | +LL | let x: &'static u32 = { + | ------------ type annotation requires that `y` is borrowed for `'static` +LL | let y = 42; +LL | &y + | ^^ borrowed value does not live long enough +LL | }; + | - `y` dropped here while still borrowed + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote_const_let.rs:6:28 + | +LL | let x: &'static u32 = &{ + | ____________------------____^ + | | | + | | type annotation requires that borrow lasts for `'static` +LL | | let y = 42; +LL | | y +LL | | }; + | |_____^ creates a temporary value which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0597, E0716. +For more information about an error, try `rustc --explain E0597`. diff --git a/tests/ui/consts/promote_evaluation_unused_result.rs b/tests/ui/consts/promote_evaluation_unused_result.rs new file mode 100644 index 000000000..4eda785bb --- /dev/null +++ b/tests/ui/consts/promote_evaluation_unused_result.rs @@ -0,0 +1,6 @@ +// build-pass (FIXME(62277): could be check-pass?) + +fn main() { + + let _: &'static usize = &(loop {}, 1).1; +} diff --git a/tests/ui/consts/promote_fn_calls.rs b/tests/ui/consts/promote_fn_calls.rs new file mode 100644 index 000000000..8995aaacd --- /dev/null +++ b/tests/ui/consts/promote_fn_calls.rs @@ -0,0 +1,11 @@ +// build-pass (FIXME(62277): could be check-pass?) +// aux-build:promotable_const_fn_lib.rs + +extern crate promotable_const_fn_lib; + +use promotable_const_fn_lib::{foo, Foo}; + +fn main() { + let x: &'static usize = &foo(); + let x: &'static usize = &Foo::foo(); +} diff --git a/tests/ui/consts/promote_fn_calls_std.rs b/tests/ui/consts/promote_fn_calls_std.rs new file mode 100644 index 000000000..557f6a434 --- /dev/null +++ b/tests/ui/consts/promote_fn_calls_std.rs @@ -0,0 +1,29 @@ +#![allow(deprecated, deprecated_in_future)] // can be removed if different fns are chosen +// build-pass (FIXME(62277): could be check-pass?) + +fn main() { + let x: &'static u8 = &u8::max_value(); + let x: &'static u16 = &u16::max_value(); + let x: &'static u32 = &u32::max_value(); + let x: &'static u64 = &u64::max_value(); + let x: &'static u128 = &u128::max_value(); + let x: &'static usize = &usize::max_value(); + let x: &'static u8 = &u8::min_value(); + let x: &'static u16 = &u16::min_value(); + let x: &'static u32 = &u32::min_value(); + let x: &'static u64 = &u64::min_value(); + let x: &'static u128 = &u128::min_value(); + let x: &'static usize = &usize::min_value(); + let x: &'static i8 = &i8::max_value(); + let x: &'static i16 = &i16::max_value(); + let x: &'static i32 = &i32::max_value(); + let x: &'static i64 = &i64::max_value(); + let x: &'static i128 = &i128::max_value(); + let x: &'static isize = &isize::max_value(); + let x: &'static i8 = &i8::min_value(); + let x: &'static i16 = &i16::min_value(); + let x: &'static i32 = &i32::min_value(); + let x: &'static i64 = &i64::min_value(); + let x: &'static i128 = &i128::min_value(); + let x: &'static isize = &isize::min_value(); +} diff --git a/tests/ui/consts/promoted-const-drop.rs b/tests/ui/consts/promoted-const-drop.rs new file mode 100644 index 000000000..c896c011a --- /dev/null +++ b/tests/ui/consts/promoted-const-drop.rs @@ -0,0 +1,15 @@ +#![feature(const_trait_impl)] +#![feature(const_mut_refs)] + +struct A(); + +impl const Drop for A { + fn drop(&mut self) {} +} + +const C: A = A(); + +fn main() { + let _: &'static A = &A(); //~ ERROR temporary value dropped while borrowed + let _: &'static [A] = &[C]; //~ ERROR temporary value dropped while borrowed +} diff --git a/tests/ui/consts/promoted-const-drop.stderr b/tests/ui/consts/promoted-const-drop.stderr new file mode 100644 index 000000000..480283417 --- /dev/null +++ b/tests/ui/consts/promoted-const-drop.stderr @@ -0,0 +1,24 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted-const-drop.rs:13:26 + | +LL | let _: &'static A = &A(); + | ---------- ^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | let _: &'static [A] = &[C]; +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted-const-drop.rs:14:28 + | +LL | let _: &'static [A] = &[C]; + | ------------ ^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/promoted-storage.rs b/tests/ui/consts/promoted-storage.rs new file mode 100644 index 000000000..52ef685e8 --- /dev/null +++ b/tests/ui/consts/promoted-storage.rs @@ -0,0 +1,20 @@ +// Check that storage statements reset local qualification. +// check-pass +use std::cell::Cell; + +const C: Option<Cell<u32>> = { + let mut c = None; + let mut i = 0; + while i == 0 { + let mut x = None; + c = x; + x = Some(Cell::new(0)); + let _ = x; + i += 1; + } + c +}; + +fn main() { + let _: &'static _ = &C; +} diff --git a/tests/ui/consts/promoted-validation-55454.rs b/tests/ui/consts/promoted-validation-55454.rs new file mode 100644 index 000000000..23cae4fb5 --- /dev/null +++ b/tests/ui/consts/promoted-validation-55454.rs @@ -0,0 +1,9 @@ +// https://github.com/rust-lang/rust/issues/55454 +// build-pass (FIXME(62277): could be check-pass?) + +#[derive(PartialEq)] +struct This<T>(T); + +fn main() { + This(Some(&1)) == This(Some(&1)); +} diff --git a/tests/ui/consts/promoted_const_call.rs b/tests/ui/consts/promoted_const_call.rs new file mode 100644 index 000000000..30ae73053 --- /dev/null +++ b/tests/ui/consts/promoted_const_call.rs @@ -0,0 +1,19 @@ +#![feature(const_mut_refs)] +#![feature(const_trait_impl)] +struct Panic; +impl const Drop for Panic { fn drop(&mut self) { panic!(); } } +pub const fn id<T>(x: T) -> T { x } +pub const C: () = { + let _: &'static _ = &id(&Panic); + //~^ ERROR: temporary value dropped while borrowed + //~| ERROR: temporary value dropped while borrowed +}; + +fn main() { + let _: &'static _ = &id(&Panic); + //~^ ERROR: temporary value dropped while borrowed + //~| ERROR: temporary value dropped while borrowed + let _: &'static _ = &&(Panic, 0).1; + //~^ ERROR: temporary value dropped while borrowed + //~| ERROR: temporary value dropped while borrowed +} diff --git a/tests/ui/consts/promoted_const_call.stderr b/tests/ui/consts/promoted_const_call.stderr new file mode 100644 index 000000000..83cc16f6f --- /dev/null +++ b/tests/ui/consts/promoted_const_call.stderr @@ -0,0 +1,65 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call.rs:7:26 + | +LL | let _: &'static _ = &id(&Panic); + | ---------- ^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | }; + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call.rs:7:30 + | +LL | let _: &'static _ = &id(&Panic); + | ---------- ^^^^^ - temporary value is freed at the end of this statement + | | | + | | creates a temporary value which is freed while still in use + | type annotation requires that borrow lasts for `'static` + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call.rs:13:26 + | +LL | let _: &'static _ = &id(&Panic); + | ---------- ^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call.rs:13:30 + | +LL | let _: &'static _ = &id(&Panic); + | ---------- ^^^^^ - temporary value is freed at the end of this statement + | | | + | | creates a temporary value which is freed while still in use + | type annotation requires that borrow lasts for `'static` + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call.rs:16:26 + | +LL | let _: &'static _ = &&(Panic, 0).1; + | ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call.rs:16:27 + | +LL | let _: &'static _ = &&(Panic, 0).1; + | ---------- ^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/promoted_const_call2.rs b/tests/ui/consts/promoted_const_call2.rs new file mode 100644 index 000000000..f332cd18c --- /dev/null +++ b/tests/ui/consts/promoted_const_call2.rs @@ -0,0 +1,14 @@ +#![feature(const_precise_live_drops)] +pub const fn id<T>(x: T) -> T { x } +pub const C: () = { + let _: &'static _ = &id(&String::new()); + //~^ ERROR: temporary value dropped while borrowed + //~| ERROR: temporary value dropped while borrowed + //~| ERROR: destructor of `String` cannot be evaluated at compile-time +}; + +fn main() { + let _: &'static _ = &id(&String::new()); + //~^ ERROR: temporary value dropped while borrowed + //~| ERROR: temporary value dropped while borrowed +} diff --git a/tests/ui/consts/promoted_const_call2.stderr b/tests/ui/consts/promoted_const_call2.stderr new file mode 100644 index 000000000..13d864ed3 --- /dev/null +++ b/tests/ui/consts/promoted_const_call2.stderr @@ -0,0 +1,50 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call2.rs:4:26 + | +LL | let _: &'static _ = &id(&String::new()); + | ---------- ^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | }; + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call2.rs:4:30 + | +LL | let _: &'static _ = &id(&String::new()); + | ---------- ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement + | | | + | | creates a temporary value which is freed while still in use + | type annotation requires that borrow lasts for `'static` + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call2.rs:11:26 + | +LL | let _: &'static _ = &id(&String::new()); + | ---------- ^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call2.rs:11:30 + | +LL | let _: &'static _ = &id(&String::new()); + | ---------- ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement + | | | + | | creates a temporary value which is freed while still in use + | type annotation requires that borrow lasts for `'static` + +error[E0493]: destructor of `String` cannot be evaluated at compile-time + --> $DIR/promoted_const_call2.rs:4:30 + | +LL | let _: &'static _ = &id(&String::new()); + | ^^^^^^^^^^^^^ the destructor for this type cannot be evaluated in constants + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0493, E0716. +For more information about an error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/promoted_const_call3.rs b/tests/ui/consts/promoted_const_call3.rs new file mode 100644 index 000000000..6d68a2de7 --- /dev/null +++ b/tests/ui/consts/promoted_const_call3.rs @@ -0,0 +1,26 @@ +pub const fn id<T>(x: T) -> T { x } +pub const C: () = { + let _: &'static _ = &String::new(); + //~^ ERROR: destructor of `String` cannot be evaluated at compile-time + //~| ERROR: temporary value dropped while borrowed + + let _: &'static _ = &id(&String::new()); + //~^ ERROR: destructor of `String` cannot be evaluated at compile-time + //~| ERROR: temporary value dropped while borrowed + //~| ERROR: temporary value dropped while borrowed + + let _: &'static _ = &std::mem::ManuallyDrop::new(String::new()); + //~^ ERROR: temporary value dropped while borrowed +}; + +fn main() { + let _: &'static _ = &String::new(); + //~^ ERROR: temporary value dropped while borrowed + + let _: &'static _ = &id(&String::new()); + //~^ ERROR: temporary value dropped while borrowed + //~| ERROR: temporary value dropped while borrowed + + let _: &'static _ = &std::mem::ManuallyDrop::new(String::new()); + //~^ ERROR: temporary value dropped while borrowed +} diff --git a/tests/ui/consts/promoted_const_call3.stderr b/tests/ui/consts/promoted_const_call3.stderr new file mode 100644 index 000000000..af17457a1 --- /dev/null +++ b/tests/ui/consts/promoted_const_call3.stderr @@ -0,0 +1,105 @@ +error[E0493]: destructor of `String` cannot be evaluated at compile-time + --> $DIR/promoted_const_call3.rs:7:30 + | +LL | let _: &'static _ = &id(&String::new()); + | ^^^^^^^^^^^^^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constants + +error[E0493]: destructor of `String` cannot be evaluated at compile-time + --> $DIR/promoted_const_call3.rs:3:26 + | +LL | let _: &'static _ = &String::new(); + | ^^^^^^^^^^^^^ the destructor for this type cannot be evaluated in constants +... +LL | }; + | - value is dropped here + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call3.rs:3:26 + | +LL | let _: &'static _ = &String::new(); + | ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | }; + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call3.rs:7:26 + | +LL | let _: &'static _ = &id(&String::new()); + | ---------- ^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | }; + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call3.rs:7:30 + | +LL | let _: &'static _ = &id(&String::new()); + | ---------- ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement + | | | + | | creates a temporary value which is freed while still in use + | type annotation requires that borrow lasts for `'static` + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call3.rs:12:26 + | +LL | let _: &'static _ = &std::mem::ManuallyDrop::new(String::new()); + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | +LL | }; + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call3.rs:17:26 + | +LL | let _: &'static _ = &String::new(); + | ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call3.rs:20:26 + | +LL | let _: &'static _ = &id(&String::new()); + | ---------- ^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call3.rs:20:30 + | +LL | let _: &'static _ = &id(&String::new()); + | ---------- ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement + | | | + | | creates a temporary value which is freed while still in use + | type annotation requires that borrow lasts for `'static` + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call3.rs:24:26 + | +LL | let _: &'static _ = &std::mem::ManuallyDrop::new(String::new()); + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0493, E0716. +For more information about an error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/promoted_const_call4.rs b/tests/ui/consts/promoted_const_call4.rs new file mode 100644 index 000000000..82a17b7bf --- /dev/null +++ b/tests/ui/consts/promoted_const_call4.rs @@ -0,0 +1,18 @@ +// run-pass + +use std::sync::atomic::*; + +static FLAG: AtomicBool = AtomicBool::new(false); + +struct NoisyDrop(&'static str); +impl Drop for NoisyDrop { + fn drop(&mut self) { + FLAG.store(true, Ordering::SeqCst); + } +} +fn main() { + { + let _val = &&(NoisyDrop("drop!"), 0).1; + } + assert!(FLAG.load(Ordering::SeqCst)); +} diff --git a/tests/ui/consts/promoted_const_call5.rs b/tests/ui/consts/promoted_const_call5.rs new file mode 100644 index 000000000..3ac8d358c --- /dev/null +++ b/tests/ui/consts/promoted_const_call5.rs @@ -0,0 +1,42 @@ +#![feature(rustc_attrs)] +#![feature(staged_api)] +#![stable(feature = "a", since = "1.0.0")] + +#[rustc_promotable] +#[stable(feature = "a", since = "1.0.0")] +#[rustc_const_stable(feature = "a", since = "1.0.0")] +pub const fn id<T>(x: &'static T) -> &'static T { x } + +#[rustc_promotable] +#[stable(feature = "a", since = "1.0.0")] +#[rustc_const_stable(feature = "a", since = "1.0.0")] +pub const fn new_string() -> String { + String::new() +} + +#[rustc_promotable] +#[stable(feature = "a", since = "1.0.0")] +#[rustc_const_stable(feature = "a", since = "1.0.0")] +pub const fn new_manually_drop<T>(t: T) -> std::mem::ManuallyDrop<T> { + std::mem::ManuallyDrop::new(t) +} + + +const C: () = { + let _: &'static _ = &id(&new_string()); + //~^ ERROR destructor of `String` cannot be evaluated at compile-time + //~| ERROR: temporary value dropped while borrowed + //~| ERROR: temporary value dropped while borrowed + + let _: &'static _ = &new_manually_drop(new_string()); + //~^ ERROR: temporary value dropped while borrowed +}; + +fn main() { + let _: &'static _ = &id(&new_string()); + //~^ ERROR: temporary value dropped while borrowed + //~| ERROR: temporary value dropped while borrowed + + let _: &'static _ = &new_manually_drop(new_string()); + //~^ ERROR: temporary value dropped while borrowed +} diff --git a/tests/ui/consts/promoted_const_call5.stderr b/tests/ui/consts/promoted_const_call5.stderr new file mode 100644 index 000000000..f736220b1 --- /dev/null +++ b/tests/ui/consts/promoted_const_call5.stderr @@ -0,0 +1,74 @@ +error[E0493]: destructor of `String` cannot be evaluated at compile-time + --> $DIR/promoted_const_call5.rs:26:30 + | +LL | let _: &'static _ = &id(&new_string()); + | ^^^^^^^^^^^^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constants + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call5.rs:26:26 + | +LL | let _: &'static _ = &id(&new_string()); + | ---------- ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | }; + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call5.rs:26:30 + | +LL | let _: &'static _ = &id(&new_string()); + | ----^^^^^^^^^^^^-- temporary value is freed at the end of this statement + | | | + | | creates a temporary value which is freed while still in use + | argument requires that borrow lasts for `'static` + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call5.rs:31:26 + | +LL | let _: &'static _ = &new_manually_drop(new_string()); + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | +LL | }; + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call5.rs:36:26 + | +LL | let _: &'static _ = &id(&new_string()); + | ---------- ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call5.rs:36:30 + | +LL | let _: &'static _ = &id(&new_string()); + | ----^^^^^^^^^^^^-- temporary value is freed at the end of this statement + | | | + | | creates a temporary value which is freed while still in use + | argument requires that borrow lasts for `'static` + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promoted_const_call5.rs:40:26 + | +LL | let _: &'static _ = &new_manually_drop(new_string()); + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0493, E0716. +For more information about an error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/promoted_regression.rs b/tests/ui/consts/promoted_regression.rs new file mode 100644 index 000000000..d57036ae5 --- /dev/null +++ b/tests/ui/consts/promoted_regression.rs @@ -0,0 +1,9 @@ +// build-pass (FIXME(62277): could be check-pass?) + +fn main() { + let _ = &[("", ""); 3]; +} + +const FOO: &[(&str, &str)] = &[("", ""); 3]; +const BAR: &[(&str, &str); 5] = &[("", ""); 5]; +const BAA: &[[&str; 12]; 11] = &[[""; 12]; 11]; diff --git a/tests/ui/consts/promotion-mutable-ref.rs b/tests/ui/consts/promotion-mutable-ref.rs new file mode 100644 index 000000000..d103c5a9d --- /dev/null +++ b/tests/ui/consts/promotion-mutable-ref.rs @@ -0,0 +1,17 @@ +// run-pass +#![feature(const_mut_refs)] + +static mut TEST: i32 = { + // We must not promote this, as CTFE needs to be able to mutate it later. + let x = &mut [1,2,3]; + x[0] += 1; + x[0] +}; + +// This still works -- it's not done via promotion. +#[allow(unused)] +static mut TEST2: &'static mut [i32] = &mut [0,1,2]; + +fn main() { + assert_eq!(unsafe { TEST }, 2); +} diff --git a/tests/ui/consts/promotion.rs b/tests/ui/consts/promotion.rs new file mode 100644 index 000000000..e379e3aea --- /dev/null +++ b/tests/ui/consts/promotion.rs @@ -0,0 +1,45 @@ +// revisions: noopt opt opt_with_overflow_checks +//[noopt]compile-flags: -C opt-level=0 +//[opt]compile-flags: -O +//[opt_with_overflow_checks]compile-flags: -C overflow-checks=on -O + +// build-pass + +const fn assert_static<T>(_: &'static T) {} + +#[allow(unconditional_panic)] +const fn fail() -> i32 { + 1/0 +} +const C: i32 = { + // Promoted that fails to evaluate in dead code -- this must work + // (for backwards compatibility reasons). + if false { + assert_static(&fail()); + } + 42 +}; + +fn main() { + assert_static(&["a", "b", "c"]); + assert_static(&["d", "e", "f"]); + assert_eq!(C, 42); + + // make sure that these do not cause trouble despite overflowing + assert_static(&(0-1)); + assert_static(&-i32::MIN); + + // div-by-non-0 is okay + assert_static(&(1/1)); + assert_static(&(1%1)); + + // in-bounds array access is okay + assert_static(&([1,2,3][0] + 1)); + assert_static(&[[1,2][1]]); + + // Top-level projections are not part of the promoted, so no error here. + if false { + #[allow(unconditional_panic)] + assert_static(&[1,2,3][4]); + } +} diff --git a/tests/ui/consts/ptr_comparisons.rs b/tests/ui/consts/ptr_comparisons.rs new file mode 100644 index 000000000..f442e6138 --- /dev/null +++ b/tests/ui/consts/ptr_comparisons.rs @@ -0,0 +1,63 @@ +// compile-flags: --crate-type=lib +// normalize-stderr-32bit: "8 bytes" -> "$$TWO_WORDS bytes" +// normalize-stderr-64bit: "16 bytes" -> "$$TWO_WORDS bytes" +// normalize-stderr-32bit: "size 4" -> "size $$WORD" +// normalize-stderr-64bit: "size 8" -> "size $$WORD" + +#![feature( + core_intrinsics, + const_raw_ptr_comparison, +)] + +const FOO: &usize = &42; + +macro_rules! check { + (eq, $a:expr, $b:expr) => { + pub const _: () = + assert!(std::intrinsics::ptr_guaranteed_cmp($a as *const u8, $b as *const u8) == 1); + }; + (ne, $a:expr, $b:expr) => { + pub const _: () = + assert!(std::intrinsics::ptr_guaranteed_cmp($a as *const u8, $b as *const u8) == 0); + }; + (!, $a:expr, $b:expr) => { + pub const _: () = + assert!(std::intrinsics::ptr_guaranteed_cmp($a as *const u8, $b as *const u8) == 2); + }; +} + +check!(eq, 0, 0); +check!(ne, 0, 1); +check!(ne, FOO as *const _, 0); +check!(ne, unsafe { (FOO as *const usize).offset(1) }, 0); +check!(ne, unsafe { (FOO as *const usize as *const u8).offset(3) }, 0); + +// We want pointers to be equal to themselves, but aren't checking this yet because +// there are some open questions (e.g. whether function pointers to the same function +// compare equal, they don't necessarily at runtime). +// The case tested here should work eventually, but does not work yet. +check!(!, FOO as *const _, FOO as *const _); + + +/////////////////////////////////////////////////////////////////////////////// +// If any of the below start compiling, make sure to add a `check` test for it. +// These invocations exist as canaries so we don't forget to check that the +// behaviour of `guaranteed_eq` and `guaranteed_ne` is still correct. +// All of these try to obtain an out of bounds pointer in some manner. If we +// can create out of bounds pointers, we can offset a pointer far enough that +// at runtime it would be zero and at compile-time it would not be zero. + +const _: *const usize = unsafe { (FOO as *const usize).offset(2) }; + +const _: *const u8 = + unsafe { std::ptr::addr_of!((*(FOO as *const usize as *const [u8; 1000]))[999]) }; +//~^ ERROR evaluation of constant value failed +//~| out-of-bounds + +const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) + 4 }; +//~^ ERROR evaluation of constant value failed +//~| unable to turn pointer into raw bytes + +const _: usize = unsafe { *std::mem::transmute::<&&usize, &usize>(&FOO) + 4 }; +//~^ ERROR evaluation of constant value failed +//~| unable to turn pointer into raw bytes diff --git a/tests/ui/consts/ptr_comparisons.stderr b/tests/ui/consts/ptr_comparisons.stderr new file mode 100644 index 000000000..fea924d12 --- /dev/null +++ b/tests/ui/consts/ptr_comparisons.stderr @@ -0,0 +1,40 @@ +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | + = note: out-of-bounds pointer arithmetic: alloc3 has size $WORD, so pointer to $TWO_WORDS bytes starting at offset 0 is out-of-bounds + | +note: inside `ptr::const_ptr::<impl *const usize>::offset` + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL +note: inside `_` + --> $DIR/ptr_comparisons.rs:50:34 + | +LL | const _: *const usize = unsafe { (FOO as *const usize).offset(2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $DIR/ptr_comparisons.rs:53:33 + | +LL | unsafe { std::ptr::addr_of!((*(FOO as *const usize as *const [u8; 1000]))[999]) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: alloc3 has size $WORD, so pointer to 1000 bytes starting at offset 0 is out-of-bounds + +error[E0080]: evaluation of constant value failed + --> $DIR/ptr_comparisons.rs:57:27 + | +LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) + 4 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: evaluation of constant value failed + --> $DIR/ptr_comparisons.rs:61:27 + | +LL | const _: usize = unsafe { *std::mem::transmute::<&&usize, &usize>(&FOO) + 4 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/ptr_is_null.rs b/tests/ui/consts/ptr_is_null.rs new file mode 100644 index 000000000..8babb6858 --- /dev/null +++ b/tests/ui/consts/ptr_is_null.rs @@ -0,0 +1,16 @@ +// compile-flags: --crate-type=lib +// check-pass + +#![feature(const_ptr_is_null)] + +const FOO: &usize = &42; + +pub const _: () = assert!(!(FOO as *const usize).is_null()); + +pub const _: () = assert!(!(42 as *const usize).is_null()); + +pub const _: () = assert!((0 as *const usize).is_null()); + +pub const _: () = assert!(std::ptr::null::<usize>().is_null()); + +pub const _: () = assert!(!("foo" as *const str).is_null()); diff --git a/tests/ui/consts/qualif-indirect-mutation-fail.rs b/tests/ui/consts/qualif-indirect-mutation-fail.rs new file mode 100644 index 000000000..a6d293404 --- /dev/null +++ b/tests/ui/consts/qualif-indirect-mutation-fail.rs @@ -0,0 +1,64 @@ +// compile-flags: --crate-type=lib +#![feature(const_mut_refs)] +#![feature(const_precise_live_drops)] +#![feature(const_swap)] +#![feature(raw_ref_op)] + +// Mutable borrow of a field with drop impl. +pub const fn f() { + let mut a: (u32, Option<String>) = (0, None); //~ ERROR destructor of + let _ = &mut a.1; +} + +// Mutable borrow of a type with drop impl. +pub const A1: () = { + let mut x = None; //~ ERROR destructor of + let mut y = Some(String::new()); + let a = &mut x; + let b = &mut y; + std::mem::swap(a, b); + std::mem::forget(y); +}; + +// Mutable borrow of a type with drop impl. +pub const A2: () = { + let mut x = None; + let mut y = Some(String::new()); + let a = &mut x; + let b = &mut y; + std::mem::swap(a, b); + std::mem::forget(y); + let _z = x; //~ ERROR destructor of +}; + +// Shared borrow of a type that might be !Freeze and Drop. +pub const fn g1<T>() { + let x: Option<T> = None; //~ ERROR destructor of + let _ = x.is_some(); +} + +// Shared borrow of a type that might be !Freeze and Drop. +pub const fn g2<T>() { + let x: Option<T> = None; + let _ = x.is_some(); + let _y = x; //~ ERROR destructor of +} + +// Mutable raw reference to a Drop type. +pub const fn address_of_mut() { + let mut x: Option<String> = None; //~ ERROR destructor of + &raw mut x; + + let mut y: Option<String> = None; //~ ERROR destructor of + std::ptr::addr_of_mut!(y); +} + +// Const raw reference to a Drop type. Conservatively assumed to allow mutation +// until resolution of https://github.com/rust-lang/rust/issues/56604. +pub const fn address_of_const() { + let x: Option<String> = None; //~ ERROR destructor of + &raw const x; + + let y: Option<String> = None; //~ ERROR destructor of + std::ptr::addr_of!(y); +} diff --git a/tests/ui/consts/qualif-indirect-mutation-fail.stderr b/tests/ui/consts/qualif-indirect-mutation-fail.stderr new file mode 100644 index 000000000..6379c00e4 --- /dev/null +++ b/tests/ui/consts/qualif-indirect-mutation-fail.stderr @@ -0,0 +1,57 @@ +error[E0493]: destructor of `(u32, Option<String>)` cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:9:9 + | +LL | let mut a: (u32, Option<String>) = (0, None); + | ^^^^^ the destructor for this type cannot be evaluated in constant functions + +error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:15:9 + | +LL | let mut x = None; + | ^^^^^ the destructor for this type cannot be evaluated in constants + +error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:31:9 + | +LL | let _z = x; + | ^^ the destructor for this type cannot be evaluated in constants + +error[E0493]: destructor of `Option<T>` cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:36:9 + | +LL | let x: Option<T> = None; + | ^ the destructor for this type cannot be evaluated in constant functions + +error[E0493]: destructor of `Option<T>` cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:44:9 + | +LL | let _y = x; + | ^^ the destructor for this type cannot be evaluated in constant functions + +error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:52:9 + | +LL | let mut y: Option<String> = None; + | ^^^^^ the destructor for this type cannot be evaluated in constant functions + +error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:49:9 + | +LL | let mut x: Option<String> = None; + | ^^^^^ the destructor for this type cannot be evaluated in constant functions + +error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:62:9 + | +LL | let y: Option<String> = None; + | ^ the destructor for this type cannot be evaluated in constant functions + +error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:59:9 + | +LL | let x: Option<String> = None; + | ^ the destructor for this type cannot be evaluated in constant functions + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/qualif-indirect-mutation-pass.rs b/tests/ui/consts/qualif-indirect-mutation-pass.rs new file mode 100644 index 000000000..06af6a03b --- /dev/null +++ b/tests/ui/consts/qualif-indirect-mutation-pass.rs @@ -0,0 +1,24 @@ +// compile-flags: --crate-type=lib +// check-pass +#![feature(const_mut_refs)] +#![feature(const_precise_live_drops)] + +// Mutable reference allows only mutation of !Drop place. +pub const fn f() { + let mut x: (Option<String>, u32) = (None, 0); + let mut a = 10; + *(&mut a) = 11; + x.1 = a; +} + +// Mutable reference allows only mutation of !Drop place. +pub const fn g() { + let mut a: (u32, Option<String>) = (0, None); + let _ = &mut a.0; +} + +// Shared reference does not allow for mutation. +pub const fn h() { + let x: Option<String> = None; + let _ = &x; +} diff --git a/tests/ui/consts/qualif-union.rs b/tests/ui/consts/qualif-union.rs new file mode 100644 index 000000000..11c019be9 --- /dev/null +++ b/tests/ui/consts/qualif-union.rs @@ -0,0 +1,33 @@ +// Checks that unions use type based qualification. Regression test for issue #90268. + +use std::cell::Cell; +use std::mem::ManuallyDrop; + +union U { i: u32, c: ManuallyDrop<Cell<u32>> } + +const C1: ManuallyDrop<Cell<u32>> = { + unsafe { U { c: ManuallyDrop::new(Cell::new(0)) }.c } +}; + +const C2: ManuallyDrop<Cell<u32>> = { + unsafe { U { i : 0 }.c } +}; + +const C3: ManuallyDrop<Cell<u32>> = { + let mut u = U { i: 0 }; + u.i = 1; + unsafe { u.c } +}; + +const C4: U = U { i: 0 }; + +const C5: [U; 1] = [U {i : 0}; 1]; + +fn main() { + // Interior mutability should prevent promotion. + let _: &'static _ = &C1; //~ ERROR temporary value dropped while borrowed + let _: &'static _ = &C2; //~ ERROR temporary value dropped while borrowed + let _: &'static _ = &C3; //~ ERROR temporary value dropped while borrowed + let _: &'static _ = &C4; //~ ERROR temporary value dropped while borrowed + let _: &'static _ = &C5; //~ ERROR temporary value dropped while borrowed +} diff --git a/tests/ui/consts/qualif-union.stderr b/tests/ui/consts/qualif-union.stderr new file mode 100644 index 000000000..d847cf88f --- /dev/null +++ b/tests/ui/consts/qualif-union.stderr @@ -0,0 +1,57 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/qualif-union.rs:28:26 + | +LL | let _: &'static _ = &C1; + | ---------- ^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/qualif-union.rs:29:26 + | +LL | let _: &'static _ = &C2; + | ---------- ^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/qualif-union.rs:30:26 + | +LL | let _: &'static _ = &C3; + | ---------- ^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/qualif-union.rs:31:26 + | +LL | let _: &'static _ = &C4; + | ---------- ^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | let _: &'static _ = &C5; +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/qualif-union.rs:32:26 + | +LL | let _: &'static _ = &C5; + | ---------- ^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/qualif_overwrite.rs b/tests/ui/consts/qualif_overwrite.rs new file mode 100644 index 000000000..aae4e41ff --- /dev/null +++ b/tests/ui/consts/qualif_overwrite.rs @@ -0,0 +1,13 @@ +use std::cell::Cell; + +// this is overly conservative. The reset to `None` should clear `a` of all qualifications +// while we could fix this, it would be inconsistent with `qualif_overwrite_2.rs`. +// We can fix this properly in the future by allowing constants that do not depend on generics +// to be checked by an analysis on the final value instead of looking at the body. +const FOO: &Option<Cell<usize>> = { + let mut a = Some(Cell::new(0)); + a = None; // sets `qualif(a)` to `qualif(a) | qualif(None)` + &{a} //~ ERROR cannot refer to interior mutable +}; + +fn main() {} diff --git a/tests/ui/consts/qualif_overwrite.stderr b/tests/ui/consts/qualif_overwrite.stderr new file mode 100644 index 000000000..86a669c43 --- /dev/null +++ b/tests/ui/consts/qualif_overwrite.stderr @@ -0,0 +1,9 @@ +error[E0492]: constants cannot refer to interior mutable data + --> $DIR/qualif_overwrite.rs:10:5 + | +LL | &{a} + | ^^^^ this borrow of an interior mutable value may end up in the final value + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0492`. diff --git a/tests/ui/consts/qualif_overwrite_2.rs b/tests/ui/consts/qualif_overwrite_2.rs new file mode 100644 index 000000000..1819d9a6d --- /dev/null +++ b/tests/ui/consts/qualif_overwrite_2.rs @@ -0,0 +1,11 @@ +use std::cell::Cell; + +// const qualification is not smart enough to know about fields and always assumes that there might +// be other fields that caused the qualification +const FOO: &Option<Cell<usize>> = { + let mut a = (Some(Cell::new(0)),); + a.0 = None; // sets `qualif(a)` to `qualif(a) | qualif(None)` + &{a.0} //~ ERROR cannot refer to interior mutable +}; + +fn main() {} diff --git a/tests/ui/consts/qualif_overwrite_2.stderr b/tests/ui/consts/qualif_overwrite_2.stderr new file mode 100644 index 000000000..9eb123d0b --- /dev/null +++ b/tests/ui/consts/qualif_overwrite_2.stderr @@ -0,0 +1,9 @@ +error[E0492]: constants cannot refer to interior mutable data + --> $DIR/qualif_overwrite_2.rs:8:5 + | +LL | &{a.0} + | ^^^^^^ this borrow of an interior mutable value may end up in the final value + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0492`. diff --git a/tests/ui/consts/raw-ptr-const.rs b/tests/ui/consts/raw-ptr-const.rs new file mode 100644 index 000000000..b9c542d03 --- /dev/null +++ b/tests/ui/consts/raw-ptr-const.rs @@ -0,0 +1,8 @@ +// This is a regression test for a `delay_span_bug` during interning when a constant +// evaluates to a (non-dangling) raw pointer. For now this errors; potentially it +// could also be allowed. + +const CONST_RAW: *const Vec<i32> = &Vec::new() as *const _; +//~^ ERROR untyped pointers are not allowed in constant + +fn main() {} diff --git a/tests/ui/consts/raw-ptr-const.stderr b/tests/ui/consts/raw-ptr-const.stderr new file mode 100644 index 000000000..f7b53433b --- /dev/null +++ b/tests/ui/consts/raw-ptr-const.stderr @@ -0,0 +1,8 @@ +error: untyped pointers are not allowed in constant + --> $DIR/raw-ptr-const.rs:5:1 + | +LL | const CONST_RAW: *const Vec<i32> = &Vec::new() as *const _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/consts/raw_pointer_promoted.rs b/tests/ui/consts/raw_pointer_promoted.rs new file mode 100644 index 000000000..4c62ad444 --- /dev/null +++ b/tests/ui/consts/raw_pointer_promoted.rs @@ -0,0 +1,5 @@ +// check-pass + +pub const FOO: &'static *const i32 = &(&0 as _); + +fn main() {} diff --git a/tests/ui/consts/recursive-zst-static.default.stderr b/tests/ui/consts/recursive-zst-static.default.stderr new file mode 100644 index 000000000..d68960b09 --- /dev/null +++ b/tests/ui/consts/recursive-zst-static.default.stderr @@ -0,0 +1,25 @@ +error[E0391]: cycle detected when const-evaluating + checking `FOO` + --> $DIR/recursive-zst-static.rs:10:1 + | +LL | static FOO: () = FOO; + | ^^^^^^^^^^^^^^ + | +note: ...which requires const-evaluating + checking `FOO`... + --> $DIR/recursive-zst-static.rs:10:18 + | +LL | static FOO: () = FOO; + | ^^^ + = note: ...which again requires const-evaluating + checking `FOO`, completing the cycle +note: cycle used when linting top-level module + --> $DIR/recursive-zst-static.rs:10:1 + | +LL | / static FOO: () = FOO; +LL | | +LL | | fn main() { +LL | | FOO +LL | | } + | |_^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/consts/recursive-zst-static.rs b/tests/ui/consts/recursive-zst-static.rs new file mode 100644 index 000000000..4e61634b3 --- /dev/null +++ b/tests/ui/consts/recursive-zst-static.rs @@ -0,0 +1,14 @@ +// revisions: default unleash +//[unleash]compile-flags: -Zunleash-the-miri-inside-of-you + +// This test ensures that we do not allow ZST statics to initialize themselves without ever +// actually creating a value of that type. This is important, as the ZST may have private fields +// that users can reasonably expect to only get initialized by their own code. Thus unsafe code +// can depend on this fact and will thus do unsound things when it is violated. +// See https://github.com/rust-lang/rust/issues/71078 for more details. + +static FOO: () = FOO; //~ cycle detected when const-evaluating + checking `FOO` + +fn main() { + FOO +} diff --git a/tests/ui/consts/recursive-zst-static.unleash.stderr b/tests/ui/consts/recursive-zst-static.unleash.stderr new file mode 100644 index 000000000..d68960b09 --- /dev/null +++ b/tests/ui/consts/recursive-zst-static.unleash.stderr @@ -0,0 +1,25 @@ +error[E0391]: cycle detected when const-evaluating + checking `FOO` + --> $DIR/recursive-zst-static.rs:10:1 + | +LL | static FOO: () = FOO; + | ^^^^^^^^^^^^^^ + | +note: ...which requires const-evaluating + checking `FOO`... + --> $DIR/recursive-zst-static.rs:10:18 + | +LL | static FOO: () = FOO; + | ^^^ + = note: ...which again requires const-evaluating + checking `FOO`, completing the cycle +note: cycle used when linting top-level module + --> $DIR/recursive-zst-static.rs:10:1 + | +LL | / static FOO: () = FOO; +LL | | +LL | | fn main() { +LL | | FOO +LL | | } + | |_^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/consts/recursive.rs b/tests/ui/consts/recursive.rs new file mode 100644 index 000000000..5d736e31b --- /dev/null +++ b/tests/ui/consts/recursive.rs @@ -0,0 +1,10 @@ +#![allow(unused)] + +const fn f<T>(x: T) { //~ WARN function cannot return without recursing + f(x); + //~^ ERROR evaluation of constant value failed +} + +const X: () = f(1); + +fn main() {} diff --git a/tests/ui/consts/recursive.stderr b/tests/ui/consts/recursive.stderr new file mode 100644 index 000000000..60ce64d2a --- /dev/null +++ b/tests/ui/consts/recursive.stderr @@ -0,0 +1,36 @@ +warning: function cannot return without recursing + --> $DIR/recursive.rs:3:1 + | +LL | const fn f<T>(x: T) { + | ^^^^^^^^^^^^^^^^^^^ cannot return without recursing +LL | f(x); + | ---- recursive call site + | + = help: a `loop` may express intention better if this is on purpose + = note: `#[warn(unconditional_recursion)]` on by default + +error[E0080]: evaluation of constant value failed + --> $DIR/recursive.rs:4:5 + | +LL | f(x); + | ^^^^ reached the configured maximum number of stack frames + | +note: inside `f::<i32>` + --> $DIR/recursive.rs:4:5 + | +LL | f(x); + | ^^^^ +note: [... 126 additional calls inside `f::<i32>` ...] + --> $DIR/recursive.rs:4:5 + | +LL | f(x); + | ^^^^ +note: inside `X` + --> $DIR/recursive.rs:8:15 + | +LL | const X: () = f(1); + | ^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/references.rs b/tests/ui/consts/references.rs new file mode 100644 index 000000000..d0af47a8e --- /dev/null +++ b/tests/ui/consts/references.rs @@ -0,0 +1,27 @@ +// run-pass + +const FOO: &[u8] = b"foo"; +const BAR: &[u8] = &[1, 2, 3]; + +const BOO: &i32 = &42; + +fn main() { + match &[1u8, 2, 3] as &[u8] { + FOO => panic!("a"), + BAR => println!("b"), + _ => panic!("c"), + } + + match b"foo" as &[u8] { + FOO => println!("a"), + BAR => panic!("b"), + _ => panic!("c"), + } + + #[allow(unreachable_patterns)] + match &43 { + &42 => panic!(), + BOO => panic!(), + _ => println!("d"), + } +} diff --git a/tests/ui/consts/refs_check_const_eq-issue-88384.rs b/tests/ui/consts/refs_check_const_eq-issue-88384.rs new file mode 100644 index 000000000..1496b28bd --- /dev/null +++ b/tests/ui/consts/refs_check_const_eq-issue-88384.rs @@ -0,0 +1,25 @@ +#![feature(fn_traits)] +#![feature(adt_const_params)] +//~^ WARNING the feature `adt_const_params` is incomplete + +#[derive(PartialEq, Eq)] +struct CompileTimeSettings{ + hooks: &'static[fn()], +} + +struct Foo<const T: CompileTimeSettings>; +//~^ ERROR using function pointers as const generic parameters is forbidden + +impl<const T: CompileTimeSettings> Foo<T> { + //~^ ERROR using function pointers as const generic parameters is forbidden + fn call_hooks(){ + } +} + +fn main(){ + const SETTINGS: CompileTimeSettings = CompileTimeSettings{ + hooks: &[], + }; + + Foo::<SETTINGS>::call_hooks(); +} diff --git a/tests/ui/consts/refs_check_const_eq-issue-88384.stderr b/tests/ui/consts/refs_check_const_eq-issue-88384.stderr new file mode 100644 index 000000000..3855b5f2a --- /dev/null +++ b/tests/ui/consts/refs_check_const_eq-issue-88384.stderr @@ -0,0 +1,24 @@ +warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/refs_check_const_eq-issue-88384.rs:2:12 + | +LL | #![feature(adt_const_params)] + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0741]: using function pointers as const generic parameters is forbidden + --> $DIR/refs_check_const_eq-issue-88384.rs:10:21 + | +LL | struct Foo<const T: CompileTimeSettings>; + | ^^^^^^^^^^^^^^^^^^^ + +error[E0741]: using function pointers as const generic parameters is forbidden + --> $DIR/refs_check_const_eq-issue-88384.rs:13:15 + | +LL | impl<const T: CompileTimeSettings> Foo<T> { + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0741`. diff --git a/tests/ui/consts/refs_check_const_value_eq-issue-88876.rs b/tests/ui/consts/refs_check_const_value_eq-issue-88876.rs new file mode 100644 index 000000000..6ce9da436 --- /dev/null +++ b/tests/ui/consts/refs_check_const_value_eq-issue-88876.rs @@ -0,0 +1,12 @@ +// check-pass + +#![allow(incomplete_features)] +#![feature(adt_const_params)] + +struct FooConst<const ARRAY: &'static [&'static str]> {} + +const FOO_ARR: &[&'static str; 2] = &["Hello", "Friend"]; + +fn main() { + let _ = FooConst::<FOO_ARR> {}; +} diff --git a/tests/ui/consts/repeat_match.rs b/tests/ui/consts/repeat_match.rs new file mode 100644 index 000000000..20983184a --- /dev/null +++ b/tests/ui/consts/repeat_match.rs @@ -0,0 +1,12 @@ +// run-pass + +// https://github.com/rust-lang/rust/issues/45044 + +const X: [u8; 1] = [0; 1]; + +fn main() { + match &X { + &X => println!("a"), + _ => println!("b"), + }; +} diff --git a/tests/ui/consts/return-in-const-fn.rs b/tests/ui/consts/return-in-const-fn.rs new file mode 100644 index 000000000..077a33c08 --- /dev/null +++ b/tests/ui/consts/return-in-const-fn.rs @@ -0,0 +1,10 @@ +// run-pass + +// https://github.com/rust-lang/rust/issues/43754 + +const fn foo(x: usize) -> usize { + return x; +} +fn main() { + [0; foo(2)]; +} diff --git a/tests/ui/consts/rustc-const-stability-require-const.rs b/tests/ui/consts/rustc-const-stability-require-const.rs new file mode 100644 index 000000000..4fb259b33 --- /dev/null +++ b/tests/ui/consts/rustc-const-stability-require-const.rs @@ -0,0 +1,47 @@ +#![crate_type = "lib"] +#![feature(staged_api)] +#![stable(feature = "foo", since = "1.0.0")] + +#[stable(feature = "foo", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_foo", issue = "none")] +pub fn foo() {} +//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` + +#[stable(feature = "bar", since = "1.0.0")] +#[rustc_const_stable(feature = "const_bar", since = "1.0.0")] +pub fn bar() {} +//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` + +#[stable(feature = "potato", since = "1.0.0")] +pub struct Potato; + +impl Potato { + #[stable(feature = "salad", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_salad", issue = "none")] + pub fn salad(&self) -> &'static str { "mmmmmm" } + //~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` + + #[stable(feature = "roasted", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_roasted", issue = "none")] + pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" } + //~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` +} + +#[stable(feature = "bar", since = "1.0.0")] +#[rustc_const_stable(feature = "const_bar", since = "1.0.0")] +pub extern "C" fn bar_c() {} +//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` + +#[stable(feature = "foo", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_foo", issue = "none")] +pub extern "C" fn foo_c() {} +//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` + + +#[stable(feature = "foobar", since = "1.0.0")] +#[rustc_const_unstable(feature = "foobar_const", issue = "none")] +pub const fn foobar() {} + +#[stable(feature = "barfoo", since = "1.0.0")] +#[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")] +pub const fn barfoo() {} diff --git a/tests/ui/consts/rustc-const-stability-require-const.stderr b/tests/ui/consts/rustc-const-stability-require-const.stderr new file mode 100644 index 000000000..1027b9311 --- /dev/null +++ b/tests/ui/consts/rustc-const-stability-require-const.stderr @@ -0,0 +1,86 @@ +error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` + --> $DIR/rustc-const-stability-require-const.rs:7:1 + | +LL | #[rustc_const_unstable(feature = "const_foo", issue = "none")] + | -------------------------------------------------------------- attribute specified here +LL | pub fn foo() {} + | ^^^^^^^^^^^^ + | +help: make the function or method const + --> $DIR/rustc-const-stability-require-const.rs:7:1 + | +LL | pub fn foo() {} + | ^^^^^^^^^^^^ + +error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` + --> $DIR/rustc-const-stability-require-const.rs:12:1 + | +LL | #[rustc_const_stable(feature = "const_bar", since = "1.0.0")] + | ------------------------------------------------------------- attribute specified here +LL | pub fn bar() {} + | ^^^^^^^^^^^^ + | +help: make the function or method const + --> $DIR/rustc-const-stability-require-const.rs:12:1 + | +LL | pub fn bar() {} + | ^^^^^^^^^^^^ + +error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` + --> $DIR/rustc-const-stability-require-const.rs:21:5 + | +LL | #[rustc_const_unstable(feature = "const_salad", issue = "none")] + | ---------------------------------------------------------------- attribute specified here +LL | pub fn salad(&self) -> &'static str { "mmmmmm" } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function or method const + --> $DIR/rustc-const-stability-require-const.rs:21:5 + | +LL | pub fn salad(&self) -> &'static str { "mmmmmm" } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` + --> $DIR/rustc-const-stability-require-const.rs:26:5 + | +LL | #[rustc_const_unstable(feature = "const_roasted", issue = "none")] + | ------------------------------------------------------------------ attribute specified here +LL | pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function or method const + --> $DIR/rustc-const-stability-require-const.rs:26:5 + | +LL | pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` + --> $DIR/rustc-const-stability-require-const.rs:32:1 + | +LL | #[rustc_const_stable(feature = "const_bar", since = "1.0.0")] + | ------------------------------------------------------------- attribute specified here +LL | pub extern "C" fn bar_c() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function or method const + --> $DIR/rustc-const-stability-require-const.rs:32:1 + | +LL | pub extern "C" fn bar_c() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` + --> $DIR/rustc-const-stability-require-const.rs:37:1 + | +LL | #[rustc_const_unstable(feature = "const_foo", issue = "none")] + | -------------------------------------------------------------- attribute specified here +LL | pub extern "C" fn foo_c() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function or method const + --> $DIR/rustc-const-stability-require-const.rs:37:1 + | +LL | pub extern "C" fn foo_c() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/consts/rustc-impl-const-stability.rs b/tests/ui/consts/rustc-impl-const-stability.rs new file mode 100644 index 000000000..0c18efa0a --- /dev/null +++ b/tests/ui/consts/rustc-impl-const-stability.rs @@ -0,0 +1,19 @@ +// check-pass + +#![crate_type = "lib"] +#![feature(staged_api)] +#![feature(const_trait_impl)] +#![stable(feature = "foo", since = "1.0.0")] + +#[stable(feature = "potato", since = "1.27.0")] +pub struct Data { + _data: u128, +} + +#[stable(feature = "potato", since = "1.27.0")] +#[rustc_const_unstable(feature = "data_foo", issue = "none")] +impl const Default for Data { + fn default() -> Data { + Data { _data: 42 } + } +} diff --git a/tests/ui/consts/rvalue-static-promotion.rs b/tests/ui/consts/rvalue-static-promotion.rs new file mode 100644 index 000000000..c48d9eae9 --- /dev/null +++ b/tests/ui/consts/rvalue-static-promotion.rs @@ -0,0 +1,19 @@ +// run-pass + +use std::cell::Cell; + +const NONE_CELL_STRING: Option<Cell<String>> = None; + +struct Foo<T>(#[allow(unused_tuple_struct_fields)] T); +impl<T> Foo<T> { + const FOO: Option<Box<T>> = None; +} + +fn main() { + let _: &'static u32 = &42; + let _: &'static Option<u32> = &None; + + // We should be able to peek at consts and see they're None. + let _: &'static Option<Cell<String>> = &NONE_CELL_STRING; + let _: &'static Option<Box<()>> = &Foo::FOO; +} diff --git a/tests/ui/consts/self_normalization.rs b/tests/ui/consts/self_normalization.rs new file mode 100644 index 000000000..b2a34f587 --- /dev/null +++ b/tests/ui/consts/self_normalization.rs @@ -0,0 +1,16 @@ +// check-pass + +fn testfn(_arr: &mut [(); 0]) {} + +trait TestTrait { + fn method(); +} + +impl TestTrait for [(); 0] { + fn method() { + let mut arr: Self = [(); 0]; + testfn(&mut arr); + } +} + +fn main() {} diff --git a/tests/ui/consts/self_normalization2.rs b/tests/ui/consts/self_normalization2.rs new file mode 100644 index 000000000..4fca38cba --- /dev/null +++ b/tests/ui/consts/self_normalization2.rs @@ -0,0 +1,21 @@ +// check-pass + +trait Gen<T> { + fn gen(x: Self) -> T; +} + +struct A; + +impl Gen<[(); 0]> for A { + fn gen(x: Self) -> [(); 0] { + [] + } +} + +fn array() -> impl Gen<[(); 0]> { + A +} + +fn main() { + let [] = Gen::gen(array()); +} diff --git a/tests/ui/consts/signed_enum_discr.rs b/tests/ui/consts/signed_enum_discr.rs new file mode 100644 index 000000000..2e4395ccf --- /dev/null +++ b/tests/ui/consts/signed_enum_discr.rs @@ -0,0 +1,19 @@ +// run-pass + +// https://github.com/rust-lang/rust/issues/49181 + +#[derive(Eq, PartialEq)] +#[repr(i8)] +pub enum A { + B = -1, + C = 1, +} + +pub const D: A = A::B; + +fn main() { + match A::C { + D => {}, + _ => {} + } +} diff --git a/tests/ui/consts/stable-precise-live-drops-in-libcore.rs b/tests/ui/consts/stable-precise-live-drops-in-libcore.rs new file mode 100644 index 000000000..7cd3dbec9 --- /dev/null +++ b/tests/ui/consts/stable-precise-live-drops-in-libcore.rs @@ -0,0 +1,22 @@ +#![stable(feature = "core", since = "1.6.0")] +#![feature(staged_api)] +#![feature(const_precise_live_drops)] + +enum Either<T, S> { + Left(T), + Right(S), +} + +impl<T> Either<T, T> { + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "foo", since = "1.0.0")] + pub const fn unwrap(self) -> T { + //~^ ERROR destructor of + match self { + Self::Left(t) => t, + Self::Right(t) => t, + } + } +} + +fn main() {} diff --git a/tests/ui/consts/stable-precise-live-drops-in-libcore.stderr b/tests/ui/consts/stable-precise-live-drops-in-libcore.stderr new file mode 100644 index 000000000..5f70391ee --- /dev/null +++ b/tests/ui/consts/stable-precise-live-drops-in-libcore.stderr @@ -0,0 +1,12 @@ +error[E0493]: destructor of `Either<T, T>` cannot be evaluated at compile-time + --> $DIR/stable-precise-live-drops-in-libcore.rs:13:25 + | +LL | pub const fn unwrap(self) -> T { + | ^^^^ the destructor for this type cannot be evaluated in constant functions +... +LL | } + | - value is dropped here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/static-cycle-error.rs b/tests/ui/consts/static-cycle-error.rs new file mode 100644 index 000000000..9ce050aae --- /dev/null +++ b/tests/ui/consts/static-cycle-error.rs @@ -0,0 +1,11 @@ +// check-pass + +struct Foo { + foo: Option<&'static Foo> +} + +static FOO: Foo = Foo { + foo: Some(&FOO), +}; + +fn main() {} diff --git a/tests/ui/consts/static-raw-pointer-interning.rs b/tests/ui/consts/static-raw-pointer-interning.rs new file mode 100644 index 000000000..cab60c91e --- /dev/null +++ b/tests/ui/consts/static-raw-pointer-interning.rs @@ -0,0 +1,15 @@ +// run-pass + +static FOO: Foo = Foo { + field: &42 as *const i32, +}; + +struct Foo { + field: *const i32, +} + +unsafe impl Sync for Foo {} + +fn main() { + assert_eq!(unsafe { *FOO.field }, 42); +} diff --git a/tests/ui/consts/static-raw-pointer-interning2.rs b/tests/ui/consts/static-raw-pointer-interning2.rs new file mode 100644 index 000000000..2b915fd7c --- /dev/null +++ b/tests/ui/consts/static-raw-pointer-interning2.rs @@ -0,0 +1,15 @@ +// run-pass + +static mut FOO: Foo = Foo { + field: &mut [42] as *mut [i32] as *mut i32, +}; + +struct Foo { + field: *mut i32, +} + +unsafe impl Sync for Foo {} + +fn main() { + assert_eq!(unsafe { *FOO.field = 69; *FOO.field }, 69); +} diff --git a/tests/ui/consts/static_mut_containing_mut_ref.rs b/tests/ui/consts/static_mut_containing_mut_ref.rs new file mode 100644 index 000000000..df09c76c5 --- /dev/null +++ b/tests/ui/consts/static_mut_containing_mut_ref.rs @@ -0,0 +1,7 @@ +// build-pass (FIXME(62277): could be check-pass?) + +static mut STDERR_BUFFER_SPACE: [u8; 42] = [0u8; 42]; + +pub static mut STDERR_BUFFER: *mut [u8] = unsafe { &mut STDERR_BUFFER_SPACE }; + +fn main() {} diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr b/tests/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr new file mode 100644 index 000000000..8db75dd63 --- /dev/null +++ b/tests/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr @@ -0,0 +1,9 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/static_mut_containing_mut_ref2.rs:7:45 + | +LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ modifying a static's initial value from another static's initializer + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.rs b/tests/ui/consts/static_mut_containing_mut_ref2.rs new file mode 100644 index 000000000..613685460 --- /dev/null +++ b/tests/ui/consts/static_mut_containing_mut_ref2.rs @@ -0,0 +1,11 @@ +// revisions: stock mut_refs + +#![cfg_attr(mut_refs, feature(const_mut_refs))] + +static mut STDERR_BUFFER_SPACE: u8 = 0; + +pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; +//[mut_refs]~^ ERROR could not evaluate static initializer +//[stock]~^^ ERROR mutable references are not allowed in statics + +fn main() {} diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr b/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr new file mode 100644 index 000000000..5cdcea232 --- /dev/null +++ b/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr @@ -0,0 +1,12 @@ +error[E0658]: mutable references are not allowed in statics + --> $DIR/static_mut_containing_mut_ref2.rs:7:46 + | +LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/static_mut_containing_mut_ref3.rs b/tests/ui/consts/static_mut_containing_mut_ref3.rs new file mode 100644 index 000000000..c24c7e279 --- /dev/null +++ b/tests/ui/consts/static_mut_containing_mut_ref3.rs @@ -0,0 +1,6 @@ +static mut FOO: (u8, u8) = (42, 43); + +static mut BAR: () = unsafe { FOO.0 = 99; }; +//~^ ERROR could not evaluate static initializer + +fn main() {} diff --git a/tests/ui/consts/static_mut_containing_mut_ref3.stderr b/tests/ui/consts/static_mut_containing_mut_ref3.stderr new file mode 100644 index 000000000..91f9dbd8d --- /dev/null +++ b/tests/ui/consts/static_mut_containing_mut_ref3.stderr @@ -0,0 +1,9 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/static_mut_containing_mut_ref3.rs:3:31 + | +LL | static mut BAR: () = unsafe { FOO.0 = 99; }; + | ^^^^^^^^^^ modifying a static's initial value from another static's initializer + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/std/alloc.32bit.stderr b/tests/ui/consts/std/alloc.32bit.stderr new file mode 100644 index 000000000..8c83df53d --- /dev/null +++ b/tests/ui/consts/std/alloc.32bit.stderr @@ -0,0 +1,25 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/alloc.rs:12:1 + | +LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x00000000, but expected a valid enum tag + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/alloc.rs:16:1 + | +LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x00000003, but expected a valid enum tag + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/std/alloc.64bit.stderr b/tests/ui/consts/std/alloc.64bit.stderr new file mode 100644 index 000000000..addedad17 --- /dev/null +++ b/tests/ui/consts/std/alloc.64bit.stderr @@ -0,0 +1,25 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/alloc.rs:12:1 + | +LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/alloc.rs:16:1 + | +LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x0000000000000003, but expected a valid enum tag + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/std/alloc.rs b/tests/ui/consts/std/alloc.rs new file mode 100644 index 000000000..9abf35d63 --- /dev/null +++ b/tests/ui/consts/std/alloc.rs @@ -0,0 +1,19 @@ +// stderr-per-bitwidth +// ignore-debug (the debug assertions change the error) +// Strip out raw byte dumps to make comparison platform-independent: +// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" +// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" +use std::alloc::Layout; + +// ok +const LAYOUT_VALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x08) }; + +// not ok, since alignment needs to be non-zero. +const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) }; +//~^ ERROR it is undefined behavior to use this value + +// not ok, since alignment needs to be a power of two. +const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) }; +//~^ ERROR it is undefined behavior to use this value + +fn main() {} diff --git a/tests/ui/consts/std/cell.rs b/tests/ui/consts/std/cell.rs new file mode 100644 index 000000000..f1ef54131 --- /dev/null +++ b/tests/ui/consts/std/cell.rs @@ -0,0 +1,46 @@ +#![feature(const_refs_to_cell)] + +use std::cell::*; + +// not ok, because this creates a dangling pointer, just like `let x = Cell::new(42).as_ptr()` would +static FOO: Wrap<*mut u32> = Wrap(Cell::new(42).as_ptr()); +//~^ ERROR encountered dangling pointer +const FOO_CONST: Wrap<*mut u32> = Wrap(Cell::new(42).as_ptr()); +//~^ ERROR encountered dangling pointer + +// Ok, these are just base values and it is the `Wrap` author's job to uphold `Send` and `Sync` +// invariants, since they used `unsafe impl`. +static FOO3: Wrap<Cell<u32>> = Wrap(Cell::new(42)); +const FOO3_CONST: Wrap<Cell<u32>> = Wrap(Cell::new(42)); + +// ok, we are referring to the memory of another static item. +static FOO4: Wrap<*mut u32> = Wrap(FOO3.0.as_ptr()); + +// not ok, the use of a constant here is equivalent to an inline declaration of the value, so +// its memory will get freed before the constant is finished evaluating, thus creating a dangling +// pointer. This would happen exactly the same at runtime. +const FOO4_CONST: Wrap<*mut u32> = Wrap(FOO3_CONST.0.as_ptr()); +//~^ ERROR encountered dangling pointer + +// not ok, because the `as_ptr` call takes a reference to a temporary that will get freed +// before the constant is finished evaluating. +const FOO2: *mut u32 = Cell::new(42).as_ptr(); +//~^ ERROR encountered dangling pointer + +struct IMSafeTrustMe(UnsafeCell<u32>); +unsafe impl Send for IMSafeTrustMe {} +unsafe impl Sync for IMSafeTrustMe {} + +static BAR: IMSafeTrustMe = IMSafeTrustMe(UnsafeCell::new(5)); + + + +struct Wrap<T>(T); +unsafe impl<T> Send for Wrap<T> {} +unsafe impl<T> Sync for Wrap<T> {} + +static BAR_PTR: Wrap<*mut u32> = Wrap(BAR.0.get()); + +const fn fst_ref<T, U>(x: &(T, U)) -> &T { &x.0 } + +fn main() {} diff --git a/tests/ui/consts/std/cell.stderr b/tests/ui/consts/std/cell.stderr new file mode 100644 index 000000000..937fa7db0 --- /dev/null +++ b/tests/ui/consts/std/cell.stderr @@ -0,0 +1,26 @@ +error: encountered dangling pointer in final constant + --> $DIR/cell.rs:6:1 + | +LL | static FOO: Wrap<*mut u32> = Wrap(Cell::new(42).as_ptr()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered dangling pointer in final constant + --> $DIR/cell.rs:8:1 + | +LL | const FOO_CONST: Wrap<*mut u32> = Wrap(Cell::new(42).as_ptr()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered dangling pointer in final constant + --> $DIR/cell.rs:22:1 + | +LL | const FOO4_CONST: Wrap<*mut u32> = Wrap(FOO3_CONST.0.as_ptr()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered dangling pointer in final constant + --> $DIR/cell.rs:27:1 + | +LL | const FOO2: *mut u32 = Cell::new(42).as_ptr(); + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/consts/std/iter.rs b/tests/ui/consts/std/iter.rs new file mode 100644 index 000000000..e9af781eb --- /dev/null +++ b/tests/ui/consts/std/iter.rs @@ -0,0 +1,9 @@ +// run-pass + +const I: std::iter::Empty<u32> = std::iter::empty(); + +fn main() { + for i in I { + panic!("magical value creation: {}", i); + } +} diff --git a/tests/ui/consts/std/slice.rs b/tests/ui/consts/std/slice.rs new file mode 100644 index 000000000..f19defc64 --- /dev/null +++ b/tests/ui/consts/std/slice.rs @@ -0,0 +1,10 @@ +// build-pass (FIXME(62277): could be check-pass?) + +struct Wrap<T>(T); +unsafe impl<T> Send for Wrap<T> {} +unsafe impl<T> Sync for Wrap<T> {} + +static FOO: Wrap<*const u32> = Wrap([42, 44, 46].as_ptr()); +static BAR: Wrap<*const u8> = Wrap("hello".as_ptr()); + +fn main() {} diff --git a/tests/ui/consts/too_generic_eval_ice.rs b/tests/ui/consts/too_generic_eval_ice.rs new file mode 100644 index 000000000..8b3f4b714 --- /dev/null +++ b/tests/ui/consts/too_generic_eval_ice.rs @@ -0,0 +1,14 @@ +pub struct Foo<A, B>(A, B); + +impl<A, B> Foo<A, B> { + const HOST_SIZE: usize = std::mem::size_of::<B>(); + + pub fn crash() -> bool { + [5; Self::HOST_SIZE] == [6; 0] + //~^ ERROR constant expression depends on a generic parameter + //~| ERROR constant expression depends on a generic parameter + //~| ERROR can't compare `[{integer}; Self::HOST_SIZE]` with `[{integer}; 0]` + } +} + +fn main() {} diff --git a/tests/ui/consts/too_generic_eval_ice.stderr b/tests/ui/consts/too_generic_eval_ice.stderr new file mode 100644 index 000000000..5af82a3e3 --- /dev/null +++ b/tests/ui/consts/too_generic_eval_ice.stderr @@ -0,0 +1,37 @@ +error: constant expression depends on a generic parameter + --> $DIR/too_generic_eval_ice.rs:7:13 + | +LL | [5; Self::HOST_SIZE] == [6; 0] + | ^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: constant expression depends on a generic parameter + --> $DIR/too_generic_eval_ice.rs:7:30 + | +LL | [5; Self::HOST_SIZE] == [6; 0] + | ^^ + | + = note: this may fail depending on what value the parameter takes + +error[E0277]: can't compare `[{integer}; Self::HOST_SIZE]` with `[{integer}; 0]` + --> $DIR/too_generic_eval_ice.rs:7:30 + | +LL | [5; Self::HOST_SIZE] == [6; 0] + | ^^ no implementation for `[{integer}; Self::HOST_SIZE] == [{integer}; 0]` + | + = help: the trait `PartialEq<[{integer}; 0]>` is not implemented for `[{integer}; Self::HOST_SIZE]` + = help: the following other types implement trait `PartialEq<Rhs>`: + <&[B] as PartialEq<[A; N]>> + <&[T] as PartialEq<Vec<U, A>>> + <&mut [B] as PartialEq<[A; N]>> + <&mut [T] as PartialEq<Vec<U, A>>> + <[A; N] as PartialEq<&[B]>> + <[A; N] as PartialEq<&mut [B]>> + <[A; N] as PartialEq<[B; N]>> + <[A; N] as PartialEq<[B]>> + and 3 others + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_specialization.rs b/tests/ui/consts/trait_specialization.rs new file mode 100644 index 000000000..c581ef6b0 --- /dev/null +++ b/tests/ui/consts/trait_specialization.rs @@ -0,0 +1,65 @@ +// ignore-wasm32-bare which doesn't support `std::process:exit()` +// compile-flags: -Zmir-opt-level=3 +// run-pass + +// Tests that specialization does not cause optimizations running on polymorphic MIR to resolve +// to a `default` implementation. + +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete + +trait Marker {} + +trait SpecializedTrait { + const CONST_BOOL: bool; + const CONST_STR: &'static str; + fn method() -> &'static str; +} +impl <T> SpecializedTrait for T { + default const CONST_BOOL: bool = false; + default const CONST_STR: &'static str = "in default impl"; + #[inline(always)] + default fn method() -> &'static str { + "in default impl" + } +} +impl <T: Marker> SpecializedTrait for T { + const CONST_BOOL: bool = true; + const CONST_STR: &'static str = "in specialized impl"; + fn method() -> &'static str { + "in specialized impl" + } +} + +fn const_bool<T>() -> &'static str { + if <T as SpecializedTrait>::CONST_BOOL { + "in specialized impl" + } else { + "in default impl" + } +} +fn const_str<T>() -> &'static str { + <T as SpecializedTrait>::CONST_STR +} +fn run_method<T>() -> &'static str { + <T as SpecializedTrait>::method() +} + +struct TypeA; +impl Marker for TypeA {} +struct TypeB; + +#[inline(never)] +fn exit_if_not_eq(left: &str, right: &str) { + if left != right { + std::process::exit(1); + } +} + +pub fn main() { + exit_if_not_eq("in specialized impl", const_bool::<TypeA>()); + exit_if_not_eq("in default impl", const_bool::<TypeB>()); + exit_if_not_eq("in specialized impl", const_str::<TypeA>()); + exit_if_not_eq("in default impl", const_str::<TypeB>()); + exit_if_not_eq("in specialized impl", run_method::<TypeA>()); + exit_if_not_eq("in default impl", run_method::<TypeB>()); +} diff --git a/tests/ui/consts/trait_specialization.stderr b/tests/ui/consts/trait_specialization.stderr new file mode 100644 index 000000000..10bebe8eb --- /dev/null +++ b/tests/ui/consts/trait_specialization.stderr @@ -0,0 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/trait_specialization.rs:8:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/consts/transmute-const.rs b/tests/ui/consts/transmute-const.rs new file mode 100644 index 000000000..c5c3dfc4c --- /dev/null +++ b/tests/ui/consts/transmute-const.rs @@ -0,0 +1,12 @@ +// run-pass + +use std::mem; + +#[repr(transparent)] +struct Foo(#[allow(unused_tuple_struct_fields)] u32); + +const TRANSMUTED_U32: u32 = unsafe { mem::transmute(Foo(3)) }; + +fn main() { + assert_eq!(TRANSMUTED_U32, 3); +} diff --git a/tests/ui/consts/transmute-size-mismatch-before-typeck.rs b/tests/ui/consts/transmute-size-mismatch-before-typeck.rs new file mode 100644 index 000000000..852a5b3b4 --- /dev/null +++ b/tests/ui/consts/transmute-size-mismatch-before-typeck.rs @@ -0,0 +1,13 @@ +// normalize-stderr-64bit "64 bits" -> "word size" +// normalize-stderr-32bit "32 bits" -> "word size" +// normalize-stderr-64bit "128 bits" -> "2 * word size" +// normalize-stderr-32bit "64 bits" -> "2 * word size" + +fn main() { + match &b""[..] { + ZST => {} + } +} + +const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; +//~^ ERROR cannot transmute between types of different sizes diff --git a/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr b/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr new file mode 100644 index 000000000..4e8470173 --- /dev/null +++ b/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr @@ -0,0 +1,12 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/transmute-size-mismatch-before-typeck.rs:12:29 + | +LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `usize` (word size) + = note: target type: `&[u8]` (2 * word size) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0512`. diff --git a/tests/ui/consts/try-operator.rs b/tests/ui/consts/try-operator.rs new file mode 100644 index 000000000..fe43b132c --- /dev/null +++ b/tests/ui/consts/try-operator.rs @@ -0,0 +1,23 @@ +// run-pass + +#![feature(try_trait_v2)] +#![feature(const_trait_impl)] +#![feature(const_try)] +#![feature(const_convert)] + +fn main() { + const fn result() -> Result<bool, ()> { + Err(())?; + Ok(true) + } + + const FOO: Result<bool, ()> = result(); + assert_eq!(Err(()), FOO); + + const fn option() -> Option<()> { + None?; + Some(()) + } + const BAR: Option<()> = option(); + assert_eq!(None, BAR); +} diff --git a/tests/ui/consts/tuple-struct-constructors.rs b/tests/ui/consts/tuple-struct-constructors.rs new file mode 100644 index 000000000..1655f0eb8 --- /dev/null +++ b/tests/ui/consts/tuple-struct-constructors.rs @@ -0,0 +1,10 @@ +// run-pass + +// https://github.com/rust-lang/rust/issues/41898 + +use std::num::NonZeroU64; + +fn main() { + const FOO: NonZeroU64 = unsafe { NonZeroU64::new_unchecked(2) }; + if let FOO = FOO {} +} diff --git a/tests/ui/consts/underscore_const_names.rs b/tests/ui/consts/underscore_const_names.rs new file mode 100644 index 000000000..d0e625bf1 --- /dev/null +++ b/tests/ui/consts/underscore_const_names.rs @@ -0,0 +1,31 @@ +// build-pass (FIXME(62277): could be check-pass?) + +#![deny(unused)] + +trait Trt {} +pub struct Str {} +impl Trt for Str {} + +macro_rules! check_impl { + ($struct:ident,$trait:ident) => { + const _ : () = { + use std::marker::PhantomData; + struct ImplementsTrait<T: $trait>(PhantomData<T>); + let _ = ImplementsTrait::<$struct>(PhantomData); + () + }; + } +} + +const _ : () = (); + +const _ : i32 = 42; +const _ : Str = Str{}; + +check_impl!(Str, Trt); +check_impl!(Str, Trt); + +fn main() { + check_impl!(Str, Trt); + check_impl!(Str, Trt); +} diff --git a/tests/ui/consts/uninhabited-const-issue-61744.rs b/tests/ui/consts/uninhabited-const-issue-61744.rs new file mode 100644 index 000000000..ca6449cce --- /dev/null +++ b/tests/ui/consts/uninhabited-const-issue-61744.rs @@ -0,0 +1,19 @@ +// build-fail + +pub const unsafe fn fake_type<T>() -> T { + hint_unreachable() //~ ERROR evaluation of `<i32 as Const>::CONSTANT` failed +} + +pub const unsafe fn hint_unreachable() -> ! { + fake_type() +} + +trait Const { + const CONSTANT: i32 = unsafe { fake_type() }; +} + +impl<T> Const for T {} + +pub fn main() -> () { + dbg!(i32::CONSTANT); //~ constant +} diff --git a/tests/ui/consts/uninhabited-const-issue-61744.stderr b/tests/ui/consts/uninhabited-const-issue-61744.stderr new file mode 100644 index 000000000..3a94e1931 --- /dev/null +++ b/tests/ui/consts/uninhabited-const-issue-61744.stderr @@ -0,0 +1,668 @@ +error[E0080]: evaluation of `<i32 as Const>::CONSTANT` failed + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ reached the configured maximum number of stack frames + | +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<!>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `hint_unreachable` + --> $DIR/uninhabited-const-issue-61744.rs:8:5 + | +LL | fake_type() + | ^^^^^^^^^^^ +note: inside `fake_type::<i32>` + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ +note: inside `<i32 as Const>::CONSTANT` + --> $DIR/uninhabited-const-issue-61744.rs:12:36 + | +LL | const CONSTANT: i32 = unsafe { fake_type() }; + | ^^^^^^^^^^^ + +note: erroneous constant used + --> $DIR/uninhabited-const-issue-61744.rs:18:10 + | +LL | dbg!(i32::CONSTANT); + | ^^^^^^^^^^^^^ + +note: erroneous constant used + --> $DIR/uninhabited-const-issue-61744.rs:18:10 + | +LL | dbg!(i32::CONSTANT); + | ^^^^^^^^^^^^^ + +note: erroneous constant used + --> $DIR/uninhabited-const-issue-61744.rs:18:10 + | +LL | dbg!(i32::CONSTANT); + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/union_constant.rs b/tests/ui/consts/union_constant.rs new file mode 100644 index 000000000..508ff7e0a --- /dev/null +++ b/tests/ui/consts/union_constant.rs @@ -0,0 +1,11 @@ +// build-pass (FIXME(62277): could be check-pass?) + +union Uninit { + _never_use: *const u8, + uninit: (), +} + +const UNINIT: Uninit = Uninit { uninit: () }; +const UNINIT2: (Uninit,) = (Uninit { uninit: () }, ); + +fn main() {} diff --git a/tests/ui/consts/unnormalized-param-env.rs b/tests/ui/consts/unnormalized-param-env.rs new file mode 100644 index 000000000..a7bbe4db9 --- /dev/null +++ b/tests/ui/consts/unnormalized-param-env.rs @@ -0,0 +1,31 @@ +// check-pass + +pub trait CSpace<const N: usize> { + type Traj; +} + +pub struct Const<const R: usize>; + +pub trait Obstacle<CS, const N: usize> { + fn trajectory_free<FT, S1>(&self, t: &FT) + where + CS::Traj: Sized, + CS: CSpace<N>; +} + +// ----- + +const N: usize = 4; + +struct ObstacleSpace2df32; + +impl<CS> Obstacle<CS, N> for ObstacleSpace2df32 { + fn trajectory_free<TF, S1>(&self, t: &TF) + where + CS::Traj: Sized, + CS: CSpace<N>, + { + } +} + +fn main() {} diff --git a/tests/ui/consts/unstable-const-fn-in-libcore.rs b/tests/ui/consts/unstable-const-fn-in-libcore.rs new file mode 100644 index 000000000..ca4ed8f0b --- /dev/null +++ b/tests/ui/consts/unstable-const-fn-in-libcore.rs @@ -0,0 +1,27 @@ +// This is a non-regression test for const-qualification of unstable items in libcore +// as explained in issue #67053. +// const-qualification could miss some `const fn`s if they were unstable and the feature +// gate was not enabled in libcore. + +#![stable(feature = "core", since = "1.6.0")] +#![feature(staged_api, const_trait_impl)] + +enum Opt<T> { + Some(T), + None, +} + +impl<T> Opt<T> { + #[rustc_const_unstable(feature = "foo", issue = "none")] + #[stable(feature = "rust1", since = "1.0.0")] + const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T { + //~^ ERROR destructor of + //~| ERROR destructor of + match self { + Opt::Some(t) => t, + Opt::None => f(), + } + } +} + +fn main() {} diff --git a/tests/ui/consts/unstable-const-fn-in-libcore.stderr b/tests/ui/consts/unstable-const-fn-in-libcore.stderr new file mode 100644 index 000000000..e5b00dd07 --- /dev/null +++ b/tests/ui/consts/unstable-const-fn-in-libcore.stderr @@ -0,0 +1,21 @@ +error[E0493]: destructor of `F` cannot be evaluated at compile-time + --> $DIR/unstable-const-fn-in-libcore.rs:17:60 + | +LL | const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T { + | ^ the destructor for this type cannot be evaluated in constant functions +... +LL | } + | - value is dropped here + +error[E0493]: destructor of `Opt<T>` cannot be evaluated at compile-time + --> $DIR/unstable-const-fn-in-libcore.rs:17:54 + | +LL | const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T { + | ^^^^ the destructor for this type cannot be evaluated in constant functions +... +LL | } + | - value is dropped here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/unstable-precise-live-drops-in-libcore.rs b/tests/ui/consts/unstable-precise-live-drops-in-libcore.rs new file mode 100644 index 000000000..619084eaa --- /dev/null +++ b/tests/ui/consts/unstable-precise-live-drops-in-libcore.rs @@ -0,0 +1,23 @@ +// check-pass + +#![stable(feature = "core", since = "1.6.0")] +#![feature(staged_api)] +#![feature(const_precise_live_drops)] + +enum Either<T, S> { + Left(T), + Right(S), +} + +impl<T> Either<T, T> { + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "foo", issue = "none")] + pub const fn unwrap(self) -> T { + match self { + Self::Left(t) => t, + Self::Right(t) => t, + } + } +} + +fn main() {} diff --git a/tests/ui/consts/unwind-abort.rs b/tests/ui/consts/unwind-abort.rs new file mode 100644 index 000000000..6c94fc7b9 --- /dev/null +++ b/tests/ui/consts/unwind-abort.rs @@ -0,0 +1,16 @@ +// check-pass + +#![feature(c_unwind, const_extern_fn)] + +// We don't unwind in const-eval anyways. +const extern "C" fn foo() { + panic!() +} + +const fn bar() { + foo(); +} + +fn main() { + bar(); +} diff --git a/tests/ui/consts/validate_never_arrays.rs b/tests/ui/consts/validate_never_arrays.rs new file mode 100644 index 000000000..f96ca6839 --- /dev/null +++ b/tests/ui/consts/validate_never_arrays.rs @@ -0,0 +1,12 @@ +// Strip out raw byte dumps to make comparison platform-independent: +// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" +// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" +#![feature(never_type)] + +const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior +const _: &[!; 0] = unsafe { &*(1_usize as *const [!; 0]) }; // ok +const _: &[!] = unsafe { &*(1_usize as *const [!; 0]) }; // ok +const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior +const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; //~ ERROR undefined behavior + +fn main() {} diff --git a/tests/ui/consts/validate_never_arrays.stderr b/tests/ui/consts/validate_never_arrays.stderr new file mode 100644 index 000000000..12090e483 --- /dev/null +++ b/tests/ui/consts/validate_never_arrays.stderr @@ -0,0 +1,36 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/validate_never_arrays.rs:6:1 + | +LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; + | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1] + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/validate_never_arrays.rs:9:1 + | +LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; + | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/validate_never_arrays.rs:10:1 + | +LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; + | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/write-to-static-mut-in-static.rs b/tests/ui/consts/write-to-static-mut-in-static.rs new file mode 100644 index 000000000..43c63fed8 --- /dev/null +++ b/tests/ui/consts/write-to-static-mut-in-static.rs @@ -0,0 +1,10 @@ +pub static mut A: u32 = 0; +pub static mut B: () = unsafe { A = 1; }; +//~^ ERROR could not evaluate static initializer + +pub static mut C: u32 = unsafe { C = 1; 0 }; +//~^ ERROR cycle detected + +pub static D: u32 = D; + +fn main() {} diff --git a/tests/ui/consts/write-to-static-mut-in-static.stderr b/tests/ui/consts/write-to-static-mut-in-static.stderr new file mode 100644 index 000000000..395b2d42f --- /dev/null +++ b/tests/ui/consts/write-to-static-mut-in-static.stderr @@ -0,0 +1,34 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/write-to-static-mut-in-static.rs:2:33 + | +LL | pub static mut B: () = unsafe { A = 1; }; + | ^^^^^ modifying a static's initial value from another static's initializer + +error[E0391]: cycle detected when const-evaluating + checking `C` + --> $DIR/write-to-static-mut-in-static.rs:5:1 + | +LL | pub static mut C: u32 = unsafe { C = 1; 0 }; + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires const-evaluating + checking `C`... + --> $DIR/write-to-static-mut-in-static.rs:5:34 + | +LL | pub static mut C: u32 = unsafe { C = 1; 0 }; + | ^^^^^ + = note: ...which again requires const-evaluating + checking `C`, completing the cycle +note: cycle used when linting top-level module + --> $DIR/write-to-static-mut-in-static.rs:1:1 + | +LL | / pub static mut A: u32 = 0; +LL | | pub static mut B: () = unsafe { A = 1; }; +LL | | +LL | | +... | +LL | | +LL | | fn main() {} + | |____________^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0080, E0391. +For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/write_to_mut_ref_dest.rs b/tests/ui/consts/write_to_mut_ref_dest.rs new file mode 100644 index 000000000..484ec4244 --- /dev/null +++ b/tests/ui/consts/write_to_mut_ref_dest.rs @@ -0,0 +1,17 @@ +// revisions: stock mut_refs +//[mut_refs] check-pass + +#![cfg_attr(mut_refs, feature(const_mut_refs))] + +use std::cell::Cell; + +const FOO: &u32 = { + let mut a = 42; + { + let b: *mut u32 = &mut a; //[stock]~ ERROR mutable references are not allowed in constants + unsafe { *b = 5; } //[stock]~ ERROR dereferencing raw mutable pointers in constants + } + &{a} +}; + +fn main() {} diff --git a/tests/ui/consts/write_to_mut_ref_dest.stock.stderr b/tests/ui/consts/write_to_mut_ref_dest.stock.stderr new file mode 100644 index 000000000..bb1059276 --- /dev/null +++ b/tests/ui/consts/write_to_mut_ref_dest.stock.stderr @@ -0,0 +1,21 @@ +error[E0658]: mutable references are not allowed in constants + --> $DIR/write_to_mut_ref_dest.rs:11:27 + | +LL | let b: *mut u32 = &mut a; + | ^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: dereferencing raw mutable pointers in constants is unstable + --> $DIR/write_to_mut_ref_dest.rs:12:18 + | +LL | unsafe { *b = 5; } + | ^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/write_to_static_via_mut_ref.rs b/tests/ui/consts/write_to_static_via_mut_ref.rs new file mode 100644 index 000000000..39b830ae4 --- /dev/null +++ b/tests/ui/consts/write_to_static_via_mut_ref.rs @@ -0,0 +1,7 @@ +#![feature(const_mut_refs)] + +static OH_NO: &mut i32 = &mut 42; //~ ERROR mutable references are not allowed +fn main() { + assert_eq!(*OH_NO, 42); + *OH_NO = 43; //~ ERROR cannot assign to `*OH_NO`, as `OH_NO` is an immutable static +} diff --git a/tests/ui/consts/write_to_static_via_mut_ref.stderr b/tests/ui/consts/write_to_static_via_mut_ref.stderr new file mode 100644 index 000000000..f64f0db6b --- /dev/null +++ b/tests/ui/consts/write_to_static_via_mut_ref.stderr @@ -0,0 +1,16 @@ +error[E0764]: mutable references are not allowed in the final value of statics + --> $DIR/write_to_static_via_mut_ref.rs:3:26 + | +LL | static OH_NO: &mut i32 = &mut 42; + | ^^^^^^^ + +error[E0594]: cannot assign to `*OH_NO`, as `OH_NO` is an immutable static item + --> $DIR/write_to_static_via_mut_ref.rs:6:5 + | +LL | *OH_NO = 43; + | ^^^^^^^^^^^ cannot assign + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0594, E0764. +For more information about an error, try `rustc --explain E0594`. diff --git a/tests/ui/consts/zst_no_llvm_alloc.rs b/tests/ui/consts/zst_no_llvm_alloc.rs new file mode 100644 index 000000000..2a41f708c --- /dev/null +++ b/tests/ui/consts/zst_no_llvm_alloc.rs @@ -0,0 +1,21 @@ +// run-pass + +#[repr(align(4))] +struct Foo; + +static FOO: Foo = Foo; + +fn main() { + let x: &'static () = &(); + assert_ne!(x as *const () as usize, 1); + let x: &'static Foo = &Foo; + assert_ne!(x as *const Foo as usize, 4); + + // statics must have a unique address + assert_ne!(&FOO as *const Foo as usize, 4); + + // FIXME this two tests should be assert_eq! + // this stopped working since we are promoting to constants instead of statics + assert_ne!(<Vec<i32>>::new().as_ptr(), <&[i32]>::default().as_ptr()); + assert_ne!(<Box<[i32]>>::default().as_ptr(), (&[]).as_ptr()); +} |