From c5a35ba1936fc1cf5781b4fd9ebead4c274ef0f7 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 6 Mar 2020 10:55:20 +0100 Subject: [PATCH] Non-empty enums need to produce a layout with variants --- src/librustc/ty/layout.rs | 24 ++++++++++------- src/librustc_mir/interpret/operand.rs | 2 +- src/test/ui/consts/issue-69191.rs | 37 +++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/consts/issue-69191.rs diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index e8bf2eb9a12c9..f35117cd1a0cf 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -779,20 +779,26 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { .filter_map(|(i, v)| if absent(v) { None } else { Some(i) }); (present_variants.next(), present_variants.next()) }; - let present_first = match present_first { - present_first @ Some(_) => present_first, - // Uninhabited because it has no variants, or only absent ones. - None if def.is_enum() => return tcx.layout_raw(param_env.and(tcx.types.never)), - // if it's a struct, still compute a layout so that we can still compute the - // field offsets - None => Some(VariantIdx::new(0)), + let (present_first, allow_enum_layout_opt) = match present_first { + present_first @ Some(_) => (present_first, !def.repr.inhibit_enum_layout_opt()), + // Do not run layout optimizations because it has no variants, + // or only absent ones, which will make the niche logic ICE. + None if def.is_enum() => { + if variants.is_empty() { + return tcx.layout_raw(param_env.and(tcx.types.never)); + } else { + (None, false) + } + } + // If it's a struct, still compute a valid layout. + None => (Some(VariantIdx::new(0)), !def.repr.inhibit_enum_layout_opt()), }; let is_struct = !def.is_enum() || // Only one variant is present. (present_second.is_none() && // Representation optimizations are allowed. - !def.repr.inhibit_enum_layout_opt()); + allow_enum_layout_opt); if is_struct { // Struct, or univariant enum equivalent to a struct. // (Typechecking will reject discriminant-sizing attrs.) @@ -883,7 +889,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { .all(|(i, v)| v.discr == ty::VariantDiscr::Relative(i.as_u32())); // Niche-filling enum optimization. - if !def.repr.inhibit_enum_layout_opt() && no_explicit_discriminants { + if allow_enum_layout_opt && no_explicit_discriminants { let mut dataful_variant = None; let mut niche_variants = VariantIdx::MAX..=VariantIdx::new(0); diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 14b8a341e26a0..1a2e453e5bb75 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -361,7 +361,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { let base = match op.try_as_mplace(self) { Ok(mplace) => { - // The easy case + // We can reuse the mplace field compuation logic for indirect operands let field = self.mplace_field(mplace, field)?; return Ok(field.into()); } diff --git a/src/test/ui/consts/issue-69191.rs b/src/test/ui/consts/issue-69191.rs new file mode 100644 index 0000000000000..281b87f757ea6 --- /dev/null +++ b/src/test/ui/consts/issue-69191.rs @@ -0,0 +1,37 @@ +// 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) => {} + } +}