diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 0d2876bdf81..44b86dc03c0 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -43,14 +43,13 @@ #![allow(unsigned_negation)] -pub use self::PointerField::*; pub use self::Repr::*; use std::num::Int; use std::rc::Rc; use llvm::{ValueRef, True, IntEQ, IntNE}; -use back::abi; +use back::abi::FAT_PTR_ADDR; use middle::subst; use middle::subst::Subst; use trans::_match; @@ -71,7 +70,6 @@ use util::ppaux::ty_to_string; type Hint = attr::ReprAttr; - /// Representations. #[deriving(Eq, PartialEq, Show)] pub enum Repr<'tcx> { @@ -101,7 +99,7 @@ pub enum Repr<'tcx> { nullfields: Vec> }, /// Two cases distinguished by a nullable pointer: the case with discriminant - /// `nndiscr` is represented by the struct `nonnull`, where the `ptrfield`th + /// `nndiscr` is represented by the struct `nonnull`, where the `discrfield`th /// field is known to be nonnull due to its type; if that field is null, then /// it represents the other case, which is inhabited by at most one value /// (and all other fields are undefined/unused). @@ -112,7 +110,7 @@ pub enum Repr<'tcx> { StructWrappedNullablePointer { nonnull: Struct<'tcx>, nndiscr: Disr, - ptrfield: PointerField, + discrfield: DiscrField, nullfields: Vec>, } } @@ -230,18 +228,20 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let st = mk_struct(cx, cases[discr].tys[], false, t); match cases[discr].find_ptr(cx) { - Some(ThinPointer(_)) if st.fields.len() == 1 => { + Some(ref pf) if pf.len() == 1 && st.fields.len() == 1 => { return RawNullablePointer { nndiscr: discr as Disr, nnty: st.fields[0], nullfields: cases[1 - discr].tys.clone() }; } - Some(ptrfield) => { + Some(pf) => { + let mut discrfield = vec![0]; + discrfield.extend(pf.into_iter()); return StructWrappedNullablePointer { nndiscr: discr as Disr, nonnull: st, - ptrfield: ptrfield, + discrfield: discrfield, nullfields: cases[1 - discr].tys.clone() }; } @@ -335,49 +335,67 @@ struct Case<'tcx> { tys: Vec> } +/// This represents the (GEP) indices to follow to get to the discriminant field +pub type DiscrField = Vec; -#[deriving(Copy, Eq, PartialEq, Show)] -pub enum PointerField { - ThinPointer(uint), - FatPointer(uint) +fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Option { + match ty.sty { + // &T/&mut T/Box could either be a thin or fat pointer depending on T + ty::ty_rptr(_, ty::mt { ty, .. }) | ty::ty_uniq(ty) => match ty.sty { + // &[T] and &str are a pointer and length pair + ty::ty_vec(_, None) | ty::ty_str => Some(vec![FAT_PTR_ADDR]), + + ty::ty_struct(..) if !ty::type_is_sized(tcx, ty) => Some(vec![FAT_PTR_ADDR]), + + // Any other &T is just a pointer + _ => Some(vec![]) + }, + + // Functions are just pointers + ty::ty_bare_fn(..) => Some(vec![]), + + // Closures are a pair of pointers: the code and environment + ty::ty_closure(..) => Some(vec![FAT_PTR_ADDR]), + + // Perhaps one of the fields of this struct is non-null + // let's recurse and find out + ty::ty_struct(def_id, ref substs) => { + let fields = ty::lookup_struct_fields(tcx, def_id); + for (j, field) in fields.iter().enumerate() { + let field_ty = ty::lookup_field_type(tcx, def_id, field.id, substs); + match find_discr_field_candidate(tcx, field_ty) { + Some(v) => { + let mut discrfield = vec![j]; + discrfield.extend(v.into_iter()); + return Some(discrfield); + } + None => continue + } + } + None + }, + + // Anything else is not a pointer + _ => None + } } impl<'tcx> Case<'tcx> { - fn is_zerolen<'a>(&self, cx: &CrateContext<'a, 'tcx>, scapegoat: Ty<'tcx>) - -> bool { + fn is_zerolen<'a>(&self, cx: &CrateContext<'a, 'tcx>, scapegoat: Ty<'tcx>) -> bool { mk_struct(cx, self.tys[], false, scapegoat).size == 0 } - fn find_ptr<'a>(&self, cx: &CrateContext<'a, 'tcx>) -> Option { + fn find_ptr<'a>(&self, cx: &CrateContext<'a, 'tcx>) -> Option { for (i, &ty) in self.tys.iter().enumerate() { - match ty.sty { - // &T/&mut T/Box could either be a thin or fat pointer depending on T - ty::ty_rptr(_, ty::mt { ty, .. }) | ty::ty_uniq(ty) => match ty.sty { - // &[T] and &str are a pointer and length pair - ty::ty_vec(_, None) | ty::ty_str => return Some(FatPointer(i)), - - // &Trait is a pair of pointers: the actual object and a vtable - ty::ty_trait(..) => return Some(FatPointer(i)), - - ty::ty_struct(..) if !ty::type_is_sized(cx.tcx(), ty) => { - return Some(FatPointer(i)) - } - - // Any other &T is just a pointer - _ => return Some(ThinPointer(i)) - }, - - // Functions are just pointers - ty::ty_bare_fn(..) => return Some(ThinPointer(i)), - - // Closures are a pair of pointers: the code and environment - ty::ty_closure(..) => return Some(FatPointer(i)), - - // Anything else is not a pointer - _ => continue + match find_discr_field_candidate(cx.tcx(), ty) { + Some(v) => { + let mut discrfield = vec![i]; + discrfield.extend(v.into_iter()); + return Some(discrfield); + } + None => continue } } - None } } @@ -709,8 +727,8 @@ pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, val = ICmp(bcx, cmp, Load(bcx, scrutinee), C_null(llptrty)); signed = false; } - StructWrappedNullablePointer { nndiscr, ptrfield, .. } => { - val = struct_wrapped_nullable_bitdiscr(bcx, nndiscr, ptrfield, scrutinee); + StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => { + val = struct_wrapped_nullable_bitdiscr(bcx, nndiscr, discrfield, scrutinee); signed = false; } } @@ -720,12 +738,9 @@ pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, } } -fn struct_wrapped_nullable_bitdiscr(bcx: Block, nndiscr: Disr, ptrfield: PointerField, +fn struct_wrapped_nullable_bitdiscr(bcx: Block, nndiscr: Disr, discrfield: &DiscrField, scrutinee: ValueRef) -> ValueRef { - let llptrptr = match ptrfield { - ThinPointer(field) => GEPi(bcx, scrutinee, &[0, field]), - FatPointer(field) => GEPi(bcx, scrutinee, &[0, field, abi::FAT_PTR_ADDR]) - }; + let llptrptr = GEPi(bcx, scrutinee, discrfield[]); let llptr = Load(bcx, llptrptr); let cmp = if nndiscr == 0 { IntEQ } else { IntNE }; ICmp(bcx, cmp, llptr, C_null(val_ty(llptr))) @@ -811,17 +826,10 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, Store(bcx, C_null(llptrty), val) } } - StructWrappedNullablePointer { ref nonnull, nndiscr, ptrfield, .. } => { + StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => { if discr != nndiscr { - let (llptrptr, llptrty) = match ptrfield { - ThinPointer(field) => - (GEPi(bcx, val, &[0, field]), - type_of::type_of(bcx.ccx(), nonnull.fields[field])), - FatPointer(field) => { - let v = GEPi(bcx, val, &[0, field, abi::FAT_PTR_ADDR]); - (v, val_ty(v).element_type()) - } - }; + let llptrptr = GEPi(bcx, val, discrfield[]); + let llptrty = val_ty(llptrptr).element_type(); Store(bcx, C_null(llptrty), llptrptr) } } @@ -1041,7 +1049,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>, discr false) } else { let vals = nonnull.fields.iter().map(|&ty| { - // Always use null even if it's not the `ptrfield`th + // Always use null even if it's not the `discrfield`th // field; see #8506. C_null(type_of::sizing_type_of(ccx, ty)) }).collect::>(); @@ -1121,9 +1129,8 @@ fn padding(ccx: &CrateContext, size: u64) -> ValueRef { #[inline] fn roundup(x: u64, a: u32) -> u64 { let a = a as u64; ((x + (a - 1)) / a) * a } -/// Get the discriminant of a constant value. (Not currently used.) -pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef) - -> Disr { +/// Get the discriminant of a constant value. +pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef) -> Disr { match *r { CEnum(ity, _, _) => { match ity { @@ -1138,25 +1145,8 @@ pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef) } } Univariant(..) => 0, - RawNullablePointer { nndiscr, .. } => { - if is_null(val) { - /* subtraction as uint is ok because nndiscr is either 0 or 1 */ - (1 - nndiscr) as Disr - } else { - nndiscr - } - } - StructWrappedNullablePointer { nndiscr, ptrfield, .. } => { - let (idx, sub_idx) = match ptrfield { - ThinPointer(field) => (field, None), - FatPointer(field) => (field, Some(abi::FAT_PTR_ADDR)) - }; - if is_null(const_struct_field(ccx, val, idx, sub_idx)) { - /* subtraction as uint is ok because nndiscr is either 0 or 1 */ - (1 - nndiscr) as Disr - } else { - nndiscr - } + RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => { + ccx.sess().bug("const discrim access of non c-like enum") } } } @@ -1170,29 +1160,25 @@ pub fn const_get_field(ccx: &CrateContext, r: &Repr, val: ValueRef, _discr: Disr, ix: uint) -> ValueRef { match *r { CEnum(..) => ccx.sess().bug("element access in C-like enum const"), - Univariant(..) => const_struct_field(ccx, val, ix, None), - General(..) => const_struct_field(ccx, val, ix + 1, None), + Univariant(..) => const_struct_field(ccx, val, ix), + General(..) => const_struct_field(ccx, val, ix + 1), RawNullablePointer { .. } => { assert_eq!(ix, 0); val - } - StructWrappedNullablePointer{ .. } => const_struct_field(ccx, val, ix, None) + }, + StructWrappedNullablePointer{ .. } => const_struct_field(ccx, val, ix) } } /// Extract field of struct-like const, skipping our alignment padding. -fn const_struct_field(ccx: &CrateContext, val: ValueRef, ix: uint, sub_idx: Option) - -> ValueRef { +fn const_struct_field(ccx: &CrateContext, val: ValueRef, ix: uint) -> ValueRef { // Get the ix-th non-undef element of the struct. let mut real_ix = 0; // actual position in the struct let mut ix = ix; // logical index relative to real_ix let mut field; loop { loop { - field = match sub_idx { - Some(si) => const_get_elt(ccx, val, &[real_ix, si as u32]), - None => const_get_elt(ccx, val, &[real_ix]) - }; + field = const_get_elt(ccx, val, &[real_ix]); if !is_undef(field) { break; } diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index ea2a4ef6b28..d080cda4b81 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -750,6 +750,7 @@ pub fn is_undef(val: ValueRef) -> bool { } } +#[allow(dead_code)] // potentially useful pub fn is_null(val: ValueRef) -> bool { unsafe { llvm::LLVMIsNull(val) != False diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 640e83469b2..b8c4a23b87a 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -2292,14 +2292,14 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { }, adt::StructWrappedNullablePointer { nonnull: ref struct_def, nndiscr, - ptrfield, ..} => { + ref discrfield, ..} => { // Create a description of the non-null variant let (variant_type_metadata, variant_llvm_type, member_description_factory) = describe_enum_variant(cx, self.enum_type, struct_def, &*(*self.variants)[nndiscr as uint], - OptimizedDiscriminant(ptrfield), + OptimizedDiscriminant, self.containing_scope, self.span); @@ -2315,10 +2315,10 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { // member's name. let null_variant_index = (1 - nndiscr) as uint; let null_variant_name = token::get_name((*self.variants)[null_variant_index].name); - let discrfield = match ptrfield { - adt::ThinPointer(field) => format!("{}", field), - adt::FatPointer(field) => format!("{}", field) - }; + let discrfield = discrfield.iter() + .skip(1) + .map(|x| x.to_string()) + .collect::>().connect("$"); let union_member_name = format!("RUST$ENCODED$ENUM${}${}", discrfield, null_variant_name); @@ -2367,7 +2367,7 @@ impl<'tcx> VariantMemberDescriptionFactory<'tcx> { #[deriving(Copy)] enum EnumDiscriminantInfo { RegularDiscriminant(DIType), - OptimizedDiscriminant(adt::PointerField), + OptimizedDiscriminant, NoDiscriminant }