From d15a98b87815850ef9dd11564e896b6f19b724c3 Mon Sep 17 00:00:00 2001
From: Trevor Spiteri <tspiteri@ieee.org>
Date: Sat, 22 Feb 2020 14:03:46 +0100
Subject: [PATCH 01/28] Stabilize const for integer {to,from}_{be,le,ne}_bytes
 methods

All of these functions can be implemented simply and naturally as
const functions, e.g. u32::from_le_bytes can be implemented as

    (bytes[0] as u32)
        | (bytes[1] as u32) << 8
        | (bytes[2] as u32) << 16
        | (bytes[3] as u32) << 24

So stabilizing the constness will not expose that internally they are
implemented using transmute which is not const in stable.
---
 src/libcore/lib.rs                            |  1 -
 src/libcore/num/mod.rs                        | 28 +++++++++++--------
 .../ui/consts/const-int-conversion-rpass.rs   |  2 --
 3 files changed, 16 insertions(+), 15 deletions(-)

diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index bca96b77812c8..00909094cd0f5 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -131,7 +131,6 @@
 #![feature(rtm_target_feature)]
 #![feature(f16c_target_feature)]
 #![feature(hexagon_target_feature)]
-#![feature(const_int_conversion)]
 #![feature(const_transmute)]
 #![feature(structural_match)]
 #![feature(abi_unadjusted)]
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index 6f55e7c8be8ca..22897680567e2 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -2195,7 +2195,7 @@ let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes();
 assert_eq!(bytes, ", $be_bytes, ");
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")]
+            #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")]
             #[inline]
             pub const fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
                 self.to_be().to_ne_bytes()
@@ -2215,7 +2215,7 @@ let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes();
 assert_eq!(bytes, ", $le_bytes, ");
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")]
+            #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")]
             #[inline]
             pub const fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
                 self.to_le().to_ne_bytes()
@@ -2250,7 +2250,8 @@ assert_eq!(
 );
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")]
+            #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")]
+            #[allow_internal_unstable(const_transmute)]
             #[inline]
             pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
                 // SAFETY: integers are plain old datatypes so we can always transmute them to
@@ -2284,7 +2285,7 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 }
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")]
+            #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")]
             #[inline]
             pub const fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
                 Self::from_be(Self::from_ne_bytes(bytes))
@@ -2317,7 +2318,7 @@ fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 }
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")]
+            #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")]
             #[inline]
             pub const fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
                 Self::from_le(Self::from_ne_bytes(bytes))
@@ -2360,7 +2361,8 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 }
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")]
+            #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")]
+            #[allow_internal_unstable(const_transmute)]
             #[inline]
             pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
                 // SAFETY: integers are plain old datatypes so we can always transmute to them
@@ -4132,7 +4134,7 @@ let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes();
 assert_eq!(bytes, ", $be_bytes, ");
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")]
+            #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")]
             #[inline]
             pub const fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
                 self.to_be().to_ne_bytes()
@@ -4152,7 +4154,7 @@ let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes();
 assert_eq!(bytes, ", $le_bytes, ");
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")]
+            #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")]
             #[inline]
             pub const fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
                 self.to_le().to_ne_bytes()
@@ -4187,7 +4189,8 @@ assert_eq!(
 );
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")]
+            #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")]
+            #[allow_internal_unstable(const_transmute)]
             #[inline]
             pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
                 // SAFETY: integers are plain old datatypes so we can always transmute them to
@@ -4221,7 +4224,7 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 }
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")]
+            #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")]
             #[inline]
             pub const fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
                 Self::from_be(Self::from_ne_bytes(bytes))
@@ -4254,7 +4257,7 @@ fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 }
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")]
+            #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")]
             #[inline]
             pub const fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
                 Self::from_le(Self::from_ne_bytes(bytes))
@@ -4297,7 +4300,8 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 }
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")]
+            #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")]
+            #[allow_internal_unstable(const_transmute)]
             #[inline]
             pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
                 // SAFETY: integers are plain old datatypes so we can always transmute to them
diff --git a/src/test/ui/consts/const-int-conversion-rpass.rs b/src/test/ui/consts/const-int-conversion-rpass.rs
index d52dbbae1e7b5..6484169dd9ae1 100644
--- a/src/test/ui/consts/const-int-conversion-rpass.rs
+++ b/src/test/ui/consts/const-int-conversion-rpass.rs
@@ -1,7 +1,5 @@
 // run-pass
 
-#![feature(const_int_conversion)]
-
 const REVERSE: u32 = 0x12345678_u32.reverse_bits();
 const FROM_BE_BYTES: i32 = i32::from_be_bytes([0x12, 0x34, 0x56, 0x78]);
 const FROM_LE_BYTES: i32 = i32::from_le_bytes([0x12, 0x34, 0x56, 0x78]);

From 87f0dc63a864c6d9a3c34aa4052762dbcd316c91 Mon Sep 17 00:00:00 2001
From: Trevor Spiteri <tspiteri@ieee.org>
Date: Wed, 26 Feb 2020 11:59:37 +0100
Subject: [PATCH 02/28] use unions instead of transmute and add const safety
 comments

---
 src/libcore/num/mod.rs | 44 ++++++++++++++++++++++++++++++++++--------
 1 file changed, 36 insertions(+), 8 deletions(-)

diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index 22897680567e2..b64abc319360e 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -2251,12 +2251,19 @@ assert_eq!(
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
             #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")]
-            #[allow_internal_unstable(const_transmute)]
+            // SAFETY: const sound because integers are plain old datatypes so we can always
+            // transmute them to arrays of bytes
+            #[allow_internal_unstable(const_fn_union)]
             #[inline]
             pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
+                #[repr(C)]
+                union Bytes {
+                    val: $SelfT,
+                    bytes: [u8; mem::size_of::<$SelfT>()],
+                }
                 // SAFETY: integers are plain old datatypes so we can always transmute them to
                 // arrays of bytes
-                unsafe { mem::transmute(self) }
+                unsafe { Bytes { val: self }.bytes }
             }
         }
 
@@ -2362,11 +2369,18 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
             #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")]
-            #[allow_internal_unstable(const_transmute)]
+            // SAFETY: const sound because integers are plain old datatypes so we can always
+            // transmute to them
+            #[allow_internal_unstable(const_fn_union)]
             #[inline]
             pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+                #[repr(C)]
+                union Bytes {
+                    val: $SelfT,
+                    bytes: [u8; mem::size_of::<$SelfT>()],
+                }
                 // SAFETY: integers are plain old datatypes so we can always transmute to them
-                unsafe { mem::transmute(bytes) }
+                unsafe { Bytes { bytes }.val }
             }
         }
     }
@@ -4190,12 +4204,19 @@ assert_eq!(
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
             #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")]
-            #[allow_internal_unstable(const_transmute)]
+            // SAFETY: const sound because integers are plain old datatypes so we can always
+            // transmute them to arrays of bytes
+            #[allow_internal_unstable(const_fn_union)]
             #[inline]
             pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
+                #[repr(C)]
+                union Bytes {
+                    val: $SelfT,
+                    bytes: [u8; mem::size_of::<$SelfT>()],
+                }
                 // SAFETY: integers are plain old datatypes so we can always transmute them to
                 // arrays of bytes
-                unsafe { mem::transmute(self) }
+                unsafe { Bytes { val: self }.bytes }
             }
         }
 
@@ -4301,11 +4322,18 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
             #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")]
-            #[allow_internal_unstable(const_transmute)]
+            // SAFETY: const sound because integers are plain old datatypes so we can always
+            // transmute to them
+            #[allow_internal_unstable(const_fn_union)]
             #[inline]
             pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+                #[repr(C)]
+                union Bytes {
+                    val: $SelfT,
+                    bytes: [u8; mem::size_of::<$SelfT>()],
+                }
                 // SAFETY: integers are plain old datatypes so we can always transmute to them
-                unsafe { mem::transmute(bytes) }
+                unsafe { Bytes { bytes }.val }
             }
         }
     }

From 503026b622d1095770178fbe606a4ba783216992 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sun, 3 Nov 2019 17:21:37 +0100
Subject: [PATCH 03/28] mem::zeroed/uninit: panic on types that do not permit
 zero-initialization

---
 src/libcore/intrinsics.rs                     |  10 ++
 src/libcore/mem/mod.rs                        |   6 +
 src/librustc/ty/layout.rs                     |  30 -----
 src/librustc_codegen_ssa/mir/block.rs         |  31 ++++-
 src/librustc_index/vec.rs                     |   2 +-
 src/librustc_target/abi/mod.rs                | 115 ++++++++++++++++++
 src/librustc_target/lib.rs                    |   3 +
 src/librustc_typeck/check/intrinsic.rs        |   5 +-
 .../intrinsics/panic-uninitialized-zeroed.rs  | 113 +++++++++++++++++
 .../never_type/panic-uninitialized-zeroed.rs  | 102 ----------------
 10 files changed, 280 insertions(+), 137 deletions(-)
 create mode 100644 src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
 delete mode 100644 src/test/ui/never_type/panic-uninitialized-zeroed.rs

diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index 94928211a978a..c02dabcacde85 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -721,6 +721,16 @@ extern "rust-intrinsic" {
     /// This will statically either panic, or do nothing.
     pub fn panic_if_uninhabited<T>();
 
+    /// A guard for unsafe functions that cannot ever be executed if `T` does not permit
+    /// zero-initialization: This will statically either panic, or do nothing.
+    #[cfg(not(bootstrap))]
+    pub fn panic_if_zero_invalid<T>();
+
+    /// A guard for unsafe functions that cannot ever be executed if `T` has invalid
+    /// bit patterns: This will statically either panic, or do nothing.
+    #[cfg(not(bootstrap))]
+    pub fn panic_if_any_invalid<T>();
+
     /// Gets a reference to a static `Location` indicating where it was called.
     #[rustc_const_unstable(feature = "const_caller_location", issue = "47809")]
     pub fn caller_location() -> &'static crate::panic::Location<'static>;
diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs
index 9eb151cf528a5..124eb37fff17e 100644
--- a/src/libcore/mem/mod.rs
+++ b/src/libcore/mem/mod.rs
@@ -495,6 +495,9 @@ pub const fn needs_drop<T>() -> bool {
 #[allow(deprecated)]
 #[rustc_diagnostic_item = "mem_zeroed"]
 pub unsafe fn zeroed<T>() -> T {
+    #[cfg(not(bootstrap))]
+    intrinsics::panic_if_zero_invalid::<T>();
+    #[cfg(bootstrap)]
     intrinsics::panic_if_uninhabited::<T>();
     intrinsics::init()
 }
@@ -528,6 +531,9 @@ pub unsafe fn zeroed<T>() -> T {
 #[allow(deprecated)]
 #[rustc_diagnostic_item = "mem_uninitialized"]
 pub unsafe fn uninitialized<T>() -> T {
+    #[cfg(not(bootstrap))]
+    intrinsics::panic_if_any_invalid::<T>();
+    #[cfg(bootstrap)]
     intrinsics::panic_if_uninhabited::<T>();
     intrinsics::uninit()
 }
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index e8bf2eb9a12c9..6b5f540e5b830 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -1907,36 +1907,6 @@ impl<'tcx, T: HasTyCtxt<'tcx>> HasTyCtxt<'tcx> for LayoutCx<'tcx, T> {
     }
 }
 
-pub trait MaybeResult<T> {
-    type Error;
-
-    fn from(x: Result<T, Self::Error>) -> Self;
-    fn to_result(self) -> Result<T, Self::Error>;
-}
-
-impl<T> MaybeResult<T> for T {
-    type Error = !;
-
-    fn from(x: Result<T, Self::Error>) -> Self {
-        let Ok(x) = x;
-        x
-    }
-    fn to_result(self) -> Result<T, Self::Error> {
-        Ok(self)
-    }
-}
-
-impl<T, E> MaybeResult<T> for Result<T, E> {
-    type Error = E;
-
-    fn from(x: Result<T, Self::Error>) -> Self {
-        x
-    }
-    fn to_result(self) -> Result<T, Self::Error> {
-        self
-    }
-}
-
 pub type TyLayout<'tcx> = ::rustc_target::abi::TyLayout<'tcx, Ty<'tcx>>;
 
 impl<'tcx> LayoutOf for LayoutCx<'tcx, TyCtxt<'tcx>> {
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index a1b54607b809e..923e2486ace68 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -521,11 +521,36 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         }
 
         // Emit a panic or a no-op for `panic_if_uninhabited`.
-        if intrinsic == Some("panic_if_uninhabited") {
+        // These are intrinsics that compile to panics so that we can get a message
+        // which mentions the offending type, even from a const context.
+        #[derive(Debug, PartialEq)]
+        enum PanicIntrinsic { IfUninhabited, IfZeroInvalid, IfAnyInvalid };
+        let panic_intrinsic = intrinsic.and_then(|i| match i {
+            "panic_if_uninhabited" => Some(PanicIntrinsic::IfUninhabited),
+            "panic_if_zero_invalid" => Some(PanicIntrinsic::IfZeroInvalid),
+            "panic_if_any_invalid" => Some(PanicIntrinsic::IfAnyInvalid),
+            _ => None
+        });
+        if let Some(intrinsic) = panic_intrinsic {
+            use PanicIntrinsic::*;
             let ty = instance.unwrap().substs.type_at(0);
             let layout = bx.layout_of(ty);
-            if layout.abi.is_uninhabited() {
-                let msg_str = format!("Attempted to instantiate uninhabited type {}", ty);
+            let do_panic = match intrinsic {
+                IfUninhabited => layout.abi.is_uninhabited(),
+                IfZeroInvalid => // We unwrap as the error type is `!`.
+                    !layout.might_permit_raw_init(&bx, /*zero:*/ true).unwrap(),
+                IfAnyInvalid => // We unwrap as the error type is `!`.
+                    !layout.might_permit_raw_init(&bx, /*zero:*/ false).unwrap(),
+            };
+            if do_panic {
+                let msg_str = if layout.abi.is_uninhabited() {
+                    // Use this error even for the other intrinsics as it is more precise.
+                    format!("attempted to instantiate uninhabited type `{}`", ty)
+                } else if intrinsic == IfZeroInvalid {
+                    format!("attempted to zero-initialize type `{}`, which is invalid", ty)
+                } else {
+                    format!("attempted to leave type `{}` uninitialized, which is invalid", ty)
+                };
                 let msg = bx.const_str(Symbol::intern(&msg_str));
                 let location = self.get_caller_location(&mut bx, span).immediate();
 
diff --git a/src/librustc_index/vec.rs b/src/librustc_index/vec.rs
index 1dfe97238a3df..7020939fa20b2 100644
--- a/src/librustc_index/vec.rs
+++ b/src/librustc_index/vec.rs
@@ -196,7 +196,7 @@ macro_rules! newtype_index {
 
             #[inline]
             fn index(self) -> usize {
-                usize::from(self)
+                self.as_usize()
             }
         }
 
diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index edd0ba46f7565..13a0eb66f32a5 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -919,6 +919,7 @@ impl<'a, Ty> Deref for TyLayout<'a, Ty> {
     }
 }
 
+/// Trait for context types that can compute layouts of things.
 pub trait LayoutOf {
     type Ty;
     type TyLayout;
@@ -929,6 +930,39 @@ pub trait LayoutOf {
     }
 }
 
+/// The `TyLayout` above will always be a `MaybeResult<TyLayout<'_, Self>>`.
+/// We can't add the bound due to the lifetime, but this trait is still useful when
+/// writing code that's generic over the `LayoutOf` impl.
+pub trait MaybeResult<T> {
+    type Error;
+
+    fn from(x: Result<T, Self::Error>) -> Self;
+    fn to_result(self) -> Result<T, Self::Error>;
+}
+
+impl<T> MaybeResult<T> for T {
+    type Error = !;
+
+    fn from(x: Result<T, Self::Error>) -> Self {
+        let Ok(x) = x;
+        x
+    }
+    fn to_result(self) -> Result<T, Self::Error> {
+        Ok(self)
+    }
+}
+
+impl<T, E> MaybeResult<T> for Result<T, E> {
+    type Error = E;
+
+    fn from(x: Result<T, Self::Error>) -> Self {
+        x
+    }
+    fn to_result(self) -> Result<T, Self::Error> {
+        self
+    }
+}
+
 #[derive(Copy, Clone, PartialEq, Eq)]
 pub enum PointerKind {
     /// Most general case, we know no restrictions to tell LLVM.
@@ -969,6 +1003,9 @@ impl<'a, Ty> TyLayout<'a, Ty> {
     {
         Ty::for_variant(self, cx, variant_index)
     }
+
+    /// Callers might want to use `C: LayoutOf<Ty=Ty, TyLayout: MaybeResult<Self>>`
+    /// to allow recursion (see `might_permit_zero_init` below for an example).
     pub fn field<C>(self, cx: &C, i: usize) -> C::TyLayout
     where
         Ty: TyLayoutMethods<'a, C>,
@@ -976,6 +1013,7 @@ impl<'a, Ty> TyLayout<'a, Ty> {
     {
         Ty::field(self, cx, i)
     }
+
     pub fn pointee_info_at<C>(self, cx: &C, offset: Size) -> Option<PointeeInfo>
     where
         Ty: TyLayoutMethods<'a, C>,
@@ -999,4 +1037,81 @@ impl<'a, Ty> TyLayout<'a, Ty> {
             Abi::Aggregate { sized } => sized && self.size.bytes() == 0,
         }
     }
+
+    /// Determines if this type permits "raw" initialization by just transmuting some
+    /// memory into an instance of `T`.
+    /// `zero` indicates if the memory is zero-initialized, or alternatively
+    /// left entirely uninitialized.
+    /// This is conservative: in doubt, it will answer `true`.
+    pub fn might_permit_raw_init<C, E>(
+        self,
+        cx: &C,
+        zero: bool,
+    ) -> Result<bool, E>
+    where
+        Self: Copy,
+        Ty: TyLayoutMethods<'a, C>,
+        C: LayoutOf<Ty = Ty, TyLayout: MaybeResult<Self, Error = E>>
+    {
+        let scalar_allows_raw_init = move |s: &Scalar| -> bool {
+            let range = &s.valid_range;
+            if zero {
+                // The range must contain 0.
+                range.contains(&0) ||
+                (*range.start() > *range.end()) // wrap-around allows 0
+            } else {
+                // The range must include all values.
+                *range.start() == range.end().wrapping_add(1)
+            }
+        };
+
+        // Abi is the most informative here.
+        let res = match &self.abi {
+            Abi::Uninhabited => false, // definitely UB
+            Abi::Scalar(s) => scalar_allows_raw_init(s),
+            Abi::ScalarPair(s1, s2) =>
+                scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2),
+            Abi::Vector { element: s, count } =>
+                *count == 0 || scalar_allows_raw_init(s),
+            Abi::Aggregate { .. } => {
+                match self.variants {
+                    Variants::Multiple { .. } =>
+                        if zero {
+                            // FIXME: could we identify the variant with discriminant 0, check that?
+                            true
+                        } else {
+                            // FIXME: This needs to have some sort of discriminant,
+                            // which cannot be undef. But for now we are conservative.
+                            true
+                        },
+                    Variants::Single { .. } => {
+                        // For aggregates, recurse.
+                        match self.fields {
+                            FieldPlacement::Union(..) => true, // An all-0 unit is fine.
+                            FieldPlacement::Array { .. } =>
+                                // FIXME: The widely use smallvec 0.6 creates uninit arrays
+                                // with any element type, so let us not (yet) complain about that.
+                                // count == 0 ||
+                                // self.field(cx, 0).to_result()?.might_permit_raw_init(cx, zero)?
+                                true,
+                            FieldPlacement::Arbitrary { ref offsets, .. } => {
+                                let mut res = true;
+                                // Check that all fields accept zero-init.
+                                for idx in 0..offsets.len() {
+                                    let field = self.field(cx, idx).to_result()?;
+                                    if !field.might_permit_raw_init(cx, zero)? {
+                                        res = false;
+                                        break;
+                                    }
+                                }
+                                res
+                            }
+                        }
+                    }
+                }
+            }
+        };
+        trace!("might_permit_raw_init({:?}, zero={}) = {}", self.details, zero, res);
+        Ok(res)
+    }
 }
diff --git a/src/librustc_target/lib.rs b/src/librustc_target/lib.rs
index 71150e74f70d4..3c397eb444d1d 100644
--- a/src/librustc_target/lib.rs
+++ b/src/librustc_target/lib.rs
@@ -10,6 +10,9 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![feature(bool_to_option)]
 #![feature(nll)]
+#![feature(never_type)]
+#![feature(associated_type_bounds)]
+#![feature(exhaustive_patterns)]
 
 #[macro_use]
 extern crate log;
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 3572eda5c1399..321932fb193a0 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -147,7 +147,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             ),
             "rustc_peek" => (1, vec![param(0)], param(0)),
             "caller_location" => (0, vec![], tcx.caller_location_ty()),
-            "panic_if_uninhabited" => (1, Vec::new(), tcx.mk_unit()),
+            "panic_if_uninhabited" |
+            "panic_if_zero_invalid" |
+            "panic_if_any_invalid" =>
+                (1, Vec::new(), tcx.mk_unit()),
             "init" => (1, Vec::new(), param(0)),
             "uninit" => (1, Vec::new(), param(0)),
             "forget" => (1, vec![param(0)], tcx.mk_unit()),
diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
new file mode 100644
index 0000000000000..937f949a7b00b
--- /dev/null
+++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
@@ -0,0 +1,113 @@
+// run-pass
+// ignore-wasm32-bare compiled with panic=abort by default
+
+// This test checks panic emitted from `mem::{uninitialized,zeroed}`.
+
+#![feature(never_type)]
+#![allow(deprecated, invalid_value)]
+
+use std::{mem, panic};
+use std::ptr::NonNull;
+
+#[allow(dead_code)]
+struct Foo {
+    x: u8,
+    y: !,
+}
+
+enum Bar {}
+
+#[allow(dead_code)]
+enum OneVariant { Variant(i32) }
+
+fn test_panic_msg<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) {
+    let err = panic::catch_unwind(op).err();
+    assert_eq!(
+        err.as_ref().and_then(|a| a.downcast_ref::<String>()).map(|s| &**s),
+        Some(msg)
+    );
+}
+
+fn main() {
+    unsafe {
+        // Uninitialized types
+        test_panic_msg(
+            || mem::uninitialized::<!>(),
+            "attempted to instantiate uninhabited type `!`"
+        );
+        test_panic_msg(
+            || mem::zeroed::<!>(),
+            "attempted to instantiate uninhabited type `!`"
+        );
+        test_panic_msg(
+            || mem::MaybeUninit::<!>::uninit().assume_init(),
+            "attempted to instantiate uninhabited type `!`"
+        );
+
+        test_panic_msg(
+            || mem::uninitialized::<Foo>(),
+            "attempted to instantiate uninhabited type `Foo`"
+        );
+        test_panic_msg(
+            || mem::zeroed::<Foo>(),
+            "attempted to instantiate uninhabited type `Foo`"
+        );
+        test_panic_msg(
+            || mem::MaybeUninit::<Foo>::uninit().assume_init(),
+            "attempted to instantiate uninhabited type `Foo`"
+        );
+
+        test_panic_msg(
+            || mem::uninitialized::<Bar>(),
+            "attempted to instantiate uninhabited type `Bar`"
+        );
+        test_panic_msg(
+            || mem::zeroed::<Bar>(),
+            "attempted to instantiate uninhabited type `Bar`"
+        );
+        test_panic_msg(
+            || mem::MaybeUninit::<Bar>::uninit().assume_init(),
+            "attempted to instantiate uninhabited type `Bar`"
+        );
+
+        // Types that do not like zero-initialziation
+        test_panic_msg(
+            || mem::uninitialized::<fn()>(),
+            "attempted to leave type `fn()` uninitialized, which is invalid"
+        );
+        test_panic_msg(
+            || mem::zeroed::<fn()>(),
+            "attempted to zero-initialize type `fn()`, which is invalid"
+        );
+
+        test_panic_msg(
+            || mem::uninitialized::<*const dyn Send>(),
+            "attempted to leave type `*const dyn std::marker::Send` uninitialized, which is invalid"
+        );
+        test_panic_msg(
+            || mem::zeroed::<*const dyn Send>(),
+            "attempted to zero-initialize type `*const dyn std::marker::Send`, which is invalid"
+        );
+
+        test_panic_msg(
+            || mem::uninitialized::<(NonNull<u32>, u32, u32)>(),
+            "attempted to leave type `(std::ptr::NonNull<u32>, u32, u32)` uninitialized, \
+                which is invalid"
+        );
+        test_panic_msg(
+            || mem::zeroed::<(NonNull<u32>, u32, u32)>(),
+            "attempted to zero-initialize type `(std::ptr::NonNull<u32>, u32, u32)`, \
+                which is invalid"
+        );
+
+        test_panic_msg(
+            || mem::uninitialized::<bool>(),
+            "attempted to leave type `bool` uninitialized, which is invalid"
+        );
+
+        // Some things that should work.
+        let _val = mem::zeroed::<bool>();
+        let _val = mem::zeroed::<OneVariant>();
+        let _val = mem::zeroed::<Option<&'static i32>>();
+    }
+}
diff --git a/src/test/ui/never_type/panic-uninitialized-zeroed.rs b/src/test/ui/never_type/panic-uninitialized-zeroed.rs
deleted file mode 100644
index e0c30160b9e94..0000000000000
--- a/src/test/ui/never_type/panic-uninitialized-zeroed.rs
+++ /dev/null
@@ -1,102 +0,0 @@
-// run-pass
-// ignore-wasm32-bare compiled with panic=abort by default
-// This test checks that instantiating an uninhabited type via `mem::{uninitialized,zeroed}` results
-// in a runtime panic.
-
-#![feature(never_type)]
-#![allow(deprecated, invalid_value)]
-
-use std::{mem, panic};
-
-#[allow(dead_code)]
-struct Foo {
-    x: u8,
-    y: !,
-}
-
-enum Bar {}
-
-fn main() {
-    unsafe {
-        assert_eq!(
-            panic::catch_unwind(|| {
-                mem::uninitialized::<!>()
-            }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
-                s == "Attempted to instantiate uninhabited type !"
-            })),
-            Some(true)
-        );
-
-        assert_eq!(
-            panic::catch_unwind(|| {
-                mem::zeroed::<!>()
-            }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
-                s == "Attempted to instantiate uninhabited type !"
-            })),
-            Some(true)
-        );
-
-        assert_eq!(
-            panic::catch_unwind(|| {
-                mem::MaybeUninit::<!>::uninit().assume_init()
-            }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
-                s == "Attempted to instantiate uninhabited type !"
-            })),
-            Some(true)
-        );
-
-        assert_eq!(
-            panic::catch_unwind(|| {
-                mem::uninitialized::<Foo>()
-            }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
-                s == "Attempted to instantiate uninhabited type Foo"
-            })),
-            Some(true)
-        );
-
-        assert_eq!(
-            panic::catch_unwind(|| {
-                mem::zeroed::<Foo>()
-            }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
-                s == "Attempted to instantiate uninhabited type Foo"
-            })),
-            Some(true)
-        );
-
-        assert_eq!(
-            panic::catch_unwind(|| {
-                mem::MaybeUninit::<Foo>::uninit().assume_init()
-            }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
-                s == "Attempted to instantiate uninhabited type Foo"
-            })),
-            Some(true)
-        );
-
-        assert_eq!(
-            panic::catch_unwind(|| {
-                mem::uninitialized::<Bar>()
-            }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
-                s == "Attempted to instantiate uninhabited type Bar"
-            })),
-            Some(true)
-        );
-
-        assert_eq!(
-            panic::catch_unwind(|| {
-                mem::zeroed::<Bar>()
-            }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
-                s == "Attempted to instantiate uninhabited type Bar"
-            })),
-            Some(true)
-        );
-
-        assert_eq!(
-            panic::catch_unwind(|| {
-                mem::MaybeUninit::<Bar>::uninit().assume_init()
-            }).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
-                s == "Attempted to instantiate uninhabited type Bar"
-            })),
-            Some(true)
-        );
-    }
-}

