about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/ci/docker/armhf-gnu/Dockerfile3
-rw-r--r--src/doc/unstable-book/src/language-features/non-exhaustive.md11
-rw-r--r--src/libcore/iter/sources.rs4
-rw-r--r--src/librustc/ty/mod.rs14
-rw-r--r--src/librustc_metadata/encoder.rs9
-rw-r--r--src/librustc_passes/ast_validation.rs9
-rw-r--r--src/librustc_privacy/lib.rs21
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs10
-rw-r--r--src/librustc_typeck/check/demand.rs71
-rw-r--r--src/librustc_typeck/diagnostics.rs13
-rw-r--r--src/librustdoc/clean/mod.rs3
-rw-r--r--src/librustdoc/html/render.rs15
-rw-r--r--src/librustdoc/html/static/main.js13
-rw-r--r--src/libstd/io/mod.rs25
-rw-r--r--src/libstd/macros.rs8
-rw-r--r--src/libstd/sys/redox/ext/io.rs15
-rw-r--r--src/libstd/sys/unix/ext/io.rs15
-rw-r--r--src/libstd/sys/windows/ext/io.rs21
-rw-r--r--src/libsyntax/feature_gate.rs16
-rw-r--r--src/libsyntax/parse/parser.rs83
-rw-r--r--src/test/incremental/issue-59523-on-implemented-is-not-unused.rs27
-rw-r--r--src/test/incremental/issue-59524-layout-scalar-valid-range-is-not-unused.rs19
-rw-r--r--src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/enums.rs10
-rw-r--r--src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/structs.rs14
-rw-r--r--src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/variants.rs9
-rw-r--r--src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums.rs53
-rw-r--r--src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs.rs20
-rw-r--r--src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants.rs22
-rw-r--r--src/test/ui/deref-suggestion.rs18
-rw-r--r--src/test/ui/deref-suggestion.stderr56
-rw-r--r--src/test/ui/issues/issue-34334.rs8
-rw-r--r--src/test/ui/issues/issue-34334.stderr43
-rw-r--r--src/test/ui/parser/pat-tuple-1.rs2
-rw-r--r--src/test/ui/parser/pat-tuple-5.rs2
-rw-r--r--src/test/ui/parser/recover-from-bad-variant.rs14
-rw-r--r--src/test/ui/parser/recover-from-bad-variant.stderr23
-rw-r--r--src/test/ui/parser/recover-tuple-pat.rs12
-rw-r--r--src/test/ui/parser/recover-tuple-pat.stderr24
-rw-r--r--src/test/ui/parser/recover-tuple.rs11
-rw-r--r--src/test/ui/parser/recover-tuple.stderr18
-rw-r--r--src/test/ui/parser/trait-object-lifetime-parens.rs5
-rw-r--r--src/test/ui/parser/trait-object-lifetime-parens.stderr17
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/enum.rs44
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/enum_same_crate.rs (renamed from src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums_same_crate.rs)1
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/struct.rs (renamed from src/test/ui/rfc-2008-non-exhaustive/structs.rs)12
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/struct.stderr (renamed from src/test/ui/rfc-2008-non-exhaustive/structs.stderr)18
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/structs_same_crate.rs (renamed from src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs_same_crate.rs)1
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/variant.rs (renamed from src/test/ui/rfc-2008-non-exhaustive/variants.rs)25
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/variant.stderr52
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/variants_create.rs17
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/variants_create.stderr20
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/variants_same_crate.rs (renamed from src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants_same_crate.rs)7
52 files changed, 722 insertions, 281 deletions
diff --git a/src/ci/docker/armhf-gnu/Dockerfile b/src/ci/docker/armhf-gnu/Dockerfile
index 2b7624d53ee..e4c2097f970 100644
--- a/src/ci/docker/armhf-gnu/Dockerfile
+++ b/src/ci/docker/armhf-gnu/Dockerfile
@@ -71,7 +71,8 @@ COPY scripts/qemu-bare-bones-addentropy.c /tmp/addentropy.c
 RUN arm-linux-gnueabihf-gcc addentropy.c -o rootfs/addentropy -static
 
 # TODO: What is this?!
-RUN curl -O http://ftp.nl.debian.org/debian/dists/jessie/main/installer-armhf/current/images/device-tree/vexpress-v2p-ca15-tc1.dtb
+# Source of the file: https://github.com/vfdev-5/qemu-rpi2-vexpress/raw/master/vexpress-v2p-ca15-tc1.dtb
+RUN curl -O https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/vexpress-v2p-ca15-tc1.dtb
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
diff --git a/src/doc/unstable-book/src/language-features/non-exhaustive.md b/src/doc/unstable-book/src/language-features/non-exhaustive.md
index f9840e1b83f..907147c17ef 100644
--- a/src/doc/unstable-book/src/language-features/non-exhaustive.md
+++ b/src/doc/unstable-book/src/language-features/non-exhaustive.md
@@ -7,10 +7,12 @@ The tracking issue for this feature is: [#44109]
 ------------------------
 
 The `non_exhaustive` gate allows you to use the `#[non_exhaustive]` attribute
-on structs and enums. When applied within a crate, users of the crate will need
-to use the `_` pattern when matching enums and use the `..` pattern when
-matching structs. Structs marked as `non_exhaustive` will not be able to be
-created normally outside of the defining crate. This is demonstrated below:
+on structs, enums and enum variants. When applied within a crate, users of the
+crate will need to use the `_` pattern when matching enums and use the `..`
+pattern when matching structs. Enum variants cannot be matched against.
+Structs and enum variants marked as `non_exhaustive` will not be able to
+be created normally outside of the defining crate. This is demonstrated
+below:
 
 ```rust,ignore (pseudo-Rust)
 use std::error::Error as StdError;
@@ -72,4 +74,3 @@ let config = Config { window_width: 640, window_height: 480 };
 // when marked non_exhaustive.
 let &Config { window_width, window_height, .. } = config;
 ```
-
diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs
index ffc24df3ed4..7934e5880d7 100644
--- a/src/libcore/iter/sources.rs
+++ b/src/libcore/iter/sources.rs
@@ -375,8 +375,8 @@ pub fn once<T>(value: T) -> Once<T> {
     Once { inner: Some(value).into_iter() }
 }
 
-/// An iterator that repeats elements of type `A` endlessly by
-/// applying the provided closure `F: FnMut() -> A`.
+/// An iterator that yields a single element of type `A` by
+/// applying the provided closure `F: FnOnce() -> A`.
 ///
 /// This `struct` is created by the [`once_with`] function.
 /// See its documentation for more.
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index f0045136f41..102057c1380 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1869,6 +1869,11 @@ impl<'a, 'gcx, 'tcx> VariantDef {
         if adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, "non_exhaustive") {
             debug!("found non-exhaustive field list for {:?}", parent_did);
             flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE;
+        } else if let Some(variant_did) = variant_did {
+            if tcx.has_attr(variant_did, "non_exhaustive") {
+                debug!("found non-exhaustive field list for {:?}", variant_did);
+                flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE;
+            }
         }
 
         VariantDef {
@@ -2146,6 +2151,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
             debug!("found non-exhaustive variant list for {:?}", did);
             flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE;
         }
+
         flags |= match kind {
             AdtKind::Enum => AdtFlags::IS_ENUM,
             AdtKind::Union => AdtFlags::IS_UNION,
@@ -2299,21 +2305,25 @@ impl<'a, 'gcx, 'tcx> AdtDef {
             self.variants.iter().all(|v| v.fields.is_empty())
     }
 
+    /// Return a `VariantDef` given a variant id.
     pub fn variant_with_id(&self, vid: DefId) -> &VariantDef {
         self.variants.iter().find(|v| v.def_id == vid)
             .expect("variant_with_id: unknown variant")
     }
 
+    /// Return a `VariantDef` given a constructor id.
     pub fn variant_with_ctor_id(&self, cid: DefId) -> &VariantDef {
         self.variants.iter().find(|v| v.ctor_def_id == Some(cid))
             .expect("variant_with_ctor_id: unknown variant")
     }
 
+    /// Return the index of `VariantDef` given a variant id.
     pub fn variant_index_with_id(&self, vid: DefId) -> VariantIdx {
         self.variants.iter_enumerated().find(|(_, v)| v.def_id == vid)
             .expect("variant_index_with_id: unknown variant").0
     }
 
