diff --git a/src/ci/scripts/install-msys2.sh b/src/ci/scripts/install-msys2.sh
index 3a78ef209e4e5..9e899ba9d8947 100755
--- a/src/ci/scripts/install-msys2.sh
+++ b/src/ci/scripts/install-msys2.sh
@@ -12,10 +12,14 @@ IFS=$'\n\t'
 source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
 
 if isWindows; then
-    for RETRY_COUNT in 1 2 3 4 5 6 7 8 9 10; do
-        choco install msys2 \
-            --params="/InstallDir:$(ciCheckoutPath)/msys2 /NoPath" -y --no-progress \
-            && mkdir -p "$(ciCheckoutPath)/msys2/home/${USERNAME}" \
-            && ciCommandAddPath "$(ciCheckoutPath)/msys2/usr/bin" && break
-    done
+    # Pre-followed the api/v2 URL to the CDN since the API can be a bit flakey
+    curl -sSL https://packages.chocolatey.org/msys2.20190524.0.0.20191030.nupkg > \
+        msys2.nupkg
+    curl -sSL https://packages.chocolatey.org/chocolatey-core.extension.1.3.5.1.nupkg > \
+        chocolatey-core.extension.nupkg
+    choco install -s . msys2 \
+        --params="/InstallDir:$(ciCheckoutPath)/msys2 /NoPath" -y --no-progress
+    rm msys2.nupkg chocolatey-core.extension.nupkg
+    mkdir -p "$(ciCheckoutPath)/msys2/home/${USERNAME}"
+    ciCommandAddPath "$(ciCheckoutPath)/msys2/usr/bin"
 fi
diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs
index bb6d6db57d214..fe5d16862a6a6 100644
--- a/src/libcore/char/methods.rs
+++ b/src/libcore/char/methods.rs
@@ -434,36 +434,35 @@ impl char {
     #[inline]
     pub fn encode_utf8(self, dst: &mut [u8]) -> &mut str {
         let code = self as u32;
-        // SAFETY: each arm checks the size of the slice and only uses `get_unchecked` unsafe ops
-        unsafe {
-            let len = if code < MAX_ONE_B && !dst.is_empty() {
-                *dst.get_unchecked_mut(0) = code as u8;
-                1
-            } else if code < MAX_TWO_B && dst.len() >= 2 {
-                *dst.get_unchecked_mut(0) = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
-                *dst.get_unchecked_mut(1) = (code & 0x3F) as u8 | TAG_CONT;
-                2
-            } else if code < MAX_THREE_B && dst.len() >= 3 {
-                *dst.get_unchecked_mut(0) = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
-                *dst.get_unchecked_mut(1) = (code >> 6 & 0x3F) as u8 | TAG_CONT;
-                *dst.get_unchecked_mut(2) = (code & 0x3F) as u8 | TAG_CONT;
-                3
-            } else if dst.len() >= 4 {
-                *dst.get_unchecked_mut(0) = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
-                *dst.get_unchecked_mut(1) = (code >> 12 & 0x3F) as u8 | TAG_CONT;
-                *dst.get_unchecked_mut(2) = (code >> 6 & 0x3F) as u8 | TAG_CONT;
-                *dst.get_unchecked_mut(3) = (code & 0x3F) as u8 | TAG_CONT;
-                4
-            } else {
-                panic!(
-                    "encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}",
-                    from_u32_unchecked(code).len_utf8(),
-                    code,
-                    dst.len(),
-                )
-            };
-            from_utf8_unchecked_mut(dst.get_unchecked_mut(..len))
-        }
+        let len = self.len_utf8();
+        match (len, &mut dst[..]) {
+            (1, [a, ..]) => {
+                *a = code as u8;
+            }
+            (2, [a, b, ..]) => {
+                *a = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
+                *b = (code & 0x3F) as u8 | TAG_CONT;
+            }
+            (3, [a, b, c, ..]) => {
+                *a = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
+                *b = (code >> 6 & 0x3F) as u8 | TAG_CONT;
+                *c = (code & 0x3F) as u8 | TAG_CONT;
+            }
+            (4, [a, b, c, d, ..]) => {
+                *a = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
+                *b = (code >> 12 & 0x3F) as u8 | TAG_CONT;
+                *c = (code >> 6 & 0x3F) as u8 | TAG_CONT;
+                *d = (code & 0x3F) as u8 | TAG_CONT;
+            }
+            _ => panic!(
+                "encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}",
+                len,
+                code,
+                dst.len(),
+            ),
+        };
+        // SAFETY: We just wrote UTF-8 content in, so converting to str is fine.
+        unsafe { from_utf8_unchecked_mut(&mut dst[..len]) }
     }
 
     /// Encodes this character as UTF-16 into the provided `u16` buffer,
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index d12aebb87b975..7d11dd2800fd4 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -129,6 +129,7 @@
 #![feature(associated_type_bounds)]
 #![feature(const_type_id)]
 #![feature(const_caller_location)]
+#![feature(slice_patterns)]
 
 #[prelude_import]
 #[allow(unused)]
diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index 843880200f3d7..51f0818fe0be1 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -432,6 +432,7 @@ pub enum UnsupportedOpInfo<'tcx> {
     HeapAllocNonPowerOfTwoAlignment(u64),
     ReadFromReturnPointer,
     PathNotFound(Vec<String>),
+    TransmuteSizeDiff(Ty<'tcx>, Ty<'tcx>),
 }
 
 impl fmt::Debug for UnsupportedOpInfo<'tcx> {
