diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 6b6032516ca73..e665e058e6022 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -1874,15 +1874,16 @@ impl<'a> LoweringContext<'a> {
                         if let Ok(snippet) = self.sess.source_map().span_to_snippet(data.span) {
                             // Do not suggest going from `Trait()` to `Trait<>`
                             if data.inputs.len() > 0 {
-                                let split = snippet.find('(').unwrap();
-                                let trait_name = &snippet[0..split];
-                                let args = &snippet[split + 1 .. snippet.len() - 1];
-                                err.span_suggestion(
-                                    data.span,
-                                    "use angle brackets instead",
-                                    format!("{}<{}>", trait_name, args),
-                                    Applicability::MaybeIncorrect,
-                                );
+                                if let Some(split) = snippet.find('(') {
+                                    let trait_name = &snippet[0..split];
+                                    let args = &snippet[split + 1 .. snippet.len() - 1];
+                                    err.span_suggestion(
+                                        data.span,
+                                        "use angle brackets instead",
+                                        format!("{}<{}>", trait_name, args),
+                                        Applicability::MaybeIncorrect,
+                                    );
+                                }
                             }
                         };
                         err.emit();
diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs
index 9b7bccca2ddf3..3e71b871801d1 100644
--- a/src/librustc_mir/build/matches/simplify.rs
+++ b/src/librustc_mir/build/matches/simplify.rs
@@ -164,7 +164,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         self.hir.tcx().features().exhaustive_patterns &&
                         !v.uninhabited_from(self.hir.tcx(), substs, adt_def.adt_kind()).is_empty()
                     }
