Support a few more rvalues.

This commit is contained in:
Camille GILLOT 2023-04-15 16:41:57 +00:00
parent 7ef555d84a
commit 74a967bcec
28 changed files with 835 additions and 33 deletions

View File

@ -226,6 +226,11 @@ impl ScalarInt {
}
}
#[inline]
pub fn try_from_target_usize(i: impl Into<u128>, tcx: TyCtxt<'_>) -> Option<Self> {
Self::try_from_uint(i, tcx.data_layout.pointer_size)
}
#[inline]
pub fn assert_bits(self, target_size: Size) -> u128 {
self.to_bits(target_size).unwrap_or_else(|size| {

View File

@ -193,47 +193,64 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
rvalue: &Rvalue<'tcx>,
state: &mut State<Self::Value>,
) -> ValueOrPlace<Self::Value> {
match rvalue {
Rvalue::Cast(
kind @ (CastKind::IntToInt
| CastKind::FloatToInt
| CastKind::FloatToFloat
| CastKind::IntToFloat),
operand,
ty,
) => match self.eval_operand(operand, state) {
FlatSet::Elem(op) => match kind {
CastKind::IntToInt | CastKind::IntToFloat => {
self.ecx.int_to_int_or_float(&op, *ty)
}
CastKind::FloatToInt | CastKind::FloatToFloat => {
self.ecx.float_to_float_or_int(&op, *ty)
}
_ => unreachable!(),
let val = match rvalue {
Rvalue::Cast(CastKind::IntToInt | CastKind::IntToFloat, operand, ty) => {
match self.eval_operand(operand, state) {
FlatSet::Elem(op) => self
.ecx
.int_to_int_or_float(&op, *ty)
.map_or(FlatSet::Top, |result| self.wrap_immediate(result)),
FlatSet::Bottom => FlatSet::Bottom,
FlatSet::Top => FlatSet::Top,
}
.map(|result| ValueOrPlace::Value(self.wrap_immediate(result)))
.unwrap_or(ValueOrPlace::TOP),
_ => ValueOrPlace::TOP,
},
}
Rvalue::Cast(CastKind::FloatToInt | CastKind::FloatToFloat, operand, ty) => {
match self.eval_operand(operand, state) {
FlatSet::Elem(op) => self
.ecx
.float_to_float_or_int(&op, *ty)
.map_or(FlatSet::Top, |result| self.wrap_immediate(result)),
FlatSet::Bottom => FlatSet::Bottom,
FlatSet::Top => FlatSet::Top,
}
}
Rvalue::Cast(CastKind::Transmute, operand, _) => {
match self.eval_operand(operand, state) {
FlatSet::Elem(op) => self.wrap_immediate(*op),
FlatSet::Bottom => FlatSet::Bottom,
FlatSet::Top => FlatSet::Top,
}
}
Rvalue::BinaryOp(op, box (left, right)) => {
// Overflows must be ignored here.
let (val, _overflow) = self.binary_op(state, *op, left, right);
ValueOrPlace::Value(val)
val
}
Rvalue::UnaryOp(op, operand) => match self.eval_operand(operand, state) {
FlatSet::Elem(value) => self
.ecx
.unary_op(*op, &value)
.map(|val| ValueOrPlace::Value(self.wrap_immty(val)))
.unwrap_or(ValueOrPlace::Value(FlatSet::Top)),
FlatSet::Bottom => ValueOrPlace::Value(FlatSet::Bottom),
FlatSet::Top => ValueOrPlace::Value(FlatSet::Top),
FlatSet::Elem(value) => {
self.ecx.unary_op(*op, &value).map_or(FlatSet::Top, |val| self.wrap_immty(val))
}
FlatSet::Bottom => FlatSet::Bottom,
FlatSet::Top => FlatSet::Top,
},
Rvalue::Discriminant(place) => {
ValueOrPlace::Value(state.get_discr(place.as_ref(), self.map()))
Rvalue::NullaryOp(null_op, ty) => {
let Ok(layout) = self.tcx.layout_of(self.param_env.and(*ty)) else {
return ValueOrPlace::Value(FlatSet::Top);
};
let val = match null_op {
NullOp::SizeOf if layout.is_sized() => layout.size.bytes(),
NullOp::AlignOf if layout.is_sized() => layout.align.abi.bytes(),
NullOp::OffsetOf(fields) => layout
.offset_of_subfield(&self.ecx, fields.iter().map(|f| f.index()))
.bytes(),
_ => return ValueOrPlace::Value(FlatSet::Top),
};
ScalarInt::try_from_target_usize(val, self.tcx).map_or(FlatSet::Top, FlatSet::Elem)
}
_ => self.super_rvalue(rvalue, state),
}
Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), self.map()),
_ => return self.super_rvalue(rvalue, state),
};
ValueOrPlace::Value(val)
}
fn handle_constant(

View File

@ -0,0 +1,76 @@
- // MIR for `concrete` before DataflowConstProp
+ // MIR for `concrete` after DataflowConstProp
fn concrete() -> () {
let mut _0: ();
let _1: usize;
let mut _2: usize;
let mut _4: usize;
let mut _6: usize;
let mut _8: usize;
scope 1 {
debug x => _1;
let _3: usize;
scope 2 {
debug y => _3;
let _5: usize;
scope 3 {
debug z0 => _5;
let _7: usize;
scope 4 {
debug z1 => _7;
}
}
}
}
bb0: {
StorageLive(_1);
StorageLive(_2);
- _2 = OffsetOf(Alpha, [0]);
- _1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable];
+ _2 = const 4_usize;
+ _1 = must_use::<usize>(const 4_usize) -> [return: bb1, unwind unreachable];
}
bb1: {
StorageDead(_2);
StorageLive(_3);
StorageLive(_4);
- _4 = OffsetOf(Alpha, [1]);
- _3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable];
+ _4 = const 0_usize;
+ _3 = must_use::<usize>(const 0_usize) -> [return: bb2, unwind unreachable];
}
bb2: {
StorageDead(_4);
StorageLive(_5);
StorageLive(_6);
- _6 = OffsetOf(Alpha, [2, 0]);
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
+ _6 = const 2_usize;
+ _5 = must_use::<usize>(const 2_usize) -> [return: bb3, unwind unreachable];
}
bb3: {
StorageDead(_6);
StorageLive(_7);
StorageLive(_8);
- _8 = OffsetOf(Alpha, [2, 1]);
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
+ _8 = const 3_usize;
+ _7 = must_use::<usize>(const 3_usize) -> [return: bb4, unwind unreachable];
}
bb4: {
StorageDead(_8);
_0 = const ();
StorageDead(_7);
StorageDead(_5);
StorageDead(_3);
StorageDead(_1);
return;
}
}

View File

@ -0,0 +1,76 @@
- // MIR for `concrete` before DataflowConstProp
+ // MIR for `concrete` after DataflowConstProp
fn concrete() -> () {
let mut _0: ();
let _1: usize;
let mut _2: usize;
let mut _4: usize;
let mut _6: usize;
let mut _8: usize;
scope 1 {
debug x => _1;
let _3: usize;
scope 2 {
debug y => _3;
let _5: usize;
scope 3 {
debug z0 => _5;
let _7: usize;
scope 4 {
debug z1 => _7;
}
}
}
}
bb0: {
StorageLive(_1);
StorageLive(_2);
- _2 = OffsetOf(Alpha, [0]);
- _1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue];
+ _2 = const 4_usize;
+ _1 = must_use::<usize>(const 4_usize) -> [return: bb1, unwind continue];
}
bb1: {
StorageDead(_2);
StorageLive(_3);
StorageLive(_4);
- _4 = OffsetOf(Alpha, [1]);
- _3 = must_use::<usize>(move _4) -> [return: bb2, unwind continue];
+ _4 = const 0_usize;
+ _3 = must_use::<usize>(const 0_usize) -> [return: bb2, unwind continue];
}
bb2: {
StorageDead(_4);
StorageLive(_5);
StorageLive(_6);
- _6 = OffsetOf(Alpha, [2, 0]);
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue];
+ _6 = const 2_usize;
+ _5 = must_use::<usize>(const 2_usize) -> [return: bb3, unwind continue];
}
bb3: {
StorageDead(_6);
StorageLive(_7);
StorageLive(_8);
- _8 = OffsetOf(Alpha, [2, 1]);
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue];
+ _8 = const 3_usize;
+ _7 = must_use::<usize>(const 3_usize) -> [return: bb4, unwind continue];
}
bb4: {
StorageDead(_8);
_0 = const ();
StorageDead(_7);
StorageDead(_5);
StorageDead(_3);
StorageDead(_1);
return;
}
}

