Skip to content

Commit

Permalink
Auto merge of #70629 - anyska:fields-variant, r=oli-obk
Browse files Browse the repository at this point in the history
rustc_target::abi: add Primitive variant to FieldsShape.

Originally suggested by @eddyb.
  • Loading branch information
bors committed Apr 17, 2020
2 parents 861996e + 8f081d5 commit b2c1a60
Show file tree
Hide file tree
Showing 10 changed files with 59 additions and 23 deletions.
4 changes: 2 additions & 2 deletions src/librustc_codegen_llvm/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
}

Expand Down
6 changes: 6 additions & 0 deletions src/librustc_data_structures/stable_hasher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) };
Expand Down
15 changes: 11 additions & 4 deletions src/librustc_middle/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
}
Expand All @@ -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,
Expand Down
10 changes: 6 additions & 4 deletions src/librustc_mir/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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(())
}

Expand Down
5 changes: 4 additions & 1 deletion src/librustc_mir/interpret/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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(())
}
Expand Down Expand Up @@ -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)?;
},
Expand Down
1 change: 1 addition & 0 deletions src/librustc_target/abi/call/mips64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
5 changes: 4 additions & 1 deletion src/librustc_target/abi/call/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
3 changes: 3 additions & 0 deletions src/librustc_target/abi/call/riscv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
29 changes: 21 additions & 8 deletions src/librustc_target/abi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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 },
Expand Down Expand Up @@ -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);
Expand All @@ -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 } => {
Expand All @@ -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];
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 1 addition & 3 deletions src/test/ui/layout/debug.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -316,9 +316,7 @@ LL | type Test = Result<i32, i32>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: layout_of(i32) = Layout {
fields: Union(
0,
),
fields: Primitive,
variants: Single {
index: 0,
},
Expand Down

0 comments on commit b2c1a60

Please sign in to comment.