about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs27
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs49
-rw-r--r--tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr3
-rw-r--r--tests/ui/match/match_non_exhaustive.stderr3
-rw-r--r--tests/ui/pattern/usefulness/auxiliary/non-exhaustive.rs2
-rw-r--r--tests/ui/pattern/usefulness/issue-105479-str-non-exhaustiveness.rs12
-rw-r--r--tests/ui/pattern/usefulness/issue-105479-str-non-exhaustiveness.stderr17
-rw-r--r--tests/ui/pattern/usefulness/issue-30240.stderr2
-rw-r--r--tests/ui/pattern/usefulness/nested-non-exhaustive-enums.rs18
-rw-r--r--tests/ui/pattern/usefulness/nested-non-exhaustive-enums.stderr22
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/enum.stderr5
11 files changed, 119 insertions, 41 deletions
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index f46cf0dc0ff..95dced644e1 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -720,32 +720,31 @@ fn non_exhaustive_match<'p, 'tcx>(
         };
     };
 
-    let is_variant_list_non_exhaustive = matches!(scrut_ty.kind(),
-        ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local());
-
     adt_defined_here(cx, &mut err, scrut_ty, &witnesses);
-    err.note(format!(
-        "the matched value is of type `{}`{}",
-        scrut_ty,
-        if is_variant_list_non_exhaustive { ", which is marked as non-exhaustive" } else { "" }
-    ));
+    err.note(format!("the matched value is of type `{}`", scrut_ty));
 
     if !is_empty_match && witnesses.len() == 1 {
         let mut non_exhaustive_tys = FxHashSet::default();
         collect_non_exhaustive_tys(&witnesses[0], &mut non_exhaustive_tys);
 
         for ty in non_exhaustive_tys {
-            if ty == cx.tcx.types.usize || ty == cx.tcx.types.isize {
+            if ty.is_ptr_sized_integral() {
                 err.note(format!(
                     "`{ty}` does not have a fixed maximum value, so a wildcard `_` is necessary to match \
-                     exhaustively",
-                ));
+                         exhaustively",
+                    ));
                 if cx.tcx.sess.is_nightly_build() {
                     err.help(format!(
-                        "add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \
-                         enable precise `{ty}` matching",
-                    ));
+                            "add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \
+                             enable precise `{ty}` matching",
+                        ));
                 }