View File

@ -0,0 +1,72 @@
- // MIR for `generic` before DataflowConstProp
+ // MIR for `generic` after DataflowConstProp
fn generic() -> () {
let mut _0: ();
let _1: usize;
let mut _2: usize;
let mut _4: usize;
let mut _6: usize;
let mut _8: usize;
scope 1 {
debug gx => _1;
let _3: usize;
scope 2 {
debug gy => _3;
let _5: usize;
scope 3 {
debug dx => _5;
let _7: usize;
scope 4 {
debug dy => _7;
}
}
}
}
bb0: {
StorageLive(_1);
StorageLive(_2);
_2 = OffsetOf(Gamma<T>, [0]);
_1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable];
}
bb1: {
StorageDead(_2);
StorageLive(_3);
StorageLive(_4);
_4 = OffsetOf(Gamma<T>, [1]);
_3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable];
}
bb2: {
StorageDead(_4);
StorageLive(_5);
StorageLive(_6);
- _6 = OffsetOf(Delta<T>, [1]);
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
+ _6 = const 0_usize;
+ _5 = must_use::<usize>(const 0_usize) -> [return: bb3, unwind unreachable];
}
bb3: {
StorageDead(_6);
StorageLive(_7);
StorageLive(_8);
- _8 = OffsetOf(Delta<T>, [2]);
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
+ _8 = const 2_usize;
+ _7 = must_use::<usize>(const 2_usize) -> [return: bb4, unwind unreachable];
}
bb4: {
StorageDead(_8);
_0 = const ();
StorageDead(_7);
StorageDead(_5);
StorageDead(_3);
StorageDead(_1);
return;
}
}

