Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Refactor layout to use the new ReprOptions
  • Loading branch information
ahicks92 committed Feb 7, 2017
1 parent 541aa8a commit c3b64cf
Showing 1 changed file with 39 additions and 63 deletions.
102 changes: 39 additions & 63 deletions src/librustc/ty/layout.rs
Expand Up @@ -15,7 +15,7 @@ pub use self::Primitive::*;
use infer::InferCtxt;
use session::Session;
use traits;
use ty::{self, Ty, TyCtxt, TypeFoldable};
use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions};

use syntax::ast::{FloatTy, IntTy, UintTy};
use syntax::attr;
Expand Down Expand Up @@ -437,7 +437,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.
fn repr_discr(tcx: TyCtxt, ty: Ty, hints: &[attr::ReprAttr], min: i64, max: i64)
fn repr_discr(tcx: TyCtxt, ty: Ty, repr: &ReprOptions, 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
Expand All @@ -449,34 +449,24 @@ impl Integer {
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());
}
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);
}
if let Some(ity) = repr.int {
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());
}

if repr.c {
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),
}
}

Expand Down Expand Up @@ -568,9 +558,9 @@ enum StructKind {
impl<'a, 'gcx, 'tcx> 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,
repr: &ReprOptions, kind: StructKind,
scapegoat: Ty<'gcx>) -> Result<Struct, LayoutError<'gcx>> {
let packed = reprs.contains(&attr::ReprPacked);
let packed = repr.packed;
let mut ret = Struct {
align: if packed { dl.i8_align } else { dl.aggregate_align },
packed: packed,
Expand All @@ -580,27 +570,16 @@ impl<'a, 'gcx, 'tcx> Struct {
min_size: Size::from_bytes(0),
};

// Anything with ReprExtern or ReprPacked doesn't optimize.
// Anything with repr(C) or repr(packed) 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")
}
});
}
let mut can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind)
&& ! (repr.c || repr.packed);

// Disable field reordering until we can decide what to do.
// The odd pattern here avoids a warning about the value never being read.
if can_optimize { can_optimize = false }
if can_optimize { can_optimize = false; }

let (optimize, sort_ascending) = match kind {
StructKind::AlwaysSizedUnivariant => (can_optimize, false),
Expand Down Expand Up @@ -1092,7 +1071,7 @@ impl<'a, 'gcx, 'tcx> Layout {

// The never type.
ty::TyNever => Univariant {
variant: Struct::new(dl, &vec![], &[],
variant: Struct::new(dl, &vec![], &ReprOptions::default(),
StructKind::AlwaysSizedUnivariant, ty)?,
non_zero: false
},
Expand Down Expand Up @@ -1135,12 +1114,12 @@ impl<'a, 'gcx, 'tcx> Layout {
ty::TyFnDef(..) => {
Univariant {
variant: Struct::new(dl, &vec![],
&[], StructKind::AlwaysSizedUnivariant, ty)?,
&ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?,
non_zero: false
}
}
ty::TyDynamic(..) => {
let mut unit = Struct::new(dl, &vec![], &[],
let mut unit = Struct::new(dl, &vec![], &ReprOptions::default(),
StructKind::AlwaysSizedUnivariant, ty)?;
unit.sized = false;
Univariant { variant: unit, non_zero: false }
Expand All @@ -1152,7 +1131,7 @@ impl<'a, 'gcx, 'tcx> Layout {
let st = Struct::new(dl,
&tys.map(|ty| ty.layout(infcx))
.collect::<Result<Vec<_>, _>>()?,
&[],
&ReprOptions::default(),
StructKind::AlwaysSizedUnivariant, ty)?;
Univariant { variant: st, non_zero: false }
}
Expand All @@ -1163,7 +1142,7 @@ impl<'a, 'gcx, 'tcx> Layout {
let st = Struct::new(dl,
&tys.iter().map(|ty| ty.layout(infcx))
.collect::<Result<Vec<_>, _>>()?,
&[], StructKind::AlwaysSizedUnivariant, ty)?;
&ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?;
Univariant { variant: st, non_zero: false }
}

Expand All @@ -1187,16 +1166,13 @@ impl<'a, 'gcx, 'tcx> Layout {

// ADTs.
ty::TyAdt(def, substs) => {
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!(hints.len(), 0);

return success(Univariant {
variant: Struct::new(dl, &vec![],
&hints[..], StructKind::AlwaysSizedUnivariant, ty)?,
&def.repr, StructKind::AlwaysSizedUnivariant, ty)?,
non_zero: false
});
}
Expand All @@ -1219,7 +1195,7 @@ impl<'a, 'gcx, 'tcx> Layout {

// FIXME: should handle i128? signed-value based impl is weird and hard to
// grok.
let (discr, signed) = Integer::repr_discr(tcx, ty, &hints[..],
let (discr, signed) = Integer::repr_discr(tcx, ty, &def.repr,
min,
max);
return success(CEnum {
Expand All @@ -1232,7 +1208,7 @@ impl<'a, 'gcx, 'tcx> Layout {
});
}

if !def.is_enum() || def.variants.len() == 1 && hints.is_empty() {
if !def.is_enum() || def.variants.len() == 1 {
// Struct, or union, or univariant enum equivalent to a struct.
// (Typechecking will reject discriminant-sizing attrs.)

Expand All @@ -1259,7 +1235,7 @@ impl<'a, 'gcx, 'tcx> Layout {
un.extend(dl, fields.iter().map(|&f| Ok(f)), ty)?;
UntaggedUnion { variants: un }
} else {
let st = Struct::new(dl, &fields, &hints[..],
let st = Struct::new(dl, &fields, &def.repr,
kind, ty)?;
let non_zero = Some(def.did) == tcx.lang_items.non_zero();
Univariant { variant: st, non_zero: non_zero }
Expand All @@ -1282,7 +1258,7 @@ impl<'a, 'gcx, 'tcx> Layout {
v.fields.iter().map(|field| field.ty(tcx, substs)).collect::<Vec<_>>()
}).collect::<Vec<_>>();

if variants.len() == 2 && hints.is_empty() {
if variants.len() == 2 && !def.repr.c {
// Nullable pointer optimization
for discr in 0..2 {
let other_fields = variants[1 - discr].iter().map(|ty| {
Expand Down Expand Up @@ -1315,7 +1291,7 @@ 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)?;
&def.repr, StructKind::AlwaysSizedUnivariant, ty)?;

// We have to fix the last element of path here.
let mut i = *path.last().unwrap();
Expand All @@ -1338,7 +1314,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, &hints[..], 0, discr_max);
let (min_ity, _) = Integer::repr_discr(tcx, ty, &def.repr, 0, discr_max);

let mut align = dl.aggregate_align;
let mut size = Size::from_bytes(0);
Expand All @@ -1356,7 +1332,7 @@ impl<'a, 'gcx, 'tcx> Layout {
fields.insert(0, &discr);
let st = Struct::new(dl,
&fields,
&hints[..], StructKind::EnumVariant, ty)?;
&def.repr, 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.
Expand Down

0 comments on commit c3b64cf

Please sign in to comment.