-                });
+                }) && (adt_def.did.is_local() || !adt_def.is_variant_list_non_exhaustive());
                 if irrefutable {
                     let place = tcx.mk_place_downcast(match_pair.place, adt_def, variant_index);
                     candidate.match_pairs.extend(self.field_match_pairs(place, subpatterns));
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index e7095101f465d..272369008370a 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -22,7 +22,7 @@ use rustc::ty::subst::InternalSubsts;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_index::vec::IndexVec;
 use rustc::ty::layout::{
-    LayoutOf, TyLayout, LayoutError, HasTyCtxt, TargetDataLayout, HasDataLayout,
+    LayoutOf, TyLayout, LayoutError, HasTyCtxt, TargetDataLayout, HasDataLayout, Size,
 };
 
 use crate::interpret::{
@@ -34,6 +34,9 @@ use crate::interpret::{
 use crate::const_eval::error_to_const_error;
 use crate::transform::{MirPass, MirSource};
 
+/// The maximum number of bytes that we'll allocate space for a return value.
+const MAX_ALLOC_LIMIT: u64 = 1024;
+
 pub struct ConstProp;
 
 impl<'tcx> MirPass<'tcx> for ConstProp {
@@ -434,6 +437,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
     ) -> Option<()> {
         let span = source_info.span;
 
+        // #66397: Don't try to eval into large places as that can cause an OOM
+        if place_layout.size >= Size::from_bytes(MAX_ALLOC_LIMIT) {
+            return None;
+        }
+
         let overflow_check = self.tcx.sess.overflow_checks();
 
         // Perform any special handling for specific Rvalue types.
diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index fde5c5bed4d91..26d37f196befa 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -738,11 +738,7 @@ impl FieldPlacement {
 
     pub fn offset(&self, i: usize) -> Size {
         match *self {
-            FieldPlacement::Union(count) => {
-                assert!(i < count,
-                        "Tried to access field {} of union with {} fields", i, count);
-                Size::ZERO
-            },
+            FieldPlacement::Union(_) => Size::ZERO,
             FieldPlacement::Array { stride, count } => {
                 let i = i as u64;
                 assert!(i < count);
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index aa05a08686a99..e1b540515af41 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1221,16 +1221,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         )
     }
 
-    /// Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by
-    /// removing the dummy `Self` type (`trait_object_dummy_self`).
-    fn trait_ref_to_existential(&self, trait_ref: ty::TraitRef<'tcx>)
-                                -> ty::ExistentialTraitRef<'tcx> {
-        if trait_ref.self_ty() != self.tcx().types.trait_object_dummy_self {
-            bug!("trait_ref_to_existential called on {:?} with non-dummy Self", trait_ref);
-        }
-        ty::ExistentialTraitRef::erase_self_ty(self.tcx(), trait_ref)
-    }
-
     fn conv_object_ty_poly_trait_ref(&self,
         span: Span,
         trait_bounds: &[hir::PolyTraitRef],
@@ -1412,13 +1402,30 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         debug!("regular_traits: {:?}", regular_traits);
         debug!("auto_traits: {:?}", auto_traits);
 
+        // Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by
+        // removing the dummy `Self` type (`trait_object_dummy_self`).
+        let trait_ref_to_existential = |trait_ref: ty::TraitRef<'tcx>| {
+            if trait_ref.self_ty() != dummy_self {
+                // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`,
+                // which picks up non-supertraits where clauses - but also, the object safety
+                // completely ignores trait aliases, which could be object safety hazards. We
+                // `delay_span_bug` here to avoid an ICE in stable even when the feature is
+                // disabled. (#66420)
+                tcx.sess.delay_span_bug(DUMMY_SP, &format!(
+                    "trait_ref_to_existential called on {:?} with non-dummy Self",
+                    trait_ref,
+                ));
+            }
+            ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
+        };
+
         // Erase the `dummy_self` (`trait_object_dummy_self`) used above.
         let existential_trait_refs = regular_traits.iter().map(|i| {
-            i.trait_ref().map_bound(|trait_ref| self.trait_ref_to_existential(trait_ref))
+            i.trait_ref().map_bound(|trait_ref| trait_ref_to_existential(trait_ref))
         });
         let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| {
             bound.map_bound(|b| {
-                let trait_ref = self.trait_ref_to_existential(b.projection_ty.trait_ref(tcx));
+                let trait_ref = trait_ref_to_existential(b.projection_ty.trait_ref(tcx));
                 ty::ExistentialProjection {
                     ty: b.ty,
                     item_def_id: b.projection_ty.item_def_id,
diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs
index ff9c945eec452..6e37c0dbbdf9d 100644
--- a/src/librustc_typeck/check/generator_interior.rs
+++ b/src/librustc_typeck/check/generator_interior.rs
@@ -244,7 +244,13 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
         // can be reborrowed without needing to spill to a temporary.
         // If this were not the case, then we could conceivably have
         // to create intermediate temporaries.)
-        let ty = self.fcx.tables.borrow().expr_ty(expr);
-        self.record(ty, scope, Some(expr), expr.span);
+        //
+        // The type table might not have information for this expression
+        // if it is in a malformed scope. (#66387)
+        if let Some(ty) = self.fcx.tables.borrow().expr_ty_opt(expr) {
+            self.record(ty, scope, Some(expr), expr.span);
+        } else {
+            self.fcx.tcx.sess.delay_span_bug(expr.span, "no type for node");
+        }
     }
 }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index f7132cd868aac..a02d5b5a571c5 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3010,7 +3010,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         fallback_has_occurred: bool,
         mutate_fullfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
     ) {
-        if let Err(mut errors) = self.fulfillment_cx.borrow_mut().select_where_possible(self) {
+        let result = self.fulfillment_cx.borrow_mut().select_where_possible(self);
+        if let Err(mut errors) = result {
             mutate_fullfillment_errors(&mut errors);
             self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred);
         }
diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs
index 84c86c9651fcf..5217f63660795 100644
--- a/src/libsyntax/attr/builtin.rs
+++ b/src/libsyntax/attr/builtin.rs
@@ -655,7 +655,10 @@ fn find_deprecation_generic<'a, I>(sess: &ParseSess,
             break
         }
 
-        let meta = attr.meta().unwrap();
+        let meta = match attr.meta() {
+            Some(meta) => meta,
+            None => continue,
+        };
         depr = match &meta.kind {
             MetaItemKind::Word => Some(Deprecation { since: None, note: None }),
             MetaItemKind::NameValue(..) => {
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index e81d4573b73e5..e6e9d37962af4 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -442,7 +442,9 @@ impl<'a> Parser<'a> {
     crate fn unexpected<T>(&mut self) -> PResult<'a, T> {
         match self.expect_one_of(&[], &[]) {
             Err(e) => Err(e),
-            Ok(_) => unreachable!(),
+            // We can get `Ok(true)` from `recover_closing_delimiter`
+            // which is called in `expected_one_of_not_found`.
+            Ok(_) => FatalError.raise(),
         }
     }
 
diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs
index 37310f46f7eed..3c7f80aa399bf 100644
--- a/src/libsyntax_ext/format.rs
+++ b/src/libsyntax_ext/format.rs
@@ -374,10 +374,12 @@ impl<'a, 'b> Context<'a, 'b> {
                                 format!("are {} arguments", count)
                             },
                         ));
-                        e.span_label(
-                            self.args[pos].span,
-                            "this parameter corresponds to the precision flag",
-                        );
+                        if let Some(arg) = self.args.get(pos) {
+                            e.span_label(
+                                arg.span,
+                                "this parameter corresponds to the precision flag",
+                            );
+                        }
                         zero_based_note = true;
                     }
                     _ => {}
diff --git a/src/test/ui/async-await/issue-66387-if-without-else.rs b/src/test/ui/async-await/issue-66387-if-without-else.rs
new file mode 100644
index 0000000000000..aa5a8db61210d
--- /dev/null
+++ b/src/test/ui/async-await/issue-66387-if-without-else.rs
@@ -0,0 +1,10 @@
+// edition:2018
+async fn f() -> i32 {
+    if true { //~ ERROR if may be missing an else clause
+        return 0;
+    }
+    // An `if` block without `else` causes the type table not to have a type for this expr.
+    // Check that we do not unconditionally access the type table and we don't ICE.
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/issue-66387-if-without-else.stderr b/src/test/ui/async-await/issue-66387-if-without-else.stderr
new file mode 100644
index 0000000000000..32952059525a0
--- /dev/null
+++ b/src/test/ui/async-await/issue-66387-if-without-else.stderr
@@ -0,0 +1,16 @@
+error[E0317]: if may be missing an else clause
+  --> $DIR/issue-66387-if-without-else.rs:3:5
+   |
+LL | /     if true {
+LL | |         return 0;
+LL | |     }
+   | |_____^ expected (), found i32
+   |
+   = note: expected type `()`
+              found type `i32`
+   = note: `if` expressions without `else` evaluate to `()`
+   = help: consider adding an `else` block that evaluates to the expected type
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0317`.
diff --git a/src/test/ui/consts/issue-66342.rs b/src/test/ui/consts/issue-66342.rs
new file mode 100644
index 0000000000000..417f69041658d
--- /dev/null
+++ b/src/test/ui/consts/issue-66342.rs
@@ -0,0 +1,12 @@
+// check-pass
+// only-x86_64
+
+// Checks that the compiler does not actually try to allocate 4 TB during compilation and OOM crash.
+
+fn foo() -> [u8; 4 * 1024 * 1024 * 1024 * 1024] {
+    unimplemented!()
+}
+
+fn main() {
+    foo();
+}
diff --git a/src/test/ui/consts/issue-66397.rs b/src/test/ui/consts/issue-66397.rs
new file mode 100644
index 0000000000000..1b4aff43b5bf1
--- /dev/null
+++ b/src/test/ui/consts/issue-66397.rs
@@ -0,0 +1,8 @@
+// check-pass
+// only-x86_64
+
+// Checks that the compiler does not actually try to allocate 4 TB during compilation and OOM crash.
+
+fn main() {
+    [0; 4 * 1024 * 1024 * 1024 * 1024];
+}
diff --git a/src/test/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs b/src/test/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs
new file mode 100644
index 0000000000000..c0cde75d4caeb
--- /dev/null
+++ b/src/test/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs
@@ -0,0 +1,11 @@
+// The original problem in #66340 was that `find_deprecation_generic`
+// called `attr.meta().unwrap()` under the assumption that the attribute
+// was a well-formed `MetaItem`.
+
+fn main() {
+    foo()
+}
+
+#[deprecated(note = test)]
+//~^ ERROR expected unsuffixed literal or identifier, found `test`
+fn foo() {}
diff --git a/src/test/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr b/src/test/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr
new file mode 100644
index 0000000000000..24178faf8de78
--- /dev/null
+++ b/src/test/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr
@@ -0,0 +1,8 @@
+error: expected unsuffixed literal or identifier, found `test`
+  --> $DIR/issue-66340-deprecated-attr-non-meta-grammar.rs:9:21
+   |
+LL | #[deprecated(note = test)]
+   |                     ^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/if/ifmt-bad-arg.rs b/src/test/ui/if/ifmt-bad-arg.rs
index ba897f171af25..a0b0a8fb98594 100644
--- a/src/test/ui/if/ifmt-bad-arg.rs
+++ b/src/test/ui/if/ifmt-bad-arg.rs
@@ -86,4 +86,9 @@ tenth number: {}",
     println!("{:foo}", 1); //~ ERROR unknown format trait `foo`
     println!("{5} {:4$} {6:7$}", 1);
     //~^ ERROR invalid reference to positional arguments 4, 5, 6 and 7 (there is 1 argument)
+
+    // We used to ICE here because we tried to unconditionally access the first argument, which
+    // doesn't exist.
+    println!("{:.*}");
+    //~^ ERROR 2 positional arguments in format string, but no arguments were given
 }
diff --git a/src/test/ui/if/ifmt-bad-arg.stderr b/src/test/ui/if/ifmt-bad-arg.stderr
index c58cbc312335a..11dcc3a6d232e 100644
--- a/src/test/ui/if/ifmt-bad-arg.stderr
+++ b/src/test/ui/if/ifmt-bad-arg.stderr
@@ -285,6 +285,17 @@ LL |     println!("{5} {:4$} {6:7$}", 1);
    = note: positional arguments are zero-based
    = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
 
+error: 2 positional arguments in format string, but no arguments were given
+  --> $DIR/ifmt-bad-arg.rs:92:15
+   |
+LL |     println!("{:.*}");
+   |               ^^--^
+   |                 |
+   |                 this precision flag adds an extra required argument at position 0, which is why there are 2 arguments expected
+   |
+   = note: positional arguments are zero-based
+   = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
+
 error[E0308]: mismatched types
   --> $DIR/ifmt-bad-arg.rs:78:32
    |
@@ -303,6 +314,6 @@ LL |     println!("{} {:07$.*} {}", 1, 3.2, 4);
    = note: expected type `&usize`
               found type `&{float}`
 
-error: aborting due to 35 previous errors
+error: aborting due to 36 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-65462.rs b/src/test/ui/issues/issue-65462.rs
new file mode 100644
index 0000000000000..8c39ea531d244
--- /dev/null
+++ b/src/test/ui/issues/issue-65462.rs
@@ -0,0 +1,15 @@
+// build-pass
+
+enum Empty {}
+enum Enum {
+    Empty( Empty )
+}
+
+fn foobar() -> Option< Enum > {
+    let value: Option< Empty > = None;
+    Some( Enum::Empty( value? ) )
+}
+
+fn main() {
+    foobar();
+}
diff --git a/src/test/ui/issues/issue-65673.rs b/src/test/ui/issues/issue-65673.rs
new file mode 100644
index 0000000000000..4b47bd493a568
--- /dev/null
+++ b/src/test/ui/issues/issue-65673.rs
@@ -0,0 +1,12 @@
+#![feature(trait_alias)] // Enabled to reduce stderr output, but can be triggered even if disabled.
+trait Trait {}
+trait WithType {
+    type Ctx;
+}
+trait Alias<T> = where T: Trait;
+
+impl<T> WithType for T {
+    type Ctx = dyn Alias<T>;
+//~^ ERROR the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time
+}
+fn main() {}
diff --git a/src/test/ui/issues/issue-65673.stderr b/src/test/ui/issues/issue-65673.stderr
new file mode 100644
index 0000000000000..a556e35b6a944
--- /dev/null
+++ b/src/test/ui/issues/issue-65673.stderr
@@ -0,0 +1,17 @@
+error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time
+  --> $DIR/issue-65673.rs:9:5
+   |
+LL |     type Ctx;
+   |          --- associated type defined here
+...
+LL | impl<T> WithType for T {
+   | ---------------------- in this `impl` item
+LL |     type Ctx = dyn Alias<T>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)`
+   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/issues/issue-66353.rs b/src/test/ui/issues/issue-66353.rs
new file mode 100644
index 0000000000000..d8abdd5206ef4
--- /dev/null
+++ b/src/test/ui/issues/issue-66353.rs
@@ -0,0 +1,15 @@
+// #66353: ICE when trying to recover from incorrect associated type
+
+trait _Func<T> {
+    fn func(_: Self);
+}
+
+trait _A {
+    type AssocT;
+}
+
+fn main() {
+    _Func::< <() as _A>::AssocT >::func(());
+    //~^ ERROR the trait bound `(): _A` is not satisfied
+    //~| ERROR the trait bound `(): _Func<_>` is not satisfied
+}
diff --git a/src/test/ui/issues/issue-66353.stderr b/src/test/ui/issues/issue-66353.stderr
new file mode 100644
index 0000000000000..8fd50300ca63e
--- /dev/null
+++ b/src/test/ui/issues/issue-66353.stderr
@@ -0,0 +1,18 @@
+error[E0277]: the trait bound `(): _A` is not satisfied
+  --> $DIR/issue-66353.rs:12:14
+   |
+LL |     _Func::< <() as _A>::AssocT >::func(());
+   |              ^^^^^^^^^^^^^^^^^^ the trait `_A` is not implemented for `()`
+
+error[E0277]: the trait bound `(): _Func<_>` is not satisfied
+  --> $DIR/issue-66353.rs:12:41
+   |
+LL |     fn func(_: Self);
+   |     ----------------- required by `_Func::func`
+...
+LL |     _Func::< <() as _A>::AssocT >::func(());
+   |                                         ^^ the trait `_Func<_>` is not implemented for `()`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/parser/issue-66357-unexpected-unreachable.rs b/src/test/ui/parser/issue-66357-unexpected-unreachable.rs
new file mode 100644
index 0000000000000..1730adfa91419
--- /dev/null
+++ b/src/test/ui/parser/issue-66357-unexpected-unreachable.rs
@@ -0,0 +1,14 @@
+// The problem in #66357 was that the call trace:
+//
+// - parse_fn_block_decl
+// - expect_or
+// - unexpected
+// - expect_one_of
+// - expected_one_of_not_found
+// - recover_closing_delimiter
+//
+// ended up bubbling up `Ok(true)` to `unexpected` which then used `unreachable!()`.
+
+fn f() { |[](* }
+//~^ ERROR expected one of `,` or `:`, found `(`
+//~| ERROR expected one of `)`, `-`, `_`, `box`, `mut`, `ref`, `|`, identifier, or path, found `*`
diff --git a/src/test/ui/parser/issue-66357-unexpected-unreachable.stderr b/src/test/ui/parser/issue-66357-unexpected-unreachable.stderr
new file mode 100644
index 0000000000000..c7b6e15ddace8
--- /dev/null
+++ b/src/test/ui/parser/issue-66357-unexpected-unreachable.stderr
@@ -0,0 +1,16 @@
+error: expected one of `,` or `:`, found `(`
+  --> $DIR/issue-66357-unexpected-unreachable.rs:12:13
+   |
+LL | fn f() { |[](* }
+   |             ^ expected one of `,` or `:` here
+
+error: expected one of `)`, `-`, `_`, `box`, `mut`, `ref`, `|`, identifier, or path, found `*`
+  --> $DIR/issue-66357-unexpected-unreachable.rs:12:14
+   |
+LL | fn f() { |[](* }
+   |             -^ help: `)` may belong here
+   |             |
+   |             unclosed delimiter
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/monovariants.rs b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/monovariants.rs
new file mode 100644
index 0000000000000..5f86db86d4477
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/monovariants.rs
@@ -0,0 +1,8 @@
+#[non_exhaustive]
+pub enum NonExhaustiveMonovariant {
+    Variant(u32),
+}
+
+pub enum ExhaustiveMonovariant {
+    Variant(u32),
+}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/borrowck-exhaustive.rs b/src/test/ui/rfc-2008-non-exhaustive/borrowck-exhaustive.rs
new file mode 100644
index 0000000000000..be775b37f7b77
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/borrowck-exhaustive.rs
@@ -0,0 +1,42 @@
+// Test that the borrow checker doesn't consider checking an exhaustive pattern
+// as an access.
+
+// check-pass
+
+// aux-build:monovariants.rs
+extern crate monovariants;
+
+use monovariants::ExhaustiveMonovariant;
+
+enum Local {
+    Variant(u32),
+}
+
+#[non_exhaustive]
+enum LocalNonExhaustive {
+    Variant(u32),
+}
+
+fn main() {
+    let mut x = ExhaustiveMonovariant::Variant(1);
+    let y = &mut x;
+    match x {
+        ExhaustiveMonovariant::Variant(_) => {},
+        _ => {},
+    }
+    drop(y);
+    let mut x = Local::Variant(1);
+    let y = &mut x;
+    match x {
+        Local::Variant(_) => {},
+        _ => {},
+    }
+    drop(y);
+    let mut x = LocalNonExhaustive::Variant(1);
+    let y = &mut x;
+    match x {
+        LocalNonExhaustive::Variant(_) => {},
+        _ => {},
+    }
+    drop(y);
+}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/borrowck-non-exhaustive.rs b/src/test/ui/rfc-2008-non-exhaustive/borrowck-non-exhaustive.rs
new file mode 100644
index 0000000000000..00dcf89c7aa67
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/borrowck-non-exhaustive.rs
@@ -0,0 +1,18 @@
+// Test that the borrow checker considers `#[non_exhaustive]` when checking
+// whether a match contains a discriminant read.
+
+// aux-build:monovariants.rs
+extern crate monovariants;
+
+use monovariants::NonExhaustiveMonovariant;
+
+fn main() {
+    let mut x = NonExhaustiveMonovariant::Variant(1);
+    let y = &mut x;
+    match x {
+        NonExhaustiveMonovariant::Variant(_) => {},
+        //~^ ERROR cannot use `x` because it was mutably borrowed
+        _ => {},
+    }
+    drop(y);
+}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/borrowck-non-exhaustive.stderr b/src/test/ui/rfc-2008-non-exhaustive/borrowck-non-exhaustive.stderr
new file mode 100644
index 0000000000000..9edfa84cbc085
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/borrowck-non-exhaustive.stderr
@@ -0,0 +1,15 @@
+error[E0503]: cannot use `x` because it was mutably borrowed
+  --> $DIR/borrowck-non-exhaustive.rs:13:9
+   |
+LL |     let y = &mut x;
+   |             ------ borrow of `x` occurs here
+LL |     match x {
+LL |         NonExhaustiveMonovariant::Variant(_) => {},
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of borrowed `x`
+...
+LL |     drop(y);
+   |          - borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0503`.