]> git.lizzy.rs Git - rust.git/commitdiff
Address comments
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Mon, 5 Sep 2016 22:26:02 +0000 (01:26 +0300)
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Thu, 8 Sep 2016 20:37:32 +0000 (23:37 +0300)
src/librustc/ty/layout.rs
src/librustc/ty/util.rs

index 3c0aa041d2dd3a62b3c3b297186e439176e8eee5..e3f3da916a0a94df2fd45d442874392d94c2f53f 100644 (file)
@@ -15,7 +15,7 @@
 use infer::InferCtxt;
 use session::Session;
 use traits;
-use ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable};
+use ty::{self, Ty, TyCtxt, TypeFoldable};
 
 use syntax::ast::{FloatTy, IntTy, UintTy};
 use syntax::attr;
@@ -555,7 +555,7 @@ pub fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
             }
 
             // Is this the NonZero lang item wrapping a pointer or integer type?
-            (&Univariant { non_zero: true, .. }, &ty::TyAdt(def, substs)) if def.is_struct() => {
+            (&Univariant { non_zero: true, .. }, &ty::TyAdt(def, substs)) => {
                 let fields = &def.struct_variant().fields;
                 assert_eq!(fields.len(), 1);
                 match *fields[0].ty(tcx, substs).layout(infcx)? {
@@ -918,243 +918,229 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                 Univariant { variant: st, non_zero: false }
             }
 
-            // ADTs.
-            ty::TyAdt(def, substs) => match def.adt_kind() {
-                AdtKind::Struct => {
-                    if ty.is_simd() {
-                        // SIMD vector types.
-                        let element = ty.simd_type(tcx);
-                        match *element.layout(infcx)? {
-                            Scalar { value, .. } => {
-                                return success(Vector {
-                                    element: value,
-                                    count: ty.simd_size(tcx) as u64
-                                });
-                            }
-                            _ => {
-                                tcx.sess.fatal(&format!("monomorphising SIMD type `{}` with \
-                                                        a non-machine element type `{}`",
-                                                        ty, element));
-                            }
-                        }
+            // SIMD vector types.
+            ty::TyAdt(def, ..) if def.is_simd() => {
+                let element = ty.simd_type(tcx);
+                match *element.layout(infcx)? {
+                    Scalar { value, .. } => {
+                        return success(Vector {
+                            element: value,
+                            count: ty.simd_size(tcx) as u64
+                        });
                     }
-                    let fields = def.struct_variant().fields.iter().map(|field| {
-                        field.ty(tcx, substs).layout(infcx)
+                    _ => {
+                        tcx.sess.fatal(&format!("monomorphising SIMD type `{}` with \
+                                                a non-machine element type `{}`",
+                                                ty, element));
+                    }
+                }
+            }
+
+            // ADTs.
+            ty::TyAdt(def, substs) => {
+                let hint = *tcx.lookup_repr_hints(def.did).get(0)
+                    .unwrap_or(&attr::ReprAny);
+
+                if def.variants.is_empty() {
+                    // Uninhabitable; represent as unit
+                    // (Typechecking will reject discriminant-sizing attrs.)
+                    assert_eq!(hint, attr::ReprAny);
+
+                    return success(Univariant {
+                        variant: Struct::new(dl, false),
+                        non_zero: false
                     });
-                    let packed = tcx.lookup_packed(def.did);
-                    let mut st = Struct::new(dl, packed);
-                    st.extend(dl, fields, ty)?;
+                }
 
-                    Univariant {
-                        variant: st,
-                        non_zero: Some(def.did) == tcx.lang_items.non_zero()
+                if def.is_enum() && def.variants.iter().all(|v| v.fields.is_empty()) {
+                    // All bodies empty -> intlike
+                    let (mut min, mut max) = (i64::MAX, i64::MIN);
+                    for v in &def.variants {
+                        let x = v.disr_val.to_u64_unchecked() as i64;
+                        if x < min { min = x; }
+                        if x > max { max = x; }
                     }
+
+                    let (discr, signed) = Integer::repr_discr(tcx, hint, min, max);
+                    return success(CEnum {
+                        discr: discr,
+                        signed: signed,
+                        min: min as u64,
+                        max: max as u64
+                    });
                 }
-                AdtKind::Union => {
-                    let fields = def.struct_variant().fields.iter().map(|field| {
+
+                if def.variants.len() == 1 {
+                    // Struct, or union, or univariant enum equivalent to a struct.
+                    // (Typechecking will reject discriminant-sizing attrs.)
+                    assert!(!def.is_enum() || hint == attr::ReprAny);
+                    let fields = def.variants[0].fields.iter().map(|field| {
                         field.ty(tcx, substs).layout(infcx)
                     });
                     let packed = tcx.lookup_packed(def.did);
-                    let mut un = Union::new(dl, packed);
-                    un.extend(dl, fields, ty)?;
-                    UntaggedUnion { variants: un }
+                    let layout = if def.is_union() {
+                        let mut un = Union::new(dl, packed);
+                        un.extend(dl, fields, ty)?;
+                        UntaggedUnion { variants: un }
+                    } else {
+                        let mut st = Struct::new(dl, packed);
+                        st.extend(dl, fields, ty)?;
+                        let non_zero = Some(def.did) == tcx.lang_items.non_zero();
+                        Univariant { variant: st, non_zero: non_zero }
+                    };
+                    return success(layout);
                 }
-                AdtKind::Enum => {
-                    let hint = *tcx.lookup_repr_hints(def.did).get(0)
-                        .unwrap_or(&attr::ReprAny);
-
-                    if def.variants.is_empty() {
-                        // Uninhabitable; represent as unit
-                        // (Typechecking will reject discriminant-sizing attrs.)
-                        assert_eq!(hint, attr::ReprAny);
-
-                        return success(Univariant {
-                            variant: Struct::new(dl, false),
-                            non_zero: false
-                        });
-                    }
-
-                    if def.variants.iter().all(|v| v.fields.is_empty()) {
-                        // All bodies empty -> intlike
-                        let (mut min, mut max) = (i64::MAX, i64::MIN);
-                        for v in &def.variants {
-                            let x = v.disr_val.to_u64_unchecked() as i64;
-                            if x < min { min = x; }
-                            if x > max { max = x; }
-                        }
 
-                        let (discr, signed) = Integer::repr_discr(tcx, hint, min, max);
-                        return success(CEnum {
-                            discr: discr,
-                            signed: signed,
-                            min: min as u64,
-                            max: max as u64
-                        });
+                // Since there's at least one
+                // non-empty body, explicit discriminants should have
+                // been rejected by a checker before this point.
+                for (i, v) in def.variants.iter().enumerate() {
+                    if i as u64 != v.disr_val.to_u64_unchecked() {
+                        bug!("non-C-like enum {} with specified discriminants",
+                            tcx.item_path_str(def.did));
                     }
+                }
 
-                    // Since there's at least one
-                    // non-empty body, explicit discriminants should have
-                    // been rejected by a checker before this point.
-                    for (i, v) in def.variants.iter().enumerate() {
-                        if i as u64 != v.disr_val.to_u64_unchecked() {
-                            bug!("non-C-like enum {} with specified discriminants",
-                                tcx.item_path_str(def.did));
-                        }
-                    }
+                // Cache the substituted and normalized variant field types.
+                let variants = def.variants.iter().map(|v| {
+                    v.fields.iter().map(|field| field.ty(tcx, substs)).collect::<Vec<_>>()
+                }).collect::<Vec<_>>();
 
-                    if def.variants.len() == 1 {
-                        // Equivalent to a struct/tuple/newtype.
-                        // (Typechecking will reject discriminant-sizing attrs.)
-                        assert_eq!(hint, attr::ReprAny);
-                        let fields = def.variants[0].fields.iter().map(|field| {
-                            field.ty(tcx, substs).layout(infcx)
+                if variants.len() == 2 && hint == attr::ReprAny {
+                    // Nullable pointer optimization
+                    for discr in 0..2 {
+                        let other_fields = variants[1 - discr].iter().map(|ty| {
+                            ty.layout(infcx)
                         });
-                        let mut st = Struct::new(dl, false);
-                        st.extend(dl, fields, ty)?;
-                        return success(Univariant { variant: st, non_zero: false });
-                    }
-
-                    // Cache the substituted and normalized variant field types.
-                    let variants = def.variants.iter().map(|v| {
-                        v.fields.iter().map(|field| field.ty(tcx, substs)).collect::<Vec<_>>()
-                    }).collect::<Vec<_>>();
-
-                    if variants.len() == 2 && hint == attr::ReprAny {
-                        // Nullable pointer optimization
-                        for discr in 0..2 {
-                            let other_fields = variants[1 - discr].iter().map(|ty| {
-                                ty.layout(infcx)
-                            });
-                            if !Struct::would_be_zero_sized(dl, other_fields)? {
-                                continue;
-                            }
-                            let path = Struct::non_zero_field_path(infcx,
-                                variants[discr].iter().cloned())?;
-                            let mut path = if let Some(p) = path { p } else { continue };
-
-                            // FIXME(eddyb) should take advantage of a newtype.
-                            if path == &[0] && variants[discr].len() == 1 {
-                                match *variants[discr][0].layout(infcx)? {
-                                    Scalar { value, .. } => {
-                                        return success(RawNullablePointer {
-                                            nndiscr: discr as u64,
-                                            value: value
-                                        });
-                                    }
-                                    _ => {
-                                        bug!("Layout::compute: `{}`'s non-zero \
-                                            `{}` field not scalar?!",
-                                            ty, variants[discr][0])
-                                    }
+                        if !Struct::would_be_zero_sized(dl, other_fields)? {
+                            continue;
+                        }
+                        let path = Struct::non_zero_field_path(infcx,
+                            variants[discr].iter().cloned())?;
+                        let mut path = if let Some(p) = path { p } else { continue };
+
+                        // FIXME(eddyb) should take advantage of a newtype.
+                        if path == &[0] && variants[discr].len() == 1 {
+                            match *variants[discr][0].layout(infcx)? {
+                                Scalar { value, .. } => {
+                                    return success(RawNullablePointer {
+                                        nndiscr: discr as u64,
+                                        value: value
+                                    });
+                                }
+                                _ => {
+                                    bug!("Layout::compute: `{}`'s non-zero \
+                                        `{}` field not scalar?!",
+                                        ty, variants[discr][0])
                                 }
                             }
-
-                            path.push(0); // For GEP through a pointer.
-                            path.reverse();
-                            let mut st = Struct::new(dl, false);
-                            st.extend(dl, variants[discr].iter().map(|ty| ty.layout(infcx)), ty)?;
-                            return success(StructWrappedNullablePointer {
-                                nndiscr: discr as u64,
-                                nonnull: st,
-                                discrfield: path
-                            });
                         }
-                    }
 
-                    // The general case.
-                    let discr_max = (variants.len() - 1) as i64;
-                    assert!(discr_max >= 0);
-                    let (min_ity, _) = Integer::repr_discr(tcx, hint, 0, discr_max);
-
-                    let mut align = dl.aggregate_align;
-                    let mut size = Size::from_bytes(0);
-
-                    // We're interested in the smallest alignment, so start large.
-                    let mut start_align = Align::from_bytes(256, 256).unwrap();
-
-                    // Create the set of structs that represent each variant
-                    // Use the minimum integer type we figured out above
-                    let discr = Some(Scalar { value: Int(min_ity), non_zero: false });
-                    let mut variants = variants.into_iter().map(|fields| {
-                        let mut found_start = false;
-                        let fields = fields.into_iter().map(|field| {
-                            let field = field.layout(infcx)?;
-                            if !found_start {
-                                // Find the first field we can't move later
-                                // to make room for a larger discriminant.
-                                let field_align = field.align(dl);
-                                if field.size(dl).bytes() != 0 || field_align.abi() != 1 {
-                                    start_align = start_align.min(field_align);
-                                    found_start = true;
-                                }
-                            }
-                            Ok(field)
-                        });
+                        path.push(0); // For GEP through a pointer.
+                        path.reverse();
                         let mut st = Struct::new(dl, false);
-                        st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?;
-                        size = cmp::max(size, st.min_size());
-                        align = align.max(st.align);
-                        Ok(st)
-                    }).collect::<Result<Vec<_>, _>>()?;
-
-                    // Align the maximum variant size to the largest alignment.
-                    size = size.abi_align(align);
-
-                    if size.bytes() >= dl.obj_size_bound() {
-                        return Err(LayoutError::SizeOverflow(ty));
+                        st.extend(dl, variants[discr].iter().map(|ty| ty.layout(infcx)), ty)?;
+                        return success(StructWrappedNullablePointer {
+                            nndiscr: discr as u64,
+                            nonnull: st,
+                            discrfield: path
+                        });
                     }
+                }
 
-                    // Check to see if we should use a different type for the
-                    // discriminant. We can safely use a type with the same size
-                    // as the alignment of the first field of each variant.
-                    // We increase the size of the discriminant to avoid LLVM copying
-                    // padding when it doesn't need to. This normally causes unaligned
-                    // load/stores and excessive memcpy/memset operations. By using a
-                    // bigger integer size, LLVM can be sure about it's contents and
-                    // won't be so conservative.
-
-                    // Use the initial field alignment
-                    let wanted = start_align.abi();
-                    let mut ity = min_ity;
-                    for &candidate in &[I16, I32, I64] {
-                        let ty = Int(candidate);
-                        if wanted == ty.align(dl).abi() && wanted == ty.size(dl).bytes() {
-                            ity = candidate;
-                            break;
+                // The general case.
+                let discr_max = (variants.len() - 1) as i64;
+                assert!(discr_max >= 0);
+                let (min_ity, _) = Integer::repr_discr(tcx, hint, 0, discr_max);
+
+                let mut align = dl.aggregate_align;
+                let mut size = Size::from_bytes(0);
+
+                // We're interested in the smallest alignment, so start large.
+                let mut start_align = Align::from_bytes(256, 256).unwrap();
+
+                // Create the set of structs that represent each variant
+                // Use the minimum integer type we figured out above
+                let discr = Some(Scalar { value: Int(min_ity), non_zero: false });
+                let mut variants = variants.into_iter().map(|fields| {
+                    let mut found_start = false;
+                    let fields = fields.into_iter().map(|field| {
+                        let field = field.layout(infcx)?;
+                        if !found_start {
+                            // Find the first field we can't move later
+                            // to make room for a larger discriminant.
+                            let field_align = field.align(dl);
+                            if field.size(dl).bytes() != 0 || field_align.abi() != 1 {
+                                start_align = start_align.min(field_align);
+                                found_start = true;
+                            }
                         }
-                    }
+                        Ok(field)
+                    });
+                    let mut st = Struct::new(dl, false);
+                    st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?;
+                    size = cmp::max(size, st.min_size());
+                    align = align.max(st.align);
+                    Ok(st)
+                }).collect::<Result<Vec<_>, _>>()?;
+
+                // Align the maximum variant size to the largest alignment.
+                size = size.abi_align(align);
+
+                if size.bytes() >= dl.obj_size_bound() {
+                    return Err(LayoutError::SizeOverflow(ty));
+                }
 
-                    // FIXME(eddyb) conservative only to avoid diverging from trans::adt.
-                    if align.abi() != start_align.abi() {
-                        ity = min_ity;
+                // Check to see if we should use a different type for the
+                // discriminant. We can safely use a type with the same size
+                // as the alignment of the first field of each variant.
+                // We increase the size of the discriminant to avoid LLVM copying
+                // padding when it doesn't need to. This normally causes unaligned
+                // load/stores and excessive memcpy/memset operations. By using a
+                // bigger integer size, LLVM can be sure about it's contents and
+                // won't be so conservative.
+
+                // Use the initial field alignment
+                let wanted = start_align.abi();
+                let mut ity = min_ity;
+                for &candidate in &[I16, I32, I64] {
+                    let ty = Int(candidate);
+                    if wanted == ty.align(dl).abi() && wanted == ty.size(dl).bytes() {
+                        ity = candidate;
+                        break;
                     }
+                }
 
-                    // If the alignment is not larger than the chosen discriminant size,
-                    // don't use the alignment as the final size.
-                    if ity <= min_ity {
-                        ity = min_ity;
-                    } else {
-                        // Patch up the variants' first few fields.
-                        let old_ity_size = Int(min_ity).size(dl);
-                        let new_ity_size = Int(ity).size(dl);
-                        for variant in &mut variants {
-                            for offset in &mut variant.offset_after_field {
-                                if *offset > old_ity_size {
-                                    break;
-                                }
-                                *offset = new_ity_size;
+                // FIXME(eddyb) conservative only to avoid diverging from trans::adt.
+                if align.abi() != start_align.abi() {
+                    ity = min_ity;
+                }
+
+                // If the alignment is not larger than the chosen discriminant size,
+                // don't use the alignment as the final size.
+                if ity <= min_ity {
+                    ity = min_ity;
+                } else {
+                    // Patch up the variants' first few fields.
+                    let old_ity_size = Int(min_ity).size(dl);
+                    let new_ity_size = Int(ity).size(dl);
+                    for variant in &mut variants {
+                        for offset in &mut variant.offset_after_field {
+                            if *offset > old_ity_size {
+                                break;
                             }
+                            *offset = new_ity_size;
                         }
                     }
+                }
 
-                    General {
-                        discr: ity,
-                        variants: variants,
-                        size: size,
-                        align: align
-                    }
+                General {
+                    discr: ity,
+                    variants: variants,
+                    size: size,
+                    align: align
                 }
-            },
+            }
 
             // Types with no meaningful known layout.
             ty::TyProjection(_) | ty::TyAnon(..) => {
index 68de8d96f33dcbfd56399869d0608c91c5237222..6b3ebaa895fa3883a59321596d1062b6dbf67e9b 100644 (file)
@@ -253,15 +253,13 @@ pub fn enum_repr_type(self, opt_hint: Option<&attr::ReprAttr>) -> attr::IntType
     /// if not a structure at all. Corresponds to the only possible unsized
     /// field, and its type can be used to determine unsizing strategy.
     pub fn struct_tail(self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
-        loop {
-            match ty.sty {
-                TyAdt(def, substs) if def.is_struct() => {
-                    match def.struct_variant().fields.last() {
-                        Some(f) => ty = f.ty(self, substs),
-                        None => break
-                    }
-                }
-                _ => break
+        while let TyAdt(def, substs) = ty.sty {
+            if !def.is_struct() {
+                break
+            }
+            match def.struct_variant().fields.last() {
+                Some(f) => ty = f.ty(self, substs),
+                None => break
             }
         }
         ty
@@ -277,17 +275,14 @@ pub fn struct_lockstep_tails(self,
                                  target: Ty<'tcx>)
                                  -> (Ty<'tcx>, Ty<'tcx>) {
         let (mut a, mut b) = (source, target);
-        loop {
-            match (&a.sty, &b.sty) {
-                (&TyAdt(a_def, a_substs), &TyAdt(b_def, b_substs))
-                        if a_def == b_def && a_def.is_struct() => {
-                    match a_def.struct_variant().fields.last() {
-                        Some(f) => {
-                            a = f.ty(self, a_substs);
-                            b = f.ty(self, b_substs);
-                        }
-                        _ => break
-                    }
+        while let (&TyAdt(a_def, a_substs), &TyAdt(b_def, b_substs)) = (&a.sty, &b.sty) {
+            if a_def != b_def || !a_def.is_struct() {
+                break
+            }
+            match a_def.struct_variant().fields.last() {
+                Some(f) => {
+                    a = f.ty(self, a_substs);
+                    b = f.ty(self, b_substs);
                 }
                 _ => break
             }