From 6fd909b2b1dd2789e0f1af79283c6105fa502ca3 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Wed, 6 Nov 2019 11:07:00 +0100
Subject: [PATCH 04/28] reference tracking issue

---
 src/librustc_target/abi/mod.rs | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index 13a0eb66f32a5..4e4ef46909095 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -1077,10 +1077,11 @@ impl<'a, Ty> TyLayout<'a, Ty> {
                 match self.variants {
                     Variants::Multiple { .. } =>
                         if zero {
-                            // FIXME: could we identify the variant with discriminant 0, check that?
+                            // FIXME(#66151):
+                            // could we identify the variant with discriminant 0, check that?
                             true
                         } else {
-                            // FIXME: This needs to have some sort of discriminant,
+                            // FIXME(#66151): This needs to have some sort of discriminant,
                             // which cannot be undef. But for now we are conservative.
                             true
                         },
@@ -1089,7 +1090,7 @@ impl<'a, Ty> TyLayout<'a, Ty> {
                         match self.fields {
                             FieldPlacement::Union(..) => true, // An all-0 unit is fine.
                             FieldPlacement::Array { .. } =>
-                                // FIXME: The widely use smallvec 0.6 creates uninit arrays
+                                // FIXME(#66151): The widely use smallvec 0.6 creates uninit arrays
                                 // with any element type, so let us not (yet) complain about that.
                                 // count == 0 ||
                                 // self.field(cx, 0).to_result()?.might_permit_raw_init(cx, zero)?

From d78c4aa62ec0382d85e88b44cce2c087c5357f53 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sat, 9 Nov 2019 12:19:44 +0100
Subject: [PATCH 05/28] use valid_range_exclusive for correct overflow handling

---
 src/librustc_target/abi/mod.rs | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index 4e4ef46909095..c48e7de6b0486 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -1051,17 +1051,20 @@ impl<'a, Ty> TyLayout<'a, Ty> {
     where
         Self: Copy,
         Ty: TyLayoutMethods<'a, C>,
-        C: LayoutOf<Ty = Ty, TyLayout: MaybeResult<Self, Error = E>>
+        C: LayoutOf<Ty = Ty, TyLayout: MaybeResult<Self, Error = E>> + HasDataLayout
     {
         let scalar_allows_raw_init = move |s: &Scalar| -> bool {
-            let range = &s.valid_range;
             if zero {
+                let range = &s.valid_range;
                 // The range must contain 0.
                 range.contains(&0) ||
                 (*range.start() > *range.end()) // wrap-around allows 0
             } else {
-                // The range must include all values.
-                *range.start() == range.end().wrapping_add(1)
+                // The range must include all values. `valid_range_exclusive` handles
+                // the wrap-around using target arithmetic; with wrap-around then the full
+                // range is one where `start == end`.
+                let range = s.valid_range_exclusive(cx);
+                range.start == range.end
             }
         };
 

From df6a3a0ed216a8548130f9b431964531a1bc7633 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sat, 9 Nov 2019 12:24:26 +0100
Subject: [PATCH 06/28] test some more things that should not panic

---
 .../intrinsics/panic-uninitialized-zeroed.rs  | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
index 937f949a7b00b..9c869947bfa10 100644
--- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
+++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
@@ -6,8 +6,11 @@
 #![feature(never_type)]
 #![allow(deprecated, invalid_value)]
 
-use std::{mem, panic};
-use std::ptr::NonNull;
+use std::{
+    mem::{self, MaybeUninit},
+    panic,
+    ptr::NonNull,
+};
 
 #[allow(dead_code)]
 struct Foo {
@@ -40,7 +43,7 @@ fn main() {
             "attempted to instantiate uninhabited type `!`"
         );
         test_panic_msg(
-            || mem::MaybeUninit::<!>::uninit().assume_init(),
+            || MaybeUninit::<!>::uninit().assume_init(),
             "attempted to instantiate uninhabited type `!`"
         );
 
@@ -53,7 +56,7 @@ fn main() {
             "attempted to instantiate uninhabited type `Foo`"
         );
         test_panic_msg(
-            || mem::MaybeUninit::<Foo>::uninit().assume_init(),
+            || MaybeUninit::<Foo>::uninit().assume_init(),
             "attempted to instantiate uninhabited type `Foo`"
         );
 
@@ -66,7 +69,7 @@ fn main() {
             "attempted to instantiate uninhabited type `Bar`"
         );
         test_panic_msg(
-            || mem::MaybeUninit::<Bar>::uninit().assume_init(),
+            || MaybeUninit::<Bar>::uninit().assume_init(),
             "attempted to instantiate uninhabited type `Bar`"
         );
 
@@ -109,5 +112,11 @@ fn main() {
         let _val = mem::zeroed::<bool>();
         let _val = mem::zeroed::<OneVariant>();
         let _val = mem::zeroed::<Option<&'static i32>>();
+        let _val = mem::zeroed::<MaybeUninit<NonNull<u32>>>();
+        let _val = mem::uninitialized::<MaybeUninit<bool>>();
+
+        // We don't panic for these just to be conservative. They are UB as of now (2019-11-09).
+        let _val = mem::uninitialized::<i32>();
+        let _val = mem::uninitialized::<*const ()>();
     }
 }

From b133d6776fde22e944eb7f266ee165ffcf7cdb09 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Wed, 13 Nov 2019 09:00:29 +0100
Subject: [PATCH 07/28] make it even more conservative, and note some FIXMEs

---
 src/librustc_codegen_ssa/mir/block.rs          |  2 ++
 src/librustc_target/abi/mod.rs                 | 18 +++++++++++++-----
 .../intrinsics/panic-uninitialized-zeroed.rs   |  2 ++
 3 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index 923e2486ace68..ae3d8442add67 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -526,6 +526,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         #[derive(Debug, PartialEq)]
         enum PanicIntrinsic { IfUninhabited, IfZeroInvalid, IfAnyInvalid };
         let panic_intrinsic = intrinsic.and_then(|i| match i {
+            // FIXME: Move to symbols instead of strings.
             "panic_if_uninhabited" => Some(PanicIntrinsic::IfUninhabited),
             "panic_if_zero_invalid" => Some(PanicIntrinsic::IfZeroInvalid),
             "panic_if_any_invalid" => Some(PanicIntrinsic::IfAnyInvalid),
@@ -555,6 +556,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 let location = self.get_caller_location(&mut bx, span).immediate();
 
                 // Obtain the panic entry point.
+                // FIXME: dedup this with `codegen_assert_terminator` above.
                 let def_id =
                     common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem);
                 let instance = ty::Instance::mono(bx.tcx(), def_id);
diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index c48e7de6b0486..71f97ca85832c 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -1043,6 +1043,10 @@ impl<'a, Ty> TyLayout<'a, Ty> {
     /// `zero` indicates if the memory is zero-initialized, or alternatively
     /// left entirely uninitialized.
     /// This is conservative: in doubt, it will answer `true`.
+    ///
+    /// FIXME: Once we removed all the conservatism, we could alternatively
+    /// create an all-0/all-undef constant and run the vonst value validator to see if
+    /// this is a valid value for the given type.
     pub fn might_permit_raw_init<C, E>(
         self,
         cx: &C,
@@ -1095,11 +1099,14 @@ impl<'a, Ty> TyLayout<'a, Ty> {
                             FieldPlacement::Array { .. } =>
                                 // FIXME(#66151): The widely use smallvec 0.6 creates uninit arrays
                                 // with any element type, so let us not (yet) complain about that.
-                                // count == 0 ||
-                                // self.field(cx, 0).to_result()?.might_permit_raw_init(cx, zero)?
+                                /* count == 0 ||
+                                self.field(cx, 0).to_result()?.might_permit_raw_init(cx, zero)? */
                                 true,
-                            FieldPlacement::Arbitrary { ref offsets, .. } => {
-                                let mut res = true;
+                            FieldPlacement::Arbitrary { .. } => {
+                                // FIXME(#66151) cargo depends on sized-chunks 0.3.0 which
+                                // has some illegal zero-initialization, so let us not (yet)
+                                // complain about aggregates either.
+                                /* let mut res = true;
                                 // Check that all fields accept zero-init.
                                 for idx in 0..offsets.len() {
                                     let field = self.field(cx, idx).to_result()?;
@@ -1108,7 +1115,8 @@ impl<'a, Ty> TyLayout<'a, Ty> {
                                         break;
                                     }
                                 }
-                                res
+                                res */
+                                true
                             }
                         }
                     }
diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
index 9c869947bfa10..a1b2a1af2c434 100644
--- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
+++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
@@ -92,6 +92,7 @@ fn main() {
             "attempted to zero-initialize type `*const dyn std::marker::Send`, which is invalid"
         );
 
+        /* FIXME(#66151) we conservatively do not error here yet.
         test_panic_msg(
             || mem::uninitialized::<(NonNull<u32>, u32, u32)>(),
             "attempted to leave type `(std::ptr::NonNull<u32>, u32, u32)` uninitialized, \
@@ -102,6 +103,7 @@ fn main() {
             "attempted to zero-initialize type `(std::ptr::NonNull<u32>, u32, u32)`, \
                 which is invalid"
         );
+        */
 
         test_panic_msg(
             || mem::uninitialized::<bool>(),

From 6e66f586a0da51fbd4cafa2e1da914cf07c65503 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sun, 16 Feb 2020 22:45:28 +0100
Subject: [PATCH 08/28] fmt

---
 src/librustc_codegen_ssa/mir/block.rs  | 16 +++++++-----
 src/librustc_target/abi/mod.rs         | 34 ++++++++++++--------------
 src/librustc_typeck/check/intrinsic.rs |  7 +++---
 3 files changed, 28 insertions(+), 29 deletions(-)

diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index ae3d8442add67..7c5a17d43b6da 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -524,13 +524,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         // These are intrinsics that compile to panics so that we can get a message
         // which mentions the offending type, even from a const context.
         #[derive(Debug, PartialEq)]
-        enum PanicIntrinsic { IfUninhabited, IfZeroInvalid, IfAnyInvalid };
+        enum PanicIntrinsic {
+            IfUninhabited,
+            IfZeroInvalid,
+            IfAnyInvalid,
+        };
         let panic_intrinsic = intrinsic.and_then(|i| match i {
             // FIXME: Move to symbols instead of strings.
             "panic_if_uninhabited" => Some(PanicIntrinsic::IfUninhabited),
             "panic_if_zero_invalid" => Some(PanicIntrinsic::IfZeroInvalid),
             "panic_if_any_invalid" => Some(PanicIntrinsic::IfAnyInvalid),
-            _ => None
+            _ => None,
         });
         if let Some(intrinsic) = panic_intrinsic {
             use PanicIntrinsic::*;
@@ -538,10 +542,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             let layout = bx.layout_of(ty);
             let do_panic = match intrinsic {
                 IfUninhabited => layout.abi.is_uninhabited(),
-                IfZeroInvalid => // We unwrap as the error type is `!`.
-                    !layout.might_permit_raw_init(&bx, /*zero:*/ true).unwrap(),
-                IfAnyInvalid => // We unwrap as the error type is `!`.
-                    !layout.might_permit_raw_init(&bx, /*zero:*/ false).unwrap(),
+                // We unwrap as the error type is `!`.
+                IfZeroInvalid => !layout.might_permit_raw_init(&bx, /*zero:*/ true).unwrap(),
+                // We unwrap as the error type is `!`.
+                IfAnyInvalid => !layout.might_permit_raw_init(&bx, /*zero:*/ false).unwrap(),
             };
             if do_panic {
                 let msg_str = if layout.abi.is_uninhabited() {
diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index 71f97ca85832c..c043d87f69f9d 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -1047,22 +1047,17 @@ impl<'a, Ty> TyLayout<'a, Ty> {
     /// FIXME: Once we removed all the conservatism, we could alternatively
     /// create an all-0/all-undef constant and run the vonst value validator to see if
     /// this is a valid value for the given type.
-    pub fn might_permit_raw_init<C, E>(
-        self,
-        cx: &C,
-        zero: bool,
-    ) -> Result<bool, E>
+    pub fn might_permit_raw_init<C, E>(self, cx: &C, zero: bool) -> Result<bool, E>
     where
         Self: Copy,
         Ty: TyLayoutMethods<'a, C>,
-        C: LayoutOf<Ty = Ty, TyLayout: MaybeResult<Self, Error = E>> + HasDataLayout
+        C: LayoutOf<Ty = Ty, TyLayout: MaybeResult<Self, Error = E>> + HasDataLayout,
     {
         let scalar_allows_raw_init = move |s: &Scalar| -> bool {
             if zero {
                 let range = &s.valid_range;
                 // The range must contain 0.
-                range.contains(&0) ||
-                (*range.start() > *range.end()) // wrap-around allows 0
+                range.contains(&0) || (*range.start() > *range.end()) // wrap-around allows 0
             } else {
                 // The range must include all values. `valid_range_exclusive` handles
                 // the wrap-around using target arithmetic; with wrap-around then the full
@@ -1076,13 +1071,11 @@ impl<'a, Ty> TyLayout<'a, Ty> {
         let res = match &self.abi {
             Abi::Uninhabited => false, // definitely UB
             Abi::Scalar(s) => scalar_allows_raw_init(s),
-            Abi::ScalarPair(s1, s2) =>
-                scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2),
-            Abi::Vector { element: s, count } =>
-                *count == 0 || scalar_allows_raw_init(s),
+            Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2),
+            Abi::Vector { element: s, count } => *count == 0 || scalar_allows_raw_init(s),
             Abi::Aggregate { .. } => {
                 match self.variants {
-                    Variants::Multiple { .. } =>
+                    Variants::Multiple { .. } => {
                         if zero {
                             // FIXME(#66151):
                             // could we identify the variant with discriminant 0, check that?
@@ -1091,17 +1084,20 @@ impl<'a, Ty> TyLayout<'a, Ty> {
                             // FIXME(#66151): This needs to have some sort of discriminant,
                             // which cannot be undef. But for now we are conservative.
                             true
-                        },
+                        }
+                    }
                     Variants::Single { .. } => {
                         // For aggregates, recurse.
                         match self.fields {
                             FieldPlacement::Union(..) => true, // An all-0 unit is fine.
                             FieldPlacement::Array { .. } =>
-                                // FIXME(#66151): The widely use smallvec 0.6 creates uninit arrays
-                                // with any element type, so let us not (yet) complain about that.
-                                /* count == 0 ||
-                                self.field(cx, 0).to_result()?.might_permit_raw_init(cx, zero)? */
-                                true,
+                            // FIXME(#66151): The widely use smallvec 0.6 creates uninit arrays
+                            // with any element type, so let us not (yet) complain about that.
+                            /* count == 0 ||
+                            self.field(cx, 0).to_result()?.might_permit_raw_init(cx, zero)? */
+                            {
+                                true
+                            }
                             FieldPlacement::Arbitrary { .. } => {
                                 // FIXME(#66151) cargo depends on sized-chunks 0.3.0 which
                                 // has some illegal zero-initialization, so let us not (yet)
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 321932fb193a0..d2a358c3e09b8 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -147,10 +147,9 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             ),
             "rustc_peek" => (1, vec![param(0)], param(0)),
             "caller_location" => (0, vec![], tcx.caller_location_ty()),
-            "panic_if_uninhabited" |
-            "panic_if_zero_invalid" |
-            "panic_if_any_invalid" =>
-                (1, Vec::new(), tcx.mk_unit()),
+            "panic_if_uninhabited" | "panic_if_zero_invalid" | "panic_if_any_invalid" => {
+                (1, Vec::new(), tcx.mk_unit())
+            }
             "init" => (1, Vec::new(), param(0)),
             "uninit" => (1, Vec::new(), param(0)),
             "forget" => (1, vec![param(0)], tcx.mk_unit()),

From 729f4cd9ae9a619677afaa4c389e000c03e5b22b Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Mon, 17 Feb 2020 09:21:02 +0100
Subject: [PATCH 09/28] we cannot short-circuit just becuase the Abi seems
 harmless

also add tests for ScalarPair enums
---
 src/librustc_target/abi/mod.rs                | 63 ++++---------------
 .../intrinsics/panic-uninitialized-zeroed.rs  | 48 +++++++++++++-
 2 files changed, 59 insertions(+), 52 deletions(-)

diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index c043d87f69f9d..aa9474233a4ea 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -1045,7 +1045,7 @@ impl<'a, Ty> TyLayout<'a, Ty> {
     /// This is conservative: in doubt, it will answer `true`.
     ///
     /// FIXME: Once we removed all the conservatism, we could alternatively
-    /// create an all-0/all-undef constant and run the vonst value validator to see if
+    /// create an all-0/all-undef constant and run the const value validator to see if
     /// this is a valid value for the given type.
     pub fn might_permit_raw_init<C, E>(self, cx: &C, zero: bool) -> Result<bool, E>
     where
@@ -1067,59 +1067,22 @@ impl<'a, Ty> TyLayout<'a, Ty> {
             }
         };
 
-        // Abi is the most informative here.
-        let res = match &self.abi {
+        // Check the ABI.
+        let valid = match &self.abi {
             Abi::Uninhabited => false, // definitely UB
             Abi::Scalar(s) => scalar_allows_raw_init(s),
             Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2),
             Abi::Vector { element: s, count } => *count == 0 || scalar_allows_raw_init(s),
-            Abi::Aggregate { .. } => {
-                match self.variants {
-                    Variants::Multiple { .. } => {
-                        if zero {
-                            // FIXME(#66151):
-                            // could we identify the variant with discriminant 0, check that?
-                            true
-                        } else {
-                            // FIXME(#66151): This needs to have some sort of discriminant,
-                            // which cannot be undef. But for now we are conservative.
-                            true
-                        }
-                    }
-                    Variants::Single { .. } => {
-                        // For aggregates, recurse.
-                        match self.fields {
-                            FieldPlacement::Union(..) => true, // An all-0 unit is fine.
-                            FieldPlacement::Array { .. } =>
-                            // FIXME(#66151): The widely use smallvec 0.6 creates uninit arrays
-                            // with any element type, so let us not (yet) complain about that.
-                            /* count == 0 ||
-                            self.field(cx, 0).to_result()?.might_permit_raw_init(cx, zero)? */
-                            {
-                                true
-                            }
-                            FieldPlacement::Arbitrary { .. } => {
-                                // FIXME(#66151) cargo depends on sized-chunks 0.3.0 which
-                                // has some illegal zero-initialization, so let us not (yet)
-                                // complain about aggregates either.
-                                /* let mut res = true;
-                                // Check that all fields accept zero-init.
-                                for idx in 0..offsets.len() {
-                                    let field = self.field(cx, idx).to_result()?;
-                                    if !field.might_permit_raw_init(cx, zero)? {
-                                        res = false;
-                                        break;
-                                    }
-                                }
-                                res */
-                                true
-                            }
-                        }
-                    }
-                }
-            }
+            Abi::Aggregate { .. } => true, // Cannot be excluded *right now*.
         };
-        trace!("might_permit_raw_init({:?}, zero={}) = {}", self.details, zero, res);
-        Ok(res)
+        if !valid {
+            // This is definitely not okay.
+            trace!("might_permit_raw_init({:?}, zero={}): not valid", self.details, zero);
+            return Ok(false);
+        }
+
+        // If we have not found an error yet, we need to recursively descend.
+        // FIXME(#66151): For now, we are conservative and do not do this.
+        Ok(true)
     }
 }
diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
index a1b2a1af2c434..be0df0ea2541c 100644
--- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
+++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
@@ -7,9 +7,10 @@
 #![allow(deprecated, invalid_value)]
 
 use std::{
-    mem::{self, MaybeUninit},
+    mem::{self, MaybeUninit, ManuallyDrop},
     panic,
     ptr::NonNull,
+    num,
 };
 
 #[allow(dead_code)]
@@ -23,6 +24,18 @@ enum Bar {}
 #[allow(dead_code)]
 enum OneVariant { Variant(i32) }
 
+// An enum with ScalarPair layout
+#[allow(dead_code)]
+enum LR {
+    Left(i64),
+    Right(i64),
+}
+#[allow(dead_code, non_camel_case_types)]
+enum LR_NonZero {
+    Left(num::NonZeroI64),
+    Right(num::NonZeroI64),
+}
+
 fn test_panic_msg<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) {
     let err = panic::catch_unwind(op).err();
     assert_eq!(
@@ -33,7 +46,7 @@ fn test_panic_msg<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) {
 
 fn main() {
     unsafe {
-        // Uninitialized types
+        // Uninhabited types
         test_panic_msg(
             || mem::uninitialized::<!>(),
             "attempted to instantiate uninhabited type `!`"
@@ -93,6 +106,26 @@ fn main() {
         );
 
         /* FIXME(#66151) we conservatively do not error here yet.
+        test_panic_msg(
+            || mem::uninitialized::<LR_NonZero>(),
+            "attempted to leave type `LR_NonZero` uninitialized, which is invalid"
+        );
+        test_panic_msg(
+            || mem::zeroed::<LR_NonZero>(),
+            "attempted to zero-initialize type `LR_NonZero`, which is invalid"
+        );
+
+        test_panic_msg(
+            || mem::uninitialized::<ManuallyDrop<LR_NonZero>>(),
+            "attempted to leave type `std::mem::ManuallyDrop<LR_NonZero>` uninitialized, \
+             which is invalid"
+        );
+        test_panic_msg(
+            || mem::zeroed::<ManuallyDrop<LR_NonZero>>(),
+            "attempted to zero-initialize type `std::mem::ManuallyDrop<LR_NonZero>`, \
+             which is invalid"
+        );
+
         test_panic_msg(
             || mem::uninitialized::<(NonNull<u32>, u32, u32)>(),
             "attempted to leave type `(std::ptr::NonNull<u32>, u32, u32)` uninitialized, \
@@ -105,13 +138,24 @@ fn main() {
         );
         */
 
+        // Types that can be zero, but not uninit.
         test_panic_msg(
             || mem::uninitialized::<bool>(),
             "attempted to leave type `bool` uninitialized, which is invalid"
         );
+        test_panic_msg(
+            || mem::uninitialized::<LR>(),
+            "attempted to leave type `LR` uninitialized, which is invalid"
+        );
+        test_panic_msg(
+            || mem::uninitialized::<ManuallyDrop<LR>>(),
+            "attempted to leave type `std::mem::ManuallyDrop<LR>` uninitialized, which is invalid"
+        );
 
         // Some things that should work.
         let _val = mem::zeroed::<bool>();
+        let _val = mem::zeroed::<LR>();
+        let _val = mem::zeroed::<ManuallyDrop<LR>>();
         let _val = mem::zeroed::<OneVariant>();
         let _val = mem::zeroed::<Option<&'static i32>>();
         let _val = mem::zeroed::<MaybeUninit<NonNull<u32>>>();

From bfe593e03a0f73ee52ac666be17e963957ef628f Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sat, 29 Feb 2020 09:29:51 +0100
Subject: [PATCH 10/28] clarify a comment in the test

---
 src/test/ui/intrinsics/panic-uninitialized-zeroed.rs | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
index be0df0ea2541c..02f8ecaa4eec5 100644
--- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
+++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
@@ -161,7 +161,9 @@ fn main() {
         let _val = mem::zeroed::<MaybeUninit<NonNull<u32>>>();
         let _val = mem::uninitialized::<MaybeUninit<bool>>();
 
-        // We don't panic for these just to be conservative. They are UB as of now (2019-11-09).
+        // These are UB because they have not been officially blessed, but we await the resolution
+        // of <https://github.com/rust-lang/unsafe-code-guidelines/issues/71> before doing
+        // anything about that.
         let _val = mem::uninitialized::<i32>();
         let _val = mem::uninitialized::<*const ()>();
     }

From 7c84e451d533f12d3a1a7b35ca66bdd02ecf17fc Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sat, 29 Feb 2020 09:40:40 +0100
Subject: [PATCH 11/28] move panic intrinsic codegen to helper function

---
 src/librustc_codegen_ssa/mir/block.rs | 158 +++++++++++++++-----------
 1 file changed, 92 insertions(+), 66 deletions(-)

diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index 7c5a17d43b6da..c8d352cd2dd98 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -434,6 +434,89 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         helper.do_call(self, &mut bx, fn_abi, llfn, &args, None, cleanup);
     }
 
+    /// Returns `true` if this is indeed a panic intrinsic and codegen is done.
+    fn codegen_panic_intrinsic(
+        &mut self,
+        helper: &TerminatorCodegenHelper<'tcx>,
+        bx: &mut Bx,
+        intrinsic: Option<&str>,
+        instance: Option<Instance<'tcx>>,
+        span: Span,
+        destination: &Option<(mir::Place<'tcx>, mir::BasicBlock)>,
+        cleanup: Option<mir::BasicBlock>,
+    ) -> bool {
+        // Emit a panic or a no-op for `panic_if_uninhabited`.
+        // These are intrinsics that compile to panics so that we can get a message
+        // which mentions the offending type, even from a const context.
+        #[derive(Debug, PartialEq)]
+        enum PanicIntrinsic {
+            IfUninhabited,
+            IfZeroInvalid,
+            IfAnyInvalid,
+        };
+        let panic_intrinsic = intrinsic.and_then(|i| match i {
+            // FIXME: Move to symbols instead of strings.
+            "panic_if_uninhabited" => Some(PanicIntrinsic::IfUninhabited),
+            "panic_if_zero_invalid" => Some(PanicIntrinsic::IfZeroInvalid),
+            "panic_if_any_invalid" => Some(PanicIntrinsic::IfAnyInvalid),
+            _ => None,
+        });
+        if let Some(intrinsic) = panic_intrinsic {
+            use PanicIntrinsic::*;
+            let ty = instance.unwrap().substs.type_at(0);
+            let layout = bx.layout_of(ty);
+            let do_panic = match intrinsic {
+                IfUninhabited => layout.abi.is_uninhabited(),
+                // We unwrap as the error type is `!`.
+                IfZeroInvalid => !layout.might_permit_raw_init(bx, /*zero:*/ true).unwrap(),
+                // We unwrap as the error type is `!`.
+                IfAnyInvalid => !layout.might_permit_raw_init(bx, /*zero:*/ false).unwrap(),
+            };
+            if do_panic {
+                let msg_str = if layout.abi.is_uninhabited() {
+                    // Use this error even for the other intrinsics as it is more precise.
+                    format!("attempted to instantiate uninhabited type `{}`", ty)
+                } else if intrinsic == IfZeroInvalid {
+                    format!("attempted to zero-initialize type `{}`, which is invalid", ty)
+                } else {
+                    format!("attempted to leave type `{}` uninitialized, which is invalid", ty)
+                };
+                let msg = bx.const_str(Symbol::intern(&msg_str));
+                let location = self.get_caller_location(bx, span).immediate();
+
+                // Obtain the panic entry point.
+                // FIXME: dedup this with `codegen_assert_terminator` above.
+                let def_id =
+                    common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem);
+                let instance = ty::Instance::mono(bx.tcx(), def_id);
+                let fn_abi = FnAbi::of_instance(bx, instance, &[]);
+                let llfn = bx.get_fn_addr(instance);
+
+                if let Some((_, target)) = destination.as_ref() {
+                    helper.maybe_sideeffect(self.mir, bx, &[*target]);
+                }
+                // Codegen the actual panic invoke/call.
+                helper.do_call(
+                    self,
+                    bx,
+                    fn_abi,
+                    llfn,
+                    &[msg.0, msg.1, location],
+                    destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)),
+                    cleanup,
+                );
+            } else {
+                // a NOP
+                let target = destination.as_ref().unwrap().1;
+                helper.maybe_sideeffect(self.mir, bx, &[target]);
+                helper.funclet_br(self, bx, target)
+            }
+            true
+        } else {
+            false
+        }
+    }
+
     fn codegen_call_terminator(
         &mut self,
         helper: TerminatorCodegenHelper<'tcx>,
@@ -520,72 +603,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             bug!("`miri_start_panic` should never end up in compiled code");
         }
 
-        // Emit a panic or a no-op for `panic_if_uninhabited`.
-        // These are intrinsics that compile to panics so that we can get a message
-        // which mentions the offending type, even from a const context.
-        #[derive(Debug, PartialEq)]
-        enum PanicIntrinsic {
-            IfUninhabited,
-            IfZeroInvalid,
-            IfAnyInvalid,
-        };
-        let panic_intrinsic = intrinsic.and_then(|i| match i {
-            // FIXME: Move to symbols instead of strings.
-            "panic_if_uninhabited" => Some(PanicIntrinsic::IfUninhabited),
-            "panic_if_zero_invalid" => Some(PanicIntrinsic::IfZeroInvalid),
-            "panic_if_any_invalid" => Some(PanicIntrinsic::IfAnyInvalid),
-            _ => None,
-        });
-        if let Some(intrinsic) = panic_intrinsic {
-            use PanicIntrinsic::*;
-            let ty = instance.unwrap().substs.type_at(0);
-            let layout = bx.layout_of(ty);
-            let do_panic = match intrinsic {
-                IfUninhabited => layout.abi.is_uninhabited(),
-                // We unwrap as the error type is `!`.
-                IfZeroInvalid => !layout.might_permit_raw_init(&bx, /*zero:*/ true).unwrap(),
-                // We unwrap as the error type is `!`.
-                IfAnyInvalid => !layout.might_permit_raw_init(&bx, /*zero:*/ false).unwrap(),
-            };
-            if do_panic {
-                let msg_str = if layout.abi.is_uninhabited() {
-                    // Use this error even for the other intrinsics as it is more precise.
-                    format!("attempted to instantiate uninhabited type `{}`", ty)
-                } else if intrinsic == IfZeroInvalid {
-                    format!("attempted to zero-initialize type `{}`, which is invalid", ty)
-                } else {
-                    format!("attempted to leave type `{}` uninitialized, which is invalid", ty)
-                };
-                let msg = bx.const_str(Symbol::intern(&msg_str));
-                let location = self.get_caller_location(&mut bx, span).immediate();
-
-                // Obtain the panic entry point.
-                // FIXME: dedup this with `codegen_assert_terminator` above.
-                let def_id =
-                    common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem);
-                let instance = ty::Instance::mono(bx.tcx(), def_id);
-                let fn_abi = FnAbi::of_instance(&bx, instance, &[]);
-                let llfn = bx.get_fn_addr(instance);
-
-                if let Some((_, target)) = destination.as_ref() {
-                    helper.maybe_sideeffect(self.mir, &mut bx, &[*target]);
-                }
-                // Codegen the actual panic invoke/call.
-                helper.do_call(
-                    self,
-                    &mut bx,
-                    fn_abi,
-                    llfn,
-                    &[msg.0, msg.1, location],
-                    destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)),
-                    cleanup,
-                );
-            } else {
-                // a NOP
-                let target = destination.as_ref().unwrap().1;
-                helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
-                helper.funclet_br(self, &mut bx, target)
-            }
+        if self.codegen_panic_intrinsic(
+            &helper,
+            &mut bx,
+            intrinsic,
+            instance,
+            span,
+            destination,
+            cleanup,
+        ) {
             return;
         }
 

From a09c33e36205991bb633a848d1e9c7604ae43ce8 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sat, 29 Feb 2020 09:41:59 +0100
Subject: [PATCH 12/28] move pattern to fn argument

---
 src/librustc_target/abi/mod.rs | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index aa9474233a4ea..d8788611878a0 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -943,8 +943,7 @@ pub trait MaybeResult<T> {
 impl<T> MaybeResult<T> for T {
     type Error = !;
 
-    fn from(x: Result<T, Self::Error>) -> Self {
-        let Ok(x) = x;
+    fn from(Ok(x): Result<T, Self::Error>) -> Self {
         x
     }
     fn to_result(self) -> Result<T, Self::Error> {

From cbf5f7d23c4c0c91580245f36fda3ba1b6a12069 Mon Sep 17 00:00:00 2001
From: Matthew Jasper <mjjasper1@gmail.com>
Date: Sat, 29 Feb 2020 12:28:32 +0000
Subject: [PATCH 13/28] Use TypeRelating for instantiating query responses

---
 .../infer/canonical/query_response.rs         | 85 +++++++++++++++++--
 .../type-annotation-with-hrtb.rs              | 33 +++++++
 2 files changed, 111 insertions(+), 7 deletions(-)
 create mode 100644 src/test/ui/nll/user-annotations/type-annotation-with-hrtb.rs

diff --git a/src/librustc_infer/infer/canonical/query_response.rs b/src/librustc_infer/infer/canonical/query_response.rs
index f4196e576054a..2873618cfadc1 100644
--- a/src/librustc_infer/infer/canonical/query_response.rs
+++ b/src/librustc_infer/infer/canonical/query_response.rs
@@ -12,14 +12,15 @@ use crate::infer::canonical::{
     Canonical, CanonicalVarValues, CanonicalizedQueryResponse, Certainty, OriginalQueryValues,
     QueryOutlivesConstraint, QueryRegionConstraints, QueryResponse,
 };
+use crate::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
 use crate::infer::region_constraints::{Constraint, RegionConstraintData};
-use crate::infer::InferCtxtBuilder;
-use crate::infer::{InferCtxt, InferOk, InferResult};
+use crate::infer::{InferCtxt, InferCtxtBuilder, InferOk, InferResult, NLLRegionVariableOrigin};
 use crate::traits::query::{Fallible, NoSolution};
-use crate::traits::TraitEngine;
+use crate::traits::{DomainGoal, TraitEngine};
 use crate::traits::{Obligation, ObligationCause, PredicateObligation};
 use rustc::arena::ArenaAllocatable;
 use rustc::ty::fold::TypeFoldable;
+use rustc::ty::relate::TypeRelation;
 use rustc::ty::subst::{GenericArg, GenericArgKind};
 use rustc::ty::{self, BoundVar, Ty, TyCtxt};
 use rustc_data_structures::captures::Captures;
@@ -304,13 +305,31 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
                 }
 
                 (GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => {
-                    let ok = self.at(cause, param_env).eq(v1, v2)?;
-                    obligations.extend(ok.into_obligations());
+                    TypeRelating::new(
+                        self,
+                        QueryTypeRelatingDelegate {
+                            infcx: self,
+                            param_env,
+                            cause,
+                            obligations: &mut obligations,
+                        },
+                        ty::Variance::Invariant,
+                    )
+                    .relate(&v1, &v2)?;
                 }
 
                 (GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => {
-                    let ok = self.at(cause, param_env).eq(v1, v2)?;
-                    obligations.extend(ok.into_obligations());
+                    TypeRelating::new(
+                        self,
+                        QueryTypeRelatingDelegate {
+                            infcx: self,
+                            param_env,
+                            cause,
+                            obligations: &mut obligations,
+                        },
+                        ty::Variance::Invariant,
+                    )
+                    .relate(&v1, &v2)?;
                 }
 
                 _ => {
@@ -656,3 +675,55 @@ pub fn make_query_region_constraints<'tcx>(
 
     QueryRegionConstraints { outlives, member_constraints: member_constraints.clone() }
 }
+
+struct QueryTypeRelatingDelegate<'a, 'tcx> {
+    infcx: &'a InferCtxt<'a, 'tcx>,
+    obligations: &'a mut Vec<PredicateObligation<'tcx>>,
+    param_env: ty::ParamEnv<'tcx>,
+    cause: &'a ObligationCause<'tcx>,
+}
+
+impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
+    fn create_next_universe(&mut self) -> ty::UniverseIndex {
+        self.infcx.create_next_universe()
+    }
+
+    fn next_existential_region_var(&mut self, from_forall: bool) -> ty::Region<'tcx> {
+        let origin = NLLRegionVariableOrigin::Existential { from_forall };
+        self.infcx.next_nll_region_var(origin)
+    }
+
+    fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> {
+        self.infcx.tcx.mk_region(ty::RePlaceholder(placeholder))
+    }
+
+    fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
+        self.infcx.next_nll_region_var_in_universe(
+            NLLRegionVariableOrigin::Existential { from_forall: false },
+            universe,
+        )
+    }
+
+    fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
+        self.obligations.push(Obligation {
+            cause: self.cause.clone(),
+            param_env: self.param_env,
+            predicate: ty::Predicate::RegionOutlives(ty::Binder::dummy(ty::OutlivesPredicate(
+                sup, sub,
+            ))),
+            recursion_depth: 0,
+        });
+    }
+
+    fn push_domain_goal(&mut self, _: DomainGoal<'tcx>) {
+        bug!("should never be invoked with eager normalization")
+    }
+
+    fn normalization() -> NormalizationStrategy {
+        NormalizationStrategy::Eager
+    }
+
+    fn forbid_inference_vars() -> bool {
+        true
+    }
+}
diff --git a/src/test/ui/nll/user-annotations/type-annotation-with-hrtb.rs b/src/test/ui/nll/user-annotations/type-annotation-with-hrtb.rs
new file mode 100644
index 0000000000000..1f7c060386bd0
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/type-annotation-with-hrtb.rs
@@ -0,0 +1,33 @@
+// Regression test for issue #69490
+
+// check-pass
+
+pub trait Trait<T> {
+    const S: &'static str;
+}
+
+impl<T> Trait<()> for T
+where
+    T: for<'a> Trait<&'a ()>,
+{
+    // Use of `T::S` here caused an ICE
+    const S: &'static str = T::S;
+}
+
+// Some similar cases that didn't ICE:
+
+impl<'a, T> Trait<()> for (T,)
+where
+    T: Trait<&'a ()>,
+{
+    const S: &'static str = T::S;
+}
+
+impl<T> Trait<()> for [T; 1]
+where
+    T: Trait<for<'a> fn(&'a ())>,
+{
+    const S: &'static str = T::S;
+}
+
+fn main() {}

From 011fa9107f405149d006a4208ffb8503214e82ce Mon Sep 17 00:00:00 2001
From: Dodo <kasper199914@gmail.com>
Date: Mon, 2 Mar 2020 21:05:14 +0100
Subject: [PATCH 14/28] const forget tests

---
 src/libcore/tests/lib.rs |  1 +
 src/libcore/tests/mem.rs | 18 ++++++++++++++++++
 2 files changed, 19 insertions(+)

diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs
index 991458db5b72b..cc341c939803e 100644
--- a/src/libcore/tests/lib.rs
+++ b/src/libcore/tests/lib.rs
@@ -40,6 +40,7 @@
 #![feature(never_type)]
 #![feature(unwrap_infallible)]
 #![feature(leading_trailing_ones)]
+#![feature(const_forget)]
 
 extern crate test;
 
diff --git a/src/libcore/tests/mem.rs b/src/libcore/tests/mem.rs
index 59588d97787b7..4841be5fc7107 100644
--- a/src/libcore/tests/mem.rs
+++ b/src/libcore/tests/mem.rs
@@ -129,3 +129,21 @@ fn test_discriminant_send_sync() {
     is_send_sync::<Discriminant<Regular>>();
     is_send_sync::<Discriminant<NotSendSync>>();
 }
+
+#[test]
+fn test_const_forget() {
+    const fn test_const_forget<T>(x: T) {
+        forget(x);
+    }
+
+    // Writing this function signature without const-forget
+    // triggers compiler errors:
+    // 1) That we use a non-const fn inside a const fn
+    // 2) without the forget, it complains about the destructor of Box
+    const fn const_forget_box<T>(mut x: Box<T>) {
+        forget(x);
+    }
+
+    const _: () = test_const_forget(0i32);
+    const _: () = test_const_forget(Vec::<Vec<Box<i32>>>::new());
+}
\ No newline at end of file

From 5f4af546d4fd19dd1238aaf2fd1026237b39916f Mon Sep 17 00:00:00 2001
From: Dodo <kasper199914@gmail.com>
Date: Mon, 2 Mar 2020 21:40:35 +0100
Subject: [PATCH 15/28] An enter as last character pleases tidy it seems

---
 src/libcore/tests/mem.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libcore/tests/mem.rs b/src/libcore/tests/mem.rs
index 4841be5fc7107..9ed2323e2873e 100644
--- a/src/libcore/tests/mem.rs
+++ b/src/libcore/tests/mem.rs
@@ -146,4 +146,4 @@ fn test_const_forget() {
 
     const _: () = test_const_forget(0i32);
     const _: () = test_const_forget(Vec::<Vec<Box<i32>>>::new());
-}
\ No newline at end of file
+}

From a674e1c88c632c237d7e56fbb6972b46c39a1fb0 Mon Sep 17 00:00:00 2001
From: Dodo <kasper199914@gmail.com>
Date: Mon, 2 Mar 2020 23:43:50 +0100
Subject: [PATCH 16/28] remove unused mut, restructure the test

---
 src/libcore/tests/mem.rs | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/libcore/tests/mem.rs b/src/libcore/tests/mem.rs
index 9ed2323e2873e..8337ab103419f 100644
--- a/src/libcore/tests/mem.rs
+++ b/src/libcore/tests/mem.rs
@@ -132,18 +132,18 @@ fn test_discriminant_send_sync() {
 
 #[test]
 fn test_const_forget() {
-    const fn test_const_forget<T>(x: T) {
-        forget(x);
-    }
+    const _: () = forget(0i32);
+    const _: () = forget(Vec::<Vec<Box<i32>>>::new());
 
     // Writing this function signature without const-forget
     // triggers compiler errors:
     // 1) That we use a non-const fn inside a const fn
     // 2) without the forget, it complains about the destructor of Box
-    const fn const_forget_box<T>(mut x: Box<T>) {
+    const fn const_forget_box<T>(x: Box<T>) {
         forget(x);
     }
 
-    const _: () = test_const_forget(0i32);
-    const _: () = test_const_forget(Vec::<Vec<Box<i32>>>::new());
+    // Call the forget_box at runtime,
+    // as we can't const-construct a box yet.
+    const_forget_box(Box::new(0i32));
 }

From 6d03bbd480ef9bef09321fbfdc00229a03091b11 Mon Sep 17 00:00:00 2001
From: Bastian Kauschke <bastian_kauschke@hotmail.de>
Date: Sun, 8 Mar 2020 14:24:32 +0100
Subject: [PATCH 17/28] constify `mem::discriminant`

---
 src/libcore/intrinsics.rs                |  1 +
 src/libcore/lib.rs                       |  1 +
 src/libcore/mem/mod.rs                   |  3 ++-
 src/librustc_mir/interpret/intrinsics.rs |  5 +++++
 src/librustc_span/symbol.rs              |  1 +
 src/test/ui/consts/const_discriminant.rs | 22 ++++++++++++++++++++++
 6 files changed, 32 insertions(+), 1 deletion(-)
 create mode 100644 src/test/ui/consts/const_discriminant.rs

diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index a889eff75c044..63c5d782e6566 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -1852,6 +1852,7 @@ extern "rust-intrinsic" {
     ///
     /// The stabilized version of this intrinsic is
     /// [`std::mem::discriminant`](../../std/mem/fn.discriminant.html)
+    #[rustc_const_unstable(feature = "const_discriminant", issue = "69821")]
     pub fn discriminant_value<T>(v: &T) -> u64;
 
     /// Rust's "try catch" construct which invokes the function pointer `f` with
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 41fb4a77c7ae8..cac61c2c674ad 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -72,6 +72,7 @@
 #![feature(concat_idents)]
 #![feature(const_ascii_ctype_on_intrinsics)]
 #![feature(const_alloc_layout)]
+#![feature(const_discriminant)]
 #![feature(const_if_match)]
 #![feature(const_loop)]
 #![feature(const_checked_int_methods)]
diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs
index 90144d11dc9d1..c23d0adab5c0d 100644
--- a/src/libcore/mem/mod.rs
+++ b/src/libcore/mem/mod.rs
@@ -864,6 +864,7 @@ impl<T> fmt::Debug for Discriminant<T> {
 /// assert_ne!(mem::discriminant(&Foo::B(3)), mem::discriminant(&Foo::C(3)));
 /// ```
 #[stable(feature = "discriminant_value", since = "1.21.0")]
-pub fn discriminant<T>(v: &T) -> Discriminant<T> {
+#[rustc_const_unstable(feature = "const_discriminant", issue = "69821")]
+pub const fn discriminant<T>(v: &T) -> Discriminant<T> {
     Discriminant(intrinsics::discriminant_value(v), PhantomData)
 }
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index 891afbf437f2b..1e5ed76c467b4 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -216,6 +216,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 };
                 self.write_scalar(val, dest)?;
             }
+            sym::discriminant_value => {
+                let place = self.deref_operand(args[0])?;
+                let discr_val = self.read_discriminant(place.into())?.0;
+                self.write_scalar(Scalar::from_uint(discr_val, dest.layout.size), dest)?;
+            }
             sym::unchecked_shl
             | sym::unchecked_shr
             | sym::unchecked_add
diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs
index c39f9f360c027..0d37e9c2c7b08 100644
--- a/src/librustc_span/symbol.rs
+++ b/src/librustc_span/symbol.rs
@@ -265,6 +265,7 @@ symbols! {
         derive,
         diagnostic,
         direct,
+        discriminant_value,
         doc,
         doc_alias,
         doc_cfg,
diff --git a/src/test/ui/consts/const_discriminant.rs b/src/test/ui/consts/const_discriminant.rs
new file mode 100644
index 0000000000000..5a32ff2915849
--- /dev/null
+++ b/src/test/ui/consts/const_discriminant.rs
@@ -0,0 +1,22 @@
+// run-pass
+#![feature(const_discriminant)]
+
+use std::mem::{discriminant, Discriminant};
+
+enum Test {
+    A(u8),
+    B,
+    C { a: u8, b: u8 },
+}
+
+const TEST_A: Discriminant<Test> = discriminant(&Test::A(5));
+const TEST_A_OTHER: Discriminant<Test> = discriminant(&Test::A(17));
+const TEST_B: Discriminant<Test> = discriminant(&Test::B);
+
+fn main() {
+    assert_eq!(TEST_A, TEST_A_OTHER);
+    assert_eq!(TEST_A, discriminant(&Test::A(17)));
+    assert_eq!(TEST_B, discriminant(&Test::B));
+    assert_ne!(TEST_A, TEST_B);
+    assert_ne!(TEST_B, discriminant(&Test::C { a: 42, b: 7 }));
+}

From 22f2385a738827fb682bc72bb9e1d794bb436672 Mon Sep 17 00:00:00 2001
From: Bastian Kauschke <bastian_kauschke@hotmail.de>
Date: Sun, 8 Mar 2020 15:12:46 +0100
Subject: [PATCH 18/28] prevent potential promotion in const_discriminant

---
 src/test/ui/consts/const_discriminant.rs | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/src/test/ui/consts/const_discriminant.rs b/src/test/ui/consts/const_discriminant.rs
index 5a32ff2915849..564434bb6fa36 100644
--- a/src/test/ui/consts/const_discriminant.rs
+++ b/src/test/ui/consts/const_discriminant.rs
@@ -3,6 +3,8 @@
 
 use std::mem::{discriminant, Discriminant};
 
+fn identity<T>(x: T) -> T { x }
+
 enum Test {
     A(u8),
     B,
@@ -15,8 +17,8 @@ const TEST_B: Discriminant<Test> = discriminant(&Test::B);
 
 fn main() {
     assert_eq!(TEST_A, TEST_A_OTHER);
-    assert_eq!(TEST_A, discriminant(&Test::A(17)));
-    assert_eq!(TEST_B, discriminant(&Test::B));
+    assert_eq!(TEST_A, discriminant(identity(&Test::A(17))));
+    assert_eq!(TEST_B, discriminant(identity(&Test::B)));
     assert_ne!(TEST_A, TEST_B);
-    assert_ne!(TEST_B, discriminant(&Test::C { a: 42, b: 7 }));
+    assert_ne!(TEST_B, discriminant(identity(&Test::C { a: 42, b: 7 })));
 }

From 6bbb9b86c4d4be72a92676e2d51dcc8032e1fe3e Mon Sep 17 00:00:00 2001
From: Bastian Kauschke <bastian_kauschke@hotmail.de>
Date: Sun, 8 Mar 2020 17:04:02 +0100
Subject: [PATCH 19/28] test discriminant of enum with uninhabited variant

---
 src/test/ui/consts/const_discriminant.rs | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/src/test/ui/consts/const_discriminant.rs b/src/test/ui/consts/const_discriminant.rs
index 564434bb6fa36..9aac3c4532f47 100644
--- a/src/test/ui/consts/const_discriminant.rs
+++ b/src/test/ui/consts/const_discriminant.rs
@@ -15,10 +15,21 @@ const TEST_A: Discriminant<Test> = discriminant(&Test::A(5));
 const TEST_A_OTHER: Discriminant<Test> = discriminant(&Test::A(17));
 const TEST_B: Discriminant<Test> = discriminant(&Test::B);
 
+enum Void {}
+
+enum SingleVariant {
+    V,
+    Never(Void),
+}
+
+const TEST_V: Discriminant<SingleVariant> = discriminant(&SingleVariant::V);
+
 fn main() {
     assert_eq!(TEST_A, TEST_A_OTHER);
     assert_eq!(TEST_A, discriminant(identity(&Test::A(17))));
     assert_eq!(TEST_B, discriminant(identity(&Test::B)));
     assert_ne!(TEST_A, TEST_B);
     assert_ne!(TEST_B, discriminant(identity(&Test::C { a: 42, b: 7 })));
+
+    assert_eq!(TEST_V, discriminant(identity(&SingleVariant::V)));
 }

From 4b724e82d2b1065eea10a96fafb19e1390edf0d7 Mon Sep 17 00:00:00 2001
From: Bastian Kauschke <bastian_kauschke@hotmail.de>
Date: Sun, 8 Mar 2020 18:56:15 +0100
Subject: [PATCH 20/28] allow dead code in discriminant test

---
 src/test/ui/consts/const_discriminant.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/test/ui/consts/const_discriminant.rs b/src/test/ui/consts/const_discriminant.rs
index 9aac3c4532f47..c67be3c3713f5 100644
--- a/src/test/ui/consts/const_discriminant.rs
+++ b/src/test/ui/consts/const_discriminant.rs
@@ -1,5 +1,6 @@
 // run-pass
 #![feature(const_discriminant)]
+#![allow(dead_code)]
 
 use std::mem::{discriminant, Discriminant};
 

From 314da73797ede5da3ed658208aa31d6aab9cfbf0 Mon Sep 17 00:00:00 2001
From: Bastian Kauschke <bastian_kauschke@hotmail.de>
Date: Mon, 9 Mar 2020 10:12:44 +0100
Subject: [PATCH 21/28] discrimant test must not be inlined!

---
 src/test/ui/consts/const_discriminant.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/test/ui/consts/const_discriminant.rs b/src/test/ui/consts/const_discriminant.rs
index c67be3c3713f5..55e2918c85f93 100644
--- a/src/test/ui/consts/const_discriminant.rs
+++ b/src/test/ui/consts/const_discriminant.rs
@@ -4,6 +4,7 @@
 
 use std::mem::{discriminant, Discriminant};
 
+#[inline(never)]
 fn identity<T>(x: T) -> T { x }
 
 enum Test {

From 906bb8d0e8bbd026fc933fe3f5b829be5e4ac69e Mon Sep 17 00:00:00 2001
From: YI <uuuuuu@protonmail.com>
Date: Tue, 10 Mar 2020 01:51:08 +0800
Subject: [PATCH 22/28] fix #62456

---
 src/librustc_typeck/check/expr.rs              | 18 +++++++++++++-----
 .../ui/const-generics/issues/issue-62456.rs    |  9 +++++++++
 .../const-generics/issues/issue-62456.stderr   | 16 ++++++++++++++++
 3 files changed, 38 insertions(+), 5 deletions(-)
 create mode 100644 src/test/ui/const-generics/issues/issue-62456.rs
 create mode 100644 src/test/ui/const-generics/issues/issue-62456.stderr

diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index 7570d9d4b28ac..859a219c95a21 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -18,6 +18,7 @@ use crate::type_error_struct;
 use crate::util::common::ErrorReported;
 
 use rustc::middle::lang_items;
+use rustc::mir::interpret::ErrorHandled;
 use rustc::ty;
 use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
 use rustc::ty::Ty;
@@ -1039,11 +1040,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         if element_ty.references_error() {
-            tcx.types.err
-        } else if let Ok(count) = count {
-            tcx.mk_ty(ty::Array(t, count))
-        } else {
-            tcx.types.err
+            return tcx.types.err;
+        }
+        match count {
+            Ok(count) => tcx.mk_ty(ty::Array(t, count)),
+            Err(ErrorHandled::TooGeneric) => {
+                self.tcx.sess.span_err(
+                    tcx.def_span(count_def_id),
+                    "array lengths can't depend on generic parameters",
+                );
+                tcx.types.err
+            }
+            Err(ErrorHandled::Reported) => tcx.types.err,
         }
     }
 
diff --git a/src/test/ui/const-generics/issues/issue-62456.rs b/src/test/ui/const-generics/issues/issue-62456.rs
new file mode 100644
index 0000000000000..c5e6fe9104bc9
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-62456.rs
@@ -0,0 +1,9 @@
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+fn foo<const N: usize>() {
+    let _ = [0u64; N + 1];
+    //~^ ERROR array lengths can't depend on generic parameters
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-62456.stderr b/src/test/ui/const-generics/issues/issue-62456.stderr
new file mode 100644
index 0000000000000..9cdccf8407c9b
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-62456.stderr
@@ -0,0 +1,16 @@
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+  --> $DIR/issue-62456.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: array lengths can't depend on generic parameters
+  --> $DIR/issue-62456.rs:5:20
+   |
+LL |     let _ = [0u64; N + 1];
+   |                    ^^^^^
+
+error: aborting due to previous error
+

From 0a0c850d732666b1205a6f567c38e05239c65848 Mon Sep 17 00:00:00 2001
From: YI <uuuuuu@protonmail.com>
Date: Tue, 10 Mar 2020 10:54:48 +0800
Subject: [PATCH 23/28] fix test failure due to earlier emitted error

---
 .../ui/issues/issue-69602-type-err-during-codegen-ice.rs  | 1 +
 .../issues/issue-69602-type-err-during-codegen-ice.stderr | 8 +++++++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs
index 2c5257ce063cb..d060f26fb2a08 100644
--- a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs
+++ b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs
@@ -19,4 +19,5 @@ impl TraitB for B { //~ ERROR not all trait items implemented, missing: `MyA`
 
 fn main() {
     let _ = [0; B::VALUE];
+    //~^ ERROR array lengths can't depend on generic parameters
 }
diff --git a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr
index 8ae0f8b804c93..c6b2b4d27a208 100644
--- a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr
+++ b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr
@@ -13,7 +13,13 @@ LL |     type MyA: TraitA;
 LL | impl TraitB for B {
    | ^^^^^^^^^^^^^^^^^ missing `MyA` in implementation
 
-error: aborting due to 2 previous errors
+error: array lengths can't depend on generic parameters
+  --> $DIR/issue-69602-type-err-during-codegen-ice.rs:21:17
+   |
+LL |     let _ = [0; B::VALUE];
+   |                 ^^^^^^^^
+
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0046, E0437.
 For more information about an error, try `rustc --explain E0046`.

From 9263cbbcc8bb503e6abd93f111401b2f63f6a67d Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Tue, 10 Mar 2020 10:10:10 +0100
Subject: [PATCH 24/28] VariantSizeDifferences: bail on SizeOverflow

---
 src/librustc_lint/types.rs                               | 6 ++----
 src/test/ui/lint/issue-69485-var-size-diffs-too-large.rs | 9 +++++++++
 .../ui/lint/issue-69485-var-size-diffs-too-large.stderr  | 8 ++++++++
 3 files changed, 19 insertions(+), 4 deletions(-)
 create mode 100644 src/test/ui/lint/issue-69485-var-size-diffs-too-large.rs
 create mode 100644 src/test/ui/lint/issue-69485-var-size-diffs-too-large.stderr

diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 86d93612e993b..2896682ea8268 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -998,10 +998,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
             let ty = cx.tcx.erase_regions(&t);
             let layout = match cx.layout_of(ty) {
                 Ok(layout) => layout,
-                Err(ty::layout::LayoutError::Unknown(_)) => return,
-                Err(err @ ty::layout::LayoutError::SizeOverflow(_)) => {
-                    bug!("failed to get layout for `{}`: {}", t, err);
-                }
+                Err(ty::layout::LayoutError::Unknown(_))
+                | Err(ty::layout::LayoutError::SizeOverflow(_)) => return,
             };
             let (variants, tag) = match layout.variants {
                 layout::Variants::Multiple {
diff --git a/src/test/ui/lint/issue-69485-var-size-diffs-too-large.rs b/src/test/ui/lint/issue-69485-var-size-diffs-too-large.rs
new file mode 100644
index 0000000000000..59032ab9775c8
--- /dev/null
+++ b/src/test/ui/lint/issue-69485-var-size-diffs-too-large.rs
@@ -0,0 +1,9 @@
+// build-fail
+
+fn main() {
+    Bug::V([0; !0]); //~ ERROR is too big for the current
+}
+
+enum Bug {
+    V([u8; !0]),
+}
diff --git a/src/test/ui/lint/issue-69485-var-size-diffs-too-large.stderr b/src/test/ui/lint/issue-69485-var-size-diffs-too-large.stderr
new file mode 100644
index 0000000000000..ce9790fc94681
--- /dev/null
+++ b/src/test/ui/lint/issue-69485-var-size-diffs-too-large.stderr
@@ -0,0 +1,8 @@
+error: the type `[u8; 18446744073709551615]` is too big for the current architecture
+  --> $DIR/issue-69485-var-size-diffs-too-large.rs:4:12
+   |
+LL |     Bug::V([0; !0]);
+   |            ^^^^^^^
+
+error: aborting due to previous error
+

From 7b3e3ff39aa45103a6f8432466f8078970866142 Mon Sep 17 00:00:00 2001
From: Bastian Kauschke <bastian_kauschke@hotmail.de>
Date: Tue, 10 Mar 2020 12:46:22 +0100
Subject: [PATCH 25/28] explain the use of a custom identity function

---
 src/test/ui/consts/const_discriminant.rs | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/test/ui/consts/const_discriminant.rs b/src/test/ui/consts/const_discriminant.rs
index 55e2918c85f93..1ad5134e71c52 100644
--- a/src/test/ui/consts/const_discriminant.rs
+++ b/src/test/ui/consts/const_discriminant.rs
@@ -4,6 +4,9 @@
 
 use std::mem::{discriminant, Discriminant};
 
+// `discriminant(const_expr)` may get const-propagated.
+// As we want to check that const-eval is equal to ordinary exection,
+// we wrap `const_expr` with a function which is not const to prevent this.
 #[inline(never)]
 fn identity<T>(x: T) -> T { x }
 

From 4d16c217b8074784b1faad07f5a284e4a6999b53 Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Tue, 10 Mar 2020 16:20:47 +0100
Subject: [PATCH 26/28] Matrix::push: recursively expand or-patterns

---
 src/librustc_mir_build/hair/pattern/_match.rs |  6 ++++-
 ...ve-been-expanded-earlier-non-exhaustive.rs |  9 +++++++
 ...een-expanded-earlier-non-exhaustive.stderr | 25 +++++++++++++++++++
 ...69875-should-have-been-expanded-earlier.rs |  9 +++++++
 4 files changed, 48 insertions(+), 1 deletion(-)
 create mode 100644 src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs
 create mode 100644 src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr
 create mode 100644 src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier.rs

diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs
index 71aefa85c99fd..37ad5f5ea4e38 100644
--- a/src/librustc_mir_build/hair/pattern/_match.rs
+++ b/src/librustc_mir_build/hair/pattern/_match.rs
@@ -480,7 +480,11 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
     /// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it.
     crate fn push(&mut self, row: PatStack<'p, 'tcx>) {
         if let Some(rows) = row.expand_or_pat() {
-            self.0.extend(rows);
+            for row in rows {
+                // We recursively expand the or-patterns of the new rows.
+                // This is necessary as we might have `0 | (1 | 2)` or e.g., `x @ 0 | x @ (1 | 2)`.
+                self.push(row)
+            }
         } else {
             self.0.push(row);
         }
diff --git a/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs
new file mode 100644
index 0000000000000..59533cefea64c
--- /dev/null
+++ b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs
@@ -0,0 +1,9 @@
+#![feature(or_patterns)]
+
+fn main() {
+    let 0 | (1 | 2) = 0; //~ ERROR refutable pattern in local binding
+    match 0 {
+        //~^ ERROR non-exhaustive patterns
+        0 | (1 | 2) => {}
+    }
+}
diff --git a/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr
new file mode 100644
index 0000000000000..58286e87869a4
--- /dev/null
+++ b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr
@@ -0,0 +1,25 @@
+error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `3i32..=std::i32::MAX` not covered
+  --> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:4:9
+   |
+LL |     let 0 | (1 | 2) = 0;
+   |         ^^^^^^^^^^^ patterns `std::i32::MIN..=-1i32` and `3i32..=std::i32::MAX` not covered
+   |
+   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+help: you might want to use `if let` to ignore the variant that isn't matched
+   |
+LL |     if let 0 | (1 | 2) = 0 { /* */ }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0004]: non-exhaustive patterns: `std::i32::MIN..=-1i32` and `3i32..=std::i32::MAX` not covered
+  --> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:5:11
+   |
+LL |     match 0 {
+   |           ^ patterns `std::i32::MIN..=-1i32` and `3i32..=std::i32::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0004, E0005.
+For more information about an error, try `rustc --explain E0004`.
diff --git a/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier.rs b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier.rs
new file mode 100644
index 0000000000000..1de563dedbf18
--- /dev/null
+++ b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier.rs
@@ -0,0 +1,9 @@
+// check-pass
+
+#![feature(or_patterns)]
+
+fn main() {
+    let 0 | (1 | _) = 0;
+    if let 0 | (1 | 2) = 0 {}
+    if let x @ 0 | x @ (1 | 2) = 0 {}
+}

From 69aaed872cec119b1034c52151d00fb5308e7407 Mon Sep 17 00:00:00 2001
From: Florian Gilcher <florian.gilcher@asquera.de>
Date: Fri, 6 Mar 2020 10:37:23 +0100
Subject: [PATCH 27/28] Make Point `Copy` in arithmetic documentation

Small composite types like `Point { x: i32, y: i32}` are plain
old data and we should encourage users to derive `Copy` on them.

This changes the semantics of the edited examples slightly: instead
of consuming the operands during addition, it will copy them. This
is desired behaviour.

Co-Authored-By: Jake Goulding <shepmaster@mac.com>
---
 src/libcore/ops/arith.rs | 10 +++++-----
 src/libcore/ops/mod.rs   |  2 +-
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/libcore/ops/arith.rs b/src/libcore/ops/arith.rs
index 59a72799e2567..e9ec81394e32d 100644
--- a/src/libcore/ops/arith.rs
+++ b/src/libcore/ops/arith.rs
@@ -13,7 +13,7 @@
 /// ```
 /// use std::ops::Add;
 ///
-/// #[derive(Debug, PartialEq)]
+/// #[derive(Debug, Copy, Clone, PartialEq)]
 /// struct Point {
 ///     x: i32,
 ///     y: i32,
@@ -42,7 +42,7 @@
 /// ```
 /// use std::ops::Add;
 ///
-/// #[derive(Debug, PartialEq)]
+/// #[derive(Debug, Copy, Clone, PartialEq)]
 /// struct Point<T> {
 ///     x: T,
 ///     y: T,
@@ -115,7 +115,7 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
 /// ```
 /// use std::ops::Sub;
 ///
-/// #[derive(Debug, PartialEq)]
+/// #[derive(Debug, Copy, Clone, PartialEq)]
 /// struct Point {
 ///     x: i32,
 ///     y: i32,
@@ -657,7 +657,7 @@ neg_impl_numeric! { isize i8 i16 i32 i64 i128 f32 f64 }
 /// ```
 /// use std::ops::AddAssign;
 ///
-/// #[derive(Debug, PartialEq)]
+/// #[derive(Debug, Copy, Clone, PartialEq)]
 /// struct Point {
 ///     x: i32,
 ///     y: i32,
@@ -715,7 +715,7 @@ add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
 /// ```
 /// use std::ops::SubAssign;
 ///
-/// #[derive(Debug, PartialEq)]
+/// #[derive(Debug, Copy, Clone, PartialEq)]
 /// struct Point {
 ///     x: i32,
 ///     y: i32,
diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs
index 77b92b6ccbdaa..e3e5934b44be1 100644
--- a/src/libcore/ops/mod.rs
+++ b/src/libcore/ops/mod.rs
@@ -42,7 +42,7 @@
 //! ```rust
 //! use std::ops::{Add, Sub};
 //!
-//! #[derive(Debug, PartialEq)]
+//! #[derive(Debug, Copy, Clone, PartialEq)]
 //! struct Point {
 //!     x: i32,
 //!     y: i32,

From 6b27e8d2a631183babfb25c5aac008b263ba4978 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Tue, 10 Mar 2020 21:02:15 +0300
Subject: [PATCH 28/28] parse: Tweak the function parameter edition check

Move anon-params tests to ui/anon-params.
---
 src/librustc_parse/parser/item.rs                    |  4 +---
 .../ui/{ => anon-params}/anon-params-denied-2018.rs  |  0
 .../{ => anon-params}/anon-params-denied-2018.stderr |  0
 .../{ => anon-params}/anon-params-deprecated.fixed   |  0
 .../ui/{ => anon-params}/anon-params-deprecated.rs   |  0
 .../{ => anon-params}/anon-params-deprecated.stderr  |  0
 .../ui/anon-params/anon-params-edition-hygiene.rs    | 10 ++++++++++
 .../auxiliary/anon-params-edition-hygiene.rs         | 12 ++++++++++++
 8 files changed, 23 insertions(+), 3 deletions(-)
 rename src/test/ui/{ => anon-params}/anon-params-denied-2018.rs (100%)
 rename src/test/ui/{ => anon-params}/anon-params-denied-2018.stderr (100%)
 rename src/test/ui/{ => anon-params}/anon-params-deprecated.fixed (100%)
 rename src/test/ui/{ => anon-params}/anon-params-deprecated.rs (100%)
 rename src/test/ui/{ => anon-params}/anon-params-deprecated.stderr (100%)
 create mode 100644 src/test/ui/anon-params/anon-params-edition-hygiene.rs
 create mode 100644 src/test/ui/anon-params/auxiliary/anon-params-edition-hygiene.rs

diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index 126686c8defbf..a9c4de04c0a2e 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -1544,9 +1544,7 @@ impl<'a> Parser<'a> {
 
         let is_name_required = match self.token.kind {
             token::DotDotDot => false,
-            // FIXME: Consider using interpolated token for this edition check,
-            // it should match the intent of edition hygiene better.
-            _ => req_name(self.token.uninterpolate().span.edition()),
+            _ => req_name(self.token.span.edition()),
         };
         let (pat, ty) = if is_name_required || self.is_named_param() {
             debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
diff --git a/src/test/ui/anon-params-denied-2018.rs b/src/test/ui/anon-params/anon-params-denied-2018.rs
similarity index 100%
rename from src/test/ui/anon-params-denied-2018.rs
rename to src/test/ui/anon-params/anon-params-denied-2018.rs
diff --git a/src/test/ui/anon-params-denied-2018.stderr b/src/test/ui/anon-params/anon-params-denied-2018.stderr
similarity index 100%
rename from src/test/ui/anon-params-denied-2018.stderr
rename to src/test/ui/anon-params/anon-params-denied-2018.stderr
diff --git a/src/test/ui/anon-params-deprecated.fixed b/src/test/ui/anon-params/anon-params-deprecated.fixed
similarity index 100%
rename from src/test/ui/anon-params-deprecated.fixed
rename to src/test/ui/anon-params/anon-params-deprecated.fixed
diff --git a/src/test/ui/anon-params-deprecated.rs b/src/test/ui/anon-params/anon-params-deprecated.rs
similarity index 100%
rename from src/test/ui/anon-params-deprecated.rs
rename to src/test/ui/anon-params/anon-params-deprecated.rs
diff --git a/src/test/ui/anon-params-deprecated.stderr b/src/test/ui/anon-params/anon-params-deprecated.stderr
similarity index 100%
rename from src/test/ui/anon-params-deprecated.stderr
rename to src/test/ui/anon-params/anon-params-deprecated.stderr
diff --git a/src/test/ui/anon-params/anon-params-edition-hygiene.rs b/src/test/ui/anon-params/anon-params-edition-hygiene.rs
new file mode 100644
index 0000000000000..14e11c5696f4a
--- /dev/null
+++ b/src/test/ui/anon-params/anon-params-edition-hygiene.rs
@@ -0,0 +1,10 @@
+// check-pass
+// edition:2018
+// aux-build:anon-params-edition-hygiene.rs
+
+#[macro_use]
+extern crate anon_params_edition_hygiene;
+
+generate_trait_2015!(u8);
+
+fn main() {}
diff --git a/src/test/ui/anon-params/auxiliary/anon-params-edition-hygiene.rs b/src/test/ui/anon-params/auxiliary/anon-params-edition-hygiene.rs
new file mode 100644
index 0000000000000..aa4221becc24f
--- /dev/null
+++ b/src/test/ui/anon-params/auxiliary/anon-params-edition-hygiene.rs
@@ -0,0 +1,12 @@
+// edition:2015
+
+#[macro_export]
+macro_rules! generate_trait_2015 {
+    ($Type: ident) => {
+        trait Trait {
+            fn method($Type) {}
+        }
+    };
+}
+
+fn main() {}