Skip to content

Commit 3d7a446

Browse files
committed
librustc: Traverse arbitrarily deep for nullable enum opt.
1 parent 83a44c7 commit 3d7a446

File tree

2 files changed

+85
-96
lines changed

2 files changed

+85
-96
lines changed

src/librustc_trans/trans/adt.rs

Lines changed: 79 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,13 @@
4343
4444
#![allow(unsigned_negation)]
4545

46-
pub use self::PointerField::*;
4746
pub use self::Repr::*;
4847

4948
use std::num::Int;
5049
use std::rc::Rc;
5150

5251
use llvm::{ValueRef, True, IntEQ, IntNE};
53-
use back::abi;
52+
use back::abi::FAT_PTR_ADDR;
5453
use middle::subst;
5554
use middle::subst::Subst;
5655
use trans::_match;
@@ -71,7 +70,6 @@ use util::ppaux::ty_to_string;
7170

7271
type Hint = attr::ReprAttr;
7372

74-
7573
/// Representations.
7674
#[deriving(Eq, PartialEq, Show)]
7775
pub enum Repr<'tcx> {
@@ -101,7 +99,7 @@ pub enum Repr<'tcx> {
10199
nullfields: Vec<Ty<'tcx>>
102100
},
103101
/// Two cases distinguished by a nullable pointer: the case with discriminant
104-
/// `nndiscr` is represented by the struct `nonnull`, where the `ptrfield`th
102+
/// `nndiscr` is represented by the struct `nonnull`, where the `discrfield`th
105103
/// field is known to be nonnull due to its type; if that field is null, then
106104
/// it represents the other case, which is inhabited by at most one value
107105
/// (and all other fields are undefined/unused).
@@ -112,7 +110,7 @@ pub enum Repr<'tcx> {
112110
StructWrappedNullablePointer {
113111
nonnull: Struct<'tcx>,
114112
nndiscr: Disr,
115-
ptrfield: PointerField,
113+
discrfield: DiscrField,
116114
nullfields: Vec<Ty<'tcx>>,
117115
}
118116
}
@@ -230,18 +228,20 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
230228
let st = mk_struct(cx, cases[discr].tys.as_slice(),
231229
false, t);
232230
match cases[discr].find_ptr(cx) {
233-
Some(ThinPointer(_)) if st.fields.len() == 1 => {
231+
Some(ref pf) if pf.len() == 1 && st.fields.len() == 1 => {
234232
return RawNullablePointer {
235233
nndiscr: discr as Disr,
236234
nnty: st.fields[0],
237235
nullfields: cases[1 - discr].tys.clone()
238236
};
239237
}
240-
Some(ptrfield) => {
238+
Some(pf) => {
239+
let mut discrfield = vec![0];
240+
discrfield.extend(pf.into_iter());
241241
return StructWrappedNullablePointer {
242242
nndiscr: discr as Disr,
243243
nonnull: st,
244-
ptrfield: ptrfield,
244+
discrfield: discrfield,
245245
nullfields: cases[1 - discr].tys.clone()
246246
};
247247
}
@@ -280,48 +280,70 @@ struct Case<'tcx> {
280280
tys: Vec<Ty<'tcx>>
281281
}
282282

283+
/// This represents the (GEP) indices to follow to get to the discriminant field
284+
pub type DiscrField = Vec<uint>;
283285

284-
#[deriving(Eq, PartialEq, Show)]
285-
pub enum PointerField {
286-
ThinPointer(uint),
287-
FatPointer(uint)
288-
}
286+
fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Option<DiscrField> {
287+
match ty.sty {
288+
// &T/&mut T/Box<T> could either be a thin or fat pointer depending on T
289+
ty::ty_rptr(_, ty::mt { ty, .. }) | ty::ty_uniq(ty) => match ty.sty {
290+
// &[T] and &str are a pointer and length pair
291+
ty::ty_vec(_, None) | ty::ty_str => Some(vec![FAT_PTR_ADDR]),
289292

290-
impl<'tcx> Case<'tcx> {
291-
fn is_zerolen<'a>(&self, cx: &CrateContext<'a, 'tcx>, scapegoat: Ty<'tcx>) -> bool {
292-
mk_struct(cx, self.tys.as_slice(), false, scapegoat).size == 0
293-
}
293+
// &Trait is a pair of pointers: the actual object and a vtable
294+
ty::ty_trait(..) => Some(vec![FAT_PTR_ADDR]),
294295

295-
fn find_ptr<'a>(&self, cx: &CrateContext<'a, 'tcx>) -> Option<PointerField> {
296-
for (i, &ty) in self.tys.iter().enumerate() {
297-
match ty.sty {
298-
// &T/&mut T/Box<T> could either be a thin or fat pointer depending on T
299-
ty::ty_rptr(_, ty::mt { ty, .. }) | ty::ty_uniq(ty) => match ty.sty {
300-
// &[T] and &str are a pointer and length pair
301-
ty::ty_vec(_, None) | ty::ty_str => return Some(FatPointer(i)),
296+
ty::ty_struct(..) if !ty::type_is_sized(tcx, ty) => Some(vec![FAT_PTR_ADDR]),
302297

303-
// &Trait is a pair of pointers: the actual object and a vtable
304-
ty::ty_trait(..) => return Some(FatPointer(i)),
298+
// Any other &T is just a pointer
299+
_ => Some(vec![])
300+
},
305301

306-
ty::ty_struct(..) if !ty::type_is_sized(cx.tcx(), ty) => {
307-
return Some(FatPointer(i))
308-
}
302+
// Functions are just pointers
303+
ty::ty_bare_fn(..) => Some(vec![]),
309304

310-
// Any other &T is just a pointer
311-
_ => return Some(ThinPointer(i))
312-
},
305+
// Closures are a pair of pointers: the code and environment
306+
ty::ty_closure(..) => Some(vec![FAT_PTR_ADDR]),
313307

314-
// Functions are just pointers
315-
ty::ty_bare_fn(..) => return Some(ThinPointer(i)),
308+
// Perhaps one of the fields of this struct is non-null
309+
// let's recurse and find out
310+
ty::ty_struct(def_id, ref substs) => {
311+
let fields = ty::lookup_struct_fields(tcx, def_id);
312+
for (j, field) in fields.iter().enumerate() {
313+
let field_ty = ty::lookup_field_type(tcx, def_id, field.id, substs);
314+
match find_discr_field_candidate(tcx, field_ty) {
315+
Some(v) => {
316+
let mut discrfield = vec![j];
317+
discrfield.extend(v.into_iter());
318+
return Some(discrfield);
319+
}
320+
None => continue
321+
}
322+
}
323+
None
324+
},
316325

317-
// Closures are a pair of pointers: the code and environment
318-
ty::ty_closure(..) => return Some(FatPointer(i)),
326+
// Anything else is not a pointer
327+
_ => None
328+
}
329+
}
319330

320-
// Anything else is not a pointer
321-
_ => continue
331+
impl<'tcx> Case<'tcx> {
332+
fn is_zerolen<'a>(&self, cx: &CrateContext<'a, 'tcx>, scapegoat: Ty<'tcx>) -> bool {
333+
mk_struct(cx, self.tys.as_slice(), false, scapegoat).size == 0
334+
}
335+
336+
fn find_ptr<'a>(&self, cx: &CrateContext<'a, 'tcx>) -> Option<DiscrField> {
337+
for (i, &ty) in self.tys.iter().enumerate() {
338+
match find_discr_field_candidate(cx.tcx(), ty) {
339+
Some(v) => {
340+
let mut discrfield = vec![i];
341+
discrfield.extend(v.into_iter());
342+
return Some(discrfield);
343+
}
344+
None => continue
322345
}
323346
}
324-
325347
None
326348
}
327349
}
@@ -653,8 +675,8 @@ pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
653675
val = ICmp(bcx, cmp, Load(bcx, scrutinee), C_null(llptrty));
654676
signed = false;
655677
}
656-
StructWrappedNullablePointer { nndiscr, ptrfield, .. } => {
657-
val = struct_wrapped_nullable_bitdiscr(bcx, nndiscr, ptrfield, scrutinee);
678+
StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
679+
val = struct_wrapped_nullable_bitdiscr(bcx, nndiscr, discrfield, scrutinee);
658680
signed = false;
659681
}
660682
}
@@ -664,12 +686,9 @@ pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
664686
}
665687
}
666688

