From dc0db358abe19481e475e10c32149b53370f1a1c Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 30 May 2024 05:57:31 +0200 Subject: Merging upstream version 1.72.1+dfsg1. Signed-off-by: Daniel Baumann --- ...allow-hide-behind-direct-unsafe-ptr-embedded.rs | 26 ++++ .../allow-hide-behind-direct-unsafe-ptr-param.rs | 26 ++++ ...low-hide-behind-indirect-unsafe-ptr-embedded.rs | 26 ++++ .../allow-hide-behind-indirect-unsafe-ptr-param.rs | 26 ++++ .../allow-use-behind-cousin-variant.rs | 59 +++++++++ .../cant-hide-behind-direct-struct-embedded.rs | 26 ++++ .../cant-hide-behind-direct-struct-embedded.stderr | 11 ++ .../cant-hide-behind-direct-struct-param.rs | 26 ++++ .../cant-hide-behind-direct-struct-param.stderr | 11 ++ .../cant-hide-behind-doubly-indirect-embedded.rs | 29 +++++ ...ant-hide-behind-doubly-indirect-embedded.stderr | 18 +++ .../cant-hide-behind-doubly-indirect-param.rs | 29 +++++ .../cant-hide-behind-doubly-indirect-param.stderr | 18 +++ .../cant-hide-behind-indirect-struct-embedded.rs | 29 +++++ ...ant-hide-behind-indirect-struct-embedded.stderr | 18 +++ .../cant-hide-behind-indirect-struct-param.rs | 29 +++++ .../cant-hide-behind-indirect-struct-param.stderr | 18 +++ .../feature-gate.no_gate.stderr | 21 ++++ .../feature-gate.rs | 39 ++++++ .../feature-gate.with_gate.stderr | 8 ++ .../fn-ptr-is-structurally-matchable.rs | 135 +++++++++++++++++++++ ...issue-61188-match-slice-forbidden-without-eq.rs | 19 +++ ...e-61188-match-slice-forbidden-without-eq.stderr | 11 ++ ...sue-62307-match-ref-ref-forbidden-without-eq.rs | 43 +++++++ ...62307-match-ref-ref-forbidden-without-eq.stderr | 29 +++++ .../issue-63479-match-fnptr.rs | 40 ++++++ .../issue-63479-match-fnptr.stderr | 16 +++ .../issue-6804.rs | 21 ++++ .../issue-6804.stderr | 25 ++++ ...h-empty-array-allowed-without-eq-issue-62336.rs | 17 +++ .../match-forbidden-without-eq.rs | 23 ++++ .../match-forbidden-without-eq.stderr | 21 ++++ .../match-nonempty-array-forbidden-without-eq.rs | 19 +++ ...atch-nonempty-array-forbidden-without-eq.stderr | 11 ++ .../match-requires-both-partialeq-and-eq.rs | 21 ++++ .../match-requires-both-partialeq-and-eq.stderr | 11 ++ .../phantom-data-is-structurally-matchable.rs | 53 ++++++++ .../rfc1445/eq-allows-match-on-ty-in-macro.rs | 23 ++++ .../rfc1445/eq-allows-match.rs | 17 +++ 39 files changed, 1048 insertions(+) create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-embedded.rs create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-param.rs create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-embedded.rs create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-param.rs create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-use-behind-cousin-variant.rs create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.no_gate.stderr create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.rs create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.with_gate.stderr create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.rs create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.rs create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.rs create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.stderr create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-empty-array-allowed-without-eq-issue-62336.rs create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.rs create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.stderr create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.rs create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.stderr create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/phantom-data-is-structurally-matchable.rs create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/rfc1445/eq-allows-match-on-ty-in-macro.rs create mode 100644 tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/rfc1445/eq-allows-match.rs (limited to 'tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns') diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-embedded.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-embedded.rs new file mode 100644 index 000000000..1914e1554 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-embedded.rs @@ -0,0 +1,26 @@ +// Test explores how `#[structral_match]` behaves in tandem with +// `*const` and `*mut` pointers. + +// run-pass + +#![warn(pointer_structural_match)] + +struct NoDerive(#[allow(unused_tuple_struct_fields)] i32); + +// This impl makes NoDerive irreflexive +// (which doesn't matter here because `<*const T>::eq` won't recur on `T`). +impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + +impl Eq for NoDerive { } + +#[derive(PartialEq, Eq)] +struct WrapEmbedded(*const NoDerive); + +const WRAP_UNSAFE_EMBEDDED: WrapEmbedded = WrapEmbedded(std::ptr::null()); + +fn main() { + match WRAP_UNSAFE_EMBEDDED { + WRAP_UNSAFE_EMBEDDED => { println!("WRAP_UNSAFE_EMBEDDED correctly matched itself"); } + _ => { panic!("WRAP_UNSAFE_EMBEDDED did not match itself"); } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-param.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-param.rs new file mode 100644 index 000000000..e713b003b --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-param.rs @@ -0,0 +1,26 @@ +// Test explores how `#[structral_match]` behaves in tandem with +// `*const` and `*mut` pointers. + +// run-pass + +#![warn(pointer_structural_match)] + +struct NoDerive(#[allow(unused_tuple_struct_fields)] i32); + +// This impl makes NoDerive irreflexive +// (which doesn't matter here because `<*const T>::eq` won't recur on `T`). +impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + +impl Eq for NoDerive { } + +#[derive(PartialEq, Eq)] +struct WrapParam(*const X); + +const WRAP_UNSAFE_PARAM: WrapParam = WrapParam(std::ptr::null()); + +fn main() { + match WRAP_UNSAFE_PARAM { + WRAP_UNSAFE_PARAM => { println!("WRAP_UNSAFE_PARAM correctly matched itself"); } + _ => { panic!("WRAP_UNSAFE_PARAM did not match itself"); } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-embedded.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-embedded.rs new file mode 100644 index 000000000..04da14c54 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-embedded.rs @@ -0,0 +1,26 @@ +// Test explores how `#[structral_match]` behaves in tandem with +// `*const` and `*mut` pointers. + +// run-pass + +#![warn(pointer_structural_match)] + +struct NoDerive(#[allow(unused_tuple_struct_fields)] i32); + +// This impl makes NoDerive irreflexive +// (which doesn't matter here because `<*const T>::eq` won't recur on `T`). +impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + +impl Eq for NoDerive { } + +#[derive(PartialEq, Eq)] +struct WrapEmbedded(*const NoDerive); + +const WRAP_UNSAFE_EMBEDDED: & &WrapEmbedded = & &WrapEmbedded(std::ptr::null()); + +fn main() { + match WRAP_UNSAFE_EMBEDDED { + WRAP_UNSAFE_EMBEDDED => { println!("WRAP_UNSAFE_EMBEDDED correctly matched itself"); } + _ => { panic!("WRAP_UNSAFE_EMBEDDED did not match itself"); } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-param.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-param.rs new file mode 100644 index 000000000..8313c25e7 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-param.rs @@ -0,0 +1,26 @@ +// Test explores how `#[structral_match]` behaves in tandem with +// `*const` and `*mut` pointers. + +// run-pass + +#![warn(pointer_structural_match)] + +struct NoDerive(#[allow(unused_tuple_struct_fields)] i32); + +// This impl makes NoDerive irreflexive +// (which doesn't matter here because `<*const T>::eq` won't recur on `T`). +impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + +impl Eq for NoDerive { } + +#[derive(PartialEq, Eq)] +struct WrapParam(*const X); + +const WRAP_UNSAFE_PARAM: & &WrapParam = & &WrapParam(std::ptr::null()); + +fn main() { + match WRAP_UNSAFE_PARAM { + WRAP_UNSAFE_PARAM => { println!("WRAP_UNSAFE_PARAM correctly matched itself"); } + _ => { panic!("WRAP_UNSAFE_PARAM did not match itself"); } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-use-behind-cousin-variant.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-use-behind-cousin-variant.rs new file mode 100644 index 000000000..dca8aaef1 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/allow-use-behind-cousin-variant.rs @@ -0,0 +1,59 @@ +// rust-lang/rust#62614: we want to allow matching on constants of types that +// have non-structural-match variants, *if* the constant itself does not use +// any such variant. + +// NOTE: for now, deliberately leaving the lint `indirect_structural_match` set +// to its default, so that we will not issue a diangostic even if +// rust-lang/rust#62614 remains an open issue. + +// 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; +const SUM_THREE: Eek = Eek::UnusedByTheConst(Sum(3,0)); + +const EEK_ZERO: &[Eek] = &[]; +const EEK_ONE: &[Eek] = &[THE_CONST]; + +pub fn main() { + match Eek::UnusedByTheConst(Sum(1,2)) { + ref sum if sum == &SUM_THREE => { println!("Hello 0"); } + _ => { println!("Gbye"); } + } + + match Eek::TheConst { + THE_CONST => { println!("Hello 1"); } + _ => { println!("Gbye"); } + } + + + match & &Eek::TheConst { + & & THE_CONST => { println!("Hello 2"); } + _ => { println!("Gbye"); } + } + + match & & &[][..] { + & & EEK_ZERO => { println!("Hello 3"); } + & & EEK_ONE => { println!("Gbye"); } + _ => { println!("Gbye"); } + } + + match & & &[Eek::TheConst][..] { + & & EEK_ZERO => { println!("Gby"); } + & & EEK_ONE => { println!("Hello 4"); } + _ => { println!("Gbye"); } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs new file mode 100644 index 000000000..7623839fd --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs @@ -0,0 +1,26 @@ +// This is part of a set of tests exploring the different ways a +// structural-match ADT might try to hold a +// non-structural-match in hidden manner that lets matches +// through that we had intended to reject. +// +// See discussion on rust-lang/rust#62307 and rust-lang/rust#62339 + +struct NoDerive(#[allow(unused_tuple_struct_fields)] i32); + +// This impl makes NoDerive irreflexive. +impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + +impl Eq for NoDerive { } + +#[derive(PartialEq, Eq)] +struct WrapInline(NoDerive); + +const WRAP_DIRECT_INLINE: WrapInline = WrapInline(NoDerive(0)); + +fn main() { + match WRAP_DIRECT_INLINE { + WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); } + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + _ => { println!("WRAP_DIRECT_INLINE did not match itself"); } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr new file mode 100644 index 000000000..f08ba522a --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr @@ -0,0 +1,11 @@ +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/cant-hide-behind-direct-struct-embedded.rs:22:9 + | +LL | WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); } + | ^^^^^^^^^^^^^^^^^^ + | + = 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 + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs new file mode 100644 index 000000000..93022a23d --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs @@ -0,0 +1,26 @@ +// This is part of a set of tests exploring the different ways a +// structural-match ADT might try to hold a +// non-structural-match in hidden manner that lets matches +// through that we had intended to reject. +// +// See discussion on rust-lang/rust#62307 and rust-lang/rust#62339 +#![warn(indirect_structural_match)] +struct NoDerive(i32); + +// This impl makes NoDerive irreflexive. +impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + +impl Eq for NoDerive { } + +#[derive(PartialEq, Eq)] +struct WrapParam(T); + +const WRAP_DIRECT_PARAM: WrapParam = WrapParam(NoDerive(0)); + +fn main() { + match WRAP_DIRECT_PARAM { + WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); } + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + _ => { println!("WRAP_DIRECT_PARAM did not match itself"); } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr new file mode 100644 index 000000000..012ccab17 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr @@ -0,0 +1,11 @@ +error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/cant-hide-behind-direct-struct-param.rs:22:9 + | +LL | WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); } + | ^^^^^^^^^^^^^^^^^ + | + = 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 + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs new file mode 100644 index 000000000..894739ff7 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs @@ -0,0 +1,29 @@ +// This is part of a set of tests exploring the different ways a +// structural-match ADT might try to hold a +// non-structural-match in hidden manner that lets matches +// through that we had intended to reject. +// +// See discussion on rust-lang/rust#62307 and rust-lang/rust#62339 +#![warn(indirect_structural_match)] +// run-pass + +struct NoDerive(#[allow(unused_tuple_struct_fields)] i32); + +// This impl makes NoDerive irreflexive. +impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + +impl Eq for NoDerive { } + +#[derive(PartialEq, Eq)] +struct WrapInline<'a>(&'a &'a NoDerive); + +const WRAP_DOUBLY_INDIRECT_INLINE: & &WrapInline = & &WrapInline(& & NoDerive(0)); + +fn main() { + match WRAP_DOUBLY_INDIRECT_INLINE { + WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLINE matched itself"); } + //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~| WARN this was previously accepted + _ => { println!("WRAP_DOUBLY_INDIRECT_INLINE correctly did not match itself"); } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr new file mode 100644 index 000000000..94ee2216e --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr @@ -0,0 +1,18 @@ +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/cant-hide-behind-doubly-indirect-embedded.rs:24:9 + | +LL | WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLINE matched itself"); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 + = 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 +note: the lint level is defined here + --> $DIR/cant-hide-behind-doubly-indirect-embedded.rs:7:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs new file mode 100644 index 000000000..1699dae46 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs @@ -0,0 +1,29 @@ +// This is part of a set of tests exploring the different ways a +// structural-match ADT might try to hold a +// non-structural-match in hidden manner that lets matches +// through that we had intended to reject. +// +// See discussion on rust-lang/rust#62307 and rust-lang/rust#62339 +#![warn(indirect_structural_match)] +// run-pass + +struct NoDerive(#[allow(unused_tuple_struct_fields)] i32); + +// This impl makes NoDerive irreflexive. +impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + +impl Eq for NoDerive { } + +#[derive(PartialEq, Eq)] +struct WrapParam<'a, T>(&'a &'a T); + +const WRAP_DOUBLY_INDIRECT_PARAM: & &WrapParam = & &WrapParam(& & NoDerive(0)); + +fn main() { + match WRAP_DOUBLY_INDIRECT_PARAM { + WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM matched itself"); } + //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~| WARN this was previously accepted + _ => { println!("WRAP_DOUBLY_INDIRECT_PARAM correctly did not match itself"); } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr new file mode 100644 index 000000000..666b7b95e --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr @@ -0,0 +1,18 @@ +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/cant-hide-behind-doubly-indirect-param.rs:24:9 + | +LL | WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM matched itself"); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 + = 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 +note: the lint level is defined here + --> $DIR/cant-hide-behind-doubly-indirect-param.rs:7:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs new file mode 100644 index 000000000..2672bdd9e --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs @@ -0,0 +1,29 @@ +// This is part of a set of tests exploring the different ways a +// structural-match ADT might try to hold a +// non-structural-match in hidden manner that lets matches +// through that we had intended to reject. +// +// See discussion on rust-lang/rust#62307 and rust-lang/rust#62339 +#![warn(indirect_structural_match)] +// run-pass + +struct NoDerive(#[allow(unused_tuple_struct_fields)] i32); + +// This impl makes NoDerive irreflexive. +impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + +impl Eq for NoDerive { } + +#[derive(PartialEq, Eq)] +struct WrapInline(NoDerive); + +const WRAP_INDIRECT_INLINE: & &WrapInline = & &WrapInline(NoDerive(0)); + +fn main() { + match WRAP_INDIRECT_INLINE { + WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itself"); } + //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~| WARN this was previously accepted + _ => { println!("WRAP_INDIRECT_INLINE did not match itself"); } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr new file mode 100644 index 000000000..ecbe83f3d --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr @@ -0,0 +1,18 @@ +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/cant-hide-behind-indirect-struct-embedded.rs:24:9 + | +LL | WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itself"); } + | ^^^^^^^^^^^^^^^^^^^^ + | + = 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 + = 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 +note: the lint level is defined here + --> $DIR/cant-hide-behind-indirect-struct-embedded.rs:7:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs new file mode 100644 index 000000000..3489995ae --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs @@ -0,0 +1,29 @@ +// This is part of a set of tests exploring the different ways a +// structural-match ADT might try to hold a +// non-structural-match in hidden manner that lets matches +// through that we had intended to reject. +// +// See discussion on rust-lang/rust#62307 and rust-lang/rust#62339 +#![warn(indirect_structural_match)] +// run-pass + +struct NoDerive(#[allow(unused_tuple_struct_fields)] i32); + +// This impl makes NoDerive irreflexive. +impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + +impl Eq for NoDerive { } + +#[derive(PartialEq, Eq)] +struct WrapParam(T); + +const WRAP_INDIRECT_PARAM: & &WrapParam = & &WrapParam(NoDerive(0)); + +fn main() { + match WRAP_INDIRECT_PARAM { + WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself"); } + //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~| WARN this was previously accepted + _ => { println!("WRAP_INDIRECT_PARAM correctly did not match itself"); } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr new file mode 100644 index 000000000..211990801 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr @@ -0,0 +1,18 @@ +warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/cant-hide-behind-indirect-struct-param.rs:24:9 + | +LL | WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself"); } + | ^^^^^^^^^^^^^^^^^^^ + | + = 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 + = 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 +note: the lint level is defined here + --> $DIR/cant-hide-behind-indirect-struct-param.rs:7:9 + | +LL | #![warn(indirect_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.no_gate.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.no_gate.stderr new file mode 100644 index 000000000..bd2940479 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.no_gate.stderr @@ -0,0 +1,21 @@ +error[E0658]: use of unstable library feature 'structural_match' + --> $DIR/feature-gate.rs:29:6 + | +LL | impl std::marker::StructuralPartialEq for Foo { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #31434 for more information + = help: add `#![feature(structural_match)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'structural_match' + --> $DIR/feature-gate.rs:31:6 + | +LL | impl std::marker::StructuralEq for Foo { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #31434 for more information + = help: add `#![feature(structural_match)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.rs new file mode 100644 index 000000000..ee6674097 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.rs @@ -0,0 +1,39 @@ +// Test that use of structural-match traits is only permitted with a feature gate, +// and that if a feature gate is supplied, it permits the type to be +// used in a match. + +// revisions: with_gate no_gate + +// gate-test-structural_match + +#![allow(unused)] +#![feature(rustc_attrs)] +#![cfg_attr(with_gate, feature(structural_match))] + + +struct Foo { + x: u32 +} + +const FOO: Foo = Foo { x: 0 }; + +#[rustc_error] +fn main() { //[with_gate]~ ERROR fatal error triggered by #[rustc_error] + let y = Foo { x: 1 }; + match y { + FOO => { } + _ => { } + } +} + +impl std::marker::StructuralPartialEq for Foo { } +//[no_gate]~^ ERROR use of unstable library feature 'structural_match' +impl std::marker::StructuralEq for Foo { } +//[no_gate]~^ ERROR use of unstable library feature 'structural_match' + +impl PartialEq for Foo { + fn eq(&self, other: &Self) -> bool { + self.x == other.x + } +} +impl Eq for Foo { } diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.with_gate.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.with_gate.stderr new file mode 100644 index 000000000..623fd585a --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.with_gate.stderr @@ -0,0 +1,8 @@ +error: fatal error triggered by #[rustc_error] + --> $DIR/feature-gate.rs:21:1 + | +LL | fn main() { + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.rs new file mode 100644 index 000000000..2b3fbd2a4 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.rs @@ -0,0 +1,135 @@ +// run-pass + +// This file checks that fn ptrs are considered structurally matchable. +// See also rust-lang/rust#63479. + +fn main() { + let mut count = 0; + + // A type which is not structurally matchable: + struct NotSM; + + // And one that is: + #[derive(PartialEq, Eq)] + struct SM; + + fn trivial() {} + + fn sm_to(_: SM) {} + fn not_sm_to(_: NotSM) {} + fn to_sm() -> SM { SM } + fn to_not_sm() -> NotSM { NotSM } + + // To recreate the scenario of interest in #63479, we need to add + // a ref-level-of-indirection so that we descend into the type. + + fn r_sm_to(_: &SM) {} + fn r_not_sm_to(_: &NotSM) {} + fn r_to_r_sm(_: &()) -> &SM { &SM } + fn r_to_r_not_sm(_: &()) -> &NotSM { &NotSM } + + #[derive(PartialEq, Eq)] + struct Wrap(T); + + // In the code below, we put the match input into a local so that + // we can assign it an explicit type that is an fn ptr instead of + // a singleton type of the fn itself that the type inference would + // otherwise assign. + + // Check that fn() is structural-match + const CFN1: Wrap = Wrap(trivial); + let input: Wrap = Wrap(trivial); + match Wrap(input) { + Wrap(CFN1) => count += 1, + Wrap(_) => {} + }; + + // Check that fn(T) is structural-match when T is too. + const CFN2: Wrap = Wrap(sm_to); + let input: Wrap = Wrap(sm_to); + match Wrap(input) { + Wrap(CFN2) => count += 1, + Wrap(_) => {} + }; + + // Check that fn() -> T is structural-match when T is too. + const CFN3: Wrap SM> = Wrap(to_sm); + let input: Wrap SM> = Wrap(to_sm); + match Wrap(input) { + Wrap(CFN3) => count += 1, + Wrap(_) => {} + }; + + // Check that fn(T) is structural-match even if T is not. + const CFN4: Wrap = Wrap(not_sm_to); + let input: Wrap = Wrap(not_sm_to); + match Wrap(input) { + Wrap(CFN4) => count += 1, + Wrap(_) => {} + }; + + // Check that fn() -> T is structural-match even if T is not. + const CFN5: Wrap NotSM> = Wrap(to_not_sm); + let input: Wrap NotSM> = Wrap(to_not_sm); + match Wrap(input) { + Wrap(CFN5) => count += 1, + Wrap(_) => {} + }; + + // Check that fn(&T) is structural-match when T is too. + const CFN6: Wrap = Wrap(r_sm_to); + let input: Wrap = Wrap(r_sm_to); + match Wrap(input) { + Wrap(CFN6) => count += 1, + Wrap(_) => {} + }; + + // Check that fn() -> &T is structural-match when T is too. + const CFN7: Wrap &SM> = Wrap(r_to_r_sm); + let input: Wrap &SM> = Wrap(r_to_r_sm); + match Wrap(input) { + Wrap(CFN7) => count += 1, + Wrap(_) => {} + }; + + // Check that fn(T) is structural-match even if T is not. + const CFN8: Wrap = Wrap(r_not_sm_to); + let input: Wrap = Wrap(r_not_sm_to); + match Wrap(input) { + Wrap(CFN8) => count += 1, + Wrap(_) => {} + }; + + // Check that fn() -> T is structural-match even if T is not. + const CFN9: Wrap &NotSM> = Wrap(r_to_r_not_sm); + let input: Wrap &NotSM> = Wrap(r_to_r_not_sm); + match Wrap(input) { + Wrap(CFN9) => count += 1, + Wrap(_) => {} + }; + + // Check that a type which has fn ptrs is structural-match. + #[derive(PartialEq, Eq)] + struct Foo { + alpha: fn(NotSM), + beta: fn() -> NotSM, + gamma: fn(SM), + delta: fn() -> SM, + } + + const CFOO: Foo = Foo { + alpha: not_sm_to, + beta: to_not_sm, + gamma: sm_to, + delta: to_sm, + }; + + let input = Foo { alpha: not_sm_to, beta: to_not_sm, gamma: sm_to, delta: to_sm }; + match input { + CFOO => count += 1, + Foo { .. } => {} + }; + + // Final count must be 10 now if all + assert_eq!(count, 10); +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs new file mode 100644 index 000000000..2a915d61e --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs @@ -0,0 +1,19 @@ +// Issue 61188 pointed out a case where we hit an ICE during code gen: +// the compiler assumed that `PartialEq` was always implemented on any +// use of a `const` item in a pattern context, but the pre-existing +// structural-match checking was too shallow +// (see rust-lang/rust#62307), and so we hit cases where we were +// trying to dispatch to `PartialEq` on types that did not implement +// that trait. + +struct B(i32); + +const A: &[B] = &[]; + +pub fn main() { + match &[][..] { + A => (), + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + _ => (), + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr new file mode 100644 index 000000000..46600e7b2 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr @@ -0,0 +1,11 @@ +error: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/issue-61188-match-slice-forbidden-without-eq.rs:15:9 + | +LL | A => (), + | ^ + | + = 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 + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs new file mode 100644 index 000000000..46d8ee3b6 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs @@ -0,0 +1,43 @@ +// RFC 1445 introduced `#[structural_match]`; this attribute must +// appear on the `struct`/`enum` definition for any `const` used in a +// pattern. +// +// This is our (forever-unstable) way to mark a datatype as having a +// `PartialEq` implementation that is equivalent to recursion over its +// substructure. This avoids (at least in the short term) any need to +// resolve the question of what semantics is used for such matching. +// (See RFC 1445 for more details and discussion.) + +// Issue 62307 pointed out a case where the structural-match checking +// was too shallow. +#![warn(indirect_structural_match, nontrivial_structural_match)] +// run-pass + +#[derive(Debug)] +struct B(i32); + +// Overriding `PartialEq` to use this strange notion of "equality" exposes +// whether `match` is using structural-equality or method-dispatch +// under the hood, which is the antithesis of rust-lang/rfcs#1445 +impl PartialEq for B { + fn eq(&self, other: &B) -> bool { std::cmp::min(self.0, other.0) == 0 } +} + +fn main() { + const RR_B0: & & B = & & B(0); + const RR_B1: & & B = & & B(1); + + match RR_B0 { + RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); } + //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~| WARN this was previously accepted + _ => { } + } + + match RR_B1 { + RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); } + //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` + //~| WARN this was previously accepted + _ => { } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr new file mode 100644 index 000000000..435812306 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr @@ -0,0 +1,29 @@ +warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:31:9 + | +LL | RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); } + | ^^^^^ + | + = 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 + = 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 +note: the lint level is defined here + --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:13:9 + | +LL | #![warn(indirect_structural_match, nontrivial_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:38:9 + | +LL | RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); } + | ^^^^^ + | + = 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 + = 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 + +warning: 2 warnings emitted + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.rs new file mode 100644 index 000000000..567685950 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.rs @@ -0,0 +1,40 @@ +// run-pass + +// The actual regression test from #63479. (Including this because my +// first draft at fn-ptr-is-structurally-matchable.rs failed to actually +// cover the case this hit; I've since expanded it accordingly, but the +// experience left me wary of leaving this regression test out.) + +#![warn(pointer_structural_match)] + +#[derive(Eq)] +struct A { + a: i64 +} + +impl PartialEq for A { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.a.eq(&other.a) + } +} + +type Fn = fn(&[A]); + +fn my_fn(_args: &[A]) { + println!("hello world"); +} + +const TEST: Fn = my_fn; + +struct B(Fn); + +fn main() { + let s = B(my_fn); + match s { + B(TEST) => println!("matched"), + //~^ WARN pointers in patterns behave unpredictably + //~| WARN this was previously accepted by the compiler but is being phased out + _ => panic!("didn't match") + }; +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr new file mode 100644 index 000000000..d6afc0255 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr @@ -0,0 +1,16 @@ +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-63479-match-fnptr.rs:35:7 + | +LL | B(TEST) => println!("matched"), + | ^^^^ + | + = 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 +note: the lint level is defined here + --> $DIR/issue-63479-match-fnptr.rs:8:9 + | +LL | #![warn(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.rs new file mode 100644 index 000000000..0260caa82 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.rs @@ -0,0 +1,21 @@ +// Matching against NaN should result in a warning + +#![allow(unused)] +#![deny(illegal_floating_point_literal_pattern)] + +const NAN: f64 = f64::NAN; + +fn main() { + let x = NAN; + match x { + NAN => {}, //~ ERROR floating-point types cannot be used + //~| WARN this was previously accepted by the compiler but is being phased out + _ => {}, + }; + + match [x, 1.0] { + [NAN, _] => {}, //~ ERROR floating-point types cannot be used + //~| WARN this was previously accepted by the compiler but is being phased out + _ => {}, + }; +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.stderr new file mode 100644 index 000000000..f37255d08 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804.stderr @@ -0,0 +1,25 @@ +error: floating-point types cannot be used in patterns + --> $DIR/issue-6804.rs:11:9 + | +LL | NAN => {}, + | ^^^ + | + = 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 #41620 +note: the lint level is defined here + --> $DIR/issue-6804.rs:4:9 + | +LL | #![deny(illegal_floating_point_literal_pattern)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: floating-point types cannot be used in patterns + --> $DIR/issue-6804.rs:17:10 + | +LL | [NAN, _] => {}, + | ^^^ + | + = 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 #41620 + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-empty-array-allowed-without-eq-issue-62336.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-empty-array-allowed-without-eq-issue-62336.rs new file mode 100644 index 000000000..7ba0f3a9e --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-empty-array-allowed-without-eq-issue-62336.rs @@ -0,0 +1,17 @@ +// Pre-existing behavior has been to reject patterns with consts +// denoting non-empty arrays of non-`Eq` types, but *accept* empty +// arrays of such types. +// +// See rust-lang/rust#62336. + +// run-pass + +#[derive(PartialEq, Debug)] +struct B(i32); + +fn main() { + const FOO: [B; 0] = []; + match [] { + FOO => { } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.rs new file mode 100644 index 000000000..59a22c337 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.rs @@ -0,0 +1,23 @@ +#[derive(PartialEq)] +struct Foo { + x: u32 +} + +const FOO: Foo = Foo { x: 0 }; + +fn main() { + let y = Foo { x: 1 }; + match y { + FOO => { } + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + _ => { } + } + + let x = 0.0; + match x { + f32::INFINITY => { } + //~^ WARNING floating-point types cannot be used in patterns + //~| WARNING this was previously accepted by the compiler but is being phased out + _ => { } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.stderr new file mode 100644 index 000000000..1c4fb9146 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.stderr @@ -0,0 +1,21 @@ +error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/match-forbidden-without-eq.rs:11:9 + | +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 + +warning: floating-point types cannot be used in patterns + --> $DIR/match-forbidden-without-eq.rs:18:9 + | +LL | f32::INFINITY => { } + | ^^^^^^^^^^^^^ + | + = 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 #41620 + = note: `#[warn(illegal_floating_point_literal_pattern)]` on by default + +error: aborting due to previous error; 1 warning emitted + 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 new file mode 100644 index 000000000..151a475c9 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.rs @@ -0,0 +1,19 @@ +// Issue 62307 pointed out a case where the structural-match checking +// was too shallow. +// +// Here we check similar behavior for non-empty arrays of types that +// do not derive `Eq`. +// +// (Current behavior for empty arrays differs and thus is not tested +// here; see rust-lang/rust#62336.) + +#[derive(PartialEq, Debug)] +struct B(i32); + +fn main() { + const FOO: [B; 1] = [B(0)]; + 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 new file mode 100644 index 000000000..6adebada0 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.stderr @@ -0,0 +1,11 @@ +error: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/match-nonempty-array-forbidden-without-eq.rs:16:9 + | +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 + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs new file mode 100644 index 000000000..a8deb8a75 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs @@ -0,0 +1,21 @@ +#[derive(Eq)] +struct Foo { + x: u32 +} + +impl PartialEq for Foo { + fn eq(&self, _: &Foo) -> bool { + false // ha ha! + } +} + +const FOO: Foo = Foo { x: 0 }; + +fn main() { + let y = Foo { x: 1 }; + match y { + FOO => { } + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + _ => { } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr new file mode 100644 index 000000000..f5b10f062 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr @@ -0,0 +1,11 @@ +error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/match-requires-both-partialeq-and-eq.rs:17:9 + | +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 + diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/phantom-data-is-structurally-matchable.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/phantom-data-is-structurally-matchable.rs new file mode 100644 index 000000000..50f91420c --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/phantom-data-is-structurally-matchable.rs @@ -0,0 +1,53 @@ +// run-pass + +// This file checks that `PhantomData` is considered structurally matchable. + +use std::marker::PhantomData; + +fn main() { + let mut count = 0; + + // A type which is not structurally matchable: + struct NotSM; + + // And one that is: + #[derive(PartialEq, Eq)] + struct SM; + + // Check that SM is structural-match: + const CSM: SM = SM; + match SM { + CSM => count += 1, + }; + + // Check that PhantomData is structural-match even if T is not. + const CPD1: PhantomData = PhantomData; + match PhantomData { + CPD1 => count += 1, + }; + + // Check that PhantomData is structural-match when T is. + const CPD2: PhantomData = PhantomData; + match PhantomData { + CPD2 => count += 1, + }; + + // Check that a type which has a PhantomData is structural-match. + #[derive(PartialEq, Eq, Default)] + struct Foo { + alpha: PhantomData, + beta: PhantomData, + } + + const CFOO: Foo = Foo { + alpha: PhantomData, + beta: PhantomData, + }; + + match Foo::default() { + CFOO => count += 1, + }; + + // Final count must be 4 now if all + assert_eq!(count, 4); +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/rfc1445/eq-allows-match-on-ty-in-macro.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/rfc1445/eq-allows-match-on-ty-in-macro.rs new file mode 100644 index 000000000..17174e22c --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/rfc1445/eq-allows-match-on-ty-in-macro.rs @@ -0,0 +1,23 @@ +// run-pass +#![allow(dead_code)] + +macro_rules! foo { + (#[$attr:meta] $x:ident) => { + #[$attr] + struct $x { + x: u32 + } + } +} + +foo! { #[derive(PartialEq, Eq)] Foo } + +const FOO: Foo = Foo { x: 0 }; + +fn main() { + let y = Foo { x: 1 }; + match y { + FOO => { } + _ => { } + } +} diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/rfc1445/eq-allows-match.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/rfc1445/eq-allows-match.rs new file mode 100644 index 000000000..405a69c94 --- /dev/null +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/rfc1445/eq-allows-match.rs @@ -0,0 +1,17 @@ +// run-pass +#![allow(dead_code)] + +#[derive(PartialEq, Eq)] +struct Foo { + x: u32 +} + +const FOO: Foo = Foo { x: 0 }; + +fn main() { + let y = Foo { x: 1 }; + match y { + FOO => { } + _ => { } + } +} -- cgit v1.2.3