about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-03-12 21:34:30 +0000
committerbors <bors@rust-lang.org>2022-03-12 21:34:30 +0000
commitbbbd48fa6d3c28d782f7008846ac2a603f95b39a (patch)
tree4e53670d4d95de3ccd914f75bbe8594e3e72e76e
parentf103b2969b0088953873dc1ac92eb3387c753596 (diff)
parent492d8d72936685726066ef0f0f0a9d935f537eee (diff)
downloadrust-bbbd48fa6d3c28d782f7008846ac2a603f95b39a.tar.gz
rust-bbbd48fa6d3c28d782f7008846ac2a603f95b39a.zip
Auto merge of #90358 - DevinR528:omitted-field-fix, r=jackh726
Fix exposing fields marked unstable or doc hidden

Closes https://github.com/rust-lang/rust/issues/89837

Work towards https://github.com/rust-lang/rust/issues/89554

Filter fields that are marked `doc(hidden)` or are unstable with that feature turned off. This brings structs and enums into alignment behavior-wise when emitting warning/errors about pattern exhaustiveness/reachability.

cc `@Nadrieril`
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs6
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs7
-rw-r--r--src/test/ui/pattern/usefulness/auxiliary/hidden.rs10
-rw-r--r--src/test/ui/pattern/usefulness/auxiliary/unstable.rs13
-rw-r--r--src/test/ui/pattern/usefulness/doc-hidden-fields.rs26
-rw-r--r--src/test/ui/pattern/usefulness/doc-hidden-fields.stderr59
-rw-r--r--src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs33
-rw-r--r--src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr73
-rw-r--r--src/test/ui/pattern/usefulness/stable-gated-fields.rs16
-rw-r--r--src/test/ui/pattern/usefulness/stable-gated-fields.stderr29
-rw-r--r--src/test/ui/pattern/usefulness/stable-gated-patterns.rs12
-rw-r--r--src/test/ui/pattern/usefulness/stable-gated-patterns.stderr24
-rw-r--r--src/test/ui/pattern/usefulness/unstable-gated-fields.rs18
-rw-r--r--src/test/ui/pattern/usefulness/unstable-gated-fields.stderr33
-rw-r--r--src/test/ui/pattern/usefulness/unstable-gated-patterns.rs16
-rw-r--r--src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr12
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/auxiliary/unstable.rs31
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.rs19
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr34
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.rs14
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr16
21 files changed, 422 insertions, 79 deletions
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index 61f1069d571..612bed639bf 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -692,11 +692,11 @@ impl<'tcx> Constructor<'tcx> {
     }
 
     /// Checks if the `Constructor` is a `Constructor::Variant` with a `#[doc(hidden)]`
-    /// attribute.
+    /// attribute from a type not local to the current crate.
     pub(super) fn is_doc_hidden_variant(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> bool {
         if let Constructor::Variant(idx) = self && let ty::Adt(adt, _) = pcx.ty.kind() {
-            let variant_def_id = adt.variant(*idx).def_id;
-            return pcx.cx.tcx.is_doc_hidden(variant_def_id);
+            let variant_def_id = adt.variants()[*idx].def_id;
+            return pcx.cx.tcx.is_doc_hidden(variant_def_id) && !variant_def_id.is_local();
         }
         false
     }
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index 26a1d0c473c..a264ee5d147 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -11,6 +11,7 @@ use rustc_hir::pat_util::EnumerateAndAdjustIterator;
 use rustc_hir::{HirId, Pat, PatKind};
 use rustc_infer::infer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_middle::middle::stability::EvalResult;
 use rustc_middle::ty::{self, Adt, BindingMode, Ty, TypeFoldable};
 use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
 use rustc_span::hygiene::DesugaringKind;
@@ -1308,6 +1309,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .copied()
                 .filter(|(field, _)| {
                     field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx)
+                        && !matches!(
+                            tcx.eval_stability(field.did, None, DUMMY_SP, None),
+                            EvalResult::Deny { .. }
+                        )
+                        // We only want to report the error if it is hidden and not local
+                        && !(tcx.is_doc_hidden(field.did) && !field.did.is_local())
                 })
                 .collect();
 
