Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make reprs use a structured representation instead of a slice #39595

Merged
merged 2 commits into from
Feb 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -672,9 +673,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn alloc_adt_def(self,
did: DefId,
kind: AdtKind,
variants: Vec<ty::VariantDef>)
variants: Vec<ty::VariantDef>,
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)
}

Expand Down
102 changes: 39 additions & 63 deletions src/librustc/ty/layout.rs
Original file line number Diff line number Diff line change
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
33 changes: 31 additions & 2 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1327,7 +1327,8 @@ pub struct AdtDef {
pub did: DefId,
pub variants: Vec<VariantDef>,
destructor: Cell<Option<DefId>>,
flags: Cell<AdtFlags>
flags: Cell<AdtFlags>,
pub repr: ReprOptions,
}

impl PartialEq for AdtDef {
Expand Down Expand Up @@ -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<attr::IntType>,
}

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<VariantDef>) -> Self {
variants: Vec<VariantDef>,
repr: ReprOptions) -> Self {
let mut flags = AdtFlags::NO_ADT_FLAGS;
let attrs = tcx.get_attrs(did);
if attr::contains_name(&attrs, "fundamental") {
Expand All @@ -1385,6 +1413,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
variants: variants,
flags: Cell::new(flags),
destructor: Cell::new(None),
repr: repr,
}
}

Expand Down
28 changes: 14 additions & 14 deletions src/librustc_metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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 |
Expand Down Expand Up @@ -519,8 +519,8 @@ impl<'a, 'tcx> CrateMetadata {
-> (ty::VariantDef, Option<DefIndex>) {
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!(),
};

Expand All @@ -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| {
Expand All @@ -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);
Expand Down Expand Up @@ -881,16 +881,16 @@ 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,
}
}

pub fn get_struct_ctor_def_id(&self, node_id: DefIndex) -> Option<DefId> {
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,
Expand Down
Loading