summaryrefslogtreecommitdiffstats
path: root/tests/ui/consts/const_in_pattern
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:13 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:13 +0000
commit218caa410aa38c29984be31a5229b9fa717560ee (patch)
treec54bd55eeb6e4c508940a30e94c0032fbd45d677 /tests/ui/consts/const_in_pattern
parentReleasing progress-linux version 1.67.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-218caa410aa38c29984be31a5229b9fa717560ee.tar.xz
rustc-218caa410aa38c29984be31a5229b9fa717560ee.zip
Merging upstream version 1.68.2+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/ui/consts/const_in_pattern')
-rw-r--r--tests/ui/consts/const_in_pattern/accept_structural.rs66
-rw-r--r--tests/ui/consts/const_in_pattern/auxiliary/consts.rs16
-rw-r--r--tests/ui/consts/const_in_pattern/cross-crate-fail.rs25
-rw-r--r--tests/ui/consts/const_in_pattern/cross-crate-fail.stderr14
-rw-r--r--tests/ui/consts/const_in_pattern/cross-crate-pass.rs23
-rw-r--r--tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs32
-rw-r--r--tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs36
-rw-r--r--tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr12
-rw-r--r--tests/ui/consts/const_in_pattern/incomplete-slice.rs15
-rw-r--r--tests/ui/consts/const_in_pattern/incomplete-slice.stderr26
-rw-r--r--tests/ui/consts/const_in_pattern/issue-44333.rs25
-rw-r--r--tests/ui/consts/const_in_pattern/issue-44333.stderr25
-rw-r--r--tests/ui/consts/const_in_pattern/issue-53708.rs11
-rw-r--r--tests/ui/consts/const_in_pattern/issue-62614.rs24
-rw-r--r--tests/ui/consts/const_in_pattern/issue-65466.rs21
-rw-r--r--tests/ui/consts/const_in_pattern/issue-73431.rs29
-rw-r--r--tests/ui/consts/const_in_pattern/issue-73431.stderr1
-rw-r--r--tests/ui/consts/const_in_pattern/issue-78057.rs17
-rw-r--r--tests/ui/consts/const_in_pattern/issue-78057.stderr23
-rw-r--r--tests/ui/consts/const_in_pattern/no-eq-branch-fail.rs25
-rw-r--r--tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr8
-rw-r--r--tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs32
-rw-r--r--tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr8
-rw-r--r--tests/ui/consts/const_in_pattern/reject_non_structural.rs83
-rw-r--r--tests/ui/consts/const_in_pattern/reject_non_structural.stderr76
-rw-r--r--tests/ui/consts/const_in_pattern/warn_corner_cases.rs41
-rw-r--r--tests/ui/consts/const_in_pattern/warn_corner_cases.stderr30
27 files changed, 744 insertions, 0 deletions
diff --git a/tests/ui/consts/const_in_pattern/accept_structural.rs b/tests/ui/consts/const_in_pattern/accept_structural.rs
new file mode 100644
index 000000000..1f56f581c
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/accept_structural.rs
@@ -0,0 +1,66 @@
+// run-pass
+
+#![warn(indirect_structural_match)]
+
+// This test is checking our logic for structural match checking by enumerating
+// the different kinds of const expressions. This test is collecting cases where
+// we have accepted the const expression as a pattern in the past and wish to
+// continue doing so.
+//
+// Even if a non-structural-match type is part of an expression in a const's
+// definition, that does not necessarily disqualify the const from being a match
+// pattern: in principle, we just need the types involved in the final value to
+// be structurally matchable.
+
+// See also RFC 1445
+
+#![feature(type_ascription)]
+
+#[derive(Copy, Clone, Debug)]
+struct NoPartialEq(u32);
+
+#[derive(Copy, Clone, Debug)]
+struct NoDerive(u32);
+
+// This impl makes `NoDerive` irreflexive.
+impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
+impl Eq for NoDerive { }
+
+type OND = Option<NoDerive>;
+
+fn main() {
+ const FIELD1: u32 = NoPartialEq(1).0;
+ match 1 { FIELD1 => dbg!(FIELD1), _ => panic!("whoops"), };
+ const FIELD2: u32 = NoDerive(1).0;
+ match 1 { FIELD2 => dbg!(FIELD2), _ => panic!("whoops"), };
+
+ enum CLike { One = 1, #[allow(dead_code)] Two = 2, }
+ const ONE_CAST: u32 = CLike::One as u32;
+ match 1 { ONE_CAST => dbg!(ONE_CAST), _ => panic!("whoops"), };
+
+ const NO_DERIVE_NONE: OND = None;
+ const INDIRECT: OND = NO_DERIVE_NONE;
+ match None { INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), };
+
+ const TUPLE: (OND, OND) = (None, None);
+ match (None, None) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), };
+
+ const TYPE_ASCRIPTION: OND = type_ascribe!(None, OND);
+ match None { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), };
+
+ const ARRAY: [OND; 2] = [None, None];
+ match [None; 2] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), };
+
+ const REPEAT: [OND; 2] = [None; 2];
+ match [None, None] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), };
+
+ trait Trait: Sized { const ASSOC: Option<Self>; }
+ impl Trait for NoDerive { const ASSOC: Option<NoDerive> = None; }
+ match None { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), };
+
+ const BLOCK: OND = { NoDerive(10); None };
+ match None { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), };
+
+ const ADDR_OF: &OND = &None;
+ match &None { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), };
+}
diff --git a/tests/ui/consts/const_in_pattern/auxiliary/consts.rs b/tests/ui/consts/const_in_pattern/auxiliary/consts.rs
new file mode 100644
index 000000000..b438bcd9f
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/auxiliary/consts.rs
@@ -0,0 +1,16 @@
+pub struct CustomEq;
+
+impl Eq for CustomEq {}
+impl PartialEq for CustomEq {
+ fn eq(&self, _: &Self) -> bool {
+ false
+ }
+}
+
+pub const NONE: Option<CustomEq> = None;
+pub const SOME: Option<CustomEq> = Some(CustomEq);
+
+pub trait AssocConst {
+ const NONE: Option<CustomEq> = None;
+ const SOME: Option<CustomEq> = Some(CustomEq);
+}
diff --git a/tests/ui/consts/const_in_pattern/cross-crate-fail.rs b/tests/ui/consts/const_in_pattern/cross-crate-fail.rs
new file mode 100644
index 000000000..ab297f54d
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/cross-crate-fail.rs
@@ -0,0 +1,25 @@
+// aux-build:consts.rs
+
+#![warn(indirect_structural_match)]
+
+extern crate consts;
+
+struct Defaulted;
+impl consts::AssocConst for Defaulted {}
+
+fn main() {
+ let _ = Defaulted;
+ match None {
+ consts::SOME => panic!(),
+ //~^ must be annotated with `#[derive(PartialEq, Eq)]`
+
+ _ => {}
+ }
+
+ match None {
+ <Defaulted as consts::AssocConst>::SOME => panic!(),
+ //~^ must be annotated with `#[derive(PartialEq, Eq)]`
+
+ _ => {}
+ }
+}
diff --git a/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr b/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr
new file mode 100644
index 000000000..a8066a88c
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr
@@ -0,0 +1,14 @@
+error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/cross-crate-fail.rs:13:9
+ |
+LL | consts::SOME => panic!(),
+ | ^^^^^^^^^^^^
+
+error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/cross-crate-fail.rs:20:9
+ |
+LL | <Defaulted as consts::AssocConst>::SOME => panic!(),
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/consts/const_in_pattern/cross-crate-pass.rs b/tests/ui/consts/const_in_pattern/cross-crate-pass.rs
new file mode 100644
index 000000000..1d8ecf8ae
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/cross-crate-pass.rs
@@ -0,0 +1,23 @@
+// run-pass
+// aux-build:consts.rs
+
+#![warn(indirect_structural_match)]
+
+extern crate consts;
+use consts::CustomEq;
+
+struct Defaulted;
+impl consts::AssocConst for Defaulted {}
+
+fn main() {
+ let _ = Defaulted;
+ match Some(CustomEq) {
+ consts::NONE => panic!(),
+ _ => {}
+ }
+
+ match Some(CustomEq) {
+ <Defaulted as consts::AssocConst>::NONE => panic!(),
+ _ => {}
+ }
+}
diff --git a/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs b/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs
new file mode 100644
index 000000000..a38731ceb
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs
@@ -0,0 +1,32 @@
+// run-pass
+
+#![warn(indirect_structural_match)]
+
+struct CustomEq;
+
+impl Eq for CustomEq {}
+impl PartialEq for CustomEq {
+ fn eq(&self, _: &Self) -> bool {
+ false
+ }
+}
+
+#[derive(PartialEq, Eq)]
+enum Foo {
+ Bar,
+ Baz,
+ Qux(CustomEq),
+}
+
+const BAR_BAZ: Foo = if 42 == 42 {
+ Foo::Bar
+} else {
+ Foo::Baz
+};
+
+fn main() {
+ match Foo::Qux(CustomEq) {
+ BAR_BAZ => panic!(),
+ _ => {}
+ }
+}
diff --git a/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs b/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs
new file mode 100644
index 000000000..856d20417
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs
@@ -0,0 +1,36 @@
+// check-pass
+
+struct CustomEq;
+
+impl Eq for CustomEq {}
+impl PartialEq for CustomEq {
+ fn eq(&self, _: &Self) -> bool {
+ false
+ }
+}
+
+#[derive(PartialEq, Eq)]
+enum Foo {
+ Bar,
+ Baz,
+ Qux(CustomEq),
+}
+
+// We know that `BAR_BAZ` will always be `Foo::Bar` and thus eligible for structural matching, but
+// dataflow will be more conservative.
+const BAR_BAZ: Foo = if 42 == 42 {
+ Foo::Bar
+} else {
+ Foo::Qux(CustomEq)
+};
+
+fn main() {
+ match Foo::Qux(CustomEq) {
+ BAR_BAZ => panic!(),
+ //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]`
+ //~| WARN this was previously accepted
+ //~| NOTE see issue #73448
+ //~| NOTE `#[warn(nontrivial_structural_match)]` on by default
+ _ => {}
+ }
+}
diff --git a/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr b/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr
new file mode 100644
index 000000000..223482722
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr
@@ -0,0 +1,12 @@
+warning: to use a constant of type `CustomEq` in a pattern, the constant's initializer must be trivial or `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/custom-eq-branch-warn.rs:29:9
+ |
+LL | BAR_BAZ => panic!(),
+ | ^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/73448>
+ = note: `#[warn(nontrivial_structural_match)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/consts/const_in_pattern/incomplete-slice.rs b/tests/ui/consts/const_in_pattern/incomplete-slice.rs
new file mode 100644
index 000000000..e1ccda71d
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/incomplete-slice.rs
@@ -0,0 +1,15 @@
+#[derive(PartialEq)]
+enum E {
+ A,
+}
+
+const E_SL: &[E] = &[E::A];
+
+fn main() {
+ match &[][..] {
+ //~^ ERROR non-exhaustive patterns: `&_` not covered [E0004]
+ E_SL => {}
+ //~^ WARN to use a constant of type `E` in a pattern, `E` must be annotated with `#[derive(PartialEq, Eq)]`
+ //~| WARN this was previously accepted by the compiler but is being phased out
+ }
+}
diff --git a/tests/ui/consts/const_in_pattern/incomplete-slice.stderr b/tests/ui/consts/const_in_pattern/incomplete-slice.stderr
new file mode 100644
index 000000000..ddc576ced
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/incomplete-slice.stderr
@@ -0,0 +1,26 @@
+warning: to use a constant of type `E` in a pattern, `E` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/incomplete-slice.rs:11:9
+ |
+LL | E_SL => {}
+ | ^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
+ = note: `#[warn(indirect_structural_match)]` on by default
+
+error[E0004]: non-exhaustive patterns: `&_` not covered
+ --> $DIR/incomplete-slice.rs:9:11
+ |
+LL | match &[][..] {
+ | ^^^^^^^ pattern `&_` not covered
+ |
+ = note: the matched value is of type `&[E]`
+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 ~ E_SL => {}
+LL + &_ => todo!()
+ |
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/consts/const_in_pattern/issue-44333.rs b/tests/ui/consts/const_in_pattern/issue-44333.rs
new file mode 100644
index 000000000..96e8795e5
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/issue-44333.rs
@@ -0,0 +1,25 @@
+// run-pass
+
+#![warn(pointer_structural_match)]
+
+type Func = fn(usize, usize) -> usize;
+
+fn foo(a: usize, b: usize) -> usize { a + b }
+fn bar(a: usize, b: usize) -> usize { a * b }
+fn test(x: usize) -> Func {
+ if x % 2 == 0 { foo }
+ else { bar }
+}
+
+const FOO: Func = foo;
+const BAR: Func = bar;
+
+fn main() {
+ match test(std::env::consts::ARCH.len()) {
+ FOO => println!("foo"), //~ WARN pointers in patterns behave unpredictably
+ //~^ WARN will become a hard error
+ BAR => println!("bar"), //~ WARN pointers in patterns behave unpredictably
+ //~^ WARN will become a hard error
+ _ => unreachable!(),
+ }
+}
diff --git a/tests/ui/consts/const_in_pattern/issue-44333.stderr b/tests/ui/consts/const_in_pattern/issue-44333.stderr
new file mode 100644
index 000000000..731ef509c
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/issue-44333.stderr
@@ -0,0 +1,25 @@
+warning: function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+ --> $DIR/issue-44333.rs:19:9
+ |
+LL | FOO => println!("foo"),
+ | ^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+note: the lint level is defined here
+ --> $DIR/issue-44333.rs:3:9
+ |
+LL | #![warn(pointer_structural_match)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+ --> $DIR/issue-44333.rs:21:9
+ |
+LL | BAR => println!("bar"),
+ | ^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/consts/const_in_pattern/issue-53708.rs b/tests/ui/consts/const_in_pattern/issue-53708.rs
new file mode 100644
index 000000000..355ba6379
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/issue-53708.rs
@@ -0,0 +1,11 @@
+// check-pass
+// https://github.com/rust-lang/rust/issues/53708
+#[derive(PartialEq, Eq)]
+struct S;
+
+fn main() {
+ const C: &S = &S;
+ match C {
+ C => {}
+ }
+}
diff --git a/tests/ui/consts/const_in_pattern/issue-62614.rs b/tests/ui/consts/const_in_pattern/issue-62614.rs
new file mode 100644
index 000000000..4ea9a2836
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/issue-62614.rs
@@ -0,0 +1,24 @@
+// run-pass
+
+struct Sum(u32, u32);
+
+impl PartialEq for Sum {
+ fn eq(&self, other: &Self) -> bool { self.0 + self.1 == other.0 + other.1 }
+}
+
+impl Eq for Sum { }
+
+#[derive(PartialEq, Eq)]
+enum Eek {
+ TheConst,
+ UnusedByTheConst(Sum)
+}
+
+const THE_CONST: Eek = Eek::TheConst;
+
+pub fn main() {
+ match Eek::UnusedByTheConst(Sum(1,2)) {
+ THE_CONST => { panic!(); }
+ _ => {}
+ }
+}
diff --git a/tests/ui/consts/const_in_pattern/issue-65466.rs b/tests/ui/consts/const_in_pattern/issue-65466.rs
new file mode 100644
index 000000000..2b421f4c7
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/issue-65466.rs
@@ -0,0 +1,21 @@
+#![deny(indirect_structural_match)]
+
+// check-pass
+
+#[derive(PartialEq, Eq)]
+enum O<T> {
+ Some(*const T), // Can also use PhantomData<T>
+ None,
+}
+
+struct B;
+
+const C: &[O<B>] = &[O::None];
+
+fn main() {
+ let x = O::None;
+ match &[x][..] {
+ C => (),
+ _ => (),
+ }
+}
diff --git a/tests/ui/consts/const_in_pattern/issue-73431.rs b/tests/ui/consts/const_in_pattern/issue-73431.rs
new file mode 100644
index 000000000..fa18a3af1
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/issue-73431.rs
@@ -0,0 +1,29 @@
+// run-pass
+
+// Regression test for https://github.com/rust-lang/rust/issues/73431.
+
+pub trait Zero {
+ const ZERO: Self;
+}
+
+impl Zero for usize {
+ const ZERO: Self = 0;
+}
+
+impl<T: Zero> Zero for Wrapper<T> {
+ const ZERO: Self = Wrapper(T::ZERO);
+}
+
+#[derive(Debug, PartialEq, Eq)]
+pub struct Wrapper<T>(T);
+
+fn is_zero(x: Wrapper<usize>) -> bool {
+ match x {
+ Zero::ZERO => true,
+ _ => false,
+ }
+}
+
+fn main() {
+ let _ = is_zero(Wrapper(42));
+}
diff --git a/tests/ui/consts/const_in_pattern/issue-73431.stderr b/tests/ui/consts/const_in_pattern/issue-73431.stderr
new file mode 100644
index 000000000..c82dea4aa
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/issue-73431.stderr
@@ -0,0 +1 @@
+WARN rustc_mir_build::thir::pattern::const_to_pat MIR const-checker found novel structural match violation. See #73448.
diff --git a/tests/ui/consts/const_in_pattern/issue-78057.rs b/tests/ui/consts/const_in_pattern/issue-78057.rs
new file mode 100644
index 000000000..69cf8404d
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/issue-78057.rs
@@ -0,0 +1,17 @@
+#![deny(unreachable_patterns)]
+
+#[derive(PartialEq)]
+struct Opaque(i32);
+
+impl Eq for Opaque {}
+
+const FOO: Opaque = Opaque(42);
+
+fn main() {
+ match FOO {
+ 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
new file mode 100644
index 000000000..35619594f
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/issue-78057.stderr
@@ -0,0 +1,23 @@
+error: to use a constant of type `Opaque` in a pattern, `Opaque` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/issue-78057.rs:12:9
+ |
+LL | FOO => {},
+ | ^^^
+
+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
+
diff --git a/tests/ui/consts/const_in_pattern/no-eq-branch-fail.rs b/tests/ui/consts/const_in_pattern/no-eq-branch-fail.rs
new file mode 100644
index 000000000..fc80d51c7
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/no-eq-branch-fail.rs
@@ -0,0 +1,25 @@
+#![warn(indirect_structural_match)]
+
+struct NoEq;
+
+enum Foo {
+ Bar,
+ Baz,
+ Qux(NoEq),
+}
+
+// Even though any of these values can be compared structurally, we still disallow it in a pattern
+// because `Foo` does not impl `PartialEq`.
+const BAR_BAZ: Foo = if 42 == 42 {
+ Foo::Baz
+} else {
+ Foo::Bar
+};
+
+fn main() {
+ match Foo::Qux(NoEq) {
+ BAR_BAZ => panic!(),
+ //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+ _ => {}
+ }
+}
diff --git a/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr b/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr
new file mode 100644
index 000000000..e505dad69
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr
@@ -0,0 +1,8 @@
+error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/no-eq-branch-fail.rs:21:9
+ |
+LL | BAR_BAZ => panic!(),
+ | ^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs
new file mode 100644
index 000000000..a8216901c
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs
@@ -0,0 +1,32 @@
+// This test is illustrating the difference between how failing to derive
+// `PartialEq` is handled compared to failing to implement it at all.
+
+// See also RFC 1445
+
+#[derive(PartialEq, Eq)]
+struct Structural(u32);
+
+struct NoPartialEq(u32);
+
+struct NoDerive(u32);
+
+// This impl makes NoDerive irreflexive.
+impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
+
+impl Eq for NoDerive { }
+
+const NO_DERIVE_NONE: Option<NoDerive> = None;
+const NO_PARTIAL_EQ_NONE: Option<NoPartialEq> = None;
+
+fn main() {
+ match None {
+ NO_DERIVE_NONE => println!("NO_DERIVE_NONE"),
+ _ => panic!("whoops"),
+ }
+
+ match None {
+ NO_PARTIAL_EQ_NONE => println!("NO_PARTIAL_EQ_NONE"),
+ //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+ _ => panic!("whoops"),
+ }
+}
diff --git a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr
new file mode 100644
index 000000000..95cfa4a9e
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr
@@ -0,0 +1,8 @@
+error: to use a constant of type `NoPartialEq` in a pattern, `NoPartialEq` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/reject_non_partial_eq.rs:28:9
+ |
+LL | NO_PARTIAL_EQ_NONE => println!("NO_PARTIAL_EQ_NONE"),
+ | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.rs b/tests/ui/consts/const_in_pattern/reject_non_structural.rs
new file mode 100644
index 000000000..75fde0d92
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/reject_non_structural.rs
@@ -0,0 +1,83 @@
+// This test of structural match checking enumerates the different kinds of
+// const definitions, collecting cases where the const pattern is rejected.
+//
+// Note: Even if a non-structural-match type is part of an expression in a
+// const's definition, that does not necessarily disqualify the const from being
+// a match pattern: in principle, we just need the types involved in the final
+// value to be structurally matchable.
+
+// See also RFC 1445
+
+#![feature(type_ascription)]
+#![warn(indirect_structural_match)]
+//~^ NOTE lint level is defined here
+
+#[derive(Copy, Clone, Debug)]
+struct NoPartialEq;
+
+#[derive(Copy, Clone, Debug)]
+struct NoDerive;
+
+// This impl makes `NoDerive` irreflexive.
+impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
+
+impl Eq for NoDerive { }
+
+type OND = Option<NoDerive>;
+
+struct TrivialEq(OND);
+
+// This impl makes `TrivialEq` trivial.
+impl PartialEq for TrivialEq { fn eq(&self, _: &Self) -> bool { true } }
+
+impl Eq for TrivialEq { }
+
+fn main() {
+ #[derive(PartialEq, Eq, Debug)]
+ enum Derive<X> { Some(X), None, }
+
+ const ENUM: Derive<NoDerive> = Derive::Some(NoDerive);
+ match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"), };
+ //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+
+ const FIELD: OND = TrivialEq(Some(NoDerive)).0;
+ match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), };
+ //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+
+ const NO_DERIVE_SOME: OND = Some(NoDerive);
+ const INDIRECT: OND = NO_DERIVE_SOME;
+ match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), };
+ //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+
+ const TUPLE: (OND, OND) = (None, Some(NoDerive));
+ match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), };
+ //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+
+ const TYPE_ASCRIPTION: OND = type_ascribe!(Some(NoDerive), OND);
+ match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), };
+ //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+
+ const ARRAY: [OND; 2] = [None, Some(NoDerive)];
+ match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), };
+ //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+
+ const REPEAT: [OND; 2] = [Some(NoDerive); 2];
+ match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), };
+ //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+ //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+
+ trait Trait: Sized { const ASSOC: Option<Self>; }
+ impl Trait for NoDerive { const ASSOC: Option<NoDerive> = Some(NoDerive); }
+ match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), };
+ //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+
+ const BLOCK: OND = { NoDerive; Some(NoDerive) };
+ match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), };
+ //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+
+ const ADDR_OF: &OND = &Some(NoDerive);
+ match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), };
+ //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]`
+ //~| WARN previously accepted by the compiler but is being phased out
+ //~| NOTE for more information, see issue #62411
+}
diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr
new file mode 100644
index 000000000..660198349
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr
@@ -0,0 +1,76 @@
+error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/reject_non_structural.rs:40:36
+ |
+LL | match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"), };
+ | ^^^^
+
+error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/reject_non_structural.rs:44:28
+ |
+LL | match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), };
+ | ^^^^^
+
+error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/reject_non_structural.rs:49:27
+ |
+LL | match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), };
+ | ^^^^^^^^
+
+error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/reject_non_structural.rs:53:36
+ |
+LL | match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), };
+ | ^^^^^
+
+error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/reject_non_structural.rs:57:28
+ |
+LL | match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), };
+ | ^^^^^^^^^^^^^^^
+
+error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/reject_non_structural.rs:61:36
+ |
+LL | match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), };
+ | ^^^^^
+
+error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/reject_non_structural.rs:65:33
+ |
+LL | match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), };
+ | ^^^^^^
+
+error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/reject_non_structural.rs:65:33
+ |
+LL | match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), };
+ | ^^^^^^
+
+error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/reject_non_structural.rs:71:28
+ |
+LL | match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), };
+ | ^^^^^^^^^^^^^^^
+
+error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/reject_non_structural.rs:75:28
+ |
+LL | match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), };
+ | ^^^^^
+
+warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/reject_non_structural.rs:79:29
+ |
+LL | match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), };
+ | ^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
+note: the lint level is defined here
+ --> $DIR/reject_non_structural.rs:12:9
+ |
+LL | #![warn(indirect_structural_match)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 10 previous errors; 1 warning emitted
+
diff --git a/tests/ui/consts/const_in_pattern/warn_corner_cases.rs b/tests/ui/consts/const_in_pattern/warn_corner_cases.rs
new file mode 100644
index 000000000..15cf3c84d
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/warn_corner_cases.rs
@@ -0,0 +1,41 @@
+// run-pass
+
+// This test is checking our logic for structural match checking by enumerating
+// the different kinds of const expressions. This test is collecting cases where
+// we have accepted the const expression as a pattern in the past but we want
+// to begin warning the user that a future version of Rust may start rejecting
+// such const expressions.
+
+// The specific corner cases we are exploring here are instances where the
+// const-evaluator computes a value that *does* meet the conditions for
+// structural-match, but the const expression itself has abstractions (like
+// calls to const functions) that may fit better with a type-based analysis
+// rather than a commitment to a specific value.
+
+#![warn(indirect_structural_match)]
+
+#[derive(Copy, Clone, Debug)]
+struct NoDerive(#[allow(unused_tuple_struct_fields)] u32);
+
+// This impl makes `NoDerive` irreflexive.
+impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
+impl Eq for NoDerive { }
+
+fn main() {
+ const INDEX: Option<NoDerive> = [None, Some(NoDerive(10))][0];
+ match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), };
+ //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]`
+ //~| WARN this was previously accepted
+
+ const fn build() -> Option<NoDerive> { None }
+ const CALL: Option<NoDerive> = build();
+ match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), };
+ //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]`
+ //~| WARN this was previously accepted
+
+ impl NoDerive { const fn none() -> Option<NoDerive> { None } }
+ const METHOD_CALL: Option<NoDerive> = NoDerive::none();
+ match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CALL), };
+ //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]`
+ //~| WARN this was previously accepted
+}
diff --git a/tests/ui/consts/const_in_pattern/warn_corner_cases.stderr b/tests/ui/consts/const_in_pattern/warn_corner_cases.stderr
new file mode 100644
index 000000000..e957a43a1
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/warn_corner_cases.stderr
@@ -0,0 +1,30 @@
+warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/warn_corner_cases.rs:26:47
+ |
+LL | match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), };
+ | ^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/73448>
+ = note: `#[warn(nontrivial_structural_match)]` on by default
+
+warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/warn_corner_cases.rs:32:47
+ |
+LL | match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), };
+ | ^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/73448>
+
+warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/warn_corner_cases.rs:38:47
+ |
+LL | match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CALL), };
+ | ^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/73448>
+
+warning: 3 warnings emitted
+