From d1fd11f3f94a5e4f739a027adb904db714286325 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 18 Sep 2023 15:54:23 +0000 Subject: [PATCH 1/3] Prevent spurious `unreachable pattern` lints Means you'll get more `non-exhaustive` patterns --- .../src/thir/pattern/const_to_pat.rs | 61 ++++---- .../typeid-equality-by-subtyping.stderr | 14 +- .../ui/consts/const_in_pattern/issue-78057.rs | 1 - .../const_in_pattern/issue-78057.stderr | 17 +-- tests/ui/consts/match_ice.rs | 2 +- tests/ui/consts/match_ice.stderr | 21 ++- tests/ui/pattern/issue-72565.rs | 2 +- tests/ui/pattern/issue-72565.stderr | 15 +- .../ui/pattern/non-structural-match-types.rs | 4 +- .../pattern/non-structural-match-types.stderr | 27 +++- tests/ui/pattern/usefulness/consts-opaque.rs | 29 ++-- .../pattern/usefulness/consts-opaque.stderr | 137 +++--------------- ...tch-nonempty-array-forbidden-without-eq.rs | 2 +- ...nonempty-array-forbidden-without-eq.stderr | 16 +- 14 files changed, 157 insertions(+), 191 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index ae44246602996..8ef4ba5d18970 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -180,23 +180,26 @@ impl<'tcx> ConstToPat<'tcx> { if let Some(non_sm_ty) = structural { if !self.type_has_partial_eq_impl(cv.ty()) { - if let ty::Adt(def, ..) = non_sm_ty.kind() { + let e = if let ty::Adt(def, ..) = non_sm_ty.kind() { if def.is_union() { let err = UnionPattern { span: self.span }; - self.tcx().sess.emit_err(err); + self.tcx().sess.emit_err(err) } else { // fatal avoids ICE from resolution of nonexistent method (rare case). self.tcx() .sess - .emit_fatal(TypeNotStructural { span: self.span, non_sm_ty }); + .emit_fatal(TypeNotStructural { span: self.span, non_sm_ty }) } } else { let err = InvalidPattern { span: self.span, non_sm_ty }; - self.tcx().sess.emit_err(err); - } + self.tcx().sess.emit_err(err) + }; // All branches above emitted an error. Don't print any more lints. - // The pattern we return is irrelevant since we errored. - return Box::new(Pat { span: self.span, ty: cv.ty(), kind: PatKind::Wild }); + // We errored. Signal that in the pattern, so that follow up errors can be silenced. + let kind = PatKind::Constant { + value: mir::Const::Ty(ty::Const::new_error(self.tcx(), e, cv.ty())), + }; + return Box::new(Pat { span: self.span, ty: cv.ty(), kind }); } else if !self.saw_const_match_lint.get() { if let Some(mir_structural_match_violation) = mir_structural_match_violation { match non_sm_ty.kind() { @@ -346,17 +349,17 @@ impl<'tcx> ConstToPat<'tcx> { } ty::FnDef(..) => { self.saw_const_match_error.set(true); - tcx.sess.emit_err(InvalidPattern { span, non_sm_ty: ty }); - // We errored, so the pattern we generate is irrelevant. - PatKind::Wild + let e = tcx.sess.emit_err(InvalidPattern { span, non_sm_ty: ty }); + // We errored. Signal that in the pattern, so that follow up errors can be silenced. + PatKind::Constant { value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)) } } ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => { debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty,); self.saw_const_match_error.set(true); let err = TypeNotStructural { span, non_sm_ty: ty }; - tcx.sess.emit_err(err); - // We errored, so the pattern we generate is irrelevant. - PatKind::Wild + let e = tcx.sess.emit_err(err); + // We errored. Signal that in the pattern, so that follow up errors can be silenced. + PatKind::Constant { value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)) } } ty::Adt(adt_def, args) if adt_def.is_enum() => { let (&variant_index, fields) = cv.unwrap_branch().split_first().unwrap(); @@ -427,14 +430,20 @@ impl<'tcx> ConstToPat<'tcx> { } return Err(FallbackToOpaqueConst); } else { - if !self.saw_const_match_error.get() { + if self.saw_const_match_error.get() { + // We already errored. Signal that in the pattern, so that follow up errors can be silenced. + PatKind::Constant { + value: mir::Const::Ty(ty::Const::new_misc_error(tcx, ty)), + } + } else { self.saw_const_match_error.set(true); let err = TypeNotStructural { span, non_sm_ty: *pointee_ty }; - tcx.sess.emit_err(err); + let e = tcx.sess.emit_err(err); + // We errored. Signal that in the pattern, so that follow up errors can be silenced. + PatKind::Constant { + value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)), + } } - tcx.sess.delay_span_bug(span, "`saw_const_match_error` set but no error?"); - // We errored, so the pattern we generate is irrelevant. - PatKind::Wild } } // All other references are converted into deref patterns and then recursively @@ -443,11 +452,11 @@ impl<'tcx> ConstToPat<'tcx> { _ => { if !pointee_ty.is_sized(tcx, param_env) && !pointee_ty.is_slice() { let err = UnsizedPattern { span, non_sm_ty: *pointee_ty }; - tcx.sess.emit_err(err); - - // FIXME: introduce PatKind::Error to silence follow up diagnostics due to unreachable patterns. - // We errored, so the pattern we generate is irrelevant. - PatKind::Wild + let e = tcx.sess.emit_err(err); + // We errored. Signal that in the pattern, so that follow up errors can be silenced. + PatKind::Constant { + value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)), + } } else { let old = self.behind_reference.replace(true); // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when @@ -476,9 +485,9 @@ impl<'tcx> ConstToPat<'tcx> { _ => { self.saw_const_match_error.set(true); let err = InvalidPattern { span, non_sm_ty: ty }; - tcx.sess.emit_err(err); - // We errored, so the pattern we generate is irrelevant. - PatKind::Wild + let e = tcx.sess.emit_err(err); + // We errored. Signal that in the pattern, so that follow up errors can be silenced. + PatKind::Constant { value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)) } } }; diff --git a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr index 8cbd12654480a..69bc174b6beeb 100644 --- a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr +++ b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr @@ -7,5 +7,17 @@ LL | WHAT_A_TYPE => 0, = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details -error: aborting due to previous error +error[E0015]: cannot match on `TypeId` in constant functions + --> $DIR/typeid-equality-by-subtyping.rs:18:9 + | +LL | WHAT_A_TYPE => 0, + | ^^^^^^^^^^^ + | + = note: `TypeId` cannot be compared in compile-time, and therefore cannot be used in `match`es +note: impl defined here, but it is not `const` + --> $SRC_DIR/core/src/any.rs:LL:COL + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/const_in_pattern/issue-78057.rs b/tests/ui/consts/const_in_pattern/issue-78057.rs index 69cf8404da18e..88b5d68cb6017 100644 --- a/tests/ui/consts/const_in_pattern/issue-78057.rs +++ b/tests/ui/consts/const_in_pattern/issue-78057.rs @@ -12,6 +12,5 @@ fn main() { FOO => {}, //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => {} - //~^ ERROR unreachable pattern } } diff --git a/tests/ui/consts/const_in_pattern/issue-78057.stderr b/tests/ui/consts/const_in_pattern/issue-78057.stderr index df155bdb625e6..5ec68719a9732 100644 --- a/tests/ui/consts/const_in_pattern/issue-78057.stderr +++ b/tests/ui/consts/const_in_pattern/issue-78057.stderr @@ -7,20 +7,5 @@ LL | FOO => {}, = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details -error: unreachable pattern - --> $DIR/issue-78057.rs:14:9 - | -LL | FOO => {}, - | --- matches any value -LL | -LL | _ => {} - | ^ unreachable pattern - | -note: the lint level is defined here - --> $DIR/issue-78057.rs:1:9 - | -LL | #![deny(unreachable_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/tests/ui/consts/match_ice.rs b/tests/ui/consts/match_ice.rs index 632335c841e3a..bb31fe2212616 100644 --- a/tests/ui/consts/match_ice.rs +++ b/tests/ui/consts/match_ice.rs @@ -7,7 +7,7 @@ struct T; fn main() { const C: &S = &S; - match C { + match C { //~ ERROR: non-exhaustive patterns: `&_` not covered C => {} //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` } diff --git a/tests/ui/consts/match_ice.stderr b/tests/ui/consts/match_ice.stderr index 342d94ed31c87..cb0d22303ac89 100644 --- a/tests/ui/consts/match_ice.stderr +++ b/tests/ui/consts/match_ice.stderr @@ -7,5 +7,24 @@ LL | C => {} = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details -error: aborting due to previous error +error[E0004]: non-exhaustive patterns: `&_` not covered + --> $DIR/match_ice.rs:10:11 + | +LL | match C { + | ^ pattern `&_` not covered + | +note: `S` defined here + --> $DIR/match_ice.rs:3:8 + | +LL | struct S; + | ^ + = note: the matched value is of type `&S` +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 => {}, +LL + &_ => todo!() + | + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/pattern/issue-72565.rs b/tests/ui/pattern/issue-72565.rs index 21edb26de082e..a9a5427d2ca5b 100644 --- a/tests/ui/pattern/issue-72565.rs +++ b/tests/ui/pattern/issue-72565.rs @@ -2,7 +2,7 @@ const F: &'static dyn PartialEq = &7u32; fn main() { let a: &dyn PartialEq = &7u32; - match a { + match a { //~ ERROR: non-exhaustive patterns: `&_` not covered F => panic!(), //~ ERROR: `dyn PartialEq` cannot be used in patterns } } diff --git a/tests/ui/pattern/issue-72565.stderr b/tests/ui/pattern/issue-72565.stderr index 0519720694d70..fc9ffc0630115 100644 --- a/tests/ui/pattern/issue-72565.stderr +++ b/tests/ui/pattern/issue-72565.stderr @@ -4,5 +4,18 @@ error: `dyn PartialEq` cannot be used in patterns LL | F => panic!(), | ^ -error: aborting due to previous error +error[E0004]: non-exhaustive patterns: `&_` not covered + --> $DIR/issue-72565.rs:5:11 + | +LL | match a { + | ^ pattern `&_` not covered + | + = note: the matched value is of type `&dyn PartialEq` +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 | F => panic!(), &_ => todo!(), + | +++++++++++++++ + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/pattern/non-structural-match-types.rs b/tests/ui/pattern/non-structural-match-types.rs index 5c33154736650..e822a402931b8 100644 --- a/tests/ui/pattern/non-structural-match-types.rs +++ b/tests/ui/pattern/non-structural-match-types.rs @@ -5,10 +5,10 @@ #![feature(inline_const_pat)] fn main() { - match loop {} { + match loop {} { //~ ERROR: non-exhaustive patterns: `_` not covered const { || {} } => {}, //~ ERROR cannot be used in patterns } - match loop {} { + match loop {} { //~ ERROR: non-exhaustive patterns: `_` not covered const { async {} } => {}, //~ ERROR cannot be used in patterns } } diff --git a/tests/ui/pattern/non-structural-match-types.stderr b/tests/ui/pattern/non-structural-match-types.stderr index 43d92775e880c..984dd3fbc1564 100644 --- a/tests/ui/pattern/non-structural-match-types.stderr +++ b/tests/ui/pattern/non-structural-match-types.stderr @@ -10,5 +10,30 @@ error: `{async block@$DIR/non-structural-match-types.rs:12:17: 12:25}` cannot be LL | const { async {} } => {}, | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/non-structural-match-types.rs:8:11 + | +LL | match loop {} { + | ^^^^^^^ pattern `_` not covered + | + = note: the matched value is of type `{closure@$DIR/non-structural-match-types.rs:9:17: 9:19}` +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 | const { || {} } => {}, _ => todo!(), + | ++++++++++++++ + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/non-structural-match-types.rs:11:11 + | +LL | match loop {} { + | ^^^^^^^ pattern `_` not covered + | + = note: the matched value is of type `{async block@$DIR/non-structural-match-types.rs:12:17: 12:25}` +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 | const { async {} } => {}, _ => todo!(), + | ++++++++++++++ + +error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/pattern/usefulness/consts-opaque.rs b/tests/ui/pattern/usefulness/consts-opaque.rs index c10c6205a084b..2032cf13bc26e 100644 --- a/tests/ui/pattern/usefulness/consts-opaque.rs +++ b/tests/ui/pattern/usefulness/consts-opaque.rs @@ -30,15 +30,13 @@ fn main() { match FOO { FOO => {} //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - _ => {} // should not be emitting unreachable warning - //~^ ERROR unreachable pattern + _ => {} } match FOO_REF { FOO_REF => {} //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - Foo(_) => {} // should not be emitting unreachable warning - //~^ ERROR unreachable pattern + Foo(_) => {} } // This used to cause an ICE (https://github.com/rust-lang/rust/issues/78071) @@ -51,9 +49,8 @@ fn main() { match BAR { Bar => {} - BAR => {} // should not be emitting unreachable warning + BAR => {} //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR unreachable pattern _ => {} //~^ ERROR unreachable pattern } @@ -61,8 +58,7 @@ fn main() { match BAR { BAR => {} //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - Bar => {} // should not be emitting unreachable warning - //~^ ERROR unreachable pattern + Bar => {} _ => {} //~^ ERROR unreachable pattern } @@ -70,20 +66,16 @@ fn main() { match BAR { BAR => {} //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - BAR => {} // should not be emitting unreachable warning + BAR => {} //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR unreachable pattern - _ => {} // should not be emitting unreachable warning - //~^ ERROR unreachable pattern + _ => {} } match BAZ { BAZ => {} //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - Baz::Baz1 => {} // should not be emitting unreachable warning - //~^ ERROR unreachable pattern + Baz::Baz1 => {} _ => {} - //~^ ERROR unreachable pattern } match BAZ { @@ -91,16 +83,13 @@ fn main() { BAZ => {} //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => {} - //~^ ERROR unreachable pattern } match BAZ { BAZ => {} //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - Baz::Baz2 => {} // should not be emitting unreachable warning - //~^ ERROR unreachable pattern - _ => {} // should not be emitting unreachable warning - //~^ ERROR unreachable pattern + Baz::Baz2 => {} + _ => {} } type Quux = fn(usize, usize) -> usize; diff --git a/tests/ui/pattern/usefulness/consts-opaque.stderr b/tests/ui/pattern/usefulness/consts-opaque.stderr index e01b06ccc82e4..cd88e6a22e4a5 100644 --- a/tests/ui/pattern/usefulness/consts-opaque.stderr +++ b/tests/ui/pattern/usefulness/consts-opaque.stderr @@ -8,7 +8,7 @@ LL | FOO => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:38:9 + --> $DIR/consts-opaque.rs:37:9 | LL | FOO_REF => {} | ^^^^^^^ @@ -17,7 +17,7 @@ LL | FOO_REF => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details warning: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:46:9 + --> $DIR/consts-opaque.rs:44:9 | LL | FOO_REF_REF => {} | ^^^^^^^^^^^ @@ -29,16 +29,16 @@ LL | FOO_REF_REF => {} = note: `#[warn(indirect_structural_match)]` on by default error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:54:9 + --> $DIR/consts-opaque.rs:52:9 | -LL | BAR => {} // should not be emitting unreachable warning +LL | BAR => {} | ^^^ | = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:62:9 + --> $DIR/consts-opaque.rs:59:9 | LL | BAR => {} | ^^^ @@ -47,7 +47,7 @@ LL | BAR => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:71:9 + --> $DIR/consts-opaque.rs:67:9 | LL | BAR => {} | ^^^ @@ -56,16 +56,16 @@ LL | BAR => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:73:9 + --> $DIR/consts-opaque.rs:69:9 | -LL | BAR => {} // should not be emitting unreachable warning +LL | BAR => {} | ^^^ | = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:81:9 + --> $DIR/consts-opaque.rs:75:9 | LL | BAZ => {} | ^^^ @@ -74,7 +74,7 @@ LL | BAZ => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:91:9 + --> $DIR/consts-opaque.rs:83:9 | LL | BAZ => {} | ^^^ @@ -83,7 +83,7 @@ LL | BAZ => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:98:9 + --> $DIR/consts-opaque.rs:89:9 | LL | BAZ => {} | ^^^ @@ -92,12 +92,12 @@ LL | BAZ => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: unreachable pattern - --> $DIR/consts-opaque.rs:33:9 + --> $DIR/consts-opaque.rs:54:9 | -LL | FOO => {} +LL | Bar => {} | --- matches any value -LL | -LL | _ => {} // should not be emitting unreachable warning +... +LL | _ => {} | ^ unreachable pattern | note: the lint level is defined here @@ -107,120 +107,21 @@ LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:40:9 - | -LL | FOO_REF => {} - | ------- matches any value -LL | -LL | Foo(_) => {} // should not be emitting unreachable warning - | ^^^^^^ unreachable pattern - -error: unreachable pattern - --> $DIR/consts-opaque.rs:54:9 - | -LL | Bar => {} - | --- matches any value -LL | BAR => {} // should not be emitting unreachable warning - | ^^^ unreachable pattern - -error: unreachable pattern - --> $DIR/consts-opaque.rs:57:9 + --> $DIR/consts-opaque.rs:62:9 | LL | Bar => {} | --- matches any value -... -LL | _ => {} - | ^ unreachable pattern - -error: unreachable pattern - --> $DIR/consts-opaque.rs:64:9 - | -LL | BAR => {} - | --- matches any value -LL | -LL | Bar => {} // should not be emitting unreachable warning - | ^^^ unreachable pattern - -error: unreachable pattern - --> $DIR/consts-opaque.rs:66:9 - | -LL | BAR => {} - | --- matches any value -... -LL | _ => {} - | ^ unreachable pattern - -error: unreachable pattern - --> $DIR/consts-opaque.rs:73:9 - | -LL | BAR => {} - | --- matches any value -LL | -LL | BAR => {} // should not be emitting unreachable warning - | ^^^ unreachable pattern - -error: unreachable pattern - --> $DIR/consts-opaque.rs:76:9 - | -LL | BAR => {} - | --- matches any value -... -LL | _ => {} // should not be emitting unreachable warning - | ^ unreachable pattern - -error: unreachable pattern - --> $DIR/consts-opaque.rs:83:9 - | -LL | BAZ => {} - | --- matches any value -LL | -LL | Baz::Baz1 => {} // should not be emitting unreachable warning - | ^^^^^^^^^ unreachable pattern - -error: unreachable pattern - --> $DIR/consts-opaque.rs:85:9 - | -LL | BAZ => {} - | --- matches any value -... -LL | _ => {} - | ^ unreachable pattern - -error: unreachable pattern - --> $DIR/consts-opaque.rs:93:9 - | -LL | BAZ => {} - | --- matches any value -LL | LL | _ => {} | ^ unreachable pattern -error: unreachable pattern - --> $DIR/consts-opaque.rs:100:9 - | -LL | BAZ => {} - | --- matches any value -LL | -LL | Baz::Baz2 => {} // should not be emitting unreachable warning - | ^^^^^^^^^ unreachable pattern - -error: unreachable pattern - --> $DIR/consts-opaque.rs:102:9 - | -LL | BAZ => {} - | --- matches any value -... -LL | _ => {} // should not be emitting unreachable warning - | ^ unreachable pattern - error[E0004]: non-exhaustive patterns: `Wrap(_)` not covered - --> $DIR/consts-opaque.rs:135:11 + --> $DIR/consts-opaque.rs:124:11 | LL | match WRAPQUUX { | ^^^^^^^^ pattern `Wrap(_)` not covered | note: `Wrap usize>` defined here - --> $DIR/consts-opaque.rs:117:12 + --> $DIR/consts-opaque.rs:106:12 | LL | struct Wrap(T); | ^^^^ @@ -231,6 +132,6 @@ LL ~ WRAPQUUX => {}, LL + Wrap(_) => todo!() | -error: aborting due to 23 previous errors; 1 warning emitted +error: aborting due to 12 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.rs index 151a475c91906..91a5e5a58e1dc 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.rs +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.rs @@ -12,7 +12,7 @@ struct B(i32); fn main() { const FOO: [B; 1] = [B(0)]; - match [B(1)] { + match [B(1)] { //~ ERROR: non-exhaustive patterns: `[_]` not covered FOO => { } //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` } diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.stderr index 6adebada0437d..5b81af98dfa88 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.stderr @@ -7,5 +7,19 @@ LL | FOO => { } = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details -error: aborting due to previous error +error[E0004]: non-exhaustive patterns: `[_]` not covered + --> $DIR/match-nonempty-array-forbidden-without-eq.rs:15:11 + | +LL | match [B(1)] { + | ^^^^^^ pattern `[_]` not covered + | + = note: the matched value is of type `[B; 1]` +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 => { }, +LL + [_] => todo!() + | + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0004`. From e83467c3b8ffae2322f293b148b6ddaead706adb Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 19 Sep 2023 11:49:49 +0000 Subject: [PATCH 2/3] Avoid emitting the non_exhaustive error if other errors already occurred --- compiler/rustc_middle/src/thir.rs | 13 +++++--- .../src/thir/pattern/check_match.rs | 8 ++++- .../rustc_type_ir/src/structural_impls.rs | 6 ++++ tests/ui/consts/match_ice.rs | 2 +- tests/ui/consts/match_ice.stderr | 21 +------------ tests/ui/pattern/issue-72565.rs | 2 +- tests/ui/pattern/issue-72565.stderr | 15 +-------- .../ui/pattern/non-structural-match-types.rs | 8 ++--- .../pattern/non-structural-match-types.stderr | 31 ++----------------- ...tch-nonempty-array-forbidden-without-eq.rs | 2 +- ...nonempty-array-forbidden-without-eq.stderr | 16 +--------- 11 files changed, 34 insertions(+), 90 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 89934e4350e2e..08f7434a4a9c8 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -581,13 +581,13 @@ pub enum BindingMode { ByRef(BorrowKind), } -#[derive(Clone, Debug, HashStable)] +#[derive(Clone, Debug, HashStable, TypeVisitable)] pub struct FieldPat<'tcx> { pub field: FieldIdx, pub pattern: Box>, } -#[derive(Clone, Debug, HashStable)] +#[derive(Clone, Debug, HashStable, TypeVisitable)] pub struct Pat<'tcx> { pub ty: Ty<'tcx>, pub span: Span, @@ -664,7 +664,7 @@ impl<'tcx> IntoDiagnosticArg for Pat<'tcx> { } } -#[derive(Clone, Debug, HashStable)] +#[derive(Clone, Debug, HashStable, TypeVisitable)] pub struct Ascription<'tcx> { pub annotation: CanonicalUserTypeAnnotation<'tcx>, /// Variance to use when relating the `user_ty` to the **type of the value being @@ -688,7 +688,7 @@ pub struct Ascription<'tcx> { pub variance: ty::Variance, } -#[derive(Clone, Debug, HashStable)] +#[derive(Clone, Debug, HashStable, TypeVisitable)] pub enum PatKind<'tcx> { /// A wildcard pattern: `_`. Wild, @@ -702,7 +702,9 @@ pub enum PatKind<'tcx> { Binding { mutability: Mutability, name: Symbol, + #[type_visitable(ignore)] mode: BindingMode, + #[type_visitable(ignore)] var: LocalVarId, ty: Ty<'tcx>, subpattern: Option>>, @@ -771,10 +773,11 @@ pub enum PatKind<'tcx> { }, } -#[derive(Clone, Debug, PartialEq, HashStable)] +#[derive(Clone, Debug, PartialEq, HashStable, TypeVisitable)] pub struct PatRange<'tcx> { pub lo: mir::Const<'tcx>, pub hi: mir::Const<'tcx>, + #[type_visitable(ignore)] pub end: RangeEnd, } 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 d440ca319260c..93434dd3cc290 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -19,7 +19,7 @@ use rustc_hir::HirId; use rustc_middle::thir::visit::{self, Visitor}; use rustc_middle::thir::*; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; +use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::lint::builtin::{ BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS, }; @@ -682,6 +682,12 @@ fn non_exhaustive_match<'p, 'tcx>( arms: &[ArmId], expr_span: Span, ) -> ErrorGuaranteed { + for &arm in arms { + if let Err(err) = thir[arm].pattern.error_reported() { + return err; + } + } + let is_empty_match = arms.is_empty(); let non_empty_enum = match scrut_ty.kind() { ty::Adt(def, _) => def.is_enum() && !def.variants().is_empty(), diff --git a/compiler/rustc_type_ir/src/structural_impls.rs b/compiler/rustc_type_ir/src/structural_impls.rs index f36f4ec8697fa..f1037fe0bafa5 100644 --- a/compiler/rustc_type_ir/src/structural_impls.rs +++ b/compiler/rustc_type_ir/src/structural_impls.rs @@ -153,6 +153,12 @@ impl> TypeVisitable for &[T] { } } +impl> TypeVisitable for Box<[T]> { + fn visit_with>(&self, visitor: &mut V) -> ControlFlow { + self.iter().try_for_each(|t| t.visit_with(visitor)) + } +} + impl, Ix: Idx> TypeFoldable for IndexVec { fn try_fold_with>(self, folder: &mut F) -> Result { self.try_map_id(|x| x.try_fold_with(folder)) diff --git a/tests/ui/consts/match_ice.rs b/tests/ui/consts/match_ice.rs index bb31fe2212616..632335c841e3a 100644 --- a/tests/ui/consts/match_ice.rs +++ b/tests/ui/consts/match_ice.rs @@ -7,7 +7,7 @@ struct T; fn main() { const C: &S = &S; - match C { //~ ERROR: non-exhaustive patterns: `&_` not covered + match C { C => {} //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` } diff --git a/tests/ui/consts/match_ice.stderr b/tests/ui/consts/match_ice.stderr index cb0d22303ac89..342d94ed31c87 100644 --- a/tests/ui/consts/match_ice.stderr +++ b/tests/ui/consts/match_ice.stderr @@ -7,24 +7,5 @@ LL | C => {} = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details -error[E0004]: non-exhaustive patterns: `&_` not covered - --> $DIR/match_ice.rs:10:11 - | -LL | match C { - | ^ pattern `&_` not covered - | -note: `S` defined here - --> $DIR/match_ice.rs:3:8 - | -LL | struct S; - | ^ - = note: the matched value is of type `&S` -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 => {}, -LL + &_ => todo!() - | - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/pattern/issue-72565.rs b/tests/ui/pattern/issue-72565.rs index a9a5427d2ca5b..21edb26de082e 100644 --- a/tests/ui/pattern/issue-72565.rs +++ b/tests/ui/pattern/issue-72565.rs @@ -2,7 +2,7 @@ const F: &'static dyn PartialEq = &7u32; fn main() { let a: &dyn PartialEq = &7u32; - match a { //~ ERROR: non-exhaustive patterns: `&_` not covered + match a { F => panic!(), //~ ERROR: `dyn PartialEq` cannot be used in patterns } } diff --git a/tests/ui/pattern/issue-72565.stderr b/tests/ui/pattern/issue-72565.stderr index fc9ffc0630115..0519720694d70 100644 --- a/tests/ui/pattern/issue-72565.stderr +++ b/tests/ui/pattern/issue-72565.stderr @@ -4,18 +4,5 @@ error: `dyn PartialEq` cannot be used in patterns LL | F => panic!(), | ^ -error[E0004]: non-exhaustive patterns: `&_` not covered - --> $DIR/issue-72565.rs:5:11 - | -LL | match a { - | ^ pattern `&_` not covered - | - = note: the matched value is of type `&dyn PartialEq` -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 | F => panic!(), &_ => todo!(), - | +++++++++++++++ - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/pattern/non-structural-match-types.rs b/tests/ui/pattern/non-structural-match-types.rs index e822a402931b8..fc52ee3d013c1 100644 --- a/tests/ui/pattern/non-structural-match-types.rs +++ b/tests/ui/pattern/non-structural-match-types.rs @@ -5,10 +5,10 @@ #![feature(inline_const_pat)] fn main() { - match loop {} { //~ ERROR: non-exhaustive patterns: `_` not covered - const { || {} } => {}, //~ ERROR cannot be used in patterns + match loop {} { + const { || {} } => {} //~ ERROR cannot be used in patterns } - match loop {} { //~ ERROR: non-exhaustive patterns: `_` not covered - const { async {} } => {}, //~ ERROR cannot be used in patterns + match loop {} { + const { async {} } => {} //~ ERROR cannot be used in patterns } } diff --git a/tests/ui/pattern/non-structural-match-types.stderr b/tests/ui/pattern/non-structural-match-types.stderr index 984dd3fbc1564..f3e0665fef51d 100644 --- a/tests/ui/pattern/non-structural-match-types.stderr +++ b/tests/ui/pattern/non-structural-match-types.stderr @@ -1,39 +1,14 @@ error: `{closure@$DIR/non-structural-match-types.rs:9:17: 9:19}` cannot be used in patterns --> $DIR/non-structural-match-types.rs:9:9 | -LL | const { || {} } => {}, +LL | const { || {} } => {} | ^^^^^^^^^^^^^^^ error: `{async block@$DIR/non-structural-match-types.rs:12:17: 12:25}` cannot be used in patterns --> $DIR/non-structural-match-types.rs:12:9 | -LL | const { async {} } => {}, +LL | const { async {} } => {} | ^^^^^^^^^^^^^^^^^^ -error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/non-structural-match-types.rs:8:11 - | -LL | match loop {} { - | ^^^^^^^ pattern `_` not covered - | - = note: the matched value is of type `{closure@$DIR/non-structural-match-types.rs:9:17: 9:19}` -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 | const { || {} } => {}, _ => todo!(), - | ++++++++++++++ - -error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/non-structural-match-types.rs:11:11 - | -LL | match loop {} { - | ^^^^^^^ pattern `_` not covered - | - = note: the matched value is of type `{async block@$DIR/non-structural-match-types.rs:12:17: 12:25}` -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 | const { async {} } => {}, _ => todo!(), - | ++++++++++++++ - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.rs index 91a5e5a58e1dc..151a475c91906 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.rs +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.rs @@ -12,7 +12,7 @@ struct B(i32); fn main() { const FOO: [B; 1] = [B(0)]; - match [B(1)] { //~ ERROR: non-exhaustive patterns: `[_]` not covered + match [B(1)] { FOO => { } //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` } diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.stderr index 5b81af98dfa88..6adebada0437d 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.stderr @@ -7,19 +7,5 @@ LL | FOO => { } = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details -error[E0004]: non-exhaustive patterns: `[_]` not covered - --> $DIR/match-nonempty-array-forbidden-without-eq.rs:15:11 - | -LL | match [B(1)] { - | ^^^^^^ pattern `[_]` not covered - | - = note: the matched value is of type `[B; 1]` -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 => { }, -LL + [_] => todo!() - | - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0004`. From eca786cd148a222bbc0aa2662b6855ed5f0dcb60 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 28 Sep 2023 15:59:53 +0000 Subject: [PATCH 3/3] Remember the `ErrorReported` used to silence follow up errors instead of recreating it with `delay_span_bug` --- .../src/thir/pattern/const_to_pat.rs | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 8ef4ba5d18970..fde6defd87f1b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -7,7 +7,7 @@ use rustc_middle::mir; use rustc_middle::thir::{FieldPat, Pat, PatKind}; use rustc_middle::ty::{self, Ty, TyCtxt, ValTree}; use rustc_session::lint; -use rustc_span::Span; +use rustc_span::{ErrorGuaranteed, Span}; use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCause}; @@ -48,7 +48,7 @@ struct ConstToPat<'tcx> { // This tracks if we emitted some hard error for a given const value, so that // we will not subsequently issue an irrelevant lint for the same const // value. - saw_const_match_error: Cell, + saw_const_match_error: Cell>, // This tracks if we emitted some diagnostic for a given const value, so that // we will not subsequently issue an irrelevant lint for the same const @@ -84,7 +84,7 @@ impl<'tcx> ConstToPat<'tcx> { span, infcx, param_env: pat_ctxt.param_env, - saw_const_match_error: Cell::new(false), + saw_const_match_error: Cell::new(None), saw_const_match_lint: Cell::new(false), behind_reference: Cell::new(false), treat_byte_string_as_slice: pat_ctxt @@ -154,7 +154,7 @@ impl<'tcx> ConstToPat<'tcx> { }), }; - if !self.saw_const_match_error.get() { + if self.saw_const_match_error.get().is_none() { // If we were able to successfully convert the const to some pat (possibly with some // lints, but no errors), double-check that all types in the const implement // `Structural` and `PartialEq`. @@ -333,7 +333,7 @@ impl<'tcx> ConstToPat<'tcx> { // Backwards compatibility hack because we can't cause hard errors on these // types, so we compare them via `PartialEq::eq` at runtime. ty::Adt(..) if !self.type_marked_structural(ty) && self.behind_reference.get() => { - if !self.saw_const_match_error.get() && !self.saw_const_match_lint.get() { + if self.saw_const_match_error.get().is_none() && !self.saw_const_match_lint.get() { self.saw_const_match_lint.set(true); tcx.emit_spanned_lint( lint::builtin::INDIRECT_STRUCTURAL_MATCH, @@ -348,16 +348,16 @@ impl<'tcx> ConstToPat<'tcx> { return Err(FallbackToOpaqueConst); } ty::FnDef(..) => { - self.saw_const_match_error.set(true); let e = tcx.sess.emit_err(InvalidPattern { span, non_sm_ty: ty }); + self.saw_const_match_error.set(Some(e)); // We errored. Signal that in the pattern, so that follow up errors can be silenced. PatKind::Constant { value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)) } } ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => { debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty,); - self.saw_const_match_error.set(true); let err = TypeNotStructural { span, non_sm_ty: ty }; let e = tcx.sess.emit_err(err); + self.saw_const_match_error.set(Some(e)); // We errored. Signal that in the pattern, so that follow up errors can be silenced. PatKind::Constant { value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)) } } @@ -419,7 +419,9 @@ impl<'tcx> ConstToPat<'tcx> { // instead of a hard error. ty::Adt(_, _) if !self.type_marked_structural(*pointee_ty) => { if self.behind_reference.get() { - if !self.saw_const_match_error.get() && !self.saw_const_match_lint.get() { + if self.saw_const_match_error.get().is_none() + && !self.saw_const_match_lint.get() + { self.saw_const_match_lint.set(true); tcx.emit_spanned_lint( lint::builtin::INDIRECT_STRUCTURAL_MATCH, @@ -430,15 +432,15 @@ impl<'tcx> ConstToPat<'tcx> { } return Err(FallbackToOpaqueConst); } else { - if self.saw_const_match_error.get() { + if let Some(e) = self.saw_const_match_error.get() { // We already errored. Signal that in the pattern, so that follow up errors can be silenced. PatKind::Constant { - value: mir::Const::Ty(ty::Const::new_misc_error(tcx, ty)), + value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)), } } else { - self.saw_const_match_error.set(true); let err = TypeNotStructural { span, non_sm_ty: *pointee_ty }; let e = tcx.sess.emit_err(err); + self.saw_const_match_error.set(Some(e)); // We errored. Signal that in the pattern, so that follow up errors can be silenced. PatKind::Constant { value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)), @@ -483,15 +485,15 @@ impl<'tcx> ConstToPat<'tcx> { } ty::FnPtr(..) | ty::RawPtr(..) => unreachable!(), _ => { - self.saw_const_match_error.set(true); let err = InvalidPattern { span, non_sm_ty: ty }; let e = tcx.sess.emit_err(err); + self.saw_const_match_error.set(Some(e)); // We errored. Signal that in the pattern, so that follow up errors can be silenced. PatKind::Constant { value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)) } } }; - if !self.saw_const_match_error.get() + if self.saw_const_match_error.get().is_none() && !self.saw_const_match_lint.get() && mir_structural_match_violation // FIXME(#73448): Find a way to bring const qualification into parity with