View File

@ -0,0 +1,72 @@
- // MIR for `generic` before DataflowConstProp
+ // MIR for `generic` after DataflowConstProp
fn generic() -> () {
let mut _0: ();
let _1: usize;
let mut _2: usize;
let mut _4: usize;
let mut _6: usize;
let mut _8: usize;
scope 1 {
debug gx => _1;
let _3: usize;
scope 2 {
debug gy => _3;
let _5: usize;
scope 3 {
debug dx => _5;
let _7: usize;
scope 4 {
debug dy => _7;
}
}
}
}
bb0: {
StorageLive(_1);
StorageLive(_2);
_2 = OffsetOf(Gamma<T>, [0]);
_1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue];
}
bb1: {
StorageDead(_2);
StorageLive(_3);
StorageLive(_4);
_4 = OffsetOf(Gamma<T>, [1]);
_3 = must_use::<usize>(move _4) -> [return: bb2, unwind continue];
}
bb2: {
StorageDead(_4);
StorageLive(_5);
StorageLive(_6);
- _6 = OffsetOf(Delta<T>, [1]);
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue];
+ _6 = const 0_usize;
+ _5 = must_use::<usize>(const 0_usize) -> [return: bb3, unwind continue];
}
bb3: {
StorageDead(_6);
StorageLive(_7);
StorageLive(_8);
- _8 = OffsetOf(Delta<T>, [2]);
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue];
+ _8 = const 2_usize;
+ _7 = must_use::<usize>(const 2_usize) -> [return: bb4, unwind continue];
}
bb4: {
StorageDead(_8);
_0 = const ();
StorageDead(_7);
StorageDead(_5);
StorageDead(_3);
StorageDead(_1);
return;
}
}

