diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index a0eae33c4402b..6203679a51058 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -26,6 +26,7 @@ use middle::resolve_lifetime; use middle::stability; use mir::Mir; use ty::subst::{Kind, Substs}; +use ty::ReprOptions; use traits; use ty::{self, TraitRef, Ty, TypeAndMut}; use ty::{TyS, TypeVariants, Slice}; @@ -672,9 +673,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn alloc_adt_def(self, did: DefId, kind: AdtKind, - variants: Vec) + variants: Vec, + repr: ReprOptions) -> &'gcx ty::AdtDef { - let def = ty::AdtDef::new(self, did, kind, variants); + let def = ty::AdtDef::new(self, did, kind, variants, repr); self.global_arenas.adt_def.alloc(def) } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index ff3ac3586a787..3a463e981a627 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -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; @@ -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 @@ -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), } } @@ -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> { - 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, @@ -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), @@ -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 }, @@ -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 } @@ -1152,7 +1131,7 @@ impl<'a, 'gcx, 'tcx> Layout { let st = Struct::new(dl, &tys.map(|ty| ty.layout(infcx)) .collect::, _>>()?, - &[], + &ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?; Univariant { variant: st, non_zero: false } } @@ -1163,7 +1142,7 @@ impl<'a, 'gcx, 'tcx> Layout { let st = Struct::new(dl, &tys.iter().map(|ty| ty.layout(infcx)) .collect::, _>>()?, - &[], StructKind::AlwaysSizedUnivariant, ty)?; + &ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?; Univariant { variant: st, non_zero: false } } @@ -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 }); } @@ -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 { @@ -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.) @@ -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 } @@ -1282,7 +1258,7 @@ impl<'a, 'gcx, 'tcx> Layout { v.fields.iter().map(|field| field.ty(tcx, substs)).collect::>() }).collect::>(); - 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| { @@ -1315,7 +1291,7 @@ impl<'a, 'gcx, 'tcx> Layout { let st = Struct::new(dl, &variants[discr].iter().map(|ty| ty.layout(infcx)) .collect::, _>>()?, - &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(); @@ -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); @@ -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. diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 4d9514b1473c7..beb286108a034 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1327,7 +1327,8 @@ pub struct AdtDef { pub did: DefId, pub variants: Vec, destructor: Cell>, - flags: Cell + flags: Cell, + pub repr: ReprOptions, } impl PartialEq for AdtDef { @@ -1356,11 +1357,38 @@ impl<'tcx> serialize::UseSpecializedDecodable for &'tcx AdtDef {} #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum AdtKind { Struct, Union, Enum } +/// Represents the repr options provided by the user, +#[derive(Copy, Clone, Eq, PartialEq, RustcEncodable, RustcDecodable, Default)] +pub struct ReprOptions { + pub c: bool, + pub packed: bool, + pub simd: bool, + pub int: Option, +} + +impl ReprOptions { + pub fn new<'a, 'gcx, 'tcx>(tcx: &TyCtxt<'a, 'gcx, 'tcx>, did: DefId) -> ReprOptions { + let mut ret = ReprOptions::default(); + let attrs = tcx.lookup_repr_hints(did); + for r in attrs.iter() { + match *r { + attr::ReprExtern => ret.c = true, + attr::ReprPacked => ret.packed = true, + attr::ReprSimd => ret.simd = true, + attr::ReprInt(i) => ret.int = Some(i), + attr::ReprAny => (), + } + } + ret + } +} + impl<'a, 'gcx, 'tcx> AdtDef { fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, did: DefId, kind: AdtKind, - variants: Vec) -> Self { + variants: Vec, + repr: ReprOptions) -> Self { let mut flags = AdtFlags::NO_ADT_FLAGS; let attrs = tcx.get_attrs(did); if attr::contains_name(&attrs, "fundamental") { @@ -1385,6 +1413,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { variants: variants, flags: Cell::new(flags), destructor: Cell::new(None), + repr: repr, } } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index f4a35ea5fd0cf..bb99be20f64d3 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -425,8 +425,8 @@ impl<'tcx> EntryKind<'tcx> { EntryKind::ForeignImmStatic => Def::Static(did, false), EntryKind::MutStatic | EntryKind::ForeignMutStatic => Def::Static(did, true), - EntryKind::Struct(_) => Def::Struct(did), - EntryKind::Union(_) => Def::Union(did), + EntryKind::Struct(_, _) => Def::Struct(did), + EntryKind::Union(_, _) => Def::Union(did), EntryKind::Fn(_) | EntryKind::ForeignFn(_) => Def::Fn(did), EntryKind::Method(_) => Def::Method(did), @@ -435,7 +435,7 @@ impl<'tcx> EntryKind<'tcx> { EntryKind::Mod(_) => Def::Mod(did), EntryKind::Variant(_) => Def::Variant(did), EntryKind::Trait(_) => Def::Trait(did), - EntryKind::Enum => Def::Enum(did), + EntryKind::Enum(_) => Def::Enum(did), EntryKind::MacroDef(_) => Def::Macro(did), EntryKind::ForeignMod | @@ -519,8 +519,8 @@ impl<'a, 'tcx> CrateMetadata { -> (ty::VariantDef, Option) { let data = match item.kind { EntryKind::Variant(data) | - EntryKind::Struct(data) | - EntryKind::Union(data) => data.decode(self), + EntryKind::Struct(data, _) | + EntryKind::Union(data, _) => data.decode(self), _ => bug!(), }; @@ -547,7 +547,7 @@ impl<'a, 'tcx> CrateMetadata { let item = self.entry(item_id); let did = self.local_def_id(item_id); let mut ctor_index = None; - let variants = if let EntryKind::Enum = item.kind { + let variants = if let EntryKind::Enum(_) = item.kind { item.children .decode(self) .map(|index| { @@ -561,14 +561,14 @@ impl<'a, 'tcx> CrateMetadata { ctor_index = struct_ctor; vec![variant] }; - let kind = match item.kind { - EntryKind::Enum => ty::AdtKind::Enum, - EntryKind::Struct(_) => ty::AdtKind::Struct, - EntryKind::Union(_) => ty::AdtKind::Union, + let (kind, repr) = match item.kind { + EntryKind::Enum(repr) => (ty::AdtKind::Enum, repr), + EntryKind::Struct(_, repr) => (ty::AdtKind::Struct, repr), + EntryKind::Union(_, repr) => (ty::AdtKind::Union, repr), _ => bug!("get_adt_def called on a non-ADT {:?}", did), }; - let adt = tcx.alloc_adt_def(did, kind, variants); + let adt = tcx.alloc_adt_def(did, kind, variants, repr); if let Some(ctor_index) = ctor_index { // Make adt definition available through constructor id as well. tcx.adt_defs.borrow_mut().insert(self.local_def_id(ctor_index), adt); @@ -881,8 +881,8 @@ impl<'a, 'tcx> CrateMetadata { pub fn get_ctor_kind(&self, node_id: DefIndex) -> CtorKind { match self.entry(node_id).kind { - EntryKind::Struct(data) | - EntryKind::Union(data) | + EntryKind::Struct(data, _) | + EntryKind::Union(data, _) | EntryKind::Variant(data) => data.decode(self).ctor_kind, _ => CtorKind::Fictive, } @@ -890,7 +890,7 @@ impl<'a, 'tcx> CrateMetadata { pub fn get_struct_ctor_def_id(&self, node_id: DefIndex) -> Option { match self.entry(node_id).kind { - EntryKind::Struct(data) => { + EntryKind::Struct(data, _) => { data.decode(self).struct_ctor.map(|index| self.local_def_id(index)) } _ => None, diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 69e1bbd77662b..f4ff5f4626f35 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -20,7 +20,7 @@ use rustc::middle::dependency_format::Linkage; use rustc::middle::lang_items; use rustc::mir; use rustc::traits::specialization_graph; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, Ty, TyCtxt, ReprOptions}; use rustc::session::config::{self, CrateTypeProcMacro}; use rustc::util::nodemap::{FxHashMap, NodeSet}; @@ -401,8 +401,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } + let repr_options = get_repr_options(&tcx, adt_def_id); + Entry { - kind: EntryKind::Struct(self.lazy(&data)), + kind: EntryKind::Struct(self.lazy(&data), repr_options), visibility: self.lazy(&ctor_vis), span: self.lazy(&tcx.def_span(def_id)), attributes: LazySeq::empty(), @@ -659,7 +661,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } hir::ItemForeignMod(_) => EntryKind::ForeignMod, hir::ItemTy(..) => EntryKind::Type, - hir::ItemEnum(..) => EntryKind::Enum, + hir::ItemEnum(..) => EntryKind::Enum(get_repr_options(&tcx, def_id)), hir::ItemStruct(ref struct_def, _) => { let variant = tcx.lookup_adt_def(def_id).struct_variant(); @@ -671,20 +673,24 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } else { None }; + + let repr_options = get_repr_options(&tcx, def_id); + EntryKind::Struct(self.lazy(&VariantData { ctor_kind: variant.ctor_kind, disr: variant.disr_val.to_u128_unchecked(), struct_ctor: struct_ctor, - })) + }), repr_options) } hir::ItemUnion(..) => { let variant = tcx.lookup_adt_def(def_id).struct_variant(); + let repr_options = get_repr_options(&tcx, def_id); EntryKind::Union(self.lazy(&VariantData { ctor_kind: variant.ctor_kind, disr: variant.disr_val.to_u128_unchecked(), struct_ctor: None, - })) + }), repr_options) } hir::ItemDefaultImpl(..) => { let data = ImplData { @@ -1419,3 +1425,11 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, result } + +pub fn get_repr_options<'a, 'tcx, 'gcx>(tcx: &TyCtxt<'a, 'tcx, 'gcx>, did: DefId) -> ReprOptions { + let ty = tcx.item_type(did); + match ty.sty { + ty::TyAdt(ref def, _) => return def.repr, + _ => bug!("{} is not an ADT", ty), + } +} diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index d13628e9ce7a3..10aa4784aa2e1 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -18,7 +18,7 @@ use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary}; use rustc::middle::lang_items; use rustc::middle::resolve_lifetime::ObjectLifetimeDefault; use rustc::mir; -use rustc::ty::{self, Ty}; +use rustc::ty::{self, Ty, ReprOptions}; use rustc_back::PanicStrategy; use rustc_serialize as serialize; @@ -228,11 +228,11 @@ pub enum EntryKind<'tcx> { ForeignMutStatic, ForeignMod, Type, - Enum, + Enum(ReprOptions), Field, Variant(Lazy), - Struct(Lazy), - Union(Lazy), + Struct(Lazy, ReprOptions), + Union(Lazy, ReprOptions), Fn(Lazy), ForeignFn(Lazy), Mod(Lazy), diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 1981e7c3a3d12..7936db65c44ac 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -65,7 +65,7 @@ use middle::const_val::ConstVal; use rustc_const_eval::EvalHint::UncheckedExprHint; use rustc_const_eval::{ConstContext, report_const_eval_err}; use rustc::ty::subst::Substs; -use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContainer}; +use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContainer, ReprOptions}; use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; use rustc::ty::util::IntTypeExt; use rustc::dep_graph::DepNode; @@ -1006,7 +1006,8 @@ fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let ctor_id = if !def.is_struct() { Some(ccx.tcx.hir.local_def_id(def.id())) } else { None }; let variants = vec![convert_struct_variant(ccx, ctor_id.unwrap_or(did), it.name, ConstInt::Infer(0), def)]; - let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Struct, variants); + let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Struct, variants, + ReprOptions::new(&ccx.tcx, did)); if let Some(ctor_id) = ctor_id { // Make adt definition available through constructor id as well. ccx.tcx.adt_defs.borrow_mut().insert(ctor_id, adt); @@ -1024,7 +1025,7 @@ fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let did = ccx.tcx.hir.local_def_id(it.id); let variants = vec![convert_struct_variant(ccx, did, it.name, ConstInt::Infer(0), def)]; - let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Union, variants); + let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Union, variants, ReprOptions::new(&ccx.tcx, did)); ccx.tcx.adt_defs.borrow_mut().insert(did, adt); adt } @@ -1112,7 +1113,7 @@ fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, convert_struct_variant(ccx, did, v.node.name, disr, &v.node.data) }).collect(); - let adt = tcx.alloc_adt_def(did, AdtKind::Enum, variants); + let adt = tcx.alloc_adt_def(did, AdtKind::Enum, variants, ReprOptions::new(&ccx.tcx, did)); tcx.adt_defs.borrow_mut().insert(did, adt); adt }