about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLuqman Aden <laden@csclub.uwaterloo.ca>2014-12-04 16:44:51 -0500
committerLuqman Aden <laden@csclub.uwaterloo.ca>2014-12-28 19:40:46 -0500
commite954fc4385e92907916135244fd2fe0e47b24deb (patch)
tree382e1f857171753d482ef1ed43a84a27c0c608b3
parent3e6b29f8ad1ddfcb134d743a66ee5f467e16c350 (diff)
downloadrust-e954fc4385e92907916135244fd2fe0e47b24deb.tar.gz
rust-e954fc4385e92907916135244fd2fe0e47b24deb.zip
librustc: Traverse arbitrarily deep for nullable enum opt.
-rw-r--r--src/librustc_trans/trans/adt.rs166
-rw-r--r--src/librustc_trans/trans/common.rs1
-rw-r--r--src/librustc_trans/trans/debuginfo.rs14
3 files changed, 84 insertions, 97 deletions
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<Ty<'tcx>>
     },
     /// 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<Ty<'tcx>>,
     }
 }
@@ -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<Ty<'tcx>>
 }
 
+/// This represents the (GEP) indices to follow to get to the discriminant field
+pub type DiscrField = Vec<uint>;
 
-#[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<DiscrField> {
+    match ty.sty {
+        // &T/&mut T/Box<T> 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]),
 
-impl<'tcx> Case<'tcx> {
-    fn is_zerolen<'a>(&self, cx: &CrateContext<'a, 'tcx>, scapegoat: Ty<'tcx>)
-                      -> bool {
-        mk_struct(cx, self.tys[], false, scapegoat).size == 0
-    }
+            ty::ty_struct(..) if !ty::type_is_sized(tcx, ty) => Some(vec![FAT_PTR_ADDR]),
 
-    fn find_ptr<'a>(&self, cx: &CrateContext<'a, 'tcx>) -> Option<PointerField> {
-        for (i, &ty) in self.tys.iter().enumerate() {
-            match ty.sty {
-                // &T/&mut T/Box<T> 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)),
+            // Any other &T is just a pointer
+            _ => Some(vec![])
+        },
 
-                    // &Trait is a pair of pointers: the actual object and a vtable
-                    ty::ty_trait(..) => return Some(FatPointer(i)),
+        // Functions are just pointers
+        ty::ty_bare_fn(..) => Some(vec![]),
 
-                    ty::ty_struct(..) if !ty::type_is_sized(cx.tcx(), ty) => {
-                        return Some(FatPointer(i))
-                    }
+        // Closures are a pair of pointers: the code and environment
+        ty::ty_closure(..) => Some(vec![FAT_PTR_ADDR]),
 
-                    // Any other &T is just a pointer
-                    _ => return Some(ThinPointer(i))
-                },
+        // 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
+        },
 
-                // Functions are just pointers
-                ty::ty_bare_fn(..) => return Some(ThinPointer(i)),
+        // Anything else is not a pointer
+        _ => None
+    }
+}
 
-                // Closures are a pair of pointers: the code and environment
-                ty::ty_closure(..) => return Some(FatPointer(i)),
+impl<'tcx> Case<'tcx> {
+    fn is_zerolen<'a>(&self, cx: &CrateContext<'a, 'tcx>, scapegoat: Ty<'tcx>) -> bool {
+        mk_struct(cx, self.tys[], false, scapegoat).size == 0
+    }
 
-                // Anything else is not a pointer
-                _ => continue
+    fn find_ptr<'a>(&self, cx: &CrateContext<'a, 'tcx>) -> Option<DiscrField> {
+        for (i, &ty) in self.tys.iter().enumerate() {
+            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::<Vec<ValueRef>>();
@@ -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<uint>)
-    -> 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::<Vec<_>>().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
 }