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;
/// 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
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),
}
}
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,
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),
// The never type.
ty::TyNever => Univariant {
- variant: Struct::new(dl, &vec![], &[],
+ variant: Struct::new(dl, &vec![], &ReprOptions::default(),
StructKind::AlwaysSizedUnivariant, ty)?,
non_zero: false
},
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 }
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 }
}
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 }
}
// 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
});
}
// 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 {
});
}
- 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.)
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 }
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| {
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();
// 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);
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.