+            } else if ty == cx.tcx.types.str_ {
+                err.note(format!(
+                    "`&str` cannot be matched exhaustively, so a wildcard `_` is necessary",
+                ));
+            } else if cx.is_foreign_non_exhaustive_enum(ty) {
+                err.note(format!("`{ty}` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively"));
             }
         }
     }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 08cfe98bb68..21031e8ba9d 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -618,10 +618,15 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> {
                 let new_witnesses = if let Constructor::Missing { .. } = ctor {
                     // We got the special `Missing` constructor, so each of the missing constructors
                     // gives a new pattern that is not caught by the match. We list those patterns.
-                    let new_patterns = if pcx.is_non_exhaustive {
-                        // Here we don't want the user to try to list all variants, we want them to add
-                        // a wildcard, so we only suggest that.
-                        vec![DeconstructedPat::wildcard(pcx.ty, pcx.span)]
+                    if pcx.is_non_exhaustive {
+                        witnesses
+                            .into_iter()
+                            // Here we don't want the user to try to list all variants, we want them to add
+                            // a wildcard, so we only suggest that.
+                            .map(|witness| {
+                                witness.apply_constructor(pcx, &Constructor::NonExhaustive)
+                            })
+                            .collect()
                     } else {
                         let mut split_wildcard = SplitWildcard::new(pcx);
                         split_wildcard.split(pcx, matrix.heads().map(DeconstructedPat::ctor));
@@ -633,7 +638,7 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> {
                         // constructor, that matches everything that can be built with
                         // it. For example, if `ctor` is a `Constructor::Variant` for
                         // `Option::Some`, we get the pattern `Some(_)`.
-                        let mut new: Vec<DeconstructedPat<'_, '_>> = split_wildcard
+                        let mut new_patterns: Vec<DeconstructedPat<'_, '_>> = split_wildcard
                             .iter_missing(pcx)
                             .filter_map(|missing_ctor| {
                                 // Check if this variant is marked `doc(hidden)`
@@ -648,27 +653,25 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> {
                             .collect();
 
                         if hide_variant_show_wild {
-                            new.push(DeconstructedPat::wildcard(pcx.ty, pcx.span));
+                            new_patterns.push(DeconstructedPat::wildcard(pcx.ty, pcx.span));
                         }
 
-                        new
-                    };
-
-                    witnesses
-                        .into_iter()
-                        .flat_map(|witness| {
-                            new_patterns.iter().map(move |pat| {
-                                Witness(
-                                    witness
-                                        .0
-                                        .iter()
-                                        .chain(once(pat))
-                                        .map(DeconstructedPat::clone_and_forget_reachability)
-                                        .collect(),
-                                )
+                        witnesses
+                            .into_iter()
+                            .flat_map(|witness| {
+                                new_patterns.iter().map(move |pat| {
+                                    Witness(
+                                        witness
+                                            .0
+                                            .iter()
+                                            .chain(once(pat))
+                                            .map(DeconstructedPat::clone_and_forget_reachability)
+                                            .collect(),
+                                    )
+                                })
                             })
-                        })
-                        .collect()
+                            .collect()
+                    }
                 } else {
                     witnesses
                         .into_iter()
diff --git a/tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr b/tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr
index 3a5fad15421..0807f459029 100644
--- a/tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr
+++ b/tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr
@@ -45,7 +45,8 @@ note: `E2` defined here
    |
 LL | pub enum E2 { A, B }
    | ^^^^^^^^^^^
-   = note: the matched value is of type `E2`, which is marked as non-exhaustive
+   = note: the matched value is of type `E2`
+   = note: `E2` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively
 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 |     let _e = || { match e2 { E2::A => (), E2::B => (), _ => todo!() } };
diff --git a/tests/ui/match/match_non_exhaustive.stderr b/tests/ui/match/match_non_exhaustive.stderr
index 46ee8d5179e..7b8bdfe0053 100644
--- a/tests/ui/match/match_non_exhaustive.stderr
+++ b/tests/ui/match/match_non_exhaustive.stderr
@@ -45,7 +45,8 @@ note: `E2` defined here
    |
 LL | pub enum E2 { A, B }
    | ^^^^^^^^^^^
-   = note: the matched value is of type `E2`, which is marked as non-exhaustive
+   = note: the matched value is of type `E2`
+   = note: `E2` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively
 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 |     match e2 { E2::A => (), E2::B => (), _ => todo!() };
diff --git a/tests/ui/pattern/usefulness/auxiliary/non-exhaustive.rs b/tests/ui/pattern/usefulness/auxiliary/non-exhaustive.rs
new file mode 100644
index 00000000000..6f459b8268f
--- /dev/null
+++ b/tests/ui/pattern/usefulness/auxiliary/non-exhaustive.rs
@@ -0,0 +1,2 @@
+#[non_exhaustive]
+pub enum NonExhaustiveEnum { A, B }
diff --git a/tests/ui/pattern/usefulness/issue-105479-str-non-exhaustiveness.rs b/tests/ui/pattern/usefulness/issue-105479-str-non-exhaustiveness.rs
new file mode 100644
index 00000000000..0ee7856c680
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-105479-str-non-exhaustiveness.rs
@@ -0,0 +1,12 @@
+fn main() {
+    let a = "";
+    let b = "";
+    match (a, b) {
+        //~^ ERROR non-exhaustive patterns: `(&_, _)` not covered [E0004]
+        //~| NOTE pattern `(&_, _)` not covered
+        //~| NOTE the matched value is of type `(&str, &str)`
+        //~| NOTE `&str` cannot be matched exhaustively, so a wildcard `_` is necessary
+        ("a", "b") => {}
+        ("c", "d") => {}
+    }
+}
diff --git a/tests/ui/pattern/usefulness/issue-105479-str-non-exhaustiveness.stderr b/tests/ui/pattern/usefulness/issue-105479-str-non-exhaustiveness.stderr
new file mode 100644
index 00000000000..771fc320a13
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-105479-str-non-exhaustiveness.stderr
@@ -0,0 +1,17 @@
+error[E0004]: non-exhaustive patterns: `(&_, _)` not covered
+  --> $DIR/issue-105479-str-non-exhaustiveness.rs:4:11
+   |
+LL |     match (a, b) {
+   |           ^^^^^^ pattern `(&_, _)` not covered
+   |
+   = note: the matched value is of type `(&str, &str)`
+   = note: `&str` cannot be matched exhaustively, so a wildcard `_` is necessary
+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 ~         ("c", "d") => {},
+LL +         (&_, _) => todo!()
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/issue-30240.stderr b/tests/ui/pattern/usefulness/issue-30240.stderr
index ff755d681ac..da8bbdffbf6 100644
--- a/tests/ui/pattern/usefulness/issue-30240.stderr
+++ b/tests/ui/pattern/usefulness/issue-30240.stderr
@@ -5,6 +5,7 @@ LL |     match "world" {
    |           ^^^^^^^ pattern `&_` not covered
    |
    = note: the matched value is of type `&str`
+   = note: `&str` cannot be matched exhaustively, so a wildcard `_` is necessary
 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 ~         "hello" => {},
@@ -18,6 +19,7 @@ LL |     match "world" {
    |           ^^^^^^^ pattern `&_` not covered
    |
    = note: the matched value is of type `&str`
+   = note: `&str` cannot be matched exhaustively, so a wildcard `_` is necessary
 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 ~         "hello" => {},
diff --git a/tests/ui/pattern/usefulness/nested-non-exhaustive-enums.rs b/tests/ui/pattern/usefulness/nested-non-exhaustive-enums.rs
new file mode 100644
index 00000000000..3a8a74d1fd6
--- /dev/null
+++ b/tests/ui/pattern/usefulness/nested-non-exhaustive-enums.rs
@@ -0,0 +1,18 @@
+// aux-build:non-exhaustive.rs
+
+extern crate non_exhaustive;
+
+use non_exhaustive::NonExhaustiveEnum;
+
+fn main() {
+    match Some(NonExhaustiveEnum::A) {
+        //~^ ERROR non-exhaustive patterns: `Some(_)` not covered [E0004]
+        //~| NOTE pattern `Some(_)` not covered
+        //~| NOTE `Option<NonExhaustiveEnum>` defined here
+        //~| NOTE the matched value is of type `Option<NonExhaustiveEnum>`
+        //~| NOTE `NonExhaustiveEnum` is marked as non-exhaustive
+        Some(NonExhaustiveEnum::A) => {}
+        Some(NonExhaustiveEnum::B) => {}
+        None => {}
+    }
+}
diff --git a/tests/ui/pattern/usefulness/nested-non-exhaustive-enums.stderr b/tests/ui/pattern/usefulness/nested-non-exhaustive-enums.stderr
new file mode 100644
index 00000000000..9fbd871db7c
--- /dev/null
+++ b/tests/ui/pattern/usefulness/nested-non-exhaustive-enums.stderr
@@ -0,0 +1,22 @@
+error[E0004]: non-exhaustive patterns: `Some(_)` not covered
+  --> $DIR/nested-non-exhaustive-enums.rs:8:11
+   |
+LL |     match Some(NonExhaustiveEnum::A) {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Some(_)` not covered
+   |
+note: `Option<NonExhaustiveEnum>` defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+  ::: $SRC_DIR/core/src/option.rs:LL:COL
+   |
+   = note: not covered
+   = note: the matched value is of type `Option<NonExhaustiveEnum>`
+   = note: `NonExhaustiveEnum` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively
+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 ~         None => {},
+LL +         Some(_) => todo!()
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/enum.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum.stderr
index 872cb9b8bc6..4e7f3098ab4 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/enum.stderr
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum.stderr
@@ -28,7 +28,8 @@ note: `NonExhaustiveEnum` defined here
    |
 LL | pub enum NonExhaustiveEnum {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: the matched value is of type `NonExhaustiveEnum`, which is marked as non-exhaustive
+   = note: the matched value is of type `NonExhaustiveEnum`
+   = note: `NonExhaustiveEnum` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively
 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 ~         NonExhaustiveEnum::Struct { .. } => "third",
@@ -46,7 +47,7 @@ note: `NonExhaustiveEnum` defined here
    |
 LL | pub enum NonExhaustiveEnum {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: the matched value is of type `NonExhaustiveEnum`, which is marked as non-exhaustive
+   = note: the matched value is of type `NonExhaustiveEnum`
 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 ~     match enum_unit {