about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNadrieril <nadrieril+git@gmail.com>2023-10-13 00:20:06 +0200
committerNadrieril <nadrieril+git@gmail.com>2023-10-27 19:56:12 +0200
commita4875ae1e250895a00356efc2bd5e1cf8a609802 (patch)
treeb87b19abca1f8084f42a8de8209e91b85ddc3b22
parent6f35ae6f9bc32f591262c6eee94452e3eb2918d5 (diff)
downloadrust-a4875ae1e250895a00356efc2bd5e1cf8a609802.tar.gz
rust-a4875ae1e250895a00356efc2bd5e1cf8a609802.zip
Match usize/isize exhaustively
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs27
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs136
-rw-r--r--tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.rs10
-rw-r--r--tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr18
-rw-r--r--tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr2
-rw-r--r--tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr194
-rw-r--r--tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs4
-rw-r--r--tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.rs10
-rw-r--r--tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr18
-rw-r--r--tests/ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.rs16
-rw-r--r--tests/ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.stderr68
-rw-r--r--tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.rs53
-rw-r--r--tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr50
-rw-r--r--tests/ui/pattern/usefulness/refutable-pattern-errors.rs4
-rw-r--r--tests/ui/pattern/usefulness/refutable-pattern-errors.stderr4
-rw-r--r--tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs2
-rw-r--r--tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr2
-rw-r--r--tests/ui/pattern/usefulness/tuple-struct-nonexhaustive.stderr10
18 files changed, 321 insertions, 307 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 9156af3425a..f26f80105ee 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -703,14 +703,21 @@ fn report_arm_reachability<'p, 'tcx>(
 }
 
 fn collect_non_exhaustive_tys<'tcx>(
+    tcx: TyCtxt<'tcx>,
     pat: &WitnessPat<'tcx>,
     non_exhaustive_tys: &mut FxHashSet<Ty<'tcx>>,
 ) {
     if matches!(pat.ctor(), Constructor::NonExhaustive) {
         non_exhaustive_tys.insert(pat.ty());
     }
+    if let Constructor::IntRange(range) = pat.ctor() {
+        if range.is_beyond_boundaries(pat.ty(), tcx) {
+            // The range denotes the values before `isize::MIN` or the values after `usize::MAX`/`isize::MAX`.
+            non_exhaustive_tys.insert(pat.ty());
+        }
+    }
     pat.iter_fields()
-        .for_each(|field_pat| collect_non_exhaustive_tys(field_pat, non_exhaustive_tys))
+        .for_each(|field_pat| collect_non_exhaustive_tys(tcx, field_pat, non_exhaustive_tys))
 }
 
 /// Report that a match is not exhaustive.