diff --git a/src/test/ui/pattern/usefulness/auxiliary/hidden.rs b/src/test/ui/pattern/usefulness/auxiliary/hidden.rs
index 742b7e82c16..364514ba1d3 100644
--- a/src/test/ui/pattern/usefulness/auxiliary/hidden.rs
+++ b/src/test/ui/pattern/usefulness/auxiliary/hidden.rs
@@ -1,6 +1,14 @@
-pub enum Foo {
+pub enum HiddenEnum {
     A,
     B,
     #[doc(hidden)]
     C,
 }
+
+#[derive(Default)]
+pub struct HiddenStruct {
+    pub one: u8,
+    pub two: bool,
+    #[doc(hidden)]
+    pub hide: usize,
+}
diff --git a/src/test/ui/pattern/usefulness/auxiliary/unstable.rs b/src/test/ui/pattern/usefulness/auxiliary/unstable.rs
index 3142489c861..a06b3a6e4e5 100644
--- a/src/test/ui/pattern/usefulness/auxiliary/unstable.rs
+++ b/src/test/ui/pattern/usefulness/auxiliary/unstable.rs
@@ -2,7 +2,7 @@
 #![stable(feature = "stable_test_feature", since = "1.0.0")]
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-pub enum Foo {
+pub enum UnstableEnum {
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
     Stable,
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
@@ -10,3 +10,14 @@ pub enum Foo {
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     Unstable,
 }
+
+#[derive(Default)]
+#[stable(feature = "stable_test_feature", since = "1.0.0")]
+pub struct UnstableStruct {
+    #[stable(feature = "stable_test_feature", since = "1.0.0")]
+    pub stable: bool,
+    #[stable(feature = "stable_test_feature", since = "1.0.0")]
+    pub stable2: usize,
+    #[unstable(feature = "unstable_test_feature", issue = "none")]
+    pub unstable: u8,
+}
diff --git a/src/test/ui/pattern/usefulness/doc-hidden-fields.rs b/src/test/ui/pattern/usefulness/doc-hidden-fields.rs
new file mode 100644
index 00000000000..4163b87dc85
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/doc-hidden-fields.rs
@@ -0,0 +1,26 @@
+// aux-build:hidden.rs
+
+extern crate hidden;
+
+use hidden::HiddenStruct;
+
+struct InCrate {
+    a: usize,
+    b: bool,
+    #[doc(hidden)]
+    im_hidden: u8
+}
+
+fn main() {
+    let HiddenStruct { one, two } = HiddenStruct::default();
+    //~^ pattern requires `..` due to inaccessible fields
+
+    let HiddenStruct { one } = HiddenStruct::default();
+    //~^ pattern does not mention field `two` and inaccessible fields
+
+    let HiddenStruct { one, hide } = HiddenStruct::default();
+    //~^ pattern does not mention field `two`
+
+    let InCrate { a, b } = InCrate { a: 0, b: false, im_hidden: 0 };
+    //~^ pattern does not mention field `im_hidden`
+}
diff --git a/src/test/ui/pattern/usefulness/doc-hidden-fields.stderr b/src/test/ui/pattern/usefulness/doc-hidden-fields.stderr
new file mode 100644
index 00000000000..f277bfbc884
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/doc-hidden-fields.stderr
@@ -0,0 +1,59 @@
+error: pattern requires `..` due to inaccessible fields
+  --> $DIR/doc-hidden-fields.rs:15:9
+   |
+LL |     let HiddenStruct { one, two } = HiddenStruct::default();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: ignore the inaccessible and unused fields
+   |
+LL |     let HiddenStruct { one, two, .. } = HiddenStruct::default();
+   |                                ++++
+
+error[E0027]: pattern does not mention field `two` and inaccessible fields
+  --> $DIR/doc-hidden-fields.rs:18:9
+   |
+LL |     let HiddenStruct { one } = HiddenStruct::default();
+   |         ^^^^^^^^^^^^^^^^^^^^ missing field `two` and inaccessible fields
+   |
+help: include the missing field in the pattern and ignore the inaccessible fields
+   |
+LL |     let HiddenStruct { one, two, .. } = HiddenStruct::default();
+   |                           ~~~~~~~~~~~
+help: if you don't care about this missing field, you can explicitly ignore it
+   |
+LL |     let HiddenStruct { one, .. } = HiddenStruct::default();
+   |                           ~~~~~~
+
+error[E0027]: pattern does not mention field `two`
+  --> $DIR/doc-hidden-fields.rs:21:9
+   |
+LL |     let HiddenStruct { one, hide } = HiddenStruct::default();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `two`
+   |
+help: include the missing field in the pattern
+   |
+LL |     let HiddenStruct { one, hide, two } = HiddenStruct::default();
+   |                                 ~~~~~~~
+help: if you don't care about this missing field, you can explicitly ignore it
+   |
+LL |     let HiddenStruct { one, hide, .. } = HiddenStruct::default();
+   |                                 ~~~~~~
+
+error[E0027]: pattern does not mention field `im_hidden`
+  --> $DIR/doc-hidden-fields.rs:24:9
+   |
+LL |     let InCrate { a, b } = InCrate { a: 0, b: false, im_hidden: 0 };
+   |         ^^^^^^^^^^^^^^^^ missing field `im_hidden`
+   |
+help: include the missing field in the pattern
+   |
+LL |     let InCrate { a, b, im_hidden } = InCrate { a: 0, b: false, im_hidden: 0 };
+   |                       ~~~~~~~~~~~~~
+help: if you don't care about this missing field, you can explicitly ignore it
+   |
+LL |     let InCrate { a, b, .. } = InCrate { a: 0, b: false, im_hidden: 0 };
+   |                       ~~~~~~
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0027`.
diff --git a/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs b/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs
index a1dcab09314..d968c48fb1a 100644
--- a/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs
+++ b/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs
@@ -2,29 +2,42 @@
 
 extern crate hidden;
 
-use hidden::Foo;
+use hidden::HiddenEnum;
+
+enum InCrate {
+    A,
+    B,
+    #[doc(hidden)]
+    C,
+}
 
 fn main() {
-    match Foo::A {
-        Foo::A => {}
-        Foo::B => {}
+    match HiddenEnum::A {
+        HiddenEnum::A => {}
+        HiddenEnum::B => {}
     }
     //~^^^^ non-exhaustive patterns: `_` not covered
 
-    match Foo::A {
-        Foo::A => {}
-        Foo::C => {}
+    match HiddenEnum::A {
+        HiddenEnum::A => {}
+        HiddenEnum::C => {}
     }
     //~^^^^ non-exhaustive patterns: `B` not covered
 
-    match Foo::A {
-        Foo::A => {}
+    match HiddenEnum::A {
+        HiddenEnum::A => {}
     }
     //~^^^ non-exhaustive patterns: `B` and `_` not covered
 
     match None {
         None => {}
-        Some(Foo::A) => {}
+        Some(HiddenEnum::A) => {}
     }
     //~^^^^ non-exhaustive patterns: `Some(B)` and `Some(_)` not covered
+
+    match InCrate::A {
+        InCrate::A => {}
+        InCrate::B => {}
+    }
+    //~^^^^ non-exhaustive patterns: `C` not covered
 }
diff --git a/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr b/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr
index 7d0b71a497e..296465eb818 100644
--- a/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr
+++ b/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr
@@ -1,36 +1,36 @@
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/doc-hidden-non-exhaustive.rs:8:11
+  --> $DIR/doc-hidden-non-exhaustive.rs:15:11
    |
-LL |     match Foo::A {
-   |           ^^^^^^ pattern `_` not covered
+LL |     match HiddenEnum::A {
+   |           ^^^^^^^^^^^^^ pattern `_` not covered
    |
-note: `Foo` defined here
+note: `HiddenEnum` defined here
   --> $DIR/auxiliary/hidden.rs:1:1
    |
-LL | / pub enum Foo {
+LL | / pub enum HiddenEnum {
 LL | |     A,
 LL | |     B,
 LL | |     #[doc(hidden)]
 LL | |     C,
 LL | | }
    | |_^
-   = note: the matched value is of type `Foo`
+   = note: the matched value is of type `HiddenEnum`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         Foo::B => {}
+LL ~         HiddenEnum::B => {}
 LL +         _ => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `B` not covered
-  --> $DIR/doc-hidden-non-exhaustive.rs:14:11
+  --> $DIR/doc-hidden-non-exhaustive.rs:21:11
    |
-LL |     match Foo::A {
-   |           ^^^^^^ pattern `B` not covered
+LL |     match HiddenEnum::A {
+   |           ^^^^^^^^^^^^^ pattern `B` not covered
    |
-note: `Foo` defined here
+note: `HiddenEnum` defined here
   --> $DIR/auxiliary/hidden.rs:3:5
    |
-LL | / pub enum Foo {
+LL | / pub enum HiddenEnum {
 LL | |     A,
 LL | |     B,
    | |     ^ not covered
@@ -38,23 +38,23 @@ LL | |     #[doc(hidden)]
 LL | |     C,
 LL | | }
    | |_-
-   = note: the matched value is of type `Foo`
+   = note: the matched value is of type `HiddenEnum`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         Foo::C => {}
+LL ~         HiddenEnum::C => {}
 LL +         B => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `B` and `_` not covered
-  --> $DIR/doc-hidden-non-exhaustive.rs:20:11
+  --> $DIR/doc-hidden-non-exhaustive.rs:27:11
    |
-LL |     match Foo::A {
-   |           ^^^^^^ patterns `B` and `_` not covered
+LL |     match HiddenEnum::A {
+   |           ^^^^^^^^^^^^^ patterns `B` and `_` not covered
    |
-note: `Foo` defined here
+note: `HiddenEnum` defined here
   --> $DIR/auxiliary/hidden.rs:3:5
    |
-LL | / pub enum Foo {
+LL | / pub enum HiddenEnum {
 LL | |     A,
 LL | |     B,
    | |     ^ not covered
@@ -62,20 +62,20 @@ LL | |     #[doc(hidden)]
 LL | |     C,
 LL | | }
    | |_-
-   = note: the matched value is of type `Foo`
+   = note: the matched value is of type `HiddenEnum`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
-LL ~         Foo::A => {}
+LL ~         HiddenEnum::A => {}
 LL +         B | _ => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `Some(B)` and `Some(_)` not covered
-  --> $DIR/doc-hidden-non-exhaustive.rs:25:11
+  --> $DIR/doc-hidden-non-exhaustive.rs:32:11
    |
 LL |     match None {
    |           ^^^^ patterns `Some(B)` and `Some(_)` not covered
    |
-note: `Option<Foo>` defined here
+note: `Option<HiddenEnum>` defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
    |
 LL | / pub enum Option<T> {
@@ -87,13 +87,34 @@ LL | |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
    | |     ^^^^ not covered
 LL | | }
    | |_-
-   = note: the matched value is of type `Option<Foo>`
+   = note: the matched value is of type `Option<HiddenEnum>`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
-LL ~         Some(Foo::A) => {}
+LL ~         Some(HiddenEnum::A) => {}
 LL +         Some(B) | Some(_) => todo!()
    |
 
-error: aborting due to 4 previous errors
+error[E0004]: non-exhaustive patterns: `C` not covered
+  --> $DIR/doc-hidden-non-exhaustive.rs:38:11
+   |
+LL |     match InCrate::A {
+   |           ^^^^^^^^^^ pattern `C` not covered
+   |
+note: `InCrate` defined here
+  --> $DIR/doc-hidden-non-exhaustive.rs:11:5
+   |
+LL | enum InCrate {
+   |      -------
+...
+LL |     C,
+   |     ^ not covered
+   = note: the matched value is of type `InCrate`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         InCrate::B => {}
+LL +         C => todo!()
+   |
+
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/pattern/usefulness/stable-gated-fields.rs b/src/test/ui/pattern/usefulness/stable-gated-fields.rs
new file mode 100644
index 00000000000..90f40a8d629
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/stable-gated-fields.rs
@@ -0,0 +1,16 @@
+// aux-build:unstable.rs
+
+extern crate unstable;
+
+use unstable::UnstableStruct;
+
+fn main() {
+    let UnstableStruct { stable } = UnstableStruct::default();
+    //~^ pattern does not mention field `stable2` and inaccessible fields
+
+    let UnstableStruct { stable, stable2 } = UnstableStruct::default();
+    //~^ pattern requires `..` due to inaccessible fields
+
+    // OK: stable field is matched
+    let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
+}
diff --git a/src/test/ui/pattern/usefulness/stable-gated-fields.stderr b/src/test/ui/pattern/usefulness/stable-gated-fields.stderr
new file mode 100644
index 00000000000..cf98c51a2b4
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/stable-gated-fields.stderr
@@ -0,0 +1,29 @@
+error[E0027]: pattern does not mention field `stable2` and inaccessible fields
+  --> $DIR/stable-gated-fields.rs:8:9
+   |
+LL |     let UnstableStruct { stable } = UnstableStruct::default();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `stable2` and inaccessible fields
+   |
+help: include the missing field in the pattern and ignore the inaccessible fields
+   |
+LL |     let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
+   |                                ~~~~~~~~~~~~~~~
+help: if you don't care about this missing field, you can explicitly ignore it
+   |
+LL |     let UnstableStruct { stable, .. } = UnstableStruct::default();
+   |                                ~~~~~~
+
+error: pattern requires `..` due to inaccessible fields
+  --> $DIR/stable-gated-fields.rs:11:9
+   |
+LL |     let UnstableStruct { stable, stable2 } = UnstableStruct::default();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: ignore the inaccessible and unused fields
+   |
+LL |     let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
+   |                                         ++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0027`.
diff --git a/src/test/ui/pattern/usefulness/stable-gated-patterns.rs b/src/test/ui/pattern/usefulness/stable-gated-patterns.rs
index 2e023a3be4a..ff1c472e24f 100644
--- a/src/test/ui/pattern/usefulness/stable-gated-patterns.rs
+++ b/src/test/ui/pattern/usefulness/stable-gated-patterns.rs
@@ -2,17 +2,17 @@
 
 extern crate unstable;
 
-use unstable::Foo;
+use unstable::UnstableEnum;
 
 fn main() {
-    match Foo::Stable {
-        Foo::Stable => {}
+    match UnstableEnum::Stable {
+        UnstableEnum::Stable => {}
     }
     //~^^^ non-exhaustive patterns: `Stable2` and `_` not covered
 
-    match Foo::Stable {
-        Foo::Stable => {}
-        Foo::Stable2 => {}
+    match UnstableEnum::Stable {
+        UnstableEnum::Stable => {}
+        UnstableEnum::Stable2 => {}
     }
     //~^^^^ non-exhaustive patterns: `_` not covered
 }
diff --git a/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr b/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr
index 696ef9d8de9..559539178cb 100644
--- a/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr
+++ b/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr
@@ -1,13 +1,13 @@
 error[E0004]: non-exhaustive patterns: `Stable2` and `_` not covered
   --> $DIR/stable-gated-patterns.rs:8:11
    |
-LL |     match Foo::Stable {
-   |           ^^^^^^^^^^^ patterns `Stable2` and `_` not covered
+LL |     match UnstableEnum::Stable {
+   |           ^^^^^^^^^^^^^^^^^^^^ patterns `Stable2` and `_` not covered
    |
-note: `Foo` defined here
+note: `UnstableEnum` defined here
   --> $DIR/auxiliary/unstable.rs:9:5
    |
-LL | / pub enum Foo {
+LL | / pub enum UnstableEnum {
 LL | |     #[stable(feature = "stable_test_feature", since = "1.0.0")]
 LL | |     Stable,
 LL | |     #[stable(feature = "stable_test_feature", since = "1.0.0")]
@@ -17,23 +17,23 @@ LL | |     #[unstable(feature = "unstable_test_feature", issue = "none")]
 LL | |     Unstable,
 LL | | }
    | |_-
-   = note: the matched value is of type `Foo`
+   = note: the matched value is of type `UnstableEnum`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
-LL ~         Foo::Stable => {}
+LL ~         UnstableEnum::Stable => {}
 LL +         Stable2 | _ => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/stable-gated-patterns.rs:13:11
    |
-LL |     match Foo::Stable {
-   |           ^^^^^^^^^^^ pattern `_` not covered
+LL |     match UnstableEnum::Stable {
+   |           ^^^^^^^^^^^^^^^^^^^^ pattern `_` not covered
    |
-note: `Foo` defined here
+note: `UnstableEnum` defined here
   --> $DIR/auxiliary/unstable.rs:5:1
    |
-LL | / pub enum Foo {
+LL | / pub enum UnstableEnum {
 LL | |     #[stable(feature = "stable_test_feature", since = "1.0.0")]
 LL | |     Stable,
 LL | |     #[stable(feature = "stable_test_feature", since = "1.0.0")]
@@ -41,10 +41,10 @@ LL | |     #[stable(feature = "stable_test_feature", since = "1.0.0")]
 LL | |     Unstable,
 LL | | }
    | |_^
-   = note: the matched value is of type `Foo`
+   = note: the matched value is of type `UnstableEnum`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         Foo::Stable2 => {}
+LL ~         UnstableEnum::Stable2 => {}
 LL +         _ => todo!()
    |
 
diff --git a/src/test/ui/pattern/usefulness/unstable-gated-fields.rs b/src/test/ui/pattern/usefulness/unstable-gated-fields.rs
new file mode 100644
index 00000000000..2b473ae989b
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/unstable-gated-fields.rs
@@ -0,0 +1,18 @@
+#![feature(unstable_test_feature)]
+
+// aux-build:unstable.rs
+
+extern crate unstable;
+
+use unstable::UnstableStruct;
+
+fn main() {
+    let UnstableStruct { stable, stable2, } = UnstableStruct::default();
+    //~^ pattern does not mention field `unstable`
+
+    let UnstableStruct { stable, unstable, } = UnstableStruct::default();
+    //~^ pattern does not mention field `stable2`
+
+    // OK: stable field is matched
+    let UnstableStruct { stable, stable2, unstable } = UnstableStruct::default();
+}
diff --git a/src/test/ui/pattern/usefulness/unstable-gated-fields.stderr b/src/test/ui/pattern/usefulness/unstable-gated-fields.stderr
new file mode 100644
index 00000000000..e4f5fa06b3f
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/unstable-gated-fields.stderr
@@ -0,0 +1,33 @@
+error[E0027]: pattern does not mention field `unstable`
+  --> $DIR/unstable-gated-fields.rs:10:9
+   |
+LL |     let UnstableStruct { stable, stable2, } = UnstableStruct::default();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `unstable`
+   |
+help: include the missing field in the pattern
+   |
+LL |     let UnstableStruct { stable, stable2, unstable } = UnstableStruct::default();
+   |                                         ~~~~~~~~~~~~
+help: if you don't care about this missing field, you can explicitly ignore it
+   |
+LL |     let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
+   |                                         ~~~~~~
+
+error[E0027]: pattern does not mention field `stable2`
+  --> $DIR/unstable-gated-fields.rs:13:9
+   |
+LL |     let UnstableStruct { stable, unstable, } = UnstableStruct::default();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `stable2`
+   |
+help: include the missing field in the pattern
+   |
+LL |     let UnstableStruct { stable, unstable, stable2 } = UnstableStruct::default();
+   |                                          ~~~~~~~~~~~
+help: if you don't care about this missing field, you can explicitly ignore it
+   |
+LL |     let UnstableStruct { stable, unstable, .. } = UnstableStruct::default();
+   |                                          ~~~~~~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0027`.
diff --git a/src/test/ui/pattern/usefulness/unstable-gated-patterns.rs b/src/test/ui/pattern/usefulness/unstable-gated-patterns.rs
index b9804b0ffe7..bdab327fd57 100644
--- a/src/test/ui/pattern/usefulness/unstable-gated-patterns.rs
+++ b/src/test/ui/pattern/usefulness/unstable-gated-patterns.rs
@@ -4,19 +4,19 @@
 
 extern crate unstable;
 
-use unstable::Foo;
+use unstable::UnstableEnum;
 
 fn main() {
-    match Foo::Stable {
-        Foo::Stable => {}
-        Foo::Stable2 => {}
+    match UnstableEnum::Stable {
+        UnstableEnum::Stable => {}
+        UnstableEnum::Stable2 => {}
     }
     //~^^^^ non-exhaustive patterns: `Unstable` not covered
 
     // Ok: all variants are explicitly matched
-    match Foo::Stable {
-        Foo::Stable => {}
-        Foo::Stable2 => {}
-        Foo::Unstable => {}
+    match UnstableEnum::Stable {
+        UnstableEnum::Stable => {}
+        UnstableEnum::Stable2 => {}
+        UnstableEnum::Unstable => {}
     }
 }
diff --git a/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr b/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr
index 8487c9725da..b5f1805deef 100644
--- a/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr
+++ b/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr
@@ -1,13 +1,13 @@
 error[E0004]: non-exhaustive patterns: `Unstable` not covered
   --> $DIR/unstable-gated-patterns.rs:10:11
    |
-LL |     match Foo::Stable {
-   |           ^^^^^^^^^^^ pattern `Unstable` not covered
+LL |     match UnstableEnum::Stable {
+   |           ^^^^^^^^^^^^^^^^^^^^ pattern `Unstable` not covered
    |
-note: `Foo` defined here
+note: `UnstableEnum` defined here
   --> $DIR/auxiliary/unstable.rs:11:5
    |
-LL | / pub enum Foo {
+LL | / pub enum UnstableEnum {
 LL | |     #[stable(feature = "stable_test_feature", since = "1.0.0")]
 LL | |     Stable,
 LL | |     #[stable(feature = "stable_test_feature", since = "1.0.0")]
@@ -16,10 +16,10 @@ LL | |     Unstable,
    | |     ^^^^^^^^ not covered
 LL | | }
    | |_-
-   = note: the matched value is of type `Foo`
+   = note: the matched value is of type `UnstableEnum`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         Foo::Stable2 => {}
+LL ~         UnstableEnum::Stable2 => {}
 LL +         Unstable => todo!()
    |
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/unstable.rs b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/unstable.rs
index de9d6f65945..11df44461e3 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/unstable.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/unstable.rs
@@ -27,3 +27,34 @@ impl OnlyUnstableEnum {
         Self::Unstable
     }
 }
+
+#[derive(Default)]
+#[stable(feature = "stable_test_feature", since = "1.0.0")]
+#[non_exhaustive]
+pub struct UnstableStruct {
+    #[stable(feature = "stable_test_feature", since = "1.0.0")]
+    pub stable: bool,
+    #[stable(feature = "stable_test_feature", since = "1.0.0")]
+    pub stable2: usize,
+    #[unstable(feature = "unstable_test_feature", issue = "none")]
+    pub unstable: u8,
+}
+
+#[stable(feature = "stable_test_feature", since = "1.0.0")]
+#[non_exhaustive]
+pub struct OnlyUnstableStruct {
+    #[unstable(feature = "unstable_test_feature", issue = "none")]
+    pub unstable: u8,
+    #[unstable(feature = "unstable_test_feature", issue = "none")]
+    pub unstable2: bool,
+}
+
+impl OnlyUnstableStruct {
+    #[stable(feature = "stable_test_feature", since = "1.0.0")]
+    pub fn new() -> Self {
+        Self {
+            unstable: 0,
+            unstable2: false,
+        }
+    }
+}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.rs
index fe9734fdc08..d8f07bb8f24 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.rs
@@ -13,7 +13,7 @@ use enums::{
     EmptyNonExhaustiveEnum, NestedNonExhaustive, NonExhaustiveEnum, NonExhaustiveSingleVariant,
     VariantNonExhaustive,
 };
-use unstable::{UnstableEnum, OnlyUnstableEnum};
+use unstable::{UnstableEnum, OnlyUnstableEnum, UnstableStruct, OnlyUnstableStruct};
 use structs::{FunctionalRecord, MixedVisFields, NestedStruct, NormalStruct};
 
 #[non_exhaustive]
@@ -145,6 +145,7 @@ fn main() {
     }
     //~^^ some variants are not matched explicitly
 
+    // Ok: the feature is on and all variants are matched
     #[deny(non_exhaustive_omitted_patterns)]
     match UnstableEnum::Stable {
         UnstableEnum::Stable => {}
@@ -167,4 +168,20 @@ fn main() {
         _ => {}
     }
     //~^^ some variants are not matched explicitly
+
+    #[warn(non_exhaustive_omitted_patterns)]
+    let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new();
+    //~^ some fields are not explicitly listed
+
+    // OK: both unstable fields are matched with feature on
+    #[warn(non_exhaustive_omitted_patterns)]
+    let OnlyUnstableStruct { unstable, unstable2, .. } = OnlyUnstableStruct::new();
+
+    #[warn(non_exhaustive_omitted_patterns)]
+    let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
+    //~^ some fields are not explicitly listed
+
+    // OK: both unstable and stable fields are matched with feature on
+    #[warn(non_exhaustive_omitted_patterns)]
+    let UnstableStruct { stable, stable2, unstable, .. } = UnstableStruct::default();
 }
diff --git a/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr
index 30f3f88ad91..a9885449f3f 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr
@@ -49,6 +49,34 @@ LL |     let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = Nested
    = help: ensure that all fields are mentioned explicitly by adding the suggested fields
    = note: the pattern is of type `NestedStruct` and the `non_exhaustive_omitted_patterns` attribute was found
 
+warning: some fields are not explicitly listed
+  --> $DIR/omitted-patterns.rs:173:9
+   |
+LL |     let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `unstable2` not listed
+   |
+note: the lint level is defined here
+  --> $DIR/omitted-patterns.rs:172:12
+   |
+LL |     #[warn(non_exhaustive_omitted_patterns)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: ensure that all fields are mentioned explicitly by adding the suggested fields
+   = note: the pattern is of type `OnlyUnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found
+
+warning: some fields are not explicitly listed
+  --> $DIR/omitted-patterns.rs:181:9
+   |
+LL |     let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `unstable` not listed
+   |
+note: the lint level is defined here
+  --> $DIR/omitted-patterns.rs:180:12
+   |
+LL |     #[warn(non_exhaustive_omitted_patterns)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: ensure that all fields are mentioned explicitly by adding the suggested fields
+   = note: the pattern is of type `UnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found
+
 error: some variants are not matched explicitly
   --> $DIR/omitted-patterns.rs:58:9
    |
@@ -143,18 +171,18 @@ LL |         #[deny(non_exhaustive_omitted_patterns)]
    = note: the matched value is of type `UnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found
 
 error: some variants are not matched explicitly
-  --> $DIR/omitted-patterns.rs:167:9
+  --> $DIR/omitted-patterns.rs:168:9
    |
 LL |         _ => {}
    |         ^ pattern `Unstable2` not covered
    |
 note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:164:12
+  --> $DIR/omitted-patterns.rs:165:12
    |
 LL |     #[deny(non_exhaustive_omitted_patterns)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: ensure that all variants are matched explicitly by adding the suggested match arms
    = note: the matched value is of type `OnlyUnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found
 
-error: aborting due to 8 previous errors; 4 warnings emitted
+error: aborting due to 8 previous errors; 6 warnings emitted
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.rs
index 9621d28f8e2..82ee68687ed 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.rs
@@ -6,7 +6,7 @@
 // aux-build:unstable.rs
 extern crate unstable;
 
-use unstable::{UnstableEnum, OnlyUnstableEnum};
+use unstable::{UnstableEnum, OnlyUnstableEnum, UnstableStruct, OnlyUnstableStruct};
 
 fn main() {
     // OK: this matches all the stable variants
@@ -30,4 +30,16 @@ fn main() {
     match OnlyUnstableEnum::new() {
         _ => {}
     }
+
+    // Ok: Same as the above enum (no fields can be matched on)
+    #[warn(non_exhaustive_omitted_patterns)]
+    let OnlyUnstableStruct { .. } = OnlyUnstableStruct::new();
+
+    #[warn(non_exhaustive_omitted_patterns)]
+    let UnstableStruct { stable, .. } = UnstableStruct::default();
+    //~^ some fields are not explicitly listed
+
+    // OK: stable field is matched
+    #[warn(non_exhaustive_omitted_patterns)]
+    let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
 }
diff --git a/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr
index b9a281974fa..7cce178988a 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr
@@ -1,3 +1,17 @@
+warning: some fields are not explicitly listed
+  --> $DIR/stable-omitted-patterns.rs:39:9
+   |
+LL |     let UnstableStruct { stable, .. } = UnstableStruct::default();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `stable2` not listed
+   |
+note: the lint level is defined here
+  --> $DIR/stable-omitted-patterns.rs:38:12
+   |
+LL |     #[warn(non_exhaustive_omitted_patterns)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: ensure that all fields are mentioned explicitly by adding the suggested fields
+   = note: the pattern is of type `UnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found
+
 error: some variants are not matched explicitly
   --> $DIR/stable-omitted-patterns.rs:23:9
    |
@@ -12,5 +26,5 @@ LL |         #[deny(non_exhaustive_omitted_patterns)]
    = help: ensure that all variants are matched explicitly by adding the suggested match arms
    = note: the matched value is of type `UnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found
 
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted