about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-02-09 14:25:04 +0000
committerbors <bors@rust-lang.org>2017-02-09 14:25:04 +0000
commite7fc53b8f0595d9b5be6a3b64d29d3cfed7c7199 (patch)
tree1b65f5fd9621cfea56eafd05603c31eaf4cc2ae8
parent1129ce51a6cc83ea7d7283fce194948feef4e319 (diff)
parent116bdacf6bedaba3d9ec83d202e2ca6fa54d8395 (diff)
downloadrust-e7fc53b8f0595d9b5be6a3b64d29d3cfed7c7199.tar.gz
rust-e7fc53b8f0595d9b5be6a3b64d29d3cfed7c7199.zip
Auto merge of #39686 - frewsxcv:rollup, r=frewsxcv
Rollup of 5 pull requests

- Successful merges: #39595, #39601, #39602, #39615, #39647
- Failed merges:
-rw-r--r--src/ci/docker/cross/Dockerfile6
-rw-r--r--src/libcore/fmt/float.rs94
-rw-r--r--src/libcore/fmt/mod.rs87
-rw-r--r--src/libcoretest/fmt/float.rs32
m---------src/liblibc0
-rw-r--r--src/librustc/middle/mem_categorization.rs4
-rw-r--r--src/librustc/ty/context.rs6
-rw-r--r--src/librustc/ty/layout.rs102
-rw-r--r--src/librustc/ty/mod.rs33
-rw-r--r--src/librustc_metadata/decoder.rs28
-rw-r--r--src/librustc_metadata/encoder.rs24
-rw-r--r--src/librustc_metadata/schema.rs8
-rw-r--r--src/librustc_typeck/collect.rs9
-rw-r--r--src/test/ui/did_you_mean/issue-39544.rs22
-rw-r--r--src/test/ui/did_you_mean/issue-39544.stderr8
-rw-r--r--src/tools/build-manifest/src/main.rs1
16 files changed, 278 insertions, 186 deletions
diff --git a/src/ci/docker/cross/Dockerfile b/src/ci/docker/cross/Dockerfile
index 8f947caf2cb..29a5e7bcafb 100644
--- a/src/ci/docker/cross/Dockerfile
+++ b/src/ci/docker/cross/Dockerfile
@@ -14,6 +14,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   zlib1g-dev \
   g++-arm-linux-gnueabi \
   g++-arm-linux-gnueabihf \
+  gcc-sparc64-linux-gnu \
+  libc6-dev-sparc64-cross \
   bzip2 \
   patch
 
@@ -60,9 +62,11 @@ ENV TARGETS=$TARGETS,mipsel-unknown-linux-musl
 ENV TARGETS=$TARGETS,arm-unknown-linux-musleabi
 ENV TARGETS=$TARGETS,arm-unknown-linux-musleabihf
 ENV TARGETS=$TARGETS,armv7-unknown-linux-musleabihf
+ENV TARGETS=$TARGETS,sparc64-unknown-linux-gnu
 
 ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \
-    CC_mips_unknown_linux_musl=mips-openwrt-linux-gcc
+    CC_mips_unknown_linux_musl=mips-openwrt-linux-gcc \
+    CC_sparc64_unknown_linux_gnu=sparc64-linux-gnu-gcc
 
 # Suppress some warnings in the openwrt toolchains we downloaded
 ENV STAGING_DIR=/tmp