View File

@ -0,0 +1,49 @@
// unit-test: DataflowConstProp
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
#![feature(offset_of)]
use std::marker::PhantomData;
use std::mem::offset_of;
struct Alpha {
x: u8,
y: u16,
z: Beta,
}
struct Beta(u8, u8);
struct Gamma<T> {
x: u8,
y: u16,
_t: T,
}
#[repr(C)]
struct Delta<T> {
_phantom: PhantomData<T>,
x: u8,
y: u16,
}
// EMIT_MIR offset_of.concrete.DataflowConstProp.diff
fn concrete() {
let x = offset_of!(Alpha, x);
let y = offset_of!(Alpha, y);
let z0 = offset_of!(Alpha, z.0);
let z1 = offset_of!(Alpha, z.1);
}
// EMIT_MIR offset_of.generic.DataflowConstProp.diff
fn generic<T>() {
let gx = offset_of!(Gamma<T>, x);
let gy = offset_of!(Gamma<T>, y);
let dx = offset_of!(Delta<T>, x);
let dy = offset_of!(Delta<T>, y);
}
fn main() {
concrete();
generic::<()>();
}

View File

@ -0,0 +1,15 @@
- // MIR for `from_char` before DataflowConstProp
+ // MIR for `from_char` after DataflowConstProp
fn from_char() -> i32 {
let mut _0: i32;
scope 1 {
}
bb0: {
- _0 = const 'R' as i32 (Transmute);
+ _0 = const 82_i32;
return;
}
}

View File

@ -0,0 +1,15 @@
- // MIR for `from_char` before DataflowConstProp
+ // MIR for `from_char` after DataflowConstProp
fn from_char() -> i32 {
let mut _0: i32;
scope 1 {
}
bb0: {
- _0 = const 'R' as i32 (Transmute);
+ _0 = const 82_i32;
return;
}
}

View File

@ -0,0 +1,15 @@
- // MIR for `invalid_bool` before DataflowConstProp
+ // MIR for `invalid_bool` after DataflowConstProp
fn invalid_bool() -> bool {
let mut _0: bool;
scope 1 {
}
bb0: {
- _0 = const -1_i8 as bool (Transmute);
+ _0 = const {transmute(0xff): bool};
return;
}
}

View File

@ -0,0 +1,15 @@
- // MIR for `invalid_bool` before DataflowConstProp
+ // MIR for `invalid_bool` after DataflowConstProp
fn invalid_bool() -> bool {
let mut _0: bool;
scope 1 {
}
bb0: {
- _0 = const -1_i8 as bool (Transmute);
+ _0 = const {transmute(0xff): bool};
return;
}
}

View File

@ -0,0 +1,15 @@
- // MIR for `invalid_char` before DataflowConstProp
+ // MIR for `invalid_char` after DataflowConstProp
fn invalid_char() -> char {
let mut _0: char;
scope 1 {
}
bb0: {
- _0 = const _ as char (Transmute);
+ _0 = const {transmute(0x7fffffff): char};
return;
}
}

View File

@ -0,0 +1,15 @@
- // MIR for `invalid_char` before DataflowConstProp
+ // MIR for `invalid_char` after DataflowConstProp
fn invalid_char() -> char {
let mut _0: char;
scope 1 {
}
bb0: {
- _0 = const _ as char (Transmute);
+ _0 = const {transmute(0x7fffffff): char};
return;
}
}

View File

@ -0,0 +1,18 @@
- // MIR for `less_as_i8` before DataflowConstProp
+ // MIR for `less_as_i8` after DataflowConstProp
fn less_as_i8() -> i8 {
let mut _0: i8;
let mut _1: std::cmp::Ordering;
scope 1 {
}
bb0: {
StorageLive(_1);
_1 = Less;
_0 = move _1 as i8 (Transmute);
StorageDead(_1);
return;
}
}

View File

