about summary refs log tree commit diff
diff options
context:
space:
mode:
authorYuki Okushi <huyuumi.dev@gmail.com>2020-03-20 17:02:03 +0900
committerGitHub <noreply@github.com>2020-03-20 17:02:03 +0900
commit3554f2d9411b0924fea8c78dfa82060b9500f261 (patch)
tree2369d939a5f0d77432c3b87add3007e59c6e1c21
parent5d395176809c8f8a8399a8bec31bb2f6cdbf975a (diff)
parent74608c7f206171cb72c020a03800b2d9035a35fa (diff)
downloadrust-3554f2d9411b0924fea8c78dfa82060b9500f261.tar.gz
rust-3554f2d9411b0924fea8c78dfa82060b9500f261.zip
Rollup merge of #69768 - oli-obk:union_field_ice, r=eddyb,RalfJung
Compute the correct layout for variants of uninhabited enums

r? @eddyb
cc @RalfJung

fixes #69191
cc #69763
-rw-r--r--src/librustc/ty/layout.rs14
-rw-r--r--src/librustc_mir/interpret/operand.rs2
-rw-r--r--src/librustc_mir/interpret/place.rs8
-rw-r--r--src/librustc_target/abi/mod.rs5
4 files changed, 16 insertions, 13 deletions
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 041dfc7d169..6d28796b348 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -780,8 +780,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                     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
+                    // If it's a struct, still compute a layout so that we can still compute the
+                    // field offsets.
                     None => Some(VariantIdx::new(0)),
                 };
 
@@ -1987,7 +1987,15 @@ where
 {
     fn for_variant(this: TyLayout<'tcx>, cx: &C, variant_index: VariantIdx) -> TyLayout<'tcx> {
         let details = match this.variants {
-            Variants::Single { index } if index == variant_index => this.details,
+            Variants::Single { index }
+                // If all variants but one are uninhabited, the variant layout is the enum layout.
+                if index == variant_index &&
+                // Don't confuse variants of uninhabited enums with the enum itself.
+                // For more details see https://github.com/rust-lang/rust/issues/69763.
+                this.fields != FieldPlacement::Union(0) =>
+            {
+                this.details
+            }
 
             Variants::Single { index } => {
                 // Deny calling for_variant more than once for non-Single enums.
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index 316cf2ee419..da55d710ba7 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -355,7 +355,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 computation logic for indirect operands.
                 let field = self.mplace_field(mplace, field)?;
                 return Ok(field.into());
             }
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 107cfee5ace..22ac0ac65a8 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -410,14 +410,6 @@ 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).
-                // 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);
-                }
                 assert!(
                     field < count as u64,
                     "Tried to access field {} of union {:#?} with {} fields",
diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index 2f8bbd66c32..afa30e7e632 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -660,7 +660,10 @@ impl FieldPlacement {
 
     pub fn offset(&self, i: usize) -> Size {
         match *self {
-            FieldPlacement::Union(_) => Size::ZERO,
+            FieldPlacement::Union(count) => {
+                assert!(i < count, "tried to access field {} of union with {} fields", i, count);
+                Size::ZERO
+            }
             FieldPlacement::Array { stride, count } => {
                 let i = i as u64;
                 assert!(i < count);