@@ -764,16 +771,24 @@ fn non_exhaustive_match<'p, 'tcx>(
     adt_defined_here(cx, &mut err, scrut_ty, &witnesses);
     err.note(format!("the matched value is of type `{}`", scrut_ty));
 
-    if !is_empty_match && witnesses.len() == 1 {
+    if !is_empty_match {
         let mut non_exhaustive_tys = FxHashSet::default();
-        collect_non_exhaustive_tys(&witnesses[0], &mut non_exhaustive_tys);
+        // Look at the first witness.
+        collect_non_exhaustive_tys(cx.tcx, &witnesses[0], &mut non_exhaustive_tys);
 
         for ty in non_exhaustive_tys {
             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",
+                if ty == cx.tcx.types.usize {
+                    err.note(format!(
+                        "`{ty}` does not have a fixed maximum value, so half-open ranges are necessary to match \
+                             exhaustively",
                     ));
+                } else if ty == cx.tcx.types.isize {
+                    err.note(format!(
+                        "`{ty}` does not have fixed minimum and maximum values, so half-open ranges are necessary to match \
+                             exhaustively",
+                    ));
+                }
                 if cx.tcx.sess.is_nightly_build() {
                     err.help(format!(
                             "add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \
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 00a8bd68773..5e9179896f7 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -56,6 +56,7 @@ use rustc_hir::RangeEnd;
 use rustc_index::Idx;
 use rustc_middle::middle::stability::EvalResult;
 use rustc_middle::mir;
+use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange, PatRangeBoundary};
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef};
@@ -139,20 +140,32 @@ impl MaybeInfiniteInt {
             PatRangeBoundary::PosInfinity => PosInfinity,
         }
     }
+    // This could change from finite to infinite if we got `usize::MAX+1` after range splitting.
     fn to_pat_range_bdy<'tcx>(self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> PatRangeBoundary<'tcx> {
         match self {
             NegInfinity => PatRangeBoundary::NegInfinity,
             Finite(x) => {
                 let bias = Self::signed_bias(tcx, ty);
                 let bits = x ^ bias;
-                let env = ty::ParamEnv::empty().and(ty);
-                let value = mir::Const::from_bits(tcx, bits, env);
-                PatRangeBoundary::Finite(value)
+                let size = ty.primitive_size(tcx);
+                match Scalar::try_from_uint(bits, size) {
+                    Some(scalar) => {
+                        let value = mir::Const::from_scalar(tcx, scalar, ty);
+                        PatRangeBoundary::Finite(value)
+                    }
+                    // The value doesn't fit. Since `x >= 0` and 0 always encodes the minimum value
+                    // for a type, the problem isn't that the value is too small. So it must be too
+                    // large.
+                    None => PatRangeBoundary::PosInfinity,
+                }
             }
             JustAfterMax | PosInfinity => PatRangeBoundary::PosInfinity,
         }
     }
 
+    fn is_finite(self) -> bool {
+        matches!(self, Finite(_))
+    }
     fn minus_one(self) -> Self {
         match self {
             Finite(n) => match n.checked_sub(1) {
@@ -169,22 +182,24 @@ impl MaybeInfiniteInt {
                 Some(m) => Finite(m),
                 None => JustAfterMax,
             },
+            JustAfterMax => bug!(),
             x => x,
         }
     }
 }
 
-/// An inclusive interval, used for precise integer exhaustiveness checking.
-/// `IntRange`s always store a contiguous range.
+/// An inclusive interval, used for precise integer exhaustiveness checking. `IntRange`s always
+/// store a contiguous range.
 ///
-/// `IntRange` is never used to encode an empty range or a "range" that wraps
-/// around the (offset) space: i.e., `range.lo <= range.hi`.
+/// `IntRange` is never used to encode an empty range or a "range" that wraps around the (offset)
+/// space: i.e., `range.lo <= range.hi`.
 ///
-/// The range can have open ends.
+/// Note: the range can be `NegInfinity..=NegInfinity` or `PosInfinity..=PosInfinity` to represent
+/// the values before `isize::MIN` and after `isize::MAX`/`usize::MAX`.
 #[derive(Clone, Copy, PartialEq, Eq)]
 pub(crate) struct IntRange {
-    pub(crate) lo: MaybeInfiniteInt, // Must not be `PosInfinity`.
-    pub(crate) hi: MaybeInfiniteInt, // Must not be `NegInfinity`.
+    pub(crate) lo: MaybeInfiniteInt,
+    pub(crate) hi: MaybeInfiniteInt,
 }
 
 impl IntRange {
@@ -195,9 +210,7 @@ impl IntRange {
 
     /// Best effort; will not know that e.g. `255u8..` is a singleton.
     pub(super) fn is_singleton(&self) -> bool {
-        // Since `lo` and `hi` can't be the same `Infinity`, this correctly only detects a
-        // `Finite(x)` singleton.
-        self.lo == self.hi
+        self.lo == self.hi && self.lo.is_finite()
     }
 
     #[inline]
@@ -310,18 +323,49 @@ impl IntRange {
             })
     }
 
+    /// Whether the range denotes the values before `isize::MIN` or the values after
+    /// `usize::MAX`/`isize::MAX`.
+    pub(crate) fn is_beyond_boundaries<'tcx>(&self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> bool {
+        // First check if we are usize/isize to avoid unnecessary `to_pat_range_bdy`.
+        ty.is_ptr_sized_integral() && !tcx.features().precise_pointer_size_matching && {
+            let lo = self.lo.to_pat_range_bdy(ty, tcx);
+            let hi = self.hi.to_pat_range_bdy(ty, tcx);
+            matches!(lo, PatRangeBoundary::PosInfinity)
+                || matches!(hi, PatRangeBoundary::NegInfinity)
+        }
+    }
     /// Only used for displaying the range.
     pub(super) fn to_pat<'tcx>(&self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Pat<'tcx> {
-        let lo = self.lo.to_pat_range_bdy(ty, tcx);
-        let hi = self.hi.to_pat_range_bdy(ty, tcx);
-
-        let kind = if self.is_singleton() {
+        let kind = if matches!((self.lo, self.hi), (NegInfinity, PosInfinity)) {
+            PatKind::Wild
+        } else if self.is_singleton() {
+            let lo = self.lo.to_pat_range_bdy(ty, tcx);
             let value = lo.as_finite().unwrap();
             PatKind::Constant { value }
-        } else if matches!((self.lo, self.hi), (NegInfinity, PosInfinity)) {
-            PatKind::Wild
         } else {
-            PatKind::Range(Box::new(PatRange { lo, hi, end: RangeEnd::Included, ty }))
+            let mut lo = self.lo.to_pat_range_bdy(ty, tcx);
+            let mut hi = self.hi.to_pat_range_bdy(ty, tcx);
+            let end = if hi.is_finite() {
+                RangeEnd::Included
+            } else {
+                // `0..=` isn't a valid pattern.
+                RangeEnd::Excluded
+            };
+            if matches!(hi, PatRangeBoundary::NegInfinity) {
+                // The range denotes the values before `isize::MIN`.
+                let c = ty.numeric_min_val(tcx).unwrap();
+                let value = mir::Const::from_ty_const(c, tcx);
+                hi = PatRangeBoundary::Finite(value);
+            }
+            if matches!(lo, PatRangeBoundary::PosInfinity) {
+                // The range denotes the values after `usize::MAX`/`isize::MAX`.
+                // We represent this as `usize::MAX..` which is slightly incorrect but probably
+                // clear enough.
+                let c = ty.numeric_max_val(tcx).unwrap();
+                let value = mir::Const::from_ty_const(c, tcx);
+                lo = PatRangeBoundary::Finite(value);
+            }
+            PatKind::Range(Box::new(PatRange { lo, hi, end, ty }))
         };
 
         Pat { ty, span: DUMMY_SP, kind }
@@ -843,9 +887,7 @@ pub(super) enum ConstructorSet {
     Bool,
     /// The type is spanned by integer values. The range or ranges give the set of allowed values.
     /// The second range is only useful for `char`.
-    /// `non_exhaustive` is used when the range is not allowed to be matched exhaustively (that's
-    /// for usize/isize).
-    Integers { range_1: IntRange, range_2: Option<IntRange>, non_exhaustive: bool },
+    Integers { range_1: IntRange, range_2: Option<IntRange> },
     /// The type is matched by slices. The usize is the compile-time length of the array, if known.
     Slice(Option<usize>),
     /// The type is matched by slices whose elements are uninhabited.
@@ -903,27 +945,37 @@ impl ConstructorSet {
                 Self::Integers {
                     range_1: make_range('\u{0000}' as u128, '\u{D7FF}' as u128),
                     range_2: Some(make_range('\u{E000}' as u128, '\u{10FFFF}' as u128)),
-                    non_exhaustive: false,
                 }
             }
             &ty::Int(ity) => {
-                // `usize`/`isize` are not allowed to be matched exhaustively unless the
-                // `precise_pointer_size_matching` feature is enabled.
-                let non_exhaustive =
-                    ty.is_ptr_sized_integral() && !cx.tcx.features().precise_pointer_size_matching;
-                let bits = Integer::from_int_ty(&cx.tcx, ity).size().bits() as u128;
-                let min = 1u128 << (bits - 1);
-                let max = min - 1;
-                Self::Integers { range_1: make_range(min, max), non_exhaustive, range_2: None }
+                let range = if ty.is_ptr_sized_integral()
+                    && !cx.tcx.features().precise_pointer_size_matching
+                {
+                    // The min/max values of `isize` are not allowed to be observed unless the
+                    // `precise_pointer_size_matching` feature is enabled.
+                    IntRange { lo: NegInfinity, hi: PosInfinity }
+                } else {
+                    let bits = Integer::from_int_ty(&cx.tcx, ity).size().bits() as u128;
+                    let min = 1u128 << (bits - 1);
+                    let max = min - 1;
+                    make_range(min, max)
+                };
+                Self::Integers { range_1: range, range_2: None }
             }
             &ty::Uint(uty) => {
-                // `usize`/`isize` are not allowed to be matched exhaustively unless the
-                // `precise_pointer_size_matching` feature is enabled.
-                let non_exhaustive =
-                    ty.is_ptr_sized_integral() && !cx.tcx.features().precise_pointer_size_matching;
-                let size = Integer::from_uint_ty(&cx.tcx, uty).size();
-                let max = size.truncate(u128::MAX);
-                Self::Integers { range_1: make_range(0, max), non_exhaustive, range_2: None }
+                let range = if ty.is_ptr_sized_integral()
+                    && !cx.tcx.features().precise_pointer_size_matching
+                {
+                    // The max value of `usize` is not allowed to be observed unless the
+                    // `precise_pointer_size_matching` feature is enabled.
+                    let lo = MaybeInfiniteInt::new_finite(cx.tcx, ty, 0);
+                    IntRange { lo, hi: PosInfinity }
+                } else {
+                    let size = Integer::from_uint_ty(&cx.tcx, uty).size();
+                    let max = size.truncate(u128::MAX);
+                    make_range(0, max)
+                };
+                Self::Integers { range_1: range, range_2: None }
             }
             ty::Array(sub_ty, len) if len.try_eval_target_usize(cx.tcx, cx.param_env).is_some() => {
                 let len = len.eval_target_usize(cx.tcx, cx.param_env) as usize;
@@ -1078,7 +1130,7 @@ impl ConstructorSet {
                     missing.push(Bool(true));
                 }
             }
-            ConstructorSet::Integers { range_1, range_2, non_exhaustive } => {
+            ConstructorSet::Integers { range_1, range_2 } => {
                 let seen_ranges: Vec<_> =
                     seen.map(|ctor| ctor.as_int_range().unwrap().clone()).collect();
                 for (seen, splitted_range) in range_1.split(seen_ranges.iter().cloned()) {
@@ -1095,10 +1147,6 @@ impl ConstructorSet {
                         }
                     }
                 }
-
-                if *non_exhaustive {
-                    missing.push(NonExhaustive);
-                }
             }
             &ConstructorSet::Slice(array_len) => {
                 let seen_slices = seen.map(|c| c.as_slice().unwrap());
diff --git a/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.rs b/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.rs
index 4c77180b767..b4dc1fd4556 100644
--- a/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.rs
+++ b/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.rs
@@ -1,17 +1,17 @@
 fn main() {
     match 0usize {
-        //~^ ERROR non-exhaustive patterns: `_` not covered
-        //~| NOTE pattern `_` not covered
+        //~^ ERROR non-exhaustive patterns: `usize::MAX..` not covered
+        //~| NOTE pattern `usize::MAX..` not covered
         //~| NOTE the matched value is of type `usize`
         //~| NOTE `usize` does not have a fixed maximum value
         0..=usize::MAX => {}
     }
 
     match 0isize {
-        //~^ ERROR non-exhaustive patterns: `_` not covered
-        //~| NOTE pattern `_` not covered
+        //~^ ERROR non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
+        //~| NOTE patterns `..isize::MIN` and `isize::MAX..` not covered
         //~| NOTE the matched value is of type `isize`
-        //~| NOTE `isize` does not have a fixed maximum value
+        //~| NOTE `isize` does not have fixed minimum and maximum values
         isize::MIN..=isize::MAX => {}
     }
 }
diff --git a/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr b/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr
index 853b57052ac..8694924e52f 100644
--- a/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr
+++ b/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr
@@ -1,31 +1,31 @@
-error[E0004]: non-exhaustive patterns: `_` not covered
+error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered
   --> $DIR/feature-gate-precise_pointer_size_matching.rs:2:11
    |
 LL |     match 0usize {
-   |           ^^^^^^ pattern `_` not covered
+   |           ^^^^^^ pattern `usize::MAX..` not covered
    |
    = note: the matched value is of type `usize`
-   = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
 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 ~         0..=usize::MAX => {},
-LL +         _ => todo!()
+LL +         usize::MAX.. => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `_` not covered
+error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
   --> $DIR/feature-gate-precise_pointer_size_matching.rs:10:11
    |
 LL |     match 0isize {
-   |           ^^^^^^ pattern `_` not covered
+   |           ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered
    |
    = note: the matched value is of type `isize`
-   = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+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 ~         isize::MIN..=isize::MAX => {},
-LL +         _ => todo!()
+LL +         ..isize::MIN | isize::MAX.. => todo!()
    |
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr
index 12a928bf018..7f26c93aa28 100644
--- a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr
+++ b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: type `usize` is non-empty
-  --> $DIR/pointer-sized-int.rs:58:11
+  --> $DIR/pointer-sized-int.rs:54:11
    |
 LL |     match 7usize {}
    |           ^^^^^^
diff --git a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr
index 7fa9eb8eda6..d16ec5412db 100644
--- a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr
+++ b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr
@@ -1,218 +1,162 @@
-error[E0004]: non-exhaustive patterns: `_` not covered
+error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered
   --> $DIR/pointer-sized-int.rs:14:11
    |
 LL |     match 0usize {
-   |           ^^^^^^ pattern `_` not covered
+   |           ^^^^^^ pattern `usize::MAX..` not covered
    |
    = note: the matched value is of type `usize`
-   = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
 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 ~         0 ..= usize::MAX => {},
-LL +         _ => todo!()
+LL +         usize::MAX.. => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `_` not covered
+error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
   --> $DIR/pointer-sized-int.rs:19:11
    |
 LL |     match 0isize {
-   |           ^^^^^^ pattern `_` not covered
+   |           ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered
    |
    = note: the matched value is of type `isize`
-   = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+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 ~         isize::MIN ..= isize::MAX => {},
-LL +         _ => todo!()
+LL +         ..isize::MIN | isize::MAX.. => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int.rs:24:8
-   |
-LL |     m!(0usize, 0..);
-   |        ^^^^^^ pattern `_` not covered
-   |
-   = note: the matched value is of type `usize`
-   = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
-   = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
-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 $s { $($t)+ => {}, _ => todo!() }
-   |                                ++++++++++++++
-
-error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int.rs:26:8
+error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered
+  --> $DIR/pointer-sized-int.rs:25:8
    |
 LL |     m!(0usize, 0..=usize::MAX);
-   |        ^^^^^^ pattern `_` not covered
+   |        ^^^^^^ pattern `usize::MAX..` not covered
    |
    = note: the matched value is of type `usize`
-   = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
 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 $s { $($t)+ => {}, _ => todo!() }
-   |                                ++++++++++++++
+LL |         match $s { $($t)+ => {}, usize::MAX.. => todo!() }
+   |                                +++++++++++++++++++++++++
 
-error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int.rs:28:8
+error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered
+  --> $DIR/pointer-sized-int.rs:27:8
    |
 LL |     m!(0usize, 0..5 | 5..=usize::MAX);
-   |        ^^^^^^ pattern `_` not covered
+   |        ^^^^^^ pattern `usize::MAX..` not covered
    |
    = note: the matched value is of type `usize`
-   = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
 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 $s { $($t)+ => {}, _ => todo!() }
-   |                                ++++++++++++++
+LL |         match $s { $($t)+ => {}, usize::MAX.. => todo!() }
+   |                                +++++++++++++++++++++++++
 
-error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int.rs:30:8
+error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered
+  --> $DIR/pointer-sized-int.rs:29:8
    |
 LL |     m!(0usize, 0..usize::MAX | usize::MAX);
-   |        ^^^^^^ pattern `_` not covered
+   |        ^^^^^^ pattern `usize::MAX..` not covered
    |
    = note: the matched value is of type `usize`
-   = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
 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 $s { $($t)+ => {}, _ => todo!() }
-   |                                ++++++++++++++
+LL |         match $s { $($t)+ => {}, usize::MAX.. => todo!() }
+   |                                +++++++++++++++++++++++++
 
-error[E0004]: non-exhaustive patterns: `(_, _)` not covered
-  --> $DIR/pointer-sized-int.rs:32:8
+error[E0004]: non-exhaustive patterns: `(usize::MAX.., _)` not covered
+  --> $DIR/pointer-sized-int.rs:31:8
    |
 LL |     m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
-   |        ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
+   |        ^^^^^^^^^^^^^^ pattern `(usize::MAX.., _)` not covered
    |
    = note: the matched value is of type `(usize, bool)`
-   = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
 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 $s { $($t)+ => {}, (_, _) => todo!() }
-   |                                +++++++++++++++++++
-
-error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int.rs:34:8
-   |
-LL |     m!(0usize, 0..=usize::MAX | usize::MAX..);
-   |        ^^^^^^ pattern `_` not covered
-   |
-   = note: the matched value is of type `usize`
-   = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
-   = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
-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 $s { $($t)+ => {}, _ => todo!() }
-   |                                ++++++++++++++
-
-error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int.rs:37:8
-   |
-LL |     m!(0isize, ..0 | 0..);
-   |        ^^^^^^ pattern `_` not covered
-   |
-   = note: the matched value is of type `isize`
-   = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
-   = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
-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 $s { $($t)+ => {}, _ => todo!() }
-   |                                ++++++++++++++
+LL |         match $s { $($t)+ => {}, (usize::MAX.., _) => todo!() }
+   |                                ++++++++++++++++++++++++++++++
 
-error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int.rs:39:8
+error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
+  --> $DIR/pointer-sized-int.rs:36:8
    |
 LL |     m!(0isize, isize::MIN..=isize::MAX);
-   |        ^^^^^^ pattern `_` not covered
+   |        ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered
    |
    = note: the matched value is of type `isize`
-   = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+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 |         match $s { $($t)+ => {}, _ => todo!() }
-   |                                ++++++++++++++
+LL |         match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() }
+   |                                ++++++++++++++++++++++++++++++++++++++++
 
-error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int.rs:41:8
+error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
+  --> $DIR/pointer-sized-int.rs:38:8
    |
 LL |     m!(0isize, isize::MIN..5 | 5..=isize::MAX);
-   |        ^^^^^^ pattern `_` not covered
+   |        ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered
    |
    = note: the matched value is of type `isize`
-   = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+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 |         match $s { $($t)+ => {}, _ => todo!() }
-   |                                ++++++++++++++
+LL |         match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() }
+   |                                ++++++++++++++++++++++++++++++++++++++++
 
-error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int.rs:43:8
+error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
+  --> $DIR/pointer-sized-int.rs:40:8
    |
 LL |     m!(0isize, isize::MIN..isize::MAX | isize::MAX);
-   |        ^^^^^^ pattern `_` not covered
+   |        ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered
    |
    = note: the matched value is of type `isize`
-   = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+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 |         match $s { $($t)+ => {}, _ => todo!() }
-   |                                ++++++++++++++
+LL |         match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() }
+   |                                ++++++++++++++++++++++++++++++++++++++++
 
-error[E0004]: non-exhaustive patterns: `(_, _)` not covered
-  --> $DIR/pointer-sized-int.rs:45:8
+error[E0004]: non-exhaustive patterns: `(..isize::MIN, _)` and `(isize::MAX.., _)` not covered
+  --> $DIR/pointer-sized-int.rs:42:8
    |
 LL |     m!((0isize, true), (isize::MIN..5, true)
-   |        ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
+   |        ^^^^^^^^^^^^^^ patterns `(..isize::MIN, _)` and `(isize::MAX.., _)` not covered
    |
    = note: the matched value is of type `(isize, bool)`
-   = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+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 |         match $s { $($t)+ => {}, (_, _) => todo!() }
-   |                                +++++++++++++++++++
+LL |         match $s { $($t)+ => {}, (..isize::MIN, _) | (isize::MAX.., _) => todo!() }
+   |                                ++++++++++++++++++++++++++++++++++++++++++++++++++
 
-error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int.rs:48:8
-   |
-LL |     m!(0isize, ..=isize::MIN | isize::MIN..=isize::MAX | isize::MAX..);
-   |        ^^^^^^ pattern `_` not covered
-   |
-   = note: the matched value is of type `isize`
-   = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
-   = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
-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 $s { $($t)+ => {}, _ => todo!() }
-   |                                ++++++++++++++
-
-error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int.rs:51:11
+error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
+  --> $DIR/pointer-sized-int.rs:47:11
    |
 LL |     match 0isize {
-   |           ^^^^^^ pattern `_` not covered
+   |           ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered
    |
    = note: the matched value is of type `isize`
-   = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+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 ~         1 ..= isize::MAX => {},
-LL +         _ => todo!()
+LL +         ..isize::MIN | isize::MAX.. => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: type `usize` is non-empty
-  --> $DIR/pointer-sized-int.rs:58:11
+  --> $DIR/pointer-sized-int.rs:54:11
    |
 LL |     match 7usize {}
    |           ^^^^^^
@@ -225,6 +169,6 @@ LL +         _ => todo!(),
 LL +     }
    |
 
-error: aborting due to 16 previous errors
+error: aborting due to 12 previous errors
 
 For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs
index b55f8f3e516..20a3cbe127f 100644
--- a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs
+++ b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs
@@ -22,7 +22,6 @@ fn main() {
     }
 
     m!(0usize, 0..);
-    //[deny]~^ ERROR non-exhaustive patterns
     m!(0usize, 0..=usize::MAX);
     //[deny]~^ ERROR non-exhaustive patterns
     m!(0usize, 0..5 | 5..=usize::MAX);
@@ -32,10 +31,8 @@ fn main() {
     m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
     //[deny]~^ ERROR non-exhaustive patterns
     m!(0usize, 0..=usize::MAX | usize::MAX..);
-    //[deny]~^ ERROR non-exhaustive patterns
 
     m!(0isize, ..0 | 0..);
-    //[deny]~^ ERROR non-exhaustive patterns
     m!(0isize, isize::MIN..=isize::MAX);
     //[deny]~^ ERROR non-exhaustive patterns
     m!(0isize, isize::MIN..5 | 5..=isize::MAX);
@@ -46,7 +43,6 @@ fn main() {
         | (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false));
     //[deny]~^^ ERROR non-exhaustive patterns
     m!(0isize, ..=isize::MIN | isize::MIN..=isize::MAX | isize::MAX..);
-    //[deny]~^ ERROR non-exhaustive patterns
 
     match 0isize {
         //[deny]~^ ERROR non-exhaustive patterns
diff --git a/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.rs b/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.rs
index a2aa655ca54..d60f479c0d1 100644
--- a/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.rs
+++ b/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.rs
@@ -1,18 +1,18 @@
 // This tests that the lint message explains the reason for the error.
 fn main() {
     match 0usize {
-        //~^ ERROR non-exhaustive patterns: `_` not covered
-        //~| NOTE pattern `_` not covered
+        //~^ ERROR non-exhaustive patterns: `usize::MAX..` not covered
+        //~| NOTE pattern `usize::MAX..` not covered
         //~| NOTE the matched value is of type `usize`
         //~| NOTE `usize` does not have a fixed maximum value
         0..=usize::MAX => {}
     }
 
     match 0isize {
-        //~^ ERROR non-exhaustive patterns: `_` not covered
-        //~| NOTE pattern `_` not covered
+        //~^ ERROR non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
+        //~| NOTE patterns `..isize::MIN` and `isize::MAX..` not covered
         //~| NOTE the matched value is of type `isize`
-        //~| NOTE `isize` does not have a fixed maximum value
+        //~| NOTE `isize` does not have fixed minimum and maximum values
         isize::MIN..=isize::MAX => {}
     }
 }
diff --git a/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr b/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr
index b80411b26b0..a7f93648ed3 100644
--- a/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr
+++ b/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr
@@ -1,31 +1,31 @@
-error[E0004]: non-exhaustive patterns: `_` not covered
+error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered
   --> $DIR/precise_pointer_matching-message.rs:3:11
    |
 LL |     match 0usize {
-   |           ^^^^^^ pattern `_` not covered
+   |           ^^^^^^ pattern `usize::MAX..` not covered
    |
    = note: the matched value is of type `usize`
-   = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
 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 ~         0..=usize::MAX => {},
-LL +         _ => todo!()
+LL +         usize::MAX.. => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `_` not covered
+error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
   --> $DIR/precise_pointer_matching-message.rs:11:11
    |
 LL |     match 0isize {
-   |           ^^^^^^ pattern `_` not covered
+   |           ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered
    |
    = note: the matched value is of type `isize`
-   = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+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 ~         isize::MIN..=isize::MAX => {},
-LL +         _ => todo!()
+LL +         ..isize::MIN | isize::MAX.. => todo!()
    |
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.rs b/tests/ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.rs
index 8f58227ee2c..6cbcfed709f 100644
--- a/tests/ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.rs
+++ b/tests/ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.rs
@@ -6,19 +6,19 @@ struct B<T, U>(T, U);
 
 fn main() {
     match 0 {
-        //~^ ERROR non-exhaustive patterns: `_` not covered [E0004]
+        //~^ ERROR non-exhaustive patterns: `usize::MAX..` not covered [E0004]
         0 => (),
         1..=usize::MAX => (),
     }
 
     match (0usize, 0usize) {
-        //~^ ERROR non-exhaustive patterns: `(_, _)` not covered [E0004]
+        //~^ ERROR non-exhaustive patterns: `(usize::MAX.., _)` not covered [E0004]
         (0, 0) => (),
         (1..=usize::MAX, 1..=usize::MAX) => (),
     }
 
     match (0isize, 0usize) {
-        //~^ ERROR non-exhaustive patterns: `(_, _)` not covered [E0004]
+        //~^ ERROR non-exhaustive patterns: `(..isize::MIN, _)` and `(isize::MAX.., _)` not covered [E0004]
         (isize::MIN..=isize::MAX, 0) => (),
         (isize::MIN..=isize::MAX, 1..=usize::MAX) => (),
     }
@@ -30,14 +30,14 @@ fn main() {
     }
 
     match Some(4) {
-        //~^ ERROR non-exhaustive patterns: `Some(_)` not covered
+        //~^ ERROR non-exhaustive patterns: `Some(usize::MAX..)` not covered
         Some(0) => (),
         Some(1..=usize::MAX) => (),
         None => (),
     }
 
     match Some(Some(Some(0))) {
-        //~^ ERROR non-exhaustive patterns: `Some(Some(Some(_)))` not covered
+        //~^ ERROR non-exhaustive patterns: `Some(Some(Some(usize::MAX..)))` not covered
         Some(Some(Some(0))) => (),
         Some(Some(Some(1..=usize::MAX))) => (),
         Some(Some(None)) => (),
@@ -46,13 +46,13 @@ fn main() {
     }
 
     match (A { a: 0usize }) {
-        //~^ ERROR non-exhaustive patterns: `A { .. }` not covered [E0004]
+        //~^ ERROR non-exhaustive patterns: `A { a: usize::MAX.. }` not covered [E0004]
         A { a: 0 } => (),
         A { a: 1..=usize::MAX } => (),
     }
 
     match B(0isize, 0usize) {
-        //~^ ERROR non-exhaustive patterns: `B(_, _)` not covered [E0004]
+        //~^ ERROR non-exhaustive patterns: `B(..isize::MIN, _)` and `B(isize::MAX.., _)` not covered [E0004]
         B(isize::MIN..=isize::MAX, 0) => (),
         B(isize::MIN..=isize::MAX, 1..=usize::MAX) => (),
     }
@@ -60,7 +60,7 @@ fn main() {
     // Should report only the note about usize not having fixed max value and not report
     // report the note about isize
     match B(0isize, 0usize) {
-        //~^ ERROR non-exhaustive patterns: `B(_, _)` not covered [E0004]
+        //~^ ERROR non-exhaustive patterns: `B(_, usize::MAX..)` not covered [E0004]
         B(_, 0) => (),
         B(_, 1..=usize::MAX) => (),
     }
diff --git a/tests/ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.stderr b/tests/ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.stderr
index ea1d99e20ae..556efcda516 100644
--- a/tests/ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.stderr
+++ b/tests/ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.stderr
@@ -1,46 +1,46 @@
-error[E0004]: non-exhaustive patterns: `_` not covered
+error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered
   --> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:8:11
    |
 LL |     match 0 {
-   |           ^ pattern `_` not covered
+   |           ^ pattern `usize::MAX..` not covered
    |
    = note: the matched value is of type `usize`
-   = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
 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 ~         1..=usize::MAX => (),
-LL ~         _ => todo!(),
+LL ~         usize::MAX.. => todo!(),
    |
 
-error[E0004]: non-exhaustive patterns: `(_, _)` not covered
+error[E0004]: non-exhaustive patterns: `(usize::MAX.., _)` not covered
   --> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:14:11
    |
 LL |     match (0usize, 0usize) {
-   |           ^^^^^^^^^^^^^^^^ pattern `(_, _)` not covered
+   |           ^^^^^^^^^^^^^^^^ pattern `(usize::MAX.., _)` not covered
    |
    = note: the matched value is of type `(usize, usize)`
-   = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
 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 ~         (1..=usize::MAX, 1..=usize::MAX) => (),
-LL ~         (_, _) => todo!(),
+LL ~         (usize::MAX.., _) => todo!(),
    |
 
-error[E0004]: non-exhaustive patterns: `(_, _)` not covered
+error[E0004]: non-exhaustive patterns: `(..isize::MIN, _)` and `(isize::MAX.., _)` not covered
   --> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:20:11
    |
 LL |     match (0isize, 0usize) {
-   |           ^^^^^^^^^^^^^^^^ pattern `(_, _)` not covered
+   |           ^^^^^^^^^^^^^^^^ patterns `(..isize::MIN, _)` and `(isize::MAX.., _)` not covered
    |
    = note: the matched value is of type `(isize, usize)`
-   = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+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 ~         (isize::MIN..=isize::MAX, 1..=usize::MAX) => (),
-LL ~         (_, _) => todo!(),
+LL ~         (..isize::MIN, _) | (isize::MAX.., _) => todo!(),
    |
 
 error[E0004]: non-exhaustive patterns: `Some(_)` not covered
@@ -61,11 +61,11 @@ LL ~         None => {},
 LL +         Some(_) => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `Some(_)` not covered
+error[E0004]: non-exhaustive patterns: `Some(usize::MAX..)` not covered
   --> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:32:11
    |
 LL |     match Some(4) {
-   |           ^^^^^^^ pattern `Some(_)` not covered
+   |           ^^^^^^^ pattern `Some(usize::MAX..)` not covered
    |
 note: `Option<usize>` defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
@@ -73,19 +73,19 @@ note: `Option<usize>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Option<usize>`
-   = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
 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!(),
+LL ~         Some(usize::MAX..) => todo!(),
    |
 
-error[E0004]: non-exhaustive patterns: `Some(Some(Some(_)))` not covered
+error[E0004]: non-exhaustive patterns: `Some(Some(Some(usize::MAX..)))` not covered
   --> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:39:11
    |
 LL |     match Some(Some(Some(0))) {
-   |           ^^^^^^^^^^^^^^^^^^^ pattern `Some(Some(Some(_)))` not covered
+   |           ^^^^^^^^^^^^^^^^^^^ pattern `Some(Some(Some(usize::MAX..)))` not covered
    |
 note: `Option<Option<Option<usize>>>` defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
@@ -97,19 +97,19 @@ note: `Option<Option<Option<usize>>>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Option<Option<Option<usize>>>`
-   = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
 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(Some(Some(_))) => todo!(),
+LL ~         Some(Some(Some(usize::MAX..))) => todo!(),
    |
 
-error[E0004]: non-exhaustive patterns: `A { .. }` not covered
+error[E0004]: non-exhaustive patterns: `A { a: usize::MAX.. }` not covered
   --> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:48:11
    |
 LL |     match (A { a: 0usize }) {
-   |           ^^^^^^^^^^^^^^^^^ pattern `A { .. }` not covered
+   |           ^^^^^^^^^^^^^^^^^ pattern `A { a: usize::MAX.. }` not covered
    |
 note: `A<usize>` defined here
   --> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:1:8
@@ -117,19 +117,19 @@ note: `A<usize>` defined here
 LL | struct A<T> {
    |        ^
    = note: the matched value is of type `A<usize>`
-   = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
 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 ~         A { a: 1..=usize::MAX } => (),
-LL ~         A { .. } => todo!(),
+LL ~         A { a: usize::MAX.. } => todo!(),
    |
 
-error[E0004]: non-exhaustive patterns: `B(_, _)` not covered
+error[E0004]: non-exhaustive patterns: `B(..isize::MIN, _)` and `B(isize::MAX.., _)` not covered
   --> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:54:11
    |
 LL |     match B(0isize, 0usize) {
-   |           ^^^^^^^^^^^^^^^^^ pattern `B(_, _)` not covered
+   |           ^^^^^^^^^^^^^^^^^ patterns `B(..isize::MIN, _)` and `B(isize::MAX.., _)` not covered
    |
 note: `B<isize, usize>` defined here
   --> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:5:8
@@ -137,19 +137,19 @@ note: `B<isize, usize>` defined here
 LL | struct B<T, U>(T, U);
    |        ^
    = note: the matched value is of type `B<isize, usize>`
-   = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+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 ~         B(isize::MIN..=isize::MAX, 1..=usize::MAX) => (),
-LL ~         B(_, _) => todo!(),
+LL ~         B(..isize::MIN, _) | B(isize::MAX.., _) => todo!(),
    |
 
-error[E0004]: non-exhaustive patterns: `B(_, _)` not covered
+error[E0004]: non-exhaustive patterns: `B(_, usize::MAX..)` not covered
   --> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:62:11
    |
 LL |     match B(0isize, 0usize) {
-   |           ^^^^^^^^^^^^^^^^^ pattern `B(_, _)` not covered
+   |           ^^^^^^^^^^^^^^^^^ pattern `B(_, usize::MAX..)` not covered
    |
 note: `B<isize, usize>` defined here
   --> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:5:8
@@ -157,12 +157,12 @@ note: `B<isize, usize>` defined here
 LL | struct B<T, U>(T, U);
    |        ^
    = note: the matched value is of type `B<isize, usize>`
-   = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
 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 ~         B(_, 1..=usize::MAX) => (),
-LL ~         B(_, _) => todo!(),
+LL ~         B(_, usize::MAX..) => todo!(),
    |
 
 error: aborting due to 9 previous errors
diff --git a/tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.rs b/tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.rs
index 4bd34421922..9e60d4f41a1 100644
--- a/tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.rs
+++ b/tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.rs
@@ -1,88 +1,101 @@
 struct Foo {
     first: bool,
-    second: Option<[usize; 4]>
+    second: Option<[usize; 4]>,
 }
 
 fn struct_with_a_nested_enum_and_vector() {
     match (Foo { first: true, second: None }) {
-//~^ ERROR non-exhaustive patterns: `Foo { first: false, second: Some([_, _, _, _]) }` not covered
+        //~^ ERROR non-exhaustive patterns: `Foo { first: false, second: Some([0_usize, _, _, _]) }` and `Foo { first: false, second: Some([2_usize.., _, _, _]) }` not covered
         Foo { first: true, second: None } => (),
         Foo { first: true, second: Some(_) } => (),
         Foo { first: false, second: None } => (),
-        Foo { first: false, second: Some([1, 2, 3, 4]) } => ()
+        Foo { first: false, second: Some([1, 2, 3, 4]) } => (),
     }
 }
 
 enum Color {
     Red,
     Green,
-    CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
+    CustomRGBA { a: bool, r: u8, g: u8, b: u8 },
 }
 
 fn enum_with_single_missing_variant() {
     match Color::Red {
-    //~^ ERROR non-exhaustive patterns: `Color::Red` not covered
+        //~^ ERROR non-exhaustive patterns: `Color::Red` not covered
         Color::CustomRGBA { .. } => (),
-        Color::Green => ()
+        Color::Green => (),
     }
 }
 
 enum Direction {
-    North, East, South, West
+    North,
+    East,
+    South,
+    West,
 }
 
 fn enum_with_multiple_missing_variants() {
     match Direction::North {
-    //~^ ERROR non-exhaustive patterns: `Direction::East`, `Direction::South` and `Direction::West` not covered
-        Direction::North => ()
+        //~^ ERROR non-exhaustive patterns: `Direction::East`, `Direction::South` and `Direction::West` not covered
+        Direction::North => (),
     }
 }
 
 enum ExcessiveEnum {
-    First, Second, Third, Fourth, Fifth, Sixth, Seventh, Eighth, Ninth, Tenth, Eleventh, Twelfth
+    First,
+    Second,
+    Third,
+    Fourth,
+    Fifth,
+    Sixth,
+    Seventh,
+    Eighth,
+    Ninth,
+    Tenth,
+    Eleventh,
+    Twelfth,
 }
 
 fn enum_with_excessive_missing_variants() {
     match ExcessiveEnum::First {
-    //~^ ERROR `ExcessiveEnum::Second`, `ExcessiveEnum::Third`, `ExcessiveEnum::Fourth` and 8 more not covered
-
-        ExcessiveEnum::First => ()
+        //~^ ERROR `ExcessiveEnum::Second`, `ExcessiveEnum::Third`, `ExcessiveEnum::Fourth` and 8 more not covered
+        ExcessiveEnum::First => (),
     }
 }
 
 fn enum_struct_variant() {
     match Color::Red {
-    //~^ ERROR non-exhaustive patterns: `Color::CustomRGBA { a: true, .. }` not covered
+        //~^ ERROR non-exhaustive patterns: `Color::CustomRGBA { a: true, .. }` not covered
         Color::Red => (),
         Color::Green => (),
         Color::CustomRGBA { a: false, r: _, g: _, b: 0 } => (),
-        Color::CustomRGBA { a: false, r: _, g: _, b: _ } => ()
+        Color::CustomRGBA { a: false, r: _, g: _, b: _ } => (),
     }
 }
 
 enum Enum {
     First,
-    Second(bool)
+    Second(bool),
 }
 
 fn vectors_with_nested_enums() {
     let x: &'static [Enum] = &[Enum::First, Enum::Second(false)];
     match *x {
-    //~^ ERROR non-exhaustive patterns: `[Enum::Second(true), Enum::Second(false)]` not covered
+        //~^ ERROR non-exhaustive patterns: `[Enum::Second(true), Enum::Second(false)]` not covered
         [] => (),
         [_] => (),
         [Enum::First, _] => (),
         [Enum::Second(true), Enum::First] => (),
         [Enum::Second(true), Enum::Second(true)] => (),
         [Enum::Second(false), _] => (),
-        [_, _, ref tail @ .., _] => ()
+        [_, _, ref tail @ .., _] => (),
     }
 }
 
 fn missing_nil() {
     match ((), false) {
-    //~^ ERROR non-exhaustive patterns: `((), false)` not covered
-        ((), true) => ()
+        //~^ ERROR non-exhaustive patterns: `((), false)` not covered
+        ((), true) => (),
     }
 }
 
diff --git a/tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr b/tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr
index d798ec722dd..f914b98d923 100644
--- a/tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr
+++ b/tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `Foo { first: false, second: Some([_, _, _, _]) }` not covered
+error[E0004]: non-exhaustive patterns: `Foo { first: false, second: Some([0_usize, _, _, _]) }` and `Foo { first: false, second: Some([2_usize.., _, _, _]) }` not covered
   --> $DIR/non-exhaustive-pattern-witness.rs:7:11
    |
 LL |     match (Foo { first: true, second: None }) {
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { first: false, second: Some([_, _, _, _]) }` not covered
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo { first: false, second: Some([0_usize, _, _, _]) }` and `Foo { first: false, second: Some([2_usize.., _, _, _]) }` not covered
    |
 note: `Foo` defined here
   --> $DIR/non-exhaustive-pattern-witness.rs:1:8
@@ -10,12 +10,10 @@ note: `Foo` defined here
 LL | struct Foo {
    |        ^^^
    = note: the matched value is of type `Foo`
-   = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
-   = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+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 { first: false, second: Some([1, 2, 3, 4]) } => (),
-LL +         Foo { first: false, second: Some([_, _, _, _]) } => todo!()
+LL ~         Foo { first: false, second: Some([0_usize, _, _, _]) } | Foo { first: false, second: Some([2_usize.., _, _, _]) } => todo!(),
    |
 
 error[E0004]: non-exhaustive patterns: `Color::Red` not covered
@@ -35,40 +33,42 @@ LL |     Red,
 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 ~         Color::Green => (),
-LL +         Color::Red => todo!()
+LL ~         Color::Red => todo!(),
    |
 
 error[E0004]: non-exhaustive patterns: `Direction::East`, `Direction::South` and `Direction::West` not covered
-  --> $DIR/non-exhaustive-pattern-witness.rs:35:11
+  --> $DIR/non-exhaustive-pattern-witness.rs:38:11
    |
 LL |     match Direction::North {
    |           ^^^^^^^^^^^^^^^^ patterns `Direction::East`, `Direction::South` and `Direction::West` not covered
    |
 note: `Direction` defined here
-  --> $DIR/non-exhaustive-pattern-witness.rs:31:12
+  --> $DIR/non-exhaustive-pattern-witness.rs:32:5
    |
 LL | enum Direction {
    |      ---------
-LL |     North, East, South, West
-   |            ^^^^  ^^^^^  ^^^^ not covered
-   |            |     |
-   |            |     not covered
-   |            not covered
+LL |     North,
+LL |     East,
+   |     ^^^^ not covered
+LL |     South,
+   |     ^^^^^ not covered
+LL |     West,
+   |     ^^^^ not covered
    = note: the matched value is of type `Direction`
 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 ~         Direction::North => (),
-LL +         Direction::East | Direction::South | Direction::West => todo!()
+LL ~         Direction::East | Direction::South | Direction::West => todo!(),
    |
 
 error[E0004]: non-exhaustive patterns: `ExcessiveEnum::Second`, `ExcessiveEnum::Third`, `ExcessiveEnum::Fourth` and 8 more not covered
-  --> $DIR/non-exhaustive-pattern-witness.rs:46:11
+  --> $DIR/non-exhaustive-pattern-witness.rs:60:11
    |
 LL |     match ExcessiveEnum::First {
    |           ^^^^^^^^^^^^^^^^^^^^ patterns `ExcessiveEnum::Second`, `ExcessiveEnum::Third`, `ExcessiveEnum::Fourth` and 8 more not covered
    |
 note: `ExcessiveEnum` defined here
-  --> $DIR/non-exhaustive-pattern-witness.rs:41:6
+  --> $DIR/non-exhaustive-pattern-witness.rs:44:6
    |
 LL | enum ExcessiveEnum {
    |      ^^^^^^^^^^^^^
@@ -76,11 +76,11 @@ LL | enum ExcessiveEnum {
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
    |
 LL ~         ExcessiveEnum::First => (),
-LL +         _ => todo!()
+LL ~         _ => todo!(),
    |
 
 error[E0004]: non-exhaustive patterns: `Color::CustomRGBA { a: true, .. }` not covered
-  --> $DIR/non-exhaustive-pattern-witness.rs:54:11
+  --> $DIR/non-exhaustive-pattern-witness.rs:67:11
    |
 LL |     match Color::Red {
    |           ^^^^^^^^^^ pattern `Color::CustomRGBA { a: true, .. }` not covered
@@ -91,17 +91,17 @@ note: `Color` defined here
 LL | enum Color {
    |      -----
 ...
-LL |     CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
+LL |     CustomRGBA { a: bool, r: u8, g: u8, b: u8 },
    |     ^^^^^^^^^^ not covered
    = note: the matched value is of type `Color`
 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 ~         Color::CustomRGBA { a: false, r: _, g: _, b: _ } => (),
-LL +         Color::CustomRGBA { a: true, .. } => todo!()
+LL ~         Color::CustomRGBA { a: true, .. } => todo!(),
    |
 
 error[E0004]: non-exhaustive patterns: `[Enum::Second(true), Enum::Second(false)]` not covered
-  --> $DIR/non-exhaustive-pattern-witness.rs:70:11
+  --> $DIR/non-exhaustive-pattern-witness.rs:83:11
    |
 LL |     match *x {
    |           ^^ pattern `[Enum::Second(true), Enum::Second(false)]` not covered
@@ -110,11 +110,11 @@ LL |     match *x {
 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 ~         [_, _, ref tail @ .., _] => (),
-LL +         [Enum::Second(true), Enum::Second(false)] => todo!()
+LL ~         [Enum::Second(true), Enum::Second(false)] => todo!(),
    |
 
 error[E0004]: non-exhaustive patterns: `((), false)` not covered
-  --> $DIR/non-exhaustive-pattern-witness.rs:83:11
+  --> $DIR/non-exhaustive-pattern-witness.rs:96:11
    |
 LL |     match ((), false) {
    |           ^^^^^^^^^^^ pattern `((), false)` not covered
@@ -123,7 +123,7 @@ LL |     match ((), false) {
 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 ~         ((), true) => (),
-LL +         ((), false) => todo!()
+LL ~         ((), false) => todo!(),
    |
 
 error: aborting due to 7 previous errors
diff --git a/tests/ui/pattern/usefulness/refutable-pattern-errors.rs b/tests/ui/pattern/usefulness/refutable-pattern-errors.rs
index 7a3e991d593..7603da1bb2c 100644
--- a/tests/ui/pattern/usefulness/refutable-pattern-errors.rs
+++ b/tests/ui/pattern/usefulness/refutable-pattern-errors.rs
@@ -1,6 +1,6 @@
-fn func((1, (Some(1), 2..=3)): (isize, (Option<isize>, isize))) { }
+fn func((1, (Some(1), 2..=3)): (isize, (Option<isize>, isize))) {}
 //~^ ERROR refutable pattern in function argument
-//~| `(_, _)` not covered
+//~| `(..=0_isize, _)` and `(2_isize.., _)` not covered
 
 fn main() {
     let (1, (Some(1), 2..=3)) = (1, (None, 2));
diff --git a/tests/ui/pattern/usefulness/refutable-pattern-errors.stderr b/tests/ui/pattern/usefulness/refutable-pattern-errors.stderr
index beb51a4d450..e66cd113023 100644
--- a/tests/ui/pattern/usefulness/refutable-pattern-errors.stderr
+++ b/tests/ui/pattern/usefulness/refutable-pattern-errors.stderr
@@ -1,8 +1,8 @@
 error[E0005]: refutable pattern in function argument
   --> $DIR/refutable-pattern-errors.rs:1:9
    |
-LL | fn func((1, (Some(1), 2..=3)): (isize, (Option<isize>, isize))) { }
-   |         ^^^^^^^^^^^^^^^^^^^^^ pattern `(_, _)` not covered
+LL | fn func((1, (Some(1), 2..=3)): (isize, (Option<isize>, isize))) {}
+   |         ^^^^^^^^^^^^^^^^^^^^^ patterns `(..=0_isize, _)` and `(2_isize.., _)` not covered
    |
    = note: the matched value is of type `(isize, (Option<isize>, isize))`
 
diff --git a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs
index 17dc38ab25d..4203dd94d43 100644
--- a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs
+++ b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs
@@ -1,6 +1,6 @@
 fn main() {
     let f = |3: isize| println!("hello");
     //~^ ERROR refutable pattern in function argument
-    //~| `_` not covered
+    //~| `..=2_isize` and `4_isize..` not covered
     f(4);
 }
diff --git a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr
index ab3f6f69fb1..01f077909e8 100644
--- a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr
+++ b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr
@@ -2,7 +2,7 @@ error[E0005]: refutable pattern in function argument
   --> $DIR/refutable-pattern-in-fn-arg.rs:2:14
    |
 LL |     let f = |3: isize| println!("hello");
-   |              ^ pattern `_` not covered
+   |              ^ patterns `..=2_isize` and `4_isize..` not covered
    |
    = note: the matched value is of type `isize`
 help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
diff --git a/tests/ui/pattern/usefulness/tuple-struct-nonexhaustive.stderr b/tests/ui/pattern/usefulness/tuple-struct-nonexhaustive.stderr
index 50c7fc889f4..ef707ed4aa4 100644
--- a/tests/ui/pattern/usefulness/tuple-struct-nonexhaustive.stderr
+++ b/tests/ui/pattern/usefulness/tuple-struct-nonexhaustive.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `Foo(_, _)` not covered
+error[E0004]: non-exhaustive patterns: `Foo(..=0_isize, _)` and `Foo(3_isize.., _)` not covered
   --> $DIR/tuple-struct-nonexhaustive.rs:5:11
    |
 LL |     match x {
-   |           ^ pattern `Foo(_, _)` not covered
+   |           ^ patterns `Foo(..=0_isize, _)` and `Foo(3_isize.., _)` not covered
    |
 note: `Foo` defined here
   --> $DIR/tuple-struct-nonexhaustive.rs:1:8
@@ -10,12 +10,10 @@ note: `Foo` defined here
 LL | struct Foo(isize, isize);
    |        ^^^
    = note: the matched value is of type `Foo`
-   = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
-   = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+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(2, b) => println!("{}", b),
-LL +         Foo(_, _) => todo!()
+LL +         Foo(..=0_isize, _) | Foo(3_isize.., _) => todo!()
    |
 
 error: aborting due to previous error