Skip to content

Commit 15decb8

Browse files
authored
Rollup merge of #39595 - camlorn:structured_repr, r=eddyb
Make reprs use a structured representation instead of a slice This is needed for `-z reorder-fields`. The old design uses a slice taken from HIR, plus a cache that lazily parses. The new design stores it directly in the `AdtDef` as a `ReprOptions`. We're doing this now because we need to be able to add reprs that don't necessarily exist in HIR for `-z reorder-fields`, but it needs to happen anyway. `lookup_repr_hints` should be mostly deprecated. I want to remove it from `layout` before closing this, unless people think that should be a separate PR. The `[WIP]` is because of this. The problem with closing this as-is is that the code here isn't actually testable until some parts of the compiler start using it. r? @eddyb
2 parents b0e46f0 + c3b64cf commit 15decb8

File tree

7 files changed

+116
-94
lines changed

7 files changed

+116
-94
lines changed

src/librustc/ty/context.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use middle::resolve_lifetime;
2626
use middle::stability;
2727
use mir::Mir;
2828
use ty::subst::{Kind, Substs};
29+
use ty::ReprOptions;
2930
use traits;
3031
use ty::{self, TraitRef, Ty, TypeAndMut};
3132
use ty::{TyS, TypeVariants, Slice};
@@ -672,9 +673,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
672673
pub fn alloc_adt_def(self,
673674
did: DefId,
674675
kind: AdtKind,
675-
variants: Vec<ty::VariantDef>)
676+
variants: Vec<ty::VariantDef>,
677+
repr: ReprOptions)
676678
-> &'gcx ty::AdtDef {
677-
let def = ty::AdtDef::new(self, did, kind, variants);
679+
let def = ty::AdtDef::new(self, did, kind, variants, repr);
678680
self.global_arenas.adt_def.alloc(def)
679681
}
680682

src/librustc/ty/layout.rs

Lines changed: 39 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub use self::Primitive::*;
1515
use infer::InferCtxt;
1616
use session::Session;
1717
use traits;
18-
use ty::{self, Ty, TyCtxt, TypeFoldable};
18+
use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions};
1919

