Fix pretty printing of enums without variants

92d20c4aad removed no-variants special
case from try_destructure_const with expectation that this case would be
handled gracefully when read_discriminant returns an error.

Alas in that case read_discriminant succeeds while returning a
non-existing variant, so the special case is still necessary.
This commit is contained in:
Tomasz Miąsko 2022-02-17 00:00:00 +00:00
parent e08d569360
commit c2da477853
3 changed files with 75 additions and 65 deletions

View File

@ -147,6 +147,10 @@ pub(crate) fn try_destructure_const<'tcx>(
// We go to `usize` as we cannot allocate anything bigger anyway. // We go to `usize` as we cannot allocate anything bigger anyway.
let (field_count, variant, down) = match val.ty().kind() { let (field_count, variant, down) = match val.ty().kind() {
ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op), ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op),
// Checks if we have any variants, to avoid downcasting to a non-existing variant (when
// there are no variants `read_discriminant` successfully returns a non-existing variant
// index).
ty::Adt(def, _) if def.variants.is_empty() => throw_ub!(Unreachable),
ty::Adt(def, _) => { ty::Adt(def, _) => {
let variant = ecx.read_discriminant(&op)?.1; let variant = ecx.read_discriminant(&op)?.1;
let down = ecx.operand_downcast(&op, variant)?; let down = ecx.operand_downcast(&op, variant)?;

View File

@ -2,68 +2,63 @@
+ // MIR for `main` after ConstProp + // MIR for `main` after ConstProp
fn main() -> () { fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/invalid_constant.rs:15:11: 15:11 let mut _0: (); // return place in scope 0 at $DIR/invalid_constant.rs:13:11: 13:11
let _1: std::option::Option<()>; // in scope 0 at $DIR/invalid_constant.rs:16:5: 16:12 let _1: main::InvalidChar; // in scope 0 at $DIR/invalid_constant.rs:19:9: 19:22
let mut _2: std::option::Option<std::option::Option<()>>; // in scope 0 at $DIR/invalid_constant.rs:16:7: 16:11 let mut _3: main::InvalidTag; // in scope 0 at $DIR/invalid_constant.rs:26:25: 26:46
let _3: main::Union; // in scope 0 at $DIR/invalid_constant.rs:22:9: 22:22 let mut _5: main::NoVariants; // in scope 0 at $DIR/invalid_constant.rs:33:35: 33:56
scope 1 { scope 1 {
debug _invalid_char => _3; // in scope 1 at $DIR/invalid_constant.rs:22:9: 22:22 debug _invalid_char => _1; // in scope 1 at $DIR/invalid_constant.rs:19:9: 19:22
} let _2: [main::InvalidTag; 1]; // in scope 1 at $DIR/invalid_constant.rs:26:9: 26:21
scope 2 (inlined f) { // at $DIR/invalid_constant.rs:16:5: 16:12 scope 2 {
debug x => _2; // in scope 2 at $DIR/invalid_constant.rs:16:5: 16:12 debug _invalid_tag => _2; // in scope 2 at $DIR/invalid_constant.rs:26:9: 26:21
let mut _4: isize; // in scope 2 at $DIR/invalid_constant.rs:16:5: 16:12 let _4: [main::NoVariants; 1]; // in scope 2 at $DIR/invalid_constant.rs:33:9: 33:31
let _5: std::option::Option<()>; // in scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
scope 3 { scope 3 {
debug y => _5; // in scope 3 at $DIR/invalid_constant.rs:16:5: 16:12 debug _enum_without_variants => _4; // in scope 3 at $DIR/invalid_constant.rs:33:9: 33:31
}
} }
} }
bb0: { bb0: {
discriminant(_2) = 0; // scope 0 at $DIR/invalid_constant.rs:16:7: 16:11 StorageLive(_1); // scope 0 at $DIR/invalid_constant.rs:19:9: 19:22
- _4 = discriminant(_2); // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12 - _1 = const { InvalidChar { int: 0x110001 } }; // scope 0 at $DIR/invalid_constant.rs:19:25: 19:64
- switchInt(move _4) -> [0_isize: bb3, otherwise: bb2]; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12 + _1 = const InvalidChar { int: 1114113_u32, chr: {transmute(0x00110001): char} }; // scope 0 at $DIR/invalid_constant.rs:19:25: 19:64
+ _4 = const 0_isize; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
+ switchInt(const 0_isize) -> [0_isize: bb3, otherwise: bb2]; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
}
bb1: {
- _3 = const { Union { int: 0x110001 } }; // scope 0 at $DIR/invalid_constant.rs:22:25: 22:58
+ _3 = const main::Union { int: 1114113_u32, chr: {transmute(0x00110001): char} }; // scope 0 at $DIR/invalid_constant.rs:22:25: 22:58
// ty::Const // ty::Const
// + ty: main::Union // + ty: main::InvalidChar
- // + val: Unevaluated(main::{constant#0}, [main::Union], None) - // + val: Unevaluated(main::{constant#0}, [main::InvalidChar], None)
+ // + val: Value(Scalar(0x00110001)) + // + val: Value(Scalar(0x00110001))
// mir::Constant // mir::Constant
// + span: $DIR/invalid_constant.rs:22:25: 22:58 // + span: $DIR/invalid_constant.rs:19:25: 19:64
- // + literal: Const { ty: main::Union, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:8 ~ invalid_constant[726d]::main::{constant#0}), const_param_did: None }, substs: [main::Union], promoted: None }) } - // + literal: Const { ty: main::InvalidChar, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:7 ~ invalid_constant[726d]::main::{constant#0}), const_param_did: None }, substs: [main::InvalidChar], promoted: None }) }
+ // + literal: Const { ty: main::Union, val: Value(Scalar(0x00110001)) } + // + literal: Const { ty: main::InvalidChar, val: Value(Scalar(0x00110001)) }
nop; // scope 0 at $DIR/invalid_constant.rs:15:11: 23:2 StorageLive(_2); // scope 1 at $DIR/invalid_constant.rs:26:9: 26:21
return; // scope 0 at $DIR/invalid_constant.rs:23:2: 23:2 StorageLive(_3); // scope 1 at $DIR/invalid_constant.rs:26:25: 26:46
} (_3.0: u32) = const 4_u32; // scope 1 at $DIR/invalid_constant.rs:26:25: 26:46
- _2 = [move _3]; // scope 1 at $DIR/invalid_constant.rs:26:24: 26:47
bb2: { + _2 = [const InvalidTag { int: 4_u32, e: Scalar(0x00000004): E }]; // scope 1 at $DIR/invalid_constant.rs:26:24: 26:47
- _5 = ((_2 as Some).0: std::option::Option<()>); // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
- _1 = _5; // scope 3 at $DIR/invalid_constant.rs:16:5: 16:12
+ _5 = const Scalar(0x02): Option::<()>; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
+ // ty::Const + // ty::Const
+ // + ty: std::option::Option<()> + // + ty: main::InvalidTag
+ // + val: Value(Scalar(0x02)) + // + val: Value(Scalar(0x00000004))
+ // mir::Constant + // mir::Constant
+ // + span: $DIR/invalid_constant.rs:16:5: 16:12 + // + span: $DIR/invalid_constant.rs:26:24: 26:47
+ // + literal: Const { ty: std::option::Option<()>, val: Value(Scalar(0x02)) } + // + literal: Const { ty: main::InvalidTag, val: Value(Scalar(0x00000004)) }
+ _1 = const Scalar(0x02): Option::<()>; // scope 3 at $DIR/invalid_constant.rs:16:5: 16:12 StorageDead(_3); // scope 1 at $DIR/invalid_constant.rs:26:46: 26:47
StorageLive(_4); // scope 2 at $DIR/invalid_constant.rs:33:9: 33:31
StorageLive(_5); // scope 2 at $DIR/invalid_constant.rs:33:35: 33:56
(_5.0: u32) = const 0_u32; // scope 2 at $DIR/invalid_constant.rs:33:35: 33:56
- _4 = [move _5]; // scope 2 at $DIR/invalid_constant.rs:33:34: 33:57
+ _4 = [const NoVariants { int: 0_u32, empty: Scalar(<ZST>): Empty }]; // scope 2 at $DIR/invalid_constant.rs:33:34: 33:57
+ // ty::Const + // ty::Const
+ // + ty: std::option::Option<()> + // + ty: main::NoVariants
+ // + val: Value(Scalar(0x02)) + // + val: Value(Scalar(0x00000000))
+ // mir::Constant + // mir::Constant
+ // + span: $DIR/invalid_constant.rs:16:5: 16:12 + // + span: $DIR/invalid_constant.rs:33:34: 33:57
+ // + literal: Const { ty: std::option::Option<()>, val: Value(Scalar(0x02)) } + // + literal: Const { ty: main::NoVariants, val: Value(Scalar(0x00000000)) }
goto -> bb1; // scope 0 at $DIR/invalid_constant.rs:10:20: 10:21 StorageDead(_5); // scope 2 at $DIR/invalid_constant.rs:33:56: 33:57
} nop; // scope 0 at $DIR/invalid_constant.rs:13:11: 34:2
StorageDead(_4); // scope 2 at $DIR/invalid_constant.rs:34:1: 34:2
bb3: { StorageDead(_2); // scope 1 at $DIR/invalid_constant.rs:34:1: 34:2
discriminant(_1) = 0; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12 StorageDead(_1); // scope 0 at $DIR/invalid_constant.rs:34:1: 34:2
goto -> bb1; // scope 0 at $DIR/invalid_constant.rs:9:17: 9:21 return; // scope 0 at $DIR/invalid_constant.rs:34:2: 34:2
} }
} }

