diff options
Diffstat (limited to 'tests')
36 files changed, 772 insertions, 82 deletions
diff --git a/tests/codegen/intrinsics/transmute.rs b/tests/codegen/intrinsics/transmute.rs new file mode 100644 index 00000000000..cefcf9ed9ca --- /dev/null +++ b/tests/codegen/intrinsics/transmute.rs @@ -0,0 +1,196 @@ +// compile-flags: -O -C no-prepopulate-passes +// only-64bit (so I don't need to worry about usize) +// min-llvm-version: 15.0 # this test assumes `ptr`s + +#![crate_type = "lib"] +#![feature(core_intrinsics)] +#![feature(custom_mir)] +#![feature(inline_const)] + +use std::mem::transmute; + +// Some of the cases here are statically rejected by `mem::transmute`, so +// we need to generate custom MIR for those cases to get to codegen. +use std::intrinsics::mir::*; + +enum Never {} + +#[repr(align(2))] +pub struct BigNever(Never, u16, Never); + +#[repr(align(8))] +pub struct Scalar64(i64); + +#[repr(C, align(4))] +pub struct Aggregate64(u16, u8, i8, f32); + +// CHECK-LABEL: @check_bigger_size( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "initial")] +pub unsafe fn check_bigger_size(x: u16) -> u32 { + // CHECK: call void @llvm.trap + mir!{ + { + RET = CastTransmute(x); + Return() + } + } +} + +// CHECK-LABEL: @check_smaller_size( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "initial")] +pub unsafe fn check_smaller_size(x: u32) -> u16 { + // CHECK: call void @llvm.trap + mir!{ + { + RET = CastTransmute(x); + Return() + } + } +} + +// CHECK-LABEL: @check_to_uninhabited( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "initial")] +pub unsafe fn check_to_uninhabited(x: u16) -> BigNever { + // CHECK: call void @llvm.trap + mir!{ + { + RET = CastTransmute(x); + Return() + } + } +} + +// CHECK-LABEL: @check_from_uninhabited( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "initial")] +pub unsafe fn check_from_uninhabited(x: BigNever) -> u16 { + // CHECK: call void @llvm.trap + mir!{ + { + RET = CastTransmute(x); + Return() + } + } +} + +// CHECK-LABEL: @check_to_newtype( +#[no_mangle] +pub unsafe fn check_to_newtype(x: u64) -> Scalar64 { + // CHECK: %0 = alloca i64 + // CHECK: store i64 %x, ptr %0 + // CHECK: %1 = load i64, ptr %0 + // CHECK: ret i64 %1 + transmute(x) +} + +// CHECK-LABEL: @check_from_newtype( +#[no_mangle] +pub unsafe fn check_from_newtype(x: Scalar64) -> u64 { + // CHECK: %0 = alloca i64 + // CHECK: store i64 %x, ptr %0 + // CHECK: %1 = load i64, ptr %0 + // CHECK: ret i64 %1 + transmute(x) +} + +// CHECK-LABEL: @check_to_pair( +#[no_mangle] +pub unsafe fn check_to_pair(x: u64) -> Option<i32> { + // CHECK: %0 = alloca { i32, i32 }, align 4 + // CHECK: store i64 %x, ptr %0, align 4 + transmute(x) +} + +// CHECK-LABEL: @check_from_pair( +#[no_mangle] +pub unsafe fn check_from_pair(x: Option<i32>) -> u64 { + // The two arguments are of types that are only 4-aligned, but they're + // immediates so we can write using the destination alloca's alignment. + const { assert!(std::mem::align_of::<Option<i32>>() == 4) }; + + // CHECK: %0 = alloca i64, align 8 + // CHECK: store i32 %x.0, ptr %1, align 8 + // CHECK: store i32 %x.1, ptr %2, align 4 + // CHECK: %3 = load i64, ptr %0, align 8 + // CHECK: ret i64 %3 + transmute(x) +} + +// CHECK-LABEL: @check_to_float( +#[no_mangle] +pub unsafe fn check_to_float(x: u32) -> f32 { + // CHECK: %0 = alloca float + // CHECK: store i32 %x, ptr %0 + // CHECK: %1 = load float, ptr %0 + // CHECK: ret float %1 + transmute(x) +} + +// CHECK-LABEL: @check_from_float( +#[no_mangle] +pub unsafe fn check_from_float(x: f32) -> u32 { + // CHECK: %0 = alloca i32 + // CHECK: store float %x, ptr %0 + // CHECK: %1 = load i32, ptr %0 + // CHECK: ret i32 %1 + transmute(x) +} + +// CHECK-LABEL: @check_to_bytes( +#[no_mangle] +pub unsafe fn check_to_bytes(x: u32) -> [u8; 4] { + // CHECK: %0 = alloca [4 x i8], align 1 + // CHECK: store i32 %x, ptr %0, align 1 + // CHECK: %1 = load i32, ptr %0, align 1 + // CHECK: ret i32 %1 + transmute(x) +} + +// CHECK-LABEL: @check_from_bytes( +#[no_mangle] +pub unsafe fn check_from_bytes(x: [u8; 4]) -> u32 { + // CHECK: %1 = alloca i32, align 4 + // CHECK: %x = alloca [4 x i8], align 1 + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %1, ptr align 1 %x, i64 4, i1 false) + // CHECK: %3 = load i32, ptr %1, align 4 + // CHECK: ret i32 %3 + transmute(x) +} + +// CHECK-LABEL: @check_to_aggregate( +#[no_mangle] +pub unsafe fn check_to_aggregate(x: u64) -> Aggregate64 { + // CHECK: %0 = alloca %Aggregate64, align 4 + // CHECK: store i64 %x, ptr %0, align 4 + // CHECK: %1 = load i64, ptr %0, align 4 + // CHECK: ret i64 %1 + transmute(x) +} + +// CHECK-LABEL: @check_from_aggregate( +#[no_mangle] +pub unsafe fn check_from_aggregate(x: Aggregate64) -> u64 { + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %{{[0-9]+}}, ptr align 4 %x, i64 8, i1 false) + transmute(x) +} + +// CHECK-LABEL: @check_long_array_less_aligned( +#[no_mangle] +pub unsafe fn check_long_array_less_aligned(x: [u64; 100]) -> [u16; 400] { + // CHECK-NEXT: start + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 2 %0, ptr align 8 %x, i64 800, i1 false) + // CHECK-NEXT: ret void + transmute(x) +} + +// CHECK-LABEL: @check_long_array_more_aligned( +#[no_mangle] +pub unsafe fn check_long_array_more_aligned(x: [u8; 100]) -> [u32; 25] { + // CHECK-NEXT: start + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %0, ptr align 1 %x, i64 100, i1 false) + // CHECK-NEXT: ret void + transmute(x) +} diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs index 260dcbac0fc..4d7a80bfbe5 100644 --- a/tests/codegen/transmute-scalar.rs +++ b/tests/codegen/transmute-scalar.rs @@ -1,13 +1,19 @@ // compile-flags: -O -C no-prepopulate-passes +// min-llvm-version: 15.0 # this test assumes `ptr`s and thus no `pointercast`s #![crate_type = "lib"] -// FIXME(eddyb) all of these tests show memory stores and loads, even after a -// scalar `bitcast`, more special-casing is required to remove `alloca` usage. +// With opaque ptrs in LLVM, `transmute` can load/store any `alloca` as any type, +// without needing to pointercast, and SRoA will turn that into a `bitcast`. +// As such, there's no longer special-casing in `transmute` to attempt to +// generate `bitcast` ourselves, as that just made the IR longer. + +// FIXME: That said, `bitcast`s could still be a valuable addition if they could +// be done in `rvalue_creates_operand`, and thus avoid the `alloca`s entirely. // CHECK-LABEL: define{{.*}}i32 @f32_to_bits(float noundef %x) -// CHECK: store i32 %{{.*}}, {{.*}} %0 -// CHECK-NEXT: %[[RES:.*]] = load i32, {{.*}} %0 +// CHECK: store float %{{.*}}, ptr %0 +// CHECK-NEXT: %[[RES:.*]] = load i32, ptr %0 // CHECK: ret i32 %[[RES]] #[no_mangle] pub fn f32_to_bits(x: f32) -> u32 { @@ -25,12 +31,10 @@ pub fn bool_to_byte(b: bool) -> u8 { } // CHECK-LABEL: define{{.*}}noundef zeroext i1 @byte_to_bool(i8 noundef %byte) -// CHECK: %1 = trunc i8 %byte to i1 -// CHECK-NEXT: %2 = zext i1 %1 to i8 -// CHECK-NEXT: store i8 %2, {{.*}} %0 -// CHECK-NEXT: %3 = load i8, {{.*}} %0 -// CHECK-NEXT: %4 = trunc i8 %3 to i1 -// CHECK: ret i1 %4 +// CHECK: store i8 %byte, ptr %0 +// CHECK-NEXT: %1 = load i8, {{.*}} %0 +// CHECK-NEXT: %2 = trunc i8 %1 to i1 +// CHECK: ret i1 %2 #[no_mangle] pub unsafe fn byte_to_bool(byte: u8) -> bool { std::mem::transmute(byte) @@ -45,20 +49,8 @@ pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 { unsafe { std::mem::transmute(p) } } -// HACK(eddyb) scalar `transmute`s between pointers and non-pointers are -// currently not special-cased like other scalar `transmute`s, because -// LLVM requires specifically `ptrtoint`/`inttoptr` instead of `bitcast`. -// -// Tests below show the non-special-cased behavior (with the possible -// future special-cased instructions in the "NOTE(eddyb)" comments). - // CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int({{i16\*|ptr}} noundef %p) - -// NOTE(eddyb) see above, the following two CHECK lines should ideally be this: -// %2 = ptrtoint i16* %p to [[USIZE]] -// store [[USIZE]] %2, [[USIZE]]* %0 // CHECK: store {{i16\*|ptr}} %p, {{.*}} - // CHECK-NEXT: %[[RES:.*]] = load [[USIZE]], {{.*}} %0 // CHECK: ret [[USIZE]] %[[RES]] #[no_mangle] @@ -67,12 +59,7 @@ pub fn ptr_to_int(p: *mut u16) -> usize { } // CHECK: define{{.*}}{{i16\*|ptr}} @int_to_ptr([[USIZE]] noundef %i) - -// NOTE(eddyb) see above, the following two CHECK lines should ideally be this: -// %2 = inttoptr [[USIZE]] %i to i16* -// store i16* %2, i16** %0 // CHECK: store [[USIZE]] %i, {{.*}} - // CHECK-NEXT: %[[RES:.*]] = load {{i16\*|ptr}}, {{.*}} %0 // CHECK: ret {{i16\*|ptr}} %[[RES]] #[no_mangle] diff --git a/tests/mir-opt/const_prop/transmute.from_char.ConstProp.diff b/tests/mir-opt/const_prop/transmute.from_char.ConstProp.diff new file mode 100644 index 00000000000..933dfbb5166 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.from_char.ConstProp.diff @@ -0,0 +1,15 @@ +- // MIR for `from_char` before ConstProp ++ // MIR for `from_char` after ConstProp + + fn from_char() -> i32 { + let mut _0: i32; // return place in scope 0 at $DIR/transmute.rs:+0:23: +0:26 + scope 1 { + } + + bb0: { +- _0 = const 'R' as i32 (Transmute); // scope 1 at $DIR/transmute.rs:+1:14: +1:28 ++ _0 = const 82_i32; // scope 1 at $DIR/transmute.rs:+1:14: +1:28 + return; // scope 0 at $DIR/transmute.rs:+2:2: +2:2 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.invalid_bool.ConstProp.diff b/tests/mir-opt/const_prop/transmute.invalid_bool.ConstProp.diff new file mode 100644 index 00000000000..f3474855f02 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.invalid_bool.ConstProp.diff @@ -0,0 +1,14 @@ +- // MIR for `invalid_bool` before ConstProp ++ // MIR for `invalid_bool` after ConstProp + + fn invalid_bool() -> bool { + let mut _0: bool; // return place in scope 0 at $DIR/transmute.rs:+0:33: +0:37 + scope 1 { + } + + bb0: { + _0 = const -1_i8 as bool (Transmute); // scope 1 at $DIR/transmute.rs:+1:14: +1:30 + return; // scope 0 at $DIR/transmute.rs:+2:2: +2:2 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.invalid_char.ConstProp.diff b/tests/mir-opt/const_prop/transmute.invalid_char.ConstProp.diff new file mode 100644 index 00000000000..ba087e226c9 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.invalid_char.ConstProp.diff @@ -0,0 +1,14 @@ +- // MIR for `invalid_char` before ConstProp ++ // MIR for `invalid_char` after ConstProp + + fn invalid_char() -> char { + let mut _0: char; // return place in scope 0 at $DIR/transmute.rs:+0:33: +0:37 + scope 1 { + } + + bb0: { + _0 = const _ as char (Transmute); // scope 1 at $DIR/transmute.rs:+1:14: +1:33 + return; // scope 0 at $DIR/transmute.rs:+2:2: +2:2 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.less_as_i8.ConstProp.diff b/tests/mir-opt/const_prop/transmute.less_as_i8.ConstProp.diff new file mode 100644 index 00000000000..76d464789c1 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.less_as_i8.ConstProp.diff @@ -0,0 +1,23 @@ +- // MIR for `less_as_i8` before ConstProp ++ // MIR for `less_as_i8` after ConstProp + + fn less_as_i8() -> i8 { + let mut _0: i8; // return place in scope 0 at $DIR/transmute.rs:+0:24: +0:26 + let mut _1: std::cmp::Ordering; // in scope 0 at $DIR/transmute.rs:+1:24: +1:48 + scope 1 { + } + + bb0: { + StorageLive(_1); // scope 1 at $DIR/transmute.rs:+1:24: +1:48 +- _1 = Less; // scope 1 at $DIR/transmute.rs:+1:24: +1:48 +- _0 = move _1 as i8 (Transmute); // scope 1 at $DIR/transmute.rs:+1:14: +1:49 ++ _1 = const Less; // scope 1 at $DIR/transmute.rs:+1:24: +1:48 ++ // mir::Constant ++ // + span: no-location ++ // + literal: Const { ty: std::cmp::Ordering, val: Value(Scalar(0xff)) } ++ _0 = const -1_i8; // scope 1 at $DIR/transmute.rs:+1:14: +1:49 + StorageDead(_1); // scope 1 at $DIR/transmute.rs:+1:48: +1:49 + return; // scope 0 at $DIR/transmute.rs:+2:2: +2:2 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.rs b/tests/mir-opt/const_prop/transmute.rs new file mode 100644 index 00000000000..b753cdccd60 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.rs @@ -0,0 +1,61 @@ +// unit-test: ConstProp +// compile-flags: -O --crate-type=lib + +use std::mem::transmute; + +// EMIT_MIR transmute.less_as_i8.ConstProp.diff +pub fn less_as_i8() -> i8 { + unsafe { transmute(std::cmp::Ordering::Less) } +} + +// EMIT_MIR transmute.from_char.ConstProp.diff +pub fn from_char() -> i32 { + unsafe { transmute('R') } +} + +// EMIT_MIR transmute.valid_char.ConstProp.diff +pub fn valid_char() -> char { + unsafe { transmute(0x52_u32) } +} + +// EMIT_MIR transmute.invalid_char.ConstProp.diff +pub unsafe fn invalid_char() -> char { + unsafe { transmute(i32::MAX) } +} + +// EMIT_MIR transmute.invalid_bool.ConstProp.diff +pub unsafe fn invalid_bool() -> bool { + unsafe { transmute(-1_i8) } +} + +// EMIT_MIR transmute.undef_union_as_integer.ConstProp.diff +pub unsafe fn undef_union_as_integer() -> u32 { + union Union32 { value: u32, unit: () } + unsafe { transmute(Union32 { unit: () }) } +} + +// EMIT_MIR transmute.unreachable_direct.ConstProp.diff +pub unsafe fn unreachable_direct() -> ! { + let x: Never = unsafe { transmute(()) }; + match x {} +} + +// EMIT_MIR transmute.unreachable_ref.ConstProp.diff +pub unsafe fn unreachable_ref() -> ! { + let x: &Never = unsafe { transmute(1_usize) }; + match *x {} +} + +// EMIT_MIR transmute.unreachable_mut.ConstProp.diff +pub unsafe fn unreachable_mut() -> ! { + let x: &mut Never = unsafe { transmute(1_usize) }; + match *x {} +} + +// EMIT_MIR transmute.unreachable_box.ConstProp.diff +pub unsafe fn unreachable_box() -> ! { + let x: Box<Never> = unsafe { transmute(1_usize) }; + match *x {} +} + +enum Never {} diff --git a/tests/mir-opt/const_prop/transmute.undef_union_as_integer.ConstProp.diff b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.ConstProp.diff new file mode 100644 index 00000000000..538b1f26e4c --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.ConstProp.diff @@ -0,0 +1,22 @@ +- // MIR for `undef_union_as_integer` before ConstProp ++ // MIR for `undef_union_as_integer` after ConstProp + + fn undef_union_as_integer() -> u32 { + let mut _0: u32; // return place in scope 0 at $DIR/transmute.rs:+0:43: +0:46 + let mut _1: undef_union_as_integer::Union32; // in scope 0 at $DIR/transmute.rs:+2:24: +2:44 + let mut _2: (); // in scope 0 at $DIR/transmute.rs:+2:40: +2:42 + scope 1 { + } + + bb0: { + StorageLive(_1); // scope 1 at $DIR/transmute.rs:+2:24: +2:44 + StorageLive(_2); // scope 1 at $DIR/transmute.rs:+2:40: +2:42 + _2 = (); // scope 1 at $DIR/transmute.rs:+2:40: +2:42 + _1 = Union32 { value: move _2 }; // scope 1 at $DIR/transmute.rs:+2:24: +2:44 + StorageDead(_2); // scope 1 at $DIR/transmute.rs:+2:43: +2:44 + _0 = move _1 as u32 (Transmute); // scope 1 at $DIR/transmute.rs:+2:14: +2:45 + StorageDead(_1); // scope 1 at $DIR/transmute.rs:+2:44: +2:45 + return; // scope 0 at $DIR/transmute.rs:+3:2: +3:2 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.diff b/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.diff new file mode 100644 index 00000000000..8bf97996a67 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.diff @@ -0,0 +1,23 @@ +- // MIR for `unreachable_box` before ConstProp ++ // MIR for `unreachable_box` after ConstProp + + fn unreachable_box() -> ! { + let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37 + let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:38: +3:2 + let _2: std::boxed::Box<Never>; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 + let mut _3: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:16 + scope 1 { + debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + } + scope 2 { + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:38: +3:2 + StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 + _2 = const 1_usize as std::boxed::Box<Never> (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 + StorageLive(_3); // scope 1 at $DIR/transmute.rs:+2:5: +2:16 + unreachable; // scope 1 at $DIR/transmute.rs:+2:11: +2:13 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.diff b/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.diff new file mode 100644 index 00000000000..81b7b368993 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.diff @@ -0,0 +1,25 @@ +- // MIR for `unreachable_direct` before ConstProp ++ // MIR for `unreachable_direct` after ConstProp + + fn unreachable_direct() -> ! { + let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:39: +0:40 + let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:41: +3:2 + let _2: Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 + let mut _3: (); // in scope 0 at $DIR/transmute.rs:+1:39: +1:41 + let mut _4: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:15 + scope 1 { + debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + } + scope 2 { + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:41: +3:2 + StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 + StorageLive(_3); // scope 2 at $DIR/transmute.rs:+1:39: +1:41 + _3 = (); // scope 2 at $DIR/transmute.rs:+1:39: +1:41 + _2 = move _3 as Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:29: +1:42 + unreachable; // scope 2 at $DIR/transmute.rs:+1:29: +1:42 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.diff b/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.diff new file mode 100644 index 00000000000..34f7aea8ed2 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.diff @@ -0,0 +1,27 @@ +- // MIR for `unreachable_mut` before ConstProp ++ // MIR for `unreachable_mut` after ConstProp + + fn unreachable_mut() -> ! { + let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37 + let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:38: +3:2 + let _2: &mut Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 + let mut _3: &mut Never; // in scope 0 at $DIR/transmute.rs:+1:34: +1:52 + let mut _4: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:16 + scope 1 { + debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + } + scope 2 { + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:38: +3:2 + StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 + StorageLive(_3); // scope 0 at $DIR/transmute.rs:+1:34: +1:52 + _3 = const 1_usize as &mut Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 + _2 = &mut (*_3); // scope 0 at $DIR/transmute.rs:+1:34: +1:52 + StorageDead(_3); // scope 0 at $DIR/transmute.rs:+1:54: +1:55 + StorageLive(_4); // scope 1 at $DIR/transmute.rs:+2:5: +2:16 + unreachable; // scope 1 at $DIR/transmute.rs:+2:11: +2:13 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.diff b/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.diff new file mode 100644 index 00000000000..ff95f2a0b94 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.diff @@ -0,0 +1,23 @@ +- // MIR for `unreachable_ref` before ConstProp ++ // MIR for `unreachable_ref` after ConstProp + + fn unreachable_ref() -> ! { + let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37 + let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:38: +3:2 + let _2: &Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 + let mut _3: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:16 + scope 1 { + debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + } + scope 2 { + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:38: +3:2 + StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 + _2 = const 1_usize as &Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:30: +1:48 + StorageLive(_3); // scope 1 at $DIR/transmute.rs:+2:5: +2:16 + unreachable; // scope 1 at $DIR/transmute.rs:+2:11: +2:13 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.valid_char.ConstProp.diff b/tests/mir-opt/const_prop/transmute.valid_char.ConstProp.diff new file mode 100644 index 00000000000..eac33b73003 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.valid_char.ConstProp.diff @@ -0,0 +1,15 @@ +- // MIR for `valid_char` before ConstProp ++ // MIR for `valid_char` after ConstProp + + fn valid_char() -> char { + let mut _0: char; // return place in scope 0 at $DIR/transmute.rs:+0:24: +0:28 + scope 1 { + } + + bb0: { +- _0 = const 82_u32 as char (Transmute); // scope 1 at $DIR/transmute.rs:+1:14: +1:33 ++ _0 = const 'R'; // scope 1 at $DIR/transmute.rs:+1:14: +1:33 + return; // scope 0 at $DIR/transmute.rs:+2:2: +2:2 + } + } + diff --git a/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff b/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff index bcda1288045..8e6e6fc0ec2 100644 --- a/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff +++ b/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff @@ -24,61 +24,49 @@ StorageLive(_2); // scope 0 at $DIR/issue_75439.rs:+2:9: +2:15 StorageLive(_3); // scope 2 at $DIR/issue_75439.rs:+2:47: +2:52 _3 = _1; // scope 2 at $DIR/issue_75439.rs:+2:47: +2:52 - _2 = transmute::<[u8; 16], [u32; 4]>(move _3) -> bb1; // scope 2 at $DIR/issue_75439.rs:+2:37: +2:53 - // mir::Constant - // + span: $DIR/issue_75439.rs:8:37: 8:46 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn([u8; 16]) -> [u32; 4] {transmute::<[u8; 16], [u32; 4]>}, val: Value(<ZST>) } + _2 = move _3 as [u32; 4] (Transmute); // scope 2 at $DIR/issue_75439.rs:+2:37: +2:53 + StorageDead(_3); // scope 2 at $DIR/issue_75439.rs:+2:52: +2:53 + switchInt(_2[0 of 4]) -> [0: bb1, otherwise: bb6]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 } bb1: { - StorageDead(_3); // scope 2 at $DIR/issue_75439.rs:+2:52: +2:53 - switchInt(_2[0 of 4]) -> [0: bb2, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 + switchInt(_2[1 of 4]) -> [0: bb2, otherwise: bb6]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 } bb2: { - switchInt(_2[1 of 4]) -> [0: bb3, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 + switchInt(_2[2 of 4]) -> [0: bb4, 4294901760: bb5, otherwise: bb6]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 } bb3: { - switchInt(_2[2 of 4]) -> [0: bb5, 4294901760: bb6, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 - } - - bb4: { StorageLive(_5); // scope 3 at $DIR/issue_75439.rs:+5:14: +5:38 StorageLive(_6); // scope 4 at $DIR/issue_75439.rs:+5:33: +5:35 _6 = _4; // scope 4 at $DIR/issue_75439.rs:+5:33: +5:35 - _5 = transmute::<u32, [u8; 4]>(move _6) -> bb7; // scope 4 at $DIR/issue_75439.rs:+5:23: +5:36 - // mir::Constant - // + span: $DIR/issue_75439.rs:11:23: 11:32 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) -> [u8; 4] {transmute::<u32, [u8; 4]>}, val: Value(<ZST>) } + _5 = move _6 as [u8; 4] (Transmute); // scope 4 at $DIR/issue_75439.rs:+5:23: +5:36 + StorageDead(_6); // scope 4 at $DIR/issue_75439.rs:+5:35: +5:36 + _0 = Option::<[u8; 4]>::Some(move _5); // scope 3 at $DIR/issue_75439.rs:+5:9: +5:39 + StorageDead(_5); // scope 3 at $DIR/issue_75439.rs:+5:38: +5:39 + StorageDead(_4); // scope 1 at $DIR/issue_75439.rs:+6:5: +6:6 + goto -> bb7; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6 } - bb5: { + bb4: { StorageLive(_4); // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29 _4 = _2[3 of 4]; // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29 - goto -> bb4; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 + goto -> bb3; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 } - bb6: { + bb5: { StorageLive(_4); // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29 _4 = _2[3 of 4]; // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29 - goto -> bb4; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 + goto -> bb3; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 } - bb7: { - StorageDead(_6); // scope 4 at $DIR/issue_75439.rs:+5:35: +5:36 - _0 = Option::<[u8; 4]>::Some(move _5); // scope 3 at $DIR/issue_75439.rs:+5:9: +5:39 - StorageDead(_5); // scope 3 at $DIR/issue_75439.rs:+5:38: +5:39 - StorageDead(_4); // scope 1 at $DIR/issue_75439.rs:+6:5: +6:6 - goto -> bb9; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6 - } - - bb8: { + bb6: { _0 = Option::<[u8; 4]>::None; // scope 1 at $DIR/issue_75439.rs:+7:9: +7:13 - goto -> bb9; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6 + goto -> bb7; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6 } - bb9: { + bb7: { StorageDead(_2); // scope 0 at $DIR/issue_75439.rs:+9:1: +9:2 return; // scope 0 at $DIR/issue_75439.rs:+9:2: +9:2 } diff --git a/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff index d9898d8e0f0..5c5a9e90a9d 100644 --- a/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff @@ -11,7 +11,7 @@ StorageLive(_1); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 - _1 = std::intrinsics::assume(const true) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:72:9: 72:32 +- // + span: $DIR/lower_intrinsics.rs:105:9: 105:32 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(bool) {std::intrinsics::assume}, val: Value(<ZST>) } + assume(const true); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 + goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 diff --git a/tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff index d962ef8cb12..87960521bb4 100644 --- a/tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff @@ -31,7 +31,7 @@ _3 = &(*_4); // scope 0 at $DIR/lower_intrinsics.rs:+1:42: +1:44 - _2 = discriminant_value::<T>(move _3) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:49:5: 49:41 +- // + span: $DIR/lower_intrinsics.rs:82:5: 82:41 - // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a T) -> <T as DiscriminantKind>::Discriminant {discriminant_value::<T>}, val: Value(<ZST>) } + _2 = discriminant((*_3)); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45 @@ -46,13 +46,13 @@ StorageLive(_7); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 _19 = const _; // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 // mir::Constant - // + span: $DIR/lower_intrinsics.rs:50:42: 50:44 + // + span: $DIR/lower_intrinsics.rs:83:42: 83:44 // + literal: Const { ty: &i32, val: Unevaluated(discriminant, [T], Some(promoted[2])) } _7 = &(*_19); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 _6 = &(*_7); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 - _5 = discriminant_value::<i32>(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:50:5: 50:41 +- // + span: $DIR/lower_intrinsics.rs:83:5: 83:41 - // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a i32) -> <i32 as DiscriminantKind>::Discriminant {discriminant_value::<i32>}, val: Value(<ZST>) } + _5 = discriminant((*_6)); // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45 + goto -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45 @@ -67,13 +67,13 @@ StorageLive(_11); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 _18 = const _; // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 // mir::Constant - // + span: $DIR/lower_intrinsics.rs:51:42: 51:45 + // + span: $DIR/lower_intrinsics.rs:84:42: 84:45 // + literal: Const { ty: &(), val: Unevaluated(discriminant, [T], Some(promoted[1])) } _11 = &(*_18); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 _10 = &(*_11); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 - _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:51:5: 51:41 +- // + span: $DIR/lower_intrinsics.rs:84:5: 84:41 - // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a ()) -> <() as DiscriminantKind>::Discriminant {discriminant_value::<()>}, val: Value(<ZST>) } + _9 = discriminant((*_10)); // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46 + goto -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46 @@ -88,13 +88,13 @@ StorageLive(_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 _17 = const _; // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 // mir::Constant - // + span: $DIR/lower_intrinsics.rs:52:42: 52:47 + // + span: $DIR/lower_intrinsics.rs:85:42: 85:47 // + literal: Const { ty: &E, val: Unevaluated(discriminant, [T], Some(promoted[0])) } _15 = &(*_17); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 _14 = &(*_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 - _13 = discriminant_value::<E>(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:52:5: 52:41 +- // + span: $DIR/lower_intrinsics.rs:85:5: 85:41 - // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a E) -> <E as DiscriminantKind>::Discriminant {discriminant_value::<E>}, val: Value(<ZST>) } + _13 = discriminant((*_14)); // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48 + goto -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48 diff --git a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff index 5c972a00e46..15cce7f4a2c 100644 --- a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff @@ -49,7 +49,7 @@ StorageDead(_9); // scope 3 at $DIR/lower_intrinsics.rs:+4:90: +4:91 - _3 = copy_nonoverlapping::<i32>(move _4, move _8, const 0_usize) -> bb1; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:65:9: 65:28 +- // + span: $DIR/lower_intrinsics.rs:98:9: 98:28 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32, *mut i32, usize) {copy_nonoverlapping::<i32>}, val: Value(<ZST>) } + copy_nonoverlapping(dst = move _8, src = move _4, count = const 0_usize); // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 + goto -> bb1; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 diff --git a/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff index e535141e772..c563703b250 100644 --- a/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff @@ -24,7 +24,7 @@ _4 = &raw const (*_1); // scope 1 at $DIR/lower_intrinsics.rs:+2:55: +2:56 - _3 = option_payload_ptr::<usize>(move _4) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:99:18: 99:54 +- // + span: $DIR/lower_intrinsics.rs:132:18: 132:54 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Option<usize>) -> *const usize {option_payload_ptr::<usize>}, val: Value(<ZST>) } + _3 = &raw const (((*_4) as Some).0: usize); // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57 + goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57 @@ -37,7 +37,7 @@ _6 = &raw const (*_2); // scope 2 at $DIR/lower_intrinsics.rs:+3:55: +3:56 - _5 = option_payload_ptr::<String>(move _6) -> bb2; // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:100:18: 100:54 +- // + span: $DIR/lower_intrinsics.rs:133:18: 133:54 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Option<String>) -> *const String {option_payload_ptr::<String>}, val: Value(<ZST>) } + _5 = &raw const (((*_6) as Some).0: std::string::String); // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57 + goto -> bb2; // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57 diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff index 27fceeedf6e..f2f676843b2 100644 --- a/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff @@ -13,7 +13,7 @@ _2 = &raw const (*_1); // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47 - _0 = read_via_copy::<i32>(move _2) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:85:14: 85:45 +- // + span: $DIR/lower_intrinsics.rs:118:14: 118:45 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32) -> i32 {read_via_copy::<i32>}, val: Value(<ZST>) } + _0 = (*_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 + goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff index 610c67d2fec..3ad21283fa4 100644 --- a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff @@ -13,7 +13,7 @@ _2 = &raw const (*_1); // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47 - _0 = read_via_copy::<Never>(move _2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:90:14: 90:45 +- // + span: $DIR/lower_intrinsics.rs:123:14: 123:45 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Never) -> Never {read_via_copy::<Never>}, val: Value(<ZST>) } + unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 } diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs index f07e2816f4f..ec215c9a664 100644 --- a/tests/mir-opt/lower_intrinsics.rs +++ b/tests/mir-opt/lower_intrinsics.rs @@ -38,6 +38,39 @@ pub fn non_const<T>() -> usize { size_of_t() } +// EMIT_MIR lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff +pub fn transmute_inhabited(c: std::cmp::Ordering) -> i8 { + unsafe { std::mem::transmute(c) } +} + +// EMIT_MIR lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff +pub unsafe fn transmute_uninhabited(u: ()) -> Never { + unsafe { std::mem::transmute::<(), Never>(u) } +} + +// EMIT_MIR lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff +pub unsafe fn transmute_ref_dst<T: ?Sized>(u: &T) -> *const T { + unsafe { std::mem::transmute(u) } +} + +// EMIT_MIR lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff +pub unsafe fn transmute_to_ref_uninhabited() -> ! { + let x: &Never = std::mem::transmute(1usize); + match *x {} +} + +// EMIT_MIR lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff +pub unsafe fn transmute_to_mut_uninhabited() -> ! { + let x: &mut Never = std::mem::transmute(1usize); + match *x {} +} + +// EMIT_MIR lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff +pub unsafe fn transmute_to_box_uninhabited() -> ! { + let x: Box<Never> = std::mem::transmute(1usize); + match *x {} +} + pub enum E { A, B, diff --git a/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff new file mode 100644 index 00000000000..814368ec021 --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff @@ -0,0 +1,27 @@ +- // MIR for `transmute_inhabited` before LowerIntrinsics ++ // MIR for `transmute_inhabited` after LowerIntrinsics + + fn transmute_inhabited(_1: std::cmp::Ordering) -> i8 { + debug c => _1; // in scope 0 at $DIR/lower_intrinsics.rs:+0:28: +0:29 + let mut _0: i8; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:54: +0:56 + let mut _2: std::cmp::Ordering; // in scope 0 at $DIR/lower_intrinsics.rs:+1:34: +1:35 + scope 1 { + } + + bb0: { + StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35 + _2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35 +- _0 = transmute::<std::cmp::Ordering, i8>(move _2) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:43:14: 43:33 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(std::cmp::Ordering) -> i8 {transmute::<std::cmp::Ordering, i8>}, val: Value(<ZST>) } ++ _0 = move _2 as i8 (Transmute); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36 ++ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36 + } + + bb1: { + StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:35: +1:36 + return; // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2 + } + } + diff --git a/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff new file mode 100644 index 00000000000..5440c7a4c8e --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff @@ -0,0 +1,27 @@ +- // MIR for `transmute_ref_dst` before LowerIntrinsics ++ // MIR for `transmute_ref_dst` after LowerIntrinsics + + fn transmute_ref_dst(_1: &T) -> *const T { + debug u => _1; // in scope 0 at $DIR/lower_intrinsics.rs:+0:44: +0:45 + let mut _0: *const T; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:54: +0:62 + let mut _2: &T; // in scope 0 at $DIR/lower_intrinsics.rs:+1:34: +1:35 + scope 1 { + } + + bb0: { + StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35 + _2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35 +- _0 = transmute::<&T, *const T>(move _2) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:53:14: 53:33 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&T) -> *const T {transmute::<&T, *const T>}, val: Value(<ZST>) } ++ _0 = move _2 as *const T (Transmute); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36 ++ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36 + } + + bb1: { + StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:35: +1:36 + return; // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2 + } + } + diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff new file mode 100644 index 00000000000..43ddccc1ef7 --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff @@ -0,0 +1,29 @@ +- // MIR for `transmute_to_box_uninhabited` before LowerIntrinsics ++ // MIR for `transmute_to_box_uninhabited` after LowerIntrinsics + + fn transmute_to_box_uninhabited() -> ! { + let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:49: +0:50 + let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 + let _2: std::boxed::Box<Never>; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 + let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:16 + scope 1 { + debug x => _2; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10 + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 + StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 +- _2 = transmute::<usize, Box<Never>>(const 1_usize) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:70:25: 70:44 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> Box<Never> {transmute::<usize, Box<Never>>}, val: Value(<ZST>) } ++ _2 = const 1_usize as std::boxed::Box<Never> (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 ++ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 + } + + bb1: { + StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+2:5: +2:16 + unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+2:11: +2:13 + } + } + diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff new file mode 100644 index 00000000000..bf529a9ca67 --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff @@ -0,0 +1,29 @@ +- // MIR for `transmute_to_mut_uninhabited` before LowerIntrinsics ++ // MIR for `transmute_to_mut_uninhabited` after LowerIntrinsics + + fn transmute_to_mut_uninhabited() -> ! { + let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:49: +0:50 + let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 + let _2: &mut Never; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 + let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:16 + scope 1 { + debug x => _2; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10 + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 + StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 +- _2 = transmute::<usize, &mut Never>(const 1_usize) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:64:25: 64:44 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> &mut Never {transmute::<usize, &mut Never>}, val: Value(<ZST>) } ++ _2 = const 1_usize as &mut Never (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 ++ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 + } + + bb1: { + StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+2:5: +2:16 + unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+2:11: +2:13 + } + } + diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff new file mode 100644 index 00000000000..4940a99021f --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff @@ -0,0 +1,29 @@ +- // MIR for `transmute_to_ref_uninhabited` before LowerIntrinsics ++ // MIR for `transmute_to_ref_uninhabited` after LowerIntrinsics + + fn transmute_to_ref_uninhabited() -> ! { + let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:49: +0:50 + let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 + let _2: &Never; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 + let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:16 + scope 1 { + debug x => _2; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10 + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 + StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 +- _2 = transmute::<usize, &Never>(const 1_usize) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:58:21: 58:40 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> &Never {transmute::<usize, &Never>}, val: Value(<ZST>) } ++ _2 = const 1_usize as &Never (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48 ++ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48 + } + + bb1: { + StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+2:5: +2:16 + unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+2:11: +2:13 + } + } + diff --git a/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff new file mode 100644 index 00000000000..f3a12b9ba5f --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff @@ -0,0 +1,22 @@ +- // MIR for `transmute_uninhabited` before LowerIntrinsics ++ // MIR for `transmute_uninhabited` after LowerIntrinsics + + fn transmute_uninhabited(_1: ()) -> Never { + debug u => _1; // in scope 0 at $DIR/lower_intrinsics.rs:+0:37: +0:38 + let mut _0: Never; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:47: +0:52 + let mut _2: (); // in scope 0 at $DIR/lower_intrinsics.rs:+1:47: +1:48 + scope 1 { + } + + bb0: { + StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:47: +1:48 + _2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+1:47: +1:48 +- _0 = transmute::<(), Never>(move _2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:49 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:48:14: 48:46 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Never {transmute::<(), Never>}, val: Value(<ZST>) } ++ _0 = move _2 as Never (Transmute); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:49 ++ unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:49 + } + } + diff --git a/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff index 9870a70dec5..3b9a41249a4 100644 --- a/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff @@ -32,7 +32,7 @@ _5 = _2; // scope 0 at $DIR/lower_intrinsics.rs:+1:53: +1:54 - _3 = add_with_overflow::<i32>(move _4, move _5) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:78:14: 78:49 +- // + span: $DIR/lower_intrinsics.rs:111:14: 111:49 - // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {add_with_overflow::<i32>}, val: Value(<ZST>) } + _3 = CheckedAdd(move _4, move _5); // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55 @@ -48,7 +48,7 @@ _8 = _2; // scope 1 at $DIR/lower_intrinsics.rs:+2:53: +2:54 - _6 = sub_with_overflow::<i32>(move _7, move _8) -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:79:14: 79:49 +- // + span: $DIR/lower_intrinsics.rs:112:14: 112:49 - // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {sub_with_overflow::<i32>}, val: Value(<ZST>) } + _6 = CheckedSub(move _7, move _8); // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55 + goto -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55 @@ -64,7 +64,7 @@ _11 = _2; // scope 2 at $DIR/lower_intrinsics.rs:+3:53: +3:54 - _9 = mul_with_overflow::<i32>(move _10, move _11) -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:80:14: 80:49 +- // + span: $DIR/lower_intrinsics.rs:113:14: 113:49 - // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {mul_with_overflow::<i32>}, val: Value(<ZST>) } + _9 = CheckedMul(move _10, move _11); // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55 + goto -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55 diff --git a/tests/ui/consts/const-eval/panic-assoc-never-type.rs b/tests/ui/consts/const-eval/panic-assoc-never-type.rs index 28edf514402..1abe708d19e 100644 --- a/tests/ui/consts/const-eval/panic-assoc-never-type.rs +++ b/tests/ui/consts/const-eval/panic-assoc-never-type.rs @@ -11,5 +11,5 @@ impl PrintName { } fn main() { - let _ = PrintName::VOID; //~ constant + let _ = PrintName::VOID; //~ erroneous constant used } diff --git a/tests/ui/consts/const-eval/transmute-size-mismatch.rs b/tests/ui/consts/const-eval/transmute-size-mismatch.rs new file mode 100644 index 00000000000..2410baea28c --- /dev/null +++ b/tests/ui/consts/const-eval/transmute-size-mismatch.rs @@ -0,0 +1,24 @@ +#![feature(core_intrinsics)] +#![feature(custom_mir)] + +// These cases are statically rejected by `mem::transmute`, so we need custom +// MIR to be able to get to constant evaluation. +use std::intrinsics::mir::*; + +#[custom_mir(dialect = "runtime", phase = "initial")] +const unsafe fn mir_transmute<T, U>(x: T) -> U { + mir!{ + { + RET = CastTransmute(x); + //~^ ERROR evaluation of constant value failed + //~| ERROR evaluation of constant value failed + Return() + } + } +} + +const FROM_BIGGER: u16 = unsafe { mir_transmute(123_i32) }; + +const FROM_SMALLER: u32 = unsafe { mir_transmute(123_i16) }; + +fn main() {} diff --git a/tests/ui/consts/const-eval/transmute-size-mismatch.stderr b/tests/ui/consts/const-eval/transmute-size-mismatch.stderr new file mode 100644 index 00000000000..e051491d343 --- /dev/null +++ b/tests/ui/consts/const-eval/transmute-size-mismatch.stderr @@ -0,0 +1,37 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/transmute-size-mismatch.rs:12:13 + | +LL | RET = CastTransmute(x); + | ^^^^^^^^^^^^^^^^^^^^^^ transmuting from 4-byte type to 2-byte type: `i32` -> `u16` + | +note: inside `mir_transmute::<i32, u16>` + --> $DIR/transmute-size-mismatch.rs:12:13 + | +LL | RET = CastTransmute(x); + | ^^^^^^^^^^^^^^^^^^^^^^ +note: inside `FROM_BIGGER` + --> $DIR/transmute-size-mismatch.rs:20:35 + | +LL | const FROM_BIGGER: u16 = unsafe { mir_transmute(123_i32) }; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $DIR/transmute-size-mismatch.rs:12:13 + | +LL | RET = CastTransmute(x); + | ^^^^^^^^^^^^^^^^^^^^^^ transmuting from 2-byte type to 4-byte type: `i16` -> `u32` + | +note: inside `mir_transmute::<i16, u32>` + --> $DIR/transmute-size-mismatch.rs:12:13 + | +LL | RET = CastTransmute(x); + | ^^^^^^^^^^^^^^^^^^^^^^ +note: inside `FROM_SMALLER` + --> $DIR/transmute-size-mismatch.rs:22:36 + | +LL | const FROM_SMALLER: u32 = unsafe { mir_transmute(123_i16) }; + | ^^^^^^^^^^^^^^^^^^^^^^ + +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/ub-enum.32bit.stderr b/tests/ui/consts/const-eval/ub-enum.32bit.stderr index 2d86bd88f1c..3ad1ac974c8 100644 --- a/tests/ui/consts/const-eval/ub-enum.32bit.stderr +++ b/tests/ui/consts/const-eval/ub-enum.32bit.stderr @@ -108,13 +108,13 @@ 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 + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never 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 + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!` error: aborting due to 13 previous errors diff --git a/tests/ui/consts/const-eval/ub-enum.64bit.stderr b/tests/ui/consts/const-eval/ub-enum.64bit.stderr index a89d7ec5f6d..a66706d1af9 100644 --- a/tests/ui/consts/const-eval/ub-enum.64bit.stderr +++ b/tests/ui/consts/const-eval/ub-enum.64bit.stderr @@ -108,13 +108,13 @@ 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 + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never 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 + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!` error: aborting due to 13 previous errors diff --git a/tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr b/tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr index 231005d7e39..74bc6317c80 100644 --- a/tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr +++ b/tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr @@ -11,7 +11,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/validate_uninhabited_zsts.rs:4:14 | LL | unsafe { std::mem::transmute(()) } - | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of the never type `!` | note: inside `foo` --> $DIR/validate_uninhabited_zsts.rs:4:14 diff --git a/tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr b/tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr index 231005d7e39..74bc6317c80 100644 --- a/tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr +++ b/tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr @@ -11,7 +11,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/validate_uninhabited_zsts.rs:4:14 | LL | unsafe { std::mem::transmute(()) } - | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of the never type `!` | note: inside `foo` --> $DIR/validate_uninhabited_zsts.rs:4:14 diff --git a/tests/ui/statics/uninhabited-static.stderr b/tests/ui/statics/uninhabited-static.stderr index 437053a4476..35fdcae6a59 100644 --- a/tests/ui/statics/uninhabited-static.stderr +++ b/tests/ui/statics/uninhabited-static.stderr @@ -47,7 +47,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/uninhabited-static.rs:12:31 | LL | static VOID2: Void = unsafe { std::mem::transmute(()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Void warning: the type `Void` does not permit zero-initialization --> $DIR/uninhabited-static.rs:12:31 @@ -66,7 +66,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/uninhabited-static.rs:16:32 | LL | static NEVER2: Void = unsafe { std::mem::transmute(()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Void warning: the type `Void` does not permit zero-initialization --> $DIR/uninhabited-static.rs:16:32 |