667-
fn struct_wrapped_nullable_bitdiscr(bcx: Block, nndiscr: Disr, ptrfield: PointerField,
689+
fn struct_wrapped_nullable_bitdiscr(bcx: Block, nndiscr: Disr, discrfield: &DiscrField,
668690
scrutinee: ValueRef) -> ValueRef {
669-
let llptrptr = match ptrfield {
670-
ThinPointer(field) => GEPi(bcx, scrutinee, &[0, field]),
671-
FatPointer(field) => GEPi(bcx, scrutinee, &[0, field, abi::FAT_PTR_ADDR])
672-
};
691+
let llptrptr = GEPi(bcx, scrutinee, discrfield[]);
673692
let llptr = Load(bcx, llptrptr);
674693
let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
675694
ICmp(bcx, cmp, llptr, C_null(val_ty(llptr)))
@@ -755,17 +774,10 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
755774
Store(bcx, C_null(llptrty), val)
756775
}
757776
}
758-
StructWrappedNullablePointer { ref nonnull, nndiscr, ptrfield, .. } => {
777+
StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
759778
if discr != nndiscr {
760-
let (llptrptr, llptrty) = match ptrfield {
761-
ThinPointer(field) =>
762-
(GEPi(bcx, val, &[0, field]),
763-
type_of::type_of(bcx.ccx(), nonnull.fields[field])),
764-
FatPointer(field) => {
765-
let v = GEPi(bcx, val, &[0, field, abi::FAT_PTR_ADDR]);
766-
(v, val_ty(v).element_type())
767-
}
768-
};
779+
let llptrptr = GEPi(bcx, val, discrfield[]);
780+
let llptrty = val_ty(llptrptr).element_type();
769781
Store(bcx, C_null(llptrty), llptrptr)
770782
}
771783
}
@@ -982,7 +994,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>, discr
982994
false)
983995
} else {
984996
let vals = nonnull.fields.iter().map(|&ty| {
985-
// Always use null even if it's not the `ptrfield`th
997+
// Always use null even if it's not the `discrfield`th
986998
// field; see #8506.
987999
C_null(type_of::sizing_type_of(ccx, ty))
9881000
}).collect::<Vec<ValueRef>>();
@@ -1062,9 +1074,8 @@ fn padding(ccx: &CrateContext, size: u64) -> ValueRef {
10621074
#[inline]
10631075
fn roundup(x: u64, a: u32) -> u64 { let a = a as u64; ((x + (a - 1)) / a) * a }
10641076

1065-
/// Get the discriminant of a constant value. (Not currently used.)
1066-
pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef)
1067-
-> Disr {
1077+
/// Get the discriminant of a constant value.
1078+
pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef) -> Disr {
10681079
match *r {
10691080
CEnum(ity, _, _) => {
10701081
match ity {
@@ -1079,25 +1090,8 @@ pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef)
10791090
}
10801091
}
10811092
Univariant(..) => 0,
1082-
RawNullablePointer { nndiscr, .. } => {
1083-
if is_null(val) {
1084-
/* subtraction as uint is ok because nndiscr is either 0 or 1 */
1085-
(1 - nndiscr) as Disr
1086-
} else {
1087-
nndiscr
1088-
}
1089-
}
1090-
StructWrappedNullablePointer { nndiscr, ptrfield, .. } => {
1091-
let (idx, sub_idx) = match ptrfield {
1092-
ThinPointer(field) => (field, None),
1093-
FatPointer(field) => (field, Some(abi::FAT_PTR_ADDR))
1094-
};
1095-
if is_null(const_struct_field(ccx, val, idx, sub_idx)) {
1096-
/* subtraction as uint is ok because nndiscr is either 0 or 1 */
1097-
(1 - nndiscr) as Disr
1098-
} else {
1099-
nndiscr
1100-
}
1093+
RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => {
1094+
ccx.sess().bug("const discrim access of non c-like enum")
11011095
}
11021096
}
11031097
}
@@ -1111,29 +1105,25 @@ pub fn const_get_field(ccx: &CrateContext, r: &Repr, val: ValueRef,
11111105
_discr: Disr, ix: uint) -> ValueRef {
11121106
match *r {
11131107
CEnum(..) => ccx.sess().bug("element access in C-like enum const"),
1114-
Univariant(..) => const_struct_field(ccx, val, ix, None),
1115-
General(..) => const_struct_field(ccx, val, ix + 1, None),
1108+
Univariant(..) => const_struct_field(ccx, val, ix),
1109+
General(..) => const_struct_field(ccx, val, ix + 1),
11161110
RawNullablePointer { .. } => {
11171111
assert_eq!(ix, 0);
11181112
val
1119-
}
1120-
StructWrappedNullablePointer{ .. } => const_struct_field(ccx, val, ix, None)
1113+
},
1114+
StructWrappedNullablePointer{ .. } => const_struct_field(ccx, val, ix)
11211115
}
11221116
}
11231117