@ -0,0 +1,18 @@
- // MIR for `less_as_i8` before DataflowConstProp
+ // MIR for `less_as_i8` after DataflowConstProp
fn less_as_i8() -> i8 {
let mut _0: i8;
let mut _1: std::cmp::Ordering;
scope 1 {
}
bb0: {
StorageLive(_1);
_1 = Less;
_0 = move _1 as i8 (Transmute);
StorageDead(_1);
return;
}
}

View File

@ -0,0 +1,63 @@
// unit-test: DataflowConstProp
// compile-flags: -O --crate-type=lib
// ignore-endian-big
// EMIT_MIR_FOR_EACH_BIT_WIDTH
use std::mem::transmute;
// EMIT_MIR transmute.less_as_i8.DataflowConstProp.diff
pub fn less_as_i8() -> i8 {
unsafe { transmute(std::cmp::Ordering::Less) }
}
// EMIT_MIR transmute.from_char.DataflowConstProp.diff
pub fn from_char() -> i32 {
unsafe { transmute('R') }
}
// EMIT_MIR transmute.valid_char.DataflowConstProp.diff
pub fn valid_char() -> char {
unsafe { transmute(0x52_u32) }
}
// EMIT_MIR transmute.invalid_char.DataflowConstProp.diff
pub unsafe fn invalid_char() -> char {
unsafe { transmute(i32::MAX) }
}
// EMIT_MIR transmute.invalid_bool.DataflowConstProp.diff
pub unsafe fn invalid_bool() -> bool {
unsafe { transmute(-1_i8) }
}
// EMIT_MIR transmute.undef_union_as_integer.DataflowConstProp.diff
pub unsafe fn undef_union_as_integer() -> u32 {
union Union32 { value: u32, unit: () }
unsafe { transmute(Union32 { unit: () }) }
}
// EMIT_MIR transmute.unreachable_direct.DataflowConstProp.diff
pub unsafe fn unreachable_direct() -> ! {
let x: Never = unsafe { transmute(()) };
match x {}
}
// EMIT_MIR transmute.unreachable_ref.DataflowConstProp.diff
pub unsafe fn unreachable_ref() -> ! {
let x: &Never = unsafe { transmute(1_usize) };
match *x {}
}
// EMIT_MIR transmute.unreachable_mut.DataflowConstProp.diff
pub unsafe fn unreachable_mut() -> ! {
let x: &mut Never = unsafe { transmute(1_usize) };
match *x {}
}
// EMIT_MIR transmute.unreachable_box.DataflowConstProp.diff
pub unsafe fn unreachable_box() -> ! {
let x: Box<Never> = unsafe { transmute(1_usize) };
match *x {}
}
enum Never {}

View File

@ -0,0 +1,22 @@
- // MIR for `undef_union_as_integer` before DataflowConstProp
+ // MIR for `undef_union_as_integer` after DataflowConstProp
fn undef_union_as_integer() -> u32 {
let mut _0: u32;
let mut _1: undef_union_as_integer::Union32;
let mut _2: ();
scope 1 {
}
bb0: {
StorageLive(_1);
StorageLive(_2);
_2 = ();
_1 = Union32 { value: move _2 };
StorageDead(_2);
_0 = move _1 as u32 (Transmute);
StorageDead(_1);
return;
}
}

View File

@ -0,0 +1,22 @@
- // MIR for `undef_union_as_integer` before DataflowConstProp
+ // MIR for `undef_union_as_integer` after DataflowConstProp
fn undef_union_as_integer() -> u32 {
let mut _0: u32;
let mut _1: undef_union_as_integer::Union32;
let mut _2: ();
scope 1 {
}
bb0: {
StorageLive(_1);
StorageLive(_2);
_2 = ();
_1 = Union32 { value: move _2 };
StorageDead(_2);
_0 = move _1 as u32 (Transmute);
StorageDead(_1);
return;
}
}

View File

@ -0,0 +1,20 @@
- // MIR for `unreachable_box` before DataflowConstProp
+ // MIR for `unreachable_box` after DataflowConstProp
fn unreachable_box() -> ! {
let mut _0: !;
let _1: std::boxed::Box<Never>;
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);
- _1 = const 1_usize as std::boxed::Box<Never> (Transmute);
+ _1 = const Box::<Never>(Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global);
unreachable;
}
}

