Auto merge of #70629 - anyska:fields-variant, r=oli-obk

rustc_target::abi: add Primitive variant to FieldsShape.

Originally suggested by @eddyb.
This commit is contained in:
bors 2020-04-17 08:42:51 +00:00
commit b2c1a606fe
10 changed files with 59 additions and 23 deletions

View File

@ -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)
}

View File

@ -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) };

View File

@ -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,

View File

@ -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(())
}

View File

@ -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)?;
},

View File

@ -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();

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -316,9 +316,7 @@ LL | type Test = Result<i32, i32>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: layout_of(i32) = Layout {
fields: Union(
0,
),
fields: Primitive,
variants: Single {
index: 0,
},