rustc: collapse the remains of Layout into Variants (enums vs everything else).
This commit is contained in:
parent
b28f668e26
commit
018323ffc2
@ -769,33 +769,17 @@ impl Abi {
|
||||
}
|
||||
}
|
||||
|
||||
/// Type layout, from which size and alignment can be cheaply computed.
|
||||
/// For ADTs, it also includes field placement and enum optimizations.
|
||||
/// NOTE: Because Layout is interned, redundant information should be
|
||||
/// kept to a minimum, e.g. it includes no sub-component Ty or Layout.
|
||||
#[derive(PartialEq, Eq, Hash, Debug)]
|
||||
pub enum Layout {
|
||||
/// TyBool, TyChar, TyInt, TyUint, TyFloat, TyRawPtr, TyRef or TyFnPtr.
|
||||
Scalar,
|
||||
|
||||
/// SIMD vectors, from structs marked with #[repr(simd)].
|
||||
Vector,
|
||||
|
||||
/// TyArray, TySlice or TyStr.
|
||||
Array,
|
||||
|
||||
// Remaining variants are all ADTs such as structs, enums or tuples.
|
||||
|
||||
/// Single-case enums, and structs/tuples.
|
||||
Univariant,
|
||||
|
||||
/// Untagged unions.
|
||||
UntaggedUnion,
|
||||
pub enum Variants {
|
||||
/// Single enum variants, structs/tuples, unions, and all non-ADTs.
|
||||
Single {
|
||||
index: usize
|
||||
},
|
||||
|
||||
/// General-case enums: for each case there is a struct, and they all have
|
||||
/// all space reserved for the discriminant, and their first field starts
|
||||
/// at a non-0 offset, after where the discriminant would go.
|
||||
General {
|
||||
Tagged {
|
||||
discr: Primitive,
|
||||
/// Inclusive wrap-around range of discriminant values, that is,
|
||||
/// if min > max, it represents min..=u64::MAX followed by 0..=max.
|
||||
@ -806,7 +790,7 @@ pub enum Layout {
|
||||
variants: Vec<CachedLayout>,
|
||||
},
|
||||
|
||||
/// Two cases distinguished by a nullable pointer: the case with discriminant
|
||||
/// Two cases distinguished by a niche: the case with discriminant
|
||||
/// `nndiscr` is represented by the struct `nonnull`, where field `0`
|
||||
/// is known to be nonnull due to its type; if that field is null, then
|
||||
/// it represents the other case, which is known to be zero sized.
|
||||
@ -814,7 +798,7 @@ pub enum Layout {
|
||||
/// For example, `std::option::Option` instantiated at a safe pointer type
|
||||
/// is represented such that `None` is a null pointer and `Some` is the
|
||||
/// identity function.
|
||||
NullablePointer {
|
||||
NicheFilling {
|
||||
nndiscr: u64,
|
||||
discr: Primitive,
|
||||
variants: Vec<CachedLayout>,
|
||||
@ -842,8 +826,7 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Debug)]
|
||||
pub struct CachedLayout {
|
||||
pub variant_index: Option<usize>,
|
||||
pub layout: Layout,
|
||||
pub variants: Variants,
|
||||
pub fields: FieldPlacement,
|
||||
pub abi: Abi,
|
||||
pub align: Align,
|
||||
@ -865,7 +848,7 @@ fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
}
|
||||
|
||||
tcx.layout_depth.set(depth+1);
|
||||
let layout = Layout::compute_uncached(tcx, param_env, ty);
|
||||
let layout = CachedLayout::compute_uncached(tcx, param_env, ty);
|
||||
tcx.layout_depth.set(depth);
|
||||
|
||||
layout
|
||||
@ -878,18 +861,17 @@ pub fn provide(providers: &mut ty::maps::Providers) {
|
||||
};
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Layout {
|
||||
impl<'a, 'tcx> CachedLayout {
|
||||
fn compute_uncached(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>)
|
||||
-> Result<&'tcx CachedLayout, LayoutError<'tcx>> {
|
||||
-> Result<&'tcx Self, LayoutError<'tcx>> {
|
||||
let cx = (tcx, param_env);
|
||||
let dl = cx.data_layout();
|
||||
let scalar = |value: Primitive| {
|
||||
let align = value.align(dl);
|
||||
tcx.intern_layout(CachedLayout {
|
||||
variant_index: None,
|
||||
layout: Layout::Scalar,
|
||||
variants: Variants::Single { index: 0 },
|
||||
fields: FieldPlacement::Union(0),
|
||||
abi: Abi::Scalar(value),
|
||||
size: value.size(dl),
|
||||
@ -1028,8 +1010,7 @@ impl<'a, 'tcx> Layout {
|
||||
}
|
||||
|
||||
Ok(CachedLayout {
|
||||
variant_index: None,
|
||||
layout: Layout::Univariant,
|
||||
variants: Variants::Single { index: 0 },
|
||||
fields: FieldPlacement::Arbitrary {
|
||||
offsets,
|
||||
memory_index
|
||||
@ -1073,8 +1054,7 @@ impl<'a, 'tcx> Layout {
|
||||
memory_index: vec![0, 1]
|
||||
};
|
||||
Ok(tcx.intern_layout(CachedLayout {
|
||||
variant_index: None,
|
||||
layout: Layout::Univariant,
|
||||
variants: Variants::Single { index: 0 },
|
||||
fields,
|
||||
abi: Abi::Aggregate {
|
||||
sized: true,
|
||||
@ -1129,8 +1109,7 @@ impl<'a, 'tcx> Layout {
|
||||
.ok_or(LayoutError::SizeOverflow(ty))?;
|
||||
|
||||
tcx.intern_layout(CachedLayout {
|
||||
variant_index: None,
|
||||
layout: Layout::Array,
|
||||
variants: Variants::Single { index: 0 },
|
||||
fields: FieldPlacement::Array {
|
||||
stride: element.size,
|
||||
count
|
||||
@ -1147,8 +1126,7 @@ impl<'a, 'tcx> Layout {
|
||||
ty::TySlice(element) => {
|
||||
let element = cx.layout_of(element)?;
|
||||
tcx.intern_layout(CachedLayout {
|
||||
variant_index: None,
|
||||
layout: Layout::Array,
|
||||
variants: Variants::Single { index: 0 },
|
||||
fields: FieldPlacement::Array {
|
||||
stride: element.size,
|
||||
count: 0
|
||||
@ -1164,8 +1142,7 @@ impl<'a, 'tcx> Layout {
|
||||
}
|
||||
ty::TyStr => {
|
||||
tcx.intern_layout(CachedLayout {
|
||||
variant_index: None,
|
||||
layout: Layout::Array,
|
||||
variants: Variants::Single { index: 0 },
|
||||
fields: FieldPlacement::Array {
|
||||
stride: Size::from_bytes(1),
|
||||
count: 0
|
||||
@ -1238,8 +1215,7 @@ impl<'a, 'tcx> Layout {
|
||||
let size = size.abi_align(align);
|
||||
|
||||
tcx.intern_layout(CachedLayout {
|
||||
variant_index: None,
|
||||
layout: Layout::Vector,
|
||||
variants: Variants::Single { index: 0 },
|
||||
fields: FieldPlacement::Array {
|
||||
stride: element.size,
|
||||
count
|
||||
@ -1302,8 +1278,7 @@ impl<'a, 'tcx> Layout {
|
||||
}
|
||||
|
||||
return Ok(tcx.intern_layout(CachedLayout {
|
||||
variant_index: None,
|
||||
layout: Layout::UntaggedUnion,
|
||||
variants: Variants::Single { index: 0 },
|
||||
fields: FieldPlacement::Union(variants[0].len()),
|
||||
abi: Abi::Aggregate {
|
||||
sized: true,
|
||||
@ -1332,11 +1307,7 @@ impl<'a, 'tcx> Layout {
|
||||
else { StructKind::AlwaysSized }
|
||||
};
|
||||
|
||||
let mut cached = univariant_uninterned(&variants[0], &def.repr, kind)?;
|
||||
if def.is_enum() {
|
||||
cached.variant_index = Some(0);
|
||||
}
|
||||
return Ok(tcx.intern_layout(cached));
|
||||
return univariant(&variants[0], &def.repr, kind);
|
||||
}
|
||||
|
||||
let no_explicit_discriminants = def.variants.iter().enumerate()
|
||||
@ -1359,8 +1330,9 @@ impl<'a, 'tcx> Layout {
|
||||
univariant_uninterned(&variants[1],
|
||||
&def.repr, StructKind::AlwaysSized)?
|
||||
];
|
||||
st[0].variant_index = Some(0);
|
||||
st[1].variant_index = Some(1);
|
||||
for (i, v) in st.iter_mut().enumerate() {
|
||||
v.variants = Variants::Single { index: i };
|
||||
}
|
||||
let offset = st[i].fields.offset(field_index) + offset;
|
||||
let CachedLayout {
|
||||
mut abi,
|
||||
@ -1383,8 +1355,7 @@ impl<'a, 'tcx> Layout {
|
||||
primitive_align = primitive_align.max(discr_align);
|
||||
|
||||
return Ok(tcx.intern_layout(CachedLayout {
|
||||
variant_index: None,
|
||||
layout: Layout::NullablePointer {
|
||||
variants: Variants::NicheFilling {
|
||||
nndiscr: i as u64,
|
||||
|
||||
discr,
|
||||
@ -1426,7 +1397,7 @@ impl<'a, 'tcx> Layout {
|
||||
let mut variants = variants.into_iter().enumerate().map(|(i, field_layouts)| {
|
||||
let mut st = univariant_uninterned(&field_layouts,
|
||||
&def.repr, StructKind::EnumVariant(min_ity))?;
|
||||
st.variant_index = Some(i);
|
||||
st.variants = Variants::Single { index: i };
|
||||
// Find the first field we can't move later
|
||||
// to make room for a larger discriminant.
|
||||
for field in st.fields.index_by_increasing_offset().map(|j| field_layouts[j]) {
|
||||
@ -1506,8 +1477,7 @@ impl<'a, 'tcx> Layout {
|
||||
|
||||
let discr = Int(ity, signed);
|
||||
tcx.intern_layout(CachedLayout {
|
||||
variant_index: None,
|
||||
layout: Layout::General {
|
||||
variants: Variants::Tagged {
|
||||
discr,
|
||||
|
||||
// FIXME: should be u128?
|
||||
@ -1544,7 +1514,7 @@ impl<'a, 'tcx> Layout {
|
||||
return Err(LayoutError::Unknown(ty));
|
||||
}
|
||||
ty::TyInfer(_) | ty::TyError => {
|
||||
bug!("Layout::compute: unexpected type `{}`", ty)
|
||||
bug!("CachedLayout::compute: unexpected type `{}`", ty)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -1650,8 +1620,8 @@ impl<'a, 'tcx> Layout {
|
||||
}
|
||||
};
|
||||
|
||||
match layout.layout {
|
||||
Layout::Univariant => {
|
||||
match layout.variants {
|
||||
Variants::Single { .. } => {
|
||||
let variant_names = || {
|
||||
adt_def.variants.iter().map(|v|format!("{}", v.name)).collect::<Vec<_>>()
|
||||
};
|
||||
@ -1675,8 +1645,8 @@ impl<'a, 'tcx> Layout {
|
||||
}
|
||||
}
|
||||
|
||||
Layout::NullablePointer { .. } |
|
||||
Layout::General { .. } => {
|
||||
Variants::NicheFilling { .. } |
|
||||
Variants::Tagged { .. } => {
|
||||
debug!("print-type-size `{:#?}` adt general variants def {}",
|
||||
ty, adt_def.variants.len());
|
||||
let variant_infos: Vec<_> =
|
||||
@ -1688,27 +1658,11 @@ impl<'a, 'tcx> Layout {
|
||||
layout.for_variant(i))
|
||||
})
|
||||
.collect();
|
||||
record(adt_kind.into(), match layout.layout {
|
||||
Layout::General { discr, .. } => Some(discr.size(tcx)),
|
||||
record(adt_kind.into(), match layout.variants {
|
||||
Variants::Tagged { discr, .. } => Some(discr.size(tcx)),
|
||||
_ => None
|
||||
}, variant_infos);
|
||||
}
|
||||
|
||||
Layout::UntaggedUnion => {
|
||||
debug!("print-type-size t: `{:?}` adt union", ty);
|
||||
// layout does not currently store info about each
|
||||
// variant...
|
||||
record(adt_kind.into(), None, Vec::new());
|
||||
}
|
||||
|
||||
// other cases provide little interesting (i.e. adjustable
|
||||
// via representation tweaks) size info beyond total size.
|
||||
Layout::Scalar |
|
||||
Layout::Vector |
|
||||
Layout::Array => {
|
||||
debug!("print-type-size t: `{:?}` adt other", ty);
|
||||
record(adt_kind.into(), None, Vec::new())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1950,7 +1904,7 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (TyCtxt<'a, 'tcx, 'tcx>, ty::ParamEnv<'tcx
|
||||
// completed, to avoid problems around recursive structures
|
||||
// and the like. (Admitedly, I wasn't able to reproduce a problem
|
||||
// here, but it seems like the right thing to do. -nmatsakis)
|
||||
Layout::record_layout_for_printing(tcx, ty, param_env, layout);
|
||||
CachedLayout::record_layout_for_printing(tcx, ty, param_env, layout);
|
||||
|
||||
Ok(layout)
|
||||
}
|
||||
@ -1979,7 +1933,7 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>,
|
||||
// completed, to avoid problems around recursive structures
|
||||
// and the like. (Admitedly, I wasn't able to reproduce a problem
|
||||
// here, but it seems like the right thing to do. -nmatsakis)
|
||||
Layout::record_layout_for_printing(tcx_at.tcx, ty, param_env, layout);
|
||||
CachedLayout::record_layout_for_printing(tcx_at.tcx, ty, param_env, layout);
|
||||
|
||||
Ok(layout)
|
||||
}
|
||||
@ -1987,15 +1941,15 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>,
|
||||
|
||||
impl<'a, 'tcx> TyLayout<'tcx> {
|
||||
pub fn for_variant(&self, variant_index: usize) -> Self {
|
||||
let cached = match self.layout {
|
||||
Layout::NullablePointer { ref variants, .. } |
|
||||
Layout::General { ref variants, .. } => {
|
||||
let cached = match self.variants {
|
||||
Variants::Single { .. } => self.cached,
|
||||
|
||||
Variants::NicheFilling { ref variants, .. } |
|
||||
Variants::Tagged { ref variants, .. } => {
|
||||
&variants[variant_index]
|
||||
}
|
||||
|
||||
_ => self.cached
|
||||
};
|
||||
assert_eq!(cached.variant_index, Some(variant_index));
|
||||
assert_eq!(cached.variants, Variants::Single { index: variant_index });
|
||||
|
||||
TyLayout {
|
||||
ty: self.ty,
|
||||
@ -2081,26 +2035,17 @@ impl<'a, 'tcx> TyLayout<'tcx> {
|
||||
|
||||
// ADTs.
|
||||
ty::TyAdt(def, substs) => {
|
||||
let v = if def.is_enum() {
|
||||
match self.variant_index {
|
||||
None => match self.layout {
|
||||
// Discriminant field for enums (where applicable).
|
||||
Layout::General { discr, .. } |
|
||||
Layout::NullablePointer { discr, .. } => {
|
||||
return cx.layout_of([discr.to_ty(tcx)][i]);
|
||||
}
|
||||
_ => {
|
||||
bug!("TyLayout::field_type: enum `{}` has no discriminant",
|
||||
self.ty)
|
||||
}
|
||||
},
|
||||
Some(v) => v
|
||||
match self.variants {
|
||||
Variants::Single { index } => {
|
||||
def.variants[index].fields[i].ty(tcx, substs)
|
||||
}
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
def.variants[v].fields[i].ty(tcx, substs)
|
||||
// Discriminant field for enums (where applicable).
|
||||
Variants::Tagged { discr, .. } |
|
||||
Variants::NicheFilling { discr, .. } => {
|
||||
return cx.layout_of([discr.to_ty(tcx)][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) |
|
||||
@ -2143,18 +2088,18 @@ impl<'a, 'tcx> TyLayout<'tcx> {
|
||||
HasTyCtxt<'tcx>
|
||||
{
|
||||
let tcx = cx.tcx();
|
||||
match (&self.layout, self.abi, &self.ty.sty) {
|
||||
match (&self.variants, self.abi, &self.ty.sty) {
|
||||
// FIXME(eddyb) check this via value ranges on scalars.
|
||||
(&Layout::Scalar, Abi::Scalar(Pointer), &ty::TyRef(..)) |
|
||||
(&Layout::Scalar, Abi::Scalar(Pointer), &ty::TyFnPtr(..)) => {
|
||||
(_, Abi::Scalar(Pointer), &ty::TyRef(..)) |
|
||||
(_, Abi::Scalar(Pointer), &ty::TyFnPtr(..)) => {
|
||||
Ok(Some((Size::from_bytes(0), Pointer)))
|
||||
}
|
||||
(&Layout::Scalar, Abi::Scalar(Pointer), &ty::TyAdt(def, _)) if def.is_box() => {
|
||||
(_, Abi::Scalar(Pointer), &ty::TyAdt(def, _)) if def.is_box() => {
|
||||
Ok(Some((Size::from_bytes(0), Pointer)))
|
||||
}
|
||||
|
||||
// FIXME(eddyb) check this via value ranges on scalars.
|
||||
(&Layout::General { discr, .. }, _, &ty::TyAdt(def, _)) => {
|
||||
(&Variants::Tagged { discr, .. }, _, &ty::TyAdt(def, _)) => {
|
||||
if def.discriminants(tcx).all(|d| d.to_u128_unchecked() != 0) {
|
||||
Ok(Some((self.fields.offset(0), discr)))
|
||||
} else {
|
||||
@ -2196,20 +2141,18 @@ impl<'a, 'tcx> TyLayout<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for Layout {
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for Variants {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
use ty::layout::Layout::*;
|
||||
use ty::layout::Variants::*;
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
|
||||
match *self {
|
||||
Scalar => {}
|
||||
Vector => {}
|
||||
Array => {}
|
||||
Univariant => {}
|
||||
UntaggedUnion => {}
|
||||
General {
|
||||
Single { index } => {
|
||||
index.hash_stable(hcx, hasher);
|
||||
}
|
||||
Tagged {
|
||||
discr,
|
||||
discr_range: RangeInclusive { start, end },
|
||||
ref variants,
|
||||
@ -2219,7 +2162,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Layout {
|
||||
end.hash_stable(hcx, hasher);
|
||||
variants.hash_stable(hcx, hasher);
|
||||
}
|
||||
NullablePointer {
|
||||
NicheFilling {
|
||||
nndiscr,
|
||||
ref variants,
|
||||
ref discr,
|
||||
@ -2279,8 +2222,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Abi {
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(struct ::ty::layout::CachedLayout {
|
||||
variant_index,
|
||||
layout,
|
||||
variants,
|
||||
fields,
|
||||
abi,
|
||||
size,
|
||||
|
@ -13,7 +13,7 @@
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::ty::{self, AdtKind, Ty, TyCtxt};
|
||||
use rustc::ty::layout::{Layout, LayoutOf};
|
||||
use rustc::ty::layout::{self, LayoutOf};
|
||||
use middle::const_val::ConstVal;
|
||||
use rustc_const_eval::ConstContext;
|
||||
use util::nodemap::FxHashSet;
|
||||
@ -753,7 +753,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
|
||||
bug!("failed to get layout for `{}`: {}", t, e)
|
||||
});
|
||||
|
||||
if let Layout::General { ref variants, discr, .. } = layout.layout {
|
||||
if let layout::Variants::Tagged { ref variants, discr, .. } = layout.variants {
|
||||
let discr_size = discr.size(cx.tcx).bytes();
|
||||
|
||||
debug!("enum `{}` is {} bytes large with layout:\n{:#?}",
|
||||
|
@ -14,7 +14,7 @@
|
||||
use abi::{ArgType, ArgAttribute, CastTarget, FnType, LayoutExt, Reg, RegKind};
|
||||
use context::CrateContext;
|
||||
|
||||
use rustc::ty::layout::{self, Layout, TyLayout, Size};
|
||||
use rustc::ty::layout::{self, TyLayout, Size};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
enum Class {
|
||||
@ -87,17 +87,15 @@ fn classify_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &ArgType<'tcx>)
|
||||
}
|
||||
|
||||
layout::Abi::Aggregate { .. } => {
|
||||
// FIXME(eddyb) have to work around Rust enums for now.
|
||||
// Fix is either guarantee no data where there is no field,
|
||||
// by putting variants in fields, or be more clever.
|
||||
match layout.layout {
|
||||
Layout::General { .. } |
|
||||
Layout::NullablePointer { .. } => return Err(Memory),
|
||||
_ => {}
|
||||
}
|
||||
for i in 0..layout.fields.count() {
|
||||
let field_off = off + layout.fields.offset(i);
|
||||
classify(ccx, layout.field(ccx, i), cls, field_off)?;
|
||||
match layout.variants {
|
||||
layout::Variants::Single { .. } => {
|
||||
for i in 0..layout.fields.count() {
|
||||
let field_off = off + layout.fields.offset(i);
|
||||
classify(ccx, layout.field(ccx, i), cls, field_off)?;
|
||||
}
|
||||
}
|
||||
layout::Variants::Tagged { .. } |
|
||||
layout::Variants::NicheFilling { .. } => return Err(Memory),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1119,7 +1119,7 @@ fn prepare_union_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
// offset of zero bytes).
|
||||
struct EnumMemberDescriptionFactory<'tcx> {
|
||||
enum_type: Ty<'tcx>,
|
||||
type_rep: TyLayout<'tcx>,
|
||||
layout: TyLayout<'tcx>,
|
||||
discriminant_type_metadata: Option<DIType>,
|
||||
containing_scope: DIScope,
|
||||
span: Span,
|
||||
@ -1129,12 +1129,44 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
||||
fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
|
||||
-> Vec<MemberDescription> {
|
||||
let adt = &self.enum_type.ty_adt_def().unwrap();
|
||||
match self.type_rep.layout {
|
||||
layout::Layout::General { ref variants, .. } => {
|
||||
match self.layout.variants {
|
||||
layout::Variants::Single { .. } => {
|
||||
assert!(adt.variants.len() <= 1);
|
||||
|
||||
if adt.variants.is_empty() {
|
||||
vec![]
|
||||
} else {
|
||||
let (variant_type_metadata, member_description_factory) =
|
||||
describe_enum_variant(cx,
|
||||
self.layout,
|
||||
&adt.variants[0],
|
||||
NoDiscriminant,
|
||||
self.containing_scope,
|
||||
self.span);
|
||||
|
||||
let member_descriptions =
|
||||
member_description_factory.create_member_descriptions(cx);
|
||||
|
||||
set_members_of_composite_type(cx,
|
||||
variant_type_metadata,
|
||||
&member_descriptions[..]);
|
||||
vec![
|
||||
MemberDescription {
|
||||
name: "".to_string(),
|
||||
type_metadata: variant_type_metadata,
|
||||
offset: Size::from_bytes(0),
|
||||
size: self.layout.size,
|
||||
align: self.layout.align,
|
||||
flags: DIFlags::FlagZero
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
layout::Variants::Tagged { ref variants, .. } => {
|
||||
let discriminant_info = RegularDiscriminant(self.discriminant_type_metadata
|
||||
.expect(""));
|
||||
(0..variants.len()).map(|i| {
|
||||
let variant = self.type_rep.for_variant(i);
|
||||
let variant = self.layout.for_variant(i);
|
||||
let (variant_type_metadata, member_desc_factory) =
|
||||
describe_enum_variant(cx,
|
||||
variant,
|
||||
@ -1158,45 +1190,13 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
||||
flags: DIFlags::FlagZero
|
||||
}
|
||||
}).collect()
|
||||
},
|
||||
layout::Layout::Univariant => {
|
||||
assert!(adt.variants.len() <= 1);
|
||||
|
||||
if adt.variants.is_empty() {
|
||||
vec![]
|
||||
} else {
|
||||
let (variant_type_metadata, member_description_factory) =
|
||||
describe_enum_variant(cx,
|
||||
self.type_rep,
|
||||
&adt.variants[0],
|
||||
NoDiscriminant,
|
||||
self.containing_scope,
|
||||
self.span);
|
||||
|
||||
let member_descriptions =
|
||||
member_description_factory.create_member_descriptions(cx);
|
||||
|
||||
set_members_of_composite_type(cx,
|
||||
variant_type_metadata,
|
||||
&member_descriptions[..]);
|
||||
vec![
|
||||
MemberDescription {
|
||||
name: "".to_string(),
|
||||
type_metadata: variant_type_metadata,
|
||||
offset: Size::from_bytes(0),
|
||||
size: self.type_rep.size,
|
||||
align: self.type_rep.align,
|
||||
flags: DIFlags::FlagZero
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
layout::Layout::NullablePointer {
|
||||
layout::Variants::NicheFilling {
|
||||
nndiscr,
|
||||
discr,
|
||||
..
|
||||
} => {
|
||||
let variant = self.type_rep.for_variant(nndiscr as usize);
|
||||
let variant = self.layout.for_variant(nndiscr as usize);
|
||||
// Create a description of the non-null variant
|
||||
let (variant_type_metadata, member_description_factory) =
|
||||
describe_enum_variant(cx,
|
||||
@ -1237,8 +1237,8 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
||||
}
|
||||
}
|
||||
compute_field_path(cx, &mut name,
|
||||
self.type_rep,
|
||||
self.type_rep.fields.offset(0),
|
||||
self.layout,
|
||||
self.layout.fields.offset(0),
|
||||
discr.size(cx));
|
||||
name.push_str(&adt.variants[(1 - nndiscr) as usize].name.as_str());
|
||||
|
||||
@ -1253,8 +1253,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
||||
flags: DIFlags::FlagZero
|
||||
}
|
||||
]
|
||||
},
|
||||
ref l @ _ => bug!("Not an enum layout: {:#?}", l)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1429,21 +1428,20 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
}
|
||||
};
|
||||
|
||||
let type_rep = cx.layout_of(enum_type);
|
||||
let layout = cx.layout_of(enum_type);
|
||||
|
||||
let discriminant_type_metadata = match type_rep.layout {
|
||||
layout::Layout::NullablePointer { .. } |
|
||||
layout::Layout::Univariant { .. } => None,
|
||||
layout::Layout::General { discr, .. } => Some(discriminant_type_metadata(discr)),
|
||||
ref l @ _ => bug!("Not an enum layout: {:#?}", l)
|
||||
let discriminant_type_metadata = match layout.variants {
|
||||
layout::Variants::Single { .. } |
|
||||
layout::Variants::NicheFilling { .. } => None,
|
||||
layout::Variants::Tagged { discr, .. } => Some(discriminant_type_metadata(discr)),
|
||||
};
|
||||
|
||||
match (type_rep.abi, discriminant_type_metadata) {
|
||||
match (layout.abi, discriminant_type_metadata) {
|
||||
(layout::Abi::Scalar(_), Some(discr)) => return FinalMetadata(discr),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let (enum_type_size, enum_type_align) = type_rep.size_and_align();
|
||||
let (enum_type_size, enum_type_align) = layout.size_and_align();
|
||||
|
||||
let enum_name = CString::new(enum_name).unwrap();
|
||||
let unique_type_id_str = CString::new(
|
||||
@ -1471,7 +1469,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
enum_metadata,
|
||||
EnumMDF(EnumMemberDescriptionFactory {
|
||||
enum_type,
|
||||
type_rep,
|
||||
layout,
|
||||
discriminant_type_metadata,
|
||||
containing_scope,
|
||||
span,
|
||||
|
@ -394,12 +394,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
||||
},
|
||||
|
||||
"discriminant_value" => {
|
||||
match substs.type_at(0).sty {
|
||||
ty::TyAdt(adt, ..) if adt.is_enum() => {
|
||||
args[0].deref(bcx.ccx).trans_get_discr(bcx, ret_ty)
|
||||
}
|
||||
_ => C_null(llret_ty)
|
||||
}
|
||||
args[0].deref(bcx.ccx).trans_get_discr(bcx, ret_ty)
|
||||
}
|
||||
|
||||
"align_offset" => {
|
||||
|
@ -1094,8 +1094,26 @@ fn trans_const_adt<'a, 'tcx>(
|
||||
mir::AggregateKind::Adt(_, index, _, _) => index,
|
||||
_ => 0,
|
||||
};
|
||||
match l.layout {
|
||||
layout::Layout::General { .. } => {
|
||||
match l.variants {
|
||||
layout::Variants::Single { index } => {
|
||||
assert_eq!(variant_index, index);
|
||||
if let layout::Abi::Vector { .. } = l.abi {
|
||||
Const::new(C_vector(&vals.iter().map(|x| x.llval).collect::<Vec<_>>()), t)
|
||||
} else if let layout::FieldPlacement::Union(_) = l.fields {
|
||||
assert_eq!(variant_index, 0);
|
||||
assert_eq!(vals.len(), 1);
|
||||
let contents = [
|
||||
vals[0].llval,
|
||||
padding(ccx, l.size - ccx.size_of(vals[0].ty))
|
||||
];
|
||||
|
||||
Const::new(C_struct(ccx, &contents, l.is_packed()), t)
|
||||
} else {
|
||||
assert_eq!(variant_index, 0);
|
||||
build_const_struct(ccx, l, vals, None)
|
||||
}
|
||||
}
|
||||
layout::Variants::Tagged { .. } => {
|
||||
let discr = match *kind {
|
||||
mir::AggregateKind::Adt(adt_def, _, _, _) => {
|
||||
adt_def.discriminant_for_variant(ccx.tcx(), variant_index)
|
||||
@ -1112,23 +1130,7 @@ fn trans_const_adt<'a, 'tcx>(
|
||||
build_const_struct(ccx, l.for_variant(variant_index), vals, Some(discr))
|
||||
}
|
||||
}
|
||||
layout::Layout::UntaggedUnion => {
|
||||
assert_eq!(variant_index, 0);
|
||||
let contents = [
|
||||
vals[0].llval,
|
||||
padding(ccx, l.size - ccx.size_of(vals[0].ty))
|
||||
];
|
||||
|
||||
Const::new(C_struct(ccx, &contents, l.is_packed()), t)
|
||||
}
|
||||
layout::Layout::Univariant => {
|
||||
assert_eq!(variant_index, 0);
|
||||
build_const_struct(ccx, l, vals, None)
|
||||
}
|
||||
layout::Layout::Vector => {
|
||||
Const::new(C_vector(&vals.iter().map(|x| x.llval).collect::<Vec<_>>()), t)
|
||||
}
|
||||
layout::Layout::NullablePointer { nndiscr, .. } => {
|
||||
layout::Variants::NicheFilling { nndiscr, .. } => {
|
||||
if variant_index as u64 == nndiscr {
|
||||
build_const_struct(ccx, l.for_variant(variant_index), vals, None)
|
||||
} else {
|
||||
@ -1137,7 +1139,6 @@ fn trans_const_adt<'a, 'tcx>(
|
||||
Const::new(C_null(ccx.layout_of(t).llvm_type(ccx)), t)
|
||||
}
|
||||
}
|
||||
_ => bug!("trans_const_adt: cannot handle type {} repreented as {:#?}", t, l)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -296,10 +296,13 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
||||
/// Obtain the actual discriminant of a value.
|
||||
pub fn trans_get_discr(self, bcx: &Builder<'a, 'tcx>, cast_to: Ty<'tcx>) -> ValueRef {
|
||||
let cast_to = bcx.ccx.layout_of(cast_to).immediate_llvm_type(bcx.ccx);
|
||||
match self.layout.layout {
|
||||
layout::Layout::Univariant { .. } |
|
||||
layout::Layout::UntaggedUnion { .. } => return C_uint(cast_to, 0),
|
||||
_ => {}
|
||||
match self.layout.variants {
|
||||
layout::Variants::Single { index } => {
|
||||
assert_eq!(index, 0);
|
||||
return C_uint(cast_to, 0);
|
||||
}
|
||||
layout::Variants::Tagged { .. } |
|
||||
layout::Variants::NicheFilling { .. } => {},
|
||||
}
|
||||
|
||||
let discr = self.project_field(bcx, 0);
|
||||
@ -307,8 +310,10 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
||||
layout::Abi::Scalar(discr) => discr,
|
||||
_ => bug!("discriminant not scalar: {:#?}", discr.layout)
|
||||
};
|
||||
let (min, max) = match self.layout.layout {
|
||||
layout::Layout::General { ref discr_range, .. } => (discr_range.start, discr_range.end),
|
||||
let (min, max) = match self.layout.variants {
|
||||
layout::Variants::Tagged { ref discr_range, .. } => {
|
||||
(discr_range.start, discr_range.end)
|
||||
}
|
||||
_ => (0, u64::max_value()),
|
||||
};
|
||||
let max_next = max.wrapping_add(1);
|
||||
@ -333,20 +338,20 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
||||
bcx.load(discr.llval, discr.alignment.non_abi())
|
||||
}
|
||||
};
|
||||
match self.layout.layout {
|
||||
layout::Layout::General { .. } => {
|
||||
match self.layout.variants {
|
||||
layout::Variants::Single { .. } => bug!(),
|
||||
layout::Variants::Tagged { .. } => {
|
||||
let signed = match discr_scalar {
|
||||
layout::Int(_, signed) => signed,
|
||||
_ => false
|
||||
};
|
||||
bcx.intcast(lldiscr, cast_to, signed)
|
||||
}
|
||||
layout::Layout::NullablePointer { nndiscr, .. } => {
|
||||
layout::Variants::NicheFilling { nndiscr, .. } => {
|
||||
let cmp = if nndiscr == 0 { llvm::IntEQ } else { llvm::IntNE };
|
||||
let zero = C_null(discr.layout.llvm_type(bcx.ccx));
|
||||
bcx.intcast(bcx.icmp(cmp, lldiscr, zero), cast_to, false)
|
||||
}
|
||||
_ => bug!("{} is not an enum", self.layout.ty)
|
||||
}
|
||||
}
|
||||
|
||||
@ -356,13 +361,17 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
||||
let to = self.layout.ty.ty_adt_def().unwrap()
|
||||
.discriminant_for_variant(bcx.tcx(), variant_index)
|
||||
.to_u128_unchecked() as u64;
|
||||
match self.layout.layout {
|
||||
layout::Layout::General { .. } => {
|
||||
match self.layout.variants {
|
||||
layout::Variants::Single { index } => {
|
||||
assert_eq!(to, 0);
|
||||
assert_eq!(variant_index, index);
|
||||
}
|
||||
layout::Variants::Tagged { .. } => {
|
||||
let ptr = self.project_field(bcx, 0);
|
||||
bcx.store(C_int(ptr.layout.llvm_type(bcx.ccx), to as i64),
|
||||
ptr.llval, ptr.alignment.non_abi());
|
||||
}
|
||||
layout::Layout::NullablePointer { nndiscr, .. } => {
|
||||
layout::Variants::NicheFilling { nndiscr, .. } => {
|
||||
if to != nndiscr {
|
||||
let use_memset = match self.layout.abi {
|
||||
layout::Abi::Scalar(_) => false,
|
||||
@ -385,9 +394,6 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
assert_eq!(to, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
use llvm::{self, ValueRef};
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::ty::cast::{CastTy, IntTy};
|
||||
use rustc::ty::layout::{self, Layout, LayoutOf};
|
||||
use rustc::ty::layout::{self, LayoutOf};
|
||||
use rustc::mir;
|
||||
use rustc::middle::lang_items::ExchangeMallocFnLangItem;
|
||||
use rustc_apfloat::{ieee, Float, Status, Round};
|
||||
@ -278,8 +278,10 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
let ll_t_out = cast.immediate_llvm_type(bcx.ccx);
|
||||
let llval = operand.immediate();
|
||||
|
||||
if let Layout::General { ref discr_range, .. } = operand.layout.layout {
|
||||
if discr_range.end > discr_range.start {
|
||||
match operand.layout.variants {
|
||||
layout::Variants::Tagged {
|
||||
ref discr_range, ..
|
||||
} if discr_range.end > discr_range.start => {
|
||||
// We want `table[e as usize]` to not
|
||||
// have bound checks, and this is the most
|
||||
// convenient place to put the `assume`.
|
||||
@ -290,6 +292,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
C_uint(ll_t_in, discr_range.end)
|
||||
));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let signed = match operand.layout.abi {
|
||||
|
@ -40,8 +40,13 @@ fn uncached_llvm_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
let mut name = String::with_capacity(32);
|
||||
let printer = DefPathBasedNames::new(ccx.tcx(), true, true);
|
||||
printer.push_type_name(layout.ty, &mut name);
|
||||
if let (&ty::TyAdt(def, _), Some(v)) = (&layout.ty.sty, layout.variant_index) {
|
||||
write!(&mut name, "::{}", def.variants[v].name).unwrap();
|
||||
match (&layout.ty.sty, &layout.variants) {
|
||||
(&ty::TyAdt(def, _), &layout::Variants::Single { index }) => {
|
||||
if def.is_enum() && !def.variants.is_empty() {
|
||||
write!(&mut name, "::{}", def.variants[index].name).unwrap();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Some(name)
|
||||
}
|
||||
@ -206,7 +211,11 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
|
||||
|
||||
|
||||
// Check the cache.
|
||||
if let Some(&llty) = ccx.lltypes().borrow().get(&(self.ty, self.variant_index)) {
|
||||
let variant_index = match self.variants {
|
||||
layout::Variants::Single { index } => Some(index),
|
||||
_ => None
|
||||
};
|
||||
if let Some(&llty) = ccx.lltypes().borrow().get(&(self.ty, variant_index)) {
|
||||
return llty;
|
||||
}
|
||||
|
||||
@ -221,7 +230,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
|
||||
let mut defer = None;
|
||||
let llty = if self.ty != normal_ty {
|
||||
let mut layout = ccx.layout_of(normal_ty);
|
||||
if let Some(v) = self.variant_index {
|
||||
if let Some(v) = variant_index {
|
||||
layout = layout.for_variant(v);
|
||||
}
|
||||
layout.llvm_type(ccx)
|
||||
@ -230,7 +239,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
|
||||
};
|
||||
debug!("--> mapped {:#?} to llty={:?}", self, llty);
|
||||
|
||||
ccx.lltypes().borrow_mut().insert((self.ty, self.variant_index), llty);
|
||||
ccx.lltypes().borrow_mut().insert((self.ty, variant_index), llty);
|
||||
|
||||
if let Some((mut llty, layout)) = defer {
|
||||
llty.set_struct_body(&struct_llfields(ccx, layout), layout.is_packed())
|
||||
|
Loading…
x
Reference in New Issue
Block a user