2020
use syntax::ast::{FloatTy, IntTy, UintTy};
2121
use syntax::attr;
@@ -437,7 +437,7 @@ impl Integer {
437437
/// signed discriminant range and #[repr] attribute.
438438
/// N.B.: u64 values above i64::MAX will be treated as signed, but
439439
/// that shouldn't affect anything, other than maybe debuginfo.
440-
fn repr_discr(tcx: TyCtxt, ty: Ty, hints: &[attr::ReprAttr], min: i64, max: i64)
440+
fn repr_discr(tcx: TyCtxt, ty: Ty, repr: &ReprOptions, min: i64, max: i64)
441441
-> (Integer, bool) {
442442
// Theoretically, negative values could be larger in unsigned representation
443443
// than the unsigned representation of the signed minimum. However, if there
@@ -449,34 +449,24 @@ impl Integer {
449449
let mut min_from_extern = None;
450450
let min_default = I8;
451451

452-
for &r in hints.iter() {
453-
match r {
454-
attr::ReprInt(ity) => {
455-
let discr = Integer::from_attr(&tcx.data_layout, ity);
456-
let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
457-
if discr < fit {
458-
bug!("Integer::repr_discr: `#[repr]` hint too small for \
459-
discriminant range of enum `{}", ty)
460-
}
461-
return (discr, ity.is_signed());
462-
}
463-
attr::ReprExtern => {
464-
match &tcx.sess.target.target.arch[..] {
465-
// WARNING: the ARM EABI has two variants; the one corresponding
466-
// to `at_least == I32` appears to be used on Linux and NetBSD,
467-
// but some systems may use the variant corresponding to no
468-
// lower bound. However, we don't run on those yet...?
469-
"arm" => min_from_extern = Some(I32),
470-
_ => min_from_extern = Some(I32),
471-
}
472-
}
473-
attr::ReprAny => {},
474-
attr::ReprPacked => {
475-
bug!("Integer::repr_discr: found #[repr(packed)] on enum `{}", ty);
476-
}
477-
attr::ReprSimd => {
478-
bug!("Integer::repr_discr: found #[repr(simd)] on enum `{}", ty);
479-
}
452+
if let Some(ity) = repr.int {
453+
let discr = Integer::from_attr(&tcx.data_layout, ity);
454+
let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
455+
if discr < fit {
456+
bug!("Integer::repr_discr: `#[repr]` hint too small for \
457+
discriminant range of enum `{}", ty)
458+
}
459+
return (discr, ity.is_signed());
460+
}
461+
462+
if repr.c {
463+
match &tcx.sess.target.target.arch[..] {
464+
// WARNING: the ARM EABI has two variants; the one corresponding
465+
// to `at_least == I32` appears to be used on Linux and NetBSD,
466+
// but some systems may use the variant corresponding to no
467+
// lower bound. However, we don't run on those yet...?
468+
"arm" => min_from_extern = Some(I32),
469+
_ => min_from_extern = Some(I32),
480470
}
481471
}
482472

@@ -568,9 +558,9 @@ enum StructKind {
568558
impl<'a, 'gcx, 'tcx> Struct {
569559
// FIXME(camlorn): reprs need a better representation to deal with multiple reprs on one type.
570560
fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>,
571-
reprs: &[attr::ReprAttr], kind: StructKind,
561+
repr: &ReprOptions, kind: StructKind,
572562
scapegoat: Ty<'gcx>) -> Result<Struct, LayoutError<'gcx>> {
573-
let packed = reprs.contains(&attr::ReprPacked);
563+
let packed = repr.packed;
574564
let mut ret = Struct {
575565
align: if packed { dl.i8_align } else { dl.aggregate_align },
576566
packed: packed,
@@ -580,27 +570,16 @@ impl<'a, 'gcx, 'tcx> Struct {
580570
min_size: Size::from_bytes(0),
581571
};
582572

583-
// Anything with ReprExtern or ReprPacked doesn't optimize.
573+
// Anything with repr(C) or repr(packed) doesn't optimize.
584574
// Neither do 1-member and 2-member structs.
585575
// In addition, code in trans assume that 2-element structs can become pairs.
586576
// It's easier to just short-circuit here.
587-
let mut can_optimize = fields.len() > 2 || StructKind::EnumVariant == kind;
588-
if can_optimize {
589-
// This exhaustive match makes new reprs force the adder to modify this function.
590-
// Otherwise, things can silently break.
591-
// Note the inversion, return true to stop optimizing.
592-
can_optimize = !reprs.iter().any(|r| {
593-
match *r {
594-
attr::ReprAny | attr::ReprInt(_) => false,
595-
attr::ReprExtern | attr::ReprPacked => true,
596-
attr::ReprSimd => bug!("Simd vectors should be represented as layout::Vector")
597-
}
598-
});
599-
}
577+
let mut can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind)
578+
&& ! (repr.c || repr.packed);
600579

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

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

10931072
// The never type.
10941073
ty::TyNever => Univariant {
1095-
variant: Struct::new(dl, &vec![], &[],
1074+
variant: Struct::new(dl, &vec![], &ReprOptions::default(),
10961075
StructKind::AlwaysSizedUnivariant, ty)?,
10971076
non_zero: false
10981077
},
@@ -1135,12 +1114,12 @@ impl<'a, 'gcx, 'tcx> Layout {
11351114
ty::TyFnDef(..) => {
11361115
Univariant {
11371116
variant: Struct::new(dl, &vec![],
1138-
&[], StructKind::AlwaysSizedUnivariant, ty)?,
1117+
&ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?,
11391118
non_zero: false
11401119
}
11411120
}
11421121
ty::TyDynamic(..) => {
1143-
let mut unit = Struct::new(dl, &vec![], &[],
1122+
let mut unit = Struct::new(dl, &vec![], &ReprOptions::default(),
11441123
StructKind::AlwaysSizedUnivariant, ty)?;
11451124
unit.sized = false;
11461125
Univariant { variant: unit, non_zero: false }
@@ -1152,7 +1131,7 @@ impl<'a, 'gcx, 'tcx> Layout {
11521131
let st = Struct::new(dl,
11531132
&tys.map(|ty| ty.layout(infcx))
11541133
.collect::<Result<Vec<_>, _>>()?,
1155-
&[],
1134+
&ReprOptions::default(),
11561135
StructKind::AlwaysSizedUnivariant, ty)?;
11571136
Univariant { variant: st, non_zero: false }
11581137
}
@@ -1163,7 +1142,7 @@ impl<'a, 'gcx, 'tcx> Layout {
11631142
let st = Struct::new(dl,
11641143
&tys.iter().map(|ty| ty.layout(infcx))
11651144
.collect::<Result<Vec<_>, _>>()?,
1166-
&[], StructKind::AlwaysSizedUnivariant, ty)?;
1145+
&ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?;
11671146
Univariant { variant: st, non_zero: false }
11681147
}
11691148

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

11881167
// ADTs.
11891168
ty::TyAdt(def, substs) => {
1190-
let hints = &tcx.lookup_repr_hints(def.did)[..];
1191-
11921169
if def.variants.is_empty() {
11931170
// Uninhabitable; represent as unit
11941171
// (Typechecking will reject discriminant-sizing attrs.)
1195-
assert_eq!(hints.len(), 0);
11961172

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

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

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

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

1285-
if variants.len() == 2 && hints.is_empty() {
1261+
if variants.len() == 2 && !def.repr.c {
12861262
// Nullable pointer optimization
12871263
for discr in 0..2 {
12881264
let other_fields = variants[1 - discr].iter().map(|ty| {
@@ -1315,7 +1291,7 @@ impl<'a, 'gcx, 'tcx> Layout {
13151291
let st = Struct::new(dl,
13161292
&variants[discr].iter().map(|ty| ty.layout(infcx))
13171293
.collect::<Result<Vec<_>, _>>()?,
1318-
&hints[..], StructKind::AlwaysSizedUnivariant, ty)?;
1294+
&def.repr, StructKind::AlwaysSizedUnivariant, ty)?;
13191295

13201296
// We have to fix the last element of path here.
13211297
let mut i = *path.last().unwrap();
@@ -1338,7 +1314,7 @@ impl<'a, 'gcx, 'tcx> Layout {
13381314
// The general case.
13391315
let discr_max = (variants.len() - 1) as i64;
13401316
assert!(discr_max >= 0);
1341-
let (min_ity, _) = Integer::repr_discr(tcx, ty, &hints[..], 0, discr_max);
1317+
let (min_ity, _) = Integer::repr_discr(tcx, ty, &def.repr, 0, discr_max);
13421318

13431319
let mut align = dl.aggregate_align;
13441320
let mut size = Size::from_bytes(0);
@@ -1356,7 +1332,7 @@ impl<'a, 'gcx, 'tcx> Layout {
13561332
fields.insert(0, &discr);
13571333
let st = Struct::new(dl,
13581334
&fields,
1359-
&hints[..], StructKind::EnumVariant, ty)?;
1335+
&def.repr, StructKind::EnumVariant, ty)?;
13601336
// Find the first field we can't move later
13611337
// to make room for a larger discriminant.
13621338
// It is important to skip the first field.

src/librustc/ty/mod.rs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1327,7 +1327,8 @@ pub struct AdtDef {
13271327
pub did: DefId,
13281328
pub variants: Vec<VariantDef>,
13291329
destructor: Cell<Option<DefId>>,
1330-
flags: Cell<AdtFlags>
1330+
flags: Cell<AdtFlags>,
1331+
pub repr: ReprOptions,
13311332
}
13321333

13331334
impl PartialEq for AdtDef {
@@ -1356,11 +1357,38 @@ impl<'tcx> serialize::UseSpecializedDecodable for &'tcx AdtDef {}
13561357
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
13571358
pub enum AdtKind { Struct, Union, Enum }
13581359

1360+
/// Represents the repr options provided by the user,
1361+
#[derive(Copy, Clone, Eq, PartialEq, RustcEncodable, RustcDecodable, Default)]
1362+
pub struct ReprOptions {
1363+
pub c: bool,
1364+
pub packed: bool,
1365+
pub simd: bool,
1366+
pub int: Option<attr::IntType>,
1367+
}
1368+
1369+
impl ReprOptions {
1370+
pub fn new<'a, 'gcx, 'tcx>(tcx: &TyCtxt<'a, 'gcx, 'tcx>, did: DefId) -> ReprOptions {
1371+
let mut ret = ReprOptions::default();
1372+
let attrs = tcx.lookup_repr_hints(did);
1373+
for r in attrs.iter() {
1374+
match *r {
1375+
attr::ReprExtern => ret.c = true,
1376+
attr::ReprPacked => ret.packed = true,
1377+
attr::ReprSimd => ret.simd = true,
1378+
attr::ReprInt(i) => ret.int = Some(i),
1379+
attr::ReprAny => (),
1380+
}
1381+
}
1382+
ret
1383+
}
1384+
}
1385+
13591386
impl<'a, 'gcx, 'tcx> AdtDef {
13601387
fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
13611388
did: DefId,
13621389
kind: AdtKind,
1363-
variants: Vec<VariantDef>) -> Self {
1390+
variants: Vec<VariantDef>,
1391+
repr: ReprOptions) -> Self {
13641392
let mut flags = AdtFlags::NO_ADT_FLAGS;
13651393
let attrs = tcx.get_attrs(did);
13661394
if attr::contains_name(&attrs, "fundamental") {
@@ -1385,6 +1413,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
13851413
variants: variants,
13861414
flags: Cell::new(flags),
13871415
destructor: Cell::new(None),
1416+
repr: repr,
13881417
}
13891418
}
13901419

src/librustc_metadata/decoder.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -425,8 +425,8 @@ impl<'tcx> EntryKind<'tcx> {
425425
EntryKind::ForeignImmStatic => Def::Static(did, false),
426426
EntryKind::MutStatic |
427427
EntryKind::ForeignMutStatic => Def::Static(did, true),
428-
EntryKind::Struct(_) => Def::Struct(did),
429-
EntryKind::Union(_) => Def::Union(did),
428+
EntryKind::Struct(_, _) => Def::Struct(did),
429+
EntryKind::Union(_, _) => Def::Union(did),
430430
EntryKind::Fn(_) |
431431
EntryKind::ForeignFn(_) => Def::Fn(did),
432432
EntryKind::Method(_) => Def::Method(did),
@@ -435,7 +435,7 @@ impl<'tcx> EntryKind<'tcx> {
435435
EntryKind::Mod(_) => Def::Mod(did),
436436
EntryKind::Variant(_) => Def::Variant(did),
437437
EntryKind::Trait(_) => Def::Trait(did),
438-
EntryKind::Enum => Def::Enum(did),
438+
EntryKind::Enum(_) => Def::Enum(did),
439439
EntryKind::MacroDef(_) => Def::Macro(did),
440440

441441
EntryKind::ForeignMod |
@@ -519,8 +519,8 @@ impl<'a, 'tcx> CrateMetadata {
519519
-> (ty::VariantDef, Option<DefIndex>) {
520520
let data = match item.kind {
521521
EntryKind::Variant(data) |
522-
EntryKind::Struct(data) |
523-
EntryKind::Union(data) => data.decode(self),
522+
EntryKind::Struct(data, _) |
523+
EntryKind::Union(data, _) => data.decode(self),
524524
_ => bug!(),
525525
};
526526

@@ -547,7 +547,7 @@ impl<'a, 'tcx> CrateMetadata {
547547
let item = self.entry(item_id);
548548
let did = self.local_def_id(item_id);
549549
let mut ctor_index = None;
550-
let variants = if let EntryKind::Enum = item.kind {
550+
let variants = if let EntryKind::Enum(_) = item.kind {
551551
item.children
552552
.decode(self)
553553
.map(|index| {
@@ -561,14 +561,14 @@ impl<'a, 'tcx> CrateMetadata {
561561
ctor_index = struct_ctor;
562562
vec![variant]
563563
};
564-
let kind = match item.kind {
565-
EntryKind::Enum => ty::AdtKind::Enum,
566-
EntryKind::Struct(_) => ty::AdtKind::Struct,
567-
EntryKind::Union(_) => ty::AdtKind::Union,
564+
let (kind, repr) = match item.kind {
565+
EntryKind::Enum(repr) => (ty::AdtKind::Enum, repr),
566+
EntryKind::Struct(_, repr) => (ty::AdtKind::Struct, repr),
567+
EntryKind::Union(_, repr) => (ty::AdtKind::Union, repr),
568568
_ => bug!("get_adt_def called on a non-ADT {:?}", did),
569569
};
570570

571-
let adt = tcx.alloc_adt_def(did, kind, variants);
571+
let adt = tcx.alloc_adt_def(did, kind, variants, repr);
572572
if let Some(ctor_index) = ctor_index {
573573
// Make adt definition available through constructor id as well.
574574
tcx.adt_defs.borrow_mut().insert(self.local_def_id(ctor_index), adt);
@@ -881,16 +881,16 @@ impl<'a, 'tcx> CrateMetadata {
881881

882882
pub fn get_ctor_kind(&self, node_id: DefIndex) -> CtorKind {
883883
match self.entry(node_id).kind {
884-
EntryKind::Struct(data) |
885-
EntryKind::Union(data) |
884+
EntryKind::Struct(data, _) |
885+
EntryKind::Union(data, _) |
886886
EntryKind::Variant(data) => data.decode(self).ctor_kind,
887887
_ => CtorKind::Fictive,
888888
}
889889
}
890890

891891
pub fn get_struct_ctor_def_id(&self, node_id: DefIndex) -> Option<DefId> {
892892
match self.entry(node_id).kind {
893-
EntryKind::Struct(data) => {
893+
EntryKind::Struct(data, _) => {
894894
data.decode(self).struct_ctor.map(|index| self.local_def_id(index))
895895
}
896896
_ => None,

0 commit comments

Comments
 (0)