diff --git a/src/libcore/fmt/float.rs b/src/libcore/fmt/float.rs
new file mode 100644
index 00000000000..50248fabfcd
--- /dev/null
+++ b/src/libcore/fmt/float.rs
@@ -0,0 +1,94 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use fmt::{Formatter, Result, LowerExp, UpperExp, Display, Debug};
+use num::flt2dec;
+
+// Common code of floating point Debug and Display.
+fn float_to_decimal_common<T>(fmt: &mut Formatter, num: &T, negative_zero: bool) -> Result
+    where T: flt2dec::DecodableFloat
+{
+    let force_sign = fmt.sign_plus();
+    let sign = match (force_sign, negative_zero) {
+        (false, false) => flt2dec::Sign::Minus,
+        (false, true)  => flt2dec::Sign::MinusRaw,
+        (true,  false) => flt2dec::Sign::MinusPlus,
+        (true,  true)  => flt2dec::Sign::MinusPlusRaw,
+    };
+
+    let mut buf = [0; 1024]; // enough for f32 and f64
+    let mut parts = [flt2dec::Part::Zero(0); 16];
+    let formatted = if let Some(precision) = fmt.precision {
+        flt2dec::to_exact_fixed_str(flt2dec::strategy::grisu::format_exact, *num, sign,
+                                    precision, false, &mut buf, &mut parts)
+    } else {
+        flt2dec::to_shortest_str(flt2dec::strategy::grisu::format_shortest, *num, sign,
+                                 0, false, &mut buf, &mut parts)
+    };
+    fmt.pad_formatted_parts(&formatted)
+}
+
+// Common code of floating point LowerExp and UpperExp.
+fn float_to_exponential_common<T>(fmt: &mut Formatter, num: &T, upper: bool) -> Result
+    where T: flt2dec::DecodableFloat
+{
+    let force_sign = fmt.sign_plus();
+    let sign = match force_sign {
+        false => flt2dec::Sign::Minus,
+        true  => flt2dec::Sign::MinusPlus,
+    };
+
+    let mut buf = [0; 1024]; // enough for f32 and f64
+    let mut parts = [flt2dec::Part::Zero(0); 16];
+    let formatted = if let Some(precision) = fmt.precision {
+        // 1 integral digit + `precision` fractional digits = `precision + 1` total digits
+        flt2dec::to_exact_exp_str(flt2dec::strategy::grisu::format_exact, *num, sign,
+                                  precision + 1, upper, &mut buf, &mut parts)
+    } else {
+        flt2dec::to_shortest_exp_str(flt2dec::strategy::grisu::format_shortest, *num, sign,
+                                     (0, 0), upper, &mut buf, &mut parts)
+    };
+    fmt.pad_formatted_parts(&formatted)
+}
+
+macro_rules! floating {
+    ($ty:ident) => (
+        #[stable(feature = "rust1", since = "1.0.0")]
+        impl Debug for $ty {
+            fn fmt(&self, fmt: &mut Formatter) -> Result {
+                float_to_decimal_common(fmt, self, true)
+            }
+        }
+
+        #[stable(feature = "rust1", since = "1.0.0")]
+        impl Display for $ty {
+            fn fmt(&self, fmt: &mut Formatter) -> Result {
+                float_to_decimal_common(fmt, self, false)
+            }
+        }
+
+        #[stable(feature = "rust1", since = "1.0.0")]
+        impl LowerExp for $ty {
+            fn fmt(&self, fmt: &mut Formatter) -> Result {
+                float_to_exponential_common(fmt, self, false)
+            }
+        }
+
+        #[stable(feature = "rust1", since = "1.0.0")]
+        impl UpperExp for $ty {
+            fn fmt(&self, fmt: &mut Formatter) -> Result {
+                float_to_exponential_common(fmt, self, true)
+            }
+        }
+    )
+}
+
+floating! { f32 }
+floating! { f64 }
diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs
index a989f914db6..eb086c20181 100644
--- a/src/libcore/fmt/mod.rs
+++ b/src/libcore/fmt/mod.rs
@@ -21,6 +21,10 @@ use result;
 use slice;
 use str;
 
+mod float;
+mod num;
+mod builders;
+
 #[unstable(feature = "fmt_flags_align", issue = "27726")]
 /// Possible alignments returned by `Formatter::align`
 #[derive(Debug)]
@@ -38,9 +42,6 @@ pub enum Alignment {
 #[stable(feature = "debug_builders", since = "1.2.0")]
 pub use self::builders::{DebugStruct, DebugTuple, DebugSet, DebugList, DebugMap};
 
-mod num;
-mod builders;
-
 #[unstable(feature = "fmt_internals", reason = "internal to format_args!",
            issue = "0")]
 #[doc(hidden)]
@@ -1511,86 +1512,6 @@ impl<'a, T: ?Sized> Pointer for &'a mut T {
     }
 }
 