+    /// Return the index of `VariantDef` given a constructor id.
     pub fn variant_index_with_ctor_id(&self, cid: DefId) -> VariantIdx {
         self.variants.iter_enumerated().find(|(_, v)| v.ctor_def_id == Some(cid))
             .expect("variant_index_with_ctor_id: unknown variant").0
@@ -2930,8 +2940,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    // Returns `ty::VariantDef` if `def` refers to a struct,
-    // or variant or their constructors, panics otherwise.
+    /// Returns `ty::VariantDef` if `def` refers to a struct,
+    /// or variant or their constructors, panics otherwise.
     pub fn expect_variant_def(self, def: Def) -> &'tcx VariantDef {
         match def {
             Def::Variant(did) => {
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 9c908176a6d..796d2f6a18b 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -643,13 +643,18 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
             }
         };
 
-        // Variant constructors have the same visibility as the parent enums.
+        // Variant constructors have the same visibility as the parent enums, unless marked as
+        // non-exhaustive, in which case they are lowered to `pub(crate)`.
         let enum_id = tcx.hir().as_local_hir_id(enum_did).unwrap();
         let enum_vis = &tcx.hir().expect_item_by_hir_id(enum_id).vis;
+        let mut ctor_vis = ty::Visibility::from_hir(enum_vis, enum_id, tcx);
+        if variant.is_field_list_non_exhaustive() && ctor_vis == ty::Visibility::Public {
+            ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
+        }
 
         Entry {
             kind: EntryKind::Variant(self.lazy(&data)),
-            visibility: self.lazy(&ty::Visibility::from_hir(enum_vis, enum_id, tcx)),
+            visibility: self.lazy(&ctor_vis),
             span: self.lazy(&tcx.def_span(def_id)),
             attributes: LazySeq::empty(),
             children: LazySeq::empty(),
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 4e2aefe6231..741264d1dbe 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -192,14 +192,6 @@ impl<'a> AstValidator<'a> {
         }
     }
 
-    fn invalid_non_exhaustive_attribute(&self, variant: &Variant) {
-        let has_non_exhaustive = attr::contains_name(&variant.node.attrs, "non_exhaustive");
-        if has_non_exhaustive {
-            self.err_handler().span_err(variant.span,
-                                        "#[non_exhaustive] is not yet supported on variants");
-        }
-    }
-
     fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
         if let VisibilityKind::Inherited = vis.node {
             return
@@ -608,7 +600,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             }
             ItemKind::Enum(ref def, _) => {
                 for variant in &def.variants {
-                    self.invalid_non_exhaustive_attribute(variant);
                     for field in variant.node.data.fields() {
                         self.invalid_visibility(&field.vis, None);
                     }
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index adb1a4b1308..030883c0159 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -244,7 +244,26 @@ fn def_id_visibility<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
                     match tcx.hir().get_by_hir_id(parent_hir_id) {
                         Node::Variant(..) => {
                             let parent_did = tcx.hir().local_def_id_from_hir_id(parent_hir_id);
-                            return def_id_visibility(tcx, parent_did);
+                            let (mut ctor_vis, mut span, mut descr) = def_id_visibility(
+                                tcx, parent_did,
+                            );
+
+                            let adt_def = tcx.adt_def(tcx.hir().get_parent_did_by_hir_id(hir_id));
+                            let ctor_did = tcx.hir().local_def_id_from_hir_id(
+                                vdata.ctor_hir_id().unwrap());
+                            let variant = adt_def.variant_with_ctor_id(ctor_did);
+
+                            if variant.is_field_list_non_exhaustive() &&
+                                ctor_vis == ty::Visibility::Public
+                            {
+                                ctor_vis = ty::Visibility::Restricted(
+                                    DefId::local(CRATE_DEF_INDEX));
+                                let attrs = tcx.get_attrs(variant.def_id);
+                                span = attr::find_by_name(&attrs, "non_exhaustive").unwrap().span;
+                                descr = "crate-visible";
+                            }
+
+                            return (ctor_vis, span, descr);
                         }
                         Node::Item(..) => {
                             let item = match tcx.hir().get_by_hir_id(parent_hir_id) {
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index f55425c3168..7ce264db755 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -588,6 +588,14 @@ impl<'a> Resolver<'a> {
         let def = Def::Variant(def_id);
         self.define(parent, ident, TypeNS, (def, vis, variant.span, expansion));
 
+        // If the variant is marked as non_exhaustive then lower the visibility to within the
+        // crate.
+        let mut ctor_vis = vis;
+        let has_non_exhaustive = attr::contains_name(&variant.node.attrs, "non_exhaustive");
+        if has_non_exhaustive && vis == ty::Visibility::Public {
+            ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
+        }
+
         // Define a constructor name in the value namespace.
         // Braced variants, unlike structs, generate unusable names in
         // value namespace, they are reserved for possible future use.
@@ -597,7 +605,7 @@ impl<'a> Resolver<'a> {
         let ctor_def_id = self.definitions.local_def_id(ctor_node_id);
         let ctor_kind = CtorKind::from_ast(&variant.node.data);
         let ctor_def = Def::Ctor(ctor_def_id, CtorOf::Variant, ctor_kind);
-        self.define(parent, ident, ValueNS, (ctor_def, vis, variant.span, expansion));
+        self.define(parent, ident, ValueNS, (ctor_def, ctor_vis, variant.span, expansion));
     }
 
     /// Constructs the reduced graph for one foreign item.
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 1fc63a93022..8739147c621 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -270,6 +270,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         None
     }
 
+    fn is_hir_id_from_struct_pattern_shorthand_field(&self, hir_id: hir::HirId, sp: Span) -> bool {
+        let cm = self.sess().source_map();
+        let parent_id = self.tcx.hir().get_parent_node_by_hir_id(hir_id);
+        if let Some(parent) = self.tcx.hir().find_by_hir_id(parent_id) {
+            // Account for fields
+            if let Node::Expr(hir::Expr {
+                node: hir::ExprKind::Struct(_, fields, ..), ..
+            }) = parent {
+                if let Ok(src) = cm.span_to_snippet(sp) {
+                    for field in fields {
+                        if field.ident.as_str() == src.as_str() && field.is_shorthand {
+                            return true;
+                        }
+                    }
+                }
+            }
+        }
+        false
+    }
+
     /// This function is used to determine potential "simple" improvements or users' errors and
     /// provide them useful help. For example:
     ///
@@ -299,6 +319,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             return None;
         }
 
+        let is_struct_pat_shorthand_field = self.is_hir_id_from_struct_pattern_shorthand_field(
+            expr.hir_id,
+            sp,
+        );
+
         match (&expected.sty, &checked_ty.sty) {
             (&ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (&exp.sty, &check.sty) {
                 (&ty::Str, &ty::Array(arr, _)) |
@@ -337,12 +362,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // bar(&x); // error, expected &mut
                 // ```
                 let ref_ty = match mutability {
-                    hir::Mutability::MutMutable => self.tcx.mk_mut_ref(
-                                                       self.tcx.mk_region(ty::ReStatic),
-                                                       checked_ty),
-                    hir::Mutability::MutImmutable => self.tcx.mk_imm_ref(
-                                                       self.tcx.mk_region(ty::ReStatic),
-                                                       checked_ty),
+                    hir::Mutability::MutMutable => {
+                        self.tcx.mk_mut_ref(self.tcx.mk_region(ty::ReStatic), checked_ty)
+                    }
+                    hir::Mutability::MutImmutable => {
+                        self.tcx.mk_imm_ref(self.tcx.mk_region(ty::ReStatic), checked_ty)
+                    }
                 };
                 if self.can_coerce(ref_ty, expected) {
                     if let Ok(src) = cm.span_to_snippet(sp) {
@@ -363,14 +388,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         if let Some(sugg) = self.can_use_as_ref(expr) {
                             return Some(sugg);
                         }
+                        let field_name = if is_struct_pat_shorthand_field {
+                            format!("{}: ", sugg_expr)
+                        } else {
+                            String::new()
+                        };
                         return Some(match mutability {
-                            hir::Mutability::MutMutable => {
-                                (sp, "consider mutably borrowing here", format!("&mut {}",
-                                                                                sugg_expr))
-                            }
-                            hir::Mutability::MutImmutable => {
-                                (sp, "consider borrowing here", format!("&{}", sugg_expr))
-                            }
+                            hir::Mutability::MutMutable => (
+                                sp,
+                                "consider mutably borrowing here",
+                                format!("{}&mut {}", field_name, sugg_expr),
+                            ),
+                            hir::Mutability::MutImmutable => (
+                                sp,
+                                "consider borrowing here",
+                                format!("{}&{}", field_name, sugg_expr),
+                            ),
                         });
                     }
                 }
@@ -411,12 +444,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                                       checked,
                                                                       sp) {
                                 // do not suggest if the span comes from a macro (#52783)
-                                if let (Ok(code),
-                                        true) = (cm.span_to_snippet(sp), sp == expr.span) {
+                                if let (Ok(code), true) = (
+                                    cm.span_to_snippet(sp),
+                                    sp == expr.span,
+                                ) {
                                     return Some((
                                         sp,
                                         "consider dereferencing the borrow",
-                                        format!("*{}", code),
+                                        if is_struct_pat_shorthand_field {
+                                            format!("{}: *{}", code, code)
+                                        } else {
+                                            format!("*{}", code)
+                                        },
                                     ));
                                 }
                             }
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index cde37fb23c3..22f24df450f 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -4341,11 +4341,12 @@ foo.method(); // Ok!
 "##,
 
 E0638: r##"
-This error indicates that the struct or enum must be matched non-exhaustively
-as it has been marked as `non_exhaustive`.
+This error indicates that the struct, enum or enum variant must be matched
+non-exhaustively as it has been marked as `non_exhaustive`.
 
 When applied within a crate, downstream users of the crate will need to use the
 `_` pattern when matching enums and use the `..` pattern when matching structs.
+Downstream crates cannot match against non-exhaustive enum variants.
 
 For example, in the below example, since the enum is marked as
 `non_exhaustive`, it is required that downstream crates match non-exhaustively
@@ -4390,10 +4391,10 @@ Similarly, for structs, match with `..` to avoid this error.
 "##,
 
 E0639: r##"
-This error indicates that the struct or enum cannot be instantiated from
-outside of the defining crate as it has been marked as `non_exhaustive` and as
-such more fields/variants may be added in future that could cause adverse side
-effects for this code.
+This error indicates that the struct, enum or enum variant cannot be
+instantiated from outside of the defining crate as it has been marked
+as `non_exhaustive` and as such more fields/variants may be added in
+future that could cause adverse side effects for this code.
 
 It is recommended that you look for a `new` function or equivalent in the
 crate's documentation.
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 396488c981d..a403f0845ce 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -421,6 +421,9 @@ impl Item {
     pub fn is_enum(&self) -> bool {
         self.type_() == ItemType::Enum
     }
+    pub fn is_variant(&self) -> bool {
+        self.type_() == ItemType::Variant
+    }
     pub fn is_associated_type(&self) -> bool {
         self.type_() == ItemType::AssociatedType
     }
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 866d8fe682a..9220d2feed2 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -2604,7 +2604,15 @@ fn document_non_exhaustive_header(item: &clean::Item) -> &str {
 fn document_non_exhaustive(w: &mut fmt::Formatter<'_>, item: &clean::Item) -> fmt::Result {
     if item.is_non_exhaustive() {
         write!(w, "<div class='docblock non-exhaustive non-exhaustive-{}'>", {
-            if item.is_struct() { "struct" } else if item.is_enum() { "enum" } else { "type" }
+            if item.is_struct() {
+                "struct"
+            } else if item.is_enum() {
+                "enum"
+            } else if item.is_variant() {
+                "variant"
+            } else {
+                "type"
+            }
         })?;
 
         if item.is_struct() {
@@ -2617,6 +2625,10 @@ fn document_non_exhaustive(w: &mut fmt::Formatter<'_>, item: &clean::Item) -> fm
             write!(w, "Non-exhaustive enums could have additional variants added in future. \
                        Therefore, when matching against variants of non-exhaustive enums, an \
                        extra wildcard arm must be added to account for any future variants.")?;
+        } else if item.is_variant() {
+            write!(w, "Non-exhaustive enum variants could have additional fields added in future. \
+                       Therefore, non-exhaustive enum variants cannot be constructed in external \
+                       crates and cannot be matched against.")?;
         } else {
             write!(w, "This type will require a wildcard arm in any match statements or \
                        constructors.")?;
@@ -3679,6 +3691,7 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
             }
             write!(w, "</code></span>")?;
             document(w, cx, variant)?;
+            document_non_exhaustive(w, variant)?;
 
             use crate::clean::{Variant, VariantKind};
             if let clean::VariantItem(Variant {
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index aad7eb627bf..412029cf376 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -2071,6 +2071,14 @@ if (!DOMTokenList.prototype.remove) {
                     collapser(e, collapse);
                 });
             }
+
+            var blanket_list = document.getElementById("blanket-implementations-list");
+
+            if (blanket_list !== null) {
+                onEachLazy(blanket_list.getElementsByClassName("collapse-toggle"), function(e) {
+                    collapser(e, collapse);
+                });
+            }
         }
     }
 
@@ -2263,6 +2271,8 @@ if (!DOMTokenList.prototype.remove) {
                     otherMessage += "struct";
                 } else if (hasClass(e, "non-exhaustive-enum")) {
                     otherMessage += "enum";
+                } else if (hasClass(e, "non-exhaustive-variant")) {
+                    otherMessage += "enum variant";
                 } else if (hasClass(e, "non-exhaustive-type")) {
                     otherMessage += "type";
                 }
@@ -2280,6 +2290,9 @@ if (!DOMTokenList.prototype.remove) {
             if (hasClass(e, "type-decl") === true && showItemDeclarations === true) {
                 collapseDocs(e.previousSibling.childNodes[0], "toggle");
             }
+            if (hasClass(e, "non-exhaustive") === true) {
+                collapseDocs(e.previousSibling.childNodes[0], "toggle");
+            }
         }
     }
 
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index 14c850b6b05..14a16f3fc0f 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -24,9 +24,9 @@
 //!     let mut buffer = [0; 10];
 //!
 //!     // read up to 10 bytes
-//!     f.read(&mut buffer)?;
+//!     let n = f.read(&mut buffer)?;
 //!
-//!     println!("The bytes: {:?}", buffer);
+//!     println!("The bytes: {:?}", &buffer[..n]);
 //!     Ok(())
 //! }
 //! ```
@@ -56,9 +56,9 @@
 //!     f.seek(SeekFrom::End(-10))?;
 //!
 //!     // read up to 10 bytes
-//!     f.read(&mut buffer)?;
+//!     let n = f.read(&mut buffer)?;
 //!
-//!     println!("The bytes: {:?}", buffer);
+//!     println!("The bytes: {:?}", &buffer[..n]);
 //!     Ok(())
 //! }
 //! ```
@@ -537,7 +537,9 @@ pub trait Read {
     ///     let mut buffer = [0; 10];
     ///
     ///     // read up to 10 bytes
-    ///     f.read(&mut buffer[..])?;
+    ///     let n = f.read(&mut buffer[..])?;
+    ///
+    ///     println!("The bytes: {:?}", &buffer[..n]);
     ///     Ok(())
     /// }
     /// ```
@@ -1062,12 +1064,23 @@ impl Initializer {
 /// use std::fs::File;
 ///
 /// fn main() -> std::io::Result<()> {
+///     let data = b"some bytes";
+///
+///     let mut pos = 0;
 ///     let mut buffer = File::create("foo.txt")?;
 ///
-///     buffer.write(b"some bytes")?;
+///     while pos < data.len() {
+///         let bytes_written = buffer.write(&data[pos..])?;
+///         pos += bytes_written;
+///     }
 ///     Ok(())
 /// }
 /// ```
+///
+/// The trait also provides convenience methods like [`write_all`], which calls
+/// `write` in a loop until its entire input has been written.
+///
+/// [`write_all`]: #method.write_all
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(spotlight)]
 pub trait Write {
diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs
index d5afd069d7f..0e0292277e1 100644
--- a/src/libstd/macros.rs
+++ b/src/libstd/macros.rs
@@ -233,10 +233,14 @@ macro_rules! eprintln {
 /// to give up ownership, you can instead borrow with `dbg!(&expr)`
 /// for some expression `expr`.
 ///
+/// The `dbg!` macro works exactly the same in release builds.
+/// This is useful when debugging issues that only occur in release
+/// builds or when debugging in release mode is significantly faster.
+///
 /// Note that the macro is intended as a debugging tool and therefore you
 /// should avoid having uses of it in version control for longer periods.
 /// Use cases involving debug output that should be added to version control
-/// may be better served by macros such as `debug!` from the `log` crate.
+/// are better served by macros such as [`debug!`][debug-log] from the [`log`][log] crate.
 ///
 /// # Stability
 ///
@@ -311,6 +315,8 @@ macro_rules! eprintln {
 /// file and line whenever it's reached.
 ///
 /// [stderr]: https://en.wikipedia.org/wiki/Standard_streams#Standard_error_(stderr)
+/// [debug-log]: https://docs.rs/log/*/log/macro.debug.html
+/// [log]: https://docs.rs/log/
 #[macro_export]
 #[stable(feature = "dbg_macro", since = "1.32.0")]
 macro_rules! dbg {
diff --git a/src/libstd/sys/redox/ext/io.rs b/src/libstd/sys/redox/ext/io.rs
index f431f96c541..c21d216478f 100644
--- a/src/libstd/sys/redox/ext/io.rs
+++ b/src/libstd/sys/redox/ext/io.rs
@@ -115,6 +115,21 @@ impl AsRawFd for io::Stderr {
     fn as_raw_fd(&self) -> RawFd { 2 }
 }
 
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawFd for io::StdinLock<'a> {
+    fn as_raw_fd(&self) -> RawFd { 0 }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawFd for io::StdoutLock<'a> {
+    fn as_raw_fd(&self) -> RawFd { 1 }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawFd for io::StderrLock<'a> {
+    fn as_raw_fd(&self) -> RawFd { 2 }
+}
+
 #[stable(feature = "from_raw_os", since = "1.1.0")]
 impl FromRawFd for net::TcpStream {
     unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
diff --git a/src/libstd/sys/unix/ext/io.rs b/src/libstd/sys/unix/ext/io.rs
index 1a0b3b8962b..6bcc59495e3 100644
--- a/src/libstd/sys/unix/ext/io.rs
+++ b/src/libstd/sys/unix/ext/io.rs
@@ -95,3 +95,18 @@ impl AsRawFd for io::Stdout {
 impl AsRawFd for io::Stderr {
     fn as_raw_fd(&self) -> RawFd { libc::STDERR_FILENO }
 }
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawFd for io::StdinLock<'a> {
+    fn as_raw_fd(&self) -> RawFd { libc::STDIN_FILENO }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawFd for io::StdoutLock<'a> {
+    fn as_raw_fd(&self) -> RawFd { libc::STDOUT_FILENO }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawFd for io::StderrLock<'a> {
+    fn as_raw_fd(&self) -> RawFd { libc::STDERR_FILENO }
+}
diff --git a/src/libstd/sys/windows/ext/io.rs b/src/libstd/sys/windows/ext/io.rs
index 1a7d734b89e..ec47c2e9d5a 100644
--- a/src/libstd/sys/windows/ext/io.rs
+++ b/src/libstd/sys/windows/ext/io.rs
@@ -83,6 +83,27 @@ impl AsRawHandle for io::Stderr {
     }
 }
 
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawHandle for io::StdinLock<'a> {
+    fn as_raw_handle(&self) -> RawHandle {
+        unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as RawHandle }
+    }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawHandle for io::StdoutLock<'a> {
+    fn as_raw_handle(&self) -> RawHandle {
+        unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) as RawHandle }
+    }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawHandle for io::StderrLock<'a> {
+    fn as_raw_handle(&self) -> RawHandle {
+        unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as RawHandle }
+    }
+}
+
 #[stable(feature = "from_raw_os", since = "1.1.0")]
 impl FromRawHandle for fs::File {
     unsafe fn from_raw_handle(handle: RawHandle) -> fs::File {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 96c89d3176a..dcb55fb572f 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -906,7 +906,7 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, Attribu
                                          not currently handle destructors.",
                                         cfg_fn!(thread_local))),
 
-    ("rustc_on_unimplemented", Normal, template!(List:
+    ("rustc_on_unimplemented", Whitelisted, template!(List:
                           r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#,
                           NameValueStr: "message"),
                                              Gated(Stability::Unstable,
@@ -962,6 +962,20 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, Attribu
             is just used for rustc unit tests \
             and will never be stable",
            cfg_fn!(rustc_attrs))),
+    ("rustc_layout_scalar_valid_range_start", Whitelisted, template!(List: "value"),
+     Gated(Stability::Unstable,
+           "rustc_attrs",
+           "the `#[rustc_layout_scalar_valid_range_start]` attribute \
+            is just used to enable niche optimizations in libcore \
+            and will never be stable",
+           cfg_fn!(rustc_attrs))),
+    ("rustc_layout_scalar_valid_range_end", Whitelisted, template!(List: "value"),
+     Gated(Stability::Unstable,
+           "rustc_attrs",
+           "the `#[rustc_layout_scalar_valid_range_end]` attribute \
+            is just used to enable niche optimizations in libcore \
+            and will never be stable",
+           cfg_fn!(rustc_attrs))),
     ("rustc_regions", Normal, template!(Word), Gated(Stability::Unstable,
                                     "rustc_attrs",
                                     "the `#[rustc_regions]` attribute \
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 79c1f0cb4cc..ae8e57d54de 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -2626,7 +2626,13 @@ impl<'a> Parser<'a> {
                 let mut trailing_comma = false;
                 let mut recovered = false;
                 while self.token != token::CloseDelim(token::Paren) {
-                    es.push(self.parse_expr()?);
+                    es.push(match self.parse_expr() {
+                        Ok(es) => es,
+                        Err(err) => {
+                            // recover from parse error in tuple list
+                            return Ok(self.recover_seq_parse_error(token::Paren, lo, Err(err)));
+                        }
+                    });
                     recovered = self.expect_one_of(
                         &[],
                         &[token::Comma, token::CloseDelim(token::Paren)],
@@ -3237,36 +3243,54 @@ impl<'a> Parser<'a> {
             }
             if self.expr_is_complete(&e) { break; }
             match self.token {
-              // expr(...)
-              token::OpenDelim(token::Paren) => {
-                let es = self.parse_unspanned_seq(
-                    &token::OpenDelim(token::Paren),
-                    &token::CloseDelim(token::Paren),
-                    SeqSep::trailing_allowed(token::Comma),
-                    |p| Ok(p.parse_expr()?)
-                )?;
-                hi = self.prev_span;
-
-                let nd = self.mk_call(e, es);
-                e = self.mk_expr(lo.to(hi), nd, ThinVec::new());
-              }
+                // expr(...)
+                token::OpenDelim(token::Paren) => {
+                    let seq = self.parse_unspanned_seq(
+                        &token::OpenDelim(token::Paren),
+                        &token::CloseDelim(token::Paren),
+                        SeqSep::trailing_allowed(token::Comma),
+                        |p| Ok(p.parse_expr()?)
+                    ).map(|es| {
+                        let nd = self.mk_call(e, es);
+                        let hi = self.prev_span;
+                        self.mk_expr(lo.to(hi), nd, ThinVec::new())
+                    });
+                    e = self.recover_seq_parse_error(token::Paren, lo, seq);
+                }
 
-              // expr[...]
-              // Could be either an index expression or a slicing expression.
-              token::OpenDelim(token::Bracket) => {
-                self.bump();
-                let ix = self.parse_expr()?;
-                hi = self.span;
-                self.expect(&token::CloseDelim(token::Bracket))?;
-                let index = self.mk_index(e, ix);
-                e = self.mk_expr(lo.to(hi), index, ThinVec::new())
-              }
-              _ => return Ok(e)
+                // expr[...]
+                // Could be either an index expression or a slicing expression.
+                token::OpenDelim(token::Bracket) => {
+                    self.bump();
+                    let ix = self.parse_expr()?;
+                    hi = self.span;
+                    self.expect(&token::CloseDelim(token::Bracket))?;
+                    let index = self.mk_index(e, ix);
+                    e = self.mk_expr(lo.to(hi), index, ThinVec::new())
+                }
+                _ => return Ok(e)
             }
         }
         return Ok(e);
     }
 
+    fn recover_seq_parse_error(
+        &mut self,
+        delim: token::DelimToken,
+        lo: Span,
+        result: PResult<'a, P<Expr>>,
+    ) -> P<Expr> {
+        match result {
+            Ok(x) => x,
+            Err(mut err) => {
+                err.emit();
+                // recover from parse error
+                self.consume_block(delim);
+                self.mk_expr(lo.to(self.prev_span), ExprKind::Err, ThinVec::new())
+            }
+        }
+    }
+
     crate fn process_potential_macro_variable(&mut self) {
         let (token, span) = match self.token {
             token::Dollar if self.span.ctxt() != syntax_pos::hygiene::SyntaxContext::empty() &&
@@ -4253,7 +4277,14 @@ impl<'a> Parser<'a> {
     // Trailing commas are significant because (p) and (p,) are different patterns.
     fn parse_parenthesized_pat_list(&mut self) -> PResult<'a, (Vec<P<Pat>>, Option<usize>, bool)> {
         self.expect(&token::OpenDelim(token::Paren))?;
-        let result = self.parse_pat_list()?;
+        let result = match self.parse_pat_list() {
+            Ok(result) => result,
+            Err(mut err) => { // recover from parse error in tuple pattern list
+                err.emit();
+                self.consume_block(token::Paren);
+                return Ok((vec![], Some(0), false));
+            }
+        };
         self.expect(&token::CloseDelim(token::Paren))?;
         Ok(result)
     }
diff --git a/src/test/incremental/issue-59523-on-implemented-is-not-unused.rs b/src/test/incremental/issue-59523-on-implemented-is-not-unused.rs
new file mode 100644
index 00000000000..3d16a1543f4
--- /dev/null
+++ b/src/test/incremental/issue-59523-on-implemented-is-not-unused.rs
@@ -0,0 +1,27 @@
+// We should not see the unused_attributes lint fire for
+// rustc_on_unimplemented, but with this bug we are seeing it fire (on
+// subsequent runs) if incremental compilation is enabled.
+
+// revisions: rpass1 rpass2
+// compile-pass
+
+#![feature(on_unimplemented)]
+#![deny(unused_attributes)]
+
+#[rustc_on_unimplemented = "invalid"]
+trait Index<Idx: ?Sized> {
+    type Output: ?Sized;
+    fn index(&self, index: Idx) -> &Self::Output;
+}
+
+#[rustc_on_unimplemented = "a usize is required to index into a slice"]
+impl Index<usize> for [i32] {
+    type Output = i32;
+    fn index(&self, index: usize) -> &i32 {
+        &self[index]
+    }
+}
+
+fn main() {
+    Index::<usize>::index(&[1, 2, 3] as &[i32], 2);
+}
diff --git a/src/test/incremental/issue-59524-layout-scalar-valid-range-is-not-unused.rs b/src/test/incremental/issue-59524-layout-scalar-valid-range-is-not-unused.rs
new file mode 100644
index 00000000000..e4802cba9b6
--- /dev/null
+++ b/src/test/incremental/issue-59524-layout-scalar-valid-range-is-not-unused.rs
@@ -0,0 +1,19 @@
+// We should not see the unused_attributes lint fire for
+// rustc_layout_scalar_valid_range_start, but with this bug we are
+// seeing it fire (on subsequent runs) if incremental compilation is
+// enabled.
+
+// revisions: rpass1 rpass2
+// compile-pass
+
+#![feature(rustc_attrs)]
+#![deny(unused_attributes)]
+
+#[rustc_layout_scalar_valid_range_start(10)]
+#[rustc_layout_scalar_valid_range_end(30)]
+struct RestrictedRange(u32);
+const OKAY_RANGE: RestrictedRange = unsafe { RestrictedRange(20) };
+
+fn main() {
+    OKAY_RANGE.0;
+}
diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/enums.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/enums.rs
deleted file mode 100644
index b3e2fa2c620..00000000000
--- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/enums.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-// run-pass
-#![crate_type = "rlib"]
-#![feature(non_exhaustive)]
-
-#[non_exhaustive]
-pub enum NonExhaustiveEnum {
-    Unit,
-    Tuple(u32),
-    Struct { field: u32 }
-}
diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/structs.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/structs.rs
deleted file mode 100644
index 08b14d0df94..00000000000
--- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/structs.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-// run-pass
-#![feature(non_exhaustive)]
-
-#[non_exhaustive]
-pub struct NormalStruct {
-    pub first_field: u16,
-    pub second_field: u16,
-}
-
-#[non_exhaustive]
-pub struct UnitStruct;
-
-#[non_exhaustive]
-pub struct TupleStruct (pub u16, pub u16);
diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/variants.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/variants.rs
deleted file mode 100644
index 56a73d8ab60..00000000000
--- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/auxiliary/variants.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-// run-pass
-#![crate_type = "rlib"]
-#![feature(non_exhaustive)]
-
-pub enum NonExhaustiveVariants {
-    #[non_exhaustive] Unit,
-    #[non_exhaustive] Tuple(u32),
-    #[non_exhaustive] Struct { field: u32 }
-}
diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums.rs
deleted file mode 100644
index f7e9c538496..00000000000
--- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums.rs
+++ /dev/null
@@ -1,53 +0,0 @@
-// run-pass
-// aux-build:enums.rs
-extern crate enums;
-
-// ignore-pretty issue #37199
-
-use enums::NonExhaustiveEnum;
-
-fn main() {
-    let enum_unit = NonExhaustiveEnum::Unit;
-
-    match enum_unit {
-        NonExhaustiveEnum::Unit => 1,
-        NonExhaustiveEnum::Tuple(_) => 2,
-        // This particular arm tests that a enum marked as non-exhaustive
-        // will not error if its variants are matched exhaustively.
-        NonExhaustiveEnum::Struct { field } => field,
-        _ => 0 // no error with wildcard
-    };
-
-    match enum_unit {
-        _ => "no error with only wildcard"
-    };
-
-
-    // issue #53549 - check that variant constructors can still be called normally.
-
-    match NonExhaustiveEnum::Unit {
-        NonExhaustiveEnum::Unit => {},
-        _ => {}
-    };
-
-    match NonExhaustiveEnum::Tuple(2) {
-        NonExhaustiveEnum::Tuple(2) => {},
-        _ => {}
-    };
-
-    match (NonExhaustiveEnum::Unit {}) {
-        NonExhaustiveEnum::Unit {} => {},
-        _ => {}
-    };
-
-    match (NonExhaustiveEnum::Tuple { 0: 2 }) {
-        NonExhaustiveEnum::Tuple { 0: 2 } => {},
-        _ => {}
-    };
-
-    match (NonExhaustiveEnum::Struct { field: 2 }) {
-        NonExhaustiveEnum::Struct { field: 2 } => {},
-        _ => {}
-    };
-
-}
diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs.rs
deleted file mode 100644
index 3cd7234269e..00000000000
--- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// run-pass
-#![allow(dead_code)]
-#![allow(unused_variables)]
-// aux-build:structs.rs
-extern crate structs;
-
-use structs::{NormalStruct, UnitStruct, TupleStruct};
-
-// We only test matching here as we cannot create non-exhaustive
-// structs from another crate. ie. they'll never pass in run-pass tests.
-
-fn match_structs(ns: NormalStruct, ts: TupleStruct, us: UnitStruct) {
-    let NormalStruct { first_field, second_field, .. } = ns;
-
-    let TupleStruct { 0: first, 1: second, .. } = ts;
-
-    let UnitStruct { .. } = us;
-}
-
-fn main() { }
diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants.rs b/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants.rs
deleted file mode 100644
index 90b8219e2a3..00000000000
--- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-// run-pass
-// aux-build:variants.rs
-extern crate variants;
-
-use variants::NonExhaustiveVariants;
-
-/*
- * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for
- * variants. See issue #44109 and PR 45394.
- */
-// ignore-test
-
-fn main() {
-    let variant_tuple = NonExhaustiveVariants::Tuple { 0: 340 };
-    let variant_struct = NonExhaustiveVariants::Struct { field: 340 };
-
-    match variant_struct {
-        NonExhaustiveVariants::Unit => "",
-        NonExhaustiveVariants::Struct { field, .. } => "",
-        NonExhaustiveVariants::Tuple(fe_tpl, ..) => ""
-    };
-}
diff --git a/src/test/ui/deref-suggestion.rs b/src/test/ui/deref-suggestion.rs
index 83e54b64f47..580410aecf4 100644
--- a/src/test/ui/deref-suggestion.rs
+++ b/src/test/ui/deref-suggestion.rs
@@ -15,6 +15,14 @@ fn foo4(u: &u32) {
     //~^ ERROR mismatched types
 }
 
+struct S<'a> {
+    u: &'a u32,
+}
+
+struct R {
+    i: u32,
+}
+
 fn main() {
     let s = String::new();
     let r_s = &s;
@@ -27,4 +35,14 @@ fn main() {
     foo4(&0);
     assert_eq!(3i32, &3i32);
     //~^ ERROR mismatched types
+    let u = 3;
+    let s = S { u };
+    //~^ ERROR mismatched types
+    let s = S { u: u };
+    //~^ ERROR mismatched types
+    let i = &4;
+    let r = R { i };
+    //~^ ERROR mismatched types
+    let r = R { i: i };
+    //~^ ERROR mismatched types
 }
diff --git a/src/test/ui/deref-suggestion.stderr b/src/test/ui/deref-suggestion.stderr
index 8f061b3416e..9c49f541c93 100644
--- a/src/test/ui/deref-suggestion.stderr
+++ b/src/test/ui/deref-suggestion.stderr
@@ -23,7 +23,7 @@ LL |     foo3(u);
               found type `&u32`
 
 error[E0308]: mismatched types
-  --> $DIR/deref-suggestion.rs:22:9
+  --> $DIR/deref-suggestion.rs:30:9
    |
 LL |     foo(&"aaa".to_owned());
    |         ^^^^^^^^^^^^^^^^^
@@ -35,7 +35,7 @@ LL |     foo(&"aaa".to_owned());
               found type `&std::string::String`
 
 error[E0308]: mismatched types
-  --> $DIR/deref-suggestion.rs:24:9
+  --> $DIR/deref-suggestion.rs:32:9
    |
 LL |     foo(&mut "aaa".to_owned());
    |         ^^^^^^^^^^^^^^^^^^^^^
@@ -59,7 +59,7 @@ LL |     foo3(borrow!(0));
               found type `&{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/deref-suggestion.rs:28:5
+  --> $DIR/deref-suggestion.rs:36:5
    |
 LL |     assert_eq!(3i32, &3i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ expected i32, found &i32
@@ -68,6 +68,54 @@ LL |     assert_eq!(3i32, &3i32);
               found type `&i32`
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
-error: aborting due to 6 previous errors
+error[E0308]: mismatched types
+  --> $DIR/deref-suggestion.rs:39:17
+   |
+LL |     let s = S { u };
+   |                 ^
+   |                 |
+   |                 expected &u32, found integer
+   |                 help: consider borrowing here: `u: &u`
+   |
+   = note: expected type `&u32`
+              found type `{integer}`
+
+error[E0308]: mismatched types
+  --> $DIR/deref-suggestion.rs:41:20
+   |
+LL |     let s = S { u: u };
+   |                    ^
+   |                    |
+   |                    expected &u32, found integer
+   |                    help: consider borrowing here: `&u`
+   |
+   = note: expected type `&u32`
+              found type `{integer}`
+
+error[E0308]: mismatched types
+  --> $DIR/deref-suggestion.rs:44:17
+   |
+LL |     let r = R { i };
+   |                 ^
+   |                 |
+   |                 expected u32, found &{integer}
+   |                 help: consider dereferencing the borrow: `i: *i`
+   |
+   = note: expected type `u32`
+              found type `&{integer}`
+
+error[E0308]: mismatched types
+  --> $DIR/deref-suggestion.rs:46:20
+   |
+LL |     let r = R { i: i };
+   |                    ^
+   |                    |
+   |                    expected u32, found &{integer}
+   |                    help: consider dereferencing the borrow: `*i`
+   |
+   = note: expected type `u32`
+              found type `&{integer}`
+
+error: aborting due to 10 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-34334.rs b/src/test/ui/issues/issue-34334.rs
index 5c4f5c86a7f..928d217441e 100644
--- a/src/test/ui/issues/issue-34334.rs
+++ b/src/test/ui/issues/issue-34334.rs
@@ -1,4 +1,10 @@
 fn main () {
-    let sr: Vec<(u32, _, _) = vec![]; //~ ERROR expected one of `,` or `>`, found `=`
+    let sr: Vec<(u32, _, _) = vec![];
+    //~^ ERROR expected one of `,` or `>`, found `=`
+    //~| ERROR expected value, found struct `Vec`
+    //~| ERROR mismatched types
+    //~| ERROR invalid left-hand side expression
+    //~| ERROR expected expression, found reserved identifier `_`
     let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
+    //~^ ERROR no method named `iter` found for type `()` in the current scope
 }
diff --git a/src/test/ui/issues/issue-34334.stderr b/src/test/ui/issues/issue-34334.stderr
index 1b0babf9390..51ea0c6a908 100644
--- a/src/test/ui/issues/issue-34334.stderr
+++ b/src/test/ui/issues/issue-34334.stderr
@@ -1,10 +1,47 @@
+error: expected expression, found reserved identifier `_`
+  --> $DIR/issue-34334.rs:2:23
+   |
+LL |     let sr: Vec<(u32, _, _) = vec![];
+   |                       ^ expected expression
+
 error: expected one of `,` or `>`, found `=`
   --> $DIR/issue-34334.rs:2:29
    |
 LL |     let sr: Vec<(u32, _, _) = vec![];
-   |         --                  ^ expected one of `,` or `>` here
-   |         |
+   |         ---                 ^ expected one of `,` or `>` here
+   |         | |
+   |         | help: use `=` if you meant to assign
    |         while parsing the type for `sr`
 
-error: aborting due to previous error
+error[E0423]: expected value, found struct `Vec`
+  --> $DIR/issue-34334.rs:2:13
+   |
+LL |     let sr: Vec<(u32, _, _) = vec![];
+   |             ^^^ did you mean `Vec { /* fields */ }`?
+
+error[E0308]: mismatched types
+  --> $DIR/issue-34334.rs:2:31
+   |
+LL |     let sr: Vec<(u32, _, _) = vec![];
+   |                               ^^^^^^ expected bool, found struct `std::vec::Vec`
+   |
+   = note: expected type `bool`
+              found type `std::vec::Vec<_>`
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error[E0070]: invalid left-hand side expression
+  --> $DIR/issue-34334.rs:2:13
+   |
+LL |     let sr: Vec<(u32, _, _) = vec![];
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ left-hand of expression not valid
+
+error[E0599]: no method named `iter` found for type `()` in the current scope
+  --> $DIR/issue-34334.rs:8:36
+   |
+LL |     let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
+   |                                    ^^^^
+
+error: aborting due to 6 previous errors
 
+Some errors occurred: E0070, E0308, E0423, E0599.
+For more information about an error, try `rustc --explain E0070`.
diff --git a/src/test/ui/parser/pat-tuple-1.rs b/src/test/ui/parser/pat-tuple-1.rs
index 213fbe371d4..0e49b547f7d 100644
--- a/src/test/ui/parser/pat-tuple-1.rs
+++ b/src/test/ui/parser/pat-tuple-1.rs
@@ -1,5 +1,5 @@
 fn main() {
-    match 0 {
+    match (0, 1) {
         (, ..) => {} //~ ERROR expected pattern, found `,`
     }
 }
diff --git a/src/test/ui/parser/pat-tuple-5.rs b/src/test/ui/parser/pat-tuple-5.rs
index 03176abaf49..d4f05a5eb52 100644
--- a/src/test/ui/parser/pat-tuple-5.rs
+++ b/src/test/ui/parser/pat-tuple-5.rs
@@ -1,5 +1,5 @@
 fn main() {
-    match 0 {
+    match (0, 1) {
         (pat ..) => {} //~ ERROR unexpected token: `)`
     }
 }
diff --git a/src/test/ui/parser/recover-from-bad-variant.rs b/src/test/ui/parser/recover-from-bad-variant.rs
new file mode 100644
index 00000000000..35088fb3068
--- /dev/null
+++ b/src/test/ui/parser/recover-from-bad-variant.rs
@@ -0,0 +1,14 @@
+enum Enum {
+    Foo { a: usize, b: usize },
+    Bar(usize, usize),
+}
+
+fn main() {
+    let x = Enum::Foo(a: 3, b: 4);
+    //~^ ERROR expected type, found `3`
+    match x {
+        Enum::Foo(a, b) => {}
+        //~^ ERROR expected tuple struct/variant, found struct variant `Enum::Foo`
+        Enum::Bar(a, b) => {}
+    }
+}
diff --git a/src/test/ui/parser/recover-from-bad-variant.stderr b/src/test/ui/parser/recover-from-bad-variant.stderr
new file mode 100644
index 00000000000..1eba6d7d528
--- /dev/null
+++ b/src/test/ui/parser/recover-from-bad-variant.stderr
@@ -0,0 +1,23 @@
+error: expected type, found `3`
+  --> $DIR/recover-from-bad-variant.rs:7:26
+   |
+LL |     let x = Enum::Foo(a: 3, b: 4);
+   |                          ^ expecting a type here because of type ascription
+   |
+   = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
+note: this expression expects an ascribed type after the colon
+  --> $DIR/recover-from-bad-variant.rs:7:23
+   |
+LL |     let x = Enum::Foo(a: 3, b: 4);
+   |                       ^
+   = help: this might be indicative of a syntax error elsewhere
+
+error[E0532]: expected tuple struct/variant, found struct variant `Enum::Foo`
+  --> $DIR/recover-from-bad-variant.rs:10:9
+   |
+LL |         Enum::Foo(a, b) => {}
+   |         ^^^^^^^^^ did you mean `Enum::Foo { /* fields */ }`?
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0532`.
diff --git a/src/test/ui/parser/recover-tuple-pat.rs b/src/test/ui/parser/recover-tuple-pat.rs
new file mode 100644
index 00000000000..488e8db6b87
--- /dev/null
+++ b/src/test/ui/parser/recover-tuple-pat.rs
@@ -0,0 +1,12 @@
+fn main() {
+    let x = (1, 2, 3, 4);
+    match x {
+        (1, .., 4) => {}
+        (1, .=., 4) => { let _: usize = ""; }
+        //~^ ERROR expected pattern, found `.`
+        //~| ERROR mismatched types
+        (.=., 4) => {}
+        //~^ ERROR expected pattern, found `.`
+        (1, 2, 3, 4) => {}
+    }
+}
diff --git a/src/test/ui/parser/recover-tuple-pat.stderr b/src/test/ui/parser/recover-tuple-pat.stderr
new file mode 100644
index 00000000000..5919aa72355
--- /dev/null
+++ b/src/test/ui/parser/recover-tuple-pat.stderr
@@ -0,0 +1,24 @@
+error: expected pattern, found `.`
+  --> $DIR/recover-tuple-pat.rs:5:13
+   |
+LL |         (1, .=., 4) => { let _: usize = ""; }
+   |             ^ expected pattern
+
+error: expected pattern, found `.`
+  --> $DIR/recover-tuple-pat.rs:8:10
+   |
+LL |         (.=., 4) => {}
+   |          ^ expected pattern
+
+error[E0308]: mismatched types
+  --> $DIR/recover-tuple-pat.rs:5:41
+   |
+LL |         (1, .=., 4) => { let _: usize = ""; }
+   |                                         ^^ expected usize, found reference
+   |
+   = note: expected type `usize`
+              found type `&'static str`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/recover-tuple.rs b/src/test/ui/parser/recover-tuple.rs
new file mode 100644
index 00000000000..59e2695dec6
--- /dev/null
+++ b/src/test/ui/parser/recover-tuple.rs
@@ -0,0 +1,11 @@
+fn main() {
+    // no complaints about the tuple not matching the expected type
+    let x: (usize, usize, usize) = (3, .=.);
+    //~^ ERROR expected expression, found `.`
+    // verify that the parser recovers:
+    let y: usize = ""; //~ ERROR mismatched types
+    // no complaints about the type
+    foo(x);
+}
+
+fn foo(_: (usize, usize, usize)) {}
diff --git a/src/test/ui/parser/recover-tuple.stderr b/src/test/ui/parser/recover-tuple.stderr
new file mode 100644
index 00000000000..4252fc1fd1e
--- /dev/null
+++ b/src/test/ui/parser/recover-tuple.stderr
@@ -0,0 +1,18 @@
+error: expected expression, found `.`
+  --> $DIR/recover-tuple.rs:3:40
+   |
+LL |     let x: (usize, usize, usize) = (3, .=.);
+   |                                        ^ expected expression
+
+error[E0308]: mismatched types
+  --> $DIR/recover-tuple.rs:6:20
+   |
+LL |     let y: usize = "";
+   |                    ^^ expected usize, found reference
+   |
+   = note: expected type `usize`
+              found type `&'static str`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/trait-object-lifetime-parens.rs b/src/test/ui/parser/trait-object-lifetime-parens.rs
index b188e14778b..43f6497f7e7 100644
--- a/src/test/ui/parser/trait-object-lifetime-parens.rs
+++ b/src/test/ui/parser/trait-object-lifetime-parens.rs
@@ -6,7 +6,10 @@ fn f<'a, T: Trait + ('a)>() {} //~ ERROR parenthesized lifetime bounds are not s
 
 fn check<'a>() {
     let _: Box<Trait + ('a)>; //~ ERROR parenthesized lifetime bounds are not supported
-    let _: Box<('a) + Trait>; //~ ERROR expected type, found `'a`
+    let _: Box<('a) + Trait>;
+    //~^ ERROR expected type, found `'a`
+    //~| ERROR expected `:`, found `)`
+    //~| ERROR chained comparison operators require parentheses
 }
 
 fn main() {}
diff --git a/src/test/ui/parser/trait-object-lifetime-parens.stderr b/src/test/ui/parser/trait-object-lifetime-parens.stderr
index 084e6d5b11f..a31b7aea8fe 100644
--- a/src/test/ui/parser/trait-object-lifetime-parens.stderr
+++ b/src/test/ui/parser/trait-object-lifetime-parens.stderr
@@ -10,6 +10,21 @@ error: parenthesized lifetime bounds are not supported
 LL |     let _: Box<Trait + ('a)>;
    |                        ^^^^ help: remove the parentheses
 
+error: expected `:`, found `)`
+  --> $DIR/trait-object-lifetime-parens.rs:9:19
+   |
+LL |     let _: Box<('a) + Trait>;
+   |                   ^ expected `:`
+
+error: chained comparison operators require parentheses
+  --> $DIR/trait-object-lifetime-parens.rs:9:15
+   |
+LL |     let _: Box<('a) + Trait>;
+   |               ^^^^^^^^^^^^^^^
+   |
+   = help: use `::<...>` instead of `<...>` if you meant to specify type arguments
+   = help: or use `(...)` if you meant to specify fn arguments
+
 error: expected type, found `'a`
   --> $DIR/trait-object-lifetime-parens.rs:9:17
    |
@@ -18,5 +33,5 @@ LL |     let _: Box<('a) + Trait>;
    |         |
    |         while parsing the type for `_`
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum.rs b/src/test/ui/rfc-2008-non-exhaustive/enum.rs
index d9b1a989510..7423a970e2e 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/enum.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum.rs
@@ -12,4 +12,48 @@ fn main() {
         NonExhaustiveEnum::Tuple(_) => "second",
         NonExhaustiveEnum::Struct { .. } => "third"
     };
+
+    // Everything below this is expected to compile successfully.
+
+    let enum_unit = NonExhaustiveEnum::Unit;
+
+    match enum_unit {
+        NonExhaustiveEnum::Unit => 1,
+        NonExhaustiveEnum::Tuple(_) => 2,
+        // This particular arm tests that a enum marked as non-exhaustive
+        // will not error if its variants are matched exhaustively.
+        NonExhaustiveEnum::Struct { field } => field,
+        _ => 0 // no error with wildcard
+    };
+
+    match enum_unit {
+        _ => "no error with only wildcard"
+    };
+
+    // #53549: Check that variant constructors can still be called normally.
+    match NonExhaustiveEnum::Unit {
+        NonExhaustiveEnum::Unit => {},
+        _ => {}
+    };
+
+    match NonExhaustiveEnum::Tuple(2) {
+        NonExhaustiveEnum::Tuple(2) => {},
+        _ => {}
+    };
+
+    match (NonExhaustiveEnum::Unit {}) {
+        NonExhaustiveEnum::Unit {} => {},
+        _ => {}
+    };
+
+    match (NonExhaustiveEnum::Tuple { 0: 2 }) {
+        NonExhaustiveEnum::Tuple { 0: 2 } => {},
+        _ => {}
+    };
+
+    match (NonExhaustiveEnum::Struct { field: 2 }) {
+        NonExhaustiveEnum::Struct { field: 2 } => {},
+        _ => {}
+    };
+
 }
diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate.rs
index 384e099275e..a3626bf60b2 100644
--- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/enums_same_crate.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate.rs
@@ -1,4 +1,5 @@
 // run-pass
+
 #![feature(non_exhaustive)]
 
 #[non_exhaustive]
diff --git a/src/test/ui/rfc-2008-non-exhaustive/structs.rs b/src/test/ui/rfc-2008-non-exhaustive/struct.rs
index 303d71d12df..94ac588d240 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/structs.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/struct.rs
@@ -35,3 +35,15 @@ fn main() {
     let UnitStruct { } = us;
     //~^ ERROR `..` required with struct marked as non-exhaustive
 }
+
+// Everything below this is expected to compile successfully.
+
+// We only test matching here as we cannot create non-exhaustive
+// structs from another crate. ie. they'll never pass in run-pass tests.
+fn match_structs(ns: NormalStruct, ts: TupleStruct, us: UnitStruct) {
+    let NormalStruct { first_field, second_field, .. } = ns;
+
+    let TupleStruct { 0: first, 1: second, .. } = ts;
+
+    let UnitStruct { .. } = us;
+}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/structs.stderr b/src/test/ui/rfc-2008-non-exhaustive/struct.stderr
index 6213c392a9b..ecfad88a825 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/structs.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/struct.stderr
@@ -1,29 +1,29 @@
 error[E0423]: expected function, found struct `TupleStruct`
-  --> $DIR/structs.rs:20:14
+  --> $DIR/struct.rs:20:14
    |
 LL |     let ts = TupleStruct(640, 480);
    |              ^^^^^^^^^^^ constructor is not visible here due to private fields
 
 error[E0423]: expected value, found struct `UnitStruct`
-  --> $DIR/structs.rs:29:14
+  --> $DIR/struct.rs:29:14
    |
 LL |     let us = UnitStruct;
    |              ^^^^^^^^^^ constructor is not visible here due to private fields
 
 error[E0603]: tuple struct `TupleStruct` is private
-  --> $DIR/structs.rs:23:32
+  --> $DIR/struct.rs:23:32
    |
 LL |     let ts_explicit = structs::TupleStruct(640, 480);
    |                                ^^^^^^^^^^^
 
 error[E0603]: unit struct `UnitStruct` is private
-  --> $DIR/structs.rs:32:32
+  --> $DIR/struct.rs:32:32
    |
 LL |     let us_explicit = structs::UnitStruct;
    |                                ^^^^^^^^^^
 
 error[E0639]: cannot create non-exhaustive struct using struct expression
-  --> $DIR/structs.rs:7:14
+  --> $DIR/struct.rs:7:14
    |
 LL |       let fr = FunctionalRecord {
    |  ______________^
@@ -35,25 +35,25 @@ LL | |     };
    | |_____^
 
 error[E0639]: cannot create non-exhaustive struct using struct expression
-  --> $DIR/structs.rs:14:14
+  --> $DIR/struct.rs:14:14
    |
 LL |     let ns = NormalStruct { first_field: 640, second_field: 480 };
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0638]: `..` required with struct marked as non-exhaustive
-  --> $DIR/structs.rs:17:9
+  --> $DIR/struct.rs:17:9
    |
 LL |     let NormalStruct { first_field, second_field } = ns;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0638]: `..` required with struct marked as non-exhaustive
-  --> $DIR/structs.rs:26:9
+  --> $DIR/struct.rs:26:9
    |
 LL |     let TupleStruct { 0: first_field, 1: second_field } = ts;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0638]: `..` required with struct marked as non-exhaustive
-  --> $DIR/structs.rs:35:9
+  --> $DIR/struct.rs:35:9
    |
 LL |     let UnitStruct { } = us;
    |         ^^^^^^^^^^^^^^
diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/structs_same_crate.rs
index 5e71cce1297..2b1d7d9ac50 100644
--- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/structs_same_crate.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/structs_same_crate.rs
@@ -1,4 +1,5 @@
 // run-pass
+
 #![allow(unused_variables)]
 #![feature(non_exhaustive)]
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/variants.rs b/src/test/ui/rfc-2008-non-exhaustive/variant.rs
index 373bbc3547f..bc346aea51c 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/variants.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/variant.rs
@@ -1,26 +1,33 @@
 // aux-build:variants.rs
+
 extern crate variants;
 
 use variants::NonExhaustiveVariants;
 
-/*
- * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for
- * variants. See issue #44109 and PR 45394.
- */
-// ignore-test
-
 fn main() {
     let variant_struct = NonExhaustiveVariants::Struct { field: 640 };
     //~^ ERROR cannot create non-exhaustive variant
 
-    let variant_tuple = NonExhaustiveVariants::Tuple { 0: 640 };
-    //~^ ERROR cannot create non-exhaustive variant
+    let variant_tuple = NonExhaustiveVariants::Tuple(640);
+    //~^ ERROR tuple variant `Tuple` is private [E0603]
+
+    let variant_unit = NonExhaustiveVariants::Unit;
+    //~^ ERROR unit variant `Unit` is private [E0603]
 
     match variant_struct {
         NonExhaustiveVariants::Unit => "",
+        //~^ ERROR unit variant `Unit` is private [E0603]
         NonExhaustiveVariants::Tuple(fe_tpl) => "",
-        //~^ ERROR `..` required with variant marked as non-exhaustive
+        //~^ ERROR tuple variant `Tuple` is private [E0603]
         NonExhaustiveVariants::Struct { field } => ""
         //~^ ERROR `..` required with variant marked as non-exhaustive
     };
+
+    if let NonExhaustiveVariants::Tuple(fe_tpl) = variant_struct {
+        //~^ ERROR tuple variant `Tuple` is private [E0603]
+    }
+
+    if let NonExhaustiveVariants::Struct { field } = variant_struct {
+        //~^ ERROR `..` required with variant marked as non-exhaustive
+    }
 }
diff --git a/src/test/ui/rfc-2008-non-exhaustive/variant.stderr b/src/test/ui/rfc-2008-non-exhaustive/variant.stderr
new file mode 100644
index 00000000000..edfca789150
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/variant.stderr
@@ -0,0 +1,52 @@
+error[E0603]: tuple variant `Tuple` is private
+  --> $DIR/variant.rs:11:48
+   |
+LL |     let variant_tuple = NonExhaustiveVariants::Tuple(640);
+   |                                                ^^^^^
+
+error[E0603]: unit variant `Unit` is private
+  --> $DIR/variant.rs:14:47
+   |
+LL |     let variant_unit = NonExhaustiveVariants::Unit;
+   |                                               ^^^^
+
+error[E0603]: unit variant `Unit` is private
+  --> $DIR/variant.rs:18:32
+   |
+LL |         NonExhaustiveVariants::Unit => "",
+   |                                ^^^^
+
+error[E0603]: tuple variant `Tuple` is private
+  --> $DIR/variant.rs:20:32
+   |
+LL |         NonExhaustiveVariants::Tuple(fe_tpl) => "",
+   |                                ^^^^^
+
+error[E0603]: tuple variant `Tuple` is private
+  --> $DIR/variant.rs:26:35
+   |
+LL |     if let NonExhaustiveVariants::Tuple(fe_tpl) = variant_struct {
+   |                                   ^^^^^
+
+error[E0639]: cannot create non-exhaustive variant using struct expression
+  --> $DIR/variant.rs:8:26
+   |
+LL |     let variant_struct = NonExhaustiveVariants::Struct { field: 640 };
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0638]: `..` required with variant marked as non-exhaustive
+  --> $DIR/variant.rs:22:9
+   |
+LL |         NonExhaustiveVariants::Struct { field } => ""
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0638]: `..` required with variant marked as non-exhaustive
+  --> $DIR/variant.rs:30:12
+   |
+LL |     if let NonExhaustiveVariants::Struct { field } = variant_struct {
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
+
+Some errors occurred: E0603, E0638, E0639.
+For more information about an error, try `rustc --explain E0603`.
diff --git a/src/test/ui/rfc-2008-non-exhaustive/variants_create.rs b/src/test/ui/rfc-2008-non-exhaustive/variants_create.rs
deleted file mode 100644
index 9ed244144df..00000000000
--- a/src/test/ui/rfc-2008-non-exhaustive/variants_create.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-#![feature(non_exhaustive)]
-
-/*
- * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for
- * variants. See issue #44109 and PR 45394.
- */
-
-pub enum NonExhaustiveVariants {
-    #[non_exhaustive] Unit,
-    //~^ ERROR #[non_exhaustive] is not yet supported on variants
-    #[non_exhaustive] Tuple(u32),
-    //~^ ERROR #[non_exhaustive] is not yet supported on variants
-    #[non_exhaustive] Struct { field: u32 }
-    //~^ ERROR #[non_exhaustive] is not yet supported on variants
-}
-
-fn main() { }
diff --git a/src/test/ui/rfc-2008-non-exhaustive/variants_create.stderr b/src/test/ui/rfc-2008-non-exhaustive/variants_create.stderr
deleted file mode 100644
index 5b099d58ec4..00000000000
--- a/src/test/ui/rfc-2008-non-exhaustive/variants_create.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error: #[non_exhaustive] is not yet supported on variants
-  --> $DIR/variants_create.rs:9:23
-   |
-LL |     #[non_exhaustive] Unit,
-   |                       ^^^^
-
-error: #[non_exhaustive] is not yet supported on variants
-  --> $DIR/variants_create.rs:11:23
-   |
-LL |     #[non_exhaustive] Tuple(u32),
-   |                       ^^^^^^^^^^
-
-error: #[non_exhaustive] is not yet supported on variants
-  --> $DIR/variants_create.rs:13:23
-   |
-LL |     #[non_exhaustive] Struct { field: u32 }
-   |                       ^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
-
diff --git a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/variants_same_crate.rs
index 603e69b9ff9..470a5ea9833 100644
--- a/src/test/run-pass/rfcs/rfc-2008-non-exhaustive/variants_same_crate.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/variants_same_crate.rs
@@ -1,11 +1,6 @@
 // run-pass
-#![feature(non_exhaustive)]
 
-/*
- * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for
- * variants. See issue #44109 and PR 45394.
- */
-// ignore-test
+#![feature(non_exhaustive)]
 
 pub enum NonExhaustiveVariants {
     #[non_exhaustive] Unit,