View File

@ -0,0 +1,20 @@
- // MIR for `unreachable_box` before DataflowConstProp
+ // MIR for `unreachable_box` after DataflowConstProp
fn unreachable_box() -> ! {
let mut _0: !;
let _1: std::boxed::Box<Never>;
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);
- _1 = const 1_usize as std::boxed::Box<Never> (Transmute);
+ _1 = const Box::<Never>(Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global);
unreachable;
}
}

View File

@ -0,0 +1,22 @@
- // MIR for `unreachable_direct` before DataflowConstProp
+ // MIR for `unreachable_direct` after DataflowConstProp
fn unreachable_direct() -> ! {
let mut _0: !;
let _1: Never;
let mut _2: ();
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);
StorageLive(_2);
_2 = ();
_1 = move _2 as Never (Transmute);
unreachable;
}
}

View File

@ -0,0 +1,22 @@
- // MIR for `unreachable_direct` before DataflowConstProp
+ // MIR for `unreachable_direct` after DataflowConstProp
fn unreachable_direct() -> ! {
let mut _0: !;
let _1: Never;
let mut _2: ();
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);
StorageLive(_2);
_2 = ();
_1 = move _2 as Never (Transmute);
unreachable;
}
}

View File

@ -0,0 +1,24 @@
- // MIR for `unreachable_mut` before DataflowConstProp
+ // MIR for `unreachable_mut` after DataflowConstProp
fn unreachable_mut() -> ! {
let mut _0: !;
let _1: &mut Never;
let mut _2: &mut Never;
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);
StorageLive(_2);
- _2 = const 1_usize as &mut Never (Transmute);
+ _2 = const {0x1 as &mut Never};
_1 = &mut (*_2);
StorageDead(_2);
unreachable;
}
}

View File

@ -0,0 +1,24 @@
- // MIR for `unreachable_mut` before DataflowConstProp
+ // MIR for `unreachable_mut` after DataflowConstProp
fn unreachable_mut() -> ! {
let mut _0: !;
let _1: &mut Never;
let mut _2: &mut Never;
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);
StorageLive(_2);
- _2 = const 1_usize as &mut Never (Transmute);
+ _2 = const {0x1 as &mut Never};
_1 = &mut (*_2);
StorageDead(_2);
unreachable;
}
}

View File

@ -0,0 +1,20 @@
- // MIR for `unreachable_ref` before DataflowConstProp
+ // MIR for `unreachable_ref` after DataflowConstProp
fn unreachable_ref() -> ! {
let mut _0: !;
let _1: &Never;
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);
- _1 = const 1_usize as &Never (Transmute);
+ _1 = const {0x1 as &Never};
unreachable;
}
}

View File

@ -0,0 +1,20 @@
- // MIR for `unreachable_ref` before DataflowConstProp
+ // MIR for `unreachable_ref` after DataflowConstProp
fn unreachable_ref() -> ! {
let mut _0: !;
let _1: &Never;
scope 1 {
debug x => _1;
}
scope 2 {
}
bb0: {
StorageLive(_1);
- _1 = const 1_usize as &Never (Transmute);
+ _1 = const {0x1 as &Never};
unreachable;
}
}

View File

@ -0,0 +1,15 @@
- // MIR for `valid_char` before DataflowConstProp
+ // MIR for `valid_char` after DataflowConstProp
fn valid_char() -> char {
let mut _0: char;
scope 1 {
}
bb0: {
- _0 = const 82_u32 as char (Transmute);
+ _0 = const 'R';
return;
}
}

View File

@ -0,0 +1,15 @@
- // MIR for `valid_char` before DataflowConstProp
+ // MIR for `valid_char` after DataflowConstProp
fn valid_char() -> char {
let mut _0: char;
scope 1 {
}
bb0: {
- _0 = const 82_u32 as char (Transmute);
+ _0 = const 'R';
return;
}
}