-// Common code of floating point Debug and Display.
-fn float_to_decimal_common<T>(fmt: &mut Formatter, num: &T, negative_zero: bool) -> Result
-    where T: flt2dec::DecodableFloat
-{
-    let force_sign = fmt.sign_plus();
-    let sign = match (force_sign, negative_zero) {
-        (false, false) => flt2dec::Sign::Minus,
-        (false, true)  => flt2dec::Sign::MinusRaw,
-        (true,  false) => flt2dec::Sign::MinusPlus,
-        (true,  true)  => flt2dec::Sign::MinusPlusRaw,
-    };
-
-    let mut buf = [0; 1024]; // enough for f32 and f64
-    let mut parts = [flt2dec::Part::Zero(0); 16];
-    let formatted = if let Some(precision) = fmt.precision {
-        flt2dec::to_exact_fixed_str(flt2dec::strategy::grisu::format_exact, *num, sign,
-                                    precision, false, &mut buf, &mut parts)
-    } else {
-        flt2dec::to_shortest_str(flt2dec::strategy::grisu::format_shortest, *num, sign,
-                                 0, false, &mut buf, &mut parts)
-    };
-    fmt.pad_formatted_parts(&formatted)
-}
-
-// Common code of floating point LowerExp and UpperExp.
-fn float_to_exponential_common<T>(fmt: &mut Formatter, num: &T, upper: bool) -> Result
-    where T: flt2dec::DecodableFloat
-{
-    let force_sign = fmt.sign_plus();
-    let sign = match force_sign {
-        false => flt2dec::Sign::Minus,
-        true  => flt2dec::Sign::MinusPlus,
-    };
-
-    let mut buf = [0; 1024]; // enough for f32 and f64
-    let mut parts = [flt2dec::Part::Zero(0); 16];
-    let formatted = if let Some(precision) = fmt.precision {
-        // 1 integral digit + `precision` fractional digits = `precision + 1` total digits
-        flt2dec::to_exact_exp_str(flt2dec::strategy::grisu::format_exact, *num, sign,
-                                  precision + 1, upper, &mut buf, &mut parts)
-    } else {
-        flt2dec::to_shortest_exp_str(flt2dec::strategy::grisu::format_shortest, *num, sign,
-                                     (0, 0), upper, &mut buf, &mut parts)
-    };
-    fmt.pad_formatted_parts(&formatted)
-}
-
-macro_rules! floating { ($ty:ident) => {
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl Debug for $ty {
-        fn fmt(&self, fmt: &mut Formatter) -> Result {
-            float_to_decimal_common(fmt, self, true)
-        }
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl Display for $ty {
-        fn fmt(&self, fmt: &mut Formatter) -> Result {
-            float_to_decimal_common(fmt, self, false)
-        }
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl LowerExp for $ty {
-        fn fmt(&self, fmt: &mut Formatter) -> Result {
-            float_to_exponential_common(fmt, self, false)
-        }
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl UpperExp for $ty {
-        fn fmt(&self, fmt: &mut Formatter) -> Result {
-            float_to_exponential_common(fmt, self, true)
-        }
-    }
-} }
-floating! { f32 }
-floating! { f64 }
-
 // Implementation of Display/Debug for various core types
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libcoretest/fmt/float.rs b/src/libcoretest/fmt/float.rs
index 16cd2feddc0..695001312e4 100644
--- a/src/libcoretest/fmt/float.rs
+++ b/src/libcoretest/fmt/float.rs
@@ -9,11 +9,29 @@
 // except according to those terms.
 
 #[test]
-fn test_format_float() {
-    assert!("1" == format!("{:.0}", 1.0f64));
-    assert!("9" == format!("{:.0}", 9.4f64));
-    assert!("10" == format!("{:.0}", 9.9f64));
-    assert!("9.8" == format!("{:.1}", 9.849f64));
-    assert!("9.9" == format!("{:.1}", 9.851f64));
-    assert!("1" == format!("{:.0}", 0.5f64));
+fn test_format_f64() {
+    assert_eq!("1", format!("{:.0}", 1.0f64));
+    assert_eq!("9", format!("{:.0}", 9.4f64));
+    assert_eq!("10", format!("{:.0}", 9.9f64));
+    assert_eq!("9.8", format!("{:.1}", 9.849f64));
+    assert_eq!("9.9", format!("{:.1}", 9.851f64));
+    assert_eq!("1", format!("{:.0}", 0.5f64));
+    assert_eq!("1.23456789e6", format!("{:e}", 1234567.89f64));
+    assert_eq!("1.23456789e3", format!("{:e}", 1234.56789f64));
+    assert_eq!("1.23456789E6", format!("{:E}", 1234567.89f64));
+    assert_eq!("1.23456789E3", format!("{:E}", 1234.56789f64));
+}
+
+#[test]
+fn test_format_f32() {
+    assert_eq!("1", format!("{:.0}", 1.0f32));
+    assert_eq!("9", format!("{:.0}", 9.4f32));
+    assert_eq!("10", format!("{:.0}", 9.9f32));
+    assert_eq!("9.8", format!("{:.1}", 9.849f32));
+    assert_eq!("9.9", format!("{:.1}", 9.851f32));
+    assert_eq!("1", format!("{:.0}", 0.5f32));
+    assert_eq!("1.2345679e6", format!("{:e}", 1234567.89f32));
+    assert_eq!("1.2345679e3", format!("{:e}", 1234.56789f32));
+    assert_eq!("1.2345679E6", format!("{:E}", 1234567.89f32));
+    assert_eq!("1.2345679E3", format!("{:E}", 1234.56789f32));
 }
diff --git a/src/liblibc b/src/liblibc
-Subproject cb7f66732175e6171587ed69656b7aae7dd2e6e
+Subproject 8d8264b967a31a1a8cebe2a05110564106b6e90
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 9d1bcb8164a..627753039ba 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -202,7 +202,9 @@ impl<'tcx> cmt_<'tcx> {
             Categorization::Downcast(ref cmt, _) => {
                 if let Categorization::Local(_) = cmt.cat {
                     if let ty::TyAdt(def, _) = self.ty.sty {
-                        return def.struct_variant().find_field_named(name).map(|x| x.did);
+                        if def.is_struct() {
+                            return def.struct_variant().find_field_named(name).map(|x| x.did);
+                        }
                     }
                     None
                 } else {
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index a0eae33c440..6203679a510 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -26,6 +26,7 @@ use middle::resolve_lifetime;
 use middle::stability;
 use mir::Mir;
 use ty::subst::{Kind, Substs};
+use ty::ReprOptions;
 use traits;
 use ty::{self, TraitRef, Ty, TypeAndMut};
 use ty::{TyS, TypeVariants, Slice};
@@ -672,9 +673,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn alloc_adt_def(self,
                          did: DefId,
                          kind: AdtKind,
-                         variants: Vec<ty::VariantDef>)
+                         variants: Vec<ty::VariantDef>,
+                         repr: ReprOptions)
                          -> &'gcx ty::AdtDef {
-        let def = ty::AdtDef::new(self, did, kind, variants);
+        let def = ty::AdtDef::new(self, did, kind, variants, repr);
         self.global_arenas.adt_def.alloc(def)
     }
 
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index ff3ac3586a7..3a463e981a6 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -15,7 +15,7 @@ pub use self::Primitive::*;
 use infer::InferCtxt;
 use session::Session;
 use traits;
-use ty::{self, Ty, TyCtxt, TypeFoldable};
+use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions};
 
 use syntax::ast::{FloatTy, IntTy, UintTy};
 use syntax::attr;
@@ -437,7 +437,7 @@ impl Integer {
     /// signed discriminant range and #[repr] attribute.
     /// N.B.: u64 values above i64::MAX will be treated as signed, but
     /// that shouldn't affect anything, other than maybe debuginfo.
-    fn repr_discr(tcx: TyCtxt, ty: Ty, hints: &[attr::ReprAttr], min: i64, max: i64)
+    fn repr_discr(tcx: TyCtxt, ty: Ty, repr: &ReprOptions, min: i64, max: i64)
                       -> (Integer, bool) {
         // Theoretically, negative values could be larger in unsigned representation
         // than the unsigned representation of the signed minimum. However, if there
@@ -449,34 +449,24 @@ impl Integer {
         let mut min_from_extern = None;
         let min_default = I8;
 
-        for &r in hints.iter() {
-            match r {
-                attr::ReprInt(ity) => {
-                    let discr = Integer::from_attr(&tcx.data_layout, ity);
-                    let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
-                    if discr < fit {
-                        bug!("Integer::repr_discr: `#[repr]` hint too small for \
-                              discriminant range of enum `{}", ty)
-                    }
-                    return (discr, ity.is_signed());
-                }
-                attr::ReprExtern => {
-                    match &tcx.sess.target.target.arch[..] {
-                        // WARNING: the ARM EABI has two variants; the one corresponding
-                        // to `at_least == I32` appears to be used on Linux and NetBSD,
-                        // but some systems may use the variant corresponding to no
-                        // lower bound.  However, we don't run on those yet...?
-                        "arm" => min_from_extern = Some(I32),
-                        _ => min_from_extern = Some(I32),
-                    }
-                }
-                attr::ReprAny => {},
-                attr::ReprPacked => {
-                    bug!("Integer::repr_discr: found #[repr(packed)] on enum `{}", ty);
-                }
-                attr::ReprSimd => {
-                    bug!("Integer::repr_discr: found #[repr(simd)] on enum `{}", ty);
-                }
+        if let Some(ity) = repr.int {
+            let discr = Integer::from_attr(&tcx.data_layout, ity);
+            let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
+            if discr < fit {
+                bug!("Integer::repr_discr: `#[repr]` hint too small for \
+                  discriminant range of enum `{}", ty)
+            }
+            return (discr, ity.is_signed());
+        }
+
+        if repr.c {
+            match &tcx.sess.target.target.arch[..] {
+                // WARNING: the ARM EABI has two variants; the one corresponding
+                // to `at_least == I32` appears to be used on Linux and NetBSD,
+                // but some systems may use the variant corresponding to no
+                // lower bound.  However, we don't run on those yet...?
+                "arm" => min_from_extern = Some(I32),
+                _ => min_from_extern = Some(I32),
             }
         }
 
@@ -568,9 +558,9 @@ enum StructKind {
 impl<'a, 'gcx, 'tcx> Struct {
     // FIXME(camlorn): reprs need a better representation to deal with multiple reprs on one type.
     fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>,
-                  reprs: &[attr::ReprAttr], kind: StructKind,
+                  repr: &ReprOptions, kind: StructKind,
                   scapegoat: Ty<'gcx>) -> Result<Struct, LayoutError<'gcx>> {
-        let packed = reprs.contains(&attr::ReprPacked);
+        let packed = repr.packed;
         let mut ret = Struct {
             align: if packed { dl.i8_align } else { dl.aggregate_align },
             packed: packed,
@@ -580,27 +570,16 @@ impl<'a, 'gcx, 'tcx> Struct {
             min_size: Size::from_bytes(0),
         };
 
-        // Anything with ReprExtern or ReprPacked doesn't optimize.
+        // Anything with repr(C) or repr(packed) doesn't optimize.
         // Neither do  1-member and 2-member structs.
         // In addition, code in trans assume that 2-element structs can become pairs.
         // It's easier to just short-circuit here.
-        let mut can_optimize = fields.len() > 2 || StructKind::EnumVariant == kind;
-        if can_optimize {
-            // This exhaustive match makes new reprs force the adder to modify this function.
-            // Otherwise, things can silently break.
-            // Note the inversion, return true to stop optimizing.
-            can_optimize = !reprs.iter().any(|r| {
-                match *r {
-                    attr::ReprAny | attr::ReprInt(_) => false,
-                    attr::ReprExtern | attr::ReprPacked => true,
-                    attr::ReprSimd => bug!("Simd  vectors should be represented as layout::Vector")
-                }
-            });
-        }
+        let mut can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind)
+            && ! (repr.c || repr.packed);
 
         // Disable field reordering until we can decide what to do.
         // The odd pattern here avoids a warning about the value never being read.
-        if can_optimize { can_optimize = false }
+        if can_optimize { can_optimize = false; }
 
         let (optimize, sort_ascending) = match kind {
             StructKind::AlwaysSizedUnivariant => (can_optimize, false),
@@ -1092,7 +1071,7 @@ impl<'a, 'gcx, 'tcx> Layout {
 
             // The never type.
             ty::TyNever => Univariant {
-                variant: Struct::new(dl, &vec![], &[],
+                variant: Struct::new(dl, &vec![], &ReprOptions::default(),
                   StructKind::AlwaysSizedUnivariant, ty)?,
                 non_zero: false
             },
@@ -1135,12 +1114,12 @@ impl<'a, 'gcx, 'tcx> Layout {
             ty::TyFnDef(..) => {
                 Univariant {
                     variant: Struct::new(dl, &vec![],
-                      &[], StructKind::AlwaysSizedUnivariant, ty)?,
+                      &ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?,
                     non_zero: false
                 }
             }
             ty::TyDynamic(..) => {
-                let mut unit = Struct::new(dl, &vec![], &[],
+                let mut unit = Struct::new(dl, &vec![], &ReprOptions::default(),
                   StructKind::AlwaysSizedUnivariant, ty)?;
                 unit.sized = false;
                 Univariant { variant: unit, non_zero: false }
@@ -1152,7 +1131,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                 let st = Struct::new(dl,
                     &tys.map(|ty| ty.layout(infcx))
                       .collect::<Result<Vec<_>, _>>()?,
-                    &[],
+                    &ReprOptions::default(),
                     StructKind::AlwaysSizedUnivariant, ty)?;
                 Univariant { variant: st, non_zero: false }
             }
@@ -1163,7 +1142,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                 let st = Struct::new(dl,
                     &tys.iter().map(|ty| ty.layout(infcx))
                       .collect::<Result<Vec<_>, _>>()?,
-                    &[], StructKind::AlwaysSizedUnivariant, ty)?;
+                    &ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?;
                 Univariant { variant: st, non_zero: false }
             }
 
@@ -1187,16 +1166,13 @@ impl<'a, 'gcx, 'tcx> Layout {
 
             // ADTs.
             ty::TyAdt(def, substs) => {
-                let hints = &tcx.lookup_repr_hints(def.did)[..];
-
                 if def.variants.is_empty() {
                     // Uninhabitable; represent as unit
                     // (Typechecking will reject discriminant-sizing attrs.)
-                    assert_eq!(hints.len(), 0);
 
                     return success(Univariant {
                         variant: Struct::new(dl, &vec![],
-                          &hints[..], StructKind::AlwaysSizedUnivariant, ty)?,
+                          &def.repr, StructKind::AlwaysSizedUnivariant, ty)?,
                         non_zero: false
                     });
                 }
@@ -1219,7 +1195,7 @@ impl<'a, 'gcx, 'tcx> Layout {
 
                     // FIXME: should handle i128? signed-value based impl is weird and hard to
                     // grok.
-                    let (discr, signed) = Integer::repr_discr(tcx, ty, &hints[..],
+                    let (discr, signed) = Integer::repr_discr(tcx, ty, &def.repr,
                                                               min,
                                                               max);
                     return success(CEnum {
@@ -1232,7 +1208,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                     });
                 }
 
-                if !def.is_enum() || def.variants.len() == 1 && hints.is_empty() {
+                if !def.is_enum() || def.variants.len() == 1 {
                     // Struct, or union, or univariant enum equivalent to a struct.
                     // (Typechecking will reject discriminant-sizing attrs.)
 
@@ -1259,7 +1235,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                         un.extend(dl, fields.iter().map(|&f| Ok(f)), ty)?;
                         UntaggedUnion { variants: un }
                     } else {
-                        let st = Struct::new(dl, &fields, &hints[..],
+                        let st = Struct::new(dl, &fields, &def.repr,
                           kind, ty)?;
                         let non_zero = Some(def.did) == tcx.lang_items.non_zero();
                         Univariant { variant: st, non_zero: non_zero }
@@ -1282,7 +1258,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                     v.fields.iter().map(|field| field.ty(tcx, substs)).collect::<Vec<_>>()
                 }).collect::<Vec<_>>();
 
-                if variants.len() == 2 && hints.is_empty() {
+                if variants.len() == 2 && !def.repr.c {
                     // Nullable pointer optimization
                     for discr in 0..2 {
                         let other_fields = variants[1 - discr].iter().map(|ty| {
@@ -1315,7 +1291,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                         let st = Struct::new(dl,
                             &variants[discr].iter().map(|ty| ty.layout(infcx))
                               .collect::<Result<Vec<_>, _>>()?,
-                            &hints[..], StructKind::AlwaysSizedUnivariant, ty)?;
+                            &def.repr, StructKind::AlwaysSizedUnivariant, ty)?;
 
                         // We have to fix the last element of path here.
                         let mut i = *path.last().unwrap();
@@ -1338,7 +1314,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                 // The general case.
                 let discr_max = (variants.len() - 1) as i64;
                 assert!(discr_max >= 0);
-                let (min_ity, _) = Integer::repr_discr(tcx, ty, &hints[..], 0, discr_max);
+                let (min_ity, _) = Integer::repr_discr(tcx, ty, &def.repr, 0, discr_max);
 
                 let mut align = dl.aggregate_align;
                 let mut size = Size::from_bytes(0);
@@ -1356,7 +1332,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                     fields.insert(0, &discr);
                     let st = Struct::new(dl,
                         &fields,
-                        &hints[..], StructKind::EnumVariant, ty)?;
+                        &def.repr, StructKind::EnumVariant, ty)?;
                     // Find the first field we can't move later
                     // to make room for a larger discriminant.
                     // It is important to skip the first field.
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 4d9514b1473..beb286108a0 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1327,7 +1327,8 @@ pub struct AdtDef {
     pub did: DefId,
     pub variants: Vec<VariantDef>,
     destructor: Cell<Option<DefId>>,
-    flags: Cell<AdtFlags>
+    flags: Cell<AdtFlags>,
+    pub repr: ReprOptions,
 }
 
 impl PartialEq for AdtDef {
@@ -1356,11 +1357,38 @@ impl<'tcx> serialize::UseSpecializedDecodable for &'tcx AdtDef {}
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub enum AdtKind { Struct, Union, Enum }
 
+/// Represents the repr options provided by the user,
+#[derive(Copy, Clone, Eq, PartialEq, RustcEncodable, RustcDecodable, Default)]
+pub struct ReprOptions {
+    pub c: bool,
+    pub packed: bool,
+    pub simd: bool,
+    pub int: Option<attr::IntType>,
+}
+
+impl ReprOptions {
+    pub fn new<'a, 'gcx, 'tcx>(tcx: &TyCtxt<'a, 'gcx, 'tcx>, did: DefId) -> ReprOptions {
+        let mut ret = ReprOptions::default();
+        let attrs = tcx.lookup_repr_hints(did);
+        for r in attrs.iter() {
+            match *r {
+                attr::ReprExtern => ret.c = true,
+                attr::ReprPacked => ret.packed = true,
+                attr::ReprSimd => ret.simd = true,
+                attr::ReprInt(i) => ret.int = Some(i),
+                attr::ReprAny => (),
+            }
+        }
+        ret
+    }
+}
+
 impl<'a, 'gcx, 'tcx> AdtDef {
     fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
            did: DefId,
            kind: AdtKind,
-           variants: Vec<VariantDef>) -> Self {
+           variants: Vec<VariantDef>,
+           repr: ReprOptions) -> Self {
         let mut flags = AdtFlags::NO_ADT_FLAGS;
         let attrs = tcx.get_attrs(did);
         if attr::contains_name(&attrs, "fundamental") {
@@ -1385,6 +1413,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
             variants: variants,
             flags: Cell::new(flags),
             destructor: Cell::new(None),
+            repr: repr,
         }
     }
 
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index f4a35ea5fd0..bb99be20f64 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -425,8 +425,8 @@ impl<'tcx> EntryKind<'tcx> {
             EntryKind::ForeignImmStatic => Def::Static(did, false),
             EntryKind::MutStatic |
             EntryKind::ForeignMutStatic => Def::Static(did, true),
-            EntryKind::Struct(_) => Def::Struct(did),
-            EntryKind::Union(_) => Def::Union(did),
+            EntryKind::Struct(_, _) => Def::Struct(did),
+            EntryKind::Union(_, _) => Def::Union(did),
             EntryKind::Fn(_) |
             EntryKind::ForeignFn(_) => Def::Fn(did),
             EntryKind::Method(_) => Def::Method(did),
@@ -435,7 +435,7 @@ impl<'tcx> EntryKind<'tcx> {
             EntryKind::Mod(_) => Def::Mod(did),
             EntryKind::Variant(_) => Def::Variant(did),
             EntryKind::Trait(_) => Def::Trait(did),
-            EntryKind::Enum => Def::Enum(did),
+            EntryKind::Enum(_) => Def::Enum(did),
             EntryKind::MacroDef(_) => Def::Macro(did),
 
             EntryKind::ForeignMod |
@@ -519,8 +519,8 @@ impl<'a, 'tcx> CrateMetadata {
                    -> (ty::VariantDef, Option<DefIndex>) {
         let data = match item.kind {
             EntryKind::Variant(data) |
-            EntryKind::Struct(data) |
-            EntryKind::Union(data) => data.decode(self),
+            EntryKind::Struct(data, _) |
+            EntryKind::Union(data, _) => data.decode(self),
             _ => bug!(),
         };
 
@@ -547,7 +547,7 @@ impl<'a, 'tcx> CrateMetadata {
         let item = self.entry(item_id);
         let did = self.local_def_id(item_id);
         let mut ctor_index = None;
-        let variants = if let EntryKind::Enum = item.kind {
+        let variants = if let EntryKind::Enum(_) = item.kind {
             item.children
                 .decode(self)
                 .map(|index| {
@@ -561,14 +561,14 @@ impl<'a, 'tcx> CrateMetadata {
             ctor_index = struct_ctor;
             vec![variant]
         };
-        let kind = match item.kind {
-            EntryKind::Enum => ty::AdtKind::Enum,
-            EntryKind::Struct(_) => ty::AdtKind::Struct,
-            EntryKind::Union(_) => ty::AdtKind::Union,
+        let (kind, repr) = match item.kind {
+            EntryKind::Enum(repr) => (ty::AdtKind::Enum, repr),
+            EntryKind::Struct(_, repr) => (ty::AdtKind::Struct, repr),
+            EntryKind::Union(_, repr) => (ty::AdtKind::Union, repr),
             _ => bug!("get_adt_def called on a non-ADT {:?}", did),
         };
 
-        let adt = tcx.alloc_adt_def(did, kind, variants);
+        let adt = tcx.alloc_adt_def(did, kind, variants, repr);
         if let Some(ctor_index) = ctor_index {
             // Make adt definition available through constructor id as well.
             tcx.adt_defs.borrow_mut().insert(self.local_def_id(ctor_index), adt);
@@ -881,8 +881,8 @@ impl<'a, 'tcx> CrateMetadata {
 
     pub fn get_ctor_kind(&self, node_id: DefIndex) -> CtorKind {
         match self.entry(node_id).kind {
-            EntryKind::Struct(data) |
-            EntryKind::Union(data) |
+            EntryKind::Struct(data, _) |
+            EntryKind::Union(data, _) |
             EntryKind::Variant(data) => data.decode(self).ctor_kind,
             _ => CtorKind::Fictive,
         }
@@ -890,7 +890,7 @@ impl<'a, 'tcx> CrateMetadata {
 
     pub fn get_struct_ctor_def_id(&self, node_id: DefIndex) -> Option<DefId> {
         match self.entry(node_id).kind {
-            EntryKind::Struct(data) => {
+            EntryKind::Struct(data, _) => {
                 data.decode(self).struct_ctor.map(|index| self.local_def_id(index))
             }
             _ => None,
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 69e1bbd7766..f4ff5f4626f 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -20,7 +20,7 @@ use rustc::middle::dependency_format::Linkage;
 use rustc::middle::lang_items;
 use rustc::mir;
 use rustc::traits::specialization_graph;
-use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::{self, Ty, TyCtxt, ReprOptions};
 
 use rustc::session::config::{self, CrateTypeProcMacro};
 use rustc::util::nodemap::{FxHashMap, NodeSet};
@@ -401,8 +401,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             }
         }
 
+        let repr_options = get_repr_options(&tcx, adt_def_id);
+
         Entry {
-            kind: EntryKind::Struct(self.lazy(&data)),
+            kind: EntryKind::Struct(self.lazy(&data), repr_options),
             visibility: self.lazy(&ctor_vis),
             span: self.lazy(&tcx.def_span(def_id)),
             attributes: LazySeq::empty(),
@@ -659,7 +661,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             }
             hir::ItemForeignMod(_) => EntryKind::ForeignMod,
             hir::ItemTy(..) => EntryKind::Type,
-            hir::ItemEnum(..) => EntryKind::Enum,
+            hir::ItemEnum(..) => EntryKind::Enum(get_repr_options(&tcx, def_id)),
             hir::ItemStruct(ref struct_def, _) => {
                 let variant = tcx.lookup_adt_def(def_id).struct_variant();
 
@@ -671,20 +673,24 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 } else {
                     None
                 };
+
+                let repr_options = get_repr_options(&tcx, def_id);
+
                 EntryKind::Struct(self.lazy(&VariantData {
                     ctor_kind: variant.ctor_kind,
                     disr: variant.disr_val.to_u128_unchecked(),
                     struct_ctor: struct_ctor,
-                }))
+                }), repr_options)
             }
             hir::ItemUnion(..) => {
                 let variant = tcx.lookup_adt_def(def_id).struct_variant();
+                let repr_options = get_repr_options(&tcx, def_id);
 
                 EntryKind::Union(self.lazy(&VariantData {
                     ctor_kind: variant.ctor_kind,
                     disr: variant.disr_val.to_u128_unchecked(),
                     struct_ctor: None,
-                }))
+                }), repr_options)
             }
             hir::ItemDefaultImpl(..) => {
                 let data = ImplData {
@@ -1419,3 +1425,11 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     result
 }
+
+pub fn get_repr_options<'a, 'tcx, 'gcx>(tcx: &TyCtxt<'a, 'tcx, 'gcx>, did: DefId) -> ReprOptions {
+    let ty = tcx.item_type(did);
+    match ty.sty {
+        ty::TyAdt(ref def, _) => return def.repr,
+        _ => bug!("{} is not an ADT", ty),
+    }
+}
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index d13628e9ce7..10aa4784aa2 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -18,7 +18,7 @@ use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary};
 use rustc::middle::lang_items;
 use rustc::middle::resolve_lifetime::ObjectLifetimeDefault;
 use rustc::mir;
-use rustc::ty::{self, Ty};
+use rustc::ty::{self, Ty, ReprOptions};
 use rustc_back::PanicStrategy;
 
 use rustc_serialize as serialize;
@@ -228,11 +228,11 @@ pub enum EntryKind<'tcx> {
     ForeignMutStatic,
     ForeignMod,
     Type,
-    Enum,
+    Enum(ReprOptions),
     Field,
     Variant(Lazy<VariantData>),
-    Struct(Lazy<VariantData>),
-    Union(Lazy<VariantData>),
+    Struct(Lazy<VariantData>, ReprOptions),
+    Union(Lazy<VariantData>, ReprOptions),
     Fn(Lazy<FnData>),
     ForeignFn(Lazy<FnData>),
     Mod(Lazy<ModData>),
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 1981e7c3a3d..7936db65c44 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -65,7 +65,7 @@ use middle::const_val::ConstVal;
 use rustc_const_eval::EvalHint::UncheckedExprHint;
 use rustc_const_eval::{ConstContext, report_const_eval_err};
 use rustc::ty::subst::Substs;
-use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContainer};
+use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContainer, ReprOptions};
 use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
 use rustc::ty::util::IntTypeExt;
 use rustc::dep_graph::DepNode;
@@ -1006,7 +1006,8 @@ fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     let ctor_id = if !def.is_struct() { Some(ccx.tcx.hir.local_def_id(def.id())) } else { None };
     let variants = vec![convert_struct_variant(ccx, ctor_id.unwrap_or(did), it.name,
                                                ConstInt::Infer(0), def)];
-    let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Struct, variants);
+    let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Struct, variants,
+        ReprOptions::new(&ccx.tcx, did));
     if let Some(ctor_id) = ctor_id {
         // Make adt definition available through constructor id as well.
         ccx.tcx.adt_defs.borrow_mut().insert(ctor_id, adt);
@@ -1024,7 +1025,7 @@ fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     let did = ccx.tcx.hir.local_def_id(it.id);
     let variants = vec![convert_struct_variant(ccx, did, it.name, ConstInt::Infer(0), def)];
 
-    let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Union, variants);
+    let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Union, variants, ReprOptions::new(&ccx.tcx, did));
     ccx.tcx.adt_defs.borrow_mut().insert(did, adt);
     adt
 }
@@ -1112,7 +1113,7 @@ fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         convert_struct_variant(ccx, did, v.node.name, disr, &v.node.data)
     }).collect();
 
-    let adt = tcx.alloc_adt_def(did, AdtKind::Enum, variants);
+    let adt = tcx.alloc_adt_def(did, AdtKind::Enum, variants, ReprOptions::new(&ccx.tcx, did));
     tcx.adt_defs.borrow_mut().insert(did, adt);
     adt
 }
diff --git a/src/test/ui/did_you_mean/issue-39544.rs b/src/test/ui/did_you_mean/issue-39544.rs
new file mode 100644
index 00000000000..bcdafefa247
--- /dev/null
+++ b/src/test/ui/did_you_mean/issue-39544.rs
@@ -0,0 +1,22 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+enum X {
+    Y
+}
+
+struct Z {
+    x: X
+}
+
+fn main() {
+    let z = Z { x: X::Y };
+    let _ = &mut z.x;
+}
diff --git a/src/test/ui/did_you_mean/issue-39544.stderr b/src/test/ui/did_you_mean/issue-39544.stderr
new file mode 100644
index 00000000000..c0088f39ad3
--- /dev/null
+++ b/src/test/ui/did_you_mean/issue-39544.stderr
@@ -0,0 +1,8 @@
+error: cannot borrow immutable field `z.x` as mutable
+  --> $DIR/issue-39544.rs:21:18
+   |
+21 |     let _ = &mut z.x;
+   |                  ^^^
+
+error: aborting due to previous error
+
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 0aefe703c9c..2a24edd4e3f 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -78,6 +78,7 @@ static TARGETS: &'static [&'static str] = &[
     "powerpc64-unknown-linux-gnu",
     "powerpc64le-unknown-linux-gnu",
     "s390x-unknown-linux-gnu",
+    "sparc64-unknown-linux-gnu",
     "wasm32-unknown-emscripten",
     "x86_64-apple-darwin",
     "x86_64-apple-ios",