{"action":"created","comment":{"url":"https://api.github.com/repos/rust-lang/rust/pulls/comments/60692137","id":60692137,"diff_hunk":"@@ -0,0 +1,1336 @@\n+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT\n+// file at the top-level directory of this distribution and at\n+// http://rust-lang.org/COPYRIGHT.\n+//\n+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license\n+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your\n+// option. This file may not be copied, modified, or distributed\n+// except according to those terms.\n+\n+pub use self::Integer::*;\n+pub use self::Layout::*;\n+pub use self::Primitive::*;\n+\n+use infer::{InferCtxt, drain_fulfillment_cx_or_panic};\n+use session::Session;\n+use traits;\n+use ty::{self, Ty, TyCtxt, TypeFoldable};\n+\n+use syntax::ast::{FloatTy, IntTy, UintTy};\n+use syntax::attr;\n+use syntax::codemap::DUMMY_SP;\n+\n+use std::cmp;\n+use std::fmt;\n+use std::i64;\n+\n+/// Parsed [Data layout](http://llvm.org/docs/LangRef.html#data-layout)\n+/// for a target, which contains everything needed to compute layouts.\n+pub struct TargetDataLayout {\n+    pub endian: Endian,\n+    pub i1_align: Align,\n+    pub i8_align: Align,\n+    pub i16_align: Align,\n+    pub i32_align: Align,\n+    pub i64_align: Align,\n+    pub f32_align: Align,\n+    pub f64_align: Align,\n+    pub pointer_size: Size,\n+    pub pointer_align: Align,\n+    pub aggregate_align: Align,\n+\n+    /// Alignments for vector types.\n+    pub vector_align: Vec<(Size, Align)>\n+}\n+\n+impl Default for TargetDataLayout {\n+    fn default() -> TargetDataLayout {\n+        TargetDataLayout {\n+            endian: Endian::Big,\n+            i1_align: Align::from_bits(8, 8).unwrap(),\n+            i8_align: Align::from_bits(8, 8).unwrap(),\n+            i16_align: Align::from_bits(16, 16).unwrap(),\n+            i32_align: Align::from_bits(32, 32).unwrap(),\n+            i64_align: Align::from_bits(32, 64).unwrap(),\n+            f32_align: Align::from_bits(32, 32).unwrap(),\n+            f64_align: Align::from_bits(64, 64).unwrap(),\n+            pointer_size: Size::from_bits(64),\n+            pointer_align: Align::from_bits(64, 64).unwrap(),\n+            aggregate_align: Align::from_bits(0, 64).unwrap(),\n+            vector_align: vec![\n+                (Size::from_bits(64), Align::from_bits(64, 64).unwrap()),\n+                (Size::from_bits(128), Align::from_bits(128, 128).unwrap())\n+            ]\n+        }\n+    }\n+}\n+\n+impl TargetDataLayout {\n+    pub fn parse(sess: &Session) -> TargetDataLayout {\n+        // Parse a bit count from a string.\n+        let parse_bits = |s: &str, kind: &str, cause: &str| {\n+            s.parse::<u64>().unwrap_or_else(|err| {\n+                sess.err(&format!(\"invalid {} `{}` for `{}` in \\\"data-layout\\\": {}\",\n+                                  kind, s, cause, err));\n+                0\n+            })\n+        };\n+\n+        // Parse a size string.\n+        let size = |s: &str, cause: &str| {\n+            Size::from_bits(parse_bits(s, \"size\", cause))\n+        };\n+\n+        // Parse an alignment string.\n+        let align = |s: &[&str], cause: &str| {\n+            if s.is_empty() {\n+                sess.err(&format!(\"missing alignment for `{}` in \\\"data-layout\\\"\", cause));\n+            }\n+            let abi = parse_bits(s[0], \"alignment\", cause);\n+            let pref = s.get(1).map_or(abi, |pref| parse_bits(pref, \"alignment\", cause));\n+            Align::from_bits(abi, pref).unwrap_or_else(|err| {\n+                sess.err(&format!(\"invalid alignment for `{}` in \\\"data-layout\\\": {}\",\n+                                  cause, err));\n+                Align::from_bits(8, 8).unwrap()\n+            })\n+        };\n+\n+        let mut dl = TargetDataLayout::default();\n+        for spec in sess.target.target.data_layout.split(\"-\") {\n+            match &spec.split(\":\").collect::<Vec<_>>()[..] {\n+                [\"e\"] => dl.endian = Endian::Little,\n+                [\"E\"] => dl.endian = Endian::Big,\n+                [\"a\", a..] => dl.aggregate_align = align(a, \"a\"),\n+                [\"f32\", a..] => dl.f32_align = align(a, \"f32\"),\n+                [\"f64\", a..] => dl.f64_align = align(a, \"f64\"),\n+                [p @ \"p\", s, a..] | [p @ \"p0\", s, a..] => {\n+                    dl.pointer_size = size(s, p);\n+                    dl.pointer_align = align(a, p);\n+                }\n+                [s, a..] if s.starts_with(\"i\") => {\n+                    let ty_align = match s[1..].parse::<u64>() {\n+                        Ok(1) => &mut dl.i8_align,\n+                        Ok(8) => &mut dl.i8_align,\n+                        Ok(16) => &mut dl.i16_align,\n+                        Ok(32) => &mut dl.i32_align,\n+                        Ok(64) => &mut dl.i64_align,\n+                        Ok(_) => continue,\n+                        Err(_) => {\n+                            size(&s[1..], \"i\"); // For the user error.\n+                            continue;\n+                        }\n+                    };\n+                    *ty_align = align(a, s);\n+                }\n+                [s, a..] if s.starts_with(\"v\") => {\n+                    let v_size = size(&s[1..], \"v\");\n+                    let a = align(a, s);\n+                    if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) {\n+                        v.1 = a;\n+                        continue;\n+                    }\n+                    // No existing entry, add a new one.\n+                    dl.vector_align.push((v_size, a));\n+                }\n+                _ => {} // Ignore everything else.\n+            }\n+        }\n+\n+        // Perform consistency checks against the Target information.\n+        let endian_str = match dl.endian {\n+            Endian::Little => \"little\",\n+            Endian::Big => \"big\"\n+        };\n+        if endian_str != sess.target.target.target_endian {\n+            sess.err(&format!(\"inconsistent target specification: \\\"data-layout\\\" claims \\\n+                               architecture is {}-endian, while \\\"target-endian\\\" is `{}`\",\n+                              endian_str, sess.target.target.target_endian));\n+        }\n+\n+        if dl.pointer_size.bits().to_string() != sess.target.target.target_pointer_width {\n+            sess.err(&format!(\"inconsistent target specification: \\\"data-layout\\\" claims \\\n+                               pointers are {}-bit, while \\\"target-pointer-width\\\" is `{}`\",\n+                              dl.pointer_size.bits(), sess.target.target.target_pointer_width));\n+        }\n+\n+        dl\n+    }\n+\n+    /// Return exclusive upper bound on object size.\n+    ///\n+    /// The theoretical maximum object size is defined as the maximum positive `isize` value.\n+    /// This ensures that the `offset` semantics remain well-defined by allowing it to correctly\n+    /// index every address within an object along with one byte past the end, along with allowing\n+    /// `isize` to store the difference between any two pointers into an object.\n+    ///\n+    /// The upper bound on 64-bit currently needs to be lower because LLVM uses a 64-bit integer\n+    /// to represent object size in bits. It would need to be 1 << 61 to account for this, but is\n+    /// currently conservatively bounded to 1 << 47 as that is enough to cover the current usable\n+    /// address space on 64-bit ARMv8 and x86_64.\n+    pub fn obj_size_bound(&self) -> u64 {\n+        match self.pointer_size.bits() {\n+            32 => 1 << 31,\n+            64 => 1 << 47,\n+            bits => bug!(\"obj_size_bound: unknown pointer bit size {}\", bits)\n+        }\n+    }\n+\n+    pub fn ptr_sized_integer(&self) -> Integer {\n+        match self.pointer_size.bits() {\n+            32 => I32,\n+            64 => I64,\n+            bits => bug!(\"ptr_sized_integer: unknown pointer bit size {}\", bits)\n+        }\n+    }\n+}\n+\n+/// Endianness of the target, which must match cfg(target-endian).\n+#[derive(Copy, Clone)]\n+pub enum Endian {\n+    Little,\n+    Big\n+}\n+\n+/// Size of a type in bytes.\n+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]\n+pub struct Size {\n+    raw: u64\n+}\n+\n+impl Size {\n+    pub fn from_bits(bits: u64) -> Size {\n+        Size::from_bytes((bits + 7) / 8)\n+    }\n+\n+    pub fn from_bytes(bytes: u64) -> Size {\n+        if bytes >= (1 << 61) {\n+            bug!(\"Size::from_bytes: {} bytes in bits doesn't fit in u64\", bytes)\n+        }\n+        Size {\n+            raw: bytes\n+        }\n+    }\n+\n+    pub fn bytes(self) -> u64 {\n+        self.raw\n+    }\n+\n+    pub fn bits(self) -> u64 {\n+        self.bytes() * 8\n+    }\n+\n+    pub fn abi_align(self, align: Align) -> Size {\n+        let mask = align.abi() - 1;\n+        Size::from_bytes((self.bytes() + mask) & !mask)\n+    }\n+\n+    pub fn checked_add(self, offset: Size, dl: &TargetDataLayout) -> Option<Size> {\n+        // Each Size is less than dl.obj_size_bound(), so the sum is\n+        // also less than 1 << 62 (and therefore can't overflow).\n+        let bytes = self.bytes() + offset.bytes();\n+\n+        if bytes < dl.obj_size_bound() {\n+            Some(Size::from_bytes(bytes))\n+        } else {\n+            None\n+        }\n+    }\n+\n+    pub fn checked_mul(self, count: u64, dl: &TargetDataLayout) -> Option<Size> {\n+        // Each Size is less than dl.obj_size_bound(), so the sum is\n+        // also less than 1 << 62 (and therefore can't overflow).\n+        match self.bytes().checked_mul(count) {\n+            Some(bytes) if bytes < dl.obj_size_bound() => {\n+                Some(Size::from_bytes(bytes))\n+            }\n+            _ => None\n+        }\n+    }\n+}\n+\n+/// Alignment of a type in bytes, both ABI-mandated and preferred.\n+/// Since alignments are always powers of 2, we can pack both in one byte,\n+/// giving each a nibble (4 bits) for a maximum alignment of 2^15 = 32768.\n+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]\n+pub struct Align {\n+    raw: u8\n+}\n+\n+impl Align {\n+    pub fn from_bits(abi: u64, pref: u64) -> Result<Align, String> {\n+        Align::from_bytes((abi + 7) / 8, (pref + 7) / 8)\n+    }\n+\n+    pub fn from_bytes(abi: u64, pref: u64) -> Result<Align, String> {\n+        let pack = |align: u64| {\n+            // Treat an alignment of 0 bytes like 1-byte alignment.\n+            if align == 0 {\n+                return Ok(0);\n+            }\n+\n+            let mut bytes = align;\n+            let mut pow: u8 = 0;\n+            while (bytes & 1) == 0 {\n+                pow += 1;\n+                bytes >>= 1;\n+            }\n+            if bytes != 1 {\n+                Err(format!(\"`{}` is not a power of 2\", align))\n+            } else if pow > 0x0f {\n+                Err(format!(\"`{}` is too large\", align))\n+            } else {\n+                Ok(pow)\n+            }\n+        };\n+\n+        Ok(Align {\n+            raw: pack(abi)? | (pack(pref)? << 4)\n+        })\n+    }\n+\n+    pub fn abi(self) -> u64 {\n+        1 << (self.raw & 0xf)\n+    }\n+\n+    pub fn pref(self) -> u64 {\n+        1 << (self.raw >> 4)\n+    }\n+\n+    pub fn min(self, other: Align) -> Align {\n+        let abi = cmp::min(self.raw & 0x0f, other.raw & 0x0f);\n+        let pref = cmp::min(self.raw & 0xf0, other.raw & 0xf0);\n+        Align {\n+            raw: abi | pref\n+        }\n+    }\n+\n+    pub fn max(self, other: Align) -> Align {\n+        let abi = cmp::max(self.raw & 0x0f, other.raw & 0x0f);\n+        let pref = cmp::max(self.raw & 0xf0, other.raw & 0xf0);\n+        Align {\n+            raw: abi | pref\n+        }\n+    }\n+}\n+\n+/// Integers, also used for enum discriminants.\n+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]\n+pub enum Integer {\n+    I1,\n+    I8,\n+    I16,\n+    I32,\n+    I64\n+}\n+\n+impl Integer {\n+    /// Find the smallest Integer type which can represent the signed value.\n+    pub fn fit_signed(x: i64) -> Integer {\n+        match x {\n+            -0x0000_0001...0x0000_0000 => I1,\n+            -0x0000_0080...0x0000_007f => I8,\n+            -0x0000_8000...0x0000_7fff => I16,\n+            -0x8000_0000...0x7fff_ffff => I32,\n+            _ => I64\n+        }\n+    }\n+\n+    /// Find the smallest Integer type which can represent the unsigned value.\n+    pub fn fit_unsigned(x: u64) -> Integer {\n+        match x {\n+            0...0x0000_0001 => I1,\n+            0...0x0000_00ff => I8,\n+            0...0x0000_ffff => I16,\n+            0...0xffff_ffff => I32,\n+            _ => I64\n+        }\n+    }\n+\n+    /// Get the Integer type from an attr::IntType.\n+    pub fn from_attr(dl: &TargetDataLayout, ity: attr::IntType) -> Integer {\n+        match ity {\n+            attr::SignedInt(IntTy::I8) | attr::UnsignedInt(UintTy::U8) => I8,\n+            attr::SignedInt(IntTy::I16) | attr::UnsignedInt(UintTy::U16) => I16,\n+            attr::SignedInt(IntTy::I32) | attr::UnsignedInt(UintTy::U32) => I32,\n+            attr::SignedInt(IntTy::I64) | attr::UnsignedInt(UintTy::U64) => I64,\n+            attr::SignedInt(IntTy::Is) | attr::UnsignedInt(UintTy::Us) => {\n+                dl.ptr_sized_integer()\n+            }\n+        }\n+    }\n+\n+    /// Find the appropriate Integer type and signedness for the given\n+    /// signed discriminant range and #[repr] attribute.\n+    /// N.B.: u64 values above i64::MAX will be treated as signed, but\n+    /// that shouldn't affect anything, other than maybe debuginfo.\n+    pub fn repr_discr(tcx: &TyCtxt, hint: attr::ReprAttr, min: i64, max: i64)\n+                      -> (Integer, bool) {\n+        // Theoretically, negative values could be larger in unsigned representation\n+        // than the unsigned representation of the signed minimum. However, if there\n+        // are any negative values, the only valid unsigned representation is u64\n+        // which can fit all i64 values, so the result remains unaffected.\n+        let unsigned_fit = Integer::fit_unsigned(cmp::max(min as u64, max as u64));\n+        let signed_fit = cmp::max(Integer::fit_signed(min), Integer::fit_signed(max));\n+\n+        let at_least = match hint {\n+            attr::ReprInt(span, ity) => {\n+                let discr = Integer::from_attr(&tcx.data_layout, ity);\n+                let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };\n+                if discr < fit {\n+                    span_bug!(span, \"representation hint insufficient for discriminant range\")\n+                }\n+                return (discr, ity.is_signed());\n+            }\n+            attr::ReprExtern => {\n+                match &tcx.sess.target.target.arch[..] {\n+                    // WARNING: the ARM EABI has two variants; the one corresponding\n+                    // to `at_least == I32` appears to be used on Linux and NetBSD,\n+                    // but some systems may use the variant corresponding to no\n+                    // lower bound.  However, we don't run on those yet...?\n+                    \"arm\" => I32,\n+                    _ => I32,\n+                }\n+            }\n+            attr::ReprAny => I8,\n+            attr::ReprPacked => {\n+                bug!(\"Integer::repr_discr: found #[repr(packed)] on an enum\");\n+            }\n+            attr::ReprSimd => {\n+                bug!(\"Integer::repr_discr: found #[repr(simd)] on an enum\");\n+            }\n+        };\n+\n+        // If there are no negative values, we can use the unsigned fit.\n+        if min >= 0 {\n+            (cmp::max(unsigned_fit, at_least), false)\n+        } else {\n+            (cmp::max(signed_fit, at_least), true)\n+        }\n+    }\n+}\n+\n+/// Fundamental unit of memory access and layout.\n+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]\n+pub enum Primitive {\n+    Int(Integer),\n+    F32,\n+    F64,\n+    Pointer\n+}\n+\n+impl Primitive {\n+    pub fn size(self, dl: &TargetDataLayout) -> Size {\n+        match self {\n+            Int(I1) | Int(I8) => Size::from_bits(8),\n+            Int(I16) => Size::from_bits(16),\n+            Int(I32) | F32 => Size::from_bits(32),\n+            Int(I64) | F64 => Size::from_bits(64),\n+            Pointer => dl.pointer_size\n+        }\n+    }\n+\n+    pub fn align(self, dl: &TargetDataLayout) -> Align {\n+        match self {\n+            Int(I1) => dl.i1_align,\n+            Int(I8) => dl.i8_align,\n+            Int(I16) => dl.i16_align,\n+            Int(I32) => dl.i32_align,\n+            Int(I64) => dl.i64_align,\n+            F32 => dl.f32_align,\n+            F64 => dl.f64_align,\n+            Pointer => dl.pointer_align\n+        }\n+    }\n+}\n+\n+/// Path through fields of nested structures.\n+// FIXME(eddyb) use small vector optimization for the common case.\n+pub type FieldPath = Vec<u32>;\n+\n+/// A structure, a product type in ADT terms.\n+#[derive(PartialEq, Eq, Hash, Debug)]\n+pub struct Struct {\n+    pub align: Align,\n+\n+    /// If true, no alignment padding is used.\n+    pub packed: bool,\n+\n+    /// If true, the size is exact, otherwise it's only a lower bound.\n+    pub sized: bool,\n+\n+    /// Offsets for the first byte after each field.\n+    /// That is, field_offset(i) = offset_after_field[i - 1] and the\n+    /// whole structure's size is the last offset, excluding padding.\n+    // FIXME(eddyb) use small vector optimization for the common case.\n+    pub offset_after_field: Vec<Size>\n+}\n+\n+impl Struct {\n+    pub fn new(dl: &TargetDataLayout, packed: bool) -> Struct {\n+        Struct {\n+            align: if packed { dl.i8_align } else { dl.aggregate_align },\n+            packed: packed,\n+            sized: true,\n+            offset_after_field: vec![]\n+        }\n+    }\n+\n+    /// Extend the Struct with more fields.\n+    pub fn extend<'a, 'tcx, I>(&mut self, dl: &TargetDataLayout,\n+                               fields: I,\n+                               scapegoat: Ty<'tcx>)\n+                               -> Result<(), LayoutError<'tcx>>\n+    where I: Iterator<Item=Result<&'a Layout, LayoutError<'tcx>>> {\n+        self.offset_after_field.reserve(fields.size_hint().0);\n+\n+        for field in fields {\n+            if !self.sized {\n+                bug!(\"Struct::compute: field #{} of `{}` comes after unsized field\",\n+                     self.offset_after_field.len(), scapegoat);\n+            }\n+\n+            let field = field?;\n+            if field.is_unsized() {\n+                self.sized = false;\n+            }\n+\n+            // Invariant: offset < dl.obj_size_bound() <= 1<<61\n+            let mut offset = if !self.packed {\n+                let align = field.align(dl);\n+                self.align = self.align.max(align);\n+                self.offset_after_field.last_mut().map_or(Size::from_bytes(0), |last| {\n+                    *last = last.abi_align(align);\n+                    *last\n+                })\n+            } else {\n+                self.offset_after_field.last().map_or(Size::from_bytes(0), |&last| last)\n+            };\n+\n+            offset = offset.checked_add(field.size(dl), dl)\n+                           .map_or(Err(LayoutError::SizeOverflow(scapegoat)), Ok)?;\n+\n+            self.offset_after_field.push(offset);\n+        }\n+\n+        Ok(())\n+    }\n+\n+    /// Get the size without trailing alignment padding.\n+    pub fn min_size(&self) -> Size {\n+        self.offset_after_field.last().map_or(Size::from_bytes(0), |&last| last)\n+    }\n+\n+    /// Get the size with trailing aligment padding.\n+    pub fn stride(&self) -> Size {\n+        self.min_size().abi_align(self.align)\n+    }\n+\n+    /// Determine whether a structure would be zero-sized, given its fields.\n+    pub fn would_be_zero_sized<'a, 'tcx, I>(dl: &TargetDataLayout, fields: I)\n+                                            -> Result<bool, LayoutError<'tcx>>\n+    where I: Iterator<Item=Result<&'a Layout, LayoutError<'tcx>>> {\n+        for field in fields {\n+            let field = field?;\n+            if field.is_unsized() || field.size(dl).bytes() > 0 {\n+                return Ok(false);\n+            }\n+        }\n+        Ok(true)\n+    }\n+\n+    /// Find the path leading to a non-zero leaf field, starting from\n+    /// the given type and recursing through aggregates.\n+    // FIXME(eddyb) track value ranges and traverse already optimized enums.\n+    pub fn non_zero_field_in_type<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,\n+                                            ty: Ty<'tcx>)\n+                                            -> Result<Option<FieldPath>, LayoutError<'tcx>> {\n+        let tcx = infcx.tcx;\n+        match (ty.layout(infcx)?, &ty.sty) {\n+            (&Scalar { non_zero: true, .. }, _) => Ok(Some(vec![])),\n+            (&FatPointer { non_zero: true, .. }, _) => {\n+                Ok(Some(vec![FAT_PTR_ADDR as u32]))\n+            }\n+\n+            // Is this the NonZero lang item wrapping a pointer or integer type?\n+            (&Univariant { non_zero: true, .. }, &ty::TyStruct(def, substs)) => {\n+                let fields = &def.struct_variant().fields;\n+                assert_eq!(fields.len(), 1);\n+                let ty = normalize_associated_type(infcx, fields[0].ty(tcx, substs));\n+                match *ty.layout(infcx)? {\n+                    // FIXME(eddyb) also allow floating-point types here.\n+                    Scalar { value: Int(_), non_zero: false } |\n+                    Scalar { value: Pointer, non_zero: false } => {\n+                        Ok(Some(vec![0]))\n+                    }\n+                    FatPointer { non_zero: false, .. } => {\n+                        Ok(Some(vec![FAT_PTR_ADDR as u32, 0]))\n+                    }\n+                    _ => Ok(None)\n+                }\n+            }\n+\n+            // Perhaps one of the fields of this struct is non-zero\n+            // let's recurse and find out\n+            (_, &ty::TyStruct(def, substs)) => {\n+                Struct::non_zero_field_path(infcx, def.struct_variant().fields\n+                                                      .iter().map(|field| {\n+                    normalize_associated_type(infcx, field.ty(tcx, substs))\n+                }))\n+            }\n+\n+            // Perhaps one of the upvars of this closure is non-zero\n+            // Let's recurse and find out!\n+            (_, &ty::TyClosure(_, box ty::ClosureSubsts { upvar_tys: ref tys, .. })) |\n+            // Can we use one of the fields in this tuple?\n+            (_, &ty::TyTuple(ref tys)) => {\n+                Struct::non_zero_field_path(infcx, tys.iter().cloned())\n+            }\n+\n+            // Is this a fixed-size array of something non-zero\n+            // with at least one element?\n+            (_, &ty::TyArray(ety, d)) if d > 0 => {\n+                Struct::non_zero_field_path(infcx, Some(ety).into_iter())\n+            }\n+\n+            // Anything else is not a non-zero type.\n+            _ => Ok(None)\n+        }\n+    }\n+\n+    /// Find the path leading to a non-zero leaf field, starting from\n+    /// the given set of fields and recursing through aggregates.\n+    pub fn non_zero_field_path<'a, 'tcx, I>(infcx: &InferCtxt<'a, 'tcx>,\n+                                            fields: I)\n+                                            -> Result<Option<FieldPath>, LayoutError<'tcx>>\n+    where I: Iterator<Item=Ty<'tcx>> {\n+        for (i, ty) in fields.enumerate() {\n+            if let Some(mut path) = Struct::non_zero_field_in_type(infcx, ty)? {\n+                path.push(i as u32);\n+                return Ok(Some(path));\n+            }\n+        }\n+        Ok(None)\n+    }\n+}\n+\n+/// The first half of a fat pointer.\n+/// - For a trait object, this is the address of the box.\n+/// - For a slice, this is the base address.\n+pub const FAT_PTR_ADDR: usize = 0;\n+\n+/// The second half of a fat pointer.\n+/// - For a trait object, this is the address of the vtable.\n+/// - For a slice, this is the length.\n+pub const FAT_PTR_EXTRA: usize = 1;\n+\n+/// Type layout, from which size and alignment can be cheaply computed.\n+/// For ADTs, it also includes field placement and enum optimizations.\n+/// NOTE: Because Layout is interned, redundant information should be\n+/// kept to a minimum, e.g. it includes no sub-component Ty or Layout.\n+#[derive(Debug, PartialEq, Eq, Hash)]\n+pub enum Layout {\n+    /// TyBool, TyChar, TyInt, TyUint, TyFloat, TyRawPtr, TyRef or TyFnPtr.\n+    Scalar {\n+        value: Primitive,\n+        // If true, the value cannot represent a bit pattern of all zeroes.\n+        non_zero: bool\n+    },\n+\n+    /// SIMD vectors, from TyStruct marked with #[repr(simd)].\n+    Vector {\n+        element: Primitive,\n+        count: u64\n+    },\n+\n+    /// TyArray, TySlice or TyStr.\n+    Array {\n+        /// If true, the size is exact, otherwise it's only a lower bound.\n+        sized: bool,\n+        align: Align,\n+        size: Size\n+    },\n+\n+    /// TyRawPtr or TyRef with a !Sized pointee.\n+    FatPointer {\n+        metadata: Primitive,\n+        // If true, the pointer cannot be null.\n+        non_zero: bool\n+    },\n+\n+    // Remaining variants are all ADTs such as TyStruct, TyEnum or TyTuple.\n+\n+    /// C-like enums; basically an integer.\n+    CEnum {\n+        discr: Integer,\n+        signed: bool,\n+        // Inclusive discriminant range.\n+        // If min > max, it represents min...u64::MAX followed by 0...max.\n+        // FIXME(eddyb) always use the shortest range, e.g. by finding\n+        // the largest space between two consecutive discriminants and\n+        // taking everything else as the (shortest) discriminant range.\n+        min: u64,\n+        max: u64\n+    },\n+\n+    /// Single-case enums, and structs/tuples.\n+    Univariant {\n+        variant: Struct,\n+        // If true, the structure is NonZero.\n+        // FIXME(eddyb) use a newtype Layout kind for this.\n+        non_zero: bool\n+    },\n+\n+    /// General-case enums: for each case there is a struct, and they\n+    /// all start with a field for the discriminant.\n+    General {\n+        discr: Integer,\n+        variants: Vec<Struct>,\n+        size: Size,\n+        align: Align\n+    },\n+\n+    /// Two cases distinguished by a nullable pointer: the case with discriminant\n+    /// `nndiscr` must have single field which is known to be nonnull due to its type.\n+    /// The other case is known to be zero sized. Hence we represent the enum\n+    /// as simply a nullable pointer: if not null it indicates the `nndiscr` variant,\n+    /// otherwise it indicates the other case.\n+    ///\n+    /// For example, `std::option::Option` instantiated at a safe pointer type\n+    /// is represented such that `None` is a null pointer and `Some` is the\n+    /// identity function.\n+    RawNullablePointer {\n+        nndiscr: u64,\n+        value: Primitive\n+    },\n+\n+    /// Two cases distinguished by a nullable pointer: the case with discriminant\n+    /// `nndiscr` is represented by the struct `nonnull`, where the `discrfield`th\n+    /// field is known to be nonnull due to its type; if that field is null, then\n+    /// it represents the other case, which is known to be zero sized.\n+    StructWrappedNullablePointer {\n+        nndiscr: u64,\n+        nonnull: Struct,\n+        // N.B. There is a 0 at the start, for LLVM GEP through a pointer.\n+        discrfield: FieldPath\n+    }\n+}\n+\n+#[derive(Copy, Clone, Debug)]\n+pub enum LayoutError<'tcx> {\n+    Unknown(Ty<'tcx>),\n+    SizeOverflow(Ty<'tcx>)\n+}\n+\n+impl<'tcx> fmt::Display for LayoutError<'tcx> {\n+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n+        match *self {\n+            LayoutError::Unknown(ty) => {\n+                write!(f, \"the type `{:?}` has an unknown layout\", ty)\n+            }\n+            LayoutError::SizeOverflow(ty) => {\n+                write!(f, \"the type `{:?}` is too big for the current architecture\", ty)\n+            }\n+        }\n+    }\n+}\n+\n+/// Helper function for normalizing associated types in an inference context.\n+fn normalize_associated_type<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,","path":"src/librustc/ty/layout.rs","position":739,"original_position":739,"commit_id":"c7d564d8c96bf538cc64a3eeca1fcc3c99569625","original_commit_id":"c7d564d8c96bf538cc64a3eeca1fcc3c99569625","user":{"login":"tsion","id":26806,"avatar_url":"https://avatars.githubusercontent.com/u/26806?v=3","gravatar_id":"","url":"https://api.github.com/users/tsion","html_url":"https://github.com/tsion","followers_url":"https://api.github.com/users/tsion/followers","following_url":"https://api.github.com/users/tsion/following{/other_user}","gists_url":"https://api.github.com/users/tsion/gists{/gist_id}","starred_url":"https://api.github.com/users/tsion/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tsion/subscriptions","organizations_url":"https://api.github.com/users/tsion/orgs","repos_url":"https://api.github.com/users/tsion/repos","events_url":"https://api.github.com/users/tsion/events{/privacy}","received_events_url":"https://api.github.com/users/tsion/received_events","type":"User","site_admin":false},"body":"@eddyb In Miri I use `rustc::infer::normalize_associated_type`. Its source code is slightly different and has a warning about only being callable from trans, but *most* of it is duplicated so it seems a bit ugly. Could they be unified somehow?","created_at":"2016-04-22T05:21:18Z","updated_at":"2016-04-22T05:21:18Z","html_url":"https://github.com/rust-lang/rust/pull/32939#discussion_r60692137","pull_request_url":"https://api.github.com/repos/rust-lang/rust/pulls/32939","_links":{"self":{"href":"https://api.github.com/repos/rust-lang/rust/pulls/comments/60692137"},"html":{"href":"https://github.com/rust-lang/rust/pull/32939#discussion_r60692137"},"pull_request":{"href":"https://api.github.com/repos/rust-lang/rust/pulls/32939"}}},"pull_request":{"url":"https://api.github.com/repos/rust-lang/rust/pulls/32939","id":66354578,"html_url":"https://github.com/rust-lang/rust/pull/32939","diff_url":"https://github.com/rust-lang/rust/pull/32939.diff","patch_url":"https://github.com/rust-lang/rust/pull/32939.patch","issue_url":"https://api.github.com/repos/rust-lang/rust/issues/32939","number":32939,"state":"closed","locked":false,"title":"Compute LLVM-agnostic type layouts in rustc.","user":{"login":"eddyb","id":77424,"avatar_url":"https://avatars.githubusercontent.com/u/77424?v=3","gravatar_id":"","url":"https://api.github.com/users/eddyb","html_url":"https://github.com/eddyb","followers_url":"https://api.github.com/users/eddyb/followers","following_url":"https://api.github.com/users/eddyb/following{/other_user}","gists_url":"https://api.github.com/users/eddyb/gists{/gist_id}","starred_url":"https://api.github.com/users/eddyb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/eddyb/subscriptions","organizations_url":"https://api.github.com/users/eddyb/orgs","repos_url":"https://api.github.com/users/eddyb/repos","events_url":"https://api.github.com/users/eddyb/events{/privacy}","received_events_url":"https://api.github.com/users/eddyb/received_events","type":"User","site_admin":false},"body":"Layout for monomorphic types, and some polymorphic ones (e.g. `&T` where `T: Sized`),\r\ncan now be computed by rustc without involving LLVM in the actual process.\r\n\r\nThis gives rustc the ability to evaluate `size_of` or `align_of`, as well as obtain field offsets.\r\nMIR-based CTFE will eventually make use of these layouts, as will MIR trans, shortly.\r\n\r\nLayout computation also comes with a `[breaking-change]`, or two:\r\n* `\"data-layout\"` is now mandatory in custom target specifications, reverting the decision from #27076.\r\nThis string is needed because it describes endianness, pointer size and alignments for various types.\r\nWe have the first two and we could allow tweaking alignments in target specifications.\r\nOr we could also extract the data layout from LLVM and feed it back into rustc.\r\nHowever, that can vary with the LLVM version, which is fragile and undermines stability.\r\nFor built-in targets, I've added a check that the hardcoded data-layout matches LLVM defaults.\r\n* `transmute` calls are checked in a stricter fashion, which fixes #32377\r\n\r\nTo expand on `transmute`, there are only 2 allowed patterns: between types with statically known sizes and between pointers with the same potentially-unsized \"tail\" (which determines the type of unsized metadata they use, if any).\r\nIf you're affected, my suggestions are:\r\n* try to use casts (and raw pointer deref) instead of transmutes\r\n* *really* try to avoid `transmute` where possible\r\n* if you have a structure, try working on individual fields and unpack/repack the structure instead of transmuting it whole, e.g. `transmute::<RefCell<Box<T>>, RefCell<*mut T>>(x)` doesn't work, but `RefCell::new(Box::into_raw(x.into_inner()))` does (and `Box::into_raw` is just a `transmute`)","created_at":"2016-04-13T16:49:36Z","updated_at":"2016-04-22T05:21:18Z","closed_at":"2016-04-20T16:58:03Z","merged_at":"2016-04-20T16:58:03Z","merge_commit_sha":"c7d564d8c96bf538cc64a3eeca1fcc3c99569625","assignee":{"login":"nikomatsakis","id":155238,"avatar_url":"https://avatars.githubusercontent.com/u/155238?v=3","gravatar_id":"","url":"https://api.github.com/users/nikomatsakis","html_url":"https://github.com/nikomatsakis","followers_url":"https://api.github.com/users/nikomatsakis/followers","following_url":"https://api.github.com/users/nikomatsakis/following{/other_user}","gists_url":"https://api.github.com/users/nikomatsakis/gists{/gist_id}","starred_url":"https://api.github.com/users/nikomatsakis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nikomatsakis/subscriptions","organizations_url":"https://api.github.com/users/nikomatsakis/orgs","repos_url":"https://api.github.com/users/nikomatsakis/repos","events_url":"https://api.github.com/users/nikomatsakis/events{/privacy}","received_events_url":"https://api.github.com/users/nikomatsakis/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/rust-lang/rust/pulls/32939/commits","review_comments_url":"https://api.github.com/repos/rust-lang/rust/pulls/32939/comments","review_comment_url":"https://api.github.com/repos/rust-lang/rust/pulls/comments{/number}","comments_url":"https://api.github.com/repos/rust-lang/rust/issues/32939/comments","statuses_url":"https://api.github.com/repos/rust-lang/rust/statuses/c7d564d8c96bf538cc64a3eeca1fcc3c99569625","head":{"label":"eddyb:layout","ref":"layout","sha":"c7d564d8c96bf538cc64a3eeca1fcc3c99569625","user":{"login":"eddyb","id":77424,"avatar_url":"https://avatars.githubusercontent.com/u/77424?v=3","gravatar_id":"","url":"https://api.github.com/users/eddyb","html_url":"https://github.com/eddyb","followers_url":"https://api.github.com/users/eddyb/followers","following_url":"https://api.github.com/users/eddyb/following{/other_user}","gists_url":"https://api.github.com/users/eddyb/gists{/gist_id}","starred_url":"https://api.github.com/users/eddyb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/eddyb/subscriptions","organizations_url":"https://api.github.com/users/eddyb/orgs","repos_url":"https://api.github.com/users/eddyb/repos","events_url":"https://api.github.com/users/eddyb/events{/privacy}","received_events_url":"https://api.github.com/users/eddyb/received_events","type":"User","site_admin":false},"repo":{"id":13473977,"name":"rust","full_name":"eddyb/rust","owner":{"login":"eddyb","id":77424,"avatar_url":"https://avatars.githubusercontent.com/u/77424?v=3","gravatar_id":"","url":"https://api.github.com/users/eddyb","html_url":"https://github.com/eddyb","followers_url":"https://api.github.com/users/eddyb/followers","following_url":"https://api.github.com/users/eddyb/following{/other_user}","gists_url":"https://api.github.com/users/eddyb/gists{/gist_id}","starred_url":"https://api.github.com/users/eddyb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/eddyb/subscriptions","organizations_url":"https://api.github.com/users/eddyb/orgs","repos_url":"https://api.github.com/users/eddyb/repos","events_url":"https://api.github.com/users/eddyb/events{/privacy}","received_events_url":"https://api.github.com/users/eddyb/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/eddyb/rust","description":"a safe, concurrent, practical language","fork":true,"url":"https://api.github.com/repos/eddyb/rust","forks_url":"https://api.github.com/repos/eddyb/rust/forks","keys_url":"https://api.github.com/repos/eddyb/rust/keys{/key_id}","collaborators_url":"https://api.github.com/repos/eddyb/rust/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/eddyb/rust/teams","hooks_url":"https://api.github.com/repos/eddyb/rust/hooks","issue_events_url":"https://api.github.com/repos/eddyb/rust/issues/events{/number}","events_url":"https://api.github.com/repos/eddyb/rust/events","assignees_url":"https://api.github.com/repos/eddyb/rust/assignees{/user}","branches_url":"https://api.github.com/repos/eddyb/rust/branches{/branch}","tags_url":"https://api.github.com/repos/eddyb/rust/tags","blobs_url":"https://api.github.com/repos/eddyb/rust/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/eddyb/rust/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/eddyb/rust/git/refs{/sha}","trees_url":"https://api.github.com/repos/eddyb/rust/git/trees{/sha}","statuses_url":"https://api.github.com/repos/eddyb/rust/statuses/{sha}","languages_url":"https://api.github.com/repos/eddyb/rust/languages","stargazers_url":"https://api.github.com/repos/eddyb/rust/stargazers","contributors_url":"https://api.github.com/repos/eddyb/rust/contributors","subscribers_url":"https://api.github.com/repos/eddyb/rust/subscribers","subscription_url":"https://api.github.com/repos/eddyb/rust/subscription","commits_url":"https://api.github.com/repos/eddyb/rust/commits{/sha}","git_commits_url":"https://api.github.com/repos/eddyb/rust/git/commits{/sha}","comments_url":"https://api.github.com/repos/eddyb/rust/comments{/number}","issue_comment_url":"https://api.github.com/repos/eddyb/rust/issues/comments{/number}","contents_url":"https://api.github.com/repos/eddyb/rust/contents/{+path}","compare_url":"https://api.github.com/repos/eddyb/rust/compare/{base}...{head}","merges_url":"https://api.github.com/repos/eddyb/rust/merges","archive_url":"https://api.github.com/repos/eddyb/rust/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/eddyb/rust/downloads","issues_url":"https://api.github.com/repos/eddyb/rust/issues{/number}","pulls_url":"https://api.github.com/repos/eddyb/rust/pulls{/number}","milestones_url":"https://api.github.com/repos/eddyb/rust/milestones{/number}","notifications_url":"https://api.github.com/repos/eddyb/rust/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/eddyb/rust/labels{/name}","releases_url":"https://api.github.com/repos/eddyb/rust/releases{/id}","deployments_url":"https://api.github.com/repos/eddyb/rust/deployments","created_at":"2013-10-10T14:40:52Z","updated_at":"2015-06-10T12:47:08Z","pushed_at":"2016-04-21T13:45:15Z","git_url":"git://github.com/eddyb/rust.git","ssh_url":"git@github.com:eddyb/rust.git","clone_url":"https://github.com/eddyb/rust.git","svn_url":"https://github.com/eddyb/rust","homepage":"http://www.rust-lang.org","size":290411,"stargazers_count":1,"watchers_count":1,"language":"Rust","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":1,"default_branch":"master"}},"base":{"label":"rust-lang:master","ref":"master","sha":"478a33dabc4e6f2f501f476c79b56178d9df4f37","user":{"login":"rust-lang","id":5430905,"avatar_url":"https://avatars.githubusercontent.com/u/5430905?v=3","gravatar_id":"","url":"https://api.github.com/users/rust-lang","html_url":"https://github.com/rust-lang","followers_url":"https://api.github.com/users/rust-lang/followers","following_url":"https://api.github.com/users/rust-lang/following{/other_user}","gists_url":"https://api.github.com/users/rust-lang/gists{/gist_id}","starred_url":"https://api.github.com/users/rust-lang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rust-lang/subscriptions","organizations_url":"https://api.github.com/users/rust-lang/orgs","repos_url":"https://api.github.com/users/rust-lang/repos","events_url":"https://api.github.com/users/rust-lang/events{/privacy}","received_events_url":"https://api.github.com/users/rust-lang/received_events","type":"Organization","site_admin":false},"repo":{"id":724712,"name":"rust","full_name":"rust-lang/rust","owner":{"login":"rust-lang","id":5430905,"avatar_url":"https://avatars.githubusercontent.com/u/5430905?v=3","gravatar_id":"","url":"https://api.github.com/users/rust-lang","html_url":"https://github.com/rust-lang","followers_url":"https://api.github.com/users/rust-lang/followers","following_url":"https://api.github.com/users/rust-lang/following{/other_user}","gists_url":"https://api.github.com/users/rust-lang/gists{/gist_id}","starred_url":"https://api.github.com/users/rust-lang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rust-lang/subscriptions","organizations_url":"https://api.github.com/users/rust-lang/orgs","repos_url":"https://api.github.com/users/rust-lang/repos","events_url":"https://api.github.com/users/rust-lang/events{/privacy}","received_events_url":"https://api.github.com/users/rust-lang/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/rust-lang/rust","description":"A safe, concurrent, practical language.","fork":false,"url":"https://api.github.com/repos/rust-lang/rust","forks_url":"https://api.github.com/repos/rust-lang/rust/forks","keys_url":"https://api.github.com/repos/rust-lang/rust/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rust-lang/rust/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rust-lang/rust/teams","hooks_url":"https://api.github.com/repos/rust-lang/rust/hooks","issue_events_url":"https://api.github.com/repos/rust-lang/rust/issues/events{/number}","events_url":"https://api.github.com/repos/rust-lang/rust/events","assignees_url":"https://api.github.com/repos/rust-lang/rust/assignees{/user}","branches_url":"https://api.github.com/repos/rust-lang/rust/branches{/branch}","tags_url":"https://api.github.com/repos/rust-lang/rust/tags","blobs_url":"https://api.github.com/repos/rust-lang/rust/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rust-lang/rust/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rust-lang/rust/git/refs{/sha}","trees_url":"https://api.github.com/repos/rust-lang/rust/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rust-lang/rust/statuses/{sha}","languages_url":"https://api.github.com/repos/rust-lang/rust/languages","stargazers_url":"https://api.github.com/repos/rust-lang/rust/stargazers","contributors_url":"https://api.github.com/repos/rust-lang/rust/contributors","subscribers_url":"https://api.github.com/repos/rust-lang/rust/subscribers","subscription_url":"https://api.github.com/repos/rust-lang/rust/subscription","commits_url":"https://api.github.com/repos/rust-lang/rust/commits{/sha}","git_commits_url":"https://api.github.com/repos/rust-lang/rust/git/commits{/sha}","comments_url":"https://api.github.com/repos/rust-lang/rust/comments{/number}","issue_comment_url":"https://api.github.com/repos/rust-lang/rust/issues/comments{/number}","contents_url":"https://api.github.com/repos/rust-lang/rust/contents/{+path}","compare_url":"https://api.github.com/repos/rust-lang/rust/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rust-lang/rust/merges","archive_url":"https://api.github.com/repos/rust-lang/rust/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rust-lang/rust/downloads","issues_url":"https://api.github.com/repos/rust-lang/rust/issues{/number}","pulls_url":"https://api.github.com/repos/rust-lang/rust/pulls{/number}","milestones_url":"https://api.github.com/repos/rust-lang/rust/milestones{/number}","notifications_url":"https://api.github.com/repos/rust-lang/rust/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rust-lang/rust/labels{/name}","releases_url":"https://api.github.com/repos/rust-lang/rust/releases{/id}","deployments_url":"https://api.github.com/repos/rust-lang/rust/deployments","created_at":"2010-06-16T20:39:03Z","updated_at":"2016-04-22T04:49:44Z","pushed_at":"2016-04-22T05:20:36Z","git_url":"git://github.com/rust-lang/rust.git","ssh_url":"git@github.com:rust-lang/rust.git","clone_url":"https://github.com/rust-lang/rust.git","svn_url":"https://github.com/rust-lang/rust","homepage":"http://www.rust-lang.org","size":487317,"stargazers_count":16339,"watchers_count":16339,"language":"Rust","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":3118,"mirror_url":null,"open_issues_count":2467,"forks":3118,"open_issues":2467,"watchers":16339,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/rust-lang/rust/pulls/32939"},"html":{"href":"https://github.com/rust-lang/rust/pull/32939"},"issue":{"href":"https://api.github.com/repos/rust-lang/rust/issues/32939"},"comments":{"href":"https://api.github.com/repos/rust-lang/rust/issues/32939/comments"},"review_comments":{"href":"https://api.github.com/repos/rust-lang/rust/pulls/32939/comments"},"review_comment":{"href":"https://api.github.com/repos/rust-lang/rust/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/rust-lang/rust/pulls/32939/commits"},"statuses":{"href":"https://api.github.com/repos/rust-lang/rust/statuses/c7d564d8c96bf538cc64a3eeca1fcc3c99569625"}}}}