about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_codegen_llvm/type_of.rs4
-rw-r--r--src/librustc_data_structures/stable_hasher.rs6
-rw-r--r--src/librustc_middle/ty/layout.rs15
-rw-r--r--src/librustc_mir/interpret/validity.rs10
-rw-r--r--src/librustc_mir/interpret/visitor.rs5
-rw-r--r--src/librustc_target/abi/call/mips64.rs1
-rw-r--r--src/librustc_target/abi/call/mod.rs5
-rw-r--r--src/librustc_target/abi/call/riscv.rs3
-rw-r--r--src/librustc_target/abi/mod.rs29
-rw-r--r--src/test/ui/layout/debug.stderr4
10 files changed, 59 insertions, 23 deletions
diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs
index f475ea741c8..77009aca6d3 100644
--- a/src/librustc_codegen_llvm/type_of.rs
+++ b/src/librustc_codegen_llvm/type_of.rs
@@ -81,7 +81,7 @@ fn uncached_llvm_type<'a, 'tcx>(
     };
 
     match layout.fields {
-        FieldsShape::Union(_) => {
+        FieldsShape::Primitive | FieldsShape::Union(_) => {
             let fill = cx.type_padding_filler(layout.size, layout.align.abi);
             let packed = false;
             match name {
@@ -368,7 +368,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
             _ => {}
         }
         match self.fields {
-            FieldsShape::Union(_) => {
+            FieldsShape::Primitive | FieldsShape::Union(_) => {
                 bug!("TyAndLayout::llvm_field_index({:?}): not applicable", self)
             }
 
diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs
index a98e77cebd8..97b02eaef35 100644
--- a/src/librustc_data_structures/stable_hasher.rs
+++ b/src/librustc_data_structures/stable_hasher.rs
@@ -210,6 +210,12 @@ impl<CTX> HashStable<CTX> for ::std::num::NonZeroU32 {
     }
 }
 
+impl<CTX> HashStable<CTX> for ::std::num::NonZeroUsize {
+    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+        self.get().hash_stable(ctx, hasher)
+    }
+}
+
 impl<CTX> HashStable<CTX> for f32 {
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
         let val: u32 = unsafe { ::std::mem::transmute(*self) };
diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs
index 1bb338d43ad..5a210547f13 100644
--- a/src/librustc_middle/ty/layout.rs
+++ b/src/librustc_middle/ty/layout.rs
@@ -22,6 +22,7 @@ use std::cmp;
 use std::fmt;
 use std::iter;
 use std::mem;
+use std::num::NonZeroUsize;
 use std::ops::Bound;
 
 pub trait IntegerExt {
@@ -518,7 +519,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
             // The never type.
             ty::Never => tcx.intern_layout(Layout {
                 variants: Variants::Single { index: VariantIdx::new(0) },
-                fields: FieldsShape::Union(0),
+                fields: FieldsShape::Primitive,
                 abi: Abi::Uninhabited,
                 largest_niche: None,
                 align: dl.i8_align,
@@ -744,7 +745,10 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
 
                     return Ok(tcx.intern_layout(Layout {
                         variants: Variants::Single { index },
-                        fields: FieldsShape::Union(variants[index].len()),
+                        fields: FieldsShape::Union(
+                            NonZeroUsize::new(variants[index].len())
+                                .ok_or(LayoutError::Unknown(ty))?,
+                        ),
                         abi,
                         largest_niche: None,
                         align,
@@ -1988,7 +1992,7 @@ where
                 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 != FieldsShape::Union(0) =>
+                this.fields != FieldsShape::Primitive =>
             {
                 this.layout
             }
@@ -2006,7 +2010,10 @@ where
                 let tcx = cx.tcx();
                 tcx.intern_layout(Layout {
                     variants: Variants::Single { index: variant_index },
-                    fields: FieldsShape::Union(fields),
+                    fields: match NonZeroUsize::new(fields) {
+                        Some(fields) => FieldsShape::Union(fields),
+                        None => FieldsShape::Arbitrary { offsets: vec![], memory_index: vec![] },
+                    },
                     abi: Abi::Uninhabited,
                     largest_niche: None,
                     align: tcx.data_layout.i8_align,
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index 83b8d58e0be..2dffd78d776 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -6,6 +6,7 @@
 
 use std::convert::TryFrom;
 use std::fmt::Write;
+use std::num::NonZeroUsize;
 use std::ops::RangeInclusive;
 
 use rustc_data_structures::fx::FxHashSet;
@@ -647,10 +648,11 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
     }
 
     #[inline(always)]
-    fn visit_union(&mut self, op: OpTy<'tcx, M::PointerTag>, fields: usize) -> InterpResult<'tcx> {
-        // Empty unions are not accepted by rustc. But uninhabited enums
-        // claim to be unions, so allow them, too.
-        assert!(op.layout.abi.is_uninhabited() || fields > 0);
+    fn visit_union(
+        &mut self,
+        _op: OpTy<'tcx, M::PointerTag>,
+        _fields: NonZeroUsize,
+    ) -> InterpResult<'tcx> {
         Ok(())
     }
 
diff --git a/src/librustc_mir/interpret/visitor.rs b/src/librustc_mir/interpret/visitor.rs
index e03984f4d0b..00d39452c49 100644
--- a/src/librustc_mir/interpret/visitor.rs
+++ b/src/librustc_mir/interpret/visitor.rs
@@ -6,6 +6,8 @@ use rustc_middle::ty;
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_target::abi::{FieldsShape, VariantIdx, Variants};
 
+use std::num::NonZeroUsize;
+
 use super::{InterpCx, MPlaceTy, Machine, OpTy};
 
 // A thing that we can project into, and that has a layout.
@@ -130,7 +132,7 @@ macro_rules! make_value_visitor {
             }
             /// Visits the given value as a union. No automatic recursion can happen here.
             #[inline(always)]
-            fn visit_union(&mut self, _v: Self::V, _fields: usize) -> InterpResult<'tcx>
+            fn visit_union(&mut self, _v: Self::V, _fields: NonZeroUsize) -> InterpResult<'tcx>
             {
                 Ok(())
             }
@@ -208,6 +210,7 @@ macro_rules! make_value_visitor {
 
                 // Visit the fields of this value.
                 match v.layout().fields {
+                    FieldsShape::Primitive => {},
                     FieldsShape::Union(fields) => {
                         self.visit_union(v, fields)?;
                     },
diff --git a/src/librustc_target/abi/call/mips64.rs b/src/librustc_target/abi/call/mips64.rs
index 81de6306788..917dd104d14 100644
--- a/src/librustc_target/abi/call/mips64.rs
+++ b/src/librustc_target/abi/call/mips64.rs
@@ -88,6 +88,7 @@ where
     let mut prefix_index = 0;
 
     match arg.layout.fields {
+        abi::FieldsShape::Primitive => unreachable!(),
         abi::FieldsShape::Array { .. } => {
             // Arrays are passed indirectly
             arg.make_indirect();
diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs
index b6bfa70005b..0303312d057 100644
--- a/src/librustc_target/abi/call/mod.rs
+++ b/src/librustc_target/abi/call/mod.rs
@@ -308,13 +308,16 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
             }
 
             Abi::ScalarPair(..) | Abi::Aggregate { .. } => {
-                // Helper for computing `homogenous_aggregate`, allowing a custom
+                // Helper for computing `homogeneous_aggregate`, allowing a custom
                 // starting offset (used below for handling variants).
                 let from_fields_at =
                     |layout: Self,
                      start: Size|
                      -> Result<(HomogeneousAggregate, Size), Heterogeneous> {
                         let is_union = match layout.fields {
+                            FieldsShape::Primitive => {
+                                unreachable!("aggregates can't have `FieldsShape::Primitive`")
+                            }
                             FieldsShape::Array { count, .. } => {
                                 assert_eq!(start, Size::ZERO);
 
diff --git a/src/librustc_target/abi/call/riscv.rs b/src/librustc_target/abi/call/riscv.rs
index 0eb8816e434..2e10bed3bd4 100644
--- a/src/librustc_target/abi/call/riscv.rs
+++ b/src/librustc_target/abi/call/riscv.rs
@@ -87,6 +87,9 @@ where
         },
         Abi::Vector { .. } | Abi::Uninhabited => return Err(CannotUseFpConv),
         Abi::ScalarPair(..) | Abi::Aggregate { .. } => match arg_layout.fields {
+            FieldsShape::Primitive => {
+                unreachable!("aggregates can't have `FieldsShape::Primitive`")
+            }
             FieldsShape::Union(_) => {
                 if !arg_layout.is_zst() {
                     return Err(CannotUseFpConv);
diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index 4c25363a657..dcf181cb59f 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -4,6 +4,7 @@ pub use Primitive::*;
 use crate::spec::Target;
 
 use std::convert::{TryFrom, TryInto};
+use std::num::NonZeroUsize;
 use std::ops::{Add, AddAssign, Deref, Mul, Range, RangeInclusive, Sub};
 
 use rustc_index::vec::{Idx, IndexVec};
@@ -619,10 +620,11 @@ impl Scalar {
 /// Describes how the fields of a type are located in memory.
 #[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub enum FieldsShape {
+    /// Scalar primitives and `!`, which never have fields.
+    Primitive,
+
     /// All fields start at no offset. The `usize` is the field count.
-    ///
-    /// In the case of primitives the number of fields is `0`.
-    Union(usize),
+    Union(NonZeroUsize),
 
     /// Array/vector-like placement, with all fields of identical types.
     Array { stride: Size, count: u64 },
@@ -660,7 +662,8 @@ pub enum FieldsShape {
 impl FieldsShape {
     pub fn count(&self) -> usize {
         match *self {
-            FieldsShape::Union(count) => count,
+            FieldsShape::Primitive => 0,
+            FieldsShape::Union(count) => count.get(),
             FieldsShape::Array { count, .. } => {
                 let usize_count = count as usize;
                 assert_eq!(usize_count as u64, count);
@@ -672,8 +675,16 @@ impl FieldsShape {
 
     pub fn offset(&self, i: usize) -> Size {
         match *self {
+            FieldsShape::Primitive => {
+                unreachable!("FieldsShape::offset: `Primitive`s have no fields")
+            }
             FieldsShape::Union(count) => {
-                assert!(i < count, "tried to access field {} of union with {} fields", i, count);
+                assert!(
+                    i < count.get(),
+                    "tried to access field {} of union with {} fields",
+                    i,
+                    count
+                );
                 Size::ZERO
             }
             FieldsShape::Array { stride, count } => {
@@ -687,6 +698,9 @@ impl FieldsShape {
 
     pub fn memory_index(&self, i: usize) -> usize {
         match *self {
+            FieldsShape::Primitive => {
+                unreachable!("FieldsShape::memory_index: `Primitive`s have no fields")
+            }
             FieldsShape::Union(_) | FieldsShape::Array { .. } => i,
             FieldsShape::Arbitrary { ref memory_index, .. } => {
                 let r = memory_index[i];
@@ -718,7 +732,7 @@ impl FieldsShape {
         }
 
         (0..self.count()).map(move |i| match *self {
-            FieldsShape::Union(_) | FieldsShape::Array { .. } => i,
+            FieldsShape::Primitive | FieldsShape::Union(_) | FieldsShape::Array { .. } => i,
             FieldsShape::Arbitrary { .. } => {
                 if use_small {
                     inverse_small[i] as usize
@@ -887,7 +901,6 @@ impl Niche {
 #[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub struct Layout {
     /// Says where the fields are located within the layout.
-    /// Primitives and uninhabited enums appear as unions without fields.
     pub fields: FieldsShape,
 
     /// Encodes information about multi-variant layouts.
@@ -923,7 +936,7 @@ impl Layout {
         let align = scalar.value.align(cx);
         Layout {
             variants: Variants::Single { index: VariantIdx::new(0) },
-            fields: FieldsShape::Union(0),
+            fields: FieldsShape::Primitive,
             abi: Abi::Scalar(scalar),
             largest_niche,
             size,
diff --git a/src/test/ui/layout/debug.stderr b/src/test/ui/layout/debug.stderr
index 153dec594d3..cd8ebdffb73 100644
--- a/src/test/ui/layout/debug.stderr
+++ b/src/test/ui/layout/debug.stderr
@@ -316,9 +316,7 @@ LL | type Test = Result<i32, i32>;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: layout_of(i32) = Layout {
-    fields: Union(
-        0,
-    ),
+    fields: Primitive,
     variants: Single {
         index: 0,
     },