Add tests from #67088 and the issues mentioned in its description

This commit is contained in:
Dylan MacKenzie 2020-03-16 21:01:05 -07:00
parent 796c0ca554
commit 66f2d44c73
12 changed files with 468 additions and 16 deletions

View File

@ -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: OND = None: OND;
match None { TYPE => dbg!(TYPE), _ => 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"), };
}

View File

@ -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!(); }
_ => {}
}
}

View File

@ -0,0 +1,19 @@
#![deny(indirect_structural_match)]
#[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 => (),
_ => (),
}
}

View File

@ -0,0 +1,15 @@
error[E0601]: `main` function not found in crate `issue_65466`
--> $DIR/issue-65466.rs:1:1
|
LL | / #![deny(indirect_structural_match)]
LL | |
LL | | #[derive(PartialEq, Eq)]
LL | | enum O<T> {
... |
LL | | }
LL | | }
| |_^ consider adding a `main` function to `$DIR/issue-65466.rs`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0601`.

View File

@ -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"),
}
}

View File

@ -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

View File

@ -0,0 +1,93 @@
// 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)]`
//~| 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)]`
//~| 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)]`
//~| 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)]`
//~| ERROR must be annotated with `#[derive(PartialEq, Eq)]`
const TYPE: OND = Some(NoDerive): OND;
match Some(NoDerive) { TYPE => dbg!(TYPE), _ => panic!("whoops"), };
//~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
//~| 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)]`
//~| 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)]`
//~| 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)]`
//~| 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)]`
//~| 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
}

View File

@ -0,0 +1,136 @@
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:45: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:51: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:56: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:61:28
|
LL | match Some(NoDerive) { TYPE => dbg!(TYPE), _ => 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:66: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:71: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: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:79: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:84: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:89:29
|
LL | match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), };
| ^^^^^^^
|
note: the lint level is defined here
--> $DIR/reject_non_structural.rs:12:9
|
LL | #![warn(indirect_structural_match)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= 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>
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:45: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:51: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:56: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:61:28
|
LL | match Some(NoDerive) { TYPE => dbg!(TYPE), _ => 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:66: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:71: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: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:79: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:84:28
|
LL | match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), };
| ^^^^^
error: aborting due to 20 previous errors; 1 warning emitted

View File

@ -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 committment to a specific value.
#![warn(indirect_structural_match)]
#[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 { }
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
}

View File

@ -0,0 +1,34 @@
warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
--> $DIR/warn_corner_cases.rs:26:47
|
LL | match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), };
| ^^^^^
|
note: the lint level is defined here
--> $DIR/warn_corner_cases.rs:15:9
|
LL | #![warn(indirect_structural_match)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= 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>
warning: to use a constant of type `NoDerive` in a pattern, `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 #62411 <https://github.com/rust-lang/rust/issues/62411>
warning: to use a constant of type `NoDerive` in a pattern, `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 #62411 <https://github.com/rust-lang/rust/issues/62411>
warning: 3 warnings emitted

View File

@ -14,8 +14,6 @@ fn main() {
//~^ ERROR `a` does not live long enough [E0597]
match b {
<() as Foo<'static>>::C => { }
//~^ WARN must be annotated with `#[derive(PartialEq, Eq)]`
//~| WARN will become a hard error in a future release
_ => { }
}
}

View File

@ -1,17 +1,3 @@
warning: to use a constant of type `std::cell::Cell` in a pattern, `std::cell::Cell` must be annotated with `#[derive(PartialEq, Eq)]`
--> $DIR/issue-55511.rs:16:9
|
LL | <() as Foo<'static>>::C => { }
| ^^^^^^^^^^^^^^^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/issue-55511.rs:1:9
|
LL | #![warn(indirect_structural_match)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= 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>
error[E0597]: `a` does not live long enough
--> $DIR/issue-55511.rs:13:28
|