11241118
/// Extract field of struct-like const, skipping our alignment padding.
1125-
fn const_struct_field(ccx: &CrateContext, val: ValueRef, ix: uint, sub_idx: Option<uint>)
1126-
-> ValueRef {
1119+
fn const_struct_field(ccx: &CrateContext, val: ValueRef, ix: uint) -> ValueRef {
11271120
// Get the ix-th non-undef element of the struct.
11281121
let mut real_ix = 0; // actual position in the struct
11291122
let mut ix = ix; // logical index relative to real_ix
11301123
let mut field;
11311124
loop {
11321125
loop {
1133-
field = match sub_idx {
1134-
Some(si) => const_get_elt(ccx, val, &[real_ix, si as u32]),
1135-
None => const_get_elt(ccx, val, &[real_ix])
1136-
};
1126+
field = const_get_elt(ccx, val, &[real_ix]);
11371127
if !is_undef(field) {
11381128
break;
11391129
}

src/librustc_trans/trans/debuginfo.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2245,14 +2245,14 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
22452245
},
22462246
adt::StructWrappedNullablePointer { nonnull: ref struct_def,
22472247
nndiscr,
2248-
ptrfield, ..} => {
2248+
ref discrfield, ..} => {
22492249
// Create a description of the non-null variant
22502250
let (variant_type_metadata, variant_llvm_type, member_description_factory) =
22512251
describe_enum_variant(cx,
22522252
self.enum_type,
22532253
struct_def,
22542254
&*(*self.variants)[nndiscr as uint],
2255-
OptimizedDiscriminant(ptrfield),
2255+
OptimizedDiscriminant,
22562256
self.containing_scope,
22572257
self.span);
22582258

@@ -2268,10 +2268,9 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
22682268
// member's name.
22692269
let null_variant_index = (1 - nndiscr) as uint;
22702270
let null_variant_name = token::get_name((*self.variants)[null_variant_index].name);
2271-
let discrfield = match ptrfield {
2272-
adt::ThinPointer(field) => format!("{}", field),
2273-
adt::FatPointer(field) => format!("{}", field)
2274-
};
2271+
let discrfield = discrfield.iter()
2272+
.map(|x| x.to_string())
2273+
.collect::<Vec<_>>().connect("$");
22752274
let union_member_name = format!("RUST$ENCODED$ENUM${}${}",
22762275
discrfield,
22772276
null_variant_name);
@@ -2319,7 +2318,7 @@ impl<'tcx> VariantMemberDescriptionFactory<'tcx> {
23192318

23202319
enum EnumDiscriminantInfo {
23212320
RegularDiscriminant(DIType),
2322-
OptimizedDiscriminant(adt::PointerField),
2321+
OptimizedDiscriminant,
23232322
NoDiscriminant
23242323
}
23252324

0 commit comments

Comments
 (0)