Auto merge of #37429 - camlorn:univariant_layout_optimization, r=eddyb
struct field reordering and optimization This is work in progress. The goal is to divorce the order of fields in source code from the order of fields in the LLVM IR, then optimize structs (and tuples/enum variants)by always ordering fields from least to most aligned. It does not work yet. I intend to check compiler memory usage as a benchmark, and a crater run will probably be required. I don't know enough of the compiler to complete this work unaided. If you see places that still need updating, please mention them. The only one I know of currently is debuginfo, which I'm putting off intentionally until a bit later. r? @eddyb
This commit is contained in:
commit
8327b5afaf
@ -142,7 +142,12 @@ impl CodeStats {
|
||||
max_variant_size = cmp::max(max_variant_size, size);
|
||||
|
||||
let mut min_offset = discr_size;
|
||||
for field in fields {
|
||||
|
||||
// We want to print fields by increasing offset.
|
||||
let mut fields = fields.clone();
|
||||
fields.sort_by_key(|f| f.offset);
|
||||
|
||||
for field in fields.iter() {
|
||||
let FieldInfo { ref name, offset, size, align } = *field;
|
||||
|
||||
// Include field alignment in output only if it caused padding injection
|
||||
|
@ -24,6 +24,7 @@ use syntax_pos::DUMMY_SP;
|
||||
use std::cmp;
|
||||
use std::fmt;
|
||||
use std::i64;
|
||||
use std::iter;
|
||||
|
||||
/// Parsed [Data layout](http://llvm.org/docs/LangRef.html#data-layout)
|
||||
/// for a target, which contains everything needed to compute layouts.
|
||||
@ -415,7 +416,7 @@ impl Integer {
|
||||
/// signed discriminant range and #[repr] attribute.
|
||||
/// N.B.: u64 values above i64::MAX will be treated as signed, but
|
||||
/// that shouldn't affect anything, other than maybe debuginfo.
|
||||
pub fn repr_discr(tcx: TyCtxt, ty: Ty, hint: attr::ReprAttr, min: i64, max: i64)
|
||||
fn repr_discr(tcx: TyCtxt, ty: Ty, hints: &[attr::ReprAttr], min: i64, max: i64)
|
||||
-> (Integer, bool) {
|
||||
// Theoretically, negative values could be larger in unsigned representation
|
||||
// than the unsigned representation of the signed minimum. However, if there
|
||||
@ -424,34 +425,41 @@ impl Integer {
|
||||
let unsigned_fit = Integer::fit_unsigned(cmp::max(min as u64, max as u64));
|
||||
let signed_fit = cmp::max(Integer::fit_signed(min), Integer::fit_signed(max));
|
||||
|
||||
let at_least = match hint {
|
||||
attr::ReprInt(ity) => {
|
||||
let discr = Integer::from_attr(&tcx.data_layout, ity);
|
||||
let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
|
||||
if discr < fit {
|
||||
bug!("Integer::repr_discr: `#[repr]` hint too small for \
|
||||
discriminant range of enum `{}", ty)
|
||||
let mut min_from_extern = None;
|
||||
let min_default = I8;
|
||||
|
||||
for &r in hints.iter() {
|
||||
match r {
|
||||
attr::ReprInt(ity) => {
|
||||
let discr = Integer::from_attr(&tcx.data_layout, ity);
|
||||
let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
|
||||
if discr < fit {
|
||||
bug!("Integer::repr_discr: `#[repr]` hint too small for \
|
||||
discriminant range of enum `{}", ty)
|
||||
}
|
||||
return (discr, ity.is_signed());
|
||||
}
|
||||
return (discr, ity.is_signed());
|
||||
}
|
||||
attr::ReprExtern => {
|
||||
match &tcx.sess.target.target.arch[..] {
|
||||
// WARNING: the ARM EABI has two variants; the one corresponding
|
||||
// to `at_least == I32` appears to be used on Linux and NetBSD,
|
||||
// but some systems may use the variant corresponding to no
|
||||
// lower bound. However, we don't run on those yet...?
|
||||
"arm" => I32,
|
||||
_ => I32,
|
||||
attr::ReprExtern => {
|
||||
match &tcx.sess.target.target.arch[..] {
|
||||
// WARNING: the ARM EABI has two variants; the one corresponding
|
||||
// to `at_least == I32` appears to be used on Linux and NetBSD,
|
||||
// but some systems may use the variant corresponding to no
|
||||
// lower bound. However, we don't run on those yet...?
|
||||
"arm" => min_from_extern = Some(I32),
|
||||
_ => min_from_extern = Some(I32),
|
||||
}
|
||||
}
|
||||
attr::ReprAny => {},
|
||||
attr::ReprPacked => {
|
||||
bug!("Integer::repr_discr: found #[repr(packed)] on enum `{}", ty);
|
||||
}
|
||||
attr::ReprSimd => {
|
||||
bug!("Integer::repr_discr: found #[repr(simd)] on enum `{}", ty);
|
||||
}
|
||||
}
|
||||
attr::ReprAny => I8,
|
||||
attr::ReprPacked => {
|
||||
bug!("Integer::repr_discr: found #[repr(packed)] on enum `{}", ty);
|
||||
}
|
||||
attr::ReprSimd => {
|
||||
bug!("Integer::repr_discr: found #[repr(simd)] on enum `{}", ty);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let at_least = min_from_extern.unwrap_or(min_default);
|
||||
|
||||
// If there are no negative values, we can use the unsigned fit.
|
||||
if min >= 0 {
|
||||
@ -511,70 +519,158 @@ pub struct Struct {
|
||||
/// If true, the size is exact, otherwise it's only a lower bound.
|
||||
pub sized: bool,
|
||||
|
||||
/// Offsets for the first byte of each field.
|
||||
/// Offsets for the first byte of each field, ordered to match the source definition order.
|
||||
/// This vector does not go in increasing order.
|
||||
/// FIXME(eddyb) use small vector optimization for the common case.
|
||||
pub offsets: Vec<Size>,
|
||||
|
||||
/// Maps source order field indices to memory order indices, depending how fields were permuted.
|
||||
/// FIXME (camlorn) also consider small vector optimization here.
|
||||
pub memory_index: Vec<u32>,
|
||||
|
||||
pub min_size: Size,
|
||||
}
|
||||
|
||||
// Info required to optimize struct layout.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
|
||||
enum StructKind {
|
||||
// A tuple, closure, or univariant which cannot be coerced to unsized.
|
||||
AlwaysSizedUnivariant,
|
||||
// A univariant, the last field of which may be coerced to unsized.
|
||||
MaybeUnsizedUnivariant,
|
||||
// A univariant, but part of an enum.
|
||||
EnumVariant,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Struct {
|
||||
pub fn new(dl: &TargetDataLayout, packed: bool) -> Struct {
|
||||
Struct {
|
||||
// FIXME(camlorn): reprs need a better representation to deal with multiple reprs on one type.
|
||||
fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>,
|
||||
reprs: &[attr::ReprAttr], kind: StructKind,
|
||||
scapegoat: Ty<'gcx>) -> Result<Struct, LayoutError<'gcx>> {
|
||||
let packed = reprs.contains(&attr::ReprPacked);
|
||||
let mut ret = Struct {
|
||||
align: if packed { dl.i8_align } else { dl.aggregate_align },
|
||||
packed: packed,
|
||||
sized: true,
|
||||
offsets: vec![],
|
||||
memory_index: vec![],
|
||||
min_size: Size::from_bytes(0),
|
||||
};
|
||||
|
||||
// Anything with ReprExtern or ReprPacked doesn't optimize.
|
||||
// Neither do 1-member and 2-member structs.
|
||||
// In addition, code in trans assume that 2-element structs can become pairs.
|
||||
// It's easier to just short-circuit here.
|
||||
let mut can_optimize = fields.len() > 2 || StructKind::EnumVariant == kind;
|
||||
if can_optimize {
|
||||
// This exhaustive match makes new reprs force the adder to modify this function.
|
||||
// Otherwise, things can silently break.
|
||||
// Note the inversion, return true to stop optimizing.
|
||||
can_optimize = !reprs.iter().any(|r| {
|
||||
match *r {
|
||||
attr::ReprAny | attr::ReprInt(_) => false,
|
||||
attr::ReprExtern | attr::ReprPacked => true,
|
||||
attr::ReprSimd => bug!("Simd vectors should be represented as layout::Vector")
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Extend the Struct with more fields.
|
||||
pub fn extend<I>(&mut self, dl: &TargetDataLayout,
|
||||
fields: I,
|
||||
scapegoat: Ty<'gcx>)
|
||||
-> Result<(), LayoutError<'gcx>>
|
||||
where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
|
||||
self.offsets.reserve(fields.size_hint().0);
|
||||
let (optimize, sort_ascending) = match kind {
|
||||
StructKind::AlwaysSizedUnivariant => (can_optimize, false),
|
||||
StructKind::MaybeUnsizedUnivariant => (can_optimize, false),
|
||||
StructKind::EnumVariant => {
|
||||
assert!(fields.len() >= 1, "Enum variants must have discriminants.");
|
||||
(can_optimize && fields[0].size(dl).bytes() == 1, true)
|
||||
}
|
||||
};
|
||||
|
||||
let mut offset = self.min_size;
|
||||
ret.offsets = vec![Size::from_bytes(0); fields.len()];
|
||||
let mut inverse_memory_index: Vec<u32> = (0..fields.len() as u32).collect();
|
||||
|
||||
for field in fields {
|
||||
if !self.sized {
|
||||
bug!("Struct::extend: field #{} of `{}` comes after unsized field",
|
||||
self.offsets.len(), scapegoat);
|
||||
if optimize {
|
||||
let start = if let StructKind::EnumVariant = kind { 1 } else { 0 };
|
||||
let end = if let StructKind::MaybeUnsizedUnivariant = kind {
|
||||
fields.len() - 1
|
||||
} else {
|
||||
fields.len()
|
||||
};
|
||||
if end > start {
|
||||
let optimizing = &mut inverse_memory_index[start..end];
|
||||
if sort_ascending {
|
||||
optimizing.sort_by_key(|&x| fields[x as usize].align(dl).abi());
|
||||
} else {
|
||||
optimizing.sort_by(| &a, &b | {
|
||||
let a = fields[a as usize].align(dl).abi();
|
||||
let b = fields[b as usize].align(dl).abi();
|
||||
b.cmp(&a)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// inverse_memory_index holds field indices by increasing memory offset.
|
||||
// That is, if field 5 has offset 0, the first element of inverse_memory_index is 5.
|
||||
// We now write field offsets to the corresponding offset slot;
|
||||
// field 5 with offset 0 puts 0 in offsets[5].
|
||||
// At the bottom of this function, we use inverse_memory_index to produce memory_index.
|
||||
|
||||
if let StructKind::EnumVariant = kind {
|
||||
assert_eq!(inverse_memory_index[0], 0,
|
||||
"Enum variant discriminants must have the lowest offset.");
|
||||
}
|
||||
|
||||
let mut offset = Size::from_bytes(0);
|
||||
|
||||
for i in inverse_memory_index.iter() {
|
||||
let field = fields[*i as usize];
|
||||
if !ret.sized {
|
||||
bug!("Struct::new: field #{} of `{}` comes after unsized field",
|
||||
ret.offsets.len(), scapegoat);
|
||||
}
|
||||
|
||||
let field = field?;
|
||||
if field.is_unsized() {
|
||||
self.sized = false;
|
||||
ret.sized = false;
|
||||
}
|
||||
|
||||
// Invariant: offset < dl.obj_size_bound() <= 1<<61
|
||||
if !self.packed {
|
||||
if !ret.packed {
|
||||
let align = field.align(dl);
|
||||
self.align = self.align.max(align);
|
||||
ret.align = ret.align.max(align);
|
||||
offset = offset.abi_align(align);
|
||||
}
|
||||
|
||||
self.offsets.push(offset);
|
||||
|
||||
debug!("Struct::extend offset: {:?} field: {:?} {:?}", offset, field, field.size(dl));
|
||||
debug!("Struct::new offset: {:?} field: {:?} {:?}", offset, field, field.size(dl));
|
||||
ret.offsets[*i as usize] = offset;
|
||||
|
||||
offset = offset.checked_add(field.size(dl), dl)
|
||||
.map_or(Err(LayoutError::SizeOverflow(scapegoat)), Ok)?;
|
||||
}
|
||||
|
||||
debug!("Struct::extend min_size: {:?}", offset);
|
||||
|
||||
self.min_size = offset;
|
||||
debug!("Struct::new min_size: {:?}", offset);
|
||||
ret.min_size = offset;
|
||||
|
||||
Ok(())
|
||||
// As stated above, inverse_memory_index holds field indices by increasing offset.
|
||||
// This makes it an already-sorted view of the offsets vec.
|
||||
// To invert it, consider:
|
||||
// If field 5 has offset 0, offsets[0] is 5, and memory_index[5] should be 0.
|
||||
// Field 5 would be the first element, so memory_index is i:
|
||||
// Note: if we didn't optimize, it's already right.
|
||||
|
||||
if optimize {
|
||||
ret.memory_index = vec![0; inverse_memory_index.len()];
|
||||
|
||||
for i in 0..inverse_memory_index.len() {
|
||||
ret.memory_index[inverse_memory_index[i] as usize] = i as u32;
|
||||
}
|
||||
} else {
|
||||
ret.memory_index = inverse_memory_index;
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
/// Get the size without trailing alignment padding.
|
||||
|
||||
/// Get the size with trailing aligment padding.
|
||||
/// Get the size with trailing alignment padding.
|
||||
pub fn stride(&self) -> Size {
|
||||
self.min_size.abi_align(self.align)
|
||||
}
|
||||
@ -592,18 +688,45 @@ impl<'a, 'gcx, 'tcx> Struct {
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
/// Get indices of the tys that made this struct by increasing offset.
|
||||
#[inline]
|
||||
pub fn field_index_by_increasing_offset<'b>(&'b self) -> impl iter::Iterator<Item=usize>+'b {
|
||||
let mut inverse_small = [0u8; 64];
|
||||
let mut inverse_big = vec![];
|
||||
let use_small = self.memory_index.len() <= inverse_small.len();
|
||||
|
||||
// We have to write this logic twice in order to keep the array small.
|
||||
if use_small {
|
||||
for i in 0..self.memory_index.len() {
|
||||
inverse_small[self.memory_index[i] as usize] = i as u8;
|
||||
}
|
||||
} else {
|
||||
inverse_big = vec![0; self.memory_index.len()];
|
||||
for i in 0..self.memory_index.len() {
|
||||
inverse_big[self.memory_index[i] as usize] = i as u32;
|
||||
}
|
||||
}
|
||||
|
||||
(0..self.memory_index.len()).map(move |i| {
|
||||
if use_small { inverse_small[i] as usize }
|
||||
else { inverse_big[i] as usize }
|
||||
})
|
||||
}
|
||||
|
||||
/// Find the path leading to a non-zero leaf field, starting from
|
||||
/// the given type and recursing through aggregates.
|
||||
/// The tuple is `(path, source_path)`,
|
||||
/// where `path` is in memory order and `source_path` in source order.
|
||||
// FIXME(eddyb) track value ranges and traverse already optimized enums.
|
||||
pub fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
ty: Ty<'gcx>)
|
||||
-> Result<Option<FieldPath>, LayoutError<'gcx>> {
|
||||
fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
ty: Ty<'gcx>)
|
||||
-> Result<Option<(FieldPath, FieldPath)>, LayoutError<'gcx>> {
|
||||
let tcx = infcx.tcx.global_tcx();
|
||||
match (ty.layout(infcx)?, &ty.sty) {
|
||||
(&Scalar { non_zero: true, .. }, _) |
|
||||
(&CEnum { non_zero: true, .. }, _) => Ok(Some(vec![])),
|
||||
(&CEnum { non_zero: true, .. }, _) => Ok(Some((vec![], vec![]))),
|
||||
(&FatPointer { non_zero: true, .. }, _) => {
|
||||
Ok(Some(vec![FAT_PTR_ADDR as u32]))
|
||||
Ok(Some((vec![FAT_PTR_ADDR as u32], vec![FAT_PTR_ADDR as u32])))
|
||||
}
|
||||
|
||||
// Is this the NonZero lang item wrapping a pointer or integer type?
|
||||
@ -614,10 +737,11 @@ impl<'a, 'gcx, 'tcx> Struct {
|
||||
// FIXME(eddyb) also allow floating-point types here.
|
||||
Scalar { value: Int(_), non_zero: false } |
|
||||
Scalar { value: Pointer, non_zero: false } => {
|
||||
Ok(Some(vec![0]))
|
||||
Ok(Some((vec![0], vec![0])))
|
||||
}
|
||||
FatPointer { non_zero: false, .. } => {
|
||||
Ok(Some(vec![FAT_PTR_ADDR as u32, 0]))
|
||||
let tmp = vec![FAT_PTR_ADDR as u32, 0];
|
||||
Ok(Some((tmp.clone(), tmp)))
|
||||
}
|
||||
_ => Ok(None)
|
||||
}
|
||||
@ -625,27 +749,30 @@ impl<'a, 'gcx, 'tcx> Struct {
|
||||
|
||||
// Perhaps one of the fields of this struct is non-zero
|
||||
// let's recurse and find out
|
||||
(_, &ty::TyAdt(def, substs)) if def.is_struct() => {
|
||||
Struct::non_zero_field_path(infcx, def.struct_variant().fields
|
||||
(&Univariant { ref variant, .. }, &ty::TyAdt(def, substs)) if def.is_struct() => {
|
||||
Struct::non_zero_field_paths(infcx, def.struct_variant().fields
|
||||
.iter().map(|field| {
|
||||
field.ty(tcx, substs)
|
||||
}))
|
||||
}),
|
||||
Some(&variant.memory_index[..]))
|
||||
}
|
||||
|
||||
// Perhaps one of the upvars of this closure is non-zero
|
||||
// Let's recurse and find out!
|
||||
(_, &ty::TyClosure(def_id, ref substs)) => {
|
||||
Struct::non_zero_field_path(infcx, substs.upvar_tys(def_id, tcx))
|
||||
(&Univariant { ref variant, .. }, &ty::TyClosure(def, substs)) => {
|
||||
let upvar_tys = substs.upvar_tys(def, tcx);
|
||||
Struct::non_zero_field_paths(infcx, upvar_tys,
|
||||
Some(&variant.memory_index[..]))
|
||||
}
|
||||
// Can we use one of the fields in this tuple?
|
||||
(_, &ty::TyTuple(tys)) => {
|
||||
Struct::non_zero_field_path(infcx, tys.iter().cloned())
|
||||
(&Univariant { ref variant, .. }, &ty::TyTuple(tys)) => {
|
||||
Struct::non_zero_field_paths(infcx, tys.iter().cloned(),
|
||||
Some(&variant.memory_index[..]))
|
||||
}
|
||||
|
||||
// Is this a fixed-size array of something non-zero
|
||||
// with at least one element?
|
||||
(_, &ty::TyArray(ety, d)) if d > 0 => {
|
||||
Struct::non_zero_field_path(infcx, Some(ety).into_iter())
|
||||
Struct::non_zero_field_paths(infcx, Some(ety).into_iter(), None)
|
||||
}
|
||||
|
||||
(_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => {
|
||||
@ -663,14 +790,23 @@ impl<'a, 'gcx, 'tcx> Struct {
|
||||
|
||||
/// Find the path leading to a non-zero leaf field, starting from
|
||||
/// the given set of fields and recursing through aggregates.
|
||||
pub fn non_zero_field_path<I>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
fields: I)
|
||||
-> Result<Option<FieldPath>, LayoutError<'gcx>>
|
||||
/// Returns Some((path, source_path)) on success.
|
||||
/// `path` is translated to memory order. `source_path` is not.
|
||||
fn non_zero_field_paths<I>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
fields: I,
|
||||
permutation: Option<&[u32]>)
|
||||
-> Result<Option<(FieldPath, FieldPath)>, LayoutError<'gcx>>
|
||||
where I: Iterator<Item=Ty<'gcx>> {
|
||||
for (i, ty) in fields.enumerate() {
|
||||
if let Some(mut path) = Struct::non_zero_field_in_type(infcx, ty)? {
|
||||
path.push(i as u32);
|
||||
return Ok(Some(path));
|
||||
if let Some((mut path, mut source_path)) = Struct::non_zero_field_in_type(infcx, ty)? {
|
||||
source_path.push(i as u32);
|
||||
let index = if let Some(p) = permutation {
|
||||
p[i] as usize
|
||||
} else {
|
||||
i
|
||||
};
|
||||
path.push(index as u32);
|
||||
return Ok(Some((path, source_path)));
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
@ -723,7 +859,7 @@ impl<'a, 'gcx, 'tcx> Union {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the size with trailing aligment padding.
|
||||
/// Get the size with trailing alignment padding.
|
||||
pub fn stride(&self) -> Size {
|
||||
self.min_size.abi_align(self.align)
|
||||
}
|
||||
@ -833,7 +969,9 @@ pub enum Layout {
|
||||
nndiscr: u64,
|
||||
nonnull: Struct,
|
||||
// N.B. There is a 0 at the start, for LLVM GEP through a pointer.
|
||||
discrfield: FieldPath
|
||||
discrfield: FieldPath,
|
||||
// Like discrfield, but in source order. For debuginfo.
|
||||
discrfield_source: FieldPath
|
||||
}
|
||||
}
|
||||
|
||||
@ -887,6 +1025,7 @@ impl<'a, 'gcx, 'tcx> Layout {
|
||||
let dl = &tcx.data_layout;
|
||||
assert!(!ty.has_infer_types());
|
||||
|
||||
|
||||
let layout = match ty.sty {
|
||||
// Basic scalars.
|
||||
ty::TyBool => Scalar { value: Int(I1), non_zero: false },
|
||||
@ -908,7 +1047,11 @@ impl<'a, 'gcx, 'tcx> Layout {
|
||||
ty::TyFnPtr(_) => Scalar { value: Pointer, non_zero: true },
|
||||
|
||||
// The never type.
|
||||
ty::TyNever => Univariant { variant: Struct::new(dl, false), non_zero: false },
|
||||
ty::TyNever => Univariant {
|
||||
variant: Struct::new(dl, &vec![], &[],
|
||||
StructKind::AlwaysSizedUnivariant, ty)?,
|
||||
non_zero: false
|
||||
},
|
||||
|
||||
// Potentially-fat pointers.
|
||||
ty::TyBox(pointee) |
|
||||
@ -959,27 +1102,36 @@ impl<'a, 'gcx, 'tcx> Layout {
|
||||
// Odd unit types.
|
||||
ty::TyFnDef(..) => {
|
||||
Univariant {
|
||||
variant: Struct::new(dl, false),
|
||||
variant: Struct::new(dl, &vec![],
|
||||
&[], StructKind::AlwaysSizedUnivariant, ty)?,
|
||||
non_zero: false
|
||||
}
|
||||
}
|
||||
ty::TyDynamic(..) => {
|
||||
let mut unit = Struct::new(dl, false);
|
||||
let mut unit = Struct::new(dl, &vec![], &[],
|
||||
StructKind::AlwaysSizedUnivariant, ty)?;
|
||||
unit.sized = false;
|
||||
Univariant { variant: unit, non_zero: false }
|
||||
}
|
||||
|
||||
// Tuples and closures.
|
||||
ty::TyClosure(def_id, ref substs) => {
|
||||
let mut st = Struct::new(dl, false);
|
||||
let tys = substs.upvar_tys(def_id, tcx);
|
||||
st.extend(dl, tys.map(|ty| ty.layout(infcx)), ty)?;
|
||||
let st = Struct::new(dl,
|
||||
&tys.map(|ty| ty.layout(infcx))
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
&[],
|
||||
StructKind::AlwaysSizedUnivariant, ty)?;
|
||||
Univariant { variant: st, non_zero: false }
|
||||
}
|
||||
|
||||
ty::TyTuple(tys) => {
|
||||
let mut st = Struct::new(dl, false);
|
||||
st.extend(dl, tys.iter().map(|ty| ty.layout(infcx)), ty)?;
|
||||
// FIXME(camlorn): if we ever allow unsized tuples, this needs to be checked.
|
||||
// See the univariant case below to learn how.
|
||||
let st = Struct::new(dl,
|
||||
&tys.iter().map(|ty| ty.layout(infcx))
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
&[], StructKind::AlwaysSizedUnivariant, ty)?;
|
||||
Univariant { variant: st, non_zero: false }
|
||||
}
|
||||
|
||||
@ -1003,16 +1155,16 @@ impl<'a, 'gcx, 'tcx> Layout {
|
||||
|
||||
// ADTs.
|
||||
ty::TyAdt(def, substs) => {
|
||||
let hint = *tcx.lookup_repr_hints(def.did).get(0)
|
||||
.unwrap_or(&attr::ReprAny);
|
||||
let hints = &tcx.lookup_repr_hints(def.did)[..];
|
||||
|
||||
if def.variants.is_empty() {
|
||||
// Uninhabitable; represent as unit
|
||||
// (Typechecking will reject discriminant-sizing attrs.)
|
||||
assert_eq!(hint, attr::ReprAny);
|
||||
assert_eq!(hints.len(), 0);
|
||||
|
||||
return success(Univariant {
|
||||
variant: Struct::new(dl, false),
|
||||
variant: Struct::new(dl, &vec![],
|
||||
&hints[..], StructKind::AlwaysSizedUnivariant, ty)?,
|
||||
non_zero: false
|
||||
});
|
||||
}
|
||||
@ -1027,7 +1179,7 @@ impl<'a, 'gcx, 'tcx> Layout {
|
||||
if x > max { max = x; }
|
||||
}
|
||||
|
||||
let (discr, signed) = Integer::repr_discr(tcx, ty, hint, min, max);
|
||||
let (discr, signed) = Integer::repr_discr(tcx, ty, &hints[..], min, max);
|
||||
return success(CEnum {
|
||||
discr: discr,
|
||||
signed: signed,
|
||||
@ -1037,21 +1189,35 @@ impl<'a, 'gcx, 'tcx> Layout {
|
||||
});
|
||||
}
|
||||
|
||||
if !def.is_enum() || def.variants.len() == 1 && hint == attr::ReprAny {
|
||||
if !def.is_enum() || def.variants.len() == 1 && hints.is_empty() {
|
||||
// Struct, or union, or univariant enum equivalent to a struct.
|
||||
// (Typechecking will reject discriminant-sizing attrs.)
|
||||
|
||||
let kind = if def.is_enum() || def.variants[0].fields.len() == 0{
|
||||
StructKind::AlwaysSizedUnivariant
|
||||
} else {
|
||||
use middle::region::ROOT_CODE_EXTENT;
|
||||
let param_env = tcx.construct_parameter_environment(DUMMY_SP,
|
||||
def.did, ROOT_CODE_EXTENT);
|
||||
let fields = &def.variants[0].fields;
|
||||
let last_field = &fields[fields.len()-1];
|
||||
let always_sized = last_field.ty(tcx, param_env.free_substs)
|
||||
.is_sized(tcx, ¶m_env, DUMMY_SP);
|
||||
if !always_sized { StructKind::MaybeUnsizedUnivariant }
|
||||
else { StructKind::AlwaysSizedUnivariant }
|
||||
};
|
||||
|
||||
let fields = def.variants[0].fields.iter().map(|field| {
|
||||
field.ty(tcx, substs).layout(infcx)
|
||||
});
|
||||
}).collect::<Result<Vec<_>, _>>()?;
|
||||
let packed = tcx.lookup_packed(def.did);
|
||||
let layout = if def.is_union() {
|
||||
let mut un = Union::new(dl, packed);
|
||||
un.extend(dl, fields, ty)?;
|
||||
un.extend(dl, fields.iter().map(|&f| Ok(f)), ty)?;
|
||||
UntaggedUnion { variants: un }
|
||||
} else {
|
||||
let mut st = Struct::new(dl, packed);
|
||||
st.extend(dl, fields, ty)?;
|
||||
let st = Struct::new(dl, &fields, &hints[..],
|
||||
kind, ty)?;
|
||||
let non_zero = Some(def.did) == tcx.lang_items.non_zero();
|
||||
Univariant { variant: st, non_zero: non_zero }
|
||||
};
|
||||
@ -1073,7 +1239,7 @@ impl<'a, 'gcx, 'tcx> Layout {
|
||||
v.fields.iter().map(|field| field.ty(tcx, substs)).collect::<Vec<_>>()
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
if variants.len() == 2 && hint == attr::ReprAny {
|
||||
if variants.len() == 2 && hints.is_empty() {
|
||||
// Nullable pointer optimization
|
||||
for discr in 0..2 {
|
||||
let other_fields = variants[1 - discr].iter().map(|ty| {
|
||||
@ -1082,9 +1248,11 @@ impl<'a, 'gcx, 'tcx> Layout {
|
||||
if !Struct::would_be_zero_sized(dl, other_fields)? {
|
||||
continue;
|
||||
}
|
||||
let path = Struct::non_zero_field_path(infcx,
|
||||
variants[discr].iter().cloned())?;
|
||||
let mut path = if let Some(p) = path { p } else { continue };
|
||||
let paths = Struct::non_zero_field_paths(infcx,
|
||||
variants[discr].iter().cloned(),
|
||||
None)?;
|
||||
let (mut path, mut path_source) = if let Some(p) = paths { p }
|
||||
else { continue };
|
||||
|
||||
// FIXME(eddyb) should take advantage of a newtype.
|
||||
if path == &[0] && variants[discr].len() == 1 {
|
||||
@ -1101,14 +1269,25 @@ impl<'a, 'gcx, 'tcx> Layout {
|
||||
});
|
||||
}
|
||||
|
||||
let st = Struct::new(dl,
|
||||
&variants[discr].iter().map(|ty| ty.layout(infcx))
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
&hints[..], StructKind::AlwaysSizedUnivariant, ty)?;
|
||||
|
||||
// We have to fix the last element of path here.
|
||||
let mut i = *path.last().unwrap();
|
||||
i = st.memory_index[i as usize];
|
||||
*path.last_mut().unwrap() = i;
|
||||
path.push(0); // For GEP through a pointer.
|
||||
path.reverse();
|
||||
let mut st = Struct::new(dl, false);
|
||||
st.extend(dl, variants[discr].iter().map(|ty| ty.layout(infcx)), ty)?;
|
||||
path_source.push(0);
|
||||
path_source.reverse();
|
||||
|
||||
return success(StructWrappedNullablePointer {
|
||||
nndiscr: discr as u64,
|
||||
nonnull: st,
|
||||
discrfield: path
|
||||
discrfield: path,
|
||||
discrfield_source: path_source
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1116,7 +1295,7 @@ impl<'a, 'gcx, 'tcx> Layout {
|
||||
// The general case.
|
||||
let discr_max = (variants.len() - 1) as i64;
|
||||
assert!(discr_max >= 0);
|
||||
let (min_ity, _) = Integer::repr_discr(tcx, ty, hint, 0, discr_max);
|
||||
let (min_ity, _) = Integer::repr_discr(tcx, ty, &hints[..], 0, discr_max);
|
||||
|
||||
let mut align = dl.aggregate_align;
|
||||
let mut size = Size::from_bytes(0);
|
||||
@ -1126,24 +1305,26 @@ impl<'a, 'gcx, 'tcx> Layout {
|
||||
|
||||
// Create the set of structs that represent each variant
|
||||
// Use the minimum integer type we figured out above
|
||||
let discr = Some(Scalar { value: Int(min_ity), non_zero: false });
|
||||
let discr = Scalar { value: Int(min_ity), non_zero: false };
|
||||
let mut variants = variants.into_iter().map(|fields| {
|
||||
let mut found_start = false;
|
||||
let fields = fields.into_iter().map(|field| {
|
||||
let field = field.layout(infcx)?;
|
||||
if !found_start {
|
||||
// Find the first field we can't move later
|
||||
// to make room for a larger discriminant.
|
||||
let field_align = field.align(dl);
|
||||
if field.size(dl).bytes() != 0 || field_align.abi() != 1 {
|
||||
start_align = start_align.min(field_align);
|
||||
found_start = true;
|
||||
}
|
||||
let mut fields = fields.into_iter().map(|field| {
|
||||
field.layout(infcx)
|
||||
}).collect::<Result<Vec<_>, _>>()?;
|
||||
fields.insert(0, &discr);
|
||||
let st = Struct::new(dl,
|
||||
&fields,
|
||||
&hints[..], StructKind::EnumVariant, ty)?;
|
||||
// Find the first field we can't move later
|
||||
// to make room for a larger discriminant.
|
||||
// It is important to skip the first field.
|
||||
for i in st.field_index_by_increasing_offset().skip(1) {
|
||||
let field = fields[i];
|
||||
let field_align = field.align(dl);
|
||||
if field.size(dl).bytes() != 0 || field_align.abi() != 1 {
|
||||
start_align = start_align.min(field_align);
|
||||
break;
|
||||
}
|
||||
Ok(field)
|
||||
});
|
||||
let mut st = Struct::new(dl, false);
|
||||
st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?;
|
||||
}
|
||||
size = cmp::max(size, st.min_size);
|
||||
align = align.max(st.align);
|
||||
Ok(st)
|
||||
@ -1177,11 +1358,12 @@ impl<'a, 'gcx, 'tcx> Layout {
|
||||
let old_ity_size = Int(min_ity).size(dl);
|
||||
let new_ity_size = Int(ity).size(dl);
|
||||
for variant in &mut variants {
|
||||
for offset in &mut variant.offsets[1..] {
|
||||
if *offset > old_ity_size {
|
||||
break;
|
||||
for i in variant.offsets.iter_mut() {
|
||||
// The first field is the discrimminant, at offset 0.
|
||||
// These aren't in order, and we need to skip it.
|
||||
if *i <= old_ity_size && *i > Size::from_bytes(0) {
|
||||
*i = new_ity_size;
|
||||
}
|
||||
*offset = new_ity_size;
|
||||
}
|
||||
// We might be making the struct larger.
|
||||
if variant.min_size <= old_ity_size {
|
||||
|
@ -31,6 +31,7 @@ mod imp {
|
||||
mod os {
|
||||
use libc;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct flock {
|
||||
pub l_type: libc::c_short,
|
||||
pub l_whence: libc::c_short,
|
||||
@ -53,6 +54,7 @@ mod imp {
|
||||
mod os {
|
||||
use libc;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct flock {
|
||||
pub l_start: libc::off_t,
|
||||
pub l_len: libc::off_t,
|
||||
@ -76,6 +78,7 @@ mod imp {
|
||||
mod os {
|
||||
use libc;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct flock {
|
||||
pub l_start: libc::off_t,
|
||||
pub l_len: libc::off_t,
|
||||
@ -98,6 +101,7 @@ mod imp {
|
||||
mod os {
|
||||
use libc;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct flock {
|
||||
pub l_type: libc::c_short,
|
||||
pub l_whence: libc::c_short,
|
||||
@ -119,6 +123,7 @@ mod imp {
|
||||
mod os {
|
||||
use libc;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct flock {
|
||||
pub l_start: libc::off_t,
|
||||
pub l_len: libc::off_t,
|
||||
@ -141,6 +146,7 @@ mod imp {
|
||||
mod os {
|
||||
use libc;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct flock {
|
||||
pub l_type: libc::c_short,
|
||||
pub l_whence: libc::c_short,
|
||||
|
@ -750,7 +750,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
|
||||
if let Layout::General { ref variants, ref size, discr, .. } = *layout {
|
||||
let discr_size = Primitive::Int(discr).size(&cx.tcx.data_layout).bytes();
|
||||
|
||||
debug!("enum `{}` is {} bytes large", t, size.bytes());
|
||||
debug!("enum `{}` is {} bytes large with layout:\n{:#?}",
|
||||
t, size.bytes(), layout);
|
||||
|
||||
let (largest, slargest, largest_index) = enum_definition.variants
|
||||
.iter()
|
||||
|
@ -151,14 +151,14 @@ pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
| layout::UntaggedUnion { .. } | layout::RawNullablePointer { .. } => { }
|
||||
layout::Univariant { ..}
|
||||
| layout::StructWrappedNullablePointer { .. } => {
|
||||
let (nonnull_variant, packed) = match *l {
|
||||
layout::Univariant { ref variant, .. } => (0, variant.packed),
|
||||
let (nonnull_variant_index, nonnull_variant, packed) = match *l {
|
||||
layout::Univariant { ref variant, .. } => (0, variant, variant.packed),
|
||||
layout::StructWrappedNullablePointer { nndiscr, ref nonnull, .. } =>
|
||||
(nndiscr, nonnull.packed),
|
||||
(nndiscr, nonnull, nonnull.packed),
|
||||
_ => unreachable!()
|
||||
};
|
||||
let fields = compute_fields(cx, t, nonnull_variant as usize, true);
|
||||
llty.set_struct_body(&struct_llfields(cx, &fields, false, false),
|
||||
let fields = compute_fields(cx, t, nonnull_variant_index as usize, true);
|
||||
llty.set_struct_body(&struct_llfields(cx, &fields, nonnull_variant, false, false),
|
||||
packed)
|
||||
},
|
||||
_ => bug!("This function cannot handle {} with layout {:#?}", t, l)
|
||||
@ -188,7 +188,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
let fields = compute_fields(cx, t, nndiscr as usize, false);
|
||||
match name {
|
||||
None => {
|
||||
Type::struct_(cx, &struct_llfields(cx, &fields, sizing, dst),
|
||||
Type::struct_(cx, &struct_llfields(cx, &fields, nonnull, sizing, dst),
|
||||
nonnull.packed)
|
||||
}
|
||||
Some(name) => {
|
||||
@ -203,7 +203,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
let fields = compute_fields(cx, t, 0, true);
|
||||
match name {
|
||||
None => {
|
||||
let fields = struct_llfields(cx, &fields, sizing, dst);
|
||||
let fields = struct_llfields(cx, &fields, &variant, sizing, dst);
|
||||
Type::struct_(cx, &fields, variant.packed)
|
||||
}
|
||||
Some(name) => {
|
||||
@ -291,12 +291,14 @@ fn union_fill(cx: &CrateContext, size: u64, align: u64) -> Type {
|
||||
|
||||
|
||||
fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fields: &Vec<Ty<'tcx>>,
|
||||
variant: &layout::Struct,
|
||||
sizing: bool, dst: bool) -> Vec<Type> {
|
||||
let fields = variant.field_index_by_increasing_offset().map(|i| fields[i as usize]);
|
||||
if sizing {
|
||||
fields.iter().filter(|&ty| !dst || type_is_sized(cx.tcx(), *ty))
|
||||
.map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
|
||||
fields.filter(|ty| !dst || type_is_sized(cx.tcx(), *ty))
|
||||
.map(|ty| type_of::sizing_type_of(cx, ty)).collect()
|
||||
} else {
|
||||
fields.iter().map(|&ty| type_of::in_memory_type_of(cx, ty)).collect()
|
||||
fields.map(|ty| type_of::in_memory_type_of(cx, ty)).collect()
|
||||
}
|
||||
}
|
||||
|
||||
@ -564,16 +566,16 @@ pub fn trans_field_ptr_builder<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
|
||||
fn struct_field_ptr<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
|
||||
st: &layout::Struct, fields: &Vec<Ty<'tcx>>, val: MaybeSizedValue,
|
||||
ix: usize, needs_cast: bool) -> ValueRef {
|
||||
let ccx = bcx.ccx();
|
||||
let fty = fields[ix];
|
||||
let ccx = bcx.ccx();
|
||||
let ll_fty = type_of::in_memory_type_of(bcx.ccx(), fty);
|
||||
if bcx.is_unreachable() {
|
||||
return C_undef(ll_fty.ptr_to());
|
||||
}
|
||||
|
||||
let ptr_val = if needs_cast {
|
||||
let fields = fields.iter().map(|&ty| {
|
||||
type_of::in_memory_type_of(ccx, ty)
|
||||
let fields = st.field_index_by_increasing_offset().map(|i| {
|
||||
type_of::in_memory_type_of(ccx, fields[i])
|
||||
}).collect::<Vec<_>>();
|
||||
let real_ty = Type::struct_(ccx, &fields[..], st.packed);
|
||||
bcx.pointercast(val.value, real_ty.ptr_to())
|
||||
@ -585,15 +587,15 @@ fn struct_field_ptr<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
|
||||
// * First field - Always aligned properly
|
||||
// * Packed struct - There is no alignment padding
|
||||
// * Field is sized - pointer is properly aligned already
|
||||
if ix == 0 || st.packed || type_is_sized(bcx.tcx(), fty) {
|
||||
return bcx.struct_gep(ptr_val, ix);
|
||||
if st.offsets[ix] == layout::Size::from_bytes(0) || st.packed || type_is_sized(bcx.tcx(), fty) {
|
||||
return bcx.struct_gep(ptr_val, st.memory_index[ix] as usize);
|
||||
}
|
||||
|
||||
// If the type of the last field is [T] or str, then we don't need to do
|
||||
// any adjusments
|
||||
match fty.sty {
|
||||
ty::TySlice(..) | ty::TyStr => {
|
||||
return bcx.struct_gep(ptr_val, ix);
|
||||
return bcx.struct_gep(ptr_val, st.memory_index[ix] as usize);
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
@ -755,8 +757,12 @@ fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
// offset of current value
|
||||
let mut offset = 0;
|
||||
let mut cfields = Vec::new();
|
||||
let offsets = st.offsets.iter().map(|i| i.bytes());
|
||||
for (&val, target_offset) in vals.iter().zip(offsets) {
|
||||
cfields.reserve(st.offsets.len()*2);
|
||||
|
||||
let parts = st.field_index_by_increasing_offset().map(|i| {
|
||||
(&vals[i], st.offsets[i].bytes())
|
||||
});
|
||||
for (&val, target_offset) in parts {
|
||||
if offset < target_offset {
|
||||
cfields.push(padding(ccx, target_offset - offset));
|
||||
offset = target_offset;
|
||||
@ -807,14 +813,11 @@ pub fn const_get_field<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>,
|
||||
let l = ccx.layout_of(t);
|
||||
match *l {
|
||||
layout::CEnum { .. } => bug!("element access in C-like enum const"),
|
||||
layout::Univariant { .. } | layout::Vector { .. } => const_struct_field(val, ix),
|
||||
layout::Univariant { ref variant, .. } => {
|
||||
const_struct_field(val, variant.memory_index[ix] as usize)
|
||||
}
|
||||
layout::Vector { .. } => const_struct_field(val, ix),
|
||||
layout::UntaggedUnion { .. } => const_struct_field(val, 0),
|
||||
layout::General { .. } => const_struct_field(val, ix + 1),
|
||||
layout::RawNullablePointer { .. } => {
|
||||
assert_eq!(ix, 0);
|
||||
val
|
||||
},
|
||||
layout::StructWrappedNullablePointer{ .. } => const_struct_field(val, ix),
|
||||
_ => bug!("{} does not have fields.", t)
|
||||
}
|
||||
}
|
||||
|
@ -827,7 +827,9 @@ pub fn alloca(cx: Block, ty: Type, name: &str) -> ValueRef {
|
||||
}
|
||||
}
|
||||
DebugLoc::None.apply(cx.fcx);
|
||||
Alloca(cx, ty, name)
|
||||
let result = Alloca(cx, ty, name);
|
||||
debug!("alloca({:?}) = {:?}", name, result);
|
||||
result
|
||||
}
|
||||
|
||||
impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
|
||||
@ -1868,7 +1870,8 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||
match **layout {
|
||||
Layout::StructWrappedNullablePointer { nonnull: ref variant_layout,
|
||||
nndiscr,
|
||||
discrfield: _ } => {
|
||||
discrfield: _,
|
||||
discrfield_source: _ } => {
|
||||
debug!("print-type-size t: `{:?}` adt struct-wrapped nullable nndiscr {} is {:?}",
|
||||
ty, nndiscr, variant_layout);
|
||||
let variant_def = &adt_def.variants[nndiscr as usize];
|
||||
|
@ -870,25 +870,28 @@ impl<'tcx> MemberDescriptionFactory<'tcx> {
|
||||
|
||||
// Creates MemberDescriptions for the fields of a struct
|
||||
struct StructMemberDescriptionFactory<'tcx> {
|
||||
ty: Ty<'tcx>,
|
||||
variant: &'tcx ty::VariantDef,
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
is_simd: bool,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl<'tcx> StructMemberDescriptionFactory<'tcx> {
|
||||
fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
|
||||
-> Vec<MemberDescription> {
|
||||
let field_size = if self.is_simd {
|
||||
let fty = monomorphize::field_ty(cx.tcx(),
|
||||
self.substs,
|
||||
&self.variant.fields[0]);
|
||||
Some(machine::llsize_of_alloc(
|
||||
cx,
|
||||
type_of::type_of(cx, fty)
|
||||
) as usize)
|
||||
} else {
|
||||
None
|
||||
let layout = cx.layout_of(self.ty);
|
||||
|
||||
let tmp;
|
||||
let offsets = match *layout {
|
||||
layout::Univariant { ref variant, .. } => &variant.offsets,
|
||||
layout::Vector { element, count } => {
|
||||
let element_size = element.size(&cx.tcx().data_layout).bytes();
|
||||
tmp = (0..count).
|
||||
map(|i| layout::Size::from_bytes(i*element_size))
|
||||
.collect::<Vec<layout::Size>>();
|
||||
&tmp
|
||||
}
|
||||
_ => bug!("{} is not a struct", self.ty)
|
||||
};
|
||||
|
||||
self.variant.fields.iter().enumerate().map(|(i, f)| {
|
||||
@ -899,11 +902,7 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> {
|
||||
};
|
||||
let fty = monomorphize::field_ty(cx.tcx(), self.substs, f);
|
||||
|
||||
let offset = if self.is_simd {
|
||||
FixedMemberOffset { bytes: i * field_size.unwrap() }
|
||||
} else {
|
||||
ComputedMemberOffset
|
||||
};
|
||||
let offset = FixedMemberOffset { bytes: offsets[i].bytes() as usize};
|
||||
|
||||
MemberDescription {
|
||||
name: name,
|
||||
@ -945,9 +944,9 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
struct_metadata_stub,
|
||||
struct_llvm_type,
|
||||
StructMDF(StructMemberDescriptionFactory {
|
||||
ty: struct_type,
|
||||
variant: variant,
|
||||
substs: substs,
|
||||
is_simd: struct_type.is_simd(),
|
||||
span: span,
|
||||
})
|
||||
)
|
||||
@ -959,6 +958,7 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
|
||||
// Creates MemberDescriptions for the fields of a tuple
|
||||
struct TupleMemberDescriptionFactory<'tcx> {
|
||||
ty: Ty<'tcx>,
|
||||
component_types: Vec<Ty<'tcx>>,
|
||||
span: Span,
|
||||
}
|
||||
@ -966,6 +966,13 @@ struct TupleMemberDescriptionFactory<'tcx> {
|
||||
impl<'tcx> TupleMemberDescriptionFactory<'tcx> {
|
||||
fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
|
||||
-> Vec<MemberDescription> {
|
||||
let layout = cx.layout_of(self.ty);
|
||||
let offsets = if let layout::Univariant { ref variant, .. } = *layout {
|
||||
&variant.offsets
|
||||
} else {
|
||||
bug!("{} is not a tuple", self.ty);
|
||||
};
|
||||
|
||||
self.component_types
|
||||
.iter()
|
||||
.enumerate()
|
||||
@ -974,7 +981,7 @@ impl<'tcx> TupleMemberDescriptionFactory<'tcx> {
|
||||
name: format!("__{}", i),
|
||||
llvm_type: type_of::type_of(cx, component_type),
|
||||
type_metadata: type_metadata(cx, component_type, self.span),
|
||||
offset: ComputedMemberOffset,
|
||||
offset: FixedMemberOffset { bytes: offsets[i].bytes() as usize },
|
||||
flags: DIFlags::FlagZero,
|
||||
}
|
||||
}).collect()
|
||||
@ -1001,6 +1008,7 @@ fn prepare_tuple_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
NO_SCOPE_METADATA),
|
||||
tuple_llvm_type,
|
||||
TupleMDF(TupleMemberDescriptionFactory {
|
||||
ty: tuple_type,
|
||||
component_types: component_types.to_vec(),
|
||||
span: span,
|
||||
})
|
||||
@ -1239,7 +1247,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
||||
},
|
||||
layout::StructWrappedNullablePointer { nonnull: ref struct_def,
|
||||
nndiscr,
|
||||
ref discrfield, ..} => {
|
||||
ref discrfield_source, ..} => {
|
||||
// Create a description of the non-null variant
|
||||
let (variant_type_metadata, variant_llvm_type, member_description_factory) =
|
||||
describe_enum_variant(cx,
|
||||
@ -1262,12 +1270,12 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
||||
// member's name.
|
||||
let null_variant_index = (1 - nndiscr) as usize;
|
||||
let null_variant_name = adt.variants[null_variant_index].name;
|
||||
let discrfield = discrfield.iter()
|
||||
let discrfield_source = discrfield_source.iter()
|
||||
.skip(1)
|
||||
.map(|x| x.to_string())
|
||||
.collect::<Vec<_>>().join("$");
|
||||
let union_member_name = format!("RUST$ENCODED$ENUM${}${}",
|
||||
discrfield,
|
||||
discrfield_source,
|
||||
null_variant_name);
|
||||
|
||||
// Create the (singleton) list of descriptions of union members.
|
||||
@ -1289,6 +1297,8 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
||||
|
||||
// Creates MemberDescriptions for the fields of a single enum variant.
|
||||
struct VariantMemberDescriptionFactory<'tcx> {
|
||||
// Cloned from the layout::Struct describing the variant.
|
||||
offsets: &'tcx [layout::Size],
|
||||
args: Vec<(String, Ty<'tcx>)>,
|
||||
discriminant_type_metadata: Option<DIType>,
|
||||
span: Span,
|
||||
@ -1305,7 +1315,7 @@ impl<'tcx> VariantMemberDescriptionFactory<'tcx> {
|
||||
Some(metadata) if i == 0 => metadata,
|
||||
_ => type_metadata(cx, ty, self.span)
|
||||
},
|
||||
offset: ComputedMemberOffset,
|
||||
offset: FixedMemberOffset { bytes: self.offsets[i].bytes() as usize },
|
||||
flags: DIFlags::FlagZero
|
||||
}
|
||||
}).collect()
|
||||
@ -1325,7 +1335,7 @@ enum EnumDiscriminantInfo {
|
||||
// full RecursiveTypeDescription.
|
||||
fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
enum_type: Ty<'tcx>,
|
||||
struct_def: &layout::Struct,
|
||||
struct_def: &'tcx layout::Struct,
|
||||
variant: &'tcx ty::VariantDef,
|
||||
discriminant_info: EnumDiscriminantInfo,
|
||||
containing_scope: DIScope,
|
||||
@ -1409,6 +1419,7 @@ fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
|
||||
let member_description_factory =
|
||||
VariantMDF(VariantMemberDescriptionFactory {
|
||||
offsets: &struct_def.offsets[..],
|
||||
args: args,
|
||||
discriminant_type_metadata: match discriminant_info {
|
||||
RegularDiscriminant(discriminant_type_metadata) => {
|
||||
|
@ -11,7 +11,7 @@
|
||||
use llvm::{self, ValueRef};
|
||||
use rustc_const_eval::{ErrKind, ConstEvalErr, note_const_eval_err};
|
||||
use rustc::middle::lang_items;
|
||||
use rustc::ty;
|
||||
use rustc::ty::{self, layout};
|
||||
use rustc::mir;
|
||||
use abi::{Abi, FnType, ArgType};
|
||||
use adt;
|
||||
@ -722,8 +722,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
|
||||
}
|
||||
Immediate(llval) => {
|
||||
let l = bcx.ccx().layout_of(tuple.ty);
|
||||
let v = if let layout::Univariant { ref variant, .. } = *l {
|
||||
variant
|
||||
} else {
|
||||
bug!("Not a tuple.");
|
||||
};
|
||||
for (n, &ty) in arg_types.iter().enumerate() {
|
||||
let mut elem = bcx.extract_value(llval, n);
|
||||
let mut elem = bcx.extract_value(llval, v.memory_index[n] as usize);
|
||||
// Truncate bools to i1, if needed
|
||||
if ty.is_bool() && common::val_ty(elem) != Type::i1(bcx.ccx()) {
|
||||
elem = bcx.trunc(elem, Type::i1(bcx.ccx()));
|
||||
|
@ -246,7 +246,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
lldest: ValueRef,
|
||||
operand: OperandRef<'tcx>)
|
||||
{
|
||||
debug!("store_operand: operand={:?}", operand);
|
||||
debug!("store_operand: operand={:?} lldest={:?}", operand, lldest);
|
||||
bcx.with_block(|bcx| self.store_operand_direct(bcx, lldest, operand))
|
||||
}
|
||||
|
||||
|
@ -133,6 +133,13 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
// If this is a tuple or closure, we need to translate GEP indices.
|
||||
let layout = bcx.ccx().layout_of(dest.ty.to_ty(bcx.tcx()));
|
||||
let translation = if let Layout::Univariant { ref variant, .. } = *layout {
|
||||
Some(&variant.memory_index)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
for (i, operand) in operands.iter().enumerate() {
|
||||
let op = self.trans_operand(&bcx, operand);
|
||||
// Do not generate stores and GEPis for zero-sized fields.
|
||||
@ -140,6 +147,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
// Note: perhaps this should be StructGep, but
|
||||
// note that in some cases the values here will
|
||||
// not be structs but arrays.
|
||||
let i = if let Some(ref t) = translation {
|
||||
t[i] as usize
|
||||
} else {
|
||||
i
|
||||
};
|
||||
let dest = bcx.gepi(dest.llval, &[0, i]);
|
||||
self.store_operand(&bcx, dest, op);
|
||||
}
|
||||
|
@ -18,11 +18,11 @@
|
||||
// gdb-command:run
|
||||
|
||||
// gdb-command:print *the_a_ref
|
||||
// gdbg-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, __0 = 0, __1 = 2088533116, __2 = 2088533116}}
|
||||
// gdbg-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, [...]}}
|
||||
// gdbr-check:$1 = borrowed_enum::ABC::TheA{x: 0, y: 8970181431921507452}
|
||||
|
||||
// gdb-command:print *the_b_ref
|
||||
// gdbg-check:$2 = {{RUST$ENUM$DISR = TheB, x = 0, y = 1229782938247303441}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}}
|
||||
// gdbg-check:$2 = {{RUST$ENUM$DISR = TheB, [...]}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}}
|
||||
// gdbr-check:$2 = borrowed_enum::ABC::TheB(0, 286331153, 286331153)
|
||||
|
||||
// gdb-command:print *univariant_ref
|
||||
|
@ -42,7 +42,7 @@
|
||||
// gdb-command:continue
|
||||
|
||||
// gdb-command:print x
|
||||
// gdbg-check:$7 = {{RUST$ENUM$DISR = Case1, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 2088533116, __2 = 2088533116}}
|
||||
// gdbg-check:$7 = {{RUST$ENUM$DISR = Case1, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = Case1, [...]}}
|
||||
// gdbr-check:$7 = by_value_non_immediate_argument::Enum::Case1{x: 0, y: 8970181431921507452}
|
||||
// gdb-command:continue
|
||||
|
||||
|
@ -17,15 +17,15 @@
|
||||
// gdb-command:run
|
||||
|
||||
// gdb-command:print case1
|
||||
// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, a = 0, b = 2088533116, c = 2088533116}, {RUST$ENUM$DISR = Case1, a = 0, b = 8970181431921507452}}
|
||||
// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, [...]}, {RUST$ENUM$DISR = Case1, [...]}}
|
||||
// gdbr-check:$1 = generic_struct_style_enum::Regular::Case1{a: 0, b: 31868, c: 31868, d: 31868, e: 31868}
|
||||
|
||||
// gdb-command:print case2
|
||||
// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, a = 0, b = 4369, c = 4369, d = 4369, e = 4369}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, a = 0, b = 1229782938247303441}}
|
||||
// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, [...]}}
|
||||
// gdbr-check:$2 = generic_struct_style_enum::Regular::Case2{a: 0, b: 286331153, c: 286331153}
|
||||
|
||||
// gdb-command:print case3
|
||||
// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, a = 0, b = 22873, c = 22873, d = 22873, e = 22873}, {RUST$ENUM$DISR = Case3, a = 0, b = 1499027801, c = 1499027801}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}}
|
||||
// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}}
|
||||
// gdbr-check:$3 = generic_struct_style_enum::Regular::Case3{a: 0, b: 6438275382588823897}
|
||||
|
||||
// gdb-command:print univariant
|
||||
|
@ -19,15 +19,15 @@
|
||||
// gdb-command:run
|
||||
|
||||
// gdb-command:print case1
|
||||
// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = 31868, __2 = 31868, __3 = 31868, __4 = 31868}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 2088533116, __2 = 2088533116}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 8970181431921507452}}
|
||||
// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = 31868, __2 = 31868, __3 = 31868, __4 = 31868}, {RUST$ENUM$DISR = Case1, [...]}, {RUST$ENUM$DISR = Case1, [...]}}
|
||||
// gdbr-check:$1 = generic_tuple_style_enum::Regular::Case1(0, 31868, 31868, 31868, 31868)
|
||||
|
||||
// gdb-command:print case2
|
||||
// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, __0 = 0, __1 = 4369, __2 = 4369, __3 = 4369, __4 = 4369}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 286331153, __2 = 286331153}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 1229782938247303441}}
|
||||
// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 286331153, __2 = 286331153}, {RUST$ENUM$DISR = Case2, [...]}}
|
||||
// gdbr-check:$2 = generic_tuple_style_enum::Regular::Case2(0, 286331153, 286331153)
|
||||
|
||||
// gdb-command:print case3
|
||||
// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, __0 = 0, __1 = 22873, __2 = 22873, __3 = 22873, __4 = 22873}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 1499027801, __2 = 1499027801}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 6438275382588823897}}
|
||||
// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 6438275382588823897}}
|
||||
// gdbr-check:$3 = generic_tuple_style_enum::Regular::Case3(0, 6438275382588823897)
|
||||
|
||||
// gdb-command:print univariant
|
||||
|
@ -19,11 +19,11 @@
|
||||
// gdb-command:run
|
||||
|
||||
// gdb-command:print case1
|
||||
// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = {x = 2088533116, y = 2088533116, z = 31868}}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 8970181431921507452, __2 = 31868}}
|
||||
// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = {x = 2088533116, y = 2088533116, z = 31868}}, {RUST$ENUM$DISR = Case1, [...]}}
|
||||
// gdbr-check:$1 = struct_in_enum::Regular::Case1(0, struct_in_enum::Struct {x: 2088533116, y: 2088533116, z: 31868})
|
||||
|
||||
// gdb-command:print case2
|
||||
// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, __0 = 0, __1 = {x = 286331153, y = 286331153, z = 4369}}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 1229782938247303441, __2 = 4369}}
|
||||
// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 1229782938247303441, __2 = 4369}}
|
||||
// gdbr-check:$2 = struct_in_enum::Regular::Case2(0, 1229782938247303441, 4369)
|
||||
|
||||
// gdb-command:print univariant
|
||||
|
@ -19,15 +19,15 @@
|
||||
// gdb-command:run
|
||||
|
||||
// gdb-command:print case1
|
||||
// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, a = 0, b = 2088533116, c = 2088533116}, {RUST$ENUM$DISR = Case1, a = 0, b = 8970181431921507452}}
|
||||
// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, [...]}, {RUST$ENUM$DISR = Case1, [...]}}
|
||||
// gdbr-check:$1 = struct_style_enum::Regular::Case1{a: 0, b: 31868, c: 31868, d: 31868, e: 31868}
|
||||
|
||||
// gdb-command:print case2
|
||||
// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, a = 0, b = 4369, c = 4369, d = 4369, e = 4369}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, a = 0, b = 1229782938247303441}}
|
||||
// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, [...]}}
|
||||
// gdbr-check:$2 = struct_style_enum::Regular::Case2{a: 0, b: 286331153, c: 286331153}
|
||||
|
||||
// gdb-command:print case3
|
||||
// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, a = 0, b = 22873, c = 22873, d = 22873, e = 22873}, {RUST$ENUM$DISR = Case3, a = 0, b = 1499027801, c = 1499027801}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}}
|
||||
// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}}
|
||||
// gdbr-check:$3 = struct_style_enum::Regular::Case3{a: 0, b: 6438275382588823897}
|
||||
|
||||
// gdb-command:print univariant
|
||||
|
@ -19,15 +19,15 @@
|
||||
// gdb-command:run
|
||||
|
||||
// gdb-command:print case1
|
||||
// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = 31868, __2 = 31868, __3 = 31868, __4 = 31868}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 2088533116, __2 = 2088533116}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 8970181431921507452}}
|
||||
// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = 31868, __2 = 31868, __3 = 31868, __4 = 31868}, {RUST$ENUM$DISR = Case1, [...]}, {RUST$ENUM$DISR = Case1, [...]}}
|
||||
// gdbr-check:$1 = tuple_style_enum::Regular::Case1(0, 31868, 31868, 31868, 31868)
|
||||
|
||||
// gdb-command:print case2
|
||||
// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, __0 = 0, __1 = 4369, __2 = 4369, __3 = 4369, __4 = 4369}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 286331153, __2 = 286331153}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 1229782938247303441}}
|
||||
// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 286331153, __2 = 286331153}, {RUST$ENUM$DISR = Case2, [...]}}
|
||||
// gdbr-check:$2 = tuple_style_enum::Regular::Case2(0, 286331153, 286331153)
|
||||
|
||||
// gdb-command:print case3
|
||||
// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, __0 = 0, __1 = 22873, __2 = 22873, __3 = 22873, __4 = 22873}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 1499027801, __2 = 1499027801}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 6438275382588823897}}
|
||||
// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 6438275382588823897}}
|
||||
// gdbr-check:$3 = tuple_style_enum::Regular::Case3(0, 6438275382588823897)
|
||||
|
||||
// gdb-command:print univariant
|
||||
|
@ -18,11 +18,11 @@
|
||||
// gdb-command:run
|
||||
|
||||
// gdb-command:print *the_a
|
||||
// gdbg-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, __0 = 0, __1 = 2088533116, __2 = 2088533116}}
|
||||
// gdbg-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, [...]}}
|
||||
// gdbr-check:$1 = unique_enum::ABC::TheA{x: 0, y: 8970181431921507452}
|
||||
|
||||
// gdb-command:print *the_b
|
||||
// gdbg-check:$2 = {{RUST$ENUM$DISR = TheB, x = 0, y = 1229782938247303441}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}}
|
||||
// gdbg-check:$2 = {{RUST$ENUM$DISR = TheB, [...]}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}}
|
||||
// gdbr-check:$2 = unique_enum::ABC::TheB(0, 286331153, 286331153)
|
||||
|
||||
// gdb-command:print *univariant
|
||||
|
22
src/test/run-pass/closure-immediate.rs
Normal file
22
src/test/run-pass/closure-immediate.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
// After the work to reoptimize structs, it became possible for immediate logic to fail.
|
||||
// This test verifies that it actually works.
|
||||
|
||||
fn main() {
|
||||
let c = |a: u8, b: u16, c: u8| {
|
||||
assert_eq!(a, 1);
|
||||
assert_eq!(b, 2);
|
||||
assert_eq!(c, 3);
|
||||
};
|
||||
c(1, 2, 3);
|
||||
}
|
@ -11,6 +11,9 @@
|
||||
#![warn(variant_size_differences)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
// Note that the following test works because all fields of the enum variants are of the same size.
|
||||
// If this test is modified and the reordering logic in librustc/ty/layout.rs kicks in, it fails.
|
||||
|
||||
enum Enum1 { }
|
||||
|
||||
enum Enum2 { A, B, C }
|
||||
|
@ -14,11 +14,13 @@
|
||||
// ignore-msvc
|
||||
// ignore-emscripten
|
||||
|
||||
#[repr(C)]
|
||||
struct TwoU8s {
|
||||
one: u8,
|
||||
two: u8,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct ManyInts {
|
||||
arg1: i8,
|
||||
arg2: i16,
|
||||
@ -28,6 +30,7 @@ struct ManyInts {
|
||||
arg6: TwoU8s,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct Empty;
|
||||
|
||||
#[link(name = "rust_test_helpers", kind = "static")]
|
||||
|
43
src/test/run-pass/multiple-reprs.rs
Normal file
43
src/test/run-pass/multiple-reprs.rs
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use std::mem::size_of;
|
||||
|
||||
// The two enums that follow are designed so that bugs trigger layout optimization.
|
||||
// Specifically, if either of the following reprs used here is not detected by the compiler,
|
||||
// then the sizes will be wrong.
|
||||
|
||||
#[repr(C, u8)]
|
||||
enum E1 {
|
||||
A(u8, u16, u8),
|
||||
B(u8, u16, u8)
|
||||
}
|
||||
|
||||
#[repr(u8, C)]
|
||||
enum E2 {
|
||||
A(u8, u16, u8),
|
||||
B(u8, u16, u8)
|
||||
}
|
||||
|
||||
// From pr 37429
|
||||
|
||||
#[repr(C,packed)]
|
||||
pub struct p0f_api_query {
|
||||
pub magic: u32,
|
||||
pub addr_type: u8,
|
||||
pub addr: [u8; 16],
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
assert_eq!(size_of::<E1>(), 6);
|
||||
assert_eq!(size_of::<E2>(), 6);
|
||||
assert_eq!(size_of::<p0f_api_query>(), 21);
|
||||
}
|
@ -26,8 +26,7 @@ fn main() {
|
||||
assert_eq!(size_of::<E>(), 1);
|
||||
assert_eq!(size_of::<Option<E>>(), 1);
|
||||
assert_eq!(size_of::<Result<E, ()>>(), 1);
|
||||
assert_eq!(size_of::<S>(), 4);
|
||||
assert_eq!(size_of::<Option<S>>(), 4);
|
||||
assert_eq!(size_of::<Option<S>>(), size_of::<S>());
|
||||
let enone = None::<E>;
|
||||
let esome = Some(E::A);
|
||||
if let Some(..) = enone {
|
||||
|
@ -9,9 +9,11 @@
|
||||
// except according to those terms.
|
||||
//
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Quad { a: u64, b: u64, c: u64, d: u64 }
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Floats { a: f64, b: u8, c: f64 }
|
||||
|
||||
|
@ -26,10 +26,15 @@ enum e2 {
|
||||
a(u32), b
|
||||
}
|
||||
|
||||
#[repr(C, u8)]
|
||||
enum e3 {
|
||||
a([u16; 0], u8), b
|
||||
}
|
||||
|
||||
// Test struct field reordering to make sure it actually reorders.
|
||||
struct WillOptimize1(u8, u16, u8);
|
||||
struct WillOptimize2 { a: u8, b: u16, c: u8}
|
||||
|
||||
pub fn main() {
|
||||
assert_eq!(size_of::<u8>(), 1 as usize);
|
||||
assert_eq!(size_of::<u32>(), 4 as usize);
|
||||
@ -53,4 +58,7 @@ pub fn main() {
|
||||
assert_eq!(size_of::<e1>(), 8 as usize);
|
||||
assert_eq!(size_of::<e2>(), 8 as usize);
|
||||
assert_eq!(size_of::<e3>(), 4 as usize);
|
||||
|
||||
assert_eq!(size_of::<WillOptimize1>(), 4);
|
||||
assert_eq!(size_of::<WillOptimize2>(), 4);
|
||||
}
|
||||
|
@ -1,25 +1,22 @@
|
||||
print-type-size type: `IndirectNonZero<u32>`: 20 bytes, alignment: 4 bytes
|
||||
print-type-size field `.pre`: 1 bytes
|
||||
print-type-size padding: 3 bytes
|
||||
print-type-size field `.nested`: 12 bytes, alignment: 4 bytes
|
||||
print-type-size type: `IndirectNonZero<u32>`: 12 bytes, alignment: 4 bytes
|
||||
print-type-size field `.nested`: 8 bytes
|
||||
print-type-size field `.post`: 2 bytes
|
||||
print-type-size end padding: 2 bytes
|
||||
print-type-size type: `MyOption<IndirectNonZero<u32>>`: 20 bytes, alignment: 4 bytes
|
||||
print-type-size variant `Some`: 20 bytes
|
||||
print-type-size field `.0`: 20 bytes
|
||||
print-type-size type: `EmbeddedDiscr`: 12 bytes, alignment: 4 bytes
|
||||
print-type-size variant `Record`: 10 bytes
|
||||
print-type-size field `.pre`: 1 bytes
|
||||
print-type-size padding: 3 bytes
|
||||
print-type-size field `.val`: 4 bytes, alignment: 4 bytes
|
||||
print-type-size field `.pre`: 1 bytes
|
||||
print-type-size end padding: 1 bytes
|
||||
print-type-size type: `MyOption<IndirectNonZero<u32>>`: 12 bytes, alignment: 4 bytes
|
||||
print-type-size variant `Some`: 12 bytes
|
||||
print-type-size field `.0`: 12 bytes
|
||||
print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes
|
||||
print-type-size variant `Record`: 7 bytes
|
||||
print-type-size field `.val`: 4 bytes
|
||||
print-type-size field `.post`: 2 bytes
|
||||
print-type-size end padding: 2 bytes
|
||||
print-type-size type: `NestedNonZero<u32>`: 12 bytes, alignment: 4 bytes
|
||||
print-type-size field `.pre`: 1 bytes
|
||||
print-type-size padding: 3 bytes
|
||||
print-type-size field `.val`: 4 bytes, alignment: 4 bytes
|
||||
print-type-size field `.pre`: 1 bytes
|
||||
print-type-size end padding: 1 bytes
|
||||
print-type-size type: `NestedNonZero<u32>`: 8 bytes, alignment: 4 bytes
|
||||
print-type-size field `.val`: 4 bytes
|
||||
print-type-size field `.post`: 2 bytes
|
||||
print-type-size end padding: 2 bytes
|
||||
print-type-size field `.pre`: 1 bytes
|
||||
print-type-size end padding: 1 bytes
|
||||
print-type-size type: `MyOption<core::nonzero::NonZero<u32>>`: 4 bytes, alignment: 4 bytes
|
||||
print-type-size variant `Some`: 4 bytes
|
||||
print-type-size field `.0`: 4 bytes
|
||||
|
@ -1,13 +1,11 @@
|
||||
print-type-size type: `Padded`: 16 bytes, alignment: 4 bytes
|
||||
print-type-size type: `Padded`: 12 bytes, alignment: 4 bytes
|
||||
print-type-size field `.g`: 4 bytes
|
||||
print-type-size field `.h`: 2 bytes
|
||||
print-type-size field `.a`: 1 bytes
|
||||
print-type-size field `.b`: 1 bytes
|
||||
print-type-size padding: 2 bytes
|
||||
print-type-size field `.g`: 4 bytes, alignment: 4 bytes
|
||||
print-type-size field `.c`: 1 bytes
|
||||
print-type-size padding: 1 bytes
|
||||
print-type-size field `.h`: 2 bytes, alignment: 2 bytes
|
||||
print-type-size field `.d`: 1 bytes
|
||||
print-type-size end padding: 3 bytes
|
||||
print-type-size end padding: 2 bytes
|
||||
print-type-size type: `Packed`: 10 bytes, alignment: 1 bytes
|
||||
print-type-size field `.a`: 1 bytes
|
||||
print-type-size field `.b`: 1 bytes
|
||||
|
@ -1,10 +1,12 @@
|
||||
print-type-size type: `E1`: 12 bytes, alignment: 4 bytes
|
||||
print-type-size discriminant: 4 bytes
|
||||
print-type-size variant `A`: 5 bytes
|
||||
print-type-size field `.0`: 4 bytes
|
||||
print-type-size discriminant: 1 bytes
|
||||
print-type-size variant `A`: 7 bytes
|
||||
print-type-size field `.1`: 1 bytes
|
||||
print-type-size variant `B`: 8 bytes
|
||||
print-type-size field `.0`: 8 bytes
|
||||
print-type-size padding: 2 bytes
|
||||
print-type-size field `.0`: 4 bytes, alignment: 4 bytes
|
||||
print-type-size variant `B`: 11 bytes
|
||||
print-type-size padding: 3 bytes
|
||||
print-type-size field `.0`: 8 bytes, alignment: 4 bytes
|
||||
print-type-size type: `E2`: 12 bytes, alignment: 4 bytes
|
||||
print-type-size discriminant: 1 bytes
|
||||
print-type-size variant `A`: 7 bytes
|
||||
@ -15,7 +17,7 @@ print-type-size variant `B`: 11 bytes
|
||||
print-type-size padding: 3 bytes
|
||||
print-type-size field `.0`: 8 bytes, alignment: 4 bytes
|
||||
print-type-size type: `S`: 8 bytes, alignment: 4 bytes
|
||||
print-type-size field `.g`: 4 bytes
|
||||
print-type-size field `.a`: 1 bytes
|
||||
print-type-size field `.b`: 1 bytes
|
||||
print-type-size padding: 2 bytes
|
||||
print-type-size field `.g`: 4 bytes, alignment: 4 bytes
|
||||
print-type-size end padding: 2 bytes
|
||||
|
Loading…
x
Reference in New Issue
Block a user