From 9712fa405944cb8d5416556ac4b1f26365a10658 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 5 Mar 2020 21:53:26 -0500 Subject: [PATCH 1/3] Fix #69191 --- src/librustc_mir/interpret/place.rs | 6 ++++ ...sue-69191-ice-on-uninhabited-enum-field.rs | 31 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 src/test/ui/consts/issue-69191-ice-on-uninhabited-enum-field.rs diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 4f96cb698915d..33161dfa52c7b 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -410,6 +410,12 @@ where stride * field } layout::FieldPlacement::Union(count) => { + // This is a narrow bug-fix for rust-lang/rust#69191: if we are + // trying to access absent field of uninhabited variant, then + // signal UB (but don't ICE the compiler). + if field >= count as u64 && base.layout.abi == layout::Abi::Uninhabited { + throw_ub!(Unreachable); + } assert!( field < count as u64, "Tried to access field {} of union {:#?} with {} fields", diff --git a/src/test/ui/consts/issue-69191-ice-on-uninhabited-enum-field.rs b/src/test/ui/consts/issue-69191-ice-on-uninhabited-enum-field.rs new file mode 100644 index 0000000000000..e22ddb0f5ae0c --- /dev/null +++ b/src/test/ui/consts/issue-69191-ice-on-uninhabited-enum-field.rs @@ -0,0 +1,31 @@ +// 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), } + +#[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: UninhabitedUnivariantC = None.unwrap(); + match _seed { + UninhabitedUnivariantC::_Variant(_x) => {} + } + + let _seed: UninhabitedUnivariant32 = None.unwrap(); + match _seed { + UninhabitedUnivariant32::_Variant(_x) => {} + } +} From 40809b0585d5fe3ddad39fe00a608394ad1dec30 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 6 Mar 2020 08:48:58 +0100 Subject: [PATCH 2/3] Add FIXME --- src/librustc_mir/interpret/place.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 33161dfa52c7b..721766cc932d3 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -413,6 +413,8 @@ where // This is a narrow bug-fix for rust-lang/rust#69191: if we are // trying to access absent field of uninhabited variant, then // signal UB (but don't ICE the compiler). + // FIXME temporary hack to work around incoherence between + // layout computation and MIR building if field >= count as u64 && base.layout.abi == layout::Abi::Uninhabited { throw_ub!(Unreachable); } From b4422fb14b9e0c030e9da6fa943f0e4850b25a85 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 6 Mar 2020 06:43:11 -0500 Subject: [PATCH 3/3] Added oli's multivariant test case (alpha renaming the enum name itself). (And added Ralf's suggested test.) Added my own three-variant multi-variant as well. --- ...sue-69191-ice-on-uninhabited-enum-field.rs | 66 ++++++++++++++++++- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/src/test/ui/consts/issue-69191-ice-on-uninhabited-enum-field.rs b/src/test/ui/consts/issue-69191-ice-on-uninhabited-enum-field.rs index e22ddb0f5ae0c..5b7c7be42cf06 100644 --- a/src/test/ui/consts/issue-69191-ice-on-uninhabited-enum-field.rs +++ b/src/test/ui/consts/issue-69191-ice-on-uninhabited-enum-field.rs @@ -5,13 +5,30 @@ pub enum Void {} -enum UninhabitedUnivariant { _Variant(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), } +enum UninhabitedUnivariantC { + _Variant(Void), +} #[repr(i32)] -enum UninhabitedUnivariant32 { _Variant(Void), } +enum UninhabitedUnivariant32 { + _Variant(Void), +} fn main() { let _seed: UninhabitedUnivariant = None.unwrap(); @@ -19,6 +36,49 @@ fn main() { 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) => {}