View File

@ -1,23 +1,34 @@
// Verify that we can pretty print invalid constant introduced // Verify that we can pretty print invalid constants.
// by constant propagation. Regression test for issue #93688.
//
// compile-flags: -Copt-level=0 -Zinline-mir
#![feature(inline_const)] #![feature(inline_const)]
#[inline(always)]
pub fn f(x: Option<Option<()>>) -> Option<()> { #[derive(Copy, Clone)]
match x { #[repr(u32)]
None => None, enum E { A, B, C }
Some(y) => y,
} #[derive(Copy, Clone)]
} enum Empty {}
// EMIT_MIR invalid_constant.main.ConstProp.diff // EMIT_MIR invalid_constant.main.ConstProp.diff
fn main() { fn main() {
f(None); // An invalid char.
union InvalidChar {
union Union {
int: u32, int: u32,
chr: char, chr: char,
} }
let _invalid_char = const { Union { int: 0x110001 } }; let _invalid_char = const { InvalidChar { int: 0x110001 } };
// An enum with an invalid tag. Regression test for #93688.
union InvalidTag {
int: u32,
e: E,
}
let _invalid_tag = [InvalidTag { int: 4 }];
// An enum without variants. Regression test for #94073.
union NoVariants {
int: u32,
empty: Empty,
}
let _enum_without_variants = [NoVariants { int: 0 }];
} }