@@ -460,6 +461,11 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> {
                            passing data of type {:?}",
                 callee_ty, caller_ty
             ),
+            TransmuteSizeDiff(from_ty, to_ty) => write!(
+                f,
+                "tried to transmute from {:?} to {:?}, but their sizes differed",
+                from_ty, to_ty
+            ),
             FunctionRetMismatch(caller_ty, callee_ty) => write!(
                 f,
                 "tried to call a function with return type {:?} \
diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs
index 49b542af0a034..93f167cdb9e54 100644
--- a/src/librustc/mir/interpret/value.rs
+++ b/src/librustc/mir/interpret/value.rs
@@ -367,8 +367,9 @@ impl<'tcx, Tag> Scalar<Tag> {
     }
 
     /// Do not call this method!  Use either `assert_ptr` or `force_ptr`.
+    /// This method is intentionally private, do not make it public.
     #[inline]
-    pub fn to_ptr(self) -> InterpResult<'tcx, Pointer<Tag>> {
+    fn to_ptr(self) -> InterpResult<'tcx, Pointer<Tag>> {
         match self {
             Scalar::Raw { data: 0, .. } => throw_unsup!(InvalidNullPointerUsage),
             Scalar::Raw { .. } => throw_unsup!(ReadBytesAsPointer),
@@ -544,12 +545,6 @@ impl<'tcx, Tag> ScalarMaybeUndef<Tag> {
         }
     }
 
-    /// Do not call this method!  Use either `assert_ptr` or `force_ptr`.
-    #[inline(always)]
-    pub fn to_ptr(self) -> InterpResult<'tcx, Pointer<Tag>> {
-        self.not_undef()?.to_ptr()
-    }
-
     /// Do not call this method!  Use either `assert_bits` or `force_bits`.
     #[inline(always)]
     pub fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> {
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 2ac2d789b2d34..42db64c791518 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -2373,7 +2373,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         let span = self.tcx.def_span(generator_did);
 
         // Do not ICE on closure typeck (#66868).
-        if let None = self.tcx.hir().as_local_hir_id(generator_did) {
+        if self.tcx.hir().as_local_hir_id(generator_did).is_none() {
             return false;
         }
 
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index 933358dce018b..120f05ba7d974 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -537,8 +537,8 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
                         Ok(ConstValue::Scalar(a_val))
                     } else if let ty::FnPtr(_) = a.ty.kind {
                         let alloc_map = tcx.alloc_map.lock();
-                        let a_instance = alloc_map.unwrap_fn(a_val.to_ptr().unwrap().alloc_id);
-                        let b_instance = alloc_map.unwrap_fn(b_val.to_ptr().unwrap().alloc_id);
+                        let a_instance = alloc_map.unwrap_fn(a_val.assert_ptr().alloc_id);
+                        let b_instance = alloc_map.unwrap_fn(b_val.assert_ptr().alloc_id);
                         if a_instance == b_instance {
                             Ok(ConstValue::Scalar(a_val))
                         } else {
diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs
index 9c1bec39b29e2..fbcc976bd491e 100644
--- a/src/librustc_error_codes/error_codes.rs
+++ b/src/librustc_error_codes/error_codes.rs
@@ -346,6 +346,7 @@ E0622: include_str!("./error_codes/E0622.md"),
 E0623: include_str!("./error_codes/E0623.md"),
 E0624: include_str!("./error_codes/E0624.md"),
 E0626: include_str!("./error_codes/E0626.md"),
+E0627: include_str!("./error_codes/E0627.md"),
 E0631: include_str!("./error_codes/E0631.md"),
 E0633: include_str!("./error_codes/E0633.md"),
 E0635: include_str!("./error_codes/E0635.md"),
@@ -574,7 +575,6 @@ E0745: include_str!("./error_codes/E0745.md"),
 //  E0612, // merged into E0609
 //  E0613, // Removed (merged with E0609)
     E0625, // thread-local statics cannot be accessed at compile-time
-    E0627, // yield statement outside of generator literal
     E0628, // generators cannot have explicit parameters
     E0629, // missing 'feature' (rustc_const_unstable)
     // rustc_const_unstable attribute must be paired with stable/unstable
diff --git a/src/librustc_error_codes/error_codes/E0124.md b/src/librustc_error_codes/error_codes/E0124.md
index a7836526a7dd4..8af7cb819cfaf 100644
--- a/src/librustc_error_codes/error_codes/E0124.md
+++ b/src/librustc_error_codes/error_codes/E0124.md
@@ -1,5 +1,6 @@
-You declared two fields of a struct with the same name. Erroneous code
-example:
+A struct was declared with two fields having the same name.
+
+Erroneous code example:
 
 ```compile_fail,E0124
 struct Foo {
diff --git a/src/librustc_error_codes/error_codes/E0128.md b/src/librustc_error_codes/error_codes/E0128.md
index d0a4b32f9688e..6f8dfe3a73b9e 100644
--- a/src/librustc_error_codes/error_codes/E0128.md
+++ b/src/librustc_error_codes/error_codes/E0128.md
@@ -1,4 +1,5 @@
-Type parameter defaults can only use parameters that occur before them.
+A type parameter with default value is using forward declared identifier.
+
 Erroneous code example:
 
 ```compile_fail,E0128
@@ -7,11 +8,11 @@ struct Foo<T = U, U = ()> {
     field2: U,
 }
 // error: type parameters with a default cannot use forward declared
-// identifiers
+//        identifiers
 ```
 
-Since type parameters are evaluated in-order, you may be able to fix this issue
-by doing:
+Type parameter defaults can only use parameters that occur before them. Since
+type parameters are evaluated in-order, this issue could be fixed by doing:
 
 ```
 struct Foo<U = (), T = U> {
diff --git a/src/librustc_error_codes/error_codes/E0627.md b/src/librustc_error_codes/error_codes/E0627.md
new file mode 100644
index 0000000000000..21358e1e567dc
--- /dev/null
+++ b/src/librustc_error_codes/error_codes/E0627.md
@@ -0,0 +1,30 @@
+A yield expression was used outside of the generator literal.
+
+Erroneous code example:
+
+```compile_fail,E0627
+#![feature(generators, generator_trait)]
+
+fn fake_generator() -> &'static str {
+    yield 1;
+    return "foo"
+}
+
+fn main() {
+    let mut generator = fake_generator;
+}
+```
+
+The error occurs because keyword `yield` can only be used inside the generator
+literal. This can be fixed by constructing the generator correctly.
+
+```
+#![feature(generators, generator_trait)]
+
+fn main() {
+    let mut generator = || {
+        yield 1;
+        return "foo"
+    };
+}
+```
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 4a6379e3bc155..0d136bd7d9cf9 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -1424,7 +1424,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     }
 
     /// Reports an error if this is a borrow of local data.
-    /// This is called for all Yield statements on movable generators
+    /// This is called for all Yield expressions on movable generators
     fn check_for_local_borrow(&mut self, borrow: &BorrowData<'tcx>, yield_span: Span) {
         debug!("check_for_local_borrow({:?})", borrow);
 
diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs
index ea541bd93bc94..23b4799643a6c 100644
--- a/src/librustc_mir/borrow_check/path_utils.rs
+++ b/src/librustc_mir/borrow_check/path_utils.rs
@@ -131,7 +131,7 @@ pub(super) fn is_active<'tcx>(
 }
 
 /// Determines if a given borrow is borrowing local data
-/// This is called for all Yield statements on movable generators
+/// This is called for all Yield expressions on movable generators
 pub(super) fn borrow_of_local_data(place: &Place<'_>) -> bool {
     match place.base {
         PlaceBase::Static(_) => false,
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index a2f066bee08d1..2afa39c3cad8b 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -85,7 +85,7 @@ fn op_to_const<'tcx>(
     };
     let val = match immediate {
         Ok(mplace) => {
-            let ptr = mplace.ptr.to_ptr().unwrap();
+            let ptr = mplace.ptr.assert_ptr();
             let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
             ConstValue::ByRef { alloc, offset: ptr.offset }
         },
@@ -99,7 +99,7 @@ fn op_to_const<'tcx>(
                 // comes from a constant so it can happen have `Undef`, because the indirect
                 // memory that was read had undefined bytes.
                 let mplace = op.assert_mem_place();
-                let ptr = mplace.ptr.to_ptr().unwrap();
+                let ptr = mplace.ptr.assert_ptr();
                 let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
                 ConstValue::ByRef { alloc, offset: ptr.offset }
             },
@@ -626,7 +626,7 @@ fn validate_and_turn_into_const<'tcx>(
         // whether they become immediates.
         let def_id = cid.instance.def.def_id();
         if tcx.is_static(def_id) || cid.promoted.is_some() {
-            let ptr = mplace.ptr.to_ptr()?;
+            let ptr = mplace.ptr.assert_ptr();
             Ok(tcx.mk_const(ty::Const {
                 val: ty::ConstKind::Value(ConstValue::ByRef {
                     alloc: ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id),
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index f267be812c3d2..c6efbe8833279 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -252,6 +252,7 @@ use syntax_pos::{Span, DUMMY_SP};
 use arena::TypedArena;
 
 use smallvec::{smallvec, SmallVec};
+use std::borrow::Cow;
 use std::cmp::{self, max, min, Ordering};
 use std::convert::TryInto;
 use std::fmt;
@@ -260,11 +261,12 @@ use std::ops::RangeInclusive;
 use std::u128;
 
 pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pat<'tcx>) -> Pat<'tcx> {
-    LiteralExpander { tcx: cx.tcx }.fold_pattern(&pat)
+    LiteralExpander { tcx: cx.tcx, param_env: cx.param_env }.fold_pattern(&pat)
 }
 
 struct LiteralExpander<'tcx> {
     tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
 }
 
 impl LiteralExpander<'tcx> {
@@ -284,9 +286,23 @@ impl LiteralExpander<'tcx> {
         debug!("fold_const_value_deref {:?} {:?} {:?}", val, rty, crty);
         match (val, &crty.kind, &rty.kind) {
             // the easy case, deref a reference
-            (ConstValue::Scalar(Scalar::Ptr(p)), x, y) if x == y => {
-                let alloc = self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id);
-                ConstValue::ByRef { alloc, offset: p.offset }
+            (ConstValue::Scalar(p), x, y) if x == y => {
+                match p {
+                    Scalar::Ptr(p) => {
+                        let alloc = self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id);
+                        ConstValue::ByRef { alloc, offset: p.offset }
+                    }
+                    Scalar::Raw { .. } => {
+                        let layout = self.tcx.layout_of(self.param_env.and(rty)).unwrap();
+                        if layout.is_zst() {
+                            // Deref of a reference to a ZST is a nop.
+                            ConstValue::Scalar(Scalar::zst())
+                        } else {
+                            // FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;`
+                            bug!("cannot deref {:#?}, {} -> {}", val, crty, rty);
+                        }
+                    }
+                }
             }
             // unsize array to slice if pattern is array but match value or other patterns are slice
             (ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => {
@@ -2348,16 +2364,30 @@ fn specialize_one_pattern<'p, 'tcx>(
             // just integers. The only time they should be pointing to memory
             // is when they are subslices of nonzero slices.
             let (alloc, offset, n, ty) = match value.ty.kind {
-                ty::Array(t, n) => match value.val {
-                    ty::ConstKind::Value(ConstValue::ByRef { offset, alloc, .. }) => {
-                        (alloc, offset, n.eval_usize(cx.tcx, cx.param_env), t)
+                ty::Array(t, n) => {
+                    let n = n.eval_usize(cx.tcx, cx.param_env);
+                    // Shortcut for `n == 0` where no matter what `alloc` and `offset` we produce,
+                    // the result would be exactly what we early return here.
+                    if n == 0 {
+                        if ctor_wild_subpatterns.len() as u64 == 0 {
+                            return Some(PatStack::from_slice(&[]));
+                        } else {
+                            return None;
+                        }
                     }
-                    _ => span_bug!(pat.span, "array pattern is {:?}", value,),
-                },
+                    match value.val {
+                        ty::ConstKind::Value(ConstValue::ByRef { offset, alloc, .. }) => {
+                            (Cow::Borrowed(alloc), offset, n, t)
+                        }
+                        _ => span_bug!(pat.span, "array pattern is {:?}", value,),
+                    }
+                }
                 ty::Slice(t) => {
                     match value.val {
                         ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => {
-                            (data, Size::from_bytes(start as u64), (end - start) as u64, t)
+                            let offset = Size::from_bytes(start as u64);
+                            let n = (end - start) as u64;
+                            (Cow::Borrowed(data), offset, n, t)
                         }
                         ty::ConstKind::Value(ConstValue::ByRef { .. }) => {
                             // FIXME(oli-obk): implement `deref` for `ConstValue`
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 869aeeba418da..a68ee3308bc23 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -993,6 +993,12 @@ pub fn compare_const_vals<'tcx>(
         return fallback();
     }
 
+    // Early return for equal constants (so e.g. references to ZSTs can be compared, even if they
+    // are just integer addresses).
+    if a.val == b.val {
+        return from_bool(true);
+    }
+
     let a_bits = a.try_eval_bits(tcx, param_env, ty);
     let b_bits = b.try_eval_bits(tcx, param_env, ty);
 
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index ad2af8d7aca52..766ef6ab6feac 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -20,8 +20,8 @@ use rustc_macros::HashStable;
 use syntax::source_map::{self, Span, DUMMY_SP};
 
 use super::{
-    Immediate, MPlaceTy, Machine, MemPlace, Memory, Operand, Place, PlaceTy, ScalarMaybeUndef,
-    StackPopInfo,
+    Immediate, MPlaceTy, Machine, MemPlace, Memory, OpTy, Operand, Place, PlaceTy,
+    ScalarMaybeUndef, StackPopInfo,
 };
 
 pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
@@ -118,7 +118,7 @@ pub struct LocalState<'tcx, Tag = (), Id = AllocId> {
 }
 
 /// Current value of a local variable
-#[derive(Clone, PartialEq, Eq, Debug, HashStable)] // Miri debug-prints these
+#[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable)] // Miri debug-prints these
 pub enum LocalValue<Tag = (), Id = AllocId> {
     /// This local is not currently alive, and cannot be used at all.
     Dead,
@@ -743,7 +743,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // FIXME: should we tell the user that there was a local which was never written to?
         if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local {
             trace!("deallocating local");
-            let ptr = ptr.to_ptr()?;
+            // All locals have a backing allocation, even if the allocation is empty
+            // due to the local having ZST type.
+            let ptr = ptr.assert_ptr();
             if log_enabled!(::log::Level::Trace) {
                 self.memory.dump_alloc(ptr.alloc_id);
             }
@@ -752,13 +754,33 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         Ok(())
     }
 
+    pub(super) fn const_eval(
+        &self,
+        gid: GlobalId<'tcx>,
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+        let val = if self.tcx.is_static(gid.instance.def_id()) {
+            self.tcx.const_eval_poly(gid.instance.def_id())?
+        } else if let Some(promoted) = gid.promoted {
+            self.tcx.const_eval_promoted(gid.instance, promoted)?
+        } else {
+            self.tcx.const_eval_instance(self.param_env, gid.instance, Some(self.tcx.span))?
+        };
+        // Even though `ecx.const_eval` is called from `eval_const_to_op` we can never have a
+        // recursion deeper than one level, because the `tcx.const_eval` above is guaranteed to not
+        // return `ConstValue::Unevaluated`, which is the only way that `eval_const_to_op` will call
+        // `ecx.const_eval`.
+        self.eval_const_to_op(val, None)
+    }
+
     pub fn const_eval_raw(
         &self,
         gid: GlobalId<'tcx>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
-        // FIXME(oli-obk): make this check an assertion that it's not a static here
-        // FIXME(RalfJ, oli-obk): document that `Place::Static` can never be anything but a static
-        // and `ConstValue::Unevaluated` can never be a static
+        // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics
+        // and thus don't care about the parameter environment. While we could just use
+        // `self.param_env`, that would mean we invoke the query to evaluate the static
+        // with different parameter environments, thus causing the static to be evaluated
+        // multiple times.
         let param_env = if self.tcx.is_static(gid.instance.def_id()) {
             ty::ParamEnv::reveal_all()
         } else {
diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs
index c99f39977fe2e..9dbe685813ef2 100644
--- a/src/librustc_mir/interpret/intern.rs
+++ b/src/librustc_mir/interpret/intern.rs
@@ -188,14 +188,21 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx
         if let ty::Ref(_, referenced_ty, mutability) = ty.kind {
             let value = self.ecx.read_immediate(mplace.into())?;
             let mplace = self.ecx.ref_to_mplace(value)?;
-            // Handle trait object vtables
+            // Handle trait object vtables.
             if let ty::Dynamic(..) =
                 self.ecx.tcx.struct_tail_erasing_lifetimes(referenced_ty, self.ecx.param_env).kind
             {
-                if let Ok(vtable) = mplace.meta.unwrap().to_ptr() {
-                    // explitly choose `Immutable` here, since vtables are immutable, even
-                    // if the reference of the fat pointer is mutable
+                // Validation has already errored on an invalid vtable pointer so we can safely not
+                // do anything if this is not a real pointer.
+                if let Scalar::Ptr(vtable) = mplace.meta.unwrap() {
+                    // Explicitly choose `Immutable` here, since vtables are immutable, even
+                    // if the reference of the fat pointer is mutable.
                     self.intern_shallow(vtable.alloc_id, Mutability::Not, None)?;
+                } else {
+                    self.ecx().tcx.sess.delay_span_bug(
+                        syntax_pos::DUMMY_SP,
+                        "vtables pointers cannot be integer pointers",
+                    );
                 }
             }
             // Check if we have encountered this pointer+layout combination before.
@@ -281,7 +288,9 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
         ecx,
         leftover_allocations,
         base_intern_mode,
-        ret.ptr.to_ptr()?.alloc_id,
+        // The outermost allocation must exist, because we allocated it with
+        // `Memory::allocate`.
+        ret.ptr.assert_ptr().alloc_id,
         base_mutability,
         Some(ret.layout.ty),
     )?;
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index 8e4dc87451c32..da7cff97ee2c2 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -5,7 +5,7 @@
 use rustc::hir::def_id::DefId;
 use rustc::mir::{
     self,
-    interpret::{ConstValue, InterpResult, Scalar},
+    interpret::{ConstValue, GlobalId, InterpResult, Scalar},
     BinOp,
 };
 use rustc::ty;
@@ -118,9 +118,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             | sym::size_of
             | sym::type_id
             | sym::type_name => {
-                let val =
-                    self.tcx.const_eval_instance(self.param_env, instance, Some(self.tcx.span))?;
-                let val = self.eval_const_to_op(val, None)?;
+                let gid = GlobalId { instance, promoted: None };
+                let val = self.const_eval(gid)?;
                 self.copy_op(val, dest)?;
             }
 
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index a89abe71c654f..def979b63b52a 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -578,7 +578,15 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             ty::ConstKind::Param(_) => throw_inval!(TooGeneric),
             ty::ConstKind::Unevaluated(def_id, substs) => {
                 let instance = self.resolve(def_id, substs)?;
-                return Ok(OpTy::from(self.const_eval_raw(GlobalId { instance, promoted: None })?));
+                // We use `const_eval` here and `const_eval_raw` elsewhere in mir interpretation.
+                // The reason we use `const_eval_raw` everywhere else is to prevent cycles during
+                // validation, because validation automatically reads through any references, thus
+                // potentially requiring the current static to be evaluated again. This is not a
+                // problem here, because we are building an operand which means an actual read is
+                // happening.
+                // FIXME(oli-obk): eliminate all the `const_eval_raw` usages when we get rid of
+                // `StaticKind` once and for all.
+                return self.const_eval(GlobalId { instance, promoted: None });
             }
             ty::ConstKind::Infer(..)
             | ty::ConstKind::Bound(..)
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 1141239e49a53..2c39799cb935a 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -942,8 +942,14 @@ where
             return self.copy_op(src, dest);
         }
         // We still require the sizes to match.
-        assert!(src.layout.size == dest.layout.size,
-            "Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest);
+        if src.layout.size != dest.layout.size {
+            // FIXME: This should be an assert instead of an error, but if we transmute within an
+            // array length computation, `typeck` may not have yet been run and errored out. In fact
+            // most likey we *are* running `typeck` right now. Investigate whether we can bail out
+            // on `typeck_tables().has_errors` at all const eval entry points.
+            debug!("Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest);
+            throw_unsup!(TransmuteSizeDiff(src.layout.ty, dest.layout.ty));
+        }
         // Unsized copies rely on interpreting `src.meta` with `dest.layout`, we want
         // to avoid that here.
         assert!(!src.layout.is_unsized() && !dest.layout.is_unsized(),
@@ -987,30 +993,20 @@ where
         let (mplace, size) = match place.place {
             Place::Local { frame, local } => {
                 match self.stack[frame].locals[local].access_mut()? {
-                    Ok(local_val) => {
+                    Ok(&mut local_val) => {
                         // We need to make an allocation.
-                        // FIXME: Consider not doing anything for a ZST, and just returning
-                        // a fake pointer?  Are we even called for ZST?
-
-                        // We cannot hold on to the reference `local_val` while allocating,
-                        // but we can hold on to the value in there.
-                        let old_val =
-                            if let LocalValue::Live(Operand::Immediate(value)) = *local_val {
-                                Some(value)
-                            } else {
-                                None
-                            };
 
                         // We need the layout of the local.  We can NOT use the layout we got,
                         // that might e.g., be an inner field of a struct with `Scalar` layout,
                         // that has different alignment than the outer field.
-                        // We also need to support unsized types, and hence cannot use `allocate`.
                         let local_layout = self.layout_of_local(&self.stack[frame], local, None)?;
+
+                        // We also need to support unsized types, and hence cannot use `allocate`.
                         let (size, align) = self.size_and_align_of(meta, local_layout)?
                             .expect("Cannot allocate for non-dyn-sized type");
                         let ptr = self.memory.allocate(size, align, MemoryKind::Stack);
                         let mplace = MemPlace { ptr: ptr.into(), align, meta };
-                        if let Some(value) = old_val {
+                        if let LocalValue::Live(Operand::Immediate(value)) = local_val {
                             // Preserve old value.
                             // We don't have to validate as we can assume the local
                             // was already valid for its type.
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index 5c602ad76cd32..e862971c9e2b3 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -1810,7 +1810,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     self.tcx.sess,
                     expr.span,
                     E0627,
-                    "yield statement outside of generator literal"
+                    "yield expression outside of generator literal"
                 )
                 .emit();
             }
diff --git a/src/libstd/error.rs b/src/libstd/error.rs
index 18ebd0f1a6755..0992e40121a7b 100644
--- a/src/libstd/error.rs
+++ b/src/libstd/error.rs
@@ -91,10 +91,6 @@ pub trait Error: Debug + Display {
     /// }
     ///
     /// impl Error for SuperError {
-    ///     fn description(&self) -> &str {
-    ///         "I'm the superhero of errors"
-    ///     }
-    ///
     ///     fn cause(&self) -> Option<&dyn Error> {
     ///         Some(&self.side)
     ///     }
@@ -109,11 +105,7 @@ pub trait Error: Debug + Display {
     ///     }
     /// }
     ///
-    /// impl Error for SuperErrorSideKick {
-    ///     fn description(&self) -> &str {
-    ///         "I'm SuperError side kick"
-    ///     }
-    /// }
+    /// impl Error for SuperErrorSideKick {}
     ///
     /// fn get_super_error() -> Result<(), SuperError> {
     ///     Err(SuperError { side: SuperErrorSideKick })
@@ -159,10 +151,6 @@ pub trait Error: Debug + Display {
     /// }
     ///
     /// impl Error for SuperError {
-    ///     fn description(&self) -> &str {
-    ///         "I'm the superhero of errors"
-    ///     }
-    ///
     ///     fn source(&self) -> Option<&(dyn Error + 'static)> {
     ///         Some(&self.side)
     ///     }
@@ -177,11 +165,7 @@ pub trait Error: Debug + Display {
     ///     }
     /// }
     ///
-    /// impl Error for SuperErrorSideKick {
-    ///     fn description(&self) -> &str {
-    ///         "I'm SuperError side kick"
-    ///     }
-    /// }
+    /// impl Error for SuperErrorSideKick {}
     ///
     /// fn get_super_error() -> Result<(), SuperError> {
     ///     Err(SuperError { side: SuperErrorSideKick })
@@ -261,11 +245,7 @@ impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> {
     ///     }
     /// }
     ///
-    /// impl Error for AnError {
-    ///     fn description(&self) -> &str {
-    ///         "Description of an error"
-    ///     }
-    /// }
+    /// impl Error for AnError {}
     ///
     /// let an_error = AnError;
     /// assert!(0 == mem::size_of_val(&an_error));
@@ -300,11 +280,7 @@ impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync +
     ///     }
     /// }
     ///
-    /// impl Error for AnError {
-    ///     fn description(&self) -> &str {
-    ///         "Description of an error"
-    ///     }
-    /// }
+    /// impl Error for AnError {}
     ///
     /// unsafe impl Send for AnError {}
     ///
diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs
index c20bd3097b27d..efe839d1302fe 100644
--- a/src/libstd/io/error.rs
+++ b/src/libstd/io/error.rs
@@ -402,9 +402,7 @@ impl Error {
     ///     }
     /// }
     ///
-    /// impl error::Error for MyError {
-    ///     fn description(&self) -> &str { &self.v }
-    /// }
+    /// impl error::Error for MyError {}
     ///
     /// impl Display for MyError {
     ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
diff --git a/src/test/ui/const-generics/issues/issue-61747.rs b/src/test/ui/const-generics/issues/issue-61747.rs
new file mode 100644
index 0000000000000..64674bb894e1f
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-61747.rs
@@ -0,0 +1,16 @@
+// check-pass
+
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+struct Const<const N: usize>;
+
+impl<const C: usize> Const<{C}> {
+    fn successor() -> Const<{C + 1}> {
+        Const
+    }
+}
+
+fn main() {
+    let _x: Const::<2> = Const::<1>::successor();
+}
diff --git a/src/test/ui/const-generics/issues/issue-61747.stderr b/src/test/ui/const-generics/issues/issue-61747.stderr
new file mode 100644
index 0000000000000..ccf36a7f805ec
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-61747.stderr
@@ -0,0 +1,8 @@
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+  --> $DIR/issue-61747.rs:3:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
diff --git a/src/test/ui/const-generics/issues/issue-66205.rs b/src/test/ui/const-generics/issues/issue-66205.rs
new file mode 100644
index 0000000000000..2e47b4d1882f2
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-66205.rs
@@ -0,0 +1,10 @@
+// check-pass
+
+#![allow(incomplete_features, dead_code, unconditional_recursion)]
+#![feature(const_generics)]
+
+fn fact<const N: usize>() {
+    fact::<{ N - 1 }>();
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/consts-in-patterns.rs b/src/test/ui/consts/consts-in-patterns.rs
index ac6c5a5150688..ee1e3cc22f77d 100644
--- a/src/test/ui/consts/consts-in-patterns.rs
+++ b/src/test/ui/consts/consts-in-patterns.rs
@@ -1,7 +1,10 @@
 // run-pass
+#![feature(const_transmute)]
 
 const FOO: isize = 10;
 const BAR: isize = 3;
+const ZST: &() = unsafe { std::mem::transmute(1usize) };
+const ZST_ARR: &[u8; 0] = unsafe { std::mem::transmute(1usize) };
 
 const fn foo() -> isize { 4 }
 const BOO: isize = foo();
@@ -15,4 +18,14 @@ pub fn main() {
         _ => 3
     };
     assert_eq!(y, 2);
+    let z = match &() {
+        ZST => 9,
+        // FIXME: this should not be required
+        _ => 42,
+    };
+    assert_eq!(z, 9);
+    let z = match b"" {
+        ZST_ARR => 10,
+    };
+    assert_eq!(z, 10);
 }
diff --git a/src/test/ui/consts/recursive-zst-static.rs b/src/test/ui/consts/recursive-zst-static.rs
new file mode 100644
index 0000000000000..df7562bd9f5d2
--- /dev/null
+++ b/src/test/ui/consts/recursive-zst-static.rs
@@ -0,0 +1,7 @@
+// build-pass
+
+static FOO: () = FOO;
+
+fn main() {
+    FOO
+}
diff --git a/src/test/ui/consts/transmute-size-mismatch-before-typeck.rs b/src/test/ui/consts/transmute-size-mismatch-before-typeck.rs
new file mode 100644
index 0000000000000..1235dd8dcbd98
--- /dev/null
+++ b/src/test/ui/consts/transmute-size-mismatch-before-typeck.rs
@@ -0,0 +1,15 @@
+#![feature(const_transmute)]
+
+fn main() {
+    match &b""[..] {
+        ZST => {}
+        //~^ ERROR could not evaluate constant pattern
+    }
+}
+
+const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
+//~^ ERROR any use of this value will cause an error
+//~| ERROR cannot transmute between types of different sizes
+
+// Once the `any use of this value will cause an error` disappears in this test, make sure to
+// remove the `TransmuteSizeDiff` error variant and make its emitter site an assertion again.
diff --git a/src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr b/src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr
new file mode 100644
index 0000000000000..74de5dc9aaf82
--- /dev/null
+++ b/src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr
@@ -0,0 +1,28 @@
+error: any use of this value will cause an error
+  --> $DIR/transmute-size-mismatch-before-typeck.rs:10:29
+   |
+LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
+   | ----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                             |
+   |                             tried to transmute from usize to &[u8], but their sizes differed
+   |
+   = note: `#[deny(const_err)]` on by default
+
+error: could not evaluate constant pattern
+  --> $DIR/transmute-size-mismatch-before-typeck.rs:5:9
+   |
+LL |         ZST => {}
+   |         ^^^
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute-size-mismatch-before-typeck.rs:10:29
+   |
+LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
+   |                             ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `usize` (64 bits)
+   = note: target type: `&'static [u8]` (128 bits)
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0512`.
diff --git a/src/test/ui/feature-gates/feature-gate-generators.rs b/src/test/ui/feature-gates/feature-gate-generators.rs
index 382d891feed84..931fee1347126 100644
--- a/src/test/ui/feature-gates/feature-gate-generators.rs
+++ b/src/test/ui/feature-gates/feature-gate-generators.rs
@@ -1,6 +1,6 @@
 fn main() {
     yield true; //~ ERROR yield syntax is experimental
-                //~^ ERROR yield statement outside of generator literal
+                //~^ ERROR yield expression outside of generator literal
 }
 
 #[cfg(FALSE)]
diff --git a/src/test/ui/feature-gates/feature-gate-generators.stderr b/src/test/ui/feature-gates/feature-gate-generators.stderr
index 24b814b410c9d..4adc21efc6a21 100644
--- a/src/test/ui/feature-gates/feature-gate-generators.stderr
+++ b/src/test/ui/feature-gates/feature-gate-generators.stderr
@@ -25,7 +25,7 @@ LL |     yield 0;
    = note: for more information, see https://github.com/rust-lang/rust/issues/43122
    = help: add `#![feature(generators)]` to the crate attributes to enable
 
-error[E0627]: yield statement outside of generator literal
+error[E0627]: yield expression outside of generator literal
   --> $DIR/feature-gate-generators.rs:2:5
    |
 LL |     yield true;
@@ -33,4 +33,5 @@ LL |     yield true;
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
+Some errors have detailed explanations: E0627, E0658.
+For more information about an error, try `rustc --explain E0627`.
diff --git a/src/test/ui/generator/yield-in-const.rs b/src/test/ui/generator/yield-in-const.rs
index f6f11b9cb13dd..fe5ca822ceca1 100644
--- a/src/test/ui/generator/yield-in-const.rs
+++ b/src/test/ui/generator/yield-in-const.rs
@@ -1,6 +1,6 @@
 #![feature(generators)]
 
 const A: u8 = { yield 3u8; 3u8};
-//~^ ERROR yield statement outside
+//~^ ERROR yield expression outside
 
 fn main() {}
diff --git a/src/test/ui/generator/yield-in-const.stderr b/src/test/ui/generator/yield-in-const.stderr
index 663bb70d7a07f..dcf4fe63e64bc 100644
--- a/src/test/ui/generator/yield-in-const.stderr
+++ b/src/test/ui/generator/yield-in-const.stderr
@@ -1,4 +1,4 @@
-error[E0627]: yield statement outside of generator literal
+error[E0627]: yield expression outside of generator literal
   --> $DIR/yield-in-const.rs:3:17
    |
 LL | const A: u8 = { yield 3u8; 3u8};
@@ -6,3 +6,4 @@ LL | const A: u8 = { yield 3u8; 3u8};
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0627`.
diff --git a/src/test/ui/generator/yield-in-function.rs b/src/test/ui/generator/yield-in-function.rs
index b737d3b224035..29b811621de1e 100644
--- a/src/test/ui/generator/yield-in-function.rs
+++ b/src/test/ui/generator/yield-in-function.rs
@@ -1,4 +1,4 @@
 #![feature(generators)]
 
 fn main() { yield; }
-//~^ ERROR yield statement outside
+//~^ ERROR yield expression outside
diff --git a/src/test/ui/generator/yield-in-function.stderr b/src/test/ui/generator/yield-in-function.stderr
index e12b0e6843e41..51cce198ca3b4 100644
--- a/src/test/ui/generator/yield-in-function.stderr
+++ b/src/test/ui/generator/yield-in-function.stderr
@@ -1,4 +1,4 @@
-error[E0627]: yield statement outside of generator literal
+error[E0627]: yield expression outside of generator literal
   --> $DIR/yield-in-function.rs:3:13
    |
 LL | fn main() { yield; }
@@ -6,3 +6,4 @@ LL | fn main() { yield; }
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0627`.
diff --git a/src/test/ui/generator/yield-in-static.rs b/src/test/ui/generator/yield-in-static.rs
index 12c9ccea4cb78..d27fbb33ba10a 100644
--- a/src/test/ui/generator/yield-in-static.rs
+++ b/src/test/ui/generator/yield-in-static.rs
@@ -1,6 +1,6 @@
 #![feature(generators)]
 
 static B: u8 = { yield 3u8; 3u8};
-//~^ ERROR yield statement outside
+//~^ ERROR yield expression outside
 
 fn main() {}
diff --git a/src/test/ui/generator/yield-in-static.stderr b/src/test/ui/generator/yield-in-static.stderr
index 220520c3862ca..d867f3ad34528 100644
--- a/src/test/ui/generator/yield-in-static.stderr
+++ b/src/test/ui/generator/yield-in-static.stderr
@@ -1,4 +1,4 @@
-error[E0627]: yield statement outside of generator literal
+error[E0627]: yield expression outside of generator literal
   --> $DIR/yield-in-static.rs:3:18
    |
 LL | static B: u8 = { yield 3u8; 3u8};
@@ -6,3 +6,4 @@ LL | static B: u8 = { yield 3u8; 3u8};
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0627`.
diff --git a/src/test/ui/generic-associated-types/issue-67424.rs b/src/test/ui/generic-associated-types/issue-67424.rs
new file mode 100644
index 0000000000000..9b616b8abc2ee
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-67424.rs
@@ -0,0 +1,13 @@
+// Fixed by #67160
+
+trait Trait1 {
+    type A;
+}
+
+trait Trait2 {
+    type Type1<B>: Trait1<A=B>;
+    //~^ ERROR: generic associated types are unstable
+    //~| ERROR: type-generic associated types are not yet implemented
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-67424.stderr b/src/test/ui/generic-associated-types/issue-67424.stderr
new file mode 100644
index 0000000000000..59ff8ac0a3a70
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-67424.stderr
@@ -0,0 +1,20 @@
+error[E0658]: generic associated types are unstable
+  --> $DIR/issue-67424.rs:8:5
+   |
+LL |     type Type1<B>: Trait1<A=B>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/44265
+   = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
+
+error: type-generic associated types are not yet implemented
+  --> $DIR/issue-67424.rs:8:5
+   |
+LL |     type Type1<B>: Trait1<A=B>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/44265
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.rs b/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.rs
new file mode 100644
index 0000000000000..48a8e04829a0a
--- /dev/null
+++ b/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.rs
@@ -0,0 +1,14 @@
+// Regression test for #66270, fixed by #66246
+
+struct Bug {
+    incorrect_field: 0,
+    //~^ ERROR expected type
+}
+
+struct Empty {}
+
+fn main() {
+    let Bug {
+        any_field: Empty {},
+    } = Bug {};
+}
diff --git a/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.stderr b/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.stderr
new file mode 100644
index 0000000000000..fef0f3c0e06ef
--- /dev/null
+++ b/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.stderr
@@ -0,0 +1,8 @@
+error: expected type, found `0`
+  --> $DIR/issue-66270-pat-struct-parser-recovery.rs:4:22
+   |
+LL |     incorrect_field: 0,
+   |                      ^ expected type
+
+error: aborting due to previous error
+