diff options
Diffstat (limited to 'src/test/ui/pattern')
287 files changed, 13917 insertions, 0 deletions
diff --git a/src/test/ui/pattern/auxiliary/declarations-for-tuple-field-count-errors.rs b/src/test/ui/pattern/auxiliary/declarations-for-tuple-field-count-errors.rs new file mode 100644 index 000000000..f7373c453 --- /dev/null +++ b/src/test/ui/pattern/auxiliary/declarations-for-tuple-field-count-errors.rs @@ -0,0 +1,20 @@ +pub struct Z0; +pub struct Z1(); + +pub struct S(pub u8, pub u8, pub u8); +pub struct M( + pub u8, + pub u8, + pub u8, +); + +pub enum E1 { Z0, Z1(), S(u8, u8, u8) } + +pub enum E2 { + S(u8, u8, u8), + M( + u8, + u8, + u8, + ), +} diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-copy.rs b/src/test/ui/pattern/bindings-after-at/bind-by-copy.rs new file mode 100644 index 000000000..2b349f0ed --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/bind-by-copy.rs @@ -0,0 +1,47 @@ +// run-pass + +// Test copy + +struct A { a: i32, b: i32 } +struct B { a: i32, b: C } +struct D { a: i32, d: C } +#[derive(Copy,Clone)] +struct C { c: i32 } + +pub fn main() { + match (A {a: 10, b: 20}) { + x@A {a, b: 20} => { assert!(x.a == 10); assert!(a == 10); } + A {b: _b, ..} => { panic!(); } + } + + let mut x@B {b, ..} = B {a: 10, b: C {c: 20}}; + assert_eq!(x.a, 10); + x.b.c = 30; + assert_eq!(b.c, 20); + let mut y@D {d, ..} = D {a: 10, d: C {c: 20}}; + assert_eq!(y.a, 10); + y.d.c = 30; + assert_eq!(d.c, 20); + + let some_b = Some(B { a: 10, b: C { c: 20 } }); + + // in irrefutable pattern + if let Some(x @ B { b, .. }) = some_b { + assert_eq!(x.b.c, 20); + assert_eq!(b.c, 20); + } else { + unreachable!(); + } + + let some_b = Some(B { a: 10, b: C { c: 20 } }); + + if let Some(x @ B { b: mut b @ C { c }, .. }) = some_b { + assert_eq!(x.b.c, 20); + assert_eq!(b.c, 20); + b.c = 30; + assert_eq!(b.c, 30); + assert_eq!(c, 20); + } else { + unreachable!(); + } +} diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs new file mode 100644 index 000000000..9d1f08d6e --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs @@ -0,0 +1,37 @@ +// This test is taken directly from #16053. +// It checks that you cannot use an AND-pattern (`binding @ pat`) +// where one side is by-ref and the other is by-move. + +struct X { + x: (), +} + +fn main() { + let x = Some(X { x: () }); + match x { + Some(ref _y @ _z) => {} //~ ERROR cannot move out of value because it is borrowed + //~| ERROR borrow of moved value + None => panic!(), + } + + let x = Some(X { x: () }); + match x { + Some(_z @ ref _y) => {} + //~^ ERROR borrow of moved value + None => panic!(), + } + + let mut x = Some(X { x: () }); + match x { + Some(ref mut _y @ _z) => {} //~ ERROR cannot move out of value because it is borrowed + //~| ERROR borrow of moved value + None => panic!(), + } + + let mut x = Some(X { x: () }); + match x { + Some(_z @ ref mut _y) => {} + //~^ ERROR borrow of moved value + None => panic!(), + } +} diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr new file mode 100644 index 000000000..4249a74b3 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr @@ -0,0 +1,71 @@ +error: cannot move out of value because it is borrowed + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:12:14 + | +LL | Some(ref _y @ _z) => {} + | ------^^^-- + | | | + | | value moved into `_z` here + | value borrowed, by `_y`, here + +error: borrow of moved value + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:19:14 + | +LL | Some(_z @ ref _y) => {} + | --^^^------ + | | | + | | value borrowed here after move + | value moved into `_z` here + | move occurs because `_z` has type `X` which does not implement the `Copy` trait + +error: cannot move out of value because it is borrowed + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:26:14 + | +LL | Some(ref mut _y @ _z) => {} + | ----------^^^-- + | | | + | | value moved into `_z` here + | value borrowed, by `_y`, here + +error: borrow of moved value + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:33:14 + | +LL | Some(_z @ ref mut _y) => {} + | --^^^---------- + | | | + | | value borrowed here after move + | value moved into `_z` here + | move occurs because `_z` has type `X` which does not implement the `Copy` trait + +error[E0382]: borrow of moved value + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:12:14 + | +LL | Some(ref _y @ _z) => {} + | ^^^^^^^^^-- + | | | + | | value moved here + | value borrowed here after move + | + = note: move occurs because value has type `X`, which does not implement the `Copy` trait +help: borrow this field in the pattern to avoid moving `x.0` + | +LL | Some(ref _y @ ref _z) => {} + | +++ + +error[E0382]: borrow of moved value + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:26:14 + | +LL | Some(ref mut _y @ _z) => {} + | ^^^^^^^^^^^^^-- + | | | + | | value moved here + | value borrowed here after move + | + = note: move occurs because value has type `X`, which does not implement the `Copy` trait +help: borrow this field in the pattern to avoid moving `x.0` + | +LL | Some(ref mut _y @ ref _z) => {} + | +++ + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs new file mode 100644 index 000000000..1816a74a0 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs @@ -0,0 +1,11 @@ +// See issue #12534. + +fn main() {} + +struct A(Box<u8>); + +fn f(a @ A(u): A) -> Box<u8> { + //~^ ERROR use of partially moved value + drop(a); + u +} diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr new file mode 100644 index 000000000..ee0885a01 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr @@ -0,0 +1,14 @@ +error[E0382]: use of partially moved value + --> $DIR/bind-by-move-no-subbindings-fun-param.rs:7:6 + | +LL | fn f(a @ A(u): A) -> Box<u8> { + | ^^^^^^-^ + | | | + | | value partially moved here + | value used here after partial move + | + = note: partial move occurs because value has type `Box<u8>`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs new file mode 100644 index 000000000..a61d68215 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs @@ -0,0 +1,31 @@ +// Test that moving on both sides of an `@` pattern is not allowed. + +fn main() { + struct U; // Not copy! + + // Prevent promotion: + fn u() -> U { + U + } + + let a @ b = U; //~ ERROR use of moved value + + let a @ (b, c) = (U, U); //~ ERROR use of partially moved value + + let a @ (b, c) = (u(), u()); //~ ERROR use of partially moved value + + match Ok(U) { + a @ Ok(b) | a @ Err(b) => {} //~ ERROR use of moved value + //~^ ERROR use of moved value + } + + fn fun(a @ b: U) {} //~ ERROR use of moved value + + match [u(), u(), u(), u()] { + xs @ [a, .., b] => {} //~ ERROR use of partially moved value + } + + match [u(), u(), u(), u()] { + xs @ [_, ys @ .., _] => {} //~ ERROR use of partially moved value + } +} diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr new file mode 100644 index 000000000..8e00bf5c3 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr @@ -0,0 +1,88 @@ +error[E0382]: use of moved value + --> $DIR/borrowck-move-and-move.rs:11:9 + | +LL | let a @ b = U; + | ^^^^- - move occurs because value has type `U`, which does not implement the `Copy` trait + | | | + | | value moved here + | value used here after move + +error[E0382]: use of partially moved value + --> $DIR/borrowck-move-and-move.rs:13:9 + | +LL | let a @ (b, c) = (U, U); + | ^^^^^^^^-^ + | | | + | | value partially moved here + | value used here after partial move + | + = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait + +error[E0382]: use of partially moved value + --> $DIR/borrowck-move-and-move.rs:15:9 + | +LL | let a @ (b, c) = (u(), u()); + | ^^^^^^^^-^ + | | | + | | value partially moved here + | value used here after partial move + | + = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait + +error[E0382]: use of moved value + --> $DIR/borrowck-move-and-move.rs:18:16 + | +LL | match Ok(U) { + | ----- move occurs because value has type `Result<U, U>`, which does not implement the `Copy` trait +LL | a @ Ok(b) | a @ Err(b) => {} + | -------^- + | | | + | | value used here after move + | value moved here + +error[E0382]: use of moved value + --> $DIR/borrowck-move-and-move.rs:18:29 + | +LL | match Ok(U) { + | ----- move occurs because value has type `Result<U, U>`, which does not implement the `Copy` trait +LL | a @ Ok(b) | a @ Err(b) => {} + | --------^- + | | | + | | value used here after move + | value moved here + +error[E0382]: use of partially moved value + --> $DIR/borrowck-move-and-move.rs:25:9 + | +LL | xs @ [a, .., b] => {} + | ^^^^^^^^^^^^^-^ + | | | + | | value partially moved here + | value used here after partial move + | + = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait + +error[E0382]: use of partially moved value + --> $DIR/borrowck-move-and-move.rs:29:9 + | +LL | xs @ [_, ys @ .., _] => {} + | ^^^^^^^^^-------^^^^ + | | | + | | value partially moved here + | value used here after partial move + | + = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait + +error[E0382]: use of moved value + --> $DIR/borrowck-move-and-move.rs:22:12 + | +LL | fn fun(a @ b: U) {} + | ^^^^- + | | | + | | value moved here + | value used here after move + | move occurs because value has type `U`, which does not implement the `Copy` trait + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs new file mode 100644 index 000000000..fbdefd9d3 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs @@ -0,0 +1,84 @@ +// check-pass + +// Test `@` patterns combined with `box` patterns. + +#![feature(box_patterns)] + +#[derive(Copy, Clone)] +struct C; + +fn c() -> C { C } + +struct NC; + +fn nc() -> NC { NC } + +fn main() { + let ref a @ box b = Box::new(C); // OK; the type is `Copy`. + drop(b); + drop(b); + drop(a); + + let ref a @ box b = Box::new(c()); // OK; the type is `Copy`. + drop(b); + drop(b); + drop(a); + + fn f3(ref a @ box b: Box<C>) { // OK; the type is `Copy`. + drop(b); + drop(b); + drop(a); + } + match Box::new(c()) { + ref a @ box b => { // OK; the type is `Copy`. + drop(b); + drop(b); + drop(a); + } + } + + let ref a @ box ref b = Box::new(NC); // OK. + drop(a); + drop(b); + + fn f4(ref a @ box ref b: Box<NC>) { // OK. + drop(a); + drop(b) + } + + match Box::new(nc()) { + ref a @ box ref b => { // OK. + drop(a); + drop(b); + } + } + + match Box::new([Ok(c()), Err(nc()), Ok(c())]) { + box [Ok(a), ref xs @ .., Err(ref b)] => { + let _: C = a; + let _: &[Result<C, NC>; 1] = xs; + let _: &NC = b; + } + _ => {} + } + + match [Ok(Box::new(c())), Err(Box::new(nc())), Ok(Box::new(c())), Ok(Box::new(c()))] { + [Ok(box a), ref xs @ .., Err(box ref b), Err(box ref c)] => { + let _: C = a; + let _: &[Result<Box<C>, Box<NC>>; 1] = xs; + let _: &NC = b; + let _: &NC = c; + } + _ => {} + } + + match Box::new([Ok(c()), Err(nc()), Ok(c())]) { + box [Ok(a), ref xs @ .., Err(b)] => {} + _ => {} + } + + match [Ok(Box::new(c())), Err(Box::new(nc())), Ok(Box::new(c())), Ok(Box::new(c()))] { + [Ok(box ref a), ref xs @ .., Err(box b), Err(box ref mut c)] => {} + _ => {} + } +} diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs new file mode 100644 index 000000000..45aa65e67 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs @@ -0,0 +1,69 @@ +// Test `@` patterns combined with `box` patterns. + +#![feature(box_patterns)] + +#[derive(Copy, Clone)] +struct C; + +fn c() -> C { + C +} + +struct NC; + +fn nc() -> NC { + NC +} + +fn main() { + let a @ box &b = Box::new(&C); + + let a @ box b = Box::new(C); + + fn f1(a @ box &b: Box<&C>) {} + + fn f2(a @ box b: Box<C>) {} + + match Box::new(C) { + a @ box b => {} + } + + let ref a @ box b = Box::new(NC); //~ ERROR cannot move out of value because it is borrowed + //~| ERROR borrow of moved value + + let ref a @ box ref mut b = Box::new(nc()); + //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable + let ref a @ box ref mut b = Box::new(NC); + //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable + let ref a @ box ref mut b = Box::new(NC); + //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable + //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable + *b = NC; + let ref a @ box ref mut b = Box::new(NC); + //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable + //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable + *b = NC; + drop(a); + + let ref mut a @ box ref b = Box::new(NC); + //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable + //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable + *a = Box::new(NC); + drop(b); + + fn f5(ref mut a @ box ref b: Box<NC>) { + //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable + //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable + *a = Box::new(NC); + drop(b); + } + + match Box::new(nc()) { + ref mut a @ box ref b => { + //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable + //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable + *a = Box::new(NC); + drop(b); + } + } +} diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr new file mode 100644 index 000000000..4b2048855 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr @@ -0,0 +1,147 @@ +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-at-and-box.rs:31:9 + | +LL | let ref a @ box b = Box::new(NC); + | -----^^^^^^^- + | | | + | | value moved into `b` here + | value borrowed, by `a`, here + +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-at-and-box.rs:34:9 + | +LL | let ref a @ box ref mut b = Box::new(nc()); + | -----^^^^^^^--------- + | | | + | | mutable borrow, by `b`, occurs here + | immutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-at-and-box.rs:36:9 + | +LL | let ref a @ box ref mut b = Box::new(NC); + | -----^^^^^^^--------- + | | | + | | mutable borrow, by `b`, occurs here + | immutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-at-and-box.rs:38:9 + | +LL | let ref a @ box ref mut b = Box::new(NC); + | -----^^^^^^^--------- + | | | + | | mutable borrow, by `b`, occurs here + | immutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-at-and-box.rs:42:9 + | +LL | let ref a @ box ref mut b = Box::new(NC); + | -----^^^^^^^--------- + | | | + | | mutable borrow, by `b`, occurs here + | immutable borrow, by `a`, occurs here + +error: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-at-and-box.rs:48:9 + | +LL | let ref mut a @ box ref b = Box::new(NC); + | ---------^^^^^^^----- + | | | + | | immutable borrow, by `b`, occurs here + | mutable borrow, by `a`, occurs here + +error: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-at-and-box.rs:62:9 + | +LL | ref mut a @ box ref b => { + | ---------^^^^^^^----- + | | | + | | immutable borrow, by `b`, occurs here + | mutable borrow, by `a`, occurs here + +error: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-at-and-box.rs:54:11 + | +LL | fn f5(ref mut a @ box ref b: Box<NC>) { + | ---------^^^^^^^----- + | | | + | | immutable borrow, by `b`, occurs here + | mutable borrow, by `a`, occurs here + +error[E0382]: borrow of moved value + --> $DIR/borrowck-pat-at-and-box.rs:31:9 + | +LL | let ref a @ box b = Box::new(NC); + | ^^^^^^^^^^^^- + | | | + | | value moved here + | value borrowed here after move + | + = note: move occurs because value has type `NC`, which does not implement the `Copy` trait + +error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-at-and-box.rs:38:9 + | +LL | let ref a @ box ref mut b = Box::new(NC); + | ^^^^^^^^^^^^--------- + | | | + | | mutable borrow occurs here + | immutable borrow occurs here +... +LL | *b = NC; + | ------- mutable borrow later used here + +error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-at-and-box.rs:42:9 + | +LL | let ref a @ box ref mut b = Box::new(NC); + | ^^^^^^^^^^^^--------- + | | | + | | mutable borrow occurs here + | immutable borrow occurs here +... +LL | *b = NC; + | ------- mutable borrow later used here + +error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-at-and-box.rs:48:9 + | +LL | let ref mut a @ box ref b = Box::new(NC); + | ^^^^^^^^^^^^^^^^----- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here +... +LL | drop(b); + | - immutable borrow later used here + +error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-at-and-box.rs:62:9 + | +LL | ref mut a @ box ref b => { + | ^^^^^^^^^^^^^^^^----- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here +... +LL | drop(b); + | - immutable borrow later used here + +error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-at-and-box.rs:54:11 + | +LL | fn f5(ref mut a @ box ref b: Box<NC>) { + | ^^^^^^^^^^^^^^^^----- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here +... +LL | drop(b); + | - immutable borrow later used here + +error: aborting due to 14 previous errors + +Some errors have detailed explanations: E0382, E0502. +For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs new file mode 100644 index 000000000..0108861cf --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs @@ -0,0 +1,49 @@ +// check-pass + +// Test `Copy` bindings in the rhs of `@` patterns. + +#[derive(Copy, Clone)] +struct C; + +fn mk_c() -> C { C } + +#[derive(Copy, Clone)] +struct P<A, B>(A, B); + +enum E<A, B> { L(A), R(B) } + +fn main() { + let a @ b @ c @ d = C; + let a @ (b, c) = (C, mk_c()); + let a @ P(b, P(c, d)) = P(mk_c(), P(C, C)); + let a @ [b, c] = [C, C]; + let a @ [b, .., c] = [C, mk_c(), C]; + let a @ [b, mid @ .., c] = [C, mk_c(), C]; + let a @ &(b, c) = &(C, C); + let a @ &(b, &P(c, d)) = &(mk_c(), &P(C, C)); + + fn foo(a @ [b, mid @ .., c]: [C; 3]) {} + + use self::E::*; + match L(C) { + L(a) | R(a) => { + let a: C = a; + drop(a); + drop(a); + } + } + match R(&L(&mk_c())) { + L(L(&a)) | L(R(&a)) | R(L(&a)) | R(R(&a)) => { + let a: C = a; + drop(a); + drop(a); + } + } + + match Ok(mk_c()) { + Ok(ref a @ b) | Err(b @ ref a) => { + let _: &C = a; + let _: C = b; + } + } +} diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs new file mode 100644 index 000000000..82f16fca6 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs @@ -0,0 +1,7 @@ +// Test that `by_move_binding @ pat_with_by_ref_bindings` is prevented even with promotion. +// Currently this logic exists in THIR match checking as opposed to borrowck. + +fn main() { + struct U; + let a @ ref b = U; //~ ERROR borrow of moved value +} diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr new file mode 100644 index 000000000..be4e81c61 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr @@ -0,0 +1,12 @@ +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse-promotion.rs:6:9 + | +LL | let a @ ref b = U; + | -^^^----- + | | | + | | value borrowed here after move + | value moved into `a` here + | move occurs because `a` has type `U` which does not implement the `Copy` trait + +error: aborting due to previous error + diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs new file mode 100644 index 000000000..06dc6e1c4 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs @@ -0,0 +1,80 @@ +// Test that `by_move_binding @ pat_with_by_ref_bindings` is prevented. + +fn main() { + struct U; + + // Prevent promotion. + fn u() -> U { + U + } + + fn f1(a @ ref b: U) {} + //~^ ERROR borrow of moved value + + fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} + //~^ ERROR borrow of moved value + //~| ERROR borrow of moved value + //~| ERROR borrow of moved value + //~| ERROR use of partially moved value + fn f3(a @ [ref mut b, ref c]: [U; 2]) {} + //~^ ERROR borrow of moved value + + let a @ ref b = U; + //~^ ERROR borrow of moved value + let a @ (mut b @ ref mut c, d @ ref e) = (U, U); + //~^ ERROR borrow of moved value + //~| ERROR borrow of moved value + //~| ERROR borrow of moved value + //~| ERROR use of partially moved value + let a @ [ref mut b, ref c] = [U, U]; + //~^ ERROR borrow of moved value + let a @ ref b = u(); + //~^ ERROR borrow of moved value + let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); + //~^ ERROR borrow of moved value + //~| ERROR borrow of moved value + //~| ERROR borrow of moved value + //~| ERROR use of partially moved value + let a @ [ref mut b, ref c] = [u(), u()]; + //~^ ERROR borrow of moved value + + match Some(U) { + a @ Some(ref b) => {} + //~^ ERROR borrow of moved value + None => {} + } + match Some((U, U)) { + a @ Some((mut b @ ref mut c, d @ ref e)) => {} + //~^ ERROR borrow of moved value + //~| ERROR borrow of moved value + //~| ERROR borrow of moved value + //~| ERROR use of moved value + None => {} + } + match Some([U, U]) { + mut a @ Some([ref b, ref mut c]) => {} + //~^ ERROR borrow of moved value + //~| ERROR borrow of moved value + None => {} + } + match Some(u()) { + a @ Some(ref b) => {} + //~^ ERROR borrow of moved value + //~| ERROR borrow of moved value + None => {} + } + match Some((u(), u())) { + a @ Some((mut b @ ref mut c, d @ ref e)) => {} + //~^ ERROR borrow of moved value + //~| ERROR borrow of moved value + //~| ERROR borrow of moved value + //~| ERROR use of moved value + None => {} + } + match Some([u(), u()]) { + mut a @ Some([ref b, ref mut c]) => {} + //~^ ERROR borrow of moved value + //~| ERROR borrow of moved value + None => {} + } +} diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr new file mode 100644 index 000000000..bc2c1625f --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr @@ -0,0 +1,351 @@ +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:22:9 + | +LL | let a @ ref b = U; + | -^^^----- + | | | + | | value borrowed here after move + | value moved into `a` here + | move occurs because `a` has type `U` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:9 + | +LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); + | -^^^^^^^^^^^^---------^^^^^^-----^ + | | | | + | | | value borrowed here after move + | | value borrowed here after move + | value moved into `a` here + | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:14 + | +LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); + | -----^^^--------- + | | | + | | value borrowed here after move + | value moved into `b` here + | move occurs because `b` has type `U` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:33 + | +LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); + | -^^^----- + | | | + | | value borrowed here after move + | value moved into `d` here + | move occurs because `d` has type `U` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:29:9 + | +LL | let a @ [ref mut b, ref c] = [U, U]; + | -^^^^---------^^-----^ + | | | | + | | | value borrowed here after move + | | value borrowed here after move + | value moved into `a` here + | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:9 + | +LL | let a @ ref b = u(); + | -^^^----- + | | | + | | value borrowed here after move + | value moved into `a` here + | move occurs because `a` has type `U` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:9 + | +LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); + | -^^^^^^^^^^^^---------^^^^^^-----^ + | | | | + | | | value borrowed here after move + | | value borrowed here after move + | value moved into `a` here + | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:14 + | +LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); + | -----^^^--------- + | | | + | | value borrowed here after move + | value moved into `b` here + | move occurs because `b` has type `U` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:33 + | +LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); + | -^^^----- + | | | + | | value borrowed here after move + | value moved into `d` here + | move occurs because `d` has type `U` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:38:9 + | +LL | let a @ [ref mut b, ref c] = [u(), u()]; + | -^^^^---------^^-----^ + | | | | + | | | value borrowed here after move + | | value borrowed here after move + | value moved into `a` here + | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:42:9 + | +LL | a @ Some(ref b) => {} + | -^^^^^^^^-----^ + | | | + | | value borrowed here after move + | value moved into `a` here + | move occurs because `a` has type `Option<U>` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:9 + | +LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} + | -^^^^^^^^^^^^^^^^^---------^^^^^^-----^^ + | | | | + | | | value borrowed here after move + | | value borrowed here after move + | value moved into `a` here + | move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:19 + | +LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} + | -----^^^--------- + | | | + | | value borrowed here after move + | value moved into `b` here + | move occurs because `b` has type `U` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:38 + | +LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} + | -^^^----- + | | | + | | value borrowed here after move + | value moved into `d` here + | move occurs because `d` has type `U` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:9 + | +LL | mut a @ Some([ref b, ref mut c]) => {} + | -----^^^^^^^^^-----^^---------^^ + | | | | + | | | value borrowed here after move + | | value borrowed here after move + | value moved into `a` here + | move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:9 + | +LL | a @ Some(ref b) => {} + | -^^^^^^^^-----^ + | | | + | | value borrowed here after move + | value moved into `a` here + | move occurs because `a` has type `Option<U>` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:9 + | +LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} + | -^^^^^^^^^^^^^^^^^---------^^^^^^-----^^ + | | | | + | | | value borrowed here after move + | | value borrowed here after move + | value moved into `a` here + | move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:19 + | +LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} + | -----^^^--------- + | | | + | | value borrowed here after move + | value moved into `b` here + | move occurs because `b` has type `U` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:38 + | +LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} + | -^^^----- + | | | + | | value borrowed here after move + | value moved into `d` here + | move occurs because `d` has type `U` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:75:9 + | +LL | mut a @ Some([ref b, ref mut c]) => {} + | -----^^^^^^^^^-----^^---------^^ + | | | | + | | | value borrowed here after move + | | value borrowed here after move + | value moved into `a` here + | move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:11:11 + | +LL | fn f1(a @ ref b: U) {} + | -^^^----- + | | | + | | value borrowed here after move + | value moved into `a` here + | move occurs because `a` has type `U` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11 + | +LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} + | -----^^^^^^^^-----^^^^^^^^^^-----^ + | | | | + | | | value borrowed here after move + | | value borrowed here after move + | value moved into `a` here + | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:20 + | +LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} + | -^^^----- + | | | + | | value borrowed here after move + | value moved into `b` here + | move occurs because `b` has type `U` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:31 + | +LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} + | -----^^^----- + | | | + | | value borrowed here after move + | value moved into `d` here + | move occurs because `d` has type `U` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:19:11 + | +LL | fn f3(a @ [ref mut b, ref c]: [U; 2]) {} + | -^^^^---------^^-----^ + | | | | + | | | value borrowed here after move + | | value borrowed here after move + | value moved into `a` here + | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait + +error[E0382]: use of partially moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:9 + | +LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); + | ^^^^^^^^^^^^^^^^^^^^^^^^---------^ + | | | + | | value partially moved here + | value used here after partial move + | + = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait + +error[E0382]: use of partially moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:9 + | +LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); + | ^^^^^^^^^^^^^^^^^^^^^^^^---------^ + | | | + | | value partially moved here + | value used here after partial move + | + = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait + +error[E0382]: use of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:38 + | +LL | match Some((U, U)) { + | ------------ move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait +LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} + | -----------------------------^^^^^^^^^-- + | | | + | | value used here after move + | value moved here + +error[E0382]: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:30 + | +LL | match Some([U, U]) { + | ------------ move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait +LL | mut a @ Some([ref b, ref mut c]) => {} + | ---------------------^^^^^^^^^-- + | | | + | | value borrowed here after move + | value moved here + +error[E0382]: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:18 + | +LL | match Some(u()) { + | --------- move occurs because value has type `Option<U>`, which does not implement the `Copy` trait +LL | a @ Some(ref b) => {} + | ---------^^^^^- + | | | + | | value borrowed here after move + | value moved here + +error[E0382]: use of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:38 + | +LL | match Some((u(), u())) { + | ---------------- move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait +LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} + | -----------------------------^^^^^^^^^-- + | | | + | | value used here after move + | value moved here + +error[E0382]: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:75:30 + | +LL | match Some([u(), u()]) { + | ---------------- move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait +LL | mut a @ Some([ref b, ref mut c]) => {} + | ---------------------^^^^^^^^^-- + | | | + | | value borrowed here after move + | value moved here + +error[E0382]: use of partially moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11 + | +LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} + | ^^^^^^^^^^^^^^^^^^^^-------------^ + | | | + | | value partially moved here + | value used here after partial move + | + = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait + +error: aborting due to 33 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs new file mode 100644 index 000000000..0b0a78010 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs @@ -0,0 +1,82 @@ +// Test that `ref mut? @ pat_with_by_move_bindings` is prevented. + +fn main() { + struct U; + + // Prevent promotion. + fn u() -> U { + U + } + + fn f1(ref a @ b: U) {} + //~^ ERROR cannot move out of value because it is borrowed + //~| ERROR borrow of moved value + fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} + //~^ ERROR cannot move out of value because it is borrowed + //~| ERROR cannot move out of value because it is borrowed + //~| ERROR cannot move out of value because it is borrowed + //~| ERROR borrow of moved value + //~| ERROR borrow of moved value + fn f3(ref mut a @ [b, mut c]: [U; 2]) {} + //~^ ERROR cannot move out of value because it is borrowed + //~| ERROR borrow of partially moved value + + let ref a @ b = U; + //~^ ERROR cannot move out of value because it is borrowed + let ref a @ (ref b @ mut c, ref d @ e) = (U, U); + //~^ ERROR cannot move out of value because it is borrowed + //~| ERROR cannot move out of value because it is borrowed + //~| ERROR cannot move out of value because it is borrowed + let ref mut a @ [b, mut c] = [U, U]; + //~^ ERROR cannot move out of value because it is borrowed + //~| ERROR borrow of partially moved value + let ref a @ b = u(); + //~^ ERROR cannot move out of value because it is borrowed + //~| ERROR borrow of moved value + let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); + //~^ ERROR cannot move out of value because it is borrowed + //~| ERROR cannot move out of value because it is borrowed + //~| ERROR cannot move out of value because it is borrowed + //~| ERROR borrow of moved value + //~| ERROR borrow of moved value + let ref mut a @ [b, mut c] = [u(), u()]; + //~^ ERROR cannot move out of value because it is borrowed + //~| ERROR borrow of partially moved value + + match Some(U) { + ref a @ Some(b) => {} + //~^ ERROR cannot move out of value because it is borrowed + None => {} + } + match Some((U, U)) { + ref a @ Some((ref b @ mut c, ref d @ e)) => {} + //~^ ERROR cannot move out of value because it is borrowed + //~| ERROR cannot move out of value because it is borrowed + //~| ERROR cannot move out of value because it is borrowed + None => {} + } + match Some([U, U]) { + ref mut a @ Some([b, mut c]) => {} + //~^ ERROR cannot move out of value because it is borrowed + None => {} + } + match Some(u()) { + ref a @ Some(b) => {} + //~^ ERROR cannot move out of value because it is borrowed + None => {} + } + match Some((u(), u())) { + ref a @ Some((ref b @ mut c, ref d @ e)) => {} + //~^ ERROR cannot move out of value because it is borrowed + //~| ERROR cannot move out of value because it is borrowed + //~| ERROR cannot move out of value because it is borrowed + //~| ERROR borrow of moved value + //~| ERROR borrow of moved value + None => {} + } + match Some([u(), u()]) { + ref mut a @ Some([b, mut c]) => {} + //~^ ERROR cannot move out of value because it is borrowed + None => {} + } +} diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr new file mode 100644 index 000000000..c019aae3d --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr @@ -0,0 +1,364 @@ +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:24:9 + | +LL | let ref a @ b = U; + | -----^^^- + | | | + | | value moved into `b` here + | value borrowed, by `a`, here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:26:9 + | +LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); + | -----^^^^^^^^^^^^-----^^^^^^^^^^-^ + | | | | + | | | value moved into `e` here + | | value moved into `c` here + | value borrowed, by `a`, here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:26:18 + | +LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); + | -----^^^----- + | | | + | | value moved into `c` here + | value borrowed, by `b`, here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:26:33 + | +LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); + | -----^^^- + | | | + | | value moved into `e` here + | value borrowed, by `d`, here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9 + | +LL | let ref mut a @ [b, mut c] = [U, U]; + | ---------^^^^-^^-----^ + | | | | + | | | value moved into `c` here + | | value moved into `b` here + | value borrowed, by `a`, here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9 + | +LL | let ref a @ b = u(); + | -----^^^- + | | | + | | value moved into `b` here + | value borrowed, by `a`, here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:36:9 + | +LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); + | -----^^^^^^^^^^^^-----^^^^^^^^^^-^ + | | | | + | | | value moved into `e` here + | | value moved into `c` here + | value borrowed, by `a`, here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:36:18 + | +LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); + | -----^^^----- + | | | + | | value moved into `c` here + | value borrowed, by `b`, here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:36:33 + | +LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); + | -----^^^- + | | | + | | value moved into `e` here + | value borrowed, by `d`, here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:42:9 + | +LL | let ref mut a @ [b, mut c] = [u(), u()]; + | ---------^^^^-^^-----^ + | | | | + | | | value moved into `c` here + | | value moved into `b` here + | value borrowed, by `a`, here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:47:9 + | +LL | ref a @ Some(b) => {} + | -----^^^^^^^^-^ + | | | + | | value moved into `b` here + | value borrowed, by `a`, here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:52:9 + | +LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} + | -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^ + | | | | + | | | value moved into `e` here + | | value moved into `c` here + | value borrowed, by `a`, here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:52:23 + | +LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} + | -----^^^----- + | | | + | | value moved into `c` here + | value borrowed, by `b`, here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:52:38 + | +LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} + | -----^^^- + | | | + | | value moved into `e` here + | value borrowed, by `d`, here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:59:9 + | +LL | ref mut a @ Some([b, mut c]) => {} + | ---------^^^^^^^^^-^^-----^^ + | | | | + | | | value moved into `c` here + | | value moved into `b` here + | value borrowed, by `a`, here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:64:9 + | +LL | ref a @ Some(b) => {} + | -----^^^^^^^^-^ + | | | + | | value moved into `b` here + | value borrowed, by `a`, here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:69:9 + | +LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} + | -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^ + | | | | + | | | value moved into `e` here + | | value moved into `c` here + | value borrowed, by `a`, here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:69:23 + | +LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} + | -----^^^----- + | | | + | | value moved into `c` here + | value borrowed, by `b`, here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:69:38 + | +LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} + | -----^^^- + | | | + | | value moved into `e` here + | value borrowed, by `d`, here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:78:9 + | +LL | ref mut a @ Some([b, mut c]) => {} + | ---------^^^^^^^^^-^^-----^^ + | | | | + | | | value moved into `c` here + | | value moved into `b` here + | value borrowed, by `a`, here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:11:11 + | +LL | fn f1(ref a @ b: U) {} + | -----^^^- + | | | + | | value moved into `b` here + | value borrowed, by `a`, here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:14:11 + | +LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} + | -----^^^^^^^^^^^^-----^^^^^^^^^^-^ + | | | | + | | | value moved into `e` here + | | value moved into `c` here + | value borrowed, by `a`, here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:14:20 + | +LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} + | -----^^^----- + | | | + | | value moved into `c` here + | value borrowed, by `b`, here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:14:35 + | +LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} + | -----^^^- + | | | + | | value moved into `e` here + | value borrowed, by `d`, here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-by-move-and-ref.rs:20:11 + | +LL | fn f3(ref mut a @ [b, mut c]: [U; 2]) {} + | ---------^^^^-^^-----^ + | | | | + | | | value moved into `c` here + | | value moved into `b` here + | value borrowed, by `a`, here + +error[E0382]: borrow of partially moved value + --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9 + | +LL | let ref mut a @ [b, mut c] = [U, U]; + | ^^^^^^^^^^^^^^^^-----^ + | | | + | | value partially moved here + | value borrowed here after partial move + | + = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait + +error[E0382]: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9 + | +LL | let ref a @ b = u(); + | ^^^^^^^^- --- move occurs because value has type `U`, which does not implement the `Copy` trait + | | | + | | value moved here + | value borrowed here after move + +error[E0382]: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref.rs:36:18 + | +LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); + | ^^^^^^^^----- + | | | + | | value moved here + | value borrowed here after move + | + = note: move occurs because value has type `U`, which does not implement the `Copy` trait + +error[E0382]: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref.rs:36:33 + | +LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); + | ^^^^^^^^- + | | | + | | value moved here + | value borrowed here after move + | + = note: move occurs because value has type `U`, which does not implement the `Copy` trait + +error[E0382]: borrow of partially moved value + --> $DIR/borrowck-pat-by-move-and-ref.rs:42:9 + | +LL | let ref mut a @ [b, mut c] = [u(), u()]; + | ^^^^^^^^^^^^^^^^-----^ + | | | + | | value partially moved here + | value borrowed here after partial move + | + = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait + +error[E0382]: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref.rs:69:23 + | +LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} + | ^^^^^^^^----- + | | | + | | value moved here + | value borrowed here after move + | + = note: move occurs because value has type `U`, which does not implement the `Copy` trait +help: borrow this field in the pattern to avoid moving the value + | +LL | ref a @ Some((ref b @ ref mut c, ref d @ e)) => {} + | +++ + +error[E0382]: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref.rs:69:38 + | +LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} + | ^^^^^^^^- + | | | + | | value moved here + | value borrowed here after move + | + = note: move occurs because value has type `U`, which does not implement the `Copy` trait +help: borrow this field in the pattern to avoid moving the value + | +LL | ref a @ Some((ref b @ mut c, ref d @ ref e)) => {} + | +++ + +error[E0382]: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref.rs:11:11 + | +LL | fn f1(ref a @ b: U) {} + | ^^^^^^^^- + | | | + | | value moved here + | value borrowed here after move + | move occurs because value has type `U`, which does not implement the `Copy` trait + +error[E0382]: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref.rs:14:20 + | +LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} + | ^^^^^^^^----- + | | | + | | value moved here + | value borrowed here after move + | + = note: move occurs because value has type `U`, which does not implement the `Copy` trait + +error[E0382]: borrow of moved value + --> $DIR/borrowck-pat-by-move-and-ref.rs:14:35 + | +LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} + | ^^^^^^^^- + | | | + | | value moved here + | value borrowed here after move + | + = note: move occurs because value has type `U`, which does not implement the `Copy` trait + +error[E0382]: borrow of partially moved value + --> $DIR/borrowck-pat-by-move-and-ref.rs:20:11 + | +LL | fn f3(ref mut a @ [b, mut c]: [U; 2]) {} + | ^^^^^^^^^^^^^^^^-----^ + | | | + | | value partially moved here + | value borrowed here after partial move + | + = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait + +error: aborting due to 36 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-both-sides.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-both-sides.rs new file mode 100644 index 000000000..df213f688 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-both-sides.rs @@ -0,0 +1,45 @@ +// check-pass + +// Test that `ref` patterns may be used on both sides +// of an `@` pattern according to NLL borrowck. + +fn main() { + struct U; // Not copy! + + // Promotion: + let ref a @ ref b = U; + let _: &U = a; + let _: &U = b; + + // Prevent promotion: + fn u() -> U { U } + + let ref a @ ref b = u(); + let _: &U = a; + let _: &U = b; + + let ref a @ (ref b, [ref c, ref d]) = (u(), [u(), u()]); + let _: &(U, [U; 2]) = a; + let _: &U = b; + let _: &U = c; + let _: &U = d; + + fn f1(ref a @ (ref b, [ref c, ref mid @ .., ref d]): (U, [U; 4])) {} + + let a @ (b, [c, d]) = &(u(), [u(), u()]); + let _: &(U, [U; 2]) = a; + let _: &U = b; + let _: &U = c; + let _: &U = d; + + let ref a @ &ref b = &u(); + let _: &&U = a; + let _: &U = b; + + match Ok(u()) { + ref a @ Ok(ref b) | ref a @ Err(ref b) => { + let _: &Result<U, U> = a; + let _: &U = b; + } + } +} diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs new file mode 100644 index 000000000..6bc0d346c --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs @@ -0,0 +1,136 @@ +enum Option<T> { + None, + Some(T), +} + +fn main() { + match &mut Some(1) { + ref mut z @ &mut Some(ref a) => { + //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable + //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable + **z = None; + println!("{}", *a); + } + _ => () + } + + struct U; + + // Prevent promotion: + fn u() -> U { U } + + fn f1(ref a @ ref mut b: U) {} + //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable + fn f2(ref mut a @ ref b: U) {} + //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable + fn f3(ref a @ [ref b, ref mut mid @ .., ref c]: [U; 4]) {} + //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable + fn f4_also_moved(ref a @ ref mut b @ c: U) {} + //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable + //~| ERROR cannot move out of value because it is borrowed + //~| ERROR borrow of moved value + + let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub + //~^ ERROR cannot borrow value as mutable more than once at a time + //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable + + let ref a @ ref mut b = U; + //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable + let ref mut a @ ref b = U; + //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable + let ref a @ (ref mut b, ref mut c) = (U, U); + //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable + let ref mut a @ (ref b, ref c) = (U, U); + //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable + + let ref mut a @ ref b = u(); + //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable + //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable + *a = u(); + drop(b); + let ref a @ ref mut b = u(); + //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable + //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable + *b = u(); + drop(a); + + let ref mut a @ ref b = U; + //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable + *a = U; + drop(b); + let ref a @ ref mut b = U; + //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable + *b = U; + drop(a); + + match Ok(U) { + ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => { + //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable + //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable + *a = Err(U); + drop(b); + } + } + + match Ok(U) { + ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { + //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable + //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable + //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable + //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable + *b = U; + drop(a); + } + } + + match Ok(U) { + ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {} + //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable + //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable + //~| ERROR cannot assign to `*b`, as it is immutable for the pattern guard + _ => {} + } + match Ok(U) { + ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {} + //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable + //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable + //~| ERROR cannot assign to `*a`, as it is immutable for the pattern guard + _ => {} + } + match Ok(U) { + ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} + //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable + //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable + //~| ERROR cannot move out of `b` in pattern guard + //~| ERROR cannot move out of `b` in pattern guard + _ => {} + } + match Ok(U) { + ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} + //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable + //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable + //~| ERROR cannot move out of `a` in pattern guard + //~| ERROR cannot move out of `a` in pattern guard + _ => {} + } + + let ref a @ (ref mut b, ref mut c) = (U, U); + //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable + //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable + *b = U; + *c = U; + + let ref a @ (ref mut b, ref mut c) = (U, U); + //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable + //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable + *b = U; + drop(a); + + let ref a @ (ref mut b, ref mut c) = (U, U); + //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable + *b = U; //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable + *c = U; + drop(a); + let ref mut a @ (ref b, ref c) = (U, U); + //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable +} diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr new file mode 100644 index 000000000..2ae78d108 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr @@ -0,0 +1,454 @@ +error: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:8:9 + | +LL | ref mut z @ &mut Some(ref a) => { + | ---------^^^^^^^^^^^^^-----^ + | | | + | | immutable borrow, by `a`, occurs here + | mutable borrow, by `z`, occurs here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:33:9 + | +LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub + | ---------^^^^-----------------^ + | | | | + | | | another mutable borrow, by `c`, occurs here + | | also borrowed as immutable, by `b`, here + | first mutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:33:22 + | +LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub + | -----^^^--------- + | | | + | | mutable borrow, by `c`, occurs here + | immutable borrow, by `b`, occurs here + +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:37:9 + | +LL | let ref a @ ref mut b = U; + | -----^^^--------- + | | | + | | mutable borrow, by `b`, occurs here + | immutable borrow, by `a`, occurs here + +error: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:39:9 + | +LL | let ref mut a @ ref b = U; + | ---------^^^----- + | | | + | | immutable borrow, by `b`, occurs here + | mutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:41:9 + | +LL | let ref a @ (ref mut b, ref mut c) = (U, U); + | -----^^^^---------^^---------^ + | | | | + | | | mutable borrow, by `c`, occurs here + | | mutable borrow, by `b`, occurs here + | immutable borrow, by `a`, occurs here + +error: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:43:9 + | +LL | let ref mut a @ (ref b, ref c) = (U, U); + | ---------^^^^-----^^-----^ + | | | | + | | | immutable borrow, by `c`, occurs here + | | immutable borrow, by `b`, occurs here + | mutable borrow, by `a`, occurs here + +error: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:46:9 + | +LL | let ref mut a @ ref b = u(); + | ---------^^^----- + | | | + | | immutable borrow, by `b`, occurs here + | mutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:51:9 + | +LL | let ref a @ ref mut b = u(); + | -----^^^--------- + | | | + | | mutable borrow, by `b`, occurs here + | immutable borrow, by `a`, occurs here + +error: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:57:9 + | +LL | let ref mut a @ ref b = U; + | ---------^^^----- + | | | + | | immutable borrow, by `b`, occurs here + | mutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:61:9 + | +LL | let ref a @ ref mut b = U; + | -----^^^--------- + | | | + | | mutable borrow, by `b`, occurs here + | immutable borrow, by `a`, occurs here + +error: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:67:9 + | +LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => { + | ---------^^^^^^-----^ + | | | + | | immutable borrow, by `b`, occurs here + | mutable borrow, by `a`, occurs here + +error: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:67:33 + | +LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => { + | ---------^^^^^^^-----^ + | | | + | | immutable borrow, by `b`, occurs here + | mutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:9 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { + | -----^^^^^^---------^ + | | | + | | mutable borrow, by `b`, occurs here + | immutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:33 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { + | -----^^^^^^^---------^ + | | | + | | mutable borrow, by `b`, occurs here + | immutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:9 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {} + | -----^^^^^^---------^ + | | | + | | mutable borrow, by `b`, occurs here + | immutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:33 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {} + | -----^^^^^^^---------^ + | | | + | | mutable borrow, by `b`, occurs here + | immutable borrow, by `a`, occurs here + +error: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:9 + | +LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {} + | ---------^^^^^^-----^ + | | | + | | immutable borrow, by `b`, occurs here + | mutable borrow, by `a`, occurs here + +error: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:33 + | +LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {} + | ---------^^^^^^^-----^ + | | | + | | immutable borrow, by `b`, occurs here + | mutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:9 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} + | -----^^^^^^---------^ + | | | + | | mutable borrow, by `b`, occurs here + | immutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:33 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} + | -----^^^^^^^---------^ + | | | + | | mutable borrow, by `b`, occurs here + | immutable borrow, by `a`, occurs here + +error: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:9 + | +LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} + | ---------^^^^^^-----^ + | | | + | | immutable borrow, by `b`, occurs here + | mutable borrow, by `a`, occurs here + +error: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:33 + | +LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} + | ---------^^^^^^^-----^ + | | | + | | immutable borrow, by `b`, occurs here + | mutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:117:9 + | +LL | let ref a @ (ref mut b, ref mut c) = (U, U); + | -----^^^^---------^^---------^ + | | | | + | | | mutable borrow, by `c`, occurs here + | | mutable borrow, by `b`, occurs here + | immutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:9 + | +LL | let ref a @ (ref mut b, ref mut c) = (U, U); + | -----^^^^---------^^---------^ + | | | | + | | | mutable borrow, by `c`, occurs here + | | mutable borrow, by `b`, occurs here + | immutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:129:9 + | +LL | let ref a @ (ref mut b, ref mut c) = (U, U); + | -----^^^^---------^^---------^ + | | | | + | | | mutable borrow, by `c`, occurs here + | | mutable borrow, by `b`, occurs here + | immutable borrow, by `a`, occurs here + +error: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:134:9 + | +LL | let ref mut a @ (ref b, ref c) = (U, U); + | ---------^^^^-----^^-----^ + | | | | + | | | immutable borrow, by `c`, occurs here + | | immutable borrow, by `b`, occurs here + | mutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:22:11 + | +LL | fn f1(ref a @ ref mut b: U) {} + | -----^^^--------- + | | | + | | mutable borrow, by `b`, occurs here + | immutable borrow, by `a`, occurs here + +error: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:24:11 + | +LL | fn f2(ref mut a @ ref b: U) {} + | ---------^^^----- + | | | + | | immutable borrow, by `b`, occurs here + | mutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:26:11 + | +LL | fn f3(ref a @ [ref b, ref mut mid @ .., ref c]: [U; 4]) {} + | -----^^^^^^^^^^^----------------^^^^^^^^ + | | | + | | mutable borrow, by `mid`, occurs here + | immutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:22 + | +LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {} + | -----^^^------------- + | | | | + | | | also moved into `c` here + | | mutable borrow, by `b`, occurs here + | immutable borrow, by `a`, occurs here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:30 + | +LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {} + | ---------^^^- + | | | + | | value moved into `c` here + | value borrowed, by `b`, here + +error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:8:31 + | +LL | ref mut z @ &mut Some(ref a) => { + | ----------------------^^^^^- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here +... +LL | **z = None; + | ---------- mutable borrow later used here + +error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:46:9 + | +LL | let ref mut a @ ref b = u(); + | ^^^^^^^^^^^^----- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here +... +LL | drop(b); + | - immutable borrow later used here + +error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:51:9 + | +LL | let ref a @ ref mut b = u(); + | ^^^^^^^^--------- + | | | + | | mutable borrow occurs here + | immutable borrow occurs here +... +LL | *b = u(); + | -------- mutable borrow later used here + +error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:20 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { + | -----------^^^^^^^^^- + | | | + | | mutable borrow occurs here + | immutable borrow occurs here +... +LL | drop(a); + | - immutable borrow later used here + +error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:45 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { + | ------------^^^^^^^^^- + | | | + | | mutable borrow occurs here + | immutable borrow occurs here +... +LL | drop(a); + | - immutable borrow later used here + +error[E0594]: cannot assign to `*b`, as it is immutable for the pattern guard + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:61 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {} + | ^^^^^^ cannot assign + | + = note: variables bound in patterns are immutable until the end of the pattern guard + +error[E0594]: cannot assign to `*a`, as it is immutable for the pattern guard + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:61 + | +LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {} + | ^^^^^^^^^^^ cannot assign + | + = note: variables bound in patterns are immutable until the end of the pattern guard + +error[E0507]: cannot move out of `b` in pattern guard + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:66 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} + | ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait + | + = note: variables bound in patterns cannot be moved from until after the end of the pattern guard + +error[E0507]: cannot move out of `b` in pattern guard + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:66 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} + | ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait + | + = note: variables bound in patterns cannot be moved from until after the end of the pattern guard + +error[E0507]: cannot move out of `a` in pattern guard + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:66 + | +LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} + | ^ move occurs because `a` has type `&mut Result<U, U>`, which does not implement the `Copy` trait + | + = note: variables bound in patterns cannot be moved from until after the end of the pattern guard + +error[E0507]: cannot move out of `a` in pattern guard + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:66 + | +LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} + | ^ move occurs because `a` has type `&mut Result<U, U>`, which does not implement the `Copy` trait + | + = note: variables bound in patterns cannot be moved from until after the end of the pattern guard + +error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:117:9 + | +LL | let ref a @ (ref mut b, ref mut c) = (U, U); + | ^^^^^^^^^---------^^^^^^^^^^^^ + | | | + | | mutable borrow occurs here + | immutable borrow occurs here +... +LL | *b = U; + | ------ mutable borrow later used here + +error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:9 + | +LL | let ref a @ (ref mut b, ref mut c) = (U, U); + | ^^^^^^^^^---------^^^^^^^^^^^^ + | | | + | | mutable borrow occurs here + | immutable borrow occurs here +... +LL | *b = U; + | ------ mutable borrow later used here + +error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:129:9 + | +LL | let ref a @ (ref mut b, ref mut c) = (U, U); + | ^^^^^^^^^---------^^^^^^^^^^^^ + | | | + | | mutable borrow occurs here + | immutable borrow occurs here +LL | +LL | *b = U; + | ------ mutable borrow later used here + +error[E0382]: borrow of moved value + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:30 + | +LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {} + | --------^^^^^^^^^^^^- + | | | | + | | | value moved here + | | value borrowed here after move + | move occurs because value has type `U`, which does not implement the `Copy` trait + +error: aborting due to 47 previous errors + +Some errors have detailed explanations: E0382, E0502, E0507, E0594. +For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs new file mode 100644 index 000000000..99739c7bc --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs @@ -0,0 +1,109 @@ +// Test that `ref mut x @ ref mut y` and varieties of that are not allowed. + +fn main() { + struct U; + + fn u() -> U { U } + + fn f1(ref mut a @ ref mut b: U) {} + //~^ ERROR cannot borrow value as mutable more than once at a time + fn f2(ref mut a @ ref mut b: U) {} + //~^ ERROR cannot borrow value as mutable more than once at a time + fn f3( + ref mut a @ [ + //~^ ERROR cannot borrow value as mutable more than once at a time + [ref b @ .., _], + [_, ref mut mid @ ..], + .., + [..], + ] : [[U; 4]; 5] + ) {} + fn f4_also_moved(ref mut a @ ref mut b @ c: U) {} + //~^ ERROR cannot borrow value as mutable more than once at a time + //~| ERROR cannot move out of value because it is borrowed + //~| ERROR borrow of moved value + + let ref mut a @ ref mut b = U; + //~^ ERROR cannot borrow value as mutable more than once at a time + drop(a); + let ref mut a @ ref mut b = U; + //~^ ERROR cannot borrow value as mutable more than once at a time + //~| ERROR cannot borrow value as mutable more than once at a time + drop(b); + let ref mut a @ ref mut b = U; + //~^ ERROR cannot borrow value as mutable more than once at a time + + let ref mut a @ ref mut b = U; + //~^ ERROR cannot borrow value as mutable more than once at a time + *a = U; + let ref mut a @ ref mut b = U; + //~^ ERROR cannot borrow value as mutable more than once at a time + //~| ERROR cannot borrow value as mutable more than once at a time + *b = U; + + let ref mut a @ ( + //~^ ERROR cannot borrow value as mutable more than once at a time + ref mut b, + [ + ref mut c, + ref mut d, + ref e, + ] + ) = (U, [U, U, U]); + + let ref mut a @ ( + //~^ ERROR cannot borrow value as mutable more than once at a time + ref mut b, + [ + ref mut c, + ref mut d, + ref e, + ] + ) = (u(), [u(), u(), u()]); + + let a @ (ref mut b, ref mut c) = (U, U); + //~^ ERROR borrow of moved value + let mut val = (U, [U, U]); + let a @ (b, [c, d]) = &mut val; // Same as ^-- + //~^ ERROR borrow of moved value + + let a @ &mut ref mut b = &mut U; + //~^ ERROR borrow of moved value + let a @ &mut (ref mut b, ref mut c) = &mut (U, U); + //~^ ERROR borrow of moved value + + match Ok(U) { + ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + //~^ ERROR cannot borrow value as mutable more than once at a time + //~| ERROR cannot borrow value as mutable more than once at a time + } + } + match Ok(U) { + ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + //~^ ERROR cannot borrow value as mutable more than once at a time + //~| ERROR cannot borrow value as mutable more than once at a time + *b = U; + } + } + match Ok(U) { + ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + //~^ ERROR cannot borrow value as mutable more than once at a time + //~| ERROR cannot borrow value as mutable more than once at a time + //~| ERROR cannot borrow value as mutable more than once at a time + //~| ERROR cannot borrow value as mutable more than once at a time + *a = Err(U); + + // FIXME: The binding name value used above makes for problematic diagnostics. + // Resolve that somehow... + } + } + match Ok(U) { + ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + //~^ ERROR cannot borrow value as mutable more than once at a time + //~| ERROR cannot borrow value as mutable more than once at a time + //~| ERROR cannot borrow value as mutable more than once at a time + //~| ERROR cannot borrow value as mutable more than once at a time + drop(a); + } + } +} diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr new file mode 100644 index 000000000..aa0223041 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr @@ -0,0 +1,346 @@ +error: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:26:9 + | +LL | let ref mut a @ ref mut b = U; + | ---------^^^--------- + | | | + | | another mutable borrow, by `b`, occurs here + | first mutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:29:9 + | +LL | let ref mut a @ ref mut b = U; + | ---------^^^--------- + | | | + | | another mutable borrow, by `b`, occurs here + | first mutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:33:9 + | +LL | let ref mut a @ ref mut b = U; + | ---------^^^--------- + | | | + | | another mutable borrow, by `b`, occurs here + | first mutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:36:9 + | +LL | let ref mut a @ ref mut b = U; + | ---------^^^--------- + | | | + | | another mutable borrow, by `b`, occurs here + | first mutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:39:9 + | +LL | let ref mut a @ ref mut b = U; + | ---------^^^--------- + | | | + | | another mutable borrow, by `b`, occurs here + | first mutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:44:9 + | +LL | let ref mut a @ ( + | ^-------- + | | + | _________first mutable borrow, by `a`, occurs here + | | +LL | | +LL | | ref mut b, + | | --------- another mutable borrow, by `b`, occurs here +LL | | [ +LL | | ref mut c, + | | --------- another mutable borrow, by `c`, occurs here +LL | | ref mut d, + | | --------- another mutable borrow, by `d`, occurs here +LL | | ref e, + | | ----- also borrowed as immutable, by `e`, here +LL | | ] +LL | | ) = (U, [U, U, U]); + | |_____^ + +error: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:54:9 + | +LL | let ref mut a @ ( + | ^-------- + | | + | _________first mutable borrow, by `a`, occurs here + | | +LL | | +LL | | ref mut b, + | | --------- another mutable borrow, by `b`, occurs here +LL | | [ +LL | | ref mut c, + | | --------- another mutable borrow, by `c`, occurs here +LL | | ref mut d, + | | --------- another mutable borrow, by `d`, occurs here +LL | | ref e, + | | ----- also borrowed as immutable, by `e`, here +LL | | ] +LL | | ) = (u(), [u(), u(), u()]); + | |_________^ + +error: borrow of moved value + --> $DIR/borrowck-pat-ref-mut-twice.rs:64:9 + | +LL | let a @ (ref mut b, ref mut c) = (U, U); + | -^^^^---------^^---------^ + | | | | + | | | value borrowed here after move + | | value borrowed here after move + | value moved into `a` here + | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-ref-mut-twice.rs:67:9 + | +LL | let a @ (b, [c, d]) = &mut val; // Same as ^-- + | -^^^^-^^^-^^-^^ + | | | | | + | | | | value borrowed here after move + | | | value borrowed here after move + | | value borrowed here after move + | value moved into `a` here + | move occurs because `a` has type `&mut (U, [U; 2])` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-ref-mut-twice.rs:70:9 + | +LL | let a @ &mut ref mut b = &mut U; + | -^^^^^^^^--------- + | | | + | | value borrowed here after move + | value moved into `a` here + | move occurs because `a` has type `&mut U` which does not implement the `Copy` trait + +error: borrow of moved value + --> $DIR/borrowck-pat-ref-mut-twice.rs:72:9 + | +LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U); + | -^^^^^^^^^---------^^---------^ + | | | | + | | | value borrowed here after move + | | value borrowed here after move + | value moved into `a` here + | move occurs because `a` has type `&mut (U, U)` which does not implement the `Copy` trait + +error: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:76:9 + | +LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + | ---------^^^^^^---------^ + | | | + | | another mutable borrow, by `b`, occurs here + | first mutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:76:37 + | +LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + | ---------^^^^^^^---------^ + | | | + | | another mutable borrow, by `b`, occurs here + | first mutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:82:9 + | +LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + | ---------^^^^^^---------^ + | | | + | | another mutable borrow, by `b`, occurs here + | first mutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:82:37 + | +LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + | ---------^^^^^^^---------^ + | | | + | | another mutable borrow, by `b`, occurs here + | first mutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:89:9 + | +LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + | ---------^^^^^^---------^ + | | | + | | another mutable borrow, by `b`, occurs here + | first mutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:89:37 + | +LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + | ---------^^^^^^^---------^ + | | | + | | another mutable borrow, by `b`, occurs here + | first mutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:101:9 + | +LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + | ---------^^^^^^---------^ + | | | + | | another mutable borrow, by `b`, occurs here + | first mutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:101:37 + | +LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + | ---------^^^^^^^---------^ + | | | + | | another mutable borrow, by `b`, occurs here + | first mutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:8:11 + | +LL | fn f1(ref mut a @ ref mut b: U) {} + | ---------^^^--------- + | | | + | | another mutable borrow, by `b`, occurs here + | first mutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:10:11 + | +LL | fn f2(ref mut a @ ref mut b: U) {} + | ---------^^^--------- + | | | + | | another mutable borrow, by `b`, occurs here + | first mutable borrow, by `a`, occurs here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:13:9 + | +LL | ref mut a @ [ + | ^-------- + | | + | _________first mutable borrow, by `a`, occurs here + | | +LL | | +LL | | [ref b @ .., _], + | | ---------- also borrowed as immutable, by `b`, here +LL | | [_, ref mut mid @ ..], + | | ---------------- another mutable borrow, by `mid`, occurs here +LL | | .., +LL | | [..], +LL | | ] : [[U; 4]; 5] + | |_________^ + +error: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:21:22 + | +LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {} + | ---------^^^------------- + | | | | + | | | also moved into `c` here + | | another mutable borrow, by `b`, occurs here + | first mutable borrow, by `a`, occurs here + +error: cannot move out of value because it is borrowed + --> $DIR/borrowck-pat-ref-mut-twice.rs:21:34 + | +LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {} + | ---------^^^- + | | | + | | value moved into `c` here + | value borrowed, by `b`, here + +error[E0499]: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:29:9 + | +LL | let ref mut a @ ref mut b = U; + | ^^^^^^^^^^^^--------- + | | | + | | first mutable borrow occurs here + | second mutable borrow occurs here +... +LL | drop(b); + | - first borrow later used here + +error[E0499]: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:39:9 + | +LL | let ref mut a @ ref mut b = U; + | ^^^^^^^^^^^^--------- + | | | + | | first mutable borrow occurs here + | second mutable borrow occurs here +... +LL | *b = U; + | ------ first borrow later used here + +error[E0499]: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:89:24 + | +LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + | ---------------^^^^^^^^^- + | | | + | | second mutable borrow occurs here + | first mutable borrow occurs here +... +LL | *a = Err(U); + | ----------- first borrow later used here + +error[E0499]: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:89:53 + | +LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + | ----------------^^^^^^^^^- + | | | + | | second mutable borrow occurs here + | first mutable borrow occurs here +... +LL | *a = Err(U); + | ----------- first borrow later used here + +error[E0499]: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:101:24 + | +LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + | ---------------^^^^^^^^^- + | | | + | | second mutable borrow occurs here + | first mutable borrow occurs here +... +LL | drop(a); + | - first borrow later used here + +error[E0499]: cannot borrow value as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:101:53 + | +LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + | ----------------^^^^^^^^^- + | | | + | | second mutable borrow occurs here + | first mutable borrow occurs here +... +LL | drop(a); + | - first borrow later used here + +error[E0382]: borrow of moved value + --> $DIR/borrowck-pat-ref-mut-twice.rs:21:34 + | +LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {} + | ------------^^^^^^^^^^^^- + | | | | + | | | value moved here + | | value borrowed here after move + | move occurs because value has type `U`, which does not implement the `Copy` trait + +error: aborting due to 31 previous errors + +Some errors have detailed explanations: E0382, E0499. +For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/pattern/bindings-after-at/box-patterns.rs b/src/test/ui/pattern/bindings-after-at/box-patterns.rs new file mode 100644 index 000000000..9db37253c --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/box-patterns.rs @@ -0,0 +1,35 @@ +// Test bindings-after-at with box-patterns + +// run-pass + +#![feature(box_patterns)] + +#[derive(Debug, PartialEq)] +enum MatchArm { + Arm(usize), + Wild, +} + +fn test(x: Option<Box<i32>>) -> MatchArm { + match x { + ref bar @ Some(box n) if n > 0 => { + // bar is a &Option<Box<i32>> + assert_eq!(bar, &x); + + MatchArm::Arm(0) + }, + Some(ref bar @ box n) if n < 0 => { + // bar is a &Box<i32> here + assert_eq!(**bar, n); + + MatchArm::Arm(1) + }, + _ => MatchArm::Wild, + } +} + +fn main() { + assert_eq!(test(Some(Box::new(2))), MatchArm::Arm(0)); + assert_eq!(test(Some(Box::new(-1))), MatchArm::Arm(1)); + assert_eq!(test(Some(Box::new(0))), MatchArm::Wild); +} diff --git a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs new file mode 100644 index 000000000..1e2c2968c --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs @@ -0,0 +1,14 @@ +// Test that mixing `Copy` and non-`Copy` types in `@` patterns is forbidden. + +#[derive(Copy, Clone)] +struct C; + +struct NC<A, B>(A, B); + +fn main() { + // this compiles + let a @ NC(b, c) = NC(C, C); + + let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C)); + //~^ ERROR use of partially moved value +} diff --git a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr new file mode 100644 index 000000000..d290144b6 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr @@ -0,0 +1,14 @@ +error[E0382]: use of partially moved value + --> $DIR/copy-and-move-mixed.rs:12:9 + | +LL | let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C)); + | ^^^^^^^^^^------------^ + | | | + | | value partially moved here + | value used here after partial move + | + = note: partial move occurs because value has type `NC<C, C>`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs new file mode 100644 index 000000000..dfd4d0285 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs @@ -0,0 +1,48 @@ +// Ensures the independence of each side in `binding @ subpat` +// determine their binding modes independently of each other. +// +// That is, `binding` does not influence `subpat`. +// This is important because we might want to allow `p1 @ p2`, +// where both `p1` and `p2` are syntactically unrestricted patterns. +// If `binding` is allowed to influence `subpat`, +// this would create problems for the generalization aforementioned. + + +fn main() { + struct NotCopy; + + fn f1(a @ b: &NotCopy) { // OK + let _: &NotCopy = a; + } + fn f2(ref a @ b: &NotCopy) { + let _: &&NotCopy = a; // Ok + } + + let a @ b = &NotCopy; // OK + let _: &NotCopy = a; + let ref a @ b = &NotCopy; // OK + let _: &&NotCopy = a; + + let ref a @ b = NotCopy; //~ ERROR cannot move out of value because it is borrowed + let _a: &NotCopy = a; + let _b: NotCopy = b; + let ref mut a @ b = NotCopy; //~ ERROR cannot move out of value because it is borrowed + //~^ ERROR borrow of moved value + let _a: &NotCopy = a; + let _b: NotCopy = b; + match Ok(NotCopy) { + Ok(ref a @ b) | Err(b @ ref a) => { + //~^ ERROR cannot move out of value because it is borrowed + //~| ERROR borrow of moved value + let _a: &NotCopy = a; + let _b: NotCopy = b; + } + } + match NotCopy { + ref a @ b => { + //~^ ERROR cannot move out of value because it is borrowed + let _a: &NotCopy = a; + let _b: NotCopy = b; + } + } +} diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr new file mode 100644 index 000000000..d78faa682 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr @@ -0,0 +1,58 @@ +error: cannot move out of value because it is borrowed + --> $DIR/default-binding-modes-both-sides-independent.rs:26:9 + | +LL | let ref a @ b = NotCopy; + | -----^^^- + | | | + | | value moved into `b` here + | value borrowed, by `a`, here + +error: cannot move out of value because it is borrowed + --> $DIR/default-binding-modes-both-sides-independent.rs:29:9 + | +LL | let ref mut a @ b = NotCopy; + | ---------^^^- + | | | + | | value moved into `b` here + | value borrowed, by `a`, here + +error: cannot move out of value because it is borrowed + --> $DIR/default-binding-modes-both-sides-independent.rs:34:12 + | +LL | Ok(ref a @ b) | Err(b @ ref a) => { + | -----^^^- + | | | + | | value moved into `b` here + | value borrowed, by `a`, here + +error: borrow of moved value + --> $DIR/default-binding-modes-both-sides-independent.rs:34:29 + | +LL | Ok(ref a @ b) | Err(b @ ref a) => { + | -^^^----- + | | | + | | value borrowed here after move + | value moved into `b` here + | move occurs because `b` has type `NotCopy` which does not implement the `Copy` trait + +error: cannot move out of value because it is borrowed + --> $DIR/default-binding-modes-both-sides-independent.rs:42:9 + | +LL | ref a @ b => { + | -----^^^- + | | | + | | value moved into `b` here + | value borrowed, by `a`, here + +error[E0382]: borrow of moved value + --> $DIR/default-binding-modes-both-sides-independent.rs:29:9 + | +LL | let ref mut a @ b = NotCopy; + | ^^^^^^^^^^^^- ------- move occurs because value has type `NotCopy`, which does not implement the `Copy` trait + | | | + | | value moved here + | value borrowed here after move + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/pattern/bindings-after-at/nested-binding-mode-lint.rs b/src/test/ui/pattern/bindings-after-at/nested-binding-mode-lint.rs new file mode 100644 index 000000000..fe7d1eba1 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/nested-binding-mode-lint.rs @@ -0,0 +1,12 @@ +// check-pass + +#![deny(unused_mut)] + +fn main() { + let mut is_mut @ not_mut = 42; + &mut is_mut; + ¬_mut; + let not_mut @ mut is_mut = 42; + &mut is_mut; + ¬_mut; +} diff --git a/src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.rs b/src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.rs new file mode 100644 index 000000000..e7d99534d --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.rs @@ -0,0 +1,11 @@ +fn main() { + let mut is_mut @ not_mut = 42; + &mut is_mut; + &mut not_mut; + //~^ ERROR cannot borrow + + let not_mut @ mut is_mut = 42; + &mut is_mut; + &mut not_mut; + //~^ ERROR cannot borrow +} diff --git a/src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr b/src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr new file mode 100644 index 000000000..3180bd0af --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr @@ -0,0 +1,21 @@ +error[E0596]: cannot borrow `not_mut` as mutable, as it is not declared as mutable + --> $DIR/nested-binding-modes-mut.rs:4:5 + | +LL | let mut is_mut @ not_mut = 42; + | ------- help: consider changing this to be mutable: `mut not_mut` +LL | &mut is_mut; +LL | &mut not_mut; + | ^^^^^^^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow `not_mut` as mutable, as it is not declared as mutable + --> $DIR/nested-binding-modes-mut.rs:9:5 + | +LL | let not_mut @ mut is_mut = 42; + | -------------------- help: consider changing this to be mutable: `mut not_mut` +LL | &mut is_mut; +LL | &mut not_mut; + | ^^^^^^^^^^^^ cannot borrow as mutable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/pattern/bindings-after-at/nested-binding-modes-ref.rs b/src/test/ui/pattern/bindings-after-at/nested-binding-modes-ref.rs new file mode 100644 index 000000000..adfb0387f --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/nested-binding-modes-ref.rs @@ -0,0 +1,11 @@ +fn main() { + let ref is_ref @ is_val = 42; + *is_ref; + *is_val; + //~^ ERROR cannot be dereferenced + + let is_val @ ref is_ref = 42; + *is_ref; + *is_val; + //~^ ERROR cannot be dereferenced +} diff --git a/src/test/ui/pattern/bindings-after-at/nested-binding-modes-ref.stderr b/src/test/ui/pattern/bindings-after-at/nested-binding-modes-ref.stderr new file mode 100644 index 000000000..b378fe356 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/nested-binding-modes-ref.stderr @@ -0,0 +1,15 @@ +error[E0614]: type `{integer}` cannot be dereferenced + --> $DIR/nested-binding-modes-ref.rs:4:5 + | +LL | *is_val; + | ^^^^^^^ + +error[E0614]: type `{integer}` cannot be dereferenced + --> $DIR/nested-binding-modes-ref.rs:9:5 + | +LL | *is_val; + | ^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0614`. diff --git a/src/test/ui/pattern/bindings-after-at/nested-patterns.rs b/src/test/ui/pattern/bindings-after-at/nested-patterns.rs new file mode 100644 index 000000000..f06563d56 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/nested-patterns.rs @@ -0,0 +1,14 @@ +// run-pass + + +struct A { a: u8, b: u8 } + +pub fn main() { + match (A { a: 10, b: 20 }) { + ref x @ A { ref a, b: 20 } => { + assert_eq!(x.a, 10); + assert_eq!(*a, 10); + } + A { b: ref _b, .. } => panic!(), + } +} diff --git a/src/test/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs b/src/test/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs new file mode 100644 index 000000000..a709e34b5 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs @@ -0,0 +1,33 @@ +// Here we check that type ascription is syntactically invalid when +// not in the top position of an ascribing `let` binding or function parameter. + + +// This has no effect. +// We include it to demonstrate that this is the case: +#![feature(type_ascription)] + +fn main() {} + +fn _ok() { + let _a @ _b: u8 = 0; // OK. + fn _f(_a @ _b: u8) {} // OK. +} + +#[cfg(FALSE)] +fn case_1() { + let a: u8 @ b = 0; + //~^ ERROR expected one of `!` +} + +#[cfg(FALSE)] +fn case_2() { + let a @ (b: u8); + //~^ ERROR expected one of `!` + //~| ERROR expected one of `)` +} + +#[cfg(FALSE)] +fn case_3() { + let a: T1 @ Outer(b: T2); + //~^ ERROR expected one of `!` +} diff --git a/src/test/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr b/src/test/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr new file mode 100644 index 000000000..27660ae40 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr @@ -0,0 +1,26 @@ +error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found `@` + --> $DIR/nested-type-ascription-syntactically-invalid.rs:18:15 + | +LL | let a: u8 @ b = 0; + | ^ expected one of 7 possible tokens + +error: expected one of `)`, `,`, `@`, or `|`, found `:` + --> $DIR/nested-type-ascription-syntactically-invalid.rs:24:15 + | +LL | let a @ (b: u8); + | ^ expected one of `)`, `,`, `@`, or `|` + +error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found `)` + --> $DIR/nested-type-ascription-syntactically-invalid.rs:24:19 + | +LL | let a @ (b: u8); + | ^ expected one of 7 possible tokens + +error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found `@` + --> $DIR/nested-type-ascription-syntactically-invalid.rs:31:15 + | +LL | let a: T1 @ Outer(b: T2); + | ^ expected one of 7 possible tokens + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/pattern/bindings-after-at/or-patterns-box-patterns.rs b/src/test/ui/pattern/bindings-after-at/or-patterns-box-patterns.rs new file mode 100644 index 000000000..383e377a5 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/or-patterns-box-patterns.rs @@ -0,0 +1,43 @@ +// Test bindings-after-at with or-patterns and box-patterns + +// run-pass + +#![feature(box_patterns)] + +#[derive(Debug, PartialEq)] +enum MatchArm { + Arm(usize), + Wild, +} + +#[derive(Debug, PartialEq)] +enum Test { + Foo, + Bar, + Baz, + Qux, +} + +fn test(foo: Option<Box<Test>>) -> MatchArm { + match foo { + ref bar @ Some(box Test::Foo | box Test::Bar) => { + assert_eq!(bar, &foo); + + MatchArm::Arm(0) + }, + Some(ref bar @ box Test::Baz | ref bar @ box Test::Qux) => { + assert!(**bar == Test::Baz || **bar == Test::Qux); + + MatchArm::Arm(1) + }, + _ => MatchArm::Wild, + } +} + +fn main() { + assert_eq!(test(Some(Box::new(Test::Foo))), MatchArm::Arm(0)); + assert_eq!(test(Some(Box::new(Test::Bar))), MatchArm::Arm(0)); + assert_eq!(test(Some(Box::new(Test::Baz))), MatchArm::Arm(1)); + assert_eq!(test(Some(Box::new(Test::Qux))), MatchArm::Arm(1)); + assert_eq!(test(None), MatchArm::Wild); +} diff --git a/src/test/ui/pattern/bindings-after-at/or-patterns-slice-patterns.rs b/src/test/ui/pattern/bindings-after-at/or-patterns-slice-patterns.rs new file mode 100644 index 000000000..d315f7ee3 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/or-patterns-slice-patterns.rs @@ -0,0 +1,54 @@ +// Test bindings-after-at with or-patterns and slice-patterns + +// run-pass + + +#[derive(Debug, PartialEq)] +enum MatchArm { + Arm(usize), + Wild, +} + +#[derive(Debug, PartialEq)] +enum Test { + Foo, + Bar, + Baz, + Qux, +} + +fn test(foo: &[Option<Test>]) -> MatchArm { + match foo { + bar @ [Some(Test::Foo), .., Some(Test::Qux | Test::Foo)] => { + assert_eq!(bar, foo); + + MatchArm::Arm(0) + }, + [.., bar @ Some(Test::Bar | Test::Qux), _] => { + assert!(bar == &Some(Test::Bar) || bar == &Some(Test::Qux)); + + MatchArm::Arm(1) + }, + _ => MatchArm::Wild, + } +} + +fn main() { + let foo = vec![ + Some(Test::Foo), + Some(Test::Bar), + Some(Test::Baz), + Some(Test::Qux), + ]; + + // path 1a + assert_eq!(test(&foo), MatchArm::Arm(0)); + // path 1b + assert_eq!(test(&[Some(Test::Foo), Some(Test::Bar), Some(Test::Foo)]), MatchArm::Arm(0)); + // path 2a + assert_eq!(test(&foo[..3]), MatchArm::Arm(1)); + // path 2b + assert_eq!(test(&[Some(Test::Bar), Some(Test::Qux), Some(Test::Baz)]), MatchArm::Arm(1)); + // path 3 + assert_eq!(test(&foo[1..2]), MatchArm::Wild); +} diff --git a/src/test/ui/pattern/bindings-after-at/or-patterns.rs b/src/test/ui/pattern/bindings-after-at/or-patterns.rs new file mode 100644 index 000000000..fcc361489 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/or-patterns.rs @@ -0,0 +1,38 @@ +// Test bindings-after-at with or-patterns + +// run-pass + + +#[derive(Debug, PartialEq)] +enum MatchArm { + Arm(usize), + Wild, +} + +#[derive(Debug, Clone, Copy, PartialEq)] +enum Test { + Foo, + Bar, + Baz, + Qux, +} + +fn test(foo: Option<Test>) -> MatchArm { + match foo { + bar @ Some(Test::Foo | Test::Bar) => { + assert!(bar == Some(Test::Foo) || bar == Some(Test::Bar)); + + MatchArm::Arm(0) + }, + Some(_) => MatchArm::Arm(1), + _ => MatchArm::Wild, + } +} + +fn main() { + assert_eq!(test(Some(Test::Foo)), MatchArm::Arm(0)); + assert_eq!(test(Some(Test::Bar)), MatchArm::Arm(0)); + assert_eq!(test(Some(Test::Baz)), MatchArm::Arm(1)); + assert_eq!(test(Some(Test::Qux)), MatchArm::Arm(1)); + assert_eq!(test(None), MatchArm::Wild); +} diff --git a/src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.rs b/src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.rs new file mode 100644 index 000000000..f167a3952 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.rs @@ -0,0 +1,29 @@ +// Test that `binding @ subpat` acts as a product context with respect to duplicate binding names. +// The code that is tested here lives in resolve (see `resolve_pattern_inner`). + + +fn main() { + fn f(a @ a @ a: ()) {} + //~^ ERROR identifier `a` is bound more than once in this parameter list + //~| ERROR identifier `a` is bound more than once in this parameter list + + match Ok(0) { + Ok(a @ b @ a) + //~^ ERROR identifier `a` is bound more than once in the same pattern + | Err(a @ b @ a) + //~^ ERROR identifier `a` is bound more than once in the same pattern + => {} + } + + let a @ a @ a = (); + //~^ ERROR identifier `a` is bound more than once in the same pattern + //~| ERROR identifier `a` is bound more than once in the same pattern + let ref a @ ref a = (); + //~^ ERROR identifier `a` is bound more than once in the same pattern + let ref mut a @ ref mut a = (); + //~^ ERROR identifier `a` is bound more than once in the same pattern + + let a @ (Ok(a) | Err(a)) = Ok(()); + //~^ ERROR identifier `a` is bound more than once in the same pattern + //~| ERROR identifier `a` is bound more than once in the same pattern +} diff --git a/src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr b/src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr new file mode 100644 index 000000000..a165549f6 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr @@ -0,0 +1,64 @@ +error[E0415]: identifier `a` is bound more than once in this parameter list + --> $DIR/pat-at-same-name-both.rs:6:14 + | +LL | fn f(a @ a @ a: ()) {} + | ^ used as parameter more than once + +error[E0415]: identifier `a` is bound more than once in this parameter list + --> $DIR/pat-at-same-name-both.rs:6:18 + | +LL | fn f(a @ a @ a: ()) {} + | ^ used as parameter more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/pat-at-same-name-both.rs:11:20 + | +LL | Ok(a @ b @ a) + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/pat-at-same-name-both.rs:13:23 + | +LL | | Err(a @ b @ a) + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/pat-at-same-name-both.rs:18:13 + | +LL | let a @ a @ a = (); + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/pat-at-same-name-both.rs:18:17 + | +LL | let a @ a @ a = (); + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/pat-at-same-name-both.rs:21:21 + | +LL | let ref a @ ref a = (); + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/pat-at-same-name-both.rs:23:29 + | +LL | let ref mut a @ ref mut a = (); + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/pat-at-same-name-both.rs:26:17 + | +LL | let a @ (Ok(a) | Err(a)) = Ok(()); + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/pat-at-same-name-both.rs:26:26 + | +LL | let a @ (Ok(a) | Err(a)) = Ok(()); + | ^ used in a pattern more than once + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0415, E0416. +For more information about an error, try `rustc --explain E0415`. diff --git a/src/test/ui/pattern/bindings-after-at/slice-patterns.rs b/src/test/ui/pattern/bindings-after-at/slice-patterns.rs new file mode 100644 index 000000000..4f4c96e45 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/slice-patterns.rs @@ -0,0 +1,39 @@ +// Test bindings-after-at with slice-patterns + +// run-pass + + +#[derive(Debug, PartialEq)] +enum MatchArm { + Arm(usize), + Wild, +} + +fn test(foo: &[i32]) -> MatchArm { + match foo { + [bar @ .., n] if n == &5 => { + for i in bar { + assert!(i < &5); + } + + MatchArm::Arm(0) + }, + bar @ [x0, .., xn] => { + assert_eq!(x0, &1); + assert_eq!(x0, &1); + assert_eq!(xn, &4); + assert_eq!(bar, &[1, 2, 3, 4]); + + MatchArm::Arm(1) + }, + _ => MatchArm::Wild, + } +} + +fn main() { + let foo = vec![1, 2, 3, 4, 5]; + + assert_eq!(test(&foo), MatchArm::Arm(0)); + assert_eq!(test(&foo[..4]), MatchArm::Arm(1)); + assert_eq!(test(&foo[0..1]), MatchArm::Wild); +} diff --git a/src/test/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs b/src/test/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs new file mode 100644 index 000000000..50ac0ef27 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs @@ -0,0 +1,16 @@ +// Here we check that `_ @ sub` is syntactically invalid +// and comes with a nice actionable suggestion. + +fn main() {} + +#[cfg(FALSE)] +fn wild_before_at_is_bad_syntax() { + let _ @ a = 0; + //~^ ERROR pattern on wrong side of `@` + let _ @ ref a = 0; + //~^ ERROR pattern on wrong side of `@` + let _ @ ref mut a = 0; + //~^ ERROR pattern on wrong side of `@` + let _ @ (a, .., b) = (0, 1, 2, 3); + //~^ ERROR left-hand side of `@` must be a binding +} diff --git a/src/test/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr b/src/test/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr new file mode 100644 index 000000000..2f4541584 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr @@ -0,0 +1,43 @@ +error: pattern on wrong side of `@` + --> $DIR/wild-before-at-syntactically-rejected.rs:8:9 + | +LL | let _ @ a = 0; + | -^^^- + | | | + | | binding on the right, should be on the left + | pattern on the left, should be on the right + | help: switch the order: `a @ _` + +error: pattern on wrong side of `@` + --> $DIR/wild-before-at-syntactically-rejected.rs:10:9 + | +LL | let _ @ ref a = 0; + | -^^^----- + | | | + | | binding on the right, should be on the left + | pattern on the left, should be on the right + | help: switch the order: `ref a @ _` + +error: pattern on wrong side of `@` + --> $DIR/wild-before-at-syntactically-rejected.rs:12:9 + | +LL | let _ @ ref mut a = 0; + | -^^^--------- + | | | + | | binding on the right, should be on the left + | pattern on the left, should be on the right + | help: switch the order: `ref mut a @ _` + +error: left-hand side of `@` must be a binding + --> $DIR/wild-before-at-syntactically-rejected.rs:14:9 + | +LL | let _ @ (a, .., b) = (0, 1, 2, 3); + | -^^^---------- + | | | + | | also a pattern + | interpreted as a pattern, not a binding + | + = note: bindings are `x`, `mut x`, `ref x`, and `ref mut x` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/pattern/for-loop-bad-item.rs b/src/test/ui/pattern/for-loop-bad-item.rs new file mode 100644 index 000000000..9a56a399b --- /dev/null +++ b/src/test/ui/pattern/for-loop-bad-item.rs @@ -0,0 +1,20 @@ +struct Qux(i32); + +fn bad() { + let mut map = std::collections::HashMap::new(); + map.insert(('a', 'b'), ('c', 'd')); + + for ((_, _), (&mut c, _)) in &mut map { + //~^ ERROR mismatched types + if c == 'e' {} + } +} + +fn bad2() { + for Some(Qux(_)) | None in [Some(""), None] { + //~^ ERROR mismatched types + todo!(); + } +} + +fn main() {} diff --git a/src/test/ui/pattern/for-loop-bad-item.stderr b/src/test/ui/pattern/for-loop-bad-item.stderr new file mode 100644 index 000000000..f064a25a9 --- /dev/null +++ b/src/test/ui/pattern/for-loop-bad-item.stderr @@ -0,0 +1,32 @@ +error[E0308]: mismatched types + --> $DIR/for-loop-bad-item.rs:7:19 + | +LL | for ((_, _), (&mut c, _)) in &mut map { + | ^^^^^^ -------- this is an iterator with items of type `(&(char, char), &mut (char, char))` + | | + | expected `char`, found `&mut _` + | + = note: expected type `char` + found mutable reference `&mut _` +note: to declare a mutable binding use: `mut c` + --> $DIR/for-loop-bad-item.rs:7:19 + | +LL | for ((_, _), (&mut c, _)) in &mut map { + | ^^^^^^ +help: consider removing `&mut` from the pattern + | +LL - for ((_, _), (&mut c, _)) in &mut map { +LL + for ((_, _), (c, _)) in &mut map { + | + +error[E0308]: mismatched types + --> $DIR/for-loop-bad-item.rs:14:14 + | +LL | for Some(Qux(_)) | None in [Some(""), None] { + | ^^^^^^ ---------------- this is an iterator with items of type `Option<&str>` + | | + | expected `str`, found struct `Qux` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/pattern/ignore-all-the-things.rs b/src/test/ui/pattern/ignore-all-the-things.rs new file mode 100644 index 000000000..5980e1a85 --- /dev/null +++ b/src/test/ui/pattern/ignore-all-the-things.rs @@ -0,0 +1,44 @@ +// run-pass + +#![allow(non_shorthand_field_patterns)] +#![allow(dead_code)] +#![allow(unused_variables)] + +struct Foo(isize, isize, isize, isize); +struct Bar{a: isize, b: isize, c: isize, d: isize} + +pub fn main() { + let Foo(..) = Foo(5, 5, 5, 5); + let Foo(..) = Foo(5, 5, 5, 5); + let Bar{..} = Bar{a: 5, b: 5, c: 5, d: 5}; + let (..) = (5, 5, 5, 5); + let Foo(a, b, ..) = Foo(5, 5, 5, 5); + let Foo(.., d) = Foo(5, 5, 5, 5); + let (a, b, ..) = (5, 5, 5, 5); + let (.., c, d) = (5, 5, 5, 5); + let Bar{b: b, ..} = Bar{a: 5, b: 5, c: 5, d: 5}; + match [5, 5, 5, 5] { + [..] => { } + } + match [5, 5, 5, 5] { + [a, ..] => { } + } + match [5, 5, 5, 5] { + [.., b] => { } + } + match [5, 5, 5, 5] { + [a, .., b] => { } + } + match [5, 5, 5] { + [..] => { } + } + match [5, 5, 5] { + [a, ..] => { } + } + match [5, 5, 5] { + [.., a] => { } + } + match [5, 5, 5] { + [a, .., b] => { } + } +} diff --git a/src/test/ui/pattern/integer-range-binding.rs b/src/test/ui/pattern/integer-range-binding.rs new file mode 100644 index 000000000..ff065882d --- /dev/null +++ b/src/test/ui/pattern/integer-range-binding.rs @@ -0,0 +1,8 @@ +// run-pass + +fn main() { + let -2147483648..=2147483647 = 1; + let 0..=255 = 0u8; + let -128..=127 = 0i8; + let '\u{0000}'..='\u{10FFFF}' = 'v'; +} diff --git a/src/test/ui/pattern/issue-10392.rs b/src/test/ui/pattern/issue-10392.rs new file mode 100644 index 000000000..926fa9480 --- /dev/null +++ b/src/test/ui/pattern/issue-10392.rs @@ -0,0 +1,30 @@ +// run-pass +#![allow(unused_variables)] + +struct A { foo: isize } +struct B { a: isize, b: isize, c: isize } + +fn mka() -> A { panic!() } +fn mkb() -> B { panic!() } + +fn test() { + let A { foo, } = mka(); + let A { + foo, + } = mka(); + + let B { a, b, c, } = mkb(); + + match mka() { + A { foo: _foo, } => {} + } + + match Some(mka()) { + Some(A { foo: _foo, }) => {} + None => {} + } +} + +pub fn main() { + if false { test() } +} diff --git a/src/test/ui/pattern/issue-11577.rs b/src/test/ui/pattern/issue-11577.rs new file mode 100644 index 000000000..70177c5ed --- /dev/null +++ b/src/test/ui/pattern/issue-11577.rs @@ -0,0 +1,18 @@ +// run-pass +// Destructuring struct variants would ICE where regular structs wouldn't + +enum Foo { + VBar { num: isize } +} + +struct SBar { num: isize } + +pub fn main() { + let vbar = Foo::VBar { num: 1 }; + let Foo::VBar { num } = vbar; + assert_eq!(num, 1); + + let sbar = SBar { num: 2 }; + let SBar { num } = sbar; + assert_eq!(num, 2); +} diff --git a/src/test/ui/pattern/issue-12582.rs b/src/test/ui/pattern/issue-12582.rs new file mode 100644 index 000000000..f3366704e --- /dev/null +++ b/src/test/ui/pattern/issue-12582.rs @@ -0,0 +1,21 @@ +// run-pass + +pub fn main() { + let x = 1; + let y = 2; + + assert_eq!(3, match (x, y) { + (1, 1) => 1, + (2, 2) => 2, + (1..=2, 2) => 3, + _ => 4, + }); + + // nested tuple + assert_eq!(3, match ((x, y),) { + ((1, 1),) => 1, + ((2, 2),) => 2, + ((1..=2, 2),) => 3, + _ => 4, + }); +} diff --git a/src/test/ui/pattern/issue-14221.rs b/src/test/ui/pattern/issue-14221.rs new file mode 100644 index 000000000..282c41113 --- /dev/null +++ b/src/test/ui/pattern/issue-14221.rs @@ -0,0 +1,21 @@ +#![deny(unreachable_patterns)] +#![allow(unused_variables)] +#![allow(non_snake_case)] + +pub enum E { + A, + B, +} + +pub mod b { + pub fn key(e: ::E) -> &'static str { + match e { + A => "A", +//~^ WARN pattern binding `A` is named the same as one of the variants of the type `E` + B => "B", //~ ERROR: unreachable pattern +//~^ WARN pattern binding `B` is named the same as one of the variants of the type `E` + } + } +} + +fn main() {} diff --git a/src/test/ui/pattern/issue-14221.stderr b/src/test/ui/pattern/issue-14221.stderr new file mode 100644 index 000000000..fc8ae1ed7 --- /dev/null +++ b/src/test/ui/pattern/issue-14221.stderr @@ -0,0 +1,32 @@ +warning[E0170]: pattern binding `A` is named the same as one of the variants of the type `E` + --> $DIR/issue-14221.rs:13:13 + | +LL | A => "A", + | ^ help: to match on the variant, qualify the path: `E::A` + | + = note: `#[warn(bindings_with_variant_name)]` on by default + +warning[E0170]: pattern binding `B` is named the same as one of the variants of the type `E` + --> $DIR/issue-14221.rs:15:13 + | +LL | B => "B", + | ^ help: to match on the variant, qualify the path: `E::B` + +error: unreachable pattern + --> $DIR/issue-14221.rs:15:13 + | +LL | A => "A", + | - matches any value +LL | +LL | B => "B", + | ^ unreachable pattern + | +note: the lint level is defined here + --> $DIR/issue-14221.rs:1:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 2 warnings emitted + +For more information about this error, try `rustc --explain E0170`. diff --git a/src/test/ui/pattern/issue-15080.rs b/src/test/ui/pattern/issue-15080.rs new file mode 100644 index 000000000..4dd6981d4 --- /dev/null +++ b/src/test/ui/pattern/issue-15080.rs @@ -0,0 +1,22 @@ +// run-pass + +fn main() { + let mut x: &[_] = &[1, 2, 3, 4]; + + let mut result = vec![]; + loop { + x = match *x { + [1, n, 3, ref rest @ ..] => { + result.push(n); + rest + } + [n, ref rest @ ..] => { + result.push(n); + rest + } + [] => + break + } + } + assert_eq!(result, [2, 4]); +} diff --git a/src/test/ui/pattern/issue-22546.rs b/src/test/ui/pattern/issue-22546.rs new file mode 100644 index 000000000..c26e457f9 --- /dev/null +++ b/src/test/ui/pattern/issue-22546.rs @@ -0,0 +1,52 @@ +// run-pass +#![allow(unused_variables)] +// Parsing patterns with paths with type parameters (issue #22544) + +use std::default::Default; + +#[derive(Default)] +pub struct Foo<T>(T, T); + +impl<T: ::std::fmt::Display> Foo<T> { + fn foo(&self) { + match *self { + Foo::<T>(ref x, ref y) => println!("Goodbye, World! {} {}", x, y) + } + } +} + +trait Tr { + type U; +} + +impl<T> Tr for Foo<T> { + type U = T; +} + +struct Wrapper<T> { + value: T +} + +fn main() { + let Foo::<i32>(a, b) = Default::default(); + + let f = Foo(2,3); + f.foo(); + + let w = Wrapper { value: Foo(10u8, 11u8) }; + match w { + Wrapper::<Foo<u8>> { value: Foo(10, 11) } => {}, + ::Wrapper::<<Foo<_> as Tr>::U> { value: Foo::<u8>(11, 16) } => { panic!() }, + _ => { panic!() } + } + + if let None::<u8> = Some(8) { + panic!(); + } + if let None::<u8> { .. } = Some(8) { + panic!(); + } + if let Option::None::<u8> { .. } = Some(8) { + panic!(); + } +} diff --git a/src/test/ui/pattern/issue-27320.rs b/src/test/ui/pattern/issue-27320.rs new file mode 100644 index 000000000..d1aa56b91 --- /dev/null +++ b/src/test/ui/pattern/issue-27320.rs @@ -0,0 +1,15 @@ +// run-pass +#![allow(unused_variables)] +#![allow(dead_code)] + +macro_rules! piece( + ($piece:pat) => ($piece); +); + +enum Piece {A, B} + +fn main() { + match Piece::A { + piece!(pt@ Piece::A) | piece!(pt@ Piece::B) => {} + } +} diff --git a/src/test/ui/pattern/issue-6449.rs b/src/test/ui/pattern/issue-6449.rs new file mode 100644 index 000000000..bfd4c1232 --- /dev/null +++ b/src/test/ui/pattern/issue-6449.rs @@ -0,0 +1,44 @@ +// run-pass +#![allow(dead_code)] + +enum Foo { + Bar(isize), + Baz, +} + +enum Other { + Other1(Foo), + Other2(Foo, Foo), +} + +fn main() { + match Foo::Baz { + ::Foo::Bar(3) => panic!(), + ::Foo::Bar(_) if false => panic!(), + ::Foo::Bar(..) if false => panic!(), + ::Foo::Bar(_n) => panic!(), + ::Foo::Baz => {} + } + match Foo::Bar(3) { + ::Foo::Bar(3) => {} + ::Foo::Bar(_) if false => panic!(), + ::Foo::Bar(..) if false => panic!(), + ::Foo::Bar(_n) => panic!(), + ::Foo::Baz => panic!(), + } + match Foo::Bar(4) { + ::Foo::Bar(3) => panic!(), + ::Foo::Bar(_) if false => panic!(), + ::Foo::Bar(..) if false => panic!(), + ::Foo::Bar(n) => assert_eq!(n, 4), + ::Foo::Baz => panic!(), + } + + match Other::Other1(Foo::Baz) { + ::Other::Other1(::Foo::Baz) => {} + ::Other::Other1(::Foo::Bar(_)) => {} + ::Other::Other2(::Foo::Baz, ::Foo::Bar(_)) => {} + ::Other::Other2(::Foo::Bar(..), ::Foo::Baz) => {} + ::Other::Other2(..) => {} + } +} diff --git a/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.rs b/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.rs new file mode 100644 index 000000000..48a8e0482 --- /dev/null +++ b/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.rs @@ -0,0 +1,14 @@ +// Regression test for #66270, fixed by #66246 + +struct Bug { + incorrect_field: 0, + //~^ ERROR expected type +} + +struct Empty {} + +fn main() { + let Bug { + any_field: Empty {}, + } = Bug {}; +} diff --git a/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.stderr b/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.stderr new file mode 100644 index 000000000..fef0f3c0e --- /dev/null +++ b/src/test/ui/pattern/issue-66270-pat-struct-parser-recovery.stderr @@ -0,0 +1,8 @@ +error: expected type, found `0` + --> $DIR/issue-66270-pat-struct-parser-recovery.rs:4:22 + | +LL | incorrect_field: 0, + | ^ expected type + +error: aborting due to previous error + diff --git a/src/test/ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs b/src/test/ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs new file mode 100644 index 000000000..ae28c1403 --- /dev/null +++ b/src/test/ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs @@ -0,0 +1,21 @@ +// Regression test for #67037. +// +// In type checking patterns, E0023 occurs when the tuple pattern and the expected +// tuple pattern have different number of fields. For example, as below, `P()`, +// the tuple struct pattern, has 0 fields, but requires 1 field. +// +// In emitting E0023, we try to see if this is a case of e.g., `Some(a, b, c)` but where +// the scrutinee was of type `Some((a, b, c))`, and suggest that parentheses be added. +// +// However, we did not account for the expected type being different than the tuple pattern type. +// This caused an issue when the tuple pattern type (`P<T>`) was generic. +// Specifically, we tried deriving the 0th field's type using the `substs` of the expected type. +// When attempting to substitute `T`, there was no such substitution, so "out of range" occurred. + +struct U {} // 0 type parameters offered +struct P<T>(T); // 1 type parameter wanted + +fn main() { + let P() = U {}; //~ ERROR mismatched types + //~^ ERROR this pattern has 0 fields, but the corresponding tuple struct has 1 field +} diff --git a/src/test/ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr b/src/test/ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr new file mode 100644 index 000000000..75a231f6b --- /dev/null +++ b/src/test/ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr @@ -0,0 +1,33 @@ +error[E0308]: mismatched types + --> $DIR/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs:19:9 + | +LL | let P() = U {}; + | ^^^ ---- this expression has type `U` + | | + | expected struct `U`, found struct `P` + | + = note: expected struct `U` + found struct `P<_>` + +error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 1 field + --> $DIR/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs:19:9 + | +LL | struct P<T>(T); // 1 type parameter wanted + | - tuple struct has 1 field +... +LL | let P() = U {}; + | ^^^ expected 1 field, found 0 + | +help: use `_` to explicitly ignore each field + | +LL | let P(_) = U {}; + | + +help: use `..` to ignore all fields + | +LL | let P(..) = U {}; + | ++ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0023, E0308. +For more information about an error, try `rustc --explain E0023`. diff --git a/src/test/ui/pattern/issue-67776-match-same-name-enum-variant-refs.rs b/src/test/ui/pattern/issue-67776-match-same-name-enum-variant-refs.rs new file mode 100644 index 000000000..6fd5768a5 --- /dev/null +++ b/src/test/ui/pattern/issue-67776-match-same-name-enum-variant-refs.rs @@ -0,0 +1,42 @@ +// Test for issue #67776: binding named the same as enum variant +// should report a warning even when matching against a reference type + +// check-pass + +#![allow(unused_variables)] +#![allow(non_snake_case)] + +enum Foo { + Bar, + Baz, +} + + +fn fn1(e: Foo) { + match e { + Bar => {}, + //~^ WARNING named the same as one of the variants of the type `Foo` + Baz => {}, + //~^ WARNING named the same as one of the variants of the type `Foo` + } +} + +fn fn2(e: &Foo) { + match e { + Bar => {}, + //~^ WARNING named the same as one of the variants of the type `Foo` + Baz => {}, + //~^ WARNING named the same as one of the variants of the type `Foo` + } +} + +fn fn3(e: &mut &&mut Foo) { + match e { + Bar => {}, + //~^ WARNING named the same as one of the variants of the type `Foo` + Baz => {}, + //~^ WARNING named the same as one of the variants of the type `Foo` + } +} + +fn main() {} diff --git a/src/test/ui/pattern/issue-67776-match-same-name-enum-variant-refs.stderr b/src/test/ui/pattern/issue-67776-match-same-name-enum-variant-refs.stderr new file mode 100644 index 000000000..6f3613b63 --- /dev/null +++ b/src/test/ui/pattern/issue-67776-match-same-name-enum-variant-refs.stderr @@ -0,0 +1,41 @@ +warning[E0170]: pattern binding `Bar` is named the same as one of the variants of the type `Foo` + --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:17:9 + | +LL | Bar => {}, + | ^^^ help: to match on the variant, qualify the path: `Foo::Bar` + | + = note: `#[warn(bindings_with_variant_name)]` on by default + +warning[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo` + --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:19:9 + | +LL | Baz => {}, + | ^^^ help: to match on the variant, qualify the path: `Foo::Baz` + +warning[E0170]: pattern binding `Bar` is named the same as one of the variants of the type `Foo` + --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:26:9 + | +LL | Bar => {}, + | ^^^ help: to match on the variant, qualify the path: `Foo::Bar` + +warning[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo` + --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:28:9 + | +LL | Baz => {}, + | ^^^ help: to match on the variant, qualify the path: `Foo::Baz` + +warning[E0170]: pattern binding `Bar` is named the same as one of the variants of the type `Foo` + --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:35:9 + | +LL | Bar => {}, + | ^^^ help: to match on the variant, qualify the path: `Foo::Bar` + +warning[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo` + --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:37:9 + | +LL | Baz => {}, + | ^^^ help: to match on the variant, qualify the path: `Foo::Baz` + +warning: 6 warnings emitted + +For more information about this error, try `rustc --explain E0170`. diff --git a/src/test/ui/pattern/issue-68393-let-pat-assoc-constant.rs b/src/test/ui/pattern/issue-68393-let-pat-assoc-constant.rs new file mode 100644 index 000000000..95ead6b5d --- /dev/null +++ b/src/test/ui/pattern/issue-68393-let-pat-assoc-constant.rs @@ -0,0 +1,26 @@ +pub enum EFoo { + A, +} + +pub trait Foo { + const X: EFoo; +} + +struct Abc; + +impl Foo for Abc { + const X: EFoo = EFoo::A; +} + +struct Def; +impl Foo for Def { + const X: EFoo = EFoo::A; +} + +pub fn test<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) { + //~^ ERROR associated consts cannot be referenced in patterns + let A::X = arg; + //~^ ERROR associated consts cannot be referenced in patterns +} + +fn main() {} diff --git a/src/test/ui/pattern/issue-68393-let-pat-assoc-constant.stderr b/src/test/ui/pattern/issue-68393-let-pat-assoc-constant.stderr new file mode 100644 index 000000000..54ecc2498 --- /dev/null +++ b/src/test/ui/pattern/issue-68393-let-pat-assoc-constant.stderr @@ -0,0 +1,15 @@ +error[E0158]: associated consts cannot be referenced in patterns + --> $DIR/issue-68393-let-pat-assoc-constant.rs:20:40 + | +LL | pub fn test<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) { + | ^^^^ + +error[E0158]: associated consts cannot be referenced in patterns + --> $DIR/issue-68393-let-pat-assoc-constant.rs:22:9 + | +LL | let A::X = arg; + | ^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0158`. diff --git a/src/test/ui/pattern/issue-72565.rs b/src/test/ui/pattern/issue-72565.rs new file mode 100644 index 000000000..1e262fd50 --- /dev/null +++ b/src/test/ui/pattern/issue-72565.rs @@ -0,0 +1,8 @@ +const F: &'static dyn PartialEq<u32> = &7u32; + +fn main() { + let a: &dyn PartialEq<u32> = &7u32; + match a { + F => panic!(), //~ ERROR: `&dyn PartialEq<u32>` cannot be used in patterns + } +} diff --git a/src/test/ui/pattern/issue-72565.stderr b/src/test/ui/pattern/issue-72565.stderr new file mode 100644 index 000000000..2f82616b2 --- /dev/null +++ b/src/test/ui/pattern/issue-72565.stderr @@ -0,0 +1,8 @@ +error: `&dyn PartialEq<u32>` cannot be used in patterns + --> $DIR/issue-72565.rs:6:9 + | +LL | F => panic!(), + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/pattern/issue-72574-1.rs b/src/test/ui/pattern/issue-72574-1.rs new file mode 100644 index 000000000..1b80a2179 --- /dev/null +++ b/src/test/ui/pattern/issue-72574-1.rs @@ -0,0 +1,10 @@ +fn main() { + let x = (1, 2, 3); + match x { + (_a, _x @ ..) => {} + _ => {} + } +} +//~^^^^ ERROR `_x @` is not allowed in a tuple +//~| ERROR: `..` patterns are not allowed here +//~| ERROR: mismatched types diff --git a/src/test/ui/pattern/issue-72574-1.stderr b/src/test/ui/pattern/issue-72574-1.stderr new file mode 100644 index 000000000..653869a23 --- /dev/null +++ b/src/test/ui/pattern/issue-72574-1.stderr @@ -0,0 +1,34 @@ +error: `_x @` is not allowed in a tuple + --> $DIR/issue-72574-1.rs:4:14 + | +LL | (_a, _x @ ..) => {} + | ^^^^^^^ this is only allowed in slice patterns + | + = help: remove this and bind each tuple field independently +help: if you don't need to use the contents of _x, discard the tuple's remaining fields + | +LL | (_a, ..) => {} + | ~~ + +error: `..` patterns are not allowed here + --> $DIR/issue-72574-1.rs:4:19 + | +LL | (_a, _x @ ..) => {} + | ^^ + | + = note: only allowed in tuple, tuple struct, and slice patterns + +error[E0308]: mismatched types + --> $DIR/issue-72574-1.rs:4:9 + | +LL | match x { + | - this expression has type `({integer}, {integer}, {integer})` +LL | (_a, _x @ ..) => {} + | ^^^^^^^^^^^^^ expected a tuple with 3 elements, found one with 2 elements + | + = note: expected tuple `({integer}, {integer}, {integer})` + found tuple `(_, _)` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/pattern/issue-72574-2.rs b/src/test/ui/pattern/issue-72574-2.rs new file mode 100644 index 000000000..0ad2db848 --- /dev/null +++ b/src/test/ui/pattern/issue-72574-2.rs @@ -0,0 +1,12 @@ +struct Binder(i32, i32, i32); + +fn main() { + let x = Binder(1, 2, 3); + match x { + Binder(_a, _x @ ..) => {} + _ => {} + } +} +//~^^^^ ERROR `_x @` is not allowed in a tuple struct +//~| ERROR: `..` patterns are not allowed here +//~| ERROR: this pattern has 2 fields, but the corresponding tuple struct has 3 fields diff --git a/src/test/ui/pattern/issue-72574-2.stderr b/src/test/ui/pattern/issue-72574-2.stderr new file mode 100644 index 000000000..05650f05c --- /dev/null +++ b/src/test/ui/pattern/issue-72574-2.stderr @@ -0,0 +1,37 @@ +error: `_x @` is not allowed in a tuple struct + --> $DIR/issue-72574-2.rs:6:20 + | +LL | Binder(_a, _x @ ..) => {} + | ^^^^^^^ this is only allowed in slice patterns + | + = help: remove this and bind each tuple field independently +help: if you don't need to use the contents of _x, discard the tuple's remaining fields + | +LL | Binder(_a, ..) => {} + | ~~ + +error: `..` patterns are not allowed here + --> $DIR/issue-72574-2.rs:6:25 + | +LL | Binder(_a, _x @ ..) => {} + | ^^ + | + = note: only allowed in tuple, tuple struct, and slice patterns + +error[E0023]: this pattern has 2 fields, but the corresponding tuple struct has 3 fields + --> $DIR/issue-72574-2.rs:6:16 + | +LL | struct Binder(i32, i32, i32); + | --- --- --- tuple struct has 3 fields +... +LL | Binder(_a, _x @ ..) => {} + | ^^ ^^^^^^^ expected 3 fields, found 2 + | +help: use `_` to explicitly ignore each field + | +LL | Binder(_a, _x @ .., _) => {} + | +++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0023`. diff --git a/src/test/ui/pattern/issue-74539.rs b/src/test/ui/pattern/issue-74539.rs new file mode 100644 index 000000000..0b25f87ec --- /dev/null +++ b/src/test/ui/pattern/issue-74539.rs @@ -0,0 +1,15 @@ +enum E { + A(u8, u8), +} + +fn main() { + let e = E::A(2, 3); + match e { + E::A(x @ ..) => { + //~^ ERROR: `x @` is not allowed in a tuple struct + //~| ERROR: `..` patterns are not allowed here + //~| ERROR: this pattern has 1 field, but the corresponding tuple variant has 2 fields + x + } + }; +} diff --git a/src/test/ui/pattern/issue-74539.stderr b/src/test/ui/pattern/issue-74539.stderr new file mode 100644 index 000000000..7443946c0 --- /dev/null +++ b/src/test/ui/pattern/issue-74539.stderr @@ -0,0 +1,37 @@ +error: `x @` is not allowed in a tuple struct + --> $DIR/issue-74539.rs:8:14 + | +LL | E::A(x @ ..) => { + | ^^^^^^ this is only allowed in slice patterns + | + = help: remove this and bind each tuple field independently +help: if you don't need to use the contents of x, discard the tuple's remaining fields + | +LL | E::A(..) => { + | ~~ + +error: `..` patterns are not allowed here + --> $DIR/issue-74539.rs:8:18 + | +LL | E::A(x @ ..) => { + | ^^ + | + = note: only allowed in tuple, tuple struct, and slice patterns + +error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields + --> $DIR/issue-74539.rs:8:14 + | +LL | A(u8, u8), + | -- -- tuple variant has 2 fields +... +LL | E::A(x @ ..) => { + | ^^^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | E::A(x @ .., _) => { + | +++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0023`. diff --git a/src/test/ui/pattern/issue-74702.rs b/src/test/ui/pattern/issue-74702.rs new file mode 100644 index 000000000..0aeb3b217 --- /dev/null +++ b/src/test/ui/pattern/issue-74702.rs @@ -0,0 +1,7 @@ +fn main() { + let (foo @ ..,) = (0, 0); + //~^ ERROR: `foo @` is not allowed in a tuple + //~| ERROR: `..` patterns are not allowed here + //~| ERROR: mismatched types + dbg!(foo); +} diff --git a/src/test/ui/pattern/issue-74702.stderr b/src/test/ui/pattern/issue-74702.stderr new file mode 100644 index 000000000..f2e2c8f02 --- /dev/null +++ b/src/test/ui/pattern/issue-74702.stderr @@ -0,0 +1,34 @@ +error: `foo @` is not allowed in a tuple + --> $DIR/issue-74702.rs:2:10 + | +LL | let (foo @ ..,) = (0, 0); + | ^^^^^^^^ this is only allowed in slice patterns + | + = help: remove this and bind each tuple field independently +help: if you don't need to use the contents of foo, discard the tuple's remaining fields + | +LL | let (..,) = (0, 0); + | ~~ + +error: `..` patterns are not allowed here + --> $DIR/issue-74702.rs:2:16 + | +LL | let (foo @ ..,) = (0, 0); + | ^^ + | + = note: only allowed in tuple, tuple struct, and slice patterns + +error[E0308]: mismatched types + --> $DIR/issue-74702.rs:2:9 + | +LL | let (foo @ ..,) = (0, 0); + | ^^^^^^^^^^^ ------ this expression has type `({integer}, {integer})` + | | + | expected a tuple with 2 elements, found one with 1 element + | + = note: expected tuple `({integer}, {integer})` + found tuple `(_,)` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/pattern/issue-74954.rs b/src/test/ui/pattern/issue-74954.rs new file mode 100644 index 000000000..269ec3c7a --- /dev/null +++ b/src/test/ui/pattern/issue-74954.rs @@ -0,0 +1,7 @@ +// check-pass + +fn main() { + if let Some([b'@', filename @ ..]) = Some(b"@abc123") { + println!("filename {:?}", filename); + } +} diff --git a/src/test/ui/pattern/issue-80186-mut-binding-help-suggestion.rs b/src/test/ui/pattern/issue-80186-mut-binding-help-suggestion.rs new file mode 100644 index 000000000..a5e9b1db5 --- /dev/null +++ b/src/test/ui/pattern/issue-80186-mut-binding-help-suggestion.rs @@ -0,0 +1,9 @@ +// Regression test for correct pretty-printing of an AST representing `&(mut x)` in help +// suggestion diagnostic. + +fn main() { + let mut &x = &0; + //~^ ERROR `mut` must be attached to each individual binding + //~| HELP add `mut` to each binding + //~| SUGGESTION &(mut x) +} diff --git a/src/test/ui/pattern/issue-80186-mut-binding-help-suggestion.stderr b/src/test/ui/pattern/issue-80186-mut-binding-help-suggestion.stderr new file mode 100644 index 000000000..75b6c163b --- /dev/null +++ b/src/test/ui/pattern/issue-80186-mut-binding-help-suggestion.stderr @@ -0,0 +1,10 @@ +error: `mut` must be attached to each individual binding + --> $DIR/issue-80186-mut-binding-help-suggestion.rs:5:9 + | +LL | let mut &x = &0; + | ^^^^^^ help: add `mut` to each binding: `&(mut x)` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` + +error: aborting due to previous error + diff --git a/src/test/ui/pattern/issue-8351-1.rs b/src/test/ui/pattern/issue-8351-1.rs new file mode 100644 index 000000000..139f027cb --- /dev/null +++ b/src/test/ui/pattern/issue-8351-1.rs @@ -0,0 +1,16 @@ +// run-pass +#![allow(dead_code)] + +enum E { + Foo{f: isize}, + Bar, +} + +pub fn main() { + let e = E::Foo{f: 0}; + match e { + E::Foo{f: 1} => panic!(), + E::Foo{..} => (), + _ => panic!(), + } +} diff --git a/src/test/ui/pattern/issue-8351-2.rs b/src/test/ui/pattern/issue-8351-2.rs new file mode 100644 index 000000000..bc66cbb77 --- /dev/null +++ b/src/test/ui/pattern/issue-8351-2.rs @@ -0,0 +1,16 @@ +// run-pass +#![allow(dead_code)] + +enum E { + Foo{f: isize, b: bool}, + Bar, +} + +pub fn main() { + let e = E::Foo{f: 0, b: false}; + match e { + E::Foo{f: 1, b: true} => panic!(), + E::Foo{b: false, f: 0} => (), + _ => panic!(), + } +} diff --git a/src/test/ui/pattern/issue-88074-pat-range-type-inference-err.rs b/src/test/ui/pattern/issue-88074-pat-range-type-inference-err.rs new file mode 100644 index 000000000..16df272df --- /dev/null +++ b/src/test/ui/pattern/issue-88074-pat-range-type-inference-err.rs @@ -0,0 +1,28 @@ +trait Zero { + const ZERO: Self; +} + +impl Zero for String { + const ZERO: Self = String::new(); +} + +fn foo() { + match String::new() { + Zero::ZERO ..= Zero::ZERO => {}, + //~^ ERROR only `char` and numeric types are allowed in range patterns + _ => {}, + } +} + +fn bar() { + match Zero::ZERO { + Zero::ZERO ..= Zero::ZERO => {}, + //~^ ERROR type annotations needed [E0282] + _ => {}, + } +} + +fn main() { + foo(); + bar(); +} diff --git a/src/test/ui/pattern/issue-88074-pat-range-type-inference-err.stderr b/src/test/ui/pattern/issue-88074-pat-range-type-inference-err.stderr new file mode 100644 index 000000000..8e528f8c1 --- /dev/null +++ b/src/test/ui/pattern/issue-88074-pat-range-type-inference-err.stderr @@ -0,0 +1,19 @@ +error[E0029]: only `char` and numeric types are allowed in range patterns + --> $DIR/issue-88074-pat-range-type-inference-err.rs:11:9 + | +LL | Zero::ZERO ..= Zero::ZERO => {}, + | ----------^^^^^---------- + | | | + | | this is of type `String` but it should be `char` or numeric + | this is of type `String` but it should be `char` or numeric + +error[E0282]: type annotations needed + --> $DIR/issue-88074-pat-range-type-inference-err.rs:19:9 + | +LL | Zero::ZERO ..= Zero::ZERO => {}, + | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0029, E0282. +For more information about an error, try `rustc --explain E0029`. diff --git a/src/test/ui/pattern/issue-88074-pat-range-type-inference.rs b/src/test/ui/pattern/issue-88074-pat-range-type-inference.rs new file mode 100644 index 000000000..27db7d8c7 --- /dev/null +++ b/src/test/ui/pattern/issue-88074-pat-range-type-inference.rs @@ -0,0 +1,16 @@ +// check-pass + +trait Zero { + const ZERO: Self; +} + +impl Zero for i32 { + const ZERO: Self = 0; +} + +fn main() { + match 1 { + Zero::ZERO ..= 1 => {}, + _ => {}, + } +} diff --git a/src/test/ui/pattern/issue-92074-macro-ice.rs b/src/test/ui/pattern/issue-92074-macro-ice.rs new file mode 100644 index 000000000..039d3b314 --- /dev/null +++ b/src/test/ui/pattern/issue-92074-macro-ice.rs @@ -0,0 +1,36 @@ +pub enum En { + A(Vec<u8>) +} + +fn get_usize() -> usize { + 0 +} + +macro_rules! force_expr { + ($e:expr) => { $e } +} + +macro_rules! force_pat { + ($a:expr, $b:expr) => { $a..=$b } +} + +macro_rules! make_vec { + () => { force_expr!(Vec::new()) } //~ ERROR arbitrary expressions aren't allowed +} + +macro_rules! make_pat { + () => { force_pat!(get_usize(), get_usize()) } + //~^ ERROR arbitrary expressions aren't allowed + //~| ERROR arbitrary expressions aren't allowed +} + +#[allow(unreachable_code)] +fn f() -> Result<(), impl core::fmt::Debug> { + let x: En = loop {}; + + assert!(matches!(x, En::A(make_vec!()))); + assert!(matches!(5, make_pat!())); + Ok::<(), &'static str>(()) +} + +fn main() {} diff --git a/src/test/ui/pattern/issue-92074-macro-ice.stderr b/src/test/ui/pattern/issue-92074-macro-ice.stderr new file mode 100644 index 000000000..b340afff0 --- /dev/null +++ b/src/test/ui/pattern/issue-92074-macro-ice.stderr @@ -0,0 +1,35 @@ +error: arbitrary expressions aren't allowed in patterns + --> $DIR/issue-92074-macro-ice.rs:18:25 + | +LL | () => { force_expr!(Vec::new()) } + | ^^^^^^^^^^ +... +LL | assert!(matches!(x, En::A(make_vec!()))); + | ----------- in this macro invocation + | + = note: this error originates in the macro `make_vec` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: arbitrary expressions aren't allowed in patterns + --> $DIR/issue-92074-macro-ice.rs:22:24 + | +LL | () => { force_pat!(get_usize(), get_usize()) } + | ^^^^^^^^^^^ +... +LL | assert!(matches!(5, make_pat!())); + | ----------- in this macro invocation + | + = note: this error originates in the macro `make_pat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: arbitrary expressions aren't allowed in patterns + --> $DIR/issue-92074-macro-ice.rs:22:37 + | +LL | () => { force_pat!(get_usize(), get_usize()) } + | ^^^^^^^^^^^ +... +LL | assert!(matches!(5, make_pat!())); + | ----------- in this macro invocation + | + = note: this error originates in the macro `make_pat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/pattern/issue-95878.rs b/src/test/ui/pattern/issue-95878.rs new file mode 100644 index 000000000..f59814468 --- /dev/null +++ b/src/test/ui/pattern/issue-95878.rs @@ -0,0 +1,12 @@ +struct Foo<'a>(&'a ()); + +impl<'a> Foo<'a> { + fn spam(&mut self, baz: &mut Vec<u32>) { + match 15 { + ref Self => (), + //~^ ERROR expected identifier, found keyword `Self` + } + } +} + +fn main() {} diff --git a/src/test/ui/pattern/issue-95878.stderr b/src/test/ui/pattern/issue-95878.stderr new file mode 100644 index 000000000..e0eea06e0 --- /dev/null +++ b/src/test/ui/pattern/issue-95878.stderr @@ -0,0 +1,8 @@ +error: expected identifier, found keyword `Self` + --> $DIR/issue-95878.rs:6:17 + | +LL | ref Self => (), + | ^^^^ expected identifier, found keyword + +error: aborting due to previous error + diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs new file mode 100644 index 000000000..5445696fd --- /dev/null +++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs @@ -0,0 +1,29 @@ +// check-pass + +fn main() {} + +struct U; + +fn slice() { + let mut arr = [U, U, U, U, U, U, U, U]; + let [ref _x0, _x1, _, mut _x3, .., ref _x6, _x7] = arr; + _x3 = U; + let [ref mut _x0, _, ref _x2, _, _x4, ref mut _x5, _x6, _] = arr; + *_x5 = U; + let [_, _, _x2, _, _, _x5, _, _] = arr; + *_x0 = U; + let [ref _x0, ..] = arr; + let [_x0, ..] = arr; +} + +fn tuple() { + let mut tup = (U, U, U, U, U); + let (ref _x0, mut _x1, ref _x2, ..) = tup; + _x1 = U; + let (ref mut _x0, _, _, ref _x3, _x4) = tup; + let (_, _, _, _x3, _) = tup; + *_x0 = U; + drop(_x2); + drop(tup.2); + let (_x0, _, _, ..) = tup; +} diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs new file mode 100644 index 000000000..a6144c949 --- /dev/null +++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs @@ -0,0 +1,48 @@ +fn main() {} + +struct U; + +fn slice() { + let mut arr = [U, U, U, U, U]; + let hold_all = &arr; + let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; //~ ERROR cannot move out of `arr[..]` + _x1 = U; //~ ERROR cannot assign twice to immutable variable `_x1` + drop(hold_all); + let [_x0, ..] = arr; //~ ERROR cannot move out of `arr[..]` + drop(_x0_hold); + let [_, _, ref mut _x2, _x3, mut _x4] = arr; + //~^ ERROR cannot borrow `arr[..]` as mutable + //~| ERROR cannot move out of `arr[..]` because it is borrowed + //~| ERROR cannot move out of `arr[..]` because it is borrowed + drop(xs_hold); +} + +fn tuple() { + let mut tup = (U, U, U, U); + let (ref _x0, _x1, ref _x2, ..) = tup; + _x1 = U; //~ ERROR cannot assign twice to immutable variable + let _x0_hold = &mut tup.0; //~ ERROR cannot borrow `tup.0` as mutable because it is also + let (ref mut _x0_hold, ..) = tup; //~ ERROR cannot borrow `tup.0` as mutable because it is also + *_x0 = U; //~ ERROR cannot assign to `*_x0`, which is behind a `&` reference + *_x2 = U; //~ ERROR cannot assign to `*_x2`, which is behind a `&` reference + drop(tup.1); //~ ERROR use of moved value: `tup.1` + let _x1_hold = &tup.1; //~ ERROR borrow of moved value: `tup.1` + let (.., ref mut _x3) = tup; + let _x3_hold = &tup.3; //~ ERROR cannot borrow `tup.3` as immutable + let _x3_hold = &mut tup.3; //~ ERROR cannot borrow `tup.3` as mutable more + let (.., ref mut _x4_hold) = tup; //~ ERROR cannot borrow `tup.3` as mutable more + let (.., ref _x4_hold) = tup; //~ ERROR cannot borrow `tup.3` as immutable + drop(_x3); +} + +fn closure() { + let mut tup = (U, U, U); + let c1 = || { + let (ref _x0, _x1, _) = tup; + }; + let c2 = || { + //~^ ERROR use of moved value + let (ref mut _x0, _, _x2) = tup; + }; + drop(c1); +} diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr new file mode 100644 index 000000000..5beca04d2 --- /dev/null +++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr @@ -0,0 +1,208 @@ +error[E0505]: cannot move out of `arr[..]` because it is borrowed + --> $DIR/borrowck-move-ref-pattern.rs:8:24 + | +LL | let hold_all = &arr; + | ---- borrow of `arr` occurs here +LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; + | ^^^ move out of `arr[..]` occurs here +LL | _x1 = U; +LL | drop(hold_all); + | -------- borrow later used here + +error[E0384]: cannot assign twice to immutable variable `_x1` + --> $DIR/borrowck-move-ref-pattern.rs:9:5 + | +LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; + | --- + | | + | first assignment to `_x1` + | help: consider making this binding mutable: `mut _x1` +LL | _x1 = U; + | ^^^^^^^ cannot assign twice to immutable variable + +error[E0505]: cannot move out of `arr[..]` because it is borrowed + --> $DIR/borrowck-move-ref-pattern.rs:11:10 + | +LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; + | ------------ borrow of `arr[..]` occurs here +... +LL | let [_x0, ..] = arr; + | ^^^ move out of `arr[..]` occurs here +LL | drop(_x0_hold); + | -------- borrow later used here + +error[E0502]: cannot borrow `arr[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-move-ref-pattern.rs:13:16 + | +LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; + | ---------------- immutable borrow occurs here +... +LL | let [_, _, ref mut _x2, _x3, mut _x4] = arr; + | ^^^^^^^^^^^ mutable borrow occurs here +... +LL | drop(xs_hold); + | ------- immutable borrow later used here + +error[E0505]: cannot move out of `arr[..]` because it is borrowed + --> $DIR/borrowck-move-ref-pattern.rs:13:29 + | +LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; + | ---------------- borrow of `arr[..]` occurs here +... +LL | let [_, _, ref mut _x2, _x3, mut _x4] = arr; + | ^^^ move out of `arr[..]` occurs here +... +LL | drop(xs_hold); + | ------- borrow later used here + +error[E0505]: cannot move out of `arr[..]` because it is borrowed + --> $DIR/borrowck-move-ref-pattern.rs:13:34 + | +LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; + | ---------------- borrow of `arr[..]` occurs here +... +LL | let [_, _, ref mut _x2, _x3, mut _x4] = arr; + | ^^^^^^^ move out of `arr[..]` occurs here +... +LL | drop(xs_hold); + | ------- borrow later used here + +error[E0384]: cannot assign twice to immutable variable `_x1` + --> $DIR/borrowck-move-ref-pattern.rs:23:5 + | +LL | let (ref _x0, _x1, ref _x2, ..) = tup; + | --- + | | + | first assignment to `_x1` + | help: consider making this binding mutable: `mut _x1` +LL | _x1 = U; + | ^^^^^^^ cannot assign twice to immutable variable + +error[E0502]: cannot borrow `tup.0` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-move-ref-pattern.rs:24:20 + | +LL | let (ref _x0, _x1, ref _x2, ..) = tup; + | ------- immutable borrow occurs here +LL | _x1 = U; +LL | let _x0_hold = &mut tup.0; + | ^^^^^^^^^^ mutable borrow occurs here +LL | let (ref mut _x0_hold, ..) = tup; +LL | *_x0 = U; + | -------- immutable borrow later used here + +error[E0502]: cannot borrow `tup.0` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-move-ref-pattern.rs:25:10 + | +LL | let (ref _x0, _x1, ref _x2, ..) = tup; + | ------- immutable borrow occurs here +... +LL | let (ref mut _x0_hold, ..) = tup; + | ^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | *_x0 = U; + | -------- immutable borrow later used here + +error[E0594]: cannot assign to `*_x0`, which is behind a `&` reference + --> $DIR/borrowck-move-ref-pattern.rs:26:5 + | +LL | let (ref _x0, _x1, ref _x2, ..) = tup; + | ------- help: consider changing this to be a mutable reference: `ref mut _x0` +... +LL | *_x0 = U; + | ^^^^^^^^ `_x0` is a `&` reference, so the data it refers to cannot be written + +error[E0594]: cannot assign to `*_x2`, which is behind a `&` reference + --> $DIR/borrowck-move-ref-pattern.rs:27:5 + | +LL | let (ref _x0, _x1, ref _x2, ..) = tup; + | ------- help: consider changing this to be a mutable reference: `ref mut _x2` +... +LL | *_x2 = U; + | ^^^^^^^^ `_x2` is a `&` reference, so the data it refers to cannot be written + +error[E0382]: use of moved value: `tup.1` + --> $DIR/borrowck-move-ref-pattern.rs:28:10 + | +LL | let (ref _x0, _x1, ref _x2, ..) = tup; + | --- value moved here +... +LL | drop(tup.1); + | ^^^^^ value used here after move + | + = note: move occurs because `tup.1` has type `U`, which does not implement the `Copy` trait + +error[E0382]: borrow of moved value: `tup.1` + --> $DIR/borrowck-move-ref-pattern.rs:29:20 + | +LL | drop(tup.1); + | ----- value moved here +LL | let _x1_hold = &tup.1; + | ^^^^^^ value borrowed here after move + | + = note: move occurs because `tup.1` has type `U`, which does not implement the `Copy` trait + +error[E0502]: cannot borrow `tup.3` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-move-ref-pattern.rs:31:20 + | +LL | let (.., ref mut _x3) = tup; + | ----------- mutable borrow occurs here +LL | let _x3_hold = &tup.3; + | ^^^^^^ immutable borrow occurs here +... +LL | drop(_x3); + | --- mutable borrow later used here + +error[E0499]: cannot borrow `tup.3` as mutable more than once at a time + --> $DIR/borrowck-move-ref-pattern.rs:32:20 + | +LL | let (.., ref mut _x3) = tup; + | ----------- first mutable borrow occurs here +LL | let _x3_hold = &tup.3; +LL | let _x3_hold = &mut tup.3; + | ^^^^^^^^^^ second mutable borrow occurs here +... +LL | drop(_x3); + | --- first borrow later used here + +error[E0499]: cannot borrow `tup.3` as mutable more than once at a time + --> $DIR/borrowck-move-ref-pattern.rs:33:14 + | +LL | let (.., ref mut _x3) = tup; + | ----------- first mutable borrow occurs here +... +LL | let (.., ref mut _x4_hold) = tup; + | ^^^^^^^^^^^^^^^^ second mutable borrow occurs here +LL | let (.., ref _x4_hold) = tup; +LL | drop(_x3); + | --- first borrow later used here + +error[E0502]: cannot borrow `tup.3` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-move-ref-pattern.rs:34:14 + | +LL | let (.., ref mut _x3) = tup; + | ----------- mutable borrow occurs here +... +LL | let (.., ref _x4_hold) = tup; + | ^^^^^^^^^^^^ immutable borrow occurs here +LL | drop(_x3); + | --- mutable borrow later used here + +error[E0382]: use of moved value: `tup` + --> $DIR/borrowck-move-ref-pattern.rs:43:14 + | +LL | let mut tup = (U, U, U); + | ------- move occurs because `tup` has type `(U, U, U)`, which does not implement the `Copy` trait +LL | let c1 = || { + | -- value moved into closure here +LL | let (ref _x0, _x1, _) = tup; + | --- variable moved due to use in closure +LL | }; +LL | let c2 = || { + | ^^ value used here after move +LL | +LL | let (ref mut _x0, _, _x2) = tup; + | --- use occurs due to use in closure + +error: aborting due to 18 previous errors + +Some errors have detailed explanations: E0382, E0384, E0499, E0502, E0505, E0594. +For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs b/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs new file mode 100644 index 000000000..ff7b625a6 --- /dev/null +++ b/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs @@ -0,0 +1,12 @@ +// When conflicts between by-move bindings in `by_move_1 @ has_by_move` patterns +// happen and that code is unreachable according to borrowck, we accept this code. +// In particular, we want to ensure here that an ICE does not happen, which it did originally. + +// check-pass + +fn main() { + return; + + struct S; + let a @ (b, c) = (S, S); +} diff --git a/src/test/ui/pattern/move-ref-patterns/issue-53840.rs b/src/test/ui/pattern/move-ref-patterns/issue-53840.rs new file mode 100644 index 000000000..80effc497 --- /dev/null +++ b/src/test/ui/pattern/move-ref-patterns/issue-53840.rs @@ -0,0 +1,20 @@ +// check-pass + +enum E { + Foo(String, String, String), +} + +struct Bar { + a: String, + b: String, +} + +fn main() { + let bar = Bar { a: "1".to_string(), b: "2".to_string() }; + match E::Foo("".into(), "".into(), "".into()) { + E::Foo(a, b, ref c) => {} + } + match bar { + Bar { a, ref b } => {} + } +} diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs new file mode 100644 index 000000000..ebb1683af --- /dev/null +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs @@ -0,0 +1,120 @@ +fn main() { + struct S; // Not `Copy`. + + let mut tup0 = (S, S); + let mut tup1 = (S, S, S); + let tup2 = (S, S); + let tup3 = (S, S, S); + let tup4 = (S, S); + let mut arr0 = [S, S, S]; + let mut arr1 = [S, S, S, S, S]; + let arr2 = [S, S, S]; + let arr3 = [S, S, S, S, S]; + + // The `mov` bindings require that we capture the scrutinees by-move. + let mut closure = || { + // Tuples... + let (ref mut borrow, mov) = tup0; + let (mov, _, ref mut borrow) = tup1; + let (ref borrow, mov) = tup2; + let (mov, _, ref borrow) = tup3; + let (ref borrow, mov) = tup4; + // Arrays... + let [mov @ .., ref borrow] = arr0; + let [_, ref mut borrow @ .., _, mov] = arr1; + let [mov @ .., ref borrow] = arr2; + let [_, ref borrow @ .., _, mov] = arr3; + }; + + // Now we try to borrow and move the captures, which should result in errors... + // ...for tuples: + drop(&tup0); //~ ERROR borrow of moved value: `tup0` + drop(&tup1); //~ ERROR borrow of moved value: `tup1` + drop(&tup2); //~ ERROR borrow of moved value: `tup2` + drop(&tup3); //~ ERROR borrow of moved value: `tup3` + // Ostensibly this should compile. + // However, because closures don't capture individual fields, which is changed in RFC 2229, + // this won't compile because the entire product is moved into the closure. + // The same applies to the array patterns below. + drop(&tup4.0); //~ ERROR borrow of moved value: `tup4` + // ...for arrays: + drop(&arr0); //~ ERROR borrow of moved value: `arr0` + let [_, mov1, mov2, mov3, _] = &arr1; //~ ERROR borrow of moved value: `arr1` + drop(&arr2); //~ ERROR borrow of moved value: `arr2` + let [_, mov1, mov2, mov3, _] = &arr3; //~ ERROR borrow of moved value: `arr3` + + // Let's redo ^--- with a `match` + sum type: + macro_rules! m { + ($p:pat = $s:expr) => { + match $s { + Some($p) => {} + _ => {} + } + }; + } + let mut tup0: Option<(S, S)> = None; + let mut tup1: Option<(S, S, S)> = None; + let tup2: Option<(S, S)> = None; + let tup3: Option<(S, S, S)> = None; + let tup4: Option<(S, S)> = None; + let mut arr0: Option<[S; 3]> = None; + let mut arr1: Option<[S; 5]> = None; + let arr2: Option<[S; 3]> = None; + let arr3: Option<[S; 5]> = None; + let mut closure = || { + m!((ref mut borrow, mov) = tup0); + m!((mov, _, ref mut borrow) = tup1); + m!((ref borrow, mov) = tup2); + m!((mov, _, ref borrow) = tup3); + m!((ref borrow, mov) = tup4); + m!([mov @ .., ref borrow] = arr0); + m!([_, ref mut borrow @ .., _, mov] = arr1); + m!([mov @ .., ref borrow] = arr2); + m!([_, ref borrow @ .., _, mov] = arr3); + }; + drop(&tup0); //~ ERROR borrow of moved value: `tup0` + drop(&tup1); //~ ERROR borrow of moved value: `tup1` + drop(&tup2); //~ ERROR borrow of moved value: `tup2` + drop(&tup3); //~ ERROR borrow of moved value: `tup3` + m!((ref x, _) = &tup4); //~ ERROR borrow of moved value: `tup4` + drop(&arr0); //~ ERROR borrow of moved value: `arr0` + m!([_, mov1, mov2, mov3, _] = &arr1); //~ ERROR borrow of moved value: `arr1` + drop(&arr2); //~ ERROR borrow of moved value: `arr2` + m!([_, mov1, mov2, mov3, _] = &arr3); //~ ERROR borrow of moved value: `arr3` + + // Let's redo ^--- with `if let` (which may diverge from `match` in the future): + macro_rules! m { + ($p:pat = $s:expr) => { + if let Some($p) = $s {} + }; + } + let mut tup0: Option<(S, S)> = None; + let mut tup1: Option<(S, S, S)> = None; + let tup2: Option<(S, S)> = None; + let tup3: Option<(S, S, S)> = None; + let tup4: Option<(S, S)> = None; + let mut arr0: Option<[S; 3]> = None; + let mut arr1: Option<[S; 5]> = None; + let arr2: Option<[S; 3]> = None; + let arr3: Option<[S; 5]> = None; + let mut closure = || { + m!((ref mut borrow, mov) = tup0); + m!((mov, _, ref mut borrow) = tup1); + m!((ref borrow, mov) = tup2); + m!((mov, _, ref borrow) = tup3); + m!((ref borrow, mov) = tup4); + m!([mov @ .., ref borrow] = arr0); + m!([_, ref mut borrow @ .., _, mov] = arr1); + m!([mov @ .., ref borrow] = arr2); + m!([_, ref borrow @ .., _, mov] = arr3); + }; + drop(&tup0); //~ ERROR borrow of moved value: `tup0` + drop(&tup1); //~ ERROR borrow of moved value: `tup1` + drop(&tup2); //~ ERROR borrow of moved value: `tup2` + drop(&tup3); //~ ERROR borrow of moved value: `tup3` + m!((ref x, _) = &tup4); //~ ERROR borrow of moved value: `tup4` + drop(&arr0); //~ ERROR borrow of moved value: `arr0` + m!([_, mov1, mov2, mov3, _] = &arr1); //~ ERROR borrow of moved value: `arr1` + drop(&arr2); //~ ERROR borrow of moved value: `arr2` + m!([_, mov1, mov2, mov3, _] = &arr3); //~ ERROR borrow of moved value: `arr3` +} diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr new file mode 100644 index 000000000..f19fed089 --- /dev/null +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr @@ -0,0 +1,404 @@ +error[E0382]: borrow of moved value: `tup0` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:31:10 + | +LL | let mut tup0 = (S, S); + | -------- move occurs because `tup0` has type `(S, S)`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +LL | // Tuples... +LL | let (ref mut borrow, mov) = tup0; + | ---- variable moved due to use in closure +... +LL | drop(&tup0); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup1` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:32:10 + | +LL | let mut tup1 = (S, S, S); + | -------- move occurs because `tup1` has type `(S, S, S)`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | let (mov, _, ref mut borrow) = tup1; + | ---- variable moved due to use in closure +... +LL | drop(&tup1); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup2` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:33:10 + | +LL | let tup2 = (S, S); + | ---- move occurs because `tup2` has type `(S, S)`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | let (ref borrow, mov) = tup2; + | ---- variable moved due to use in closure +... +LL | drop(&tup2); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup3` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:34:10 + | +LL | let tup3 = (S, S, S); + | ---- move occurs because `tup3` has type `(S, S, S)`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | let (mov, _, ref borrow) = tup3; + | ---- variable moved due to use in closure +... +LL | drop(&tup3); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup4` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:39:10 + | +LL | let tup4 = (S, S); + | ---- move occurs because `tup4` has type `(S, S)`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | let (ref borrow, mov) = tup4; + | ---- variable moved due to use in closure +... +LL | drop(&tup4.0); + | ^^^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `arr0` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:41:10 + | +LL | let mut arr0 = [S, S, S]; + | -------- move occurs because `arr0` has type `[S; 3]`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | let [mov @ .., ref borrow] = arr0; + | ---- variable moved due to use in closure +... +LL | drop(&arr0); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `arr1` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:42:36 + | +LL | let mut arr1 = [S, S, S, S, S]; + | -------- move occurs because `arr1` has type `[S; 5]`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | let [_, ref mut borrow @ .., _, mov] = arr1; + | ---- variable moved due to use in closure +... +LL | let [_, mov1, mov2, mov3, _] = &arr1; + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `arr2` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:43:10 + | +LL | let arr2 = [S, S, S]; + | ---- move occurs because `arr2` has type `[S; 3]`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | let [mov @ .., ref borrow] = arr2; + | ---- variable moved due to use in closure +... +LL | drop(&arr2); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `arr3` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:44:36 + | +LL | let arr3 = [S, S, S, S, S]; + | ---- move occurs because `arr3` has type `[S; 5]`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | let [_, ref borrow @ .., _, mov] = arr3; + | ---- variable moved due to use in closure +... +LL | let [_, mov1, mov2, mov3, _] = &arr3; + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup0` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:75:10 + | +LL | let mut tup0: Option<(S, S)> = None; + | -------- move occurs because `tup0` has type `Option<(S, S)>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +LL | m!((ref mut borrow, mov) = tup0); + | ---- variable moved due to use in closure +... +LL | drop(&tup0); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup1` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:76:10 + | +LL | let mut tup1: Option<(S, S, S)> = None; + | -------- move occurs because `tup1` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +LL | m!((ref mut borrow, mov) = tup0); +LL | m!((mov, _, ref mut borrow) = tup1); + | ---- variable moved due to use in closure +... +LL | drop(&tup1); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup2` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:77:10 + | +LL | let tup2: Option<(S, S)> = None; + | ---- move occurs because `tup2` has type `Option<(S, S)>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!((ref borrow, mov) = tup2); + | ---- variable moved due to use in closure +... +LL | drop(&tup2); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup3` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:78:10 + | +LL | let tup3: Option<(S, S, S)> = None; + | ---- move occurs because `tup3` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!((mov, _, ref borrow) = tup3); + | ---- variable moved due to use in closure +... +LL | drop(&tup3); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup4` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:79:21 + | +LL | let tup4: Option<(S, S)> = None; + | ---- move occurs because `tup4` has type `Option<(S, S)>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!((ref borrow, mov) = tup4); + | ---- variable moved due to use in closure +... +LL | m!((ref x, _) = &tup4); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `arr0` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:80:10 + | +LL | let mut arr0: Option<[S; 3]> = None; + | -------- move occurs because `arr0` has type `Option<[S; 3]>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!([mov @ .., ref borrow] = arr0); + | ---- variable moved due to use in closure +... +LL | drop(&arr0); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `arr1` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:81:35 + | +LL | let mut arr1: Option<[S; 5]> = None; + | -------- move occurs because `arr1` has type `Option<[S; 5]>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!([_, ref mut borrow @ .., _, mov] = arr1); + | ---- variable moved due to use in closure +... +LL | m!([_, mov1, mov2, mov3, _] = &arr1); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `arr2` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:82:10 + | +LL | let arr2: Option<[S; 3]> = None; + | ---- move occurs because `arr2` has type `Option<[S; 3]>`, which does not implement the `Copy` trait +LL | let arr3: Option<[S; 5]> = None; +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!([mov @ .., ref borrow] = arr2); + | ---- variable moved due to use in closure +... +LL | drop(&arr2); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `arr3` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:83:35 + | +LL | let arr3: Option<[S; 5]> = None; + | ---- move occurs because `arr3` has type `Option<[S; 5]>`, which does not implement the `Copy` trait +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!([_, ref borrow @ .., _, mov] = arr3); + | ---- variable moved due to use in closure +... +LL | m!([_, mov1, mov2, mov3, _] = &arr3); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup0` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:111:10 + | +LL | let mut tup0: Option<(S, S)> = None; + | -------- move occurs because `tup0` has type `Option<(S, S)>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +LL | m!((ref mut borrow, mov) = tup0); + | ---- variable moved due to use in closure +... +LL | drop(&tup0); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup1` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:112:10 + | +LL | let mut tup1: Option<(S, S, S)> = None; + | -------- move occurs because `tup1` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +LL | m!((ref mut borrow, mov) = tup0); +LL | m!((mov, _, ref mut borrow) = tup1); + | ---- variable moved due to use in closure +... +LL | drop(&tup1); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup2` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:113:10 + | +LL | let tup2: Option<(S, S)> = None; + | ---- move occurs because `tup2` has type `Option<(S, S)>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!((ref borrow, mov) = tup2); + | ---- variable moved due to use in closure +... +LL | drop(&tup2); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup3` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:114:10 + | +LL | let tup3: Option<(S, S, S)> = None; + | ---- move occurs because `tup3` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!((mov, _, ref borrow) = tup3); + | ---- variable moved due to use in closure +... +LL | drop(&tup3); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup4` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:115:21 + | +LL | let tup4: Option<(S, S)> = None; + | ---- move occurs because `tup4` has type `Option<(S, S)>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!((ref borrow, mov) = tup4); + | ---- variable moved due to use in closure +... +LL | m!((ref x, _) = &tup4); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `arr0` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:116:10 + | +LL | let mut arr0: Option<[S; 3]> = None; + | -------- move occurs because `arr0` has type `Option<[S; 3]>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!([mov @ .., ref borrow] = arr0); + | ---- variable moved due to use in closure +... +LL | drop(&arr0); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `arr1` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:117:35 + | +LL | let mut arr1: Option<[S; 5]> = None; + | -------- move occurs because `arr1` has type `Option<[S; 5]>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!([_, ref mut borrow @ .., _, mov] = arr1); + | ---- variable moved due to use in closure +... +LL | m!([_, mov1, mov2, mov3, _] = &arr1); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `arr2` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:118:10 + | +LL | let arr2: Option<[S; 3]> = None; + | ---- move occurs because `arr2` has type `Option<[S; 3]>`, which does not implement the `Copy` trait +LL | let arr3: Option<[S; 5]> = None; +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!([mov @ .., ref borrow] = arr2); + | ---- variable moved due to use in closure +... +LL | drop(&arr2); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `arr3` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:119:35 + | +LL | let arr3: Option<[S; 5]> = None; + | ---- move occurs because `arr3` has type `Option<[S; 5]>`, which does not implement the `Copy` trait +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!([_, ref borrow @ .., _, mov] = arr3); + | ---- variable moved due to use in closure +... +LL | m!([_, mov1, mov2, mov3, _] = &arr3); + | ^^^^^ value borrowed here after move + +error: aborting due to 27 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs new file mode 100644 index 000000000..583f70f41 --- /dev/null +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs @@ -0,0 +1,28 @@ +// check-pass + +fn main() { + struct U; + fn accept_fn_once(_: impl FnOnce()) {} + fn accept_fn_mut(_: impl FnMut()) {} + fn accept_fn(_: impl Fn()) {} + + let mut tup = (U, U, U); + let (ref _x0, _x1, ref mut _x2) = tup; + let c1 = || { + drop::<&U>(_x0); + drop::<U>(_x1); + drop::<&mut U>(_x2); + }; + accept_fn_once(c1); + + let c2 = || { + drop::<&U>(_x0); + drop::<&mut U>(_x2); + }; + accept_fn_mut(c2); + + let c3 = || { + drop::<&U>(_x0); + }; + accept_fn(c3); +} diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs new file mode 100644 index 000000000..cd619cc41 --- /dev/null +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs @@ -0,0 +1,32 @@ +fn main() { + struct U; + fn accept_fn_once(_: &impl FnOnce()) {} + fn accept_fn_mut(_: &impl FnMut()) {} + fn accept_fn(_: &impl Fn()) {} + + let mut tup = (U, U, U); + let (ref _x0, _x1, ref mut _x2) = tup; + let c1 = || { + //~^ ERROR expected a closure that implements the `FnMut` + //~| ERROR expected a closure that implements the `Fn` + drop::<&U>(_x0); + drop::<U>(_x1); + drop::<&mut U>(_x2); + }; + accept_fn_once(&c1); + accept_fn_mut(&c1); + accept_fn(&c1); + + let c2 = || { + //~^ ERROR expected a closure that implements the `Fn` + drop::<&U>(_x0); + drop::<&mut U>(_x2); + }; + accept_fn_mut(&c2); + accept_fn(&c2); + + let c3 = || { + drop::<&U>(_x0); + }; + accept_fn(&c3); +} diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr new file mode 100644 index 000000000..d96e86393 --- /dev/null +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr @@ -0,0 +1,39 @@ +error[E0525]: expected a closure that implements the `FnMut` trait, but this closure only implements `FnOnce` + --> $DIR/move-ref-patterns-closure-captures.rs:9:14 + | +LL | let c1 = || { + | ^^ this closure implements `FnOnce`, not `FnMut` +... +LL | drop::<U>(_x1); + | --- closure is `FnOnce` because it moves the variable `_x1` out of its environment +... +LL | accept_fn_mut(&c1); + | ------------- the requirement to implement `FnMut` derives from here + +error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce` + --> $DIR/move-ref-patterns-closure-captures.rs:9:14 + | +LL | let c1 = || { + | ^^ this closure implements `FnOnce`, not `Fn` +... +LL | drop::<U>(_x1); + | --- closure is `FnOnce` because it moves the variable `_x1` out of its environment +... +LL | accept_fn(&c1); + | --------- the requirement to implement `Fn` derives from here + +error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut` + --> $DIR/move-ref-patterns-closure-captures.rs:20:14 + | +LL | let c2 = || { + | ^^ this closure implements `FnMut`, not `Fn` +... +LL | drop::<&mut U>(_x2); + | --- closure is `FnMut` because it mutates the variable `_x2` here +... +LL | accept_fn(&c2); + | --------- the requirement to implement `Fn` derives from here + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0525`. diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs new file mode 100644 index 000000000..1dd66aad5 --- /dev/null +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs @@ -0,0 +1,14 @@ +fn main() { + struct U; + + // A tuple is a "non-reference pattern". + // A `mut` binding pattern resets the binding mode to by-value. + + let p = (U, U); + let (a, mut b) = &p; + //~^ ERROR cannot move out of a shared reference + + let mut p = (U, U); + let (a, mut b) = &mut p; + //~^ ERROR cannot move out of a mutable reference +} diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr new file mode 100644 index 000000000..6952c743a --- /dev/null +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr @@ -0,0 +1,21 @@ +error[E0507]: cannot move out of a shared reference + --> $DIR/move-ref-patterns-default-binding-modes.rs:8:22 + | +LL | let (a, mut b) = &p; + | ----- ^^ + | | + | data moved here + | move occurs because `b` has type `U`, which does not implement the `Copy` trait + +error[E0507]: cannot move out of a mutable reference + --> $DIR/move-ref-patterns-default-binding-modes.rs:12:22 + | +LL | let (a, mut b) = &mut p; + | ----- ^^^^^^ + | | + | data moved here + | move occurs because `b` has type `U`, which does not implement the `Copy` trait + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs new file mode 100644 index 000000000..1d6d9acea --- /dev/null +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs @@ -0,0 +1,79 @@ +// run-pass + +// This test checks the dynamic semantics and drop order of pattern matching +// where a product pattern has both a by-move and by-ref binding. + +use std::cell::RefCell; +use std::rc::Rc; + +struct X { + x: Box<usize>, + d: DropOrderListPtr, +} + +type DropOrderListPtr = Rc<RefCell<Vec<usize>>>; + +impl Drop for X { + fn drop(&mut self) { + self.d.borrow_mut().push(*self.x); + } +} + +enum DoubleOption<T, U> { + Some2(T, U), + _None2, +} + +fn main() { + let d: DropOrderListPtr = <_>::default(); + { + let mk = |v| X { x: Box::new(v), d: d.clone() }; + let check = |a1: &X, a2, b1: &X, b2| { + assert_eq!(*a1.x, a2); + assert_eq!(*b1.x, b2); + }; + + let x = DoubleOption::Some2(mk(1), mk(2)); + match x { + DoubleOption::Some2(ref a, b) => check(a, 1, &b, 2), + DoubleOption::_None2 => panic!(), + } + let x = DoubleOption::Some2(mk(3), mk(4)); + match x { + DoubleOption::Some2(a, ref b) => check(&a, 3, b, 4), + DoubleOption::_None2 => panic!(), + } + match DoubleOption::Some2(mk(5), mk(6)) { + DoubleOption::Some2(ref a, b) => check(a, 5, &b, 6), + DoubleOption::_None2 => panic!(), + } + match DoubleOption::Some2(mk(7), mk(8)) { + DoubleOption::Some2(a, ref b) => check(&a, 7, b, 8), + DoubleOption::_None2 => panic!(), + } + { + let (a, ref b) = (mk(9), mk(10)); + let (ref c, d) = (mk(11), mk(12)); + check(&a, 9, b, 10); + check(c, 11, &d, 12); + } + fn fun([a, ref mut b, ref xs @ .., ref c, d]: [X; 6]) { + assert_eq!(*a.x, 13); + assert_eq!(*b.x, 14); + assert_eq!(&[*xs[0].x, *xs[1].x], &[15, 16]); + assert_eq!(*c.x, 17); + assert_eq!(*d.x, 18); + } + fun([mk(13), mk(14), mk(15), mk(16), mk(17), mk(18)]); + + let lam = |(a, ref b, c, ref mut d): (X, X, X, X)| { + assert_eq!(*a.x, 19); + assert_eq!(*b.x, 20); + assert_eq!(*c.x, 21); + assert_eq!(*d.x, 22); + }; + lam((mk(19), mk(20), mk(21), mk(22))); + } + let expected = [2, 3, 6, 5, 7, 8, 12, 11, 9, 10, 18, 13, 14, 15, 16, 17, 21, 19, 20, 22, 4, 1]; + assert_eq!(&*d.borrow(), &expected); +} diff --git a/src/test/ui/pattern/non-constant-in-const-path.rs b/src/test/ui/pattern/non-constant-in-const-path.rs new file mode 100644 index 000000000..3918485ba --- /dev/null +++ b/src/test/ui/pattern/non-constant-in-const-path.rs @@ -0,0 +1,18 @@ +// Checks if we emit `PatternError`s correctly. +// This is also a regression test for #27895 and #68394. + +static FOO: u8 = 10; + +fn main() { + let x = 0; + let 0u8..=x = 0; + //~^ ERROR: runtime values cannot be referenced in patterns + let 0u8..=FOO = 0; + //~^ ERROR: statics cannot be referenced in patterns + match 1 { + 0 ..= x => {} + //~^ ERROR: runtime values cannot be referenced in patterns + 0 ..= FOO => {} + //~^ ERROR: statics cannot be referenced in patterns + }; +} diff --git a/src/test/ui/pattern/non-constant-in-const-path.stderr b/src/test/ui/pattern/non-constant-in-const-path.stderr new file mode 100644 index 000000000..53c3974f7 --- /dev/null +++ b/src/test/ui/pattern/non-constant-in-const-path.stderr @@ -0,0 +1,28 @@ +error[E0080]: runtime values cannot be referenced in patterns + --> $DIR/non-constant-in-const-path.rs:8:15 + | +LL | let 0u8..=x = 0; + | ^ + +error[E0158]: statics cannot be referenced in patterns + --> $DIR/non-constant-in-const-path.rs:10:15 + | +LL | let 0u8..=FOO = 0; + | ^^^ + +error[E0080]: runtime values cannot be referenced in patterns + --> $DIR/non-constant-in-const-path.rs:13:15 + | +LL | 0 ..= x => {} + | ^ + +error[E0158]: statics cannot be referenced in patterns + --> $DIR/non-constant-in-const-path.rs:15:15 + | +LL | 0 ..= FOO => {} + | ^^^ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0080, E0158. +For more information about an error, try `rustc --explain E0080`. diff --git a/src/test/ui/pattern/non-structural-match-types.rs b/src/test/ui/pattern/non-structural-match-types.rs new file mode 100644 index 000000000..5c3315473 --- /dev/null +++ b/src/test/ui/pattern/non-structural-match-types.rs @@ -0,0 +1,14 @@ +// edition:2021 +#![allow(incomplete_features)] +#![allow(unreachable_code)] +#![feature(const_async_blocks)] +#![feature(inline_const_pat)] + +fn main() { + match loop {} { + const { || {} } => {}, //~ ERROR cannot be used in patterns + } + match loop {} { + const { async {} } => {}, //~ ERROR cannot be used in patterns + } +} diff --git a/src/test/ui/pattern/non-structural-match-types.stderr b/src/test/ui/pattern/non-structural-match-types.stderr new file mode 100644 index 000000000..45e162649 --- /dev/null +++ b/src/test/ui/pattern/non-structural-match-types.stderr @@ -0,0 +1,14 @@ +error: `[closure@$DIR/non-structural-match-types.rs:9:17: 9:19]` cannot be used in patterns + --> $DIR/non-structural-match-types.rs:9:9 + | +LL | const { || {} } => {}, + | ^^^^^^^^^^^^^^^ + +error: `impl Future<Output = ()>` cannot be used in patterns + --> $DIR/non-structural-match-types.rs:12:9 + | +LL | const { async {} } => {}, + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/pattern/pat-shadow-in-nested-binding.rs b/src/test/ui/pattern/pat-shadow-in-nested-binding.rs new file mode 100644 index 000000000..7badbb6b9 --- /dev/null +++ b/src/test/ui/pattern/pat-shadow-in-nested-binding.rs @@ -0,0 +1,6 @@ +#[allow(non_camel_case_types)] +struct foo(usize); + +fn main() { + let (foo, _) = (2, 3); //~ ERROR let bindings cannot shadow tuple structs +} diff --git a/src/test/ui/pattern/pat-shadow-in-nested-binding.stderr b/src/test/ui/pattern/pat-shadow-in-nested-binding.stderr new file mode 100644 index 000000000..0c5824be9 --- /dev/null +++ b/src/test/ui/pattern/pat-shadow-in-nested-binding.stderr @@ -0,0 +1,12 @@ +error[E0530]: let bindings cannot shadow tuple structs + --> $DIR/pat-shadow-in-nested-binding.rs:5:10 + | +LL | struct foo(usize); + | ------------------ the tuple struct `foo` is defined here +... +LL | let (foo, _) = (2, 3); + | ^^^ cannot be named the same as a tuple struct + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0530`. diff --git a/src/test/ui/pattern/pat-struct-field-expr-has-type.rs b/src/test/ui/pattern/pat-struct-field-expr-has-type.rs new file mode 100644 index 000000000..1d18214de --- /dev/null +++ b/src/test/ui/pattern/pat-struct-field-expr-has-type.rs @@ -0,0 +1,9 @@ +struct S { + f: u8, +} + +fn main() { + match (S { f: 42 }) { + S { f: Ok(_) } => {} //~ ERROR mismatched types + } +} diff --git a/src/test/ui/pattern/pat-struct-field-expr-has-type.stderr b/src/test/ui/pattern/pat-struct-field-expr-has-type.stderr new file mode 100644 index 000000000..3a61d4293 --- /dev/null +++ b/src/test/ui/pattern/pat-struct-field-expr-has-type.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/pat-struct-field-expr-has-type.rs:7:16 + | +LL | match (S { f: 42 }) { + | ------------- this expression has type `S` +LL | S { f: Ok(_) } => {} + | ^^^^^ expected `u8`, found enum `Result` + | + = note: expected type `u8` + found enum `Result<_, _>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/pattern/pat-tuple-bad-type.rs b/src/test/ui/pattern/pat-tuple-bad-type.rs new file mode 100644 index 000000000..98481167a --- /dev/null +++ b/src/test/ui/pattern/pat-tuple-bad-type.rs @@ -0,0 +1,15 @@ +fn main() { + let x; //~ ERROR type annotations needed + + match x { + (..) => {} + _ => {} + } + + match 0u8 { + (..) => {} //~ ERROR mismatched types + _ => {} + } + + x = 10; +} diff --git a/src/test/ui/pattern/pat-tuple-bad-type.stderr b/src/test/ui/pattern/pat-tuple-bad-type.stderr new file mode 100644 index 000000000..3342b8e40 --- /dev/null +++ b/src/test/ui/pattern/pat-tuple-bad-type.stderr @@ -0,0 +1,26 @@ +error[E0282]: type annotations needed + --> $DIR/pat-tuple-bad-type.rs:2:9 + | +LL | let x; + | ^ +... +LL | (..) => {} + | ---- type must be known at this point + | +help: consider giving `x` an explicit type + | +LL | let x: _; + | +++ + +error[E0308]: mismatched types + --> $DIR/pat-tuple-bad-type.rs:10:9 + | +LL | match 0u8 { + | --- this expression has type `u8` +LL | (..) => {} + | ^^^^ expected `u8`, found `()` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0282, E0308. +For more information about an error, try `rustc --explain E0282`. diff --git a/src/test/ui/pattern/pat-tuple-field-count-cross.rs b/src/test/ui/pattern/pat-tuple-field-count-cross.rs new file mode 100644 index 000000000..b63da4e15 --- /dev/null +++ b/src/test/ui/pattern/pat-tuple-field-count-cross.rs @@ -0,0 +1,57 @@ +// aux-build:declarations-for-tuple-field-count-errors.rs + +extern crate declarations_for_tuple_field_count_errors; + +use declarations_for_tuple_field_count_errors::*; + +fn main() { + match Z0 { + Z0() => {} //~ ERROR expected tuple struct or tuple variant, found unit struct `Z0` + Z0(x) => {} //~ ERROR expected tuple struct or tuple variant, found unit struct `Z0` + } + match Z1() { + Z1 => {} //~ ERROR match bindings cannot shadow tuple structs + Z1(x) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple struct has 0 fields + } + + match S(1, 2, 3) { + S() => {} //~ ERROR this pattern has 0 fields, but the corresponding tuple struct has 3 fields + S(1) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple struct has 3 fields + S(xyz, abc) => {} //~ ERROR this pattern has 2 fields, but the corresponding tuple struct has 3 fields + S(1, 2, 3, 4) => {} //~ ERROR this pattern has 4 fields, but the corresponding tuple struct has 3 fields + } + match M(1, 2, 3) { + M() => {} //~ ERROR this pattern has 0 fields, but the corresponding tuple struct has 3 fields + M(1) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple struct has 3 fields + M(xyz, abc) => {} //~ ERROR this pattern has 2 fields, but the corresponding tuple struct has 3 fields + M(1, 2, 3, 4) => {} //~ ERROR this pattern has 4 fields, but the corresponding tuple struct has 3 fields + } + + match E1::Z0 { + E1::Z0() => {} //~ ERROR expected tuple struct or tuple variant, found unit variant `E1::Z0` + E1::Z0(x) => {} //~ ERROR expected tuple struct or tuple variant, found unit variant `E1::Z0` + } + match E1::Z1() { + E1::Z1 => {} //~ ERROR expected unit struct, unit variant or constant, found tuple variant `E1::Z1` + E1::Z1(x) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple variant has 0 fields + } + match E1::S(1, 2, 3) { + E1::S() => {} //~ ERROR this pattern has 0 fields, but the corresponding tuple variant has 3 fields + E1::S(1) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple variant has 3 fields + E1::S(xyz, abc) => {} //~ ERROR this pattern has 2 fields, but the corresponding tuple variant has 3 fields + E1::S(1, 2, 3, 4) => {} //~ ERROR this pattern has 4 fields, but the corresponding tuple variant has 3 fields + } + + match E2::S(1, 2, 3) { + E2::S() => {} //~ ERROR this pattern has 0 fields, but the corresponding tuple variant has 3 fields + E2::S(1) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple variant has 3 fields + E2::S(xyz, abc) => {} //~ ERROR this pattern has 2 fields, but the corresponding tuple variant has 3 fields + E2::S(1, 2, 3, 4) => {} //~ ERROR this pattern has 4 fields, but the corresponding tuple variant has 3 fields + } + match E2::M(1, 2, 3) { + E2::M() => {} //~ ERROR this pattern has 0 fields, but the corresponding tuple variant has 3 fields + E2::M(1) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple variant has 3 fields + E2::M(xyz, abc) => {} //~ ERROR this pattern has 2 fields, but the corresponding tuple variant has 3 fields + E2::M(1, 2, 3, 4) => {} //~ ERROR this pattern has 4 fields, but the corresponding tuple variant has 3 fields + } +} diff --git a/src/test/ui/pattern/pat-tuple-field-count-cross.stderr b/src/test/ui/pattern/pat-tuple-field-count-cross.stderr new file mode 100644 index 000000000..d92957461 --- /dev/null +++ b/src/test/ui/pattern/pat-tuple-field-count-cross.stderr @@ -0,0 +1,531 @@ +error[E0530]: match bindings cannot shadow tuple structs + --> $DIR/pat-tuple-field-count-cross.rs:13:9 + | +LL | use declarations_for_tuple_field_count_errors::*; + | -------------------------------------------- the tuple struct `Z1` is imported here +... +LL | Z1 => {} + | ^^ + | | + | cannot be named the same as a tuple struct + | help: try specify the pattern arguments: `Z1(..)` + +error[E0532]: expected tuple struct or tuple variant, found unit struct `Z0` + --> $DIR/pat-tuple-field-count-cross.rs:9:9 + | +LL | Z0() => {} + | ^^^^ + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:1:1 + | +LL | pub struct Z0; + | ------------- `Z0` defined here +LL | pub struct Z1(); + | ------------- similarly named tuple struct `Z1` defined here + | +help: use this syntax instead + | +LL | Z0 => {} + | ~~ +help: a tuple struct with a similar name exists + | +LL | Z1() => {} + | ~~ + +error[E0532]: expected tuple struct or tuple variant, found unit struct `Z0` + --> $DIR/pat-tuple-field-count-cross.rs:10:9 + | +LL | Z0(x) => {} + | ^^^^^ + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:1:1 + | +LL | pub struct Z0; + | ------------- `Z0` defined here +LL | pub struct Z1(); + | ------------- similarly named tuple struct `Z1` defined here + | +help: use this syntax instead + | +LL | Z0 => {} + | ~~ +help: a tuple struct with a similar name exists + | +LL | Z1(x) => {} + | ~~ + +error[E0532]: expected tuple struct or tuple variant, found unit variant `E1::Z0` + --> $DIR/pat-tuple-field-count-cross.rs:31:9 + | +LL | E1::Z0() => {} + | ^^^^^^^^ + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:15 + | +LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) } + | -- -- similarly named tuple variant `Z1` defined here + | | + | `E1::Z0` defined here + | +help: use this syntax instead + | +LL | E1::Z0 => {} + | ~~~~~~ +help: a tuple variant with a similar name exists + | +LL | E1::Z1() => {} + | ~~ + +error[E0532]: expected tuple struct or tuple variant, found unit variant `E1::Z0` + --> $DIR/pat-tuple-field-count-cross.rs:32:9 + | +LL | E1::Z0(x) => {} + | ^^^^^^^^^ + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:15 + | +LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) } + | -- -- similarly named tuple variant `Z1` defined here + | | + | `E1::Z0` defined here + | +help: use this syntax instead + | +LL | E1::Z0 => {} + | ~~~~~~ +help: a tuple variant with a similar name exists + | +LL | E1::Z1(x) => {} + | ~~ + +error[E0532]: expected unit struct, unit variant or constant, found tuple variant `E1::Z1` + --> $DIR/pat-tuple-field-count-cross.rs:35:9 + | +LL | E1::Z1 => {} + | ^^^^^^ + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:19 + | +LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) } + | -- -- `E1::Z1` defined here + | | + | similarly named unit variant `Z0` defined here + | +help: use the tuple variant pattern syntax instead + | +LL | E1::Z1(/* fields */) => {} + | ~~~~~~~~~~~~~~~~~~~~ +help: a unit variant with a similar name exists + | +LL | E1::Z0 => {} + | ~~ + +error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 0 fields + --> $DIR/pat-tuple-field-count-cross.rs:14:12 + | +LL | Z1(x) => {} + | ^ expected 0 fields, found 1 + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:2:1 + | +LL | pub struct Z1(); + | ------------- tuple struct has 0 fields + +error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 3 fields + --> $DIR/pat-tuple-field-count-cross.rs:18:9 + | +LL | S() => {} + | ^^^ expected 3 fields, found 0 + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:4:14 + | +LL | pub struct S(pub u8, pub u8, pub u8); + | ------ ------ ------ tuple struct has 3 fields + | +help: use `_` to explicitly ignore each field + | +LL | S(_, _, _) => {} + | +++++++ +help: use `..` to ignore all fields + | +LL | S(..) => {} + | ++ + +error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 3 fields + --> $DIR/pat-tuple-field-count-cross.rs:19:11 + | +LL | S(1) => {} + | ^ expected 3 fields, found 1 + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:4:14 + | +LL | pub struct S(pub u8, pub u8, pub u8); + | ------ ------ ------ tuple struct has 3 fields + | +help: use `_` to explicitly ignore each field + | +LL | S(1, _, _) => {} + | ++++++ +help: use `..` to ignore the rest of the fields + | +LL | S(1, ..) => {} + | ++++ + +error[E0023]: this pattern has 2 fields, but the corresponding tuple struct has 3 fields + --> $DIR/pat-tuple-field-count-cross.rs:20:11 + | +LL | S(xyz, abc) => {} + | ^^^ ^^^ expected 3 fields, found 2 + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:4:14 + | +LL | pub struct S(pub u8, pub u8, pub u8); + | ------ ------ ------ tuple struct has 3 fields + | +help: use `_` to explicitly ignore each field + | +LL | S(xyz, abc, _) => {} + | +++ + +error[E0023]: this pattern has 4 fields, but the corresponding tuple struct has 3 fields + --> $DIR/pat-tuple-field-count-cross.rs:21:11 + | +LL | S(1, 2, 3, 4) => {} + | ^ ^ ^ ^ expected 3 fields, found 4 + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:4:14 + | +LL | pub struct S(pub u8, pub u8, pub u8); + | ------ ------ ------ tuple struct has 3 fields + +error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 3 fields + --> $DIR/pat-tuple-field-count-cross.rs:24:9 + | +LL | M() => {} + | ^^^ expected 3 fields, found 0 + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:5:12 + | +LL | pub struct M( + | - tuple struct defined here +LL | pub u8, + | ------ +LL | pub u8, + | ------ +LL | pub u8, + | ------ tuple struct has 3 fields + | +help: use `_` to explicitly ignore each field + | +LL | M(_, _, _) => {} + | +++++++ +help: use `..` to ignore all fields + | +LL | M(..) => {} + | ++ + +error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 3 fields + --> $DIR/pat-tuple-field-count-cross.rs:25:11 + | +LL | M(1) => {} + | ^ expected 3 fields, found 1 + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:5:12 + | +LL | pub struct M( + | - tuple struct defined here +LL | pub u8, + | ------ +LL | pub u8, + | ------ +LL | pub u8, + | ------ tuple struct has 3 fields + | +help: use `_` to explicitly ignore each field + | +LL | M(1, _, _) => {} + | ++++++ +help: use `..` to ignore the rest of the fields + | +LL | M(1, ..) => {} + | ++++ + +error[E0023]: this pattern has 2 fields, but the corresponding tuple struct has 3 fields + --> $DIR/pat-tuple-field-count-cross.rs:26:11 + | +LL | M(xyz, abc) => {} + | ^^^ ^^^ expected 3 fields, found 2 + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:5:12 + | +LL | pub struct M( + | - tuple struct defined here +LL | pub u8, + | ------ +LL | pub u8, + | ------ +LL | pub u8, + | ------ tuple struct has 3 fields + | +help: use `_` to explicitly ignore each field + | +LL | M(xyz, abc, _) => {} + | +++ + +error[E0023]: this pattern has 4 fields, but the corresponding tuple struct has 3 fields + --> $DIR/pat-tuple-field-count-cross.rs:27:11 + | +LL | M(1, 2, 3, 4) => {} + | ^ ^ ^ ^ expected 3 fields, found 4 + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:5:12 + | +LL | pub struct M( + | - tuple struct defined here +LL | pub u8, + | ------ +LL | pub u8, + | ------ +LL | pub u8, + | ------ tuple struct has 3 fields + +error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 0 fields + --> $DIR/pat-tuple-field-count-cross.rs:36:16 + | +LL | E1::Z1(x) => {} + | ^ expected 0 fields, found 1 + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:19 + | +LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) } + | -- tuple variant has 0 fields + +error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 3 fields + --> $DIR/pat-tuple-field-count-cross.rs:39:9 + | +LL | E1::S() => {} + | ^^^^^^^ expected 3 fields, found 0 + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:27 + | +LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) } + | -- -- -- tuple variant has 3 fields + | +help: use `_` to explicitly ignore each field + | +LL | E1::S(_, _, _) => {} + | +++++++ +help: use `..` to ignore all fields + | +LL | E1::S(..) => {} + | ++ + +error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 3 fields + --> $DIR/pat-tuple-field-count-cross.rs:40:15 + | +LL | E1::S(1) => {} + | ^ expected 3 fields, found 1 + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:27 + | +LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) } + | -- -- -- tuple variant has 3 fields + | +help: use `_` to explicitly ignore each field + | +LL | E1::S(1, _, _) => {} + | ++++++ +help: use `..` to ignore the rest of the fields + | +LL | E1::S(1, ..) => {} + | ++++ + +error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 3 fields + --> $DIR/pat-tuple-field-count-cross.rs:41:15 + | +LL | E1::S(xyz, abc) => {} + | ^^^ ^^^ expected 3 fields, found 2 + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:27 + | +LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) } + | -- -- -- tuple variant has 3 fields + | +help: use `_` to explicitly ignore each field + | +LL | E1::S(xyz, abc, _) => {} + | +++ + +error[E0023]: this pattern has 4 fields, but the corresponding tuple variant has 3 fields + --> $DIR/pat-tuple-field-count-cross.rs:42:15 + | +LL | E1::S(1, 2, 3, 4) => {} + | ^ ^ ^ ^ expected 3 fields, found 4 + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:27 + | +LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) } + | -- -- -- tuple variant has 3 fields + +error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 3 fields + --> $DIR/pat-tuple-field-count-cross.rs:46:9 + | +LL | E2::S() => {} + | ^^^^^^^ expected 3 fields, found 0 + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:14:7 + | +LL | S(u8, u8, u8), + | -- -- -- tuple variant has 3 fields + | +help: use `_` to explicitly ignore each field + | +LL | E2::S(_, _, _) => {} + | +++++++ +help: use `..` to ignore all fields + | +LL | E2::S(..) => {} + | ++ + +error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 3 fields + --> $DIR/pat-tuple-field-count-cross.rs:47:15 + | +LL | E2::S(1) => {} + | ^ expected 3 fields, found 1 + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:14:7 + | +LL | S(u8, u8, u8), + | -- -- -- tuple variant has 3 fields + | +help: use `_` to explicitly ignore each field + | +LL | E2::S(1, _, _) => {} + | ++++++ +help: use `..` to ignore the rest of the fields + | +LL | E2::S(1, ..) => {} + | ++++ + +error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 3 fields + --> $DIR/pat-tuple-field-count-cross.rs:48:15 + | +LL | E2::S(xyz, abc) => {} + | ^^^ ^^^ expected 3 fields, found 2 + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:14:7 + | +LL | S(u8, u8, u8), + | -- -- -- tuple variant has 3 fields + | +help: use `_` to explicitly ignore each field + | +LL | E2::S(xyz, abc, _) => {} + | +++ + +error[E0023]: this pattern has 4 fields, but the corresponding tuple variant has 3 fields + --> $DIR/pat-tuple-field-count-cross.rs:49:15 + | +LL | E2::S(1, 2, 3, 4) => {} + | ^ ^ ^ ^ expected 3 fields, found 4 + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:14:7 + | +LL | S(u8, u8, u8), + | -- -- -- tuple variant has 3 fields + +error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 3 fields + --> $DIR/pat-tuple-field-count-cross.rs:52:9 + | +LL | E2::M() => {} + | ^^^^^^^ expected 3 fields, found 0 + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:15:5 + | +LL | M( + | - tuple variant defined here +LL | u8, + | -- +LL | u8, + | -- +LL | u8, + | -- tuple variant has 3 fields + | +help: use `_` to explicitly ignore each field + | +LL | E2::M(_, _, _) => {} + | +++++++ +help: use `..` to ignore all fields + | +LL | E2::M(..) => {} + | ++ + +error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 3 fields + --> $DIR/pat-tuple-field-count-cross.rs:53:15 + | +LL | E2::M(1) => {} + | ^ expected 3 fields, found 1 + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:15:5 + | +LL | M( + | - tuple variant defined here +LL | u8, + | -- +LL | u8, + | -- +LL | u8, + | -- tuple variant has 3 fields + | +help: use `_` to explicitly ignore each field + | +LL | E2::M(1, _, _) => {} + | ++++++ +help: use `..` to ignore the rest of the fields + | +LL | E2::M(1, ..) => {} + | ++++ + +error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 3 fields + --> $DIR/pat-tuple-field-count-cross.rs:54:15 + | +LL | E2::M(xyz, abc) => {} + | ^^^ ^^^ expected 3 fields, found 2 + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:15:5 + | +LL | M( + | - tuple variant defined here +LL | u8, + | -- +LL | u8, + | -- +LL | u8, + | -- tuple variant has 3 fields + | +help: use `_` to explicitly ignore each field + | +LL | E2::M(xyz, abc, _) => {} + | +++ + +error[E0023]: this pattern has 4 fields, but the corresponding tuple variant has 3 fields + --> $DIR/pat-tuple-field-count-cross.rs:55:15 + | +LL | E2::M(1, 2, 3, 4) => {} + | ^ ^ ^ ^ expected 3 fields, found 4 + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:15:5 + | +LL | M( + | - tuple variant defined here +LL | u8, + | -- +LL | u8, + | -- +LL | u8, + | -- tuple variant has 3 fields + +error: aborting due to 28 previous errors + +Some errors have detailed explanations: E0023, E0530, E0532. +For more information about an error, try `rustc --explain E0023`. diff --git a/src/test/ui/pattern/pat-tuple-overfield.rs b/src/test/ui/pattern/pat-tuple-overfield.rs new file mode 100644 index 000000000..c863c6575 --- /dev/null +++ b/src/test/ui/pattern/pat-tuple-overfield.rs @@ -0,0 +1,74 @@ +struct S(u8, u8, u8); +struct M( + u8, + u8, + u8, + u8, + u8, +); + +struct Z0; +struct Z1(); +enum E1 { + Z0, + Z1(), +} + +fn main() { + match (1, 2, 3) { + (1, 2, 3, 4) => {} //~ ERROR mismatched types + (1, 2, .., 3, 4) => {} //~ ERROR mismatched types + _ => {} + } + match S(1, 2, 3) { + S(1, 2, 3, 4) => {} + //~^ ERROR this pattern has 4 fields, but the corresponding tuple struct has 3 fields + S(1, 2, .., 3, 4) => {} + //~^ ERROR this pattern has 4 fields, but the corresponding tuple struct has 3 fields + _ => {} + } + match M(1, 2, 3, 4, 5) { + M(1, 2, 3, 4, 5, 6) => {} + //~^ ERROR this pattern has 6 fields, but the corresponding tuple struct has 5 fields + M(1, + 2, + 3, + 4, + 5, + 6) => {} + //~^ ERROR this pattern has 6 fields, but the corresponding tuple struct has 5 fields + M( + 1, + 2, + 3, + 4, + 5, + 6, + ) => {} + //~^^ ERROR this pattern has 6 fields, but the corresponding tuple struct has 5 fields + } + match Z0 { + Z0 => {} + Z0() => {} //~ ERROR expected tuple struct or tuple variant, found unit struct `Z0` + Z0(_) => {} //~ ERROR expected tuple struct or tuple variant, found unit struct `Z0` + Z0(_, _) => {} //~ ERROR expected tuple struct or tuple variant, found unit struct `Z0` + } + match Z1() { + Z1 => {} //~ ERROR match bindings cannot shadow tuple structs + Z1() => {} + Z1(_) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple struct has 0 fields + Z1(_, _) => {} //~ ERROR this pattern has 2 fields, but the corresponding tuple struct has 0 fields + } + match E1::Z0 { + E1::Z0 => {} + E1::Z0() => {} //~ ERROR expected tuple struct or tuple variant, found unit variant `E1::Z0` + E1::Z0(_) => {} //~ ERROR expected tuple struct or tuple variant, found unit variant `E1::Z0` + E1::Z0(_, _) => {} //~ ERROR expected tuple struct or tuple variant, found unit variant `E1::Z0` + } + match E1::Z1() { + E1::Z1 => {} //~ ERROR expected unit struct, unit variant or constant, found tuple variant `E1::Z1` + E1::Z1() => {} + E1::Z1(_) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple variant has 0 fields + E1::Z1(_, _) => {} //~ ERROR this pattern has 2 fields, but the corresponding tuple variant has 0 fields + } +} diff --git a/src/test/ui/pattern/pat-tuple-overfield.stderr b/src/test/ui/pattern/pat-tuple-overfield.stderr new file mode 100644 index 000000000..54d89e031 --- /dev/null +++ b/src/test/ui/pattern/pat-tuple-overfield.stderr @@ -0,0 +1,312 @@ +error[E0530]: match bindings cannot shadow tuple structs + --> $DIR/pat-tuple-overfield.rs:57:9 + | +LL | struct Z1(); + | ------------ the tuple struct `Z1` is defined here +... +LL | Z1 => {} + | ^^ + | | + | cannot be named the same as a tuple struct + | help: try specify the pattern arguments: `Z1(..)` + +error[E0532]: expected tuple struct or tuple variant, found unit struct `Z0` + --> $DIR/pat-tuple-overfield.rs:52:9 + | +LL | struct Z0; + | ---------- `Z0` defined here +LL | struct Z1(); + | ------------ similarly named tuple struct `Z1` defined here +... +LL | Z0() => {} + | ^^^^ + | +help: use this syntax instead + | +LL | Z0 => {} + | ~~ +help: a tuple struct with a similar name exists + | +LL | Z1() => {} + | ~~ + +error[E0532]: expected tuple struct or tuple variant, found unit struct `Z0` + --> $DIR/pat-tuple-overfield.rs:53:9 + | +LL | struct Z0; + | ---------- `Z0` defined here +LL | struct Z1(); + | ------------ similarly named tuple struct `Z1` defined here +... +LL | Z0(_) => {} + | ^^^^^ + | +help: use this syntax instead + | +LL | Z0 => {} + | ~~ +help: a tuple struct with a similar name exists + | +LL | Z1(_) => {} + | ~~ + +error[E0532]: expected tuple struct or tuple variant, found unit struct `Z0` + --> $DIR/pat-tuple-overfield.rs:54:9 + | +LL | struct Z0; + | ---------- `Z0` defined here +LL | struct Z1(); + | ------------ similarly named tuple struct `Z1` defined here +... +LL | Z0(_, _) => {} + | ^^^^^^^^ + | +help: use this syntax instead + | +LL | Z0 => {} + | ~~ +help: a tuple struct with a similar name exists + | +LL | Z1(_, _) => {} + | ~~ + +error[E0532]: expected tuple struct or tuple variant, found unit variant `E1::Z0` + --> $DIR/pat-tuple-overfield.rs:64:9 + | +LL | Z0, + | -- `E1::Z0` defined here +LL | Z1(), + | ---- similarly named tuple variant `Z1` defined here +... +LL | E1::Z0() => {} + | ^^^^^^^^ + | +help: use this syntax instead + | +LL | E1::Z0 => {} + | ~~~~~~ +help: a tuple variant with a similar name exists + | +LL | E1::Z1() => {} + | ~~ + +error[E0532]: expected tuple struct or tuple variant, found unit variant `E1::Z0` + --> $DIR/pat-tuple-overfield.rs:65:9 + | +LL | Z0, + | -- `E1::Z0` defined here +LL | Z1(), + | ---- similarly named tuple variant `Z1` defined here +... +LL | E1::Z0(_) => {} + | ^^^^^^^^^ + | +help: use this syntax instead + | +LL | E1::Z0 => {} + | ~~~~~~ +help: a tuple variant with a similar name exists + | +LL | E1::Z1(_) => {} + | ~~ + +error[E0532]: expected tuple struct or tuple variant, found unit variant `E1::Z0` + --> $DIR/pat-tuple-overfield.rs:66:9 + | +LL | Z0, + | -- `E1::Z0` defined here +LL | Z1(), + | ---- similarly named tuple variant `Z1` defined here +... +LL | E1::Z0(_, _) => {} + | ^^^^^^^^^^^^ + | +help: use this syntax instead + | +LL | E1::Z0 => {} + | ~~~~~~ +help: a tuple variant with a similar name exists + | +LL | E1::Z1(_, _) => {} + | ~~ + +error[E0532]: expected unit struct, unit variant or constant, found tuple variant `E1::Z1` + --> $DIR/pat-tuple-overfield.rs:69:9 + | +LL | Z0, + | -- similarly named unit variant `Z0` defined here +LL | Z1(), + | ---- `E1::Z1` defined here +... +LL | E1::Z1 => {} + | ^^^^^^ + | +help: use the tuple variant pattern syntax instead + | +LL | E1::Z1() => {} + | ~~~~~~~~ +help: a unit variant with a similar name exists + | +LL | E1::Z0 => {} + | ~~ + +error[E0308]: mismatched types + --> $DIR/pat-tuple-overfield.rs:19:9 + | +LL | match (1, 2, 3) { + | --------- this expression has type `({integer}, {integer}, {integer})` +LL | (1, 2, 3, 4) => {} + | ^^^^^^^^^^^^ expected a tuple with 3 elements, found one with 4 elements + | + = note: expected tuple `({integer}, {integer}, {integer})` + found tuple `(_, _, _, _)` + +error[E0308]: mismatched types + --> $DIR/pat-tuple-overfield.rs:20:9 + | +LL | match (1, 2, 3) { + | --------- this expression has type `({integer}, {integer}, {integer})` +LL | (1, 2, 3, 4) => {} +LL | (1, 2, .., 3, 4) => {} + | ^^^^^^^^^^^^^^^^ expected a tuple with 3 elements, found one with 4 elements + | + = note: expected tuple `({integer}, {integer}, {integer})` + found tuple `(_, _, _, _)` + +error[E0023]: this pattern has 4 fields, but the corresponding tuple struct has 3 fields + --> $DIR/pat-tuple-overfield.rs:24:11 + | +LL | struct S(u8, u8, u8); + | -- -- -- tuple struct has 3 fields +... +LL | S(1, 2, 3, 4) => {} + | ^ ^ ^ ^ expected 3 fields, found 4 + +error[E0023]: this pattern has 4 fields, but the corresponding tuple struct has 3 fields + --> $DIR/pat-tuple-overfield.rs:26:11 + | +LL | struct S(u8, u8, u8); + | -- -- -- tuple struct has 3 fields +... +LL | S(1, 2, .., 3, 4) => {} + | ^ ^ ^ ^ expected 3 fields, found 4 + +error[E0023]: this pattern has 6 fields, but the corresponding tuple struct has 5 fields + --> $DIR/pat-tuple-overfield.rs:31:11 + | +LL | struct M( + | - tuple struct defined here +LL | u8, + | -- +LL | u8, + | -- +LL | u8, + | -- +LL | u8, + | -- +LL | u8, + | -- tuple struct has 5 fields +... +LL | M(1, 2, 3, 4, 5, 6) => {} + | ^ ^ ^ ^ ^ ^ expected 5 fields, found 6 + +error[E0023]: this pattern has 6 fields, but the corresponding tuple struct has 5 fields + --> $DIR/pat-tuple-overfield.rs:33:11 + | +LL | struct M( + | - tuple struct defined here +LL | u8, + | -- +LL | u8, + | -- +LL | u8, + | -- +LL | u8, + | -- +LL | u8, + | -- tuple struct has 5 fields +... +LL | M(1, + | - ^ +LL | 2, + | ^ +LL | 3, + | ^ +LL | 4, + | ^ +LL | 5, + | ^ +LL | 6) => {} + | ^ expected 5 fields, found 6 + +error[E0023]: this pattern has 6 fields, but the corresponding tuple struct has 5 fields + --> $DIR/pat-tuple-overfield.rs:41:13 + | +LL | struct M( + | - tuple struct defined here +LL | u8, + | -- +LL | u8, + | -- +LL | u8, + | -- +LL | u8, + | -- +LL | u8, + | -- tuple struct has 5 fields +... +LL | M( + | - +LL | 1, + | ^ +LL | 2, + | ^ +LL | 3, + | ^ +LL | 4, + | ^ +LL | 5, + | ^ +LL | 6, + | ^ expected 5 fields, found 6 + +error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 0 fields + --> $DIR/pat-tuple-overfield.rs:59:12 + | +LL | struct Z1(); + | --------- tuple struct has 0 fields +... +LL | Z1(_) => {} + | ^ expected 0 fields, found 1 + +error[E0023]: this pattern has 2 fields, but the corresponding tuple struct has 0 fields + --> $DIR/pat-tuple-overfield.rs:60:12 + | +LL | struct Z1(); + | --------- tuple struct has 0 fields +... +LL | Z1(_, _) => {} + | ^ ^ expected 0 fields, found 2 + +error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 0 fields + --> $DIR/pat-tuple-overfield.rs:71:16 + | +LL | Z1(), + | -- tuple variant has 0 fields +... +LL | E1::Z1(_) => {} + | ^ expected 0 fields, found 1 + +error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 0 fields + --> $DIR/pat-tuple-overfield.rs:72:16 + | +LL | Z1(), + | -- tuple variant has 0 fields +... +LL | E1::Z1(_, _) => {} + | ^ ^ expected 0 fields, found 2 + +error: aborting due to 19 previous errors + +Some errors have detailed explanations: E0023, E0308, E0530, E0532. +For more information about an error, try `rustc --explain E0023`. diff --git a/src/test/ui/pattern/pat-tuple-underfield.rs b/src/test/ui/pattern/pat-tuple-underfield.rs new file mode 100644 index 000000000..dac60e3fa --- /dev/null +++ b/src/test/ui/pattern/pat-tuple-underfield.rs @@ -0,0 +1,67 @@ +struct S(i32, f32); +enum E { + S(i32, f32), +} +struct Point4(i32, i32, i32, i32); + +fn main() { + match S(0, 1.0) { + S(x) => {} + //~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields + //~| HELP use `_` to explicitly ignore each field + } + match S(0, 1.0) { + S(_) => {} + //~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields + //~| HELP use `_` to explicitly ignore each field + //~| HELP use `..` to ignore all fields + } + match S(0, 1.0) { + S() => {} + //~^ ERROR this pattern has 0 fields, but the corresponding tuple struct has 2 fields + //~| HELP use `_` to explicitly ignore each field + //~| HELP use `..` to ignore all fields + + // Test non-standard formatting + S () => {} + //~^ ERROR this pattern has 0 fields, but the corresponding tuple struct has 2 fields + //~| HELP use `_` to explicitly ignore each field + //~| HELP use `..` to ignore all fields + } + + match E::S(0, 1.0) { + E::S(x) => {} + //~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields + //~| HELP use `_` to explicitly ignore each field + } + match E::S(0, 1.0) { + E::S(_) => {} + //~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields + //~| HELP use `_` to explicitly ignore each field + //~| HELP use `..` to ignore all fields + } + match E::S(0, 1.0) { + E::S() => {} + //~^ ERROR this pattern has 0 fields, but the corresponding tuple variant has 2 fields + //~| HELP use `_` to explicitly ignore each field + //~| HELP use `..` to ignore all fields + + // Test non-standard formatting + E::S () => {} + //~^ ERROR this pattern has 0 fields, but the corresponding tuple variant has 2 fields + //~| HELP use `_` to explicitly ignore each field + //~| HELP use `..` to ignore all fields + } + match E::S(0, 1.0) { + E::S => {} + //~^ ERROR expected unit struct, unit variant or constant, found tuple variant `E::S` + //~| HELP use the tuple variant pattern syntax instead + } + + match Point4(0, 1, 2, 3) { + Point4( a , _ ) => {} + //~^ ERROR this pattern has 2 fields, but the corresponding tuple struct has 4 fields + //~| HELP use `_` to explicitly ignore each field + //~| HELP use `..` to ignore the rest of the fields + } +} diff --git a/src/test/ui/pattern/pat-tuple-underfield.stderr b/src/test/ui/pattern/pat-tuple-underfield.stderr new file mode 100644 index 000000000..e75f9b38d --- /dev/null +++ b/src/test/ui/pattern/pat-tuple-underfield.stderr @@ -0,0 +1,167 @@ +error[E0532]: expected unit struct, unit variant or constant, found tuple variant `E::S` + --> $DIR/pat-tuple-underfield.rs:56:9 + | +LL | S(i32, f32), + | ----------- `E::S` defined here +... +LL | E::S => {} + | ^^^^ help: use the tuple variant pattern syntax instead: `E::S(_, _)` + +error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields + --> $DIR/pat-tuple-underfield.rs:9:11 + | +LL | struct S(i32, f32); + | --- --- tuple struct has 2 fields +... +LL | S(x) => {} + | ^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | S(x, _) => {} + | +++ + +error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields + --> $DIR/pat-tuple-underfield.rs:14:11 + | +LL | struct S(i32, f32); + | --- --- tuple struct has 2 fields +... +LL | S(_) => {} + | ^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | S(_, _) => {} + | +++ +help: use `..` to ignore all fields + | +LL | S(..) => {} + | ~~ + +error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 2 fields + --> $DIR/pat-tuple-underfield.rs:20:9 + | +LL | struct S(i32, f32); + | --- --- tuple struct has 2 fields +... +LL | S() => {} + | ^^^ expected 2 fields, found 0 + | +help: use `_` to explicitly ignore each field + | +LL | S(_, _) => {} + | ++++ +help: use `..` to ignore all fields + | +LL | S(..) => {} + | ++ + +error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 2 fields + --> $DIR/pat-tuple-underfield.rs:26:9 + | +LL | struct S(i32, f32); + | --- --- tuple struct has 2 fields +... +LL | S () => {} + | ^^^^ expected 2 fields, found 0 + | +help: use `_` to explicitly ignore each field + | +LL | S (_, _) => {} + | ++++ +help: use `..` to ignore all fields + | +LL | S (..) => {} + | ++ + +error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields + --> $DIR/pat-tuple-underfield.rs:33:14 + | +LL | S(i32, f32), + | --- --- tuple variant has 2 fields +... +LL | E::S(x) => {} + | ^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | E::S(x, _) => {} + | +++ + +error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields + --> $DIR/pat-tuple-underfield.rs:38:14 + | +LL | S(i32, f32), + | --- --- tuple variant has 2 fields +... +LL | E::S(_) => {} + | ^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | E::S(_, _) => {} + | +++ +help: use `..` to ignore all fields + | +LL | E::S(..) => {} + | ~~ + +error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 2 fields + --> $DIR/pat-tuple-underfield.rs:44:9 + | +LL | S(i32, f32), + | --- --- tuple variant has 2 fields +... +LL | E::S() => {} + | ^^^^^^ expected 2 fields, found 0 + | +help: use `_` to explicitly ignore each field + | +LL | E::S(_, _) => {} + | ++++ +help: use `..` to ignore all fields + | +LL | E::S(..) => {} + | ++ + +error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 2 fields + --> $DIR/pat-tuple-underfield.rs:50:9 + | +LL | S(i32, f32), + | --- --- tuple variant has 2 fields +... +LL | E::S () => {} + | ^^^^^^^ expected 2 fields, found 0 + | +help: use `_` to explicitly ignore each field + | +LL | E::S (_, _) => {} + | ++++ +help: use `..` to ignore all fields + | +LL | E::S (..) => {} + | ++ + +error[E0023]: this pattern has 2 fields, but the corresponding tuple struct has 4 fields + --> $DIR/pat-tuple-underfield.rs:62:19 + | +LL | struct Point4(i32, i32, i32, i32); + | --- --- --- --- tuple struct has 4 fields +... +LL | Point4( a , _ ) => {} + | ^ ^ expected 4 fields, found 2 + | +help: use `_` to explicitly ignore each field + | +LL | Point4( a , _ , _, _) => {} + | ++++++ +help: use `..` to ignore the rest of the fields + | +LL | Point4( a, ..) => {} + | ~~~~ + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0023, E0532. +For more information about an error, try `rustc --explain E0023`. diff --git a/src/test/ui/pattern/pat-type-err-formal-param.rs b/src/test/ui/pattern/pat-type-err-formal-param.rs new file mode 100644 index 000000000..54336b349 --- /dev/null +++ b/src/test/ui/pattern/pat-type-err-formal-param.rs @@ -0,0 +1,8 @@ +// Test the `.span_label(..)` to the type when there's a +// type error in a pattern due to a the formal parameter. + +fn main() {} + +struct Tuple(u8); + +fn foo(Tuple(_): String) {} //~ ERROR mismatched types diff --git a/src/test/ui/pattern/pat-type-err-formal-param.stderr b/src/test/ui/pattern/pat-type-err-formal-param.stderr new file mode 100644 index 000000000..206713a4b --- /dev/null +++ b/src/test/ui/pattern/pat-type-err-formal-param.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/pat-type-err-formal-param.rs:8:8 + | +LL | fn foo(Tuple(_): String) {} + | ^^^^^^^^ ------ expected due to this + | | + | expected struct `String`, found struct `Tuple` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/pattern/pat-type-err-let-stmt.rs b/src/test/ui/pattern/pat-type-err-let-stmt.rs new file mode 100644 index 000000000..6e9850b65 --- /dev/null +++ b/src/test/ui/pattern/pat-type-err-let-stmt.rs @@ -0,0 +1,16 @@ +// Test the `.span_label` to the type / scrutinee +// when there's a type error in checking a pattern. + +fn main() { + // We want to point at the `Option<u8>`. + let Ok(0): Option<u8> = 42u8; + //~^ ERROR mismatched types + //~| ERROR mismatched types + + // We want to point at the `Option<u8>`. + let Ok(0): Option<u8>; + //~^ ERROR mismatched types + + // We want to point at the scrutinee. + let Ok(0) = 42u8; //~ ERROR mismatched types +} diff --git a/src/test/ui/pattern/pat-type-err-let-stmt.stderr b/src/test/ui/pattern/pat-type-err-let-stmt.stderr new file mode 100644 index 000000000..090bd6711 --- /dev/null +++ b/src/test/ui/pattern/pat-type-err-let-stmt.stderr @@ -0,0 +1,51 @@ +error[E0308]: mismatched types + --> $DIR/pat-type-err-let-stmt.rs:6:29 + | +LL | let Ok(0): Option<u8> = 42u8; + | ---------- ^^^^ expected enum `Option`, found `u8` + | | + | expected due to this + | + = note: expected enum `Option<u8>` + found type `u8` +help: try wrapping the expression in `Some` + | +LL | let Ok(0): Option<u8> = Some(42u8); + | +++++ + + +error[E0308]: mismatched types + --> $DIR/pat-type-err-let-stmt.rs:6:9 + | +LL | let Ok(0): Option<u8> = 42u8; + | ^^^^^ ---------- expected due to this + | | + | expected enum `Option`, found enum `Result` + | + = note: expected enum `Option<u8>` + found enum `Result<_, _>` + +error[E0308]: mismatched types + --> $DIR/pat-type-err-let-stmt.rs:11:9 + | +LL | let Ok(0): Option<u8>; + | ^^^^^ ---------- expected due to this + | | + | expected enum `Option`, found enum `Result` + | + = note: expected enum `Option<u8>` + found enum `Result<_, _>` + +error[E0308]: mismatched types + --> $DIR/pat-type-err-let-stmt.rs:15:9 + | +LL | let Ok(0) = 42u8; + | ^^^^^ ---- this expression has type `u8` + | | + | expected `u8`, found enum `Result` + | + = note: expected type `u8` + found enum `Result<_, _>` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/pattern/patkind-litrange-no-expr.rs b/src/test/ui/pattern/patkind-litrange-no-expr.rs new file mode 100644 index 000000000..7ef541cb5 --- /dev/null +++ b/src/test/ui/pattern/patkind-litrange-no-expr.rs @@ -0,0 +1,24 @@ +macro_rules! enum_number { + ($name:ident { $($variant:ident = $value:expr, )* }) => { + enum $name { + $($variant = $value,)* + } + + fn foo(value: i32) -> Option<$name> { + match value { + $( $value => Some($name::$variant), )* // PatKind::Lit + $( $value ..= 42 => Some($name::$variant), )* // PatKind::Range + _ => None + } + } + } +} + +enum_number!(Change { + Pos = 1, + Neg = -1, + Arith = 1 + 1, //~ ERROR arbitrary expressions aren't allowed in patterns + //~| ERROR arbitrary expressions aren't allowed in patterns +}); + +fn main() {} diff --git a/src/test/ui/pattern/patkind-litrange-no-expr.stderr b/src/test/ui/pattern/patkind-litrange-no-expr.stderr new file mode 100644 index 000000000..eb1ee7e45 --- /dev/null +++ b/src/test/ui/pattern/patkind-litrange-no-expr.stderr @@ -0,0 +1,14 @@ +error: arbitrary expressions aren't allowed in patterns + --> $DIR/patkind-litrange-no-expr.rs:20:13 + | +LL | Arith = 1 + 1, + | ^^^^^ + +error: arbitrary expressions aren't allowed in patterns + --> $DIR/patkind-litrange-no-expr.rs:20:13 + | +LL | Arith = 1 + 1, + | ^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/pattern/pattern-binding-disambiguation.rs b/src/test/ui/pattern/pattern-binding-disambiguation.rs new file mode 100644 index 000000000..2e80ea345 --- /dev/null +++ b/src/test/ui/pattern/pattern-binding-disambiguation.rs @@ -0,0 +1,57 @@ +struct UnitStruct; +struct TupleStruct(); +struct BracedStruct{} + +enum E { + UnitVariant, + TupleVariant(), + BracedVariant{}, +} +use E::*; + +const CONST: () = (); +static STATIC: () = (); + +fn function() {} + +fn main() { + let doesnt_matter = 0; + + match UnitStruct { + UnitStruct => {} // OK, `UnitStruct` is a unit struct pattern + } + match doesnt_matter { + TupleStruct => {} //~ ERROR match bindings cannot shadow tuple structs + } + match doesnt_matter { + BracedStruct => {} // OK, `BracedStruct` is a fresh binding + } + match UnitVariant { + UnitVariant => {} // OK, `UnitVariant` is a unit variant pattern + } + match doesnt_matter { + TupleVariant => {} //~ ERROR match bindings cannot shadow tuple variants + } + match doesnt_matter { + BracedVariant => {} //~ ERROR match bindings cannot shadow struct variants + } + match CONST { + CONST => {} // OK, `CONST` is a const pattern + } + match doesnt_matter { + STATIC => {} //~ ERROR match bindings cannot shadow statics + } + match doesnt_matter { + function => {} // OK, `function` is a fresh binding + } + + let UnitStruct = UnitStruct; // OK, `UnitStruct` is a unit struct pattern + let TupleStruct = doesnt_matter; //~ ERROR let bindings cannot shadow tuple structs + let BracedStruct = doesnt_matter; // OK, `BracedStruct` is a fresh binding + let UnitVariant = UnitVariant; // OK, `UnitVariant` is a unit variant pattern + let TupleVariant = doesnt_matter; //~ ERROR let bindings cannot shadow tuple variants + let BracedVariant = doesnt_matter; //~ ERROR let bindings cannot shadow struct variants + let CONST = CONST; // OK, `CONST` is a const pattern + let STATIC = doesnt_matter; //~ ERROR let bindings cannot shadow statics + let function = doesnt_matter; // OK, `function` is a fresh binding +} diff --git a/src/test/ui/pattern/pattern-binding-disambiguation.stderr b/src/test/ui/pattern/pattern-binding-disambiguation.stderr new file mode 100644 index 000000000..1529e538b --- /dev/null +++ b/src/test/ui/pattern/pattern-binding-disambiguation.stderr @@ -0,0 +1,81 @@ +error[E0530]: match bindings cannot shadow tuple structs + --> $DIR/pattern-binding-disambiguation.rs:24:9 + | +LL | struct TupleStruct(); + | --------------------- the tuple struct `TupleStruct` is defined here +... +LL | TupleStruct => {} + | ^^^^^^^^^^^ + | | + | cannot be named the same as a tuple struct + | help: try specify the pattern arguments: `TupleStruct(..)` + +error[E0530]: match bindings cannot shadow tuple variants + --> $DIR/pattern-binding-disambiguation.rs:33:9 + | +LL | use E::*; + | ---- the tuple variant `TupleVariant` is imported here +... +LL | TupleVariant => {} + | ^^^^^^^^^^^^ + | | + | cannot be named the same as a tuple variant + | help: try specify the pattern arguments: `TupleVariant(..)` + +error[E0530]: match bindings cannot shadow struct variants + --> $DIR/pattern-binding-disambiguation.rs:36:9 + | +LL | use E::*; + | ---- the struct variant `BracedVariant` is imported here +... +LL | BracedVariant => {} + | ^^^^^^^^^^^^^ cannot be named the same as a struct variant + +error[E0530]: match bindings cannot shadow statics + --> $DIR/pattern-binding-disambiguation.rs:42:9 + | +LL | static STATIC: () = (); + | ----------------------- the static `STATIC` is defined here +... +LL | STATIC => {} + | ^^^^^^ cannot be named the same as a static + +error[E0530]: let bindings cannot shadow tuple structs + --> $DIR/pattern-binding-disambiguation.rs:49:9 + | +LL | struct TupleStruct(); + | --------------------- the tuple struct `TupleStruct` is defined here +... +LL | let TupleStruct = doesnt_matter; + | ^^^^^^^^^^^ cannot be named the same as a tuple struct + +error[E0530]: let bindings cannot shadow tuple variants + --> $DIR/pattern-binding-disambiguation.rs:52:9 + | +LL | use E::*; + | ---- the tuple variant `TupleVariant` is imported here +... +LL | let TupleVariant = doesnt_matter; + | ^^^^^^^^^^^^ cannot be named the same as a tuple variant + +error[E0530]: let bindings cannot shadow struct variants + --> $DIR/pattern-binding-disambiguation.rs:53:9 + | +LL | use E::*; + | ---- the struct variant `BracedVariant` is imported here +... +LL | let BracedVariant = doesnt_matter; + | ^^^^^^^^^^^^^ cannot be named the same as a struct variant + +error[E0530]: let bindings cannot shadow statics + --> $DIR/pattern-binding-disambiguation.rs:55:9 + | +LL | static STATIC: () = (); + | ----------------------- the static `STATIC` is defined here +... +LL | let STATIC = doesnt_matter; + | ^^^^^^ cannot be named the same as a static + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0530`. diff --git a/src/test/ui/pattern/pattern-error-continue.rs b/src/test/ui/pattern/pattern-error-continue.rs new file mode 100644 index 000000000..0702a9986 --- /dev/null +++ b/src/test/ui/pattern/pattern-error-continue.rs @@ -0,0 +1,35 @@ +// Test that certain pattern-match type errors are non-fatal + +enum A { + B(isize, isize), + C(isize, isize, isize), + D +} + +struct S { + a: isize +} + +fn f(_c: char) {} + +fn main() { + match A::B(1, 2) { + A::B(_, _, _) => (), //~ ERROR this pattern has 3 fields, but + A::D(_) => (), //~ ERROR expected tuple struct or tuple variant, found unit variant `A::D` + _ => () + } + match 'c' { + S { .. } => (), + //~^ ERROR mismatched types + //~| expected `char`, found struct `S` + + _ => () + } + f(true); + //~^ ERROR mismatched types + //~| expected `char`, found `bool` + + match () { + E::V => {} //~ ERROR failed to resolve: use of undeclared type `E` + } +} diff --git a/src/test/ui/pattern/pattern-error-continue.stderr b/src/test/ui/pattern/pattern-error-continue.stderr new file mode 100644 index 000000000..4c2eff63a --- /dev/null +++ b/src/test/ui/pattern/pattern-error-continue.stderr @@ -0,0 +1,62 @@ +error[E0433]: failed to resolve: use of undeclared type `E` + --> $DIR/pattern-error-continue.rs:33:9 + | +LL | E::V => {} + | ^ use of undeclared type `E` + +error[E0532]: expected tuple struct or tuple variant, found unit variant `A::D` + --> $DIR/pattern-error-continue.rs:18:9 + | +LL | B(isize, isize), + | --------------- similarly named tuple variant `B` defined here +LL | C(isize, isize, isize), +LL | D + | - `A::D` defined here +... +LL | A::D(_) => (), + | ^^^^^^^ + | +help: use this syntax instead + | +LL | A::D => (), + | ~~~~ +help: a tuple variant with a similar name exists + | +LL | A::B(_) => (), + | ~ + +error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields + --> $DIR/pattern-error-continue.rs:17:14 + | +LL | B(isize, isize), + | ----- ----- tuple variant has 2 fields +... +LL | A::B(_, _, _) => (), + | ^ ^ ^ expected 2 fields, found 3 + +error[E0308]: mismatched types + --> $DIR/pattern-error-continue.rs:22:9 + | +LL | match 'c' { + | --- this expression has type `char` +LL | S { .. } => (), + | ^^^^^^^^ expected `char`, found struct `S` + +error[E0308]: mismatched types + --> $DIR/pattern-error-continue.rs:28:7 + | +LL | f(true); + | - ^^^^ expected `char`, found `bool` + | | + | arguments to this function are incorrect + | +note: function defined here + --> $DIR/pattern-error-continue.rs:13:4 + | +LL | fn f(_c: char) {} + | ^ -------- + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0023, E0308, E0433, E0532. +For more information about an error, try `rustc --explain E0023`. diff --git a/src/test/ui/pattern/pattern-ident-path-generics.rs b/src/test/ui/pattern/pattern-ident-path-generics.rs new file mode 100644 index 000000000..48c02623f --- /dev/null +++ b/src/test/ui/pattern/pattern-ident-path-generics.rs @@ -0,0 +1,6 @@ +fn main() { + match Some("foo") { + None::<isize> => {} //~ ERROR mismatched types + Some(_) => {} + } +} diff --git a/src/test/ui/pattern/pattern-ident-path-generics.stderr b/src/test/ui/pattern/pattern-ident-path-generics.stderr new file mode 100644 index 000000000..01b082bd3 --- /dev/null +++ b/src/test/ui/pattern/pattern-ident-path-generics.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/pattern-ident-path-generics.rs:3:9 + | +LL | match Some("foo") { + | ----------- this expression has type `Option<&str>` +LL | None::<isize> => {} + | ^^^^^^^^^^^^^ expected `&str`, found `isize` + | + = note: expected enum `Option<&str>` + found enum `Option<isize>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/pattern/pattern-tyvar-2.rs b/src/test/ui/pattern/pattern-tyvar-2.rs new file mode 100644 index 000000000..7647c766e --- /dev/null +++ b/src/test/ui/pattern/pattern-tyvar-2.rs @@ -0,0 +1,6 @@ +enum Bar { T1((), Option<Vec<isize>>), T2, } + +fn foo(t: Bar) -> isize { match t { Bar::T1(_, Some(x)) => { return x * 3; } _ => { panic!(); } } } +//~^ ERROR cannot multiply `Vec<isize>` by `{integer}` + +fn main() { } diff --git a/src/test/ui/pattern/pattern-tyvar-2.stderr b/src/test/ui/pattern/pattern-tyvar-2.stderr new file mode 100644 index 000000000..121817e70 --- /dev/null +++ b/src/test/ui/pattern/pattern-tyvar-2.stderr @@ -0,0 +1,11 @@ +error[E0369]: cannot multiply `Vec<isize>` by `{integer}` + --> $DIR/pattern-tyvar-2.rs:3:71 + | +LL | fn foo(t: Bar) -> isize { match t { Bar::T1(_, Some(x)) => { return x * 3; } _ => { panic!(); } } } + | - ^ - {integer} + | | + | Vec<isize> + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0369`. diff --git a/src/test/ui/pattern/pattern-tyvar.rs b/src/test/ui/pattern/pattern-tyvar.rs new file mode 100644 index 000000000..e2cbf0519 --- /dev/null +++ b/src/test/ui/pattern/pattern-tyvar.rs @@ -0,0 +1,12 @@ +enum Bar { T1((), Option<Vec<isize>>), T2 } + +fn foo(t: Bar) { + match t { + Bar::T1(_, Some::<isize>(x)) => { //~ ERROR mismatched types + println!("{}", x); + } + _ => { panic!(); } + } +} + +fn main() { } diff --git a/src/test/ui/pattern/pattern-tyvar.stderr b/src/test/ui/pattern/pattern-tyvar.stderr new file mode 100644 index 000000000..f1e2a9d72 --- /dev/null +++ b/src/test/ui/pattern/pattern-tyvar.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/pattern-tyvar.rs:5:18 + | +LL | match t { + | - this expression has type `Bar` +LL | Bar::T1(_, Some::<isize>(x)) => { + | ^^^^^^^^^^^^^^^^ expected struct `Vec`, found `isize` + | + = note: expected enum `Option<Vec<isize>>` + found enum `Option<isize>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/pattern/rest-pat-semantic-disallowed.rs b/src/test/ui/pattern/rest-pat-semantic-disallowed.rs new file mode 100644 index 000000000..84552f2e7 --- /dev/null +++ b/src/test/ui/pattern/rest-pat-semantic-disallowed.rs @@ -0,0 +1,83 @@ +// Here we test that rest patterns, i.e. `..`, are not allowed +// outside of slice (+ ident patterns witin those), tuple, +// and tuple struct patterns and that duplicates are caught in these contexts. + +#![feature(box_patterns)] + +fn main() {} + +macro_rules! mk_pat { + () => { .. } //~ ERROR `..` patterns are not allowed here +} + +fn rest_patterns() { + let mk_pat!(); + + // Top level: + fn foo(..: u8) {} //~ ERROR `..` patterns are not allowed here + let ..; //~ ERROR `..` patterns are not allowed here + + // Box patterns: + let box ..; //~ ERROR `..` patterns are not allowed here + + // In or-patterns: + match 1 { + 1 | .. => {} //~ ERROR `..` patterns are not allowed here + } + + // Ref patterns: + let &..; //~ ERROR `..` patterns are not allowed here + let &mut ..; //~ ERROR `..` patterns are not allowed here + + // Ident patterns: + let x @ ..; //~ ERROR `..` patterns are not allowed here + //~^ ERROR type annotations needed + let ref x @ ..; //~ ERROR `..` patterns are not allowed here + let ref mut x @ ..; //~ ERROR `..` patterns are not allowed here + + // Tuple: + let (..): (u8,); // OK. + let (..,): (u8,); // OK. + let ( + .., + .., //~ ERROR `..` can only be used once per tuple pattern + .. //~ ERROR `..` can only be used once per tuple pattern + ): (u8, u8, u8); + let ( + .., + x, + .. //~ ERROR `..` can only be used once per tuple pattern + ): (u8, u8, u8); + + struct A(u8, u8, u8); + + // Tuple struct (same idea as for tuple patterns): + let A(..); // OK. + let A(..,); // OK. + let A( + .., + .., //~ ERROR `..` can only be used once per tuple struct pattern + .. //~ ERROR `..` can only be used once per tuple struct pattern + ); + let A( + .., + x, + .. //~ ERROR `..` can only be used once per tuple struct pattern + ); + + // Array/Slice: + let [..]: &[u8]; // OK. + let [..,]: &[u8]; // OK. + let [ + .., + .., //~ ERROR `..` can only be used once per slice pattern + .. //~ ERROR `..` can only be used once per slice pattern + ]: &[u8]; + let [ + .., + ref x @ .., //~ ERROR `..` can only be used once per slice pattern + ref mut y @ .., //~ ERROR `..` can only be used once per slice pattern + (ref z @ ..), //~ ERROR `..` patterns are not allowed here + .. //~ ERROR `..` can only be used once per slice pattern + ]: &[u8]; +} diff --git a/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr b/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr new file mode 100644 index 000000000..e6a4e5f19 --- /dev/null +++ b/src/test/ui/pattern/rest-pat-semantic-disallowed.stderr @@ -0,0 +1,201 @@ +error: `..` patterns are not allowed here + --> $DIR/rest-pat-semantic-disallowed.rs:10:13 + | +LL | () => { .. } + | ^^ +... +LL | let mk_pat!(); + | --------- in this macro invocation + | + = note: only allowed in tuple, tuple struct, and slice patterns + = note: this error originates in the macro `mk_pat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `..` patterns are not allowed here + --> $DIR/rest-pat-semantic-disallowed.rs:18:9 + | +LL | let ..; + | ^^ + | + = note: only allowed in tuple, tuple struct, and slice patterns + +error: `..` patterns are not allowed here + --> $DIR/rest-pat-semantic-disallowed.rs:21:13 + | +LL | let box ..; + | ^^ + | + = note: only allowed in tuple, tuple struct, and slice patterns + +error: `..` patterns are not allowed here + --> $DIR/rest-pat-semantic-disallowed.rs:25:13 + | +LL | 1 | .. => {} + | ^^ + | + = note: only allowed in tuple, tuple struct, and slice patterns + +error: `..` patterns are not allowed here + --> $DIR/rest-pat-semantic-disallowed.rs:29:10 + | +LL | let &..; + | ^^ + | + = note: only allowed in tuple, tuple struct, and slice patterns + +error: `..` patterns are not allowed here + --> $DIR/rest-pat-semantic-disallowed.rs:30:14 + | +LL | let &mut ..; + | ^^ + | + = note: only allowed in tuple, tuple struct, and slice patterns + +error: `..` patterns are not allowed here + --> $DIR/rest-pat-semantic-disallowed.rs:33:13 + | +LL | let x @ ..; + | ^^ + | + = note: only allowed in tuple, tuple struct, and slice patterns + +error: `..` patterns are not allowed here + --> $DIR/rest-pat-semantic-disallowed.rs:35:17 + | +LL | let ref x @ ..; + | ^^ + | + = note: only allowed in tuple, tuple struct, and slice patterns + +error: `..` patterns are not allowed here + --> $DIR/rest-pat-semantic-disallowed.rs:36:21 + | +LL | let ref mut x @ ..; + | ^^ + | + = note: only allowed in tuple, tuple struct, and slice patterns + +error: `..` can only be used once per tuple pattern + --> $DIR/rest-pat-semantic-disallowed.rs:43:9 + | +LL | .., + | -- previously used here +LL | .., + | ^^ can only be used once per tuple pattern + +error: `..` can only be used once per tuple pattern + --> $DIR/rest-pat-semantic-disallowed.rs:44:9 + | +LL | .., + | -- previously used here +LL | .., +LL | .. + | ^^ can only be used once per tuple pattern + +error: `..` can only be used once per tuple pattern + --> $DIR/rest-pat-semantic-disallowed.rs:49:9 + | +LL | .., + | -- previously used here +LL | x, +LL | .. + | ^^ can only be used once per tuple pattern + +error: `..` can only be used once per tuple struct pattern + --> $DIR/rest-pat-semantic-disallowed.rs:59:9 + | +LL | .., + | -- previously used here +LL | .., + | ^^ can only be used once per tuple struct pattern + +error: `..` can only be used once per tuple struct pattern + --> $DIR/rest-pat-semantic-disallowed.rs:60:9 + | +LL | .., + | -- previously used here +LL | .., +LL | .. + | ^^ can only be used once per tuple struct pattern + +error: `..` can only be used once per tuple struct pattern + --> $DIR/rest-pat-semantic-disallowed.rs:65:9 + | +LL | .., + | -- previously used here +LL | x, +LL | .. + | ^^ can only be used once per tuple struct pattern + +error: `..` can only be used once per slice pattern + --> $DIR/rest-pat-semantic-disallowed.rs:73:9 + | +LL | .., + | -- previously used here +LL | .., + | ^^ can only be used once per slice pattern + +error: `..` can only be used once per slice pattern + --> $DIR/rest-pat-semantic-disallowed.rs:74:9 + | +LL | .., + | -- previously used here +LL | .., +LL | .. + | ^^ can only be used once per slice pattern + +error: `..` can only be used once per slice pattern + --> $DIR/rest-pat-semantic-disallowed.rs:78:17 + | +LL | .., + | -- previously used here +LL | ref x @ .., + | ^^ can only be used once per slice pattern + +error: `..` can only be used once per slice pattern + --> $DIR/rest-pat-semantic-disallowed.rs:79:21 + | +LL | .., + | -- previously used here +LL | ref x @ .., +LL | ref mut y @ .., + | ^^ can only be used once per slice pattern + +error: `..` patterns are not allowed here + --> $DIR/rest-pat-semantic-disallowed.rs:80:18 + | +LL | (ref z @ ..), + | ^^ + | + = note: only allowed in tuple, tuple struct, and slice patterns + +error: `..` can only be used once per slice pattern + --> $DIR/rest-pat-semantic-disallowed.rs:81:9 + | +LL | .., + | -- previously used here +... +LL | .. + | ^^ can only be used once per slice pattern + +error: `..` patterns are not allowed here + --> $DIR/rest-pat-semantic-disallowed.rs:17:12 + | +LL | fn foo(..: u8) {} + | ^^ + | + = note: only allowed in tuple, tuple struct, and slice patterns + +error[E0282]: type annotations needed + --> $DIR/rest-pat-semantic-disallowed.rs:33:9 + | +LL | let x @ ..; + | ^^^^^^ + | +help: consider giving this pattern a type + | +LL | let x @ ..: _; + | +++ + +error: aborting due to 23 previous errors + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/pattern/rest-pat-syntactic.rs b/src/test/ui/pattern/rest-pat-syntactic.rs new file mode 100644 index 000000000..9656a0b5d --- /dev/null +++ b/src/test/ui/pattern/rest-pat-syntactic.rs @@ -0,0 +1,70 @@ +// Here we test that `..` is allowed in all pattern locations *syntactically*. +// The semantic test is in `rest-pat-semantic-disallowed.rs`. + +// check-pass + +fn main() {} + +macro_rules! accept_pat { + ($p:pat) => {} +} + +accept_pat!(..); + +#[cfg(FALSE)] +fn rest_patterns() { + // Top level: + fn foo(..: u8) {} + let ..; + + // Box patterns: + let box ..; + + // In or-patterns: + match x { + .. | .. => {} + } + + // Ref patterns: + let &..; + let &mut ..; + + // Ident patterns: + let x @ ..; + let ref x @ ..; + let ref mut x @ ..; + + // Tuple: + let (..); // This is interpreted as a tuple pattern, not a parenthesis one. + let (..,); // Allowing trailing comma. + let (.., .., ..); // Duplicates also. + let (.., P, ..); // Including with things in between. + + // Tuple struct (same idea as for tuple patterns): + let A(..); + let A(..,); + let A(.., .., ..); + let A(.., P, ..); + + // Array/Slice (like with tuple patterns): + let [..]; + let [..,]; + let [.., .., ..]; + let [.., P, ..]; + + // Random walk to guard against special casing: + match x { + .. | + [ + ( + box .., + &(..), + &mut .., + x @ .. + ), + ref x @ .., + ] | + ref mut x @ .. + => {} + } +} diff --git a/src/test/ui/pattern/size-and-align.rs b/src/test/ui/pattern/size-and-align.rs new file mode 100644 index 000000000..a32b5de72 --- /dev/null +++ b/src/test/ui/pattern/size-and-align.rs @@ -0,0 +1,20 @@ +// run-pass + +#![allow(non_camel_case_types)] +enum clam<T> { a(T, isize), b, } + +fn uhoh<T>(v: Vec<clam<T>> ) { + match v[1] { + clam::a::<T>(ref _t, ref u) => { + println!("incorrect"); + println!("{}", u); + panic!(); + } + clam::b::<T> => { println!("correct"); } + } +} + +pub fn main() { + let v: Vec<clam<isize>> = vec![clam::b::<isize>, clam::b::<isize>, clam::a::<isize>(42, 17)]; + uhoh::<isize>(v); +} diff --git a/src/test/ui/pattern/usefulness/always-inhabited-union-ref.rs b/src/test/ui/pattern/usefulness/always-inhabited-union-ref.rs new file mode 100644 index 000000000..7d1cac8a4 --- /dev/null +++ b/src/test/ui/pattern/usefulness/always-inhabited-union-ref.rs @@ -0,0 +1,32 @@ +// The precise semantics of inhabitedness with respect to unions and references is currently +// undecided. This test file currently checks a conservative choice. + +#![feature(exhaustive_patterns)] +#![feature(never_type)] + +#![allow(dead_code)] +#![allow(unreachable_code)] + +pub union Foo { + foo: !, +} + +fn uninhab_ref() -> &'static ! { + unimplemented!() +} + +fn uninhab_union() -> Foo { + unimplemented!() +} + +fn match_on_uninhab() { + match uninhab_ref() { + //~^ ERROR non-exhaustive patterns: type `&!` is non-empty + } + + match uninhab_union() { + //~^ ERROR non-exhaustive patterns: type `Foo` is non-empty + } +} + +fn main() {} diff --git a/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr b/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr new file mode 100644 index 000000000..cd5c283f9 --- /dev/null +++ b/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr @@ -0,0 +1,37 @@ +error[E0004]: non-exhaustive patterns: type `&!` is non-empty + --> $DIR/always-inhabited-union-ref.rs:23:11 + | +LL | match uninhab_ref() { + | ^^^^^^^^^^^^^ + | + = note: the matched value is of type `&!` + = note: references are always considered inhabited +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match uninhab_ref() { +LL + _ => todo!(), +LL + } + | + +error[E0004]: non-exhaustive patterns: type `Foo` is non-empty + --> $DIR/always-inhabited-union-ref.rs:27:11 + | +LL | match uninhab_union() { + | ^^^^^^^^^^^^^^^ + | +note: `Foo` defined here + --> $DIR/always-inhabited-union-ref.rs:10:11 + | +LL | pub union Foo { + | ^^^ + = note: the matched value is of type `Foo` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match uninhab_union() { +LL + _ => todo!(), +LL + } + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/auxiliary/empty.rs b/src/test/ui/pattern/usefulness/auxiliary/empty.rs new file mode 100644 index 000000000..29a03c9e8 --- /dev/null +++ b/src/test/ui/pattern/usefulness/auxiliary/empty.rs @@ -0,0 +1,10 @@ +#![crate_type = "rlib"] +pub enum EmptyForeignEnum {} + +pub struct VisiblyUninhabitedForeignStruct { + pub field: EmptyForeignEnum, +} + +pub struct SecretlyUninhabitedForeignStruct { + _priv: EmptyForeignEnum, +} diff --git a/src/test/ui/pattern/usefulness/auxiliary/hidden.rs b/src/test/ui/pattern/usefulness/auxiliary/hidden.rs new file mode 100644 index 000000000..364514ba1 --- /dev/null +++ b/src/test/ui/pattern/usefulness/auxiliary/hidden.rs @@ -0,0 +1,14 @@ +pub enum HiddenEnum { + A, + B, + #[doc(hidden)] + C, +} + +#[derive(Default)] +pub struct HiddenStruct { + pub one: u8, + pub two: bool, + #[doc(hidden)] + pub hide: usize, +} diff --git a/src/test/ui/pattern/usefulness/auxiliary/unstable.rs b/src/test/ui/pattern/usefulness/auxiliary/unstable.rs new file mode 100644 index 000000000..a06b3a6e4 --- /dev/null +++ b/src/test/ui/pattern/usefulness/auxiliary/unstable.rs @@ -0,0 +1,23 @@ +#![feature(staged_api)] +#![stable(feature = "stable_test_feature", since = "1.0.0")] + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub enum UnstableEnum { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Stable, + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Stable2, + #[unstable(feature = "unstable_test_feature", issue = "none")] + Unstable, +} + +#[derive(Default)] +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct UnstableStruct { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub stable: bool, + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub stable2: usize, + #[unstable(feature = "unstable_test_feature", issue = "none")] + pub unstable: u8, +} diff --git a/src/test/ui/pattern/usefulness/const-pat-ice.rs b/src/test/ui/pattern/usefulness/const-pat-ice.rs new file mode 100644 index 000000000..abfacf393 --- /dev/null +++ b/src/test/ui/pattern/usefulness/const-pat-ice.rs @@ -0,0 +1,11 @@ +// check-pass + +const FOO: &&&u32 = &&&42; + +fn main() { + match unimplemented!() { + &&&42 => {}, + FOO => {}, + _ => {}, + } +} diff --git a/src/test/ui/pattern/usefulness/const-private-fields.rs b/src/test/ui/pattern/usefulness/const-private-fields.rs new file mode 100644 index 000000000..06c832ca4 --- /dev/null +++ b/src/test/ui/pattern/usefulness/const-private-fields.rs @@ -0,0 +1,30 @@ +// check-pass +// +// Check that we don't ignore private fields in usefulness checking +#![deny(unreachable_patterns)] + +mod inner { + #[derive(PartialEq, Eq)] + pub struct PrivateField { + pub x: bool, + y: bool, + } + + pub const FOO: PrivateField = PrivateField { x: true, y: true }; + pub const BAR: PrivateField = PrivateField { x: true, y: false }; +} +use inner::*; + +fn main() { + match FOO { + FOO => {} + BAR => {} + _ => {} + } + + match FOO { + FOO => {} + PrivateField { x: true, .. } => {} + _ => {} + } +} diff --git a/src/test/ui/pattern/usefulness/consts-opaque.rs b/src/test/ui/pattern/usefulness/consts-opaque.rs new file mode 100644 index 000000000..ca4fcd85b --- /dev/null +++ b/src/test/ui/pattern/usefulness/consts-opaque.rs @@ -0,0 +1,145 @@ +// This file tests the exhaustiveness algorithm on opaque constants. Most of the examples give +// unnecessary warnings because const_to_pat.rs converts a constant pattern to a wildcard when the +// constant is not allowed as a pattern. This is an edge case so we may not care to fix it. +// See also https://github.com/rust-lang/rust/issues/78057 + +#![deny(unreachable_patterns)] + +#[derive(PartialEq)] +struct Foo(i32); +impl Eq for Foo {} +const FOO: Foo = Foo(42); +const FOO_REF: &Foo = &Foo(42); +const FOO_REF_REF: &&Foo = &&Foo(42); + +#[derive(PartialEq)] +struct Bar; +impl Eq for Bar {} +const BAR: Bar = Bar; + +#[derive(PartialEq)] +enum Baz { + Baz1, + Baz2 +} +impl Eq for Baz {} +const BAZ: Baz = Baz::Baz1; + +fn main() { + match FOO { + FOO => {} + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + _ => {} // should not be emitting unreachable warning + //~^ ERROR unreachable pattern + } + + match FOO_REF { + FOO_REF => {} + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + Foo(_) => {} // should not be emitting unreachable warning + //~^ ERROR unreachable pattern + } + + // This used to cause an ICE (https://github.com/rust-lang/rust/issues/78071) + match FOO_REF_REF { + FOO_REF_REF => {} + //~^ WARNING must be annotated with `#[derive(PartialEq, Eq)]` + //~| WARNING this was previously accepted by the compiler but is being phased out + Foo(_) => {} + } + + match BAR { + Bar => {} + BAR => {} // should not be emitting unreachable warning + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + //~| ERROR unreachable pattern + _ => {} + //~^ ERROR unreachable pattern + } + + match BAR { + BAR => {} + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + Bar => {} // should not be emitting unreachable warning + //~^ ERROR unreachable pattern + _ => {} + //~^ ERROR unreachable pattern + } + + match BAR { + BAR => {} + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + BAR => {} // should not be emitting unreachable warning + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + //~| ERROR unreachable pattern + _ => {} // should not be emitting unreachable warning + //~^ ERROR unreachable pattern + } + + match BAZ { + BAZ => {} + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + Baz::Baz1 => {} // should not be emitting unreachable warning + //~^ ERROR unreachable pattern + _ => {} + //~^ ERROR unreachable pattern + } + + match BAZ { + Baz::Baz1 => {} + BAZ => {} + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + _ => {} + //~^ ERROR unreachable pattern + } + + match BAZ { + BAZ => {} + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` + Baz::Baz2 => {} // should not be emitting unreachable warning + //~^ ERROR unreachable pattern + _ => {} // should not be emitting unreachable warning + //~^ ERROR unreachable pattern + } + + type Quux = fn(usize, usize) -> usize; + fn quux(a: usize, b: usize) -> usize { a + b } + const QUUX: Quux = quux; + + match QUUX { + QUUX => {} + QUUX => {} + _ => {} + } + + #[derive(PartialEq, Eq)] + struct Wrap<T>(T); + const WRAPQUUX: Wrap<Quux> = Wrap(quux); + + match WRAPQUUX { + WRAPQUUX => {} + WRAPQUUX => {} + Wrap(_) => {} + } + + match WRAPQUUX { + Wrap(_) => {} + WRAPQUUX => {} // detected unreachable because we do inspect the `Wrap` layer + //~^ ERROR unreachable pattern + } + + #[derive(PartialEq, Eq)] + enum WhoKnows<T> { + Yay(T), + Nope, + }; + const WHOKNOWSQUUX: WhoKnows<Quux> = WhoKnows::Yay(quux); + + match WHOKNOWSQUUX { + WHOKNOWSQUUX => {} + WhoKnows::Yay(_) => {} + WHOKNOWSQUUX => {} // detected unreachable because we do inspect the `WhoKnows` layer + //~^ ERROR unreachable pattern + WhoKnows::Nope => {} + } +} diff --git a/src/test/ui/pattern/usefulness/consts-opaque.stderr b/src/test/ui/pattern/usefulness/consts-opaque.stderr new file mode 100644 index 000000000..05c009a6f --- /dev/null +++ b/src/test/ui/pattern/usefulness/consts-opaque.stderr @@ -0,0 +1,202 @@ +error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/consts-opaque.rs:30:9 + | +LL | FOO => {} + | ^^^ + +error: unreachable pattern + --> $DIR/consts-opaque.rs:32:9 + | +LL | FOO => {} + | --- matches any value +LL | +LL | _ => {} // should not be emitting unreachable warning + | ^ unreachable pattern + | +note: the lint level is defined here + --> $DIR/consts-opaque.rs:6:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/consts-opaque.rs:37:9 + | +LL | FOO_REF => {} + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/consts-opaque.rs:39:9 + | +LL | FOO_REF => {} + | ------- matches any value +LL | +LL | Foo(_) => {} // should not be emitting unreachable warning + | ^^^^^^ unreachable pattern + +warning: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/consts-opaque.rs:45:9 + | +LL | FOO_REF_REF => {} + | ^^^^^^^^^^^ + | + = note: `#[warn(indirect_structural_match)]` on by default + = 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 `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/consts-opaque.rs:53:9 + | +LL | BAR => {} // should not be emitting unreachable warning + | ^^^ + +error: unreachable pattern + --> $DIR/consts-opaque.rs:53:9 + | +LL | Bar => {} + | --- matches any value +LL | BAR => {} // should not be emitting unreachable warning + | ^^^ unreachable pattern + +error: unreachable pattern + --> $DIR/consts-opaque.rs:56:9 + | +LL | Bar => {} + | --- matches any value +... +LL | _ => {} + | ^ unreachable pattern + +error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/consts-opaque.rs:61:9 + | +LL | BAR => {} + | ^^^ + +error: unreachable pattern + --> $DIR/consts-opaque.rs:63:9 + | +LL | BAR => {} + | --- matches any value +LL | +LL | Bar => {} // should not be emitting unreachable warning + | ^^^ unreachable pattern + +error: unreachable pattern + --> $DIR/consts-opaque.rs:65:9 + | +LL | BAR => {} + | --- matches any value +... +LL | _ => {} + | ^ unreachable pattern + +error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/consts-opaque.rs:70:9 + | +LL | BAR => {} + | ^^^ + +error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/consts-opaque.rs:72:9 + | +LL | BAR => {} // should not be emitting unreachable warning + | ^^^ + +error: unreachable pattern + --> $DIR/consts-opaque.rs:72:9 + | +LL | BAR => {} + | --- matches any value +LL | +LL | BAR => {} // should not be emitting unreachable warning + | ^^^ unreachable pattern + +error: unreachable pattern + --> $DIR/consts-opaque.rs:75:9 + | +LL | BAR => {} + | --- matches any value +... +LL | _ => {} // should not be emitting unreachable warning + | ^ unreachable pattern + +error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/consts-opaque.rs:80:9 + | +LL | BAZ => {} + | ^^^ + +error: unreachable pattern + --> $DIR/consts-opaque.rs:82:9 + | +LL | BAZ => {} + | --- matches any value +LL | +LL | Baz::Baz1 => {} // should not be emitting unreachable warning + | ^^^^^^^^^ unreachable pattern + +error: unreachable pattern + --> $DIR/consts-opaque.rs:84:9 + | +LL | BAZ => {} + | --- matches any value +... +LL | _ => {} + | ^ unreachable pattern + +error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/consts-opaque.rs:90:9 + | +LL | BAZ => {} + | ^^^ + +error: unreachable pattern + --> $DIR/consts-opaque.rs:92:9 + | +LL | BAZ => {} + | --- matches any value +LL | +LL | _ => {} + | ^ unreachable pattern + +error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/consts-opaque.rs:97:9 + | +LL | BAZ => {} + | ^^^ + +error: unreachable pattern + --> $DIR/consts-opaque.rs:99:9 + | +LL | BAZ => {} + | --- matches any value +LL | +LL | Baz::Baz2 => {} // should not be emitting unreachable warning + | ^^^^^^^^^ unreachable pattern + +error: unreachable pattern + --> $DIR/consts-opaque.rs:101:9 + | +LL | BAZ => {} + | --- matches any value +... +LL | _ => {} // should not be emitting unreachable warning + | ^ unreachable pattern + +error: unreachable pattern + --> $DIR/consts-opaque.rs:127:9 + | +LL | Wrap(_) => {} + | ------- matches any value +LL | WRAPQUUX => {} // detected unreachable because we do inspect the `Wrap` layer + | ^^^^^^^^ unreachable pattern + +error: unreachable pattern + --> $DIR/consts-opaque.rs:141:9 + | +LL | WHOKNOWSQUUX => {} // detected unreachable because we do inspect the `WhoKnows` layer + | ^^^^^^^^^^^^ + +error: aborting due to 24 previous errors; 1 warning emitted + diff --git a/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs b/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs new file mode 100644 index 000000000..c85af7f3b --- /dev/null +++ b/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs @@ -0,0 +1,16 @@ +#![feature(if_let_guard)] + +#![deny(irrefutable_let_patterns)] + +fn main() { + if let _ = 5 {} //~ ERROR irrefutable `if let` pattern + + while let _ = 5 { //~ ERROR irrefutable `while let` pattern + break; + } + + match 5 { + _ if let _ = 2 => {} //~ ERROR irrefutable `if let` guard pattern + _ => {} + } +} diff --git a/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr b/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr new file mode 100644 index 000000000..b97683526 --- /dev/null +++ b/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr @@ -0,0 +1,34 @@ +error: irrefutable `if let` pattern + --> $DIR/deny-irrefutable-let-patterns.rs:6:8 + | +LL | if let _ = 5 {} + | ^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/deny-irrefutable-let-patterns.rs:3:9 + | +LL | #![deny(irrefutable_let_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this pattern will always match, so the `if let` is useless + = help: consider replacing the `if let` with a `let` + +error: irrefutable `while let` pattern + --> $DIR/deny-irrefutable-let-patterns.rs:8:11 + | +LL | while let _ = 5 { + | ^^^^^^^^^ + | + = note: this pattern will always match, so the loop will never exit + = help: consider instead using a `loop { ... }` with a `let` inside it + +error: irrefutable `if let` guard pattern + --> $DIR/deny-irrefutable-let-patterns.rs:13:18 + | +LL | _ if let _ = 2 => {} + | ^ + | + = note: this pattern will always match, so the guard is useless + = help: consider removing the guard and adding a `let` inside the match arm + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/pattern/usefulness/doc-hidden-fields.rs b/src/test/ui/pattern/usefulness/doc-hidden-fields.rs new file mode 100644 index 000000000..4163b87dc --- /dev/null +++ b/src/test/ui/pattern/usefulness/doc-hidden-fields.rs @@ -0,0 +1,26 @@ +// aux-build:hidden.rs + +extern crate hidden; + +use hidden::HiddenStruct; + +struct InCrate { + a: usize, + b: bool, + #[doc(hidden)] + im_hidden: u8 +} + +fn main() { + let HiddenStruct { one, two } = HiddenStruct::default(); + //~^ pattern requires `..` due to inaccessible fields + + let HiddenStruct { one } = HiddenStruct::default(); + //~^ pattern does not mention field `two` and inaccessible fields + + let HiddenStruct { one, hide } = HiddenStruct::default(); + //~^ pattern does not mention field `two` + + let InCrate { a, b } = InCrate { a: 0, b: false, im_hidden: 0 }; + //~^ pattern does not mention field `im_hidden` +} diff --git a/src/test/ui/pattern/usefulness/doc-hidden-fields.stderr b/src/test/ui/pattern/usefulness/doc-hidden-fields.stderr new file mode 100644 index 000000000..f277bfbc8 --- /dev/null +++ b/src/test/ui/pattern/usefulness/doc-hidden-fields.stderr @@ -0,0 +1,59 @@ +error: pattern requires `..` due to inaccessible fields + --> $DIR/doc-hidden-fields.rs:15:9 + | +LL | let HiddenStruct { one, two } = HiddenStruct::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: ignore the inaccessible and unused fields + | +LL | let HiddenStruct { one, two, .. } = HiddenStruct::default(); + | ++++ + +error[E0027]: pattern does not mention field `two` and inaccessible fields + --> $DIR/doc-hidden-fields.rs:18:9 + | +LL | let HiddenStruct { one } = HiddenStruct::default(); + | ^^^^^^^^^^^^^^^^^^^^ missing field `two` and inaccessible fields + | +help: include the missing field in the pattern and ignore the inaccessible fields + | +LL | let HiddenStruct { one, two, .. } = HiddenStruct::default(); + | ~~~~~~~~~~~ +help: if you don't care about this missing field, you can explicitly ignore it + | +LL | let HiddenStruct { one, .. } = HiddenStruct::default(); + | ~~~~~~ + +error[E0027]: pattern does not mention field `two` + --> $DIR/doc-hidden-fields.rs:21:9 + | +LL | let HiddenStruct { one, hide } = HiddenStruct::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `two` + | +help: include the missing field in the pattern + | +LL | let HiddenStruct { one, hide, two } = HiddenStruct::default(); + | ~~~~~~~ +help: if you don't care about this missing field, you can explicitly ignore it + | +LL | let HiddenStruct { one, hide, .. } = HiddenStruct::default(); + | ~~~~~~ + +error[E0027]: pattern does not mention field `im_hidden` + --> $DIR/doc-hidden-fields.rs:24:9 + | +LL | let InCrate { a, b } = InCrate { a: 0, b: false, im_hidden: 0 }; + | ^^^^^^^^^^^^^^^^ missing field `im_hidden` + | +help: include the missing field in the pattern + | +LL | let InCrate { a, b, im_hidden } = InCrate { a: 0, b: false, im_hidden: 0 }; + | ~~~~~~~~~~~~~ +help: if you don't care about this missing field, you can explicitly ignore it + | +LL | let InCrate { a, b, .. } = InCrate { a: 0, b: false, im_hidden: 0 }; + | ~~~~~~ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0027`. diff --git a/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs b/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs new file mode 100644 index 000000000..d968c48fb --- /dev/null +++ b/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs @@ -0,0 +1,43 @@ +// aux-build:hidden.rs + +extern crate hidden; + +use hidden::HiddenEnum; + +enum InCrate { + A, + B, + #[doc(hidden)] + C, +} + +fn main() { + match HiddenEnum::A { + HiddenEnum::A => {} + HiddenEnum::B => {} + } + //~^^^^ non-exhaustive patterns: `_` not covered + + match HiddenEnum::A { + HiddenEnum::A => {} + HiddenEnum::C => {} + } + //~^^^^ non-exhaustive patterns: `B` not covered + + match HiddenEnum::A { + HiddenEnum::A => {} + } + //~^^^ non-exhaustive patterns: `B` and `_` not covered + + match None { + None => {} + Some(HiddenEnum::A) => {} + } + //~^^^^ non-exhaustive patterns: `Some(B)` and `Some(_)` not covered + + match InCrate::A { + InCrate::A => {} + InCrate::B => {} + } + //~^^^^ non-exhaustive patterns: `C` not covered +} diff --git a/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr b/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr new file mode 100644 index 000000000..643e734f9 --- /dev/null +++ b/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr @@ -0,0 +1,105 @@ +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/doc-hidden-non-exhaustive.rs:15:11 + | +LL | match HiddenEnum::A { + | ^^^^^^^^^^^^^ pattern `_` not covered + | +note: `HiddenEnum` defined here + --> $DIR/auxiliary/hidden.rs:1:1 + | +LL | pub enum HiddenEnum { + | ^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `HiddenEnum` +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 ~ HiddenEnum::B => {} +LL + _ => todo!() + | + +error[E0004]: non-exhaustive patterns: `B` not covered + --> $DIR/doc-hidden-non-exhaustive.rs:21:11 + | +LL | match HiddenEnum::A { + | ^^^^^^^^^^^^^ pattern `B` not covered + | +note: `HiddenEnum` defined here + --> $DIR/auxiliary/hidden.rs:3:5 + | +LL | pub enum HiddenEnum { + | ------------------- +LL | A, +LL | B, + | ^ not covered + = note: the matched value is of type `HiddenEnum` +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 ~ HiddenEnum::C => {} +LL + B => todo!() + | + +error[E0004]: non-exhaustive patterns: `B` and `_` not covered + --> $DIR/doc-hidden-non-exhaustive.rs:27:11 + | +LL | match HiddenEnum::A { + | ^^^^^^^^^^^^^ patterns `B` and `_` not covered + | +note: `HiddenEnum` defined here + --> $DIR/auxiliary/hidden.rs:3:5 + | +LL | pub enum HiddenEnum { + | ------------------- +LL | A, +LL | B, + | ^ not covered + = note: the matched value is of type `HiddenEnum` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ HiddenEnum::A => {} +LL + B | _ => todo!() + | + +error[E0004]: non-exhaustive patterns: `Some(B)` and `Some(_)` not covered + --> $DIR/doc-hidden-non-exhaustive.rs:32:11 + | +LL | match None { + | ^^^^ patterns `Some(B)` and `Some(_)` not covered + | +note: `Option<HiddenEnum>` defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | pub enum Option<T> { + | ------------------ +... +LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^^^ not covered + = note: the matched value is of type `Option<HiddenEnum>` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ Some(HiddenEnum::A) => {} +LL + Some(B) | Some(_) => todo!() + | + +error[E0004]: non-exhaustive patterns: `C` not covered + --> $DIR/doc-hidden-non-exhaustive.rs:38:11 + | +LL | match InCrate::A { + | ^^^^^^^^^^ pattern `C` not covered + | +note: `InCrate` defined here + --> $DIR/doc-hidden-non-exhaustive.rs:11:5 + | +LL | enum InCrate { + | ------- +... +LL | C, + | ^ not covered + = note: the matched value is of type `InCrate` +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 ~ InCrate::B => {} +LL + C => todo!() + | + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr b/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr new file mode 100644 index 000000000..d31ee0dbd --- /dev/null +++ b/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr @@ -0,0 +1,303 @@ +error: unreachable pattern + --> $DIR/empty-match.rs:37:9 + | +LL | _ => {}, + | ^ + | +note: the lint level is defined here + --> $DIR/empty-match.rs:8:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/empty-match.rs:40:9 + | +LL | _ if false => {}, + | ^ + +error: unreachable pattern + --> $DIR/empty-match.rs:47:9 + | +LL | _ => {}, + | ^ + +error: unreachable pattern + --> $DIR/empty-match.rs:50:9 + | +LL | _ if false => {}, + | ^ + +error: unreachable pattern + --> $DIR/empty-match.rs:57:9 + | +LL | _ => {}, + | ^ + +error: unreachable pattern + --> $DIR/empty-match.rs:60:9 + | +LL | _ if false => {}, + | ^ + +error[E0004]: non-exhaustive patterns: type `u8` is non-empty + --> $DIR/empty-match.rs:78:20 + | +LL | match_no_arms!(0u8); + | ^^^ + | + = note: the matched value is of type `u8` + = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern + +error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty + --> $DIR/empty-match.rs:79:20 + | +LL | match_no_arms!(NonEmptyStruct1); + | ^^^^^^^^^^^^^^^ + | +note: `NonEmptyStruct1` defined here + --> $DIR/empty-match.rs:14:8 + | +LL | struct NonEmptyStruct1; + | ^^^^^^^^^^^^^^^ + = note: the matched value is of type `NonEmptyStruct1` + = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern + +error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty + --> $DIR/empty-match.rs:80:20 + | +LL | match_no_arms!(NonEmptyStruct2(true)); + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: `NonEmptyStruct2` defined here + --> $DIR/empty-match.rs:15:8 + | +LL | struct NonEmptyStruct2(bool); + | ^^^^^^^^^^^^^^^ + = note: the matched value is of type `NonEmptyStruct2` + = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern + +error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty + --> $DIR/empty-match.rs:81:20 + | +LL | match_no_arms!((NonEmptyUnion1 { foo: () })); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: `NonEmptyUnion1` defined here + --> $DIR/empty-match.rs:16:7 + | +LL | union NonEmptyUnion1 { + | ^^^^^^^^^^^^^^ + = note: the matched value is of type `NonEmptyUnion1` + = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern + +error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty + --> $DIR/empty-match.rs:82:20 + | +LL | match_no_arms!((NonEmptyUnion2 { foo: () })); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: `NonEmptyUnion2` defined here + --> $DIR/empty-match.rs:19:7 + | +LL | union NonEmptyUnion2 { + | ^^^^^^^^^^^^^^ + = note: the matched value is of type `NonEmptyUnion2` + = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern + +error[E0004]: non-exhaustive patterns: `Foo(_)` not covered + --> $DIR/empty-match.rs:83:20 + | +LL | match_no_arms!(NonEmptyEnum1::Foo(true)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered + | +note: `NonEmptyEnum1` defined here + --> $DIR/empty-match.rs:24:5 + | +LL | enum NonEmptyEnum1 { + | ------------- +LL | Foo(bool), + | ^^^ not covered + = note: the matched value is of type `NonEmptyEnum1` + = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern + +error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered + --> $DIR/empty-match.rs:84:20 + | +LL | match_no_arms!(NonEmptyEnum2::Foo(true)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered + | +note: `NonEmptyEnum2` defined here + --> $DIR/empty-match.rs:27:5 + | +LL | enum NonEmptyEnum2 { + | ------------- +LL | Foo(bool), + | ^^^ not covered +LL | Bar, + | ^^^ not covered + = note: the matched value is of type `NonEmptyEnum2` + = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms + +error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered + --> $DIR/empty-match.rs:85:20 + | +LL | match_no_arms!(NonEmptyEnum5::V1); + | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered + | +note: `NonEmptyEnum5` defined here + --> $DIR/empty-match.rs:30:6 + | +LL | enum NonEmptyEnum5 { + | ^^^^^^^^^^^^^ + = note: the matched value is of type `NonEmptyEnum5` + = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/empty-match.rs:87:24 + | +LL | match_guarded_arm!(0u8); + | ^^^ pattern `_` not covered + | + = note: the matched value is of type `u8` +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 ~ _ if false => {} +LL + _ => todo!() + | + +error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered + --> $DIR/empty-match.rs:88:24 + | +LL | match_guarded_arm!(NonEmptyStruct1); + | ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered + | +note: `NonEmptyStruct1` defined here + --> $DIR/empty-match.rs:14:8 + | +LL | struct NonEmptyStruct1; + | ^^^^^^^^^^^^^^^ + = note: the matched value is of type `NonEmptyStruct1` +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 ~ _ if false => {} +LL + NonEmptyStruct1 => todo!() + | + +error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered + --> $DIR/empty-match.rs:89:24 + | +LL | match_guarded_arm!(NonEmptyStruct2(true)); + | ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered + | +note: `NonEmptyStruct2` defined here + --> $DIR/empty-match.rs:15:8 + | +LL | struct NonEmptyStruct2(bool); + | ^^^^^^^^^^^^^^^ + = note: the matched value is of type `NonEmptyStruct2` +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 ~ _ if false => {} +LL + NonEmptyStruct2(_) => todo!() + | + +error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered + --> $DIR/empty-match.rs:90:24 + | +LL | match_guarded_arm!((NonEmptyUnion1 { foo: () })); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered + | +note: `NonEmptyUnion1` defined here + --> $DIR/empty-match.rs:16:7 + | +LL | union NonEmptyUnion1 { + | ^^^^^^^^^^^^^^ + = note: the matched value is of type `NonEmptyUnion1` +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 ~ _ if false => {} +LL + NonEmptyUnion1 { .. } => todo!() + | + +error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered + --> $DIR/empty-match.rs:91:24 + | +LL | match_guarded_arm!((NonEmptyUnion2 { foo: () })); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered + | +note: `NonEmptyUnion2` defined here + --> $DIR/empty-match.rs:19:7 + | +LL | union NonEmptyUnion2 { + | ^^^^^^^^^^^^^^ + = note: the matched value is of type `NonEmptyUnion2` +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 ~ _ if false => {} +LL + NonEmptyUnion2 { .. } => todo!() + | + +error[E0004]: non-exhaustive patterns: `Foo(_)` not covered + --> $DIR/empty-match.rs:92:24 + | +LL | match_guarded_arm!(NonEmptyEnum1::Foo(true)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered + | +note: `NonEmptyEnum1` defined here + --> $DIR/empty-match.rs:24:5 + | +LL | enum NonEmptyEnum1 { + | ------------- +LL | Foo(bool), + | ^^^ not covered + = note: the matched value is of type `NonEmptyEnum1` +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 ~ _ if false => {} +LL + Foo(_) => todo!() + | + +error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered + --> $DIR/empty-match.rs:93:24 + | +LL | match_guarded_arm!(NonEmptyEnum2::Foo(true)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered + | +note: `NonEmptyEnum2` defined here + --> $DIR/empty-match.rs:27:5 + | +LL | enum NonEmptyEnum2 { + | ------------- +LL | Foo(bool), + | ^^^ not covered +LL | Bar, + | ^^^ not covered + = note: the matched value is of type `NonEmptyEnum2` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ _ if false => {} +LL + Foo(_) | Bar => todo!() + | + +error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered + --> $DIR/empty-match.rs:94:24 + | +LL | match_guarded_arm!(NonEmptyEnum5::V1); + | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered + | +note: `NonEmptyEnum5` defined here + --> $DIR/empty-match.rs:30:6 + | +LL | enum NonEmptyEnum5 { + | ^^^^^^^^^^^^^ + = note: the matched value is of type `NonEmptyEnum5` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms + | +LL ~ _ if false => {} +LL + _ => todo!() + | + +error: aborting due to 22 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/empty-match.normal.stderr b/src/test/ui/pattern/usefulness/empty-match.normal.stderr new file mode 100644 index 000000000..d31ee0dbd --- /dev/null +++ b/src/test/ui/pattern/usefulness/empty-match.normal.stderr @@ -0,0 +1,303 @@ +error: unreachable pattern + --> $DIR/empty-match.rs:37:9 + | +LL | _ => {}, + | ^ + | +note: the lint level is defined here + --> $DIR/empty-match.rs:8:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/empty-match.rs:40:9 + | +LL | _ if false => {}, + | ^ + +error: unreachable pattern + --> $DIR/empty-match.rs:47:9 + | +LL | _ => {}, + | ^ + +error: unreachable pattern + --> $DIR/empty-match.rs:50:9 + | +LL | _ if false => {}, + | ^ + +error: unreachable pattern + --> $DIR/empty-match.rs:57:9 + | +LL | _ => {}, + | ^ + +error: unreachable pattern + --> $DIR/empty-match.rs:60:9 + | +LL | _ if false => {}, + | ^ + +error[E0004]: non-exhaustive patterns: type `u8` is non-empty + --> $DIR/empty-match.rs:78:20 + | +LL | match_no_arms!(0u8); + | ^^^ + | + = note: the matched value is of type `u8` + = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern + +error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty + --> $DIR/empty-match.rs:79:20 + | +LL | match_no_arms!(NonEmptyStruct1); + | ^^^^^^^^^^^^^^^ + | +note: `NonEmptyStruct1` defined here + --> $DIR/empty-match.rs:14:8 + | +LL | struct NonEmptyStruct1; + | ^^^^^^^^^^^^^^^ + = note: the matched value is of type `NonEmptyStruct1` + = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern + +error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty + --> $DIR/empty-match.rs:80:20 + | +LL | match_no_arms!(NonEmptyStruct2(true)); + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: `NonEmptyStruct2` defined here + --> $DIR/empty-match.rs:15:8 + | +LL | struct NonEmptyStruct2(bool); + | ^^^^^^^^^^^^^^^ + = note: the matched value is of type `NonEmptyStruct2` + = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern + +error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty + --> $DIR/empty-match.rs:81:20 + | +LL | match_no_arms!((NonEmptyUnion1 { foo: () })); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: `NonEmptyUnion1` defined here + --> $DIR/empty-match.rs:16:7 + | +LL | union NonEmptyUnion1 { + | ^^^^^^^^^^^^^^ + = note: the matched value is of type `NonEmptyUnion1` + = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern + +error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty + --> $DIR/empty-match.rs:82:20 + | +LL | match_no_arms!((NonEmptyUnion2 { foo: () })); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: `NonEmptyUnion2` defined here + --> $DIR/empty-match.rs:19:7 + | +LL | union NonEmptyUnion2 { + | ^^^^^^^^^^^^^^ + = note: the matched value is of type `NonEmptyUnion2` + = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern + +error[E0004]: non-exhaustive patterns: `Foo(_)` not covered + --> $DIR/empty-match.rs:83:20 + | +LL | match_no_arms!(NonEmptyEnum1::Foo(true)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered + | +note: `NonEmptyEnum1` defined here + --> $DIR/empty-match.rs:24:5 + | +LL | enum NonEmptyEnum1 { + | ------------- +LL | Foo(bool), + | ^^^ not covered + = note: the matched value is of type `NonEmptyEnum1` + = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern + +error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered + --> $DIR/empty-match.rs:84:20 + | +LL | match_no_arms!(NonEmptyEnum2::Foo(true)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered + | +note: `NonEmptyEnum2` defined here + --> $DIR/empty-match.rs:27:5 + | +LL | enum NonEmptyEnum2 { + | ------------- +LL | Foo(bool), + | ^^^ not covered +LL | Bar, + | ^^^ not covered + = note: the matched value is of type `NonEmptyEnum2` + = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms + +error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered + --> $DIR/empty-match.rs:85:20 + | +LL | match_no_arms!(NonEmptyEnum5::V1); + | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered + | +note: `NonEmptyEnum5` defined here + --> $DIR/empty-match.rs:30:6 + | +LL | enum NonEmptyEnum5 { + | ^^^^^^^^^^^^^ + = note: the matched value is of type `NonEmptyEnum5` + = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/empty-match.rs:87:24 + | +LL | match_guarded_arm!(0u8); + | ^^^ pattern `_` not covered + | + = note: the matched value is of type `u8` +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 ~ _ if false => {} +LL + _ => todo!() + | + +error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered + --> $DIR/empty-match.rs:88:24 + | +LL | match_guarded_arm!(NonEmptyStruct1); + | ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered + | +note: `NonEmptyStruct1` defined here + --> $DIR/empty-match.rs:14:8 + | +LL | struct NonEmptyStruct1; + | ^^^^^^^^^^^^^^^ + = note: the matched value is of type `NonEmptyStruct1` +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 ~ _ if false => {} +LL + NonEmptyStruct1 => todo!() + | + +error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered + --> $DIR/empty-match.rs:89:24 + | +LL | match_guarded_arm!(NonEmptyStruct2(true)); + | ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered + | +note: `NonEmptyStruct2` defined here + --> $DIR/empty-match.rs:15:8 + | +LL | struct NonEmptyStruct2(bool); + | ^^^^^^^^^^^^^^^ + = note: the matched value is of type `NonEmptyStruct2` +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 ~ _ if false => {} +LL + NonEmptyStruct2(_) => todo!() + | + +error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered + --> $DIR/empty-match.rs:90:24 + | +LL | match_guarded_arm!((NonEmptyUnion1 { foo: () })); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered + | +note: `NonEmptyUnion1` defined here + --> $DIR/empty-match.rs:16:7 + | +LL | union NonEmptyUnion1 { + | ^^^^^^^^^^^^^^ + = note: the matched value is of type `NonEmptyUnion1` +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 ~ _ if false => {} +LL + NonEmptyUnion1 { .. } => todo!() + | + +error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered + --> $DIR/empty-match.rs:91:24 + | +LL | match_guarded_arm!((NonEmptyUnion2 { foo: () })); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered + | +note: `NonEmptyUnion2` defined here + --> $DIR/empty-match.rs:19:7 + | +LL | union NonEmptyUnion2 { + | ^^^^^^^^^^^^^^ + = note: the matched value is of type `NonEmptyUnion2` +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 ~ _ if false => {} +LL + NonEmptyUnion2 { .. } => todo!() + | + +error[E0004]: non-exhaustive patterns: `Foo(_)` not covered + --> $DIR/empty-match.rs:92:24 + | +LL | match_guarded_arm!(NonEmptyEnum1::Foo(true)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered + | +note: `NonEmptyEnum1` defined here + --> $DIR/empty-match.rs:24:5 + | +LL | enum NonEmptyEnum1 { + | ------------- +LL | Foo(bool), + | ^^^ not covered + = note: the matched value is of type `NonEmptyEnum1` +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 ~ _ if false => {} +LL + Foo(_) => todo!() + | + +error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered + --> $DIR/empty-match.rs:93:24 + | +LL | match_guarded_arm!(NonEmptyEnum2::Foo(true)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered + | +note: `NonEmptyEnum2` defined here + --> $DIR/empty-match.rs:27:5 + | +LL | enum NonEmptyEnum2 { + | ------------- +LL | Foo(bool), + | ^^^ not covered +LL | Bar, + | ^^^ not covered + = note: the matched value is of type `NonEmptyEnum2` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ _ if false => {} +LL + Foo(_) | Bar => todo!() + | + +error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered + --> $DIR/empty-match.rs:94:24 + | +LL | match_guarded_arm!(NonEmptyEnum5::V1); + | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered + | +note: `NonEmptyEnum5` defined here + --> $DIR/empty-match.rs:30:6 + | +LL | enum NonEmptyEnum5 { + | ^^^^^^^^^^^^^ + = note: the matched value is of type `NonEmptyEnum5` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms + | +LL ~ _ if false => {} +LL + _ => todo!() + | + +error: aborting due to 22 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/empty-match.rs b/src/test/ui/pattern/usefulness/empty-match.rs new file mode 100644 index 000000000..8110ec013 --- /dev/null +++ b/src/test/ui/pattern/usefulness/empty-match.rs @@ -0,0 +1,95 @@ +// aux-build:empty.rs +// revisions: normal exhaustive_patterns +// +// This tests a match with no arms on various types. +#![feature(never_type)] +#![feature(never_type_fallback)] +#![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))] +#![deny(unreachable_patterns)] + +extern crate empty; + +enum EmptyEnum {} + +struct NonEmptyStruct1; +struct NonEmptyStruct2(bool); +union NonEmptyUnion1 { + foo: (), +} +union NonEmptyUnion2 { + foo: (), + bar: (), +} +enum NonEmptyEnum1 { + Foo(bool), +} +enum NonEmptyEnum2 { + Foo(bool), + Bar, +} +enum NonEmptyEnum5 { + V1, V2, V3, V4, V5, +} + +fn empty_enum(x: EmptyEnum) { + match x {} // ok + match x { + _ => {}, //~ ERROR unreachable pattern + } + match x { + _ if false => {}, //~ ERROR unreachable pattern + } +} + +fn empty_foreign_enum(x: empty::EmptyForeignEnum) { + match x {} // ok + match x { + _ => {}, //~ ERROR unreachable pattern + } + match x { + _ if false => {}, //~ ERROR unreachable pattern + } +} + +fn never(x: !) { + match x {} // ok + match x { + _ => {}, //~ ERROR unreachable pattern + } + match x { + _ if false => {}, //~ ERROR unreachable pattern + } +} + +macro_rules! match_no_arms { + ($e:expr) => { + match $e {} + }; +} +macro_rules! match_guarded_arm { + ($e:expr) => { + match $e { + _ if false => {} + } + }; +} + +fn main() { + match_no_arms!(0u8); //~ ERROR type `u8` is non-empty + match_no_arms!(NonEmptyStruct1); //~ ERROR type `NonEmptyStruct1` is non-empty + match_no_arms!(NonEmptyStruct2(true)); //~ ERROR type `NonEmptyStruct2` is non-empty + match_no_arms!((NonEmptyUnion1 { foo: () })); //~ ERROR type `NonEmptyUnion1` is non-empty + match_no_arms!((NonEmptyUnion2 { foo: () })); //~ ERROR type `NonEmptyUnion2` is non-empty + match_no_arms!(NonEmptyEnum1::Foo(true)); //~ ERROR `Foo(_)` not covered + match_no_arms!(NonEmptyEnum2::Foo(true)); //~ ERROR `Foo(_)` and `Bar` not covered + match_no_arms!(NonEmptyEnum5::V1); //~ ERROR `V1`, `V2`, `V3` and 2 more not covered + + match_guarded_arm!(0u8); //~ ERROR `_` not covered + match_guarded_arm!(NonEmptyStruct1); //~ ERROR `NonEmptyStruct1` not covered + match_guarded_arm!(NonEmptyStruct2(true)); //~ ERROR `NonEmptyStruct2(_)` not covered + match_guarded_arm!((NonEmptyUnion1 { foo: () })); //~ ERROR `NonEmptyUnion1 { .. }` not covered + match_guarded_arm!((NonEmptyUnion2 { foo: () })); //~ ERROR `NonEmptyUnion2 { .. }` not covered + match_guarded_arm!(NonEmptyEnum1::Foo(true)); //~ ERROR `Foo(_)` not covered + match_guarded_arm!(NonEmptyEnum2::Foo(true)); //~ ERROR `Foo(_)` and `Bar` not covered + match_guarded_arm!(NonEmptyEnum5::V1); //~ ERROR `V1`, `V2`, `V3` and 2 more not covered +} diff --git a/src/test/ui/pattern/usefulness/floats.rs b/src/test/ui/pattern/usefulness/floats.rs new file mode 100644 index 000000000..095f5ac9a --- /dev/null +++ b/src/test/ui/pattern/usefulness/floats.rs @@ -0,0 +1,19 @@ +#![allow(illegal_floating_point_literal_pattern)] +#![deny(unreachable_patterns)] + +fn main() { + match 0.0 { + 0.0..=1.0 => {} + _ => {} // ok + } + + match 0.0 { //~ ERROR non-exhaustive patterns + 0.0..=1.0 => {} + } + + match 1.0f64 { + 0.01f64 ..= 6.5f64 => {} + 0.02f64 => {} //~ ERROR unreachable pattern + _ => {} + }; +} diff --git a/src/test/ui/pattern/usefulness/floats.stderr b/src/test/ui/pattern/usefulness/floats.stderr new file mode 100644 index 000000000..c926e50b3 --- /dev/null +++ b/src/test/ui/pattern/usefulness/floats.stderr @@ -0,0 +1,28 @@ +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/floats.rs:10:11 + | +LL | match 0.0 { + | ^^^ pattern `_` not covered + | + = note: the matched value is of type `f64` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ 0.0..=1.0 => {} +LL + _ => todo!() + | + +error: unreachable pattern + --> $DIR/floats.rs:16:7 + | +LL | 0.02f64 => {} + | ^^^^^^^ + | +note: the lint level is defined here + --> $DIR/floats.rs:2:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/guards.rs b/src/test/ui/pattern/usefulness/guards.rs new file mode 100644 index 000000000..b15440cf6 --- /dev/null +++ b/src/test/ui/pattern/usefulness/guards.rs @@ -0,0 +1,22 @@ +#![feature(exclusive_range_pattern)] +#![deny(unreachable_patterns)] + +enum Q { R(Option<usize>) } + +pub fn main() { + match Q::R(None) { + Q::R(S) if S.is_some() => {} + _ => {} + } + + match 0u8 { //~ ERROR non-exhaustive patterns + 0 .. 128 => {} + 128 ..= 255 if true => {} + } + + match 0u8 { + 0 .. 128 => {} + 128 ..= 255 if false => {} + 128 ..= 255 => {} // ok, because previous arm was guarded + } +} diff --git a/src/test/ui/pattern/usefulness/guards.stderr b/src/test/ui/pattern/usefulness/guards.stderr new file mode 100644 index 000000000..0c1563c16 --- /dev/null +++ b/src/test/ui/pattern/usefulness/guards.stderr @@ -0,0 +1,16 @@ +error[E0004]: non-exhaustive patterns: `128_u8..=u8::MAX` not covered + --> $DIR/guards.rs:12:11 + | +LL | match 0u8 { + | ^^^ pattern `128_u8..=u8::MAX` not covered + | + = note: the matched value is of type `u8` +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 ~ 128 ..= 255 if true => {} +LL + 128_u8..=u8::MAX => todo!() + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.rs b/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.rs new file mode 100644 index 000000000..0f5f49c4c --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.rs @@ -0,0 +1,101 @@ +#![feature(exclusive_range_pattern)] +#![allow(overlapping_range_endpoints)] +#![deny(unreachable_patterns)] + +macro_rules! m { + ($s:expr, $($t:tt)+) => { + match $s { $($t)+ => {} } + } +} + +macro_rules! test_int { + ($s:expr, $min:path, $max:path) => { + m!($s, $min..=$max); + m!($s, $min..5 | 5..=$max); + m!($s, $min..=4 | 5..=$max); + m!($s, $min..$max | $max); + m!(($s, true), ($min..5, true) | (5..=$max, true) | ($min..=$max, false)); + } +} + +fn main() { + test_int!(0u8, u8::MIN, u8::MAX); + test_int!(0u16, u16::MIN, u16::MAX); + test_int!(0u32, u32::MIN, u32::MAX); + test_int!(0u64, u64::MIN, u64::MAX); + test_int!(0u128, u128::MIN, u128::MAX); + + test_int!(0i8, i8::MIN, i8::MAX); + test_int!(0i16, i16::MIN, i16::MAX); + test_int!(0i32, i32::MIN, i32::MAX); + test_int!(0i64, i64::MIN, i64::MAX); + test_int!(0i128, i128::MIN, i128::MAX); + + m!('a', '\u{0}'..=char::MAX); + m!('a', '\u{0}'..='\u{10_FFFF}'); + // We can get away with just covering the following two ranges, which correspond to all valid + // Unicode Scalar Values. + m!('a', '\u{0}'..='\u{D7FF}' | '\u{E000}'..=char::MAX); + m!('a', '\u{0}'..'\u{D7FF}' | '\u{D7FF}' | '\u{E000}'..=char::MAX); + + let 0..=255 = 0u8; + let -128..=127 = 0i8; + let -2147483648..=2147483647 = 0i32; + let '\u{0000}'..='\u{10FFFF}' = 'v'; + + // Almost exhaustive + m!(0u8, 0..255); //~ ERROR non-exhaustive patterns + m!(0u8, 0..=254); //~ ERROR non-exhaustive patterns + m!(0u8, 1..=255); //~ ERROR non-exhaustive patterns + m!(0u8, 0..42 | 43..=255); //~ ERROR non-exhaustive patterns + m!(0i8, -128..127); //~ ERROR non-exhaustive patterns + m!(0i8, -128..=126); //~ ERROR non-exhaustive patterns + m!(0i8, -127..=127); //~ ERROR non-exhaustive patterns + match 0i8 { //~ ERROR non-exhaustive patterns + i8::MIN ..= -1 => {} + 1 ..= i8::MAX => {} + } + const ALMOST_MAX: u128 = u128::MAX - 1; + m!(0u128, 0..=ALMOST_MAX); //~ ERROR non-exhaustive patterns + m!(0u128, 0..=4); //~ ERROR non-exhaustive patterns + m!(0u128, 1..=u128::MAX); //~ ERROR non-exhaustive patterns + + // More complicatedly (non-)exhaustive + match 0u8 { + 0 ..= 30 => {} + 20 ..= 70 => {} + 50 ..= 255 => {} + } + match (0u8, true) { //~ ERROR non-exhaustive patterns + (0 ..= 125, false) => {} + (128 ..= 255, false) => {} + (0 ..= 255, true) => {} + } + match (0u8, true) { // ok + (0 ..= 125, false) => {} + (128 ..= 255, false) => {} + (0 ..= 255, true) => {} + (125 .. 128, false) => {} + } + match (true, 0u8) { + (true, 0 ..= 255) => {} + (false, 0 ..= 125) => {} + (false, 128 ..= 255) => {} + (false, 125 .. 128) => {} + } + match Some(0u8) { + None => {} + Some(0 ..= 125) => {} + Some(128 ..= 255) => {} + Some(125 .. 128) => {} + } + const FOO: u8 = 41; + const BAR: &u8 = &42; + match &0u8 { + 0..41 => {} + &FOO => {} + BAR => {} + 43..=255 => {} + } + +} diff --git a/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr b/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr new file mode 100644 index 000000000..f30ba05df --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr @@ -0,0 +1,149 @@ +error[E0004]: non-exhaustive patterns: `u8::MAX` not covered + --> $DIR/exhaustiveness.rs:47:8 + | +LL | m!(0u8, 0..255); + | ^^^ pattern `u8::MAX` not covered + | + = note: the matched value is of type `u8` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL | match $s { $($t)+ => {}, u8::MAX => todo!() } + | ++++++++++++++++++++ + +error[E0004]: non-exhaustive patterns: `u8::MAX` not covered + --> $DIR/exhaustiveness.rs:48:8 + | +LL | m!(0u8, 0..=254); + | ^^^ pattern `u8::MAX` not covered + | + = note: the matched value is of type `u8` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL | match $s { $($t)+ => {}, u8::MAX => todo!() } + | ++++++++++++++++++++ + +error[E0004]: non-exhaustive patterns: `0_u8` not covered + --> $DIR/exhaustiveness.rs:49:8 + | +LL | m!(0u8, 1..=255); + | ^^^ pattern `0_u8` not covered + | + = note: the matched value is of type `u8` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL | match $s { $($t)+ => {}, 0_u8 => todo!() } + | +++++++++++++++++ + +error[E0004]: non-exhaustive patterns: `42_u8` not covered + --> $DIR/exhaustiveness.rs:50:8 + | +LL | m!(0u8, 0..42 | 43..=255); + | ^^^ pattern `42_u8` not covered + | + = note: the matched value is of type `u8` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL | match $s { $($t)+ => {}, 42_u8 => todo!() } + | ++++++++++++++++++ + +error[E0004]: non-exhaustive patterns: `i8::MAX` not covered + --> $DIR/exhaustiveness.rs:51:8 + | +LL | m!(0i8, -128..127); + | ^^^ pattern `i8::MAX` not covered + | + = note: the matched value is of type `i8` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL | match $s { $($t)+ => {}, i8::MAX => todo!() } + | ++++++++++++++++++++ + +error[E0004]: non-exhaustive patterns: `i8::MAX` not covered + --> $DIR/exhaustiveness.rs:52:8 + | +LL | m!(0i8, -128..=126); + | ^^^ pattern `i8::MAX` not covered + | + = note: the matched value is of type `i8` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL | match $s { $($t)+ => {}, i8::MAX => todo!() } + | ++++++++++++++++++++ + +error[E0004]: non-exhaustive patterns: `i8::MIN` not covered + --> $DIR/exhaustiveness.rs:53:8 + | +LL | m!(0i8, -127..=127); + | ^^^ pattern `i8::MIN` not covered + | + = note: the matched value is of type `i8` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL | match $s { $($t)+ => {}, i8::MIN => todo!() } + | ++++++++++++++++++++ + +error[E0004]: non-exhaustive patterns: `0_i8` not covered + --> $DIR/exhaustiveness.rs:54:11 + | +LL | match 0i8 { + | ^^^ pattern `0_i8` not covered + | + = note: the matched value is of type `i8` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ 1 ..= i8::MAX => {} +LL + 0_i8 => todo!() + | + +error[E0004]: non-exhaustive patterns: `u128::MAX` not covered + --> $DIR/exhaustiveness.rs:59:8 + | +LL | m!(0u128, 0..=ALMOST_MAX); + | ^^^^^ pattern `u128::MAX` not covered + | + = note: the matched value is of type `u128` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL | match $s { $($t)+ => {}, u128::MAX => todo!() } + | ++++++++++++++++++++++ + +error[E0004]: non-exhaustive patterns: `5_u128..=u128::MAX` not covered + --> $DIR/exhaustiveness.rs:60:8 + | +LL | m!(0u128, 0..=4); + | ^^^^^ pattern `5_u128..=u128::MAX` not covered + | + = note: the matched value is of type `u128` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL | match $s { $($t)+ => {}, 5_u128..=u128::MAX => todo!() } + | +++++++++++++++++++++++++++++++ + +error[E0004]: non-exhaustive patterns: `0_u128` not covered + --> $DIR/exhaustiveness.rs:61:8 + | +LL | m!(0u128, 1..=u128::MAX); + | ^^^^^ pattern `0_u128` not covered + | + = note: the matched value is of type `u128` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL | match $s { $($t)+ => {}, 0_u128 => todo!() } + | +++++++++++++++++++ + +error[E0004]: non-exhaustive patterns: `(126_u8..=127_u8, false)` not covered + --> $DIR/exhaustiveness.rs:69:11 + | +LL | match (0u8, true) { + | ^^^^^^^^^^^ pattern `(126_u8..=127_u8, false)` not covered + | + = note: the matched value is of type `(u8, bool)` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ (0 ..= 255, true) => {} +LL + (126_u8..=127_u8, false) => todo!() + | + +error: aborting due to 12 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs new file mode 100644 index 000000000..5ea92b070 --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs @@ -0,0 +1,59 @@ +#![feature(exclusive_range_pattern)] +#![deny(overlapping_range_endpoints)] + +macro_rules! m { + ($s:expr, $t1:pat, $t2:pat) => { + match $s { + $t1 => {} + $t2 => {} + _ => {} + } + } +} + +fn main() { + m!(0u8, 20..=30, 30..=40); //~ ERROR multiple patterns overlap on their endpoints + m!(0u8, 30..=40, 20..=30); //~ ERROR multiple patterns overlap on their endpoints + m!(0u8, 20..=30, 31..=40); + m!(0u8, 20..=30, 29..=40); + m!(0u8, 20.. 30, 29..=40); //~ ERROR multiple patterns overlap on their endpoints + m!(0u8, 20.. 30, 28..=40); + m!(0u8, 20.. 30, 30..=40); + m!(0u8, 20..=30, 30..=30); + m!(0u8, 20..=30, 30..=31); //~ ERROR multiple patterns overlap on their endpoints + m!(0u8, 20..=30, 29..=30); + m!(0u8, 20..=30, 20..=20); + m!(0u8, 20..=30, 20..=21); + m!(0u8, 20..=30, 19..=20); //~ ERROR multiple patterns overlap on their endpoints + m!(0u8, 20..=30, 20); + m!(0u8, 20..=30, 25); + m!(0u8, 20..=30, 30); + m!(0u8, 20.. 30, 29); + m!(0u8, 20, 20..=30); + m!(0u8, 25, 20..=30); + m!(0u8, 30, 20..=30); + + match 0u8 { + 0..=10 => {} + 20..=30 => {} + 10..=20 => {} //~ ERROR multiple patterns overlap on their endpoints + _ => {} + } + match (0u8, true) { + (0..=10, true) => {} + (10..20, true) => {} // not detected + (10..20, false) => {} + _ => {} + } + match (true, 0u8) { + (true, 0..=10) => {} + (true, 10..20) => {} //~ ERROR multiple patterns overlap on their endpoints + (false, 10..20) => {} + _ => {} + } + match Some(0u8) { + Some(0..=10) => {} + Some(10..20) => {} //~ ERROR multiple patterns overlap on their endpoints + _ => {} + } +} diff --git a/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr new file mode 100644 index 000000000..24c0419e1 --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr @@ -0,0 +1,89 @@ +error: multiple patterns overlap on their endpoints + --> $DIR/overlapping_range_endpoints.rs:15:22 + | +LL | m!(0u8, 20..=30, 30..=40); + | ------- ^^^^^^^ ... with this range + | | + | this range overlaps on `30_u8`... + | +note: the lint level is defined here + --> $DIR/overlapping_range_endpoints.rs:2:9 + | +LL | #![deny(overlapping_range_endpoints)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: you likely meant to write mutually exclusive ranges + +error: multiple patterns overlap on their endpoints + --> $DIR/overlapping_range_endpoints.rs:16:22 + | +LL | m!(0u8, 30..=40, 20..=30); + | ------- ^^^^^^^ ... with this range + | | + | this range overlaps on `30_u8`... + | + = note: you likely meant to write mutually exclusive ranges + +error: multiple patterns overlap on their endpoints + --> $DIR/overlapping_range_endpoints.rs:19:22 + | +LL | m!(0u8, 20.. 30, 29..=40); + | ------- ^^^^^^^ ... with this range + | | + | this range overlaps on `29_u8`... + | + = note: you likely meant to write mutually exclusive ranges + +error: multiple patterns overlap on their endpoints + --> $DIR/overlapping_range_endpoints.rs:23:22 + | +LL | m!(0u8, 20..=30, 30..=31); + | ------- ^^^^^^^ ... with this range + | | + | this range overlaps on `30_u8`... + | + = note: you likely meant to write mutually exclusive ranges + +error: multiple patterns overlap on their endpoints + --> $DIR/overlapping_range_endpoints.rs:27:22 + | +LL | m!(0u8, 20..=30, 19..=20); + | ------- ^^^^^^^ ... with this range + | | + | this range overlaps on `20_u8`... + | + = note: you likely meant to write mutually exclusive ranges + +error: multiple patterns overlap on their endpoints + --> $DIR/overlapping_range_endpoints.rs:39:9 + | +LL | 0..=10 => {} + | ------ this range overlaps on `10_u8`... +LL | 20..=30 => {} + | ------- this range overlaps on `20_u8`... +LL | 10..=20 => {} + | ^^^^^^^ ... with this range + | + = note: you likely meant to write mutually exclusive ranges + +error: multiple patterns overlap on their endpoints + --> $DIR/overlapping_range_endpoints.rs:50:16 + | +LL | (true, 0..=10) => {} + | ------ this range overlaps on `10_u8`... +LL | (true, 10..20) => {} + | ^^^^^^ ... with this range + | + = note: you likely meant to write mutually exclusive ranges + +error: multiple patterns overlap on their endpoints + --> $DIR/overlapping_range_endpoints.rs:56:14 + | +LL | Some(0..=10) => {} + | ------ this range overlaps on `10_u8`... +LL | Some(10..20) => {} + | ^^^^^^ ... with this range + | + = note: you likely meant to write mutually exclusive ranges + +error: aborting due to 8 previous errors + diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr new file mode 100644 index 000000000..9f277fa1e --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr @@ -0,0 +1,17 @@ +error[E0004]: non-exhaustive patterns: type `usize` is non-empty + --> $DIR/pointer-sized-int.rs:48:11 + | +LL | match 7usize {} + | ^^^^^^ + | + = note: the matched value is of type `usize` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match 7usize { +LL + _ => todo!(), +LL + } + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr new file mode 100644 index 000000000..e3eb98ccd --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr @@ -0,0 +1,170 @@ +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int.rs:12:11 + | +LL | match 0usize { + | ^^^^^^ pattern `_` not covered + | + = note: the matched value is of type `usize` + = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ 0 ..= usize::MAX => {} +LL + _ => todo!() + | + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int.rs:17:11 + | +LL | match 0isize { + | ^^^^^^ pattern `_` not covered + | + = note: the matched value is of type `isize` + = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ isize::MIN ..= isize::MAX => {} +LL + _ => todo!() + | + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int.rs:22:8 + | +LL | m!(0usize, 0..=usize::MAX); + | ^^^^^^ pattern `_` not covered + | + = note: the matched value is of type `usize` + = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL | match $s { $($t)+ => {}, _ => todo!() } + | ++++++++++++++ + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int.rs:24:8 + | +LL | m!(0usize, 0..5 | 5..=usize::MAX); + | ^^^^^^ pattern `_` not covered + | + = note: the matched value is of type `usize` + = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL | match $s { $($t)+ => {}, _ => todo!() } + | ++++++++++++++ + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int.rs:26:8 + | +LL | m!(0usize, 0..usize::MAX | usize::MAX); + | ^^^^^^ pattern `_` not covered + | + = note: the matched value is of type `usize` + = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL | match $s { $($t)+ => {}, _ => todo!() } + | ++++++++++++++ + +error[E0004]: non-exhaustive patterns: `(_, _)` not covered + --> $DIR/pointer-sized-int.rs:28:8 + | +LL | m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false)); + | ^^^^^^^^^^^^^^ pattern `(_, _)` not covered + | + = note: the matched value is of type `(usize, bool)` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL | match $s { $($t)+ => {}, (_, _) => todo!() } + | +++++++++++++++++++ + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int.rs:31:8 + | +LL | m!(0isize, isize::MIN..=isize::MAX); + | ^^^^^^ pattern `_` not covered + | + = note: the matched value is of type `isize` + = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL | match $s { $($t)+ => {}, _ => todo!() } + | ++++++++++++++ + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int.rs:33:8 + | +LL | m!(0isize, isize::MIN..5 | 5..=isize::MAX); + | ^^^^^^ pattern `_` not covered + | + = note: the matched value is of type `isize` + = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL | match $s { $($t)+ => {}, _ => todo!() } + | ++++++++++++++ + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int.rs:35:8 + | +LL | m!(0isize, isize::MIN..isize::MAX | isize::MAX); + | ^^^^^^ pattern `_` not covered + | + = note: the matched value is of type `isize` + = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL | match $s { $($t)+ => {}, _ => todo!() } + | ++++++++++++++ + +error[E0004]: non-exhaustive patterns: `(_, _)` not covered + --> $DIR/pointer-sized-int.rs:37:8 + | +LL | m!((0isize, true), (isize::MIN..5, true) + | ^^^^^^^^^^^^^^ pattern `(_, _)` not covered + | + = note: the matched value is of type `(isize, bool)` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL | match $s { $($t)+ => {}, (_, _) => todo!() } + | +++++++++++++++++++ + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int.rs:41:11 + | +LL | match 0isize { + | ^^^^^^ pattern `_` not covered + | + = note: the matched value is of type `isize` + = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ 1 ..= isize::MAX => {} +LL + _ => todo!() + | + +error[E0004]: non-exhaustive patterns: type `usize` is non-empty + --> $DIR/pointer-sized-int.rs:48:11 + | +LL | match 7usize {} + | ^^^^^^ + | + = note: the matched value is of type `usize` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match 7usize { +LL + _ => todo!(), +LL + } + | + +error: aborting due to 12 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs new file mode 100644 index 000000000..1ed18c267 --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs @@ -0,0 +1,50 @@ +// revisions: allow deny +#![feature(exclusive_range_pattern)] +#![cfg_attr(allow, feature(precise_pointer_size_matching))] + +macro_rules! m { + ($s:expr, $($t:tt)+) => { + match $s { $($t)+ => {} } + } +} + +fn main() { + match 0usize { + //[deny]~^ ERROR non-exhaustive patterns + 0 ..= usize::MAX => {} + } + + match 0isize { + //[deny]~^ ERROR non-exhaustive patterns + isize::MIN ..= isize::MAX => {} + } + + m!(0usize, 0..=usize::MAX); + //[deny]~^ ERROR non-exhaustive patterns + m!(0usize, 0..5 | 5..=usize::MAX); + //[deny]~^ ERROR non-exhaustive patterns + m!(0usize, 0..usize::MAX | usize::MAX); + //[deny]~^ ERROR non-exhaustive patterns + m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false)); + //[deny]~^ ERROR non-exhaustive patterns + + m!(0isize, isize::MIN..=isize::MAX); + //[deny]~^ ERROR non-exhaustive patterns + m!(0isize, isize::MIN..5 | 5..=isize::MAX); + //[deny]~^ ERROR non-exhaustive patterns + m!(0isize, isize::MIN..isize::MAX | isize::MAX); + //[deny]~^ ERROR non-exhaustive patterns + m!((0isize, true), (isize::MIN..5, true) + | (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false)); + //[deny]~^^ ERROR non-exhaustive patterns + + match 0isize { + //[deny]~^ ERROR non-exhaustive patterns + isize::MIN ..= -1 => {} + 0 => {} + 1 ..= isize::MAX => {} + } + + match 7usize {} + //~^ ERROR non-exhaustive patterns +} diff --git a/src/test/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.rs b/src/test/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.rs new file mode 100644 index 000000000..a2aa655ca --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.rs @@ -0,0 +1,18 @@ +// This tests that the lint message explains the reason for the error. +fn main() { + match 0usize { + //~^ ERROR non-exhaustive patterns: `_` not covered + //~| NOTE pattern `_` not covered + //~| NOTE the matched value is of type `usize` + //~| NOTE `usize` does not have a fixed maximum value + 0..=usize::MAX => {} + } + + match 0isize { + //~^ ERROR non-exhaustive patterns: `_` not covered + //~| NOTE pattern `_` not covered + //~| NOTE the matched value is of type `isize` + //~| NOTE `isize` does not have a fixed maximum value + isize::MIN..=isize::MAX => {} + } +} diff --git a/src/test/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr b/src/test/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr new file mode 100644 index 000000000..30492c982 --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr @@ -0,0 +1,33 @@ +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/precise_pointer_matching-message.rs:3:11 + | +LL | match 0usize { + | ^^^^^^ pattern `_` not covered + | + = note: the matched value is of type `usize` + = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ 0..=usize::MAX => {} +LL + _ => todo!() + | + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/precise_pointer_matching-message.rs:11:11 + | +LL | match 0isize { + | ^^^^^^ pattern `_` not covered + | + = note: the matched value is of type `isize` + = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ isize::MIN..=isize::MAX => {} +LL + _ => todo!() + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/integer-ranges/reachability.rs b/src/test/ui/pattern/usefulness/integer-ranges/reachability.rs new file mode 100644 index 000000000..fb4d59b05 --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/reachability.rs @@ -0,0 +1,113 @@ +#![feature(exclusive_range_pattern)] +#![allow(overlapping_range_endpoints)] +#![deny(unreachable_patterns)] + +macro_rules! m { + ($s:expr, $t1:pat, $t2:pat) => { + match $s { + $t1 => {} + $t2 => {} + _ => {} + } + } +} + +fn main() { + m!(0u8, 42, 41); + m!(0u8, 42, 42); //~ ERROR unreachable pattern + m!(0u8, 42, 43); + + m!(0u8, 20..=30, 19); + m!(0u8, 20..=30, 20); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 21); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 25); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 29); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 30); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 31); + m!(0u8, 20..30, 19); + m!(0u8, 20..30, 20); //~ ERROR unreachable pattern + m!(0u8, 20..30, 21); //~ ERROR unreachable pattern + m!(0u8, 20..30, 25); //~ ERROR unreachable pattern + m!(0u8, 20..30, 29); //~ ERROR unreachable pattern + m!(0u8, 20..30, 30); + m!(0u8, 20..30, 31); + + m!(0u8, 20..=30, 20..=30); //~ ERROR unreachable pattern + m!(0u8, 20.. 30, 20.. 30); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 20.. 30); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 19..=30); + m!(0u8, 20..=30, 21..=30); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 20..=29); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 20..=31); + m!('a', 'A'..='z', 'a'..='z'); //~ ERROR unreachable pattern + + match 0u8 { + 5 => {}, + 6 => {}, + 7 => {}, + 8 => {}, + 5..=8 => {}, //~ ERROR unreachable pattern + _ => {}, + } + match 0u8 { + 0..10 => {}, + 10..20 => {}, + 5..15 => {}, //~ ERROR unreachable pattern + _ => {}, + } + match 0u8 { + 0..10 => {}, + 10..20 => {}, + 20..30 => {}, + 5..25 => {}, //~ ERROR unreachable pattern + _ => {}, + } + match 0u8 { + 0..10 => {}, + 10 => {}, + 11..=23 => {}, + 19..30 => {}, + 5..25 => {}, //~ ERROR unreachable pattern + _ => {}, + } + match 0usize { + 0..10 => {}, + 10..20 => {}, + 5..15 => {}, //~ ERROR unreachable pattern + _ => {}, + } + // Chars between '\u{D7FF}' and '\u{E000}' are invalid even though ranges that contain them are + // allowed. + match 'a' { + _ => {}, + '\u{D7FF}'..='\u{E000}' => {}, //~ ERROR unreachable pattern + } + match 'a' { + '\u{0}'..='\u{D7FF}' => {}, + '\u{E000}'..='\u{10_FFFF}' => {}, + '\u{D7FF}'..='\u{E000}' => {}, // FIXME should be unreachable + } + + match (0u8, true) { + (0..=255, false) => {} + (0..=255, true) => {} // ok + } + match (true, 0u8) { + (false, 0..=255) => {} + (true, 0..=255) => {} // ok + } + + const FOO: i32 = 42; + const BAR: &i32 = &42; + match &0 { + &42 => {} + &FOO => {} //~ ERROR unreachable pattern + BAR => {} //~ ERROR unreachable pattern + _ => {} + } + // Regression test, see https://github.com/rust-lang/rust/pull/66326#issuecomment-552889933 + match &0 { + BAR => {} // ok + _ => {} + } +} diff --git a/src/test/ui/pattern/usefulness/integer-ranges/reachability.stderr b/src/test/ui/pattern/usefulness/integer-ranges/reachability.stderr new file mode 100644 index 000000000..0ffb0ffd8 --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/reachability.stderr @@ -0,0 +1,154 @@ +error: unreachable pattern + --> $DIR/reachability.rs:17:17 + | +LL | m!(0u8, 42, 42); + | ^^ + | +note: the lint level is defined here + --> $DIR/reachability.rs:3:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:21:22 + | +LL | m!(0u8, 20..=30, 20); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:22:22 + | +LL | m!(0u8, 20..=30, 21); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:23:22 + | +LL | m!(0u8, 20..=30, 25); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:24:22 + | +LL | m!(0u8, 20..=30, 29); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:25:22 + | +LL | m!(0u8, 20..=30, 30); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:28:21 + | +LL | m!(0u8, 20..30, 20); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:29:21 + | +LL | m!(0u8, 20..30, 21); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:30:21 + | +LL | m!(0u8, 20..30, 25); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:31:21 + | +LL | m!(0u8, 20..30, 29); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:35:22 + | +LL | m!(0u8, 20..=30, 20..=30); + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:36:22 + | +LL | m!(0u8, 20.. 30, 20.. 30); + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:37:22 + | +LL | m!(0u8, 20..=30, 20.. 30); + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:39:22 + | +LL | m!(0u8, 20..=30, 21..=30); + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:40:22 + | +LL | m!(0u8, 20..=30, 20..=29); + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:42:24 + | +LL | m!('a', 'A'..='z', 'a'..='z'); + | ^^^^^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:49:9 + | +LL | 5..=8 => {}, + | ^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:55:9 + | +LL | 5..15 => {}, + | ^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:62:9 + | +LL | 5..25 => {}, + | ^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:70:9 + | +LL | 5..25 => {}, + | ^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:76:9 + | +LL | 5..15 => {}, + | ^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:83:9 + | +LL | _ => {}, + | - matches any value +LL | '\u{D7FF}'..='\u{E000}' => {}, + | ^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern + +error: unreachable pattern + --> $DIR/reachability.rs:104:9 + | +LL | &FOO => {} + | ^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:105:9 + | +LL | BAR => {} + | ^^^ + +error: aborting due to 24 previous errors + diff --git a/src/test/ui/pattern/usefulness/irrefutable-let-patterns.rs b/src/test/ui/pattern/usefulness/irrefutable-let-patterns.rs new file mode 100644 index 000000000..d400ef0bb --- /dev/null +++ b/src/test/ui/pattern/usefulness/irrefutable-let-patterns.rs @@ -0,0 +1,11 @@ +// run-pass + +#![allow(irrefutable_let_patterns)] + +fn main() { + if let _ = 5 {} + + while let _ = 5 { + break; + } +} diff --git a/src/test/ui/pattern/usefulness/irrefutable-unit.rs b/src/test/ui/pattern/usefulness/irrefutable-unit.rs new file mode 100644 index 000000000..dd8f03b6d --- /dev/null +++ b/src/test/ui/pattern/usefulness/irrefutable-unit.rs @@ -0,0 +1,6 @@ +// run-pass +// pretty-expanded FIXME #23616 + +pub fn main() { + let ((),()) = ((),()); +} diff --git a/src/test/ui/pattern/usefulness/issue-12116.rs b/src/test/ui/pattern/usefulness/issue-12116.rs new file mode 100644 index 000000000..3cb92a540 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-12116.rs @@ -0,0 +1,21 @@ +#![feature(box_patterns)] +#![allow(dead_code)] +#![allow(unused_variables)] +#![deny(unreachable_patterns)] + + +enum IntList { + Cons(isize, Box<IntList>), + Nil +} + +fn tail(source_list: &IntList) -> IntList { + match source_list { + &IntList::Cons(val, box ref next_list) => tail(next_list), + &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, Box::new(IntList::Nil)), + //~^ ERROR unreachable pattern + _ => panic!(), + } +} + +fn main() {} diff --git a/src/test/ui/pattern/usefulness/issue-12116.stderr b/src/test/ui/pattern/usefulness/issue-12116.stderr new file mode 100644 index 000000000..7f15c4703 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-12116.stderr @@ -0,0 +1,14 @@ +error: unreachable pattern + --> $DIR/issue-12116.rs:15:9 + | +LL | &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, Box::new(IntList::Nil)), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/issue-12116.rs:4:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/pattern/usefulness/issue-12369.rs b/src/test/ui/pattern/usefulness/issue-12369.rs new file mode 100644 index 000000000..0481c1fd9 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-12369.rs @@ -0,0 +1,11 @@ +#![deny(unreachable_patterns)] + +fn main() { + let sl = vec![1,2,3]; + let v: isize = match &*sl { + &[] => 0, + &[a,b,c] => 3, + &[a, ref rest @ ..] => a, + &[10,a, ref rest @ ..] => 10 //~ ERROR: unreachable pattern + }; +} diff --git a/src/test/ui/pattern/usefulness/issue-12369.stderr b/src/test/ui/pattern/usefulness/issue-12369.stderr new file mode 100644 index 000000000..aab2be78c --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-12369.stderr @@ -0,0 +1,14 @@ +error: unreachable pattern + --> $DIR/issue-12369.rs:9:9 + | +LL | &[10,a, ref rest @ ..] => 10 + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/issue-12369.rs:1:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/pattern/usefulness/issue-13727.rs b/src/test/ui/pattern/usefulness/issue-13727.rs new file mode 100644 index 000000000..7fb565ef3 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-13727.rs @@ -0,0 +1,15 @@ +#![allow(overflowing_literals)] +#![deny(unreachable_patterns)] + +fn test(val: u8) { + match val { + 256 => print!("0b1110\n"), + 512 => print!("0b1111\n"), + //~^ ERROR: unreachable pattern + _ => print!("fail\n"), + } +} + +fn main() { + test(1); +} diff --git a/src/test/ui/pattern/usefulness/issue-13727.stderr b/src/test/ui/pattern/usefulness/issue-13727.stderr new file mode 100644 index 000000000..07ca56a56 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-13727.stderr @@ -0,0 +1,14 @@ +error: unreachable pattern + --> $DIR/issue-13727.rs:7:5 + | +LL | 512 => print!("0b1111\n"), + | ^^^ + | +note: the lint level is defined here + --> $DIR/issue-13727.rs:2:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/pattern/usefulness/issue-15129.rs b/src/test/ui/pattern/usefulness/issue-15129.rs new file mode 100644 index 000000000..d2b72a86b --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-15129.rs @@ -0,0 +1,17 @@ +pub enum T { + T1(()), + T2(()), +} + +pub enum V { + V1(isize), + V2(bool), +} + +fn main() { + match (T::T1(()), V::V2(true)) { + //~^ ERROR non-exhaustive patterns: `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered + (T::T1(()), V::V1(i)) => (), + (T::T2(()), V::V2(b)) => (), + } +} diff --git a/src/test/ui/pattern/usefulness/issue-15129.stderr b/src/test/ui/pattern/usefulness/issue-15129.stderr new file mode 100644 index 000000000..af60f3ff5 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-15129.stderr @@ -0,0 +1,16 @@ +error[E0004]: non-exhaustive patterns: `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered + --> $DIR/issue-15129.rs:12:11 + | +LL | match (T::T1(()), V::V2(true)) { + | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered + | + = note: the matched value is of type `(T, V)` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ (T::T2(()), V::V2(b)) => (), +LL ~ (T1(()), V2(_)) | (T2(()), V1(_)) => todo!(), + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-2111.rs b/src/test/ui/pattern/usefulness/issue-2111.rs new file mode 100644 index 000000000..d27beaeff --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-2111.rs @@ -0,0 +1,11 @@ +fn foo(a: Option<usize>, b: Option<usize>) { + match (a, b) { + //~^ ERROR: non-exhaustive patterns: `(None, None)` and `(Some(_), Some(_))` not covered + (Some(a), Some(b)) if a == b => {} + (Some(_), None) | (None, Some(_)) => {} + } +} + +fn main() { + foo(None, None); +} diff --git a/src/test/ui/pattern/usefulness/issue-2111.stderr b/src/test/ui/pattern/usefulness/issue-2111.stderr new file mode 100644 index 000000000..01890b73c --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-2111.stderr @@ -0,0 +1,16 @@ +error[E0004]: non-exhaustive patterns: `(None, None)` and `(Some(_), Some(_))` not covered + --> $DIR/issue-2111.rs:2:11 + | +LL | match (a, b) { + | ^^^^^^ patterns `(None, None)` and `(Some(_), Some(_))` not covered + | + = note: the matched value is of type `(Option<usize>, Option<usize>)` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ (Some(_), None) | (None, Some(_)) => {} +LL + (None, None) | (Some(_), Some(_)) => todo!() + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-30240-b.rs b/src/test/ui/pattern/usefulness/issue-30240-b.rs new file mode 100644 index 000000000..01a6e7d8c --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-30240-b.rs @@ -0,0 +1,15 @@ +#![deny(unreachable_patterns)] + +fn main() { + match "world" { + "hello" => {} + _ => {}, + } + + match "world" { + ref _x if false => {} + "hello" => {} + "hello" => {} //~ ERROR unreachable pattern + _ => {}, + } +} diff --git a/src/test/ui/pattern/usefulness/issue-30240-b.stderr b/src/test/ui/pattern/usefulness/issue-30240-b.stderr new file mode 100644 index 000000000..59d64bc25 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-30240-b.stderr @@ -0,0 +1,14 @@ +error: unreachable pattern + --> $DIR/issue-30240-b.rs:12:9 + | +LL | "hello" => {} + | ^^^^^^^ + | +note: the lint level is defined here + --> $DIR/issue-30240-b.rs:1:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/pattern/usefulness/issue-30240-rpass.rs b/src/test/ui/pattern/usefulness/issue-30240-rpass.rs new file mode 100644 index 000000000..ab16614fd --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-30240-rpass.rs @@ -0,0 +1,14 @@ +// run-pass +fn main() { + let &ref a = &[0i32] as &[_]; + assert_eq!(a, &[0i32] as &[_]); + + let &ref a = "hello"; + assert_eq!(a, "hello"); + + match "foo" { + "fool" => unreachable!(), + "foo" => {}, + ref _x => unreachable!() + } +} diff --git a/src/test/ui/pattern/usefulness/issue-30240.rs b/src/test/ui/pattern/usefulness/issue-30240.rs new file mode 100644 index 000000000..a0c0d1626 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-30240.rs @@ -0,0 +1,10 @@ +fn main() { + match "world" { //~ ERROR non-exhaustive patterns: `&_` + "hello" => {} + } + + match "world" { //~ ERROR non-exhaustive patterns: `&_` + ref _x if false => {} + "hello" => {} + } +} diff --git a/src/test/ui/pattern/usefulness/issue-30240.stderr b/src/test/ui/pattern/usefulness/issue-30240.stderr new file mode 100644 index 000000000..759fdeafe --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-30240.stderr @@ -0,0 +1,29 @@ +error[E0004]: non-exhaustive patterns: `&_` not covered + --> $DIR/issue-30240.rs:2:11 + | +LL | match "world" { + | ^^^^^^^ pattern `&_` not covered + | + = note: the matched value is of type `&str` +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 ~ "hello" => {} +LL + &_ => todo!() + | + +error[E0004]: non-exhaustive patterns: `&_` not covered + --> $DIR/issue-30240.rs:6:11 + | +LL | match "world" { + | ^^^^^^^ pattern `&_` not covered + | + = note: the matched value is of type `&str` +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 ~ "hello" => {} +LL + &_ => todo!() + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-3096-1.rs b/src/test/ui/pattern/usefulness/issue-3096-1.rs new file mode 100644 index 000000000..edc3b3223 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-3096-1.rs @@ -0,0 +1,3 @@ +fn main() { + match () { } //~ ERROR non-exhaustive +} diff --git a/src/test/ui/pattern/usefulness/issue-3096-1.stderr b/src/test/ui/pattern/usefulness/issue-3096-1.stderr new file mode 100644 index 000000000..d8884394f --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-3096-1.stderr @@ -0,0 +1,17 @@ +error[E0004]: non-exhaustive patterns: type `()` is non-empty + --> $DIR/issue-3096-1.rs:2:11 + | +LL | match () { } + | ^^ + | + = note: the matched value is of type `()` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match () { +LL + _ => todo!(), +LL ~ } + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-3096-2.rs b/src/test/ui/pattern/usefulness/issue-3096-2.rs new file mode 100644 index 000000000..a26e42580 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-3096-2.rs @@ -0,0 +1,6 @@ +enum Bottom { } + +fn main() { + let x = &() as *const () as *const Bottom; + match x { } //~ ERROR non-exhaustive patterns +} diff --git a/src/test/ui/pattern/usefulness/issue-3096-2.stderr b/src/test/ui/pattern/usefulness/issue-3096-2.stderr new file mode 100644 index 000000000..2df8911ba --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-3096-2.stderr @@ -0,0 +1,17 @@ +error[E0004]: non-exhaustive patterns: type `*const Bottom` is non-empty + --> $DIR/issue-3096-2.rs:5:11 + | +LL | match x { } + | ^ + | + = note: the matched value is of type `*const Bottom` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match x { +LL + _ => todo!(), +LL ~ } + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-31221.rs b/src/test/ui/pattern/usefulness/issue-31221.rs new file mode 100644 index 000000000..e03f1ec5b --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-31221.rs @@ -0,0 +1,34 @@ +#![allow(dead_code)] +#![allow(unused_variables)] +#![allow(non_snake_case)] +#![deny(unreachable_patterns)] + +#[derive(Clone, Copy)] +enum Enum { + Var1, + Var2, +} + +fn main() { + use Enum::*; + let s = Var1; + match s { + Var1 => (), + Var3 => (), + Var2 => (), + //~^ ERROR unreachable pattern + }; + match &s { + &Var1 => (), + &Var3 => (), + &Var2 => (), + //~^ ERROR unreachable pattern + }; + let t = (Var1, Var1); + match t { + (Var1, b) => (), + (c, d) => (), + anything => () + //~^ ERROR unreachable pattern + }; +} diff --git a/src/test/ui/pattern/usefulness/issue-31221.stderr b/src/test/ui/pattern/usefulness/issue-31221.stderr new file mode 100644 index 000000000..7d3491444 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-31221.stderr @@ -0,0 +1,32 @@ +error: unreachable pattern + --> $DIR/issue-31221.rs:18:9 + | +LL | Var3 => (), + | ---- matches any value +LL | Var2 => (), + | ^^^^ unreachable pattern + | +note: the lint level is defined here + --> $DIR/issue-31221.rs:4:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/issue-31221.rs:24:9 + | +LL | &Var3 => (), + | ----- matches any value +LL | &Var2 => (), + | ^^^^^ unreachable pattern + +error: unreachable pattern + --> $DIR/issue-31221.rs:31:9 + | +LL | (c, d) => (), + | ------ matches any value +LL | anything => () + | ^^^^^^^^ unreachable pattern + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/pattern/usefulness/issue-31561.rs b/src/test/ui/pattern/usefulness/issue-31561.rs new file mode 100644 index 000000000..813b2409c --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-31561.rs @@ -0,0 +1,10 @@ +enum Thing { + Foo(u8), + Bar, + Baz +} + +fn main() { + let Thing::Foo(y) = Thing::Foo(1); + //~^ ERROR refutable pattern in local binding: `Bar` and `Baz` not covered +} diff --git a/src/test/ui/pattern/usefulness/issue-31561.stderr b/src/test/ui/pattern/usefulness/issue-31561.stderr new file mode 100644 index 000000000..9da6b5eee --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-31561.stderr @@ -0,0 +1,31 @@ +error[E0005]: refutable pattern in local binding: `Bar` and `Baz` not covered + --> $DIR/issue-31561.rs:8:9 + | +LL | let Thing::Foo(y) = Thing::Foo(1); + | ^^^^^^^^^^^^^ patterns `Bar` and `Baz` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +note: `Thing` defined here + --> $DIR/issue-31561.rs:3:5 + | +LL | enum Thing { + | ----- +LL | Foo(u8), +LL | Bar, + | ^^^ not covered +LL | Baz + | ^^^ not covered + = note: the matched value is of type `Thing` +help: you might want to use `if let` to ignore the variants that aren't matched + | +LL | let y = if let Thing::Foo(y) = Thing::Foo(1) { y } else { todo!() }; + | ++++++++++ ++++++++++++++++++++++ +help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched + | +LL | let Thing::Foo(y) = Thing::Foo(1) else { todo!() }; + | ++++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0005`. diff --git a/src/test/ui/pattern/usefulness/issue-35609.rs b/src/test/ui/pattern/usefulness/issue-35609.rs new file mode 100644 index 000000000..8ef75e351 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-35609.rs @@ -0,0 +1,43 @@ +enum Enum { + A, B, C, D, E, F +} +use Enum::*; + +struct S(Enum, ()); +struct Sd { x: Enum, y: () } + +fn main() { + match (A, ()) { //~ ERROR non-exhaustive + (A, _) => {} + } + + match (A, A) { //~ ERROR non-exhaustive + (_, A) => {} + } + + match ((A, ()), ()) { //~ ERROR non-exhaustive + ((A, ()), _) => {} + } + + match ((A, ()), A) { //~ ERROR non-exhaustive + ((A, ()), _) => {} + } + + match ((A, ()), ()) { //~ ERROR non-exhaustive + ((A, _), _) => {} + } + + + match S(A, ()) { //~ ERROR non-exhaustive + S(A, _) => {} + } + + match (Sd { x: A, y: () }) { //~ ERROR non-exhaustive + Sd { x: A, y: _ } => {} + } + + match Some(A) { //~ ERROR non-exhaustive + Some(A) => (), + None => () + } +} diff --git a/src/test/ui/pattern/usefulness/issue-35609.stderr b/src/test/ui/pattern/usefulness/issue-35609.stderr new file mode 100644 index 000000000..2247b818d --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-35609.stderr @@ -0,0 +1,122 @@ +error[E0004]: non-exhaustive patterns: `(B, _)`, `(C, _)`, `(D, _)` and 2 more not covered + --> $DIR/issue-35609.rs:10:11 + | +LL | match (A, ()) { + | ^^^^^^^ patterns `(B, _)`, `(C, _)`, `(D, _)` and 2 more not covered + | + = note: the matched value is of type `(Enum, ())` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms + | +LL ~ (A, _) => {} +LL + _ => todo!() + | + +error[E0004]: non-exhaustive patterns: `(_, B)`, `(_, C)`, `(_, D)` and 2 more not covered + --> $DIR/issue-35609.rs:14:11 + | +LL | match (A, A) { + | ^^^^^^ patterns `(_, B)`, `(_, C)`, `(_, D)` and 2 more not covered + | + = note: the matched value is of type `(Enum, Enum)` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms + | +LL ~ (_, A) => {} +LL + _ => todo!() + | + +error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered + --> $DIR/issue-35609.rs:18:11 + | +LL | match ((A, ()), ()) { + | ^^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered + | + = note: the matched value is of type `((Enum, ()), ())` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms + | +LL ~ ((A, ()), _) => {} +LL + _ => todo!() + | + +error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered + --> $DIR/issue-35609.rs:22:11 + | +LL | match ((A, ()), A) { + | ^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered + | + = note: the matched value is of type `((Enum, ()), Enum)` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms + | +LL ~ ((A, ()), _) => {} +LL + _ => todo!() + | + +error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered + --> $DIR/issue-35609.rs:26:11 + | +LL | match ((A, ()), ()) { + | ^^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered + | + = note: the matched value is of type `((Enum, ()), ())` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms + | +LL ~ ((A, _), _) => {} +LL + _ => todo!() + | + +error[E0004]: non-exhaustive patterns: `S(B, _)`, `S(C, _)`, `S(D, _)` and 2 more not covered + --> $DIR/issue-35609.rs:31:11 + | +LL | match S(A, ()) { + | ^^^^^^^^ patterns `S(B, _)`, `S(C, _)`, `S(D, _)` and 2 more not covered + | +note: `S` defined here + --> $DIR/issue-35609.rs:6:8 + | +LL | struct S(Enum, ()); + | ^ + = note: the matched value is of type `S` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms + | +LL ~ S(A, _) => {} +LL + _ => todo!() + | + +error[E0004]: non-exhaustive patterns: `Sd { x: B, .. }`, `Sd { x: C, .. }`, `Sd { x: D, .. }` and 2 more not covered + --> $DIR/issue-35609.rs:35:11 + | +LL | match (Sd { x: A, y: () }) { + | ^^^^^^^^^^^^^^^^^^^^ patterns `Sd { x: B, .. }`, `Sd { x: C, .. }`, `Sd { x: D, .. }` and 2 more not covered + | +note: `Sd` defined here + --> $DIR/issue-35609.rs:7:8 + | +LL | struct Sd { x: Enum, y: () } + | ^^ + = note: the matched value is of type `Sd` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms + | +LL ~ Sd { x: A, y: _ } => {} +LL + _ => todo!() + | + +error[E0004]: non-exhaustive patterns: `Some(B)`, `Some(C)`, `Some(D)` and 2 more not covered + --> $DIR/issue-35609.rs:39:11 + | +LL | match Some(A) { + | ^^^^^^^ patterns `Some(B)`, `Some(C)`, `Some(D)` and 2 more not covered + | +note: `Option<Enum>` defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | pub enum Option<T> { + | ^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `Option<Enum>` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms + | +LL ~ None => (), +LL + _ => todo!() + | + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-3601.rs b/src/test/ui/pattern/usefulness/issue-3601.rs new file mode 100644 index 000000000..6215a2398 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-3601.rs @@ -0,0 +1,34 @@ +#![feature(box_patterns)] + +struct HTMLImageData { + image: Option<String> +} + +struct ElementData { + kind: Box<ElementKind> +} + +enum ElementKind { + HTMLImageElement(HTMLImageData) +} + +enum NodeKind { + Element(ElementData) +} + +struct NodeData { + kind: Box<NodeKind>, +} + +fn main() { + let mut id = HTMLImageData { image: None }; + let ed = ElementData { kind: Box::new(ElementKind::HTMLImageElement(id)) }; + let n = NodeData { kind: Box::new(NodeKind::Element(ed)) }; + + // n.b. span could be better + match n.kind { + box NodeKind::Element(ed) => match ed.kind { //~ ERROR non-exhaustive patterns + box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => { true } + }, + }; +} diff --git a/src/test/ui/pattern/usefulness/issue-3601.stderr b/src/test/ui/pattern/usefulness/issue-3601.stderr new file mode 100644 index 000000000..eb8c63919 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-3601.stderr @@ -0,0 +1,24 @@ +error[E0004]: non-exhaustive patterns: `box _` not covered + --> $DIR/issue-3601.rs:30:44 + | +LL | box NodeKind::Element(ed) => match ed.kind { + | ^^^^^^^ pattern `box _` not covered + | +note: `Box<ElementKind>` defined here + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + | +LL | / pub struct Box< +LL | | T: ?Sized, +LL | | #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +LL | | >(Unique<T>, A); + | |_^ + = note: the matched value is of type `Box<ElementKind>` +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 ~ box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => { true } +LL + box _ => todo!() + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-39362.rs b/src/test/ui/pattern/usefulness/issue-39362.rs new file mode 100644 index 000000000..ea3c8f88e --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-39362.rs @@ -0,0 +1,18 @@ +enum Foo { + Bar { bar: Bar, id: usize } +} + +enum Bar { + A, B, C, D, E, F +} + +fn test(f: Foo) { + match f { + //~^ ERROR non-exhaustive patterns + //~| patterns + Foo::Bar { bar: Bar::A, .. } => (), + Foo::Bar { bar: Bar::B, .. } => (), + } +} + +fn main() {} diff --git a/src/test/ui/pattern/usefulness/issue-39362.stderr b/src/test/ui/pattern/usefulness/issue-39362.stderr new file mode 100644 index 000000000..ca37af6fb --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-39362.stderr @@ -0,0 +1,23 @@ +error[E0004]: non-exhaustive patterns: `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered + --> $DIR/issue-39362.rs:10:11 + | +LL | match f { + | ^ patterns `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered + | +note: `Foo` defined here + --> $DIR/issue-39362.rs:2:5 + | +LL | enum Foo { + | --- +LL | Bar { bar: Bar, id: usize } + | ^^^ not covered + = note: the matched value is of type `Foo` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms + | +LL ~ Foo::Bar { bar: Bar::B, .. } => (), +LL ~ _ => todo!(), + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-40221.rs b/src/test/ui/pattern/usefulness/issue-40221.rs new file mode 100644 index 000000000..e1f7e975b --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-40221.rs @@ -0,0 +1,16 @@ +enum P { + C(PC), +} + +enum PC { + Q, + QA, +} + +fn test(proto: P) { + match proto { //~ ERROR non-exhaustive patterns + P::C(PC::Q) => (), + } +} + +fn main() {} diff --git a/src/test/ui/pattern/usefulness/issue-40221.stderr b/src/test/ui/pattern/usefulness/issue-40221.stderr new file mode 100644 index 000000000..c477e4353 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-40221.stderr @@ -0,0 +1,23 @@ +error[E0004]: non-exhaustive patterns: `C(QA)` not covered + --> $DIR/issue-40221.rs:11:11 + | +LL | match proto { + | ^^^^^ pattern `C(QA)` not covered + | +note: `P` defined here + --> $DIR/issue-40221.rs:2:5 + | +LL | enum P { + | - +LL | C(PC), + | ^ not covered + = note: the matched value is of type `P` +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 ~ P::C(PC::Q) => (), +LL ~ C(QA) => todo!(), + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-4321.rs b/src/test/ui/pattern/usefulness/issue-4321.rs new file mode 100644 index 000000000..9715f2eba --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-4321.rs @@ -0,0 +1,8 @@ +fn main() { + let tup = (true, true); + println!("foo {:}", match tup { //~ ERROR non-exhaustive patterns: `(true, false)` not covered + (false, false) => "foo", + (false, true) => "bar", + (true, true) => "baz" + }); +} diff --git a/src/test/ui/pattern/usefulness/issue-4321.stderr b/src/test/ui/pattern/usefulness/issue-4321.stderr new file mode 100644 index 000000000..293273174 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-4321.stderr @@ -0,0 +1,16 @@ +error[E0004]: non-exhaustive patterns: `(true, false)` not covered + --> $DIR/issue-4321.rs:3:31 + | +LL | println!("foo {:}", match tup { + | ^^^ pattern `(true, false)` not covered + | + = note: the matched value is of type `(bool, bool)` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ (true, true) => "baz", +LL + (true, false) => todo!() + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-50900.rs b/src/test/ui/pattern/usefulness/issue-50900.rs new file mode 100644 index 000000000..27135af95 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-50900.rs @@ -0,0 +1,19 @@ +#[derive(PartialEq, Eq)] +pub struct Tag(pub Context, pub u16); + +#[derive(PartialEq, Eq)] +pub enum Context { + Tiff, + Exif, +} + +impl Tag { + const ExifIFDPointer: Tag = Tag(Context::Tiff, 34665); +} + +fn main() { + match Tag::ExifIFDPointer { + //~^ ERROR: non-exhaustive patterns: `Tag(Exif, _)` not covered + Tag::ExifIFDPointer => {} + } +} diff --git a/src/test/ui/pattern/usefulness/issue-50900.stderr b/src/test/ui/pattern/usefulness/issue-50900.stderr new file mode 100644 index 000000000..2bdbecabb --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-50900.stderr @@ -0,0 +1,21 @@ +error[E0004]: non-exhaustive patterns: `Tag(Exif, _)` not covered + --> $DIR/issue-50900.rs:15:11 + | +LL | match Tag::ExifIFDPointer { + | ^^^^^^^^^^^^^^^^^^^ pattern `Tag(Exif, _)` not covered + | +note: `Tag` defined here + --> $DIR/issue-50900.rs:2:12 + | +LL | pub struct Tag(pub Context, pub u16); + | ^^^ + = note: the matched value is of type `Tag` +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 ~ Tag::ExifIFDPointer => {} +LL + Tag(Exif, _) => todo!() + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-53820-slice-pattern-large-array.rs b/src/test/ui/pattern/usefulness/issue-53820-slice-pattern-large-array.rs new file mode 100644 index 000000000..5b0482de2 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-53820-slice-pattern-large-array.rs @@ -0,0 +1,11 @@ +// check-pass + +// This used to cause a stack overflow during exhaustiveness checking in the compiler. + +fn main() { + const LARGE_SIZE: usize = 1024 * 1024; + let [..] = [0u8; LARGE_SIZE]; + match [0u8; LARGE_SIZE] { + [..] => {} + } +} diff --git a/src/test/ui/pattern/usefulness/issue-56379.rs b/src/test/ui/pattern/usefulness/issue-56379.rs new file mode 100644 index 000000000..9bccccca9 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-56379.rs @@ -0,0 +1,14 @@ +enum Foo { + A(bool), + B(bool), + C(bool), +} + +fn main() { + match Foo::A(true) { + //~^ ERROR non-exhaustive patterns: `A(false)`, `B(false)` and `C(false)` not covered + Foo::A(true) => {} + Foo::B(true) => {} + Foo::C(true) => {} + } +} diff --git a/src/test/ui/pattern/usefulness/issue-56379.stderr b/src/test/ui/pattern/usefulness/issue-56379.stderr new file mode 100644 index 000000000..f6261001c --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-56379.stderr @@ -0,0 +1,27 @@ +error[E0004]: non-exhaustive patterns: `A(false)`, `B(false)` and `C(false)` not covered + --> $DIR/issue-56379.rs:8:11 + | +LL | match Foo::A(true) { + | ^^^^^^^^^^^^ patterns `A(false)`, `B(false)` and `C(false)` not covered + | +note: `Foo` defined here + --> $DIR/issue-56379.rs:2:5 + | +LL | enum Foo { + | --- +LL | A(bool), + | ^ not covered +LL | B(bool), + | ^ not covered +LL | C(bool), + | ^ not covered + = note: the matched value is of type `Foo` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ Foo::C(true) => {} +LL + A(false) | B(false) | C(false) => todo!() + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-57472.rs b/src/test/ui/pattern/usefulness/issue-57472.rs new file mode 100644 index 000000000..113100637 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-57472.rs @@ -0,0 +1,35 @@ +#![crate_type="lib"] +#![deny(unreachable_patterns)] + +mod test_struct { + // Test the exact copy of the minimal example + // posted in the issue. + pub struct Punned { + foo: [u8; 1], + bar: [u8; 1], + } + + pub fn test(punned: Punned) { + match punned { + Punned { foo: [_], .. } => println!("foo"), + Punned { bar: [_], .. } => println!("bar"), + //~^ ERROR unreachable pattern [unreachable_patterns] + } + } +} + +mod test_union { + // Test the same thing using a union. + pub union Punned { + foo: [u8; 1], + bar: [u8; 1], + } + + pub fn test(punned: Punned) { + match punned { + Punned { foo: [_] } => println!("foo"), + Punned { bar: [_] } => println!("bar"), + //~^ ERROR unreachable pattern [unreachable_patterns] + } + } +} diff --git a/src/test/ui/pattern/usefulness/issue-57472.stderr b/src/test/ui/pattern/usefulness/issue-57472.stderr new file mode 100644 index 000000000..26efdf6db --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-57472.stderr @@ -0,0 +1,20 @@ +error: unreachable pattern + --> $DIR/issue-57472.rs:15:13 + | +LL | Punned { bar: [_], .. } => println!("bar"), + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/issue-57472.rs:2:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/issue-57472.rs:31:13 + | +LL | Punned { bar: [_] } => println!("bar"), + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/pattern/usefulness/issue-65413-constants-and-slices-exhaustiveness.rs b/src/test/ui/pattern/usefulness/issue-65413-constants-and-slices-exhaustiveness.rs new file mode 100644 index 000000000..54dfa889e --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-65413-constants-and-slices-exhaustiveness.rs @@ -0,0 +1,15 @@ +// check-pass + +#![deny(unreachable_patterns)] + +const C0: &'static [u8] = b"\x00"; + +fn main() { + let x: &[u8] = &[0]; + match x { + &[] => {} + &[1..=255] => {} + C0 => {} + &[_, _, ..] => {} + } +} diff --git a/src/test/ui/pattern/usefulness/issue-66501.rs b/src/test/ui/pattern/usefulness/issue-66501.rs new file mode 100644 index 000000000..ffcfd4ad8 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-66501.rs @@ -0,0 +1,12 @@ +// check-pass + +#![allow(unreachable_patterns)] + +fn main() { + const CONST: &[Option<()>; 1] = &[Some(())]; + match &[Some(())] { + &[None] => {} + CONST => {} + &[Some(())] => {} + } +} diff --git a/src/test/ui/pattern/usefulness/issue-71930-type-of-match-scrutinee.rs b/src/test/ui/pattern/usefulness/issue-71930-type-of-match-scrutinee.rs new file mode 100644 index 000000000..e2ff9ac87 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-71930-type-of-match-scrutinee.rs @@ -0,0 +1,22 @@ +// check-pass + +// In PR 71930, it was discovered that the code to retrieve the inferred type of a match scrutinee +// was incorrect. + +fn f() -> ! { + panic!() +} + +fn g() -> usize { + match f() { // Should infer type `bool` + false => 0, + true => 1, + } +} + +fn h() -> usize { + match f() { // Should infer type `!` + } +} + +fn main() {} diff --git a/src/test/ui/pattern/usefulness/issue-72377.rs b/src/test/ui/pattern/usefulness/issue-72377.rs new file mode 100644 index 000000000..b0d8a53ed --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-72377.rs @@ -0,0 +1,17 @@ +#[derive(PartialEq, Eq)] +enum X { A, B, C, } + +fn main() { + let x = X::A; + let y = Some(X::A); + + match (x, y) { + //~^ ERROR non-exhaustive patterns: `(A, Some(A))`, `(A, Some(B))`, `(B, Some(B))` and 2 + //~| more not covered + (_, None) => false, + (v, Some(w)) if v == w => true, + (X::B, Some(X::C)) => false, + (X::B, Some(X::A)) => false, + (X::A, Some(X::C)) | (X::C, Some(X::A)) => false, + }; +} diff --git a/src/test/ui/pattern/usefulness/issue-72377.stderr b/src/test/ui/pattern/usefulness/issue-72377.stderr new file mode 100644 index 000000000..20f002dd3 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-72377.stderr @@ -0,0 +1,16 @@ +error[E0004]: non-exhaustive patterns: `(A, Some(A))`, `(A, Some(B))`, `(B, Some(B))` and 2 more not covered + --> $DIR/issue-72377.rs:8:11 + | +LL | match (x, y) { + | ^^^^^^ patterns `(A, Some(A))`, `(A, Some(B))`, `(B, Some(B))` and 2 more not covered + | + = note: the matched value is of type `(X, Option<X>)` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms + | +LL ~ (X::A, Some(X::C)) | (X::C, Some(X::A)) => false, +LL ~ _ => todo!(), + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-72476-and-89393-associated-type.rs b/src/test/ui/pattern/usefulness/issue-72476-and-89393-associated-type.rs new file mode 100644 index 000000000..058f41967 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-72476-and-89393-associated-type.rs @@ -0,0 +1,56 @@ +// check-pass + +// From https://github.com/rust-lang/rust/issues/72476 +// and https://github.com/rust-lang/rust/issues/89393 + +trait Trait { + type Projection; +} + +struct A; +impl Trait for A { + type Projection = bool; +} + +struct B; +impl Trait for B { + type Projection = (u32, u32); +} + +struct Next<T: Trait>(T::Projection); + +fn foo1(item: Next<A>) { + match item { + Next(true) => {} + Next(false) => {} + } +} + +fn foo2(x: <A as Trait>::Projection) { + match x { + true => {} + false => {} + } +} + +fn foo3(x: Next<B>) { + let Next((_, _)) = x; + match x { + Next((_, _)) => {} + } +} + +fn foo4(x: <B as Trait>::Projection) { + let (_, _) = x; + match x { + (_, _) => {} + } +} + +fn foo5<T: Trait>(x: <T as Trait>::Projection) { + match x { + _ => {} + } +} + +fn main() {} diff --git a/src/test/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs b/src/test/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs new file mode 100644 index 000000000..cbfcf0eaf --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs @@ -0,0 +1,12 @@ +enum A {} + //~^ NOTE `A` defined here + //~| NOTE + +fn f(a: &A) { + match a {} + //~^ ERROR non-exhaustive patterns: type `&A` is non-empty + //~| NOTE the matched value is of type `&A` + //~| NOTE references are always considered inhabited +} + +fn main() {} diff --git a/src/test/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.stderr b/src/test/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.stderr new file mode 100644 index 000000000..bf05d616d --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.stderr @@ -0,0 +1,23 @@ +error[E0004]: non-exhaustive patterns: type `&A` is non-empty + --> $DIR/issue-78123-non-exhaustive-reference.rs:6:11 + | +LL | match a {} + | ^ + | +note: `A` defined here + --> $DIR/issue-78123-non-exhaustive-reference.rs:1:6 + | +LL | enum A {} + | ^ + = note: the matched value is of type `&A` + = note: references are always considered inhabited +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match a { +LL + _ => todo!(), +LL + } + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-78549-ref-pat-and-str.rs b/src/test/ui/pattern/usefulness/issue-78549-ref-pat-and-str.rs new file mode 100644 index 000000000..2879caf2c --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-78549-ref-pat-and-str.rs @@ -0,0 +1,25 @@ +// check-pass +// From https://github.com/rust-lang/rust/issues/78549 + +fn main() { + match "foo" { + "foo" => {}, + &_ => {}, + } + + match "foo" { + &_ => {}, + "foo" => {}, + } + + match ("foo", 0, "bar") { + (&_, 0, &_) => {}, + ("foo", _, "bar") => {}, + (&_, _, &_) => {}, + } + + match (&"foo", "bar") { + (&"foo", &_) => {}, + (&&_, &_) => {}, + } +} diff --git a/src/test/ui/pattern/usefulness/issue-80501-or-pat-and-macro.rs b/src/test/ui/pattern/usefulness/issue-80501-or-pat-and-macro.rs new file mode 100644 index 000000000..aac7d7d53 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-80501-or-pat-and-macro.rs @@ -0,0 +1,27 @@ +// check-pass +#![deny(unreachable_patterns)] +pub enum TypeCtor { + Slice, + Array, +} + +pub struct ApplicationTy(TypeCtor); + +macro_rules! ty_app { + ($ctor:pat) => { + ApplicationTy($ctor) + }; +} + +fn _foo(ty: ApplicationTy) { + match ty { + ty_app!(TypeCtor::Array) | ty_app!(TypeCtor::Slice) => {} + } + + // same as above, with the macro expanded + match ty { + ApplicationTy(TypeCtor::Array) | ApplicationTy(TypeCtor::Slice) => {} + } +} + +fn main() {} diff --git a/src/test/ui/pattern/usefulness/issue-82772-match-box-as-struct.rs b/src/test/ui/pattern/usefulness/issue-82772-match-box-as-struct.rs new file mode 100644 index 000000000..c1bfcc734 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-82772-match-box-as-struct.rs @@ -0,0 +1,6 @@ +// This used to ICE in exhaustiveness checking. Explanation here: +// https://github.com/rust-lang/rust/issues/82772#issuecomment-905946768 +fn main() { + let Box { 1: _, .. }: Box<()>; //~ ERROR field `1` of + let Box { .. }: Box<()>; +} diff --git a/src/test/ui/pattern/usefulness/issue-82772-match-box-as-struct.stderr b/src/test/ui/pattern/usefulness/issue-82772-match-box-as-struct.stderr new file mode 100644 index 000000000..2c8c85bb1 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-82772-match-box-as-struct.stderr @@ -0,0 +1,9 @@ +error[E0451]: field `1` of struct `Box` is private + --> $DIR/issue-82772-match-box-as-struct.rs:4:15 + | +LL | let Box { 1: _, .. }: Box<()>; + | ^^^^ private field + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0451`. diff --git a/src/test/ui/pattern/usefulness/issue-88747.rs b/src/test/ui/pattern/usefulness/issue-88747.rs new file mode 100644 index 000000000..948c99f9c --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-88747.rs @@ -0,0 +1,14 @@ +// check-pass: this used to be a stack overflow because of recursion in `usefulness.rs` + +macro_rules! long_tuple_arg { + ([$($t:tt)*]#$($h:tt)*) => { + long_tuple_arg!{[$($t)*$($t)*]$($h)*} + }; + ([$([$t:tt $y:tt])*]) => { + pub fn _f(($($t,)*): ($($y,)*)) {} + } +} + +long_tuple_arg!{[[_ u8]]########## ###} + +fn main() {} diff --git a/src/test/ui/pattern/usefulness/match-arm-statics-2.rs b/src/test/ui/pattern/usefulness/match-arm-statics-2.rs new file mode 100644 index 000000000..4c5f2d356 --- /dev/null +++ b/src/test/ui/pattern/usefulness/match-arm-statics-2.rs @@ -0,0 +1,62 @@ +use self::Direction::{North, East, South, West}; + +#[derive(PartialEq, Eq)] +struct NewBool(bool); + +#[derive(PartialEq, Eq)] +enum Direction { + North, + East, + South, + West +} + +const TRUE_TRUE: (bool, bool) = (true, true); + +fn nonexhaustive_1() { + match (true, false) { + //~^ ERROR non-exhaustive patterns: `(true, false)` not covered + TRUE_TRUE => (), + (false, false) => (), + (false, true) => () + } +} + +const NONE: Option<Direction> = None; +const EAST: Direction = East; + +fn nonexhaustive_2() { + match Some(Some(North)) { + //~^ ERROR non-exhaustive patterns: `Some(Some(West))` not covered + Some(NONE) => (), + Some(Some(North)) => (), + Some(Some(EAST)) => (), + Some(Some(South)) => (), + None => () + } +} + +const NEW_FALSE: NewBool = NewBool(false); +struct Foo { + bar: Option<Direction>, + baz: NewBool +} + +const STATIC_FOO: Foo = Foo { bar: None, baz: NEW_FALSE }; + +fn nonexhaustive_3() { + match (Foo { bar: Some(North), baz: NewBool(true) }) { + //~^ ERROR non-exhaustive patterns: `Foo { bar: Some(North), baz: NewBool(true) }` + Foo { bar: None, baz: NewBool(true) } => (), + Foo { bar: _, baz: NEW_FALSE } => (), + Foo { bar: Some(West), baz: NewBool(true) } => (), + Foo { bar: Some(South), .. } => (), + Foo { bar: Some(EAST), .. } => () + } +} + +fn main() { + nonexhaustive_1(); + nonexhaustive_2(); + nonexhaustive_3(); +} diff --git a/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr b/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr new file mode 100644 index 000000000..a2b66f5ed --- /dev/null +++ b/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr @@ -0,0 +1,58 @@ +error[E0004]: non-exhaustive patterns: `(true, false)` not covered + --> $DIR/match-arm-statics-2.rs:17:11 + | +LL | match (true, false) { + | ^^^^^^^^^^^^^ pattern `(true, false)` not covered + | + = note: the matched value is of type `(bool, bool)` +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 ~ (false, true) => (), +LL + (true, false) => todo!() + | + +error[E0004]: non-exhaustive patterns: `Some(Some(West))` not covered + --> $DIR/match-arm-statics-2.rs:29:11 + | +LL | match Some(Some(North)) { + | ^^^^^^^^^^^^^^^^^ pattern `Some(Some(West))` not covered + | +note: `Option<Option<Direction>>` defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | pub enum Option<T> { + | ------------------ +... +LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^^^ + | | + | not covered + | not covered + = note: the matched value is of type `Option<Option<Direction>>` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ None => (), +LL + Some(Some(West)) => todo!() + | + +error[E0004]: non-exhaustive patterns: `Foo { bar: Some(North), baz: NewBool(true) }` not covered + --> $DIR/match-arm-statics-2.rs:48:11 + | +LL | match (Foo { bar: Some(North), baz: NewBool(true) }) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { bar: Some(North), baz: NewBool(true) }` not covered + | +note: `Foo` defined here + --> $DIR/match-arm-statics-2.rs:40:8 + | +LL | struct Foo { + | ^^^ + = note: the matched value is of type `Foo` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ Foo { bar: Some(EAST), .. } => (), +LL + Foo { bar: Some(North), baz: NewBool(true) } => todo!() + | + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/match-arm-statics.rs b/src/test/ui/pattern/usefulness/match-arm-statics.rs new file mode 100644 index 000000000..91db76ebb --- /dev/null +++ b/src/test/ui/pattern/usefulness/match-arm-statics.rs @@ -0,0 +1,69 @@ +#![allow(dead_code)] +#![deny(unreachable_patterns)] + +use self::Direction::{North, East, South, West}; + +#[derive(PartialEq, Eq)] +struct NewBool(bool); + +#[derive(PartialEq, Eq)] +enum Direction { + North, + East, + South, + West +} + +const TRUE_TRUE: (bool, bool) = (true, true); + +fn unreachable_1() { + match (true, false) { + TRUE_TRUE => (), + (false, false) => (), + (false, true) => (), + (true, false) => (), + (true, true) => () + //~^ ERROR unreachable pattern + } +} + +const NONE: Option<Direction> = None; +const EAST: Direction = East; + +fn unreachable_2() { + match Some(Some(North)) { + Some(NONE) => (), + Some(Some(North)) => (), + Some(Some(EAST)) => (), + Some(Some(South)) => (), + Some(Some(West)) => (), + Some(Some(East)) => (), + //~^ ERROR unreachable pattern + None => () + } +} + +const NEW_FALSE: NewBool = NewBool(false); +struct Foo { + bar: Option<Direction>, + baz: NewBool +} + +fn unreachable_3() { + match (Foo { bar: Some(EAST), baz: NewBool(true) }) { + Foo { bar: None, baz: NewBool(true) } => (), + Foo { bar: _, baz: NEW_FALSE } => (), + Foo { bar: Some(West), baz: NewBool(true) } => (), + Foo { bar: Some(South), .. } => (), + Foo { bar: Some(EAST), .. } => (), + Foo { bar: Some(North), baz: NewBool(true) } => (), + Foo { bar: Some(EAST), baz: NewBool(false) } => () + //~^ ERROR unreachable pattern + } +} + +fn main() { + unreachable_1(); + unreachable_2(); + unreachable_3(); +} diff --git a/src/test/ui/pattern/usefulness/match-arm-statics.stderr b/src/test/ui/pattern/usefulness/match-arm-statics.stderr new file mode 100644 index 000000000..a5dffebf6 --- /dev/null +++ b/src/test/ui/pattern/usefulness/match-arm-statics.stderr @@ -0,0 +1,26 @@ +error: unreachable pattern + --> $DIR/match-arm-statics.rs:25:9 + | +LL | (true, true) => () + | ^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/match-arm-statics.rs:2:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/match-arm-statics.rs:40:9 + | +LL | Some(Some(East)) => (), + | ^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/match-arm-statics.rs:60:9 + | +LL | Foo { bar: Some(EAST), baz: NewBool(false) } => () + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.rs b/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.rs new file mode 100644 index 000000000..33468d03f --- /dev/null +++ b/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.rs @@ -0,0 +1,13 @@ +fn main() { + let buf = &[0, 1, 2, 3]; + + match buf { //~ ERROR non-exhaustive + b"AAAA" => {} + } + + let buf: &[u8] = buf; + + match buf { //~ ERROR non-exhaustive + b"AAAA" => {} + } +} diff --git a/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr b/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr new file mode 100644 index 000000000..a90f32f7a --- /dev/null +++ b/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr @@ -0,0 +1,29 @@ +error[E0004]: non-exhaustive patterns: `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered + --> $DIR/match-byte-array-patterns-2.rs:4:11 + | +LL | match buf { + | ^^^ patterns `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered + | + = note: the matched value is of type `&[u8; 4]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ b"AAAA" => {} +LL + &[0_u8..=64_u8, _, _, _] | &[66_u8..=u8::MAX, _, _, _] => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 2 more not covered + --> $DIR/match-byte-array-patterns-2.rs:10:11 + | +LL | match buf { + | ^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 2 more not covered + | + = note: the matched value is of type `&[u8]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms + | +LL ~ b"AAAA" => {} +LL + _ => todo!() + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/match-byte-array-patterns.rs b/src/test/ui/pattern/usefulness/match-byte-array-patterns.rs new file mode 100644 index 000000000..9b6c8bd55 --- /dev/null +++ b/src/test/ui/pattern/usefulness/match-byte-array-patterns.rs @@ -0,0 +1,55 @@ +#![deny(unreachable_patterns)] + +fn main() { + let buf = &[0, 1, 2, 3]; + + match buf { + b"AAAA" => {}, + &[0x41, 0x41, 0x41, 0x41] => {} //~ ERROR unreachable pattern + _ => {} + } + + match buf { + &[0x41, 0x41, 0x41, 0x41] => {} + b"AAAA" => {}, //~ ERROR unreachable pattern + _ => {} + } + + match buf { + &[_, 0x41, 0x41, 0x41] => {}, + b"AAAA" => {}, //~ ERROR unreachable pattern + _ => {} + } + + match buf { + &[0x41, .., 0x41] => {} + b"AAAA" => {}, //~ ERROR unreachable pattern + _ => {} + } + + let buf: &[u8] = buf; + + match buf { + b"AAAA" => {}, + &[0x41, 0x41, 0x41, 0x41] => {} //~ ERROR unreachable pattern + _ => {} + } + + match buf { + &[0x41, 0x41, 0x41, 0x41] => {} + b"AAAA" => {}, //~ ERROR unreachable pattern + _ => {} + } + + match buf { + &[_, 0x41, 0x41, 0x41] => {}, + b"AAAA" => {}, //~ ERROR unreachable pattern + _ => {} + } + + match buf { + &[0x41, .., 0x41] => {} + b"AAAA" => {}, //~ ERROR unreachable pattern + _ => {} + } +} diff --git a/src/test/ui/pattern/usefulness/match-byte-array-patterns.stderr b/src/test/ui/pattern/usefulness/match-byte-array-patterns.stderr new file mode 100644 index 000000000..0c582be8d --- /dev/null +++ b/src/test/ui/pattern/usefulness/match-byte-array-patterns.stderr @@ -0,0 +1,56 @@ +error: unreachable pattern + --> $DIR/match-byte-array-patterns.rs:8:9 + | +LL | &[0x41, 0x41, 0x41, 0x41] => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/match-byte-array-patterns.rs:1:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/match-byte-array-patterns.rs:14:9 + | +LL | b"AAAA" => {}, + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/match-byte-array-patterns.rs:20:9 + | +LL | b"AAAA" => {}, + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/match-byte-array-patterns.rs:26:9 + | +LL | b"AAAA" => {}, + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/match-byte-array-patterns.rs:34:9 + | +LL | &[0x41, 0x41, 0x41, 0x41] => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/match-byte-array-patterns.rs:40:9 + | +LL | b"AAAA" => {}, + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/match-byte-array-patterns.rs:46:9 + | +LL | b"AAAA" => {}, + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/match-byte-array-patterns.rs:52:9 + | +LL | b"AAAA" => {}, + | ^^^^^^^ + +error: aborting due to 8 previous errors + diff --git a/src/test/ui/pattern/usefulness/match-non-exhaustive.rs b/src/test/ui/pattern/usefulness/match-non-exhaustive.rs new file mode 100644 index 000000000..3b210a115 --- /dev/null +++ b/src/test/ui/pattern/usefulness/match-non-exhaustive.rs @@ -0,0 +1,4 @@ +fn main() { + match 0 { 1 => () } //~ ERROR non-exhaustive patterns + match 0 { 0 if false => () } //~ ERROR non-exhaustive patterns +} diff --git a/src/test/ui/pattern/usefulness/match-non-exhaustive.stderr b/src/test/ui/pattern/usefulness/match-non-exhaustive.stderr new file mode 100644 index 000000000..08dde523a --- /dev/null +++ b/src/test/ui/pattern/usefulness/match-non-exhaustive.stderr @@ -0,0 +1,27 @@ +error[E0004]: non-exhaustive patterns: `i32::MIN..=0_i32` and `2_i32..=i32::MAX` not covered + --> $DIR/match-non-exhaustive.rs:2:11 + | +LL | match 0 { 1 => () } + | ^ patterns `i32::MIN..=0_i32` and `2_i32..=i32::MAX` not covered + | + = note: the matched value is of type `i32` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL | match 0 { 1 => (), i32::MIN..=0_i32 | 2_i32..=i32::MAX => todo!() } + | ++++++++++++++++++++++++++++++++++++++++++++++++ + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/match-non-exhaustive.rs:3:11 + | +LL | match 0 { 0 if false => () } + | ^ pattern `_` not covered + | + = note: the matched value is of type `i32` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL | match 0 { 0 if false => (), _ => todo!() } + | ++++++++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/match-privately-empty.rs b/src/test/ui/pattern/usefulness/match-privately-empty.rs new file mode 100644 index 000000000..315eb03d1 --- /dev/null +++ b/src/test/ui/pattern/usefulness/match-privately-empty.rs @@ -0,0 +1,21 @@ +#![feature(never_type)] +#![feature(exhaustive_patterns)] + +mod private { + pub struct Private { + _bot: !, + pub misc: bool, + } + pub const DATA: Option<Private> = None; +} + +fn main() { + match private::DATA { + //~^ ERROR non-exhaustive patterns: `Some(Private { misc: true, .. })` not covered + None => {} + Some(private::Private { + misc: false, + .. + }) => {} + } +} diff --git a/src/test/ui/pattern/usefulness/match-privately-empty.stderr b/src/test/ui/pattern/usefulness/match-privately-empty.stderr new file mode 100644 index 000000000..4607cfaae --- /dev/null +++ b/src/test/ui/pattern/usefulness/match-privately-empty.stderr @@ -0,0 +1,24 @@ +error[E0004]: non-exhaustive patterns: `Some(Private { misc: true, .. })` not covered + --> $DIR/match-privately-empty.rs:13:11 + | +LL | match private::DATA { + | ^^^^^^^^^^^^^ pattern `Some(Private { misc: true, .. })` not covered + | +note: `Option<Private>` defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | pub enum Option<T> { + | ------------------ +... +LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^^^ not covered + = note: the matched value is of type `Option<Private>` +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 ~ }) => {} +LL + Some(Private { misc: true, .. }) => todo!() + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/match-ref-ice.rs b/src/test/ui/pattern/usefulness/match-ref-ice.rs new file mode 100644 index 000000000..dee110f96 --- /dev/null +++ b/src/test/ui/pattern/usefulness/match-ref-ice.rs @@ -0,0 +1,16 @@ +#![deny(unreachable_patterns)] + +// The arity of `ref x` is always 1. If the pattern is compared to some non-structural type whose +// arity is always 0, an ICE occurs. +// +// Related issue: #23009 + +fn main() { + let homura = [1, 2, 3]; + + match homura { + [1, ref _madoka, 3] => (), + [1, 2, 3] => (), //~ ERROR unreachable pattern + [_, _, _] => (), + } +} diff --git a/src/test/ui/pattern/usefulness/match-ref-ice.stderr b/src/test/ui/pattern/usefulness/match-ref-ice.stderr new file mode 100644 index 000000000..fad0940ba --- /dev/null +++ b/src/test/ui/pattern/usefulness/match-ref-ice.stderr @@ -0,0 +1,14 @@ +error: unreachable pattern + --> $DIR/match-ref-ice.rs:13:9 + | +LL | [1, 2, 3] => (), + | ^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/match-ref-ice.rs:1:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/pattern/usefulness/match-slice-patterns.rs b/src/test/ui/pattern/usefulness/match-slice-patterns.rs new file mode 100644 index 000000000..92d74b8c2 --- /dev/null +++ b/src/test/ui/pattern/usefulness/match-slice-patterns.rs @@ -0,0 +1,12 @@ +fn check(list: &[Option<()>]) { + match list { + //~^ ERROR `&[_, Some(_), .., None, _]` not covered + &[] => {}, + &[_] => {}, + &[_, _] => {}, + &[_, None, ..] => {}, + &[.., Some(_), _] => {}, + } +} + +fn main() {} diff --git a/src/test/ui/pattern/usefulness/match-slice-patterns.stderr b/src/test/ui/pattern/usefulness/match-slice-patterns.stderr new file mode 100644 index 000000000..961dd5901 --- /dev/null +++ b/src/test/ui/pattern/usefulness/match-slice-patterns.stderr @@ -0,0 +1,16 @@ +error[E0004]: non-exhaustive patterns: `&[_, Some(_), .., None, _]` not covered + --> $DIR/match-slice-patterns.rs:2:11 + | +LL | match list { + | ^^^^ pattern `&[_, Some(_), .., None, _]` not covered + | + = note: the matched value is of type `&[Option<()>]` +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 ~ &[.., Some(_), _] => {} +LL ~ &[_, Some(_), .., None, _] => todo!(), + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/match-vec-fixed.rs b/src/test/ui/pattern/usefulness/match-vec-fixed.rs new file mode 100644 index 000000000..e611779de --- /dev/null +++ b/src/test/ui/pattern/usefulness/match-vec-fixed.rs @@ -0,0 +1,18 @@ +#![deny(unreachable_patterns)] + +fn a() { + let v = [1, 2, 3]; + match v { + [_, _, _] => {} + [_, _, _] => {} //~ ERROR unreachable pattern + } + match v { + [_, 1, _] => {} + [_, 1, _] => {} //~ ERROR unreachable pattern + _ => {} + } +} + +fn main() { + a(); +} diff --git a/src/test/ui/pattern/usefulness/match-vec-fixed.stderr b/src/test/ui/pattern/usefulness/match-vec-fixed.stderr new file mode 100644 index 000000000..e388a06cb --- /dev/null +++ b/src/test/ui/pattern/usefulness/match-vec-fixed.stderr @@ -0,0 +1,20 @@ +error: unreachable pattern + --> $DIR/match-vec-fixed.rs:7:9 + | +LL | [_, _, _] => {} + | ^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/match-vec-fixed.rs:1:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/match-vec-fixed.rs:11:9 + | +LL | [_, 1, _] => {} + | ^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/pattern/usefulness/match-vec-unreachable.rs b/src/test/ui/pattern/usefulness/match-vec-unreachable.rs new file mode 100644 index 000000000..3342389be --- /dev/null +++ b/src/test/ui/pattern/usefulness/match-vec-unreachable.rs @@ -0,0 +1,29 @@ +#![deny(unreachable_patterns)] + +fn main() { + let x: Vec<(isize, isize)> = Vec::new(); + let x: &[(isize, isize)] = &x; + match *x { + [a, (2, 3), _] => (), + [(1, 2), (2, 3), b] => (), //~ ERROR unreachable pattern + _ => () + } + + let x: Vec<String> = vec!["foo".to_string(), + "bar".to_string(), + "baz".to_string()]; + let x: &[String] = &x; + match *x { + [ref a, _, _, ..] => { println!("{}", a); } + [_, _, _, _, _] => { } //~ ERROR unreachable pattern + _ => { } + } + + let x: Vec<char> = vec!['a', 'b', 'c']; + let x: &[char] = &x; + match *x { + ['a', 'b', 'c', ref _tail @ ..] => {} + ['a', 'b', 'c'] => {} //~ ERROR unreachable pattern + _ => {} + } +} diff --git a/src/test/ui/pattern/usefulness/match-vec-unreachable.stderr b/src/test/ui/pattern/usefulness/match-vec-unreachable.stderr new file mode 100644 index 000000000..672fd92fb --- /dev/null +++ b/src/test/ui/pattern/usefulness/match-vec-unreachable.stderr @@ -0,0 +1,26 @@ +error: unreachable pattern + --> $DIR/match-vec-unreachable.rs:8:9 + | +LL | [(1, 2), (2, 3), b] => (), + | ^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/match-vec-unreachable.rs:1:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/match-vec-unreachable.rs:18:9 + | +LL | [_, _, _, _, _] => { } + | ^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/match-vec-unreachable.rs:26:9 + | +LL | ['a', 'b', 'c'] => {} + | ^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/pattern/usefulness/nested-exhaustive-match.rs b/src/test/ui/pattern/usefulness/nested-exhaustive-match.rs new file mode 100644 index 000000000..8b2294f84 --- /dev/null +++ b/src/test/ui/pattern/usefulness/nested-exhaustive-match.rs @@ -0,0 +1,14 @@ +// run-pass +#![allow(dead_code)] +// pretty-expanded FIXME #23616 + +struct Foo { foo: bool, bar: Option<isize>, baz: isize } + +pub fn main() { + match (Foo{foo: true, bar: Some(10), baz: 20}) { + Foo{foo: true, bar: Some(_), ..} => {} + Foo{foo: false, bar: None, ..} => {} + Foo{foo: true, bar: None, ..} => {} + Foo{foo: false, bar: Some(_), ..} => {} + } +} diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs b/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs new file mode 100644 index 000000000..2e15bc2d2 --- /dev/null +++ b/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs @@ -0,0 +1,105 @@ +// Test the "defined here" and "not covered" diagnostic hints. +// We also make sure that references are peeled off from the scrutinee type +// so that the diagnostics work better with default binding modes. + +#[derive(Clone)] +enum E { + //~^ NOTE + //~| NOTE + //~| NOTE + //~| NOTE + //~| NOTE + //~| NOTE + A, + B, + //~^ NOTE `E` defined here + //~| NOTE `E` defined here + //~| NOTE `E` defined here + //~| NOTE `E` defined here + //~| NOTE `E` defined here + //~| NOTE `E` defined here + //~| NOTE not covered + //~| NOTE not covered + //~| NOTE not covered + //~| NOTE not covered + //~| NOTE not covered + //~| NOTE not covered + C + //~^ not covered + //~| not covered + //~| not covered + //~| not covered + //~| not covered + //~| not covered +} + +fn by_val(e: E) { + let e1 = e.clone(); + match e1 { //~ ERROR non-exhaustive patterns: `B` and `C` not covered + //~^ NOTE patterns `B` and `C` not covered + //~| NOTE the matched value is of type `E` + E::A => {} + } + + let E::A = e; //~ ERROR refutable pattern in local binding: `B` and `C` not covered + //~^ NOTE patterns `B` and `C` not covered + //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with + //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html + //~| NOTE the matched value is of type `E` +} + +fn by_ref_once(e: &E) { + match e { //~ ERROR non-exhaustive patterns: `&B` and `&C` not covered + //~^ NOTE patterns `&B` and `&C` not covered + //~| NOTE the matched value is of type `&E` + E::A => {} + } + + let E::A = e; //~ ERROR refutable pattern in local binding: `&B` and `&C` not covered + //~^ NOTE patterns `&B` and `&C` not covered + //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with + //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html + //~| NOTE the matched value is of type `&E` +} + +fn by_ref_thrice(e: & &mut &E) { + match e { //~ ERROR non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered + //~^ NOTE patterns `&&mut &B` and `&&mut &C` not covered + //~| NOTE the matched value is of type `&&mut &E` + E::A => {} + } + + let E::A = e; + //~^ ERROR refutable pattern in local binding: `&&mut &B` and `&&mut &C` not covered + //~| NOTE patterns `&&mut &B` and `&&mut &C` not covered + //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with + //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html + //~| NOTE the matched value is of type `&&mut &E` +} + +enum Opt { + //~^ NOTE + //~| NOTE + Some(u8), + None, + //~^ NOTE `Opt` defined here + //~| NOTE `Opt` defined here + //~| NOTE not covered + //~| NOTE not covered +} + +fn ref_pat(e: Opt) { + match e {//~ ERROR non-exhaustive patterns: `None` not covered + //~^ NOTE pattern `None` not covered + //~| NOTE the matched value is of type `Opt` + Opt::Some(ref _x) => {} + } + + let Opt::Some(ref _x) = e; //~ ERROR refutable pattern in local binding: `None` not covered + //~^ NOTE the matched value is of type `Opt` + //~| NOTE pattern `None` not covered + //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with + //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +} + +fn main() {} diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr new file mode 100644 index 000000000..0f06c31c4 --- /dev/null +++ b/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr @@ -0,0 +1,198 @@ +error[E0004]: non-exhaustive patterns: `B` and `C` not covered + --> $DIR/non-exhaustive-defined-here.rs:38:11 + | +LL | match e1 { + | ^^ patterns `B` and `C` not covered + | +note: `E` defined here + --> $DIR/non-exhaustive-defined-here.rs:14:5 + | +LL | enum E { + | - +... +LL | B, + | ^ not covered +... +LL | C + | ^ 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, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ E::A => {} +LL + B | C => todo!() + | + +error[E0005]: refutable pattern in local binding: `B` and `C` not covered + --> $DIR/non-exhaustive-defined-here.rs:44:9 + | +LL | let E::A = e; + | ^^^^ patterns `B` and `C` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +note: `E` defined here + --> $DIR/non-exhaustive-defined-here.rs:14:5 + | +LL | enum E { + | - +... +LL | B, + | ^ not covered +... +LL | C + | ^ not covered + = note: the matched value is of type `E` +help: you might want to use `if let` to ignore the variants that aren't matched + | +LL | if let E::A = e { todo!() } + | ++ ~~~~~~~~~~~ + +error[E0004]: non-exhaustive patterns: `&B` and `&C` not covered + --> $DIR/non-exhaustive-defined-here.rs:52:11 + | +LL | match e { + | ^ patterns `&B` and `&C` not covered + | +note: `E` defined here + --> $DIR/non-exhaustive-defined-here.rs:14:5 + | +LL | enum E { + | - +... +LL | B, + | ^ not covered +... +LL | C + | ^ 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, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ E::A => {} +LL + &B | &C => todo!() + | + +error[E0005]: refutable pattern in local binding: `&B` and `&C` not covered + --> $DIR/non-exhaustive-defined-here.rs:58:9 + | +LL | let E::A = e; + | ^^^^ patterns `&B` and `&C` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +note: `E` defined here + --> $DIR/non-exhaustive-defined-here.rs:14:5 + | +LL | enum E { + | - +... +LL | B, + | ^ not covered +... +LL | C + | ^ not covered + = note: the matched value is of type `&E` +help: you might want to use `if let` to ignore the variants that aren't matched + | +LL | if let E::A = e { todo!() } + | ++ ~~~~~~~~~~~ + +error[E0004]: non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered + --> $DIR/non-exhaustive-defined-here.rs:66:11 + | +LL | match e { + | ^ patterns `&&mut &B` and `&&mut &C` not covered + | +note: `E` defined here + --> $DIR/non-exhaustive-defined-here.rs:14:5 + | +LL | enum E { + | - +... +LL | B, + | ^ not covered +... +LL | C + | ^ not covered + = note: the matched value is of type `&&mut &E` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ E::A => {} +LL + &&mut &B | &&mut &C => todo!() + | + +error[E0005]: refutable pattern in local binding: `&&mut &B` and `&&mut &C` not covered + --> $DIR/non-exhaustive-defined-here.rs:72:9 + | +LL | let E::A = e; + | ^^^^ patterns `&&mut &B` and `&&mut &C` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +note: `E` defined here + --> $DIR/non-exhaustive-defined-here.rs:14:5 + | +LL | enum E { + | - +... +LL | B, + | ^ not covered +... +LL | C + | ^ not covered + = note: the matched value is of type `&&mut &E` +help: you might want to use `if let` to ignore the variants that aren't matched + | +LL | if let E::A = e { todo!() } + | ++ ~~~~~~~~~~~ + +error[E0004]: non-exhaustive patterns: `None` not covered + --> $DIR/non-exhaustive-defined-here.rs:92:11 + | +LL | match e { + | ^ pattern `None` not covered + | +note: `Opt` defined here + --> $DIR/non-exhaustive-defined-here.rs:84:5 + | +LL | enum Opt { + | --- +... +LL | None, + | ^^^^ not covered + = note: the matched value is of type `Opt` +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 ~ Opt::Some(ref _x) => {} +LL + None => todo!() + | + +error[E0005]: refutable pattern in local binding: `None` not covered + --> $DIR/non-exhaustive-defined-here.rs:98:9 + | +LL | let Opt::Some(ref _x) = e; + | ^^^^^^^^^^^^^^^^^ pattern `None` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +note: `Opt` defined here + --> $DIR/non-exhaustive-defined-here.rs:84:5 + | +LL | enum Opt { + | --- +... +LL | None, + | ^^^^ not covered + = note: the matched value is of type `Opt` +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | let _x = if let Opt::Some(ref _x) = e { _x } else { todo!() }; + | +++++++++++ +++++++++++++++++++++++ +help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched + | +LL | let Opt::Some(ref _x) = e else { todo!() }; + | ++++++++++++++++ + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0004, E0005. +For more information about an error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.rs b/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.rs new file mode 100644 index 000000000..d19814479 --- /dev/null +++ b/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.rs @@ -0,0 +1,19 @@ +enum T { A(U), B } +enum U { C, D } + +fn match_nested_vecs<'a, T>(l1: Option<&'a [T]>, l2: Result<&'a [T], ()>) -> &'static str { + match (l1, l2) { //~ ERROR non-exhaustive patterns: `(Some(&[]), Err(_))` not covered + (Some(&[]), Ok(&[])) => "Some(empty), Ok(empty)", + (Some(&[_, ..]), Ok(_)) | (Some(&[_, ..]), Err(())) => "Some(non-empty), any", + (None, Ok(&[])) | (None, Err(())) | (None, Ok(&[_])) => "None, Ok(less than one element)", + (None, Ok(&[_, _, ..])) => "None, Ok(at least two elements)" + } +} + +fn main() { + let x = T::A(U::C); + match x { //~ ERROR non-exhaustive patterns: `A(C)` not covered + T::A(U::D) => { panic!("hello"); } + T::B => { panic!("goodbye"); } + } +} diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr new file mode 100644 index 000000000..cbbd544f9 --- /dev/null +++ b/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr @@ -0,0 +1,34 @@ +error[E0004]: non-exhaustive patterns: `(Some(&[]), Err(_))` not covered + --> $DIR/non-exhaustive-match-nested.rs:5:11 + | +LL | match (l1, l2) { + | ^^^^^^^^ pattern `(Some(&[]), Err(_))` not covered + | + = note: the matched value is of type `(Option<&[T]>, Result<&[T], ()>)` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ (None, Ok(&[_, _, ..])) => "None, Ok(at least two elements)", +LL + (Some(&[]), Err(_)) => todo!() + | + +error[E0004]: non-exhaustive patterns: `A(C)` not covered + --> $DIR/non-exhaustive-match-nested.rs:15:11 + | +LL | match x { + | ^ pattern `A(C)` not covered + | +note: `T` defined here + --> $DIR/non-exhaustive-match-nested.rs:1:10 + | +LL | enum T { A(U), B } + | - ^ not covered + = note: the matched value is of type `T` +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 ~ T::B => { panic!("goodbye"); } +LL + A(C) => todo!() + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match.rs b/src/test/ui/pattern/usefulness/non-exhaustive-match.rs new file mode 100644 index 000000000..4ff12aa2f --- /dev/null +++ b/src/test/ui/pattern/usefulness/non-exhaustive-match.rs @@ -0,0 +1,63 @@ +#![allow(illegal_floating_point_literal_pattern)] + +enum T { A, B } + +fn main() { + let x = T::A; + match x { T::B => { } } //~ ERROR non-exhaustive patterns: `A` not covered + match true { //~ ERROR non-exhaustive patterns: `false` not covered + true => {} + } + match Some(10) { //~ ERROR non-exhaustive patterns: `Some(_)` not covered + None => {} + } + match (2, 3, 4) { //~ ERROR non-exhaustive patterns: `(_, _, i32::MIN..=3_i32)` + // and `(_, _, 5_i32..=i32::MAX)` not covered + (_, _, 4) => {} + } + match (T::A, T::A) { //~ ERROR non-exhaustive patterns: `(A, A)` and `(B, B)` not covered + (T::A, T::B) => {} + (T::B, T::A) => {} + } + match T::A { //~ ERROR non-exhaustive patterns: `B` not covered + T::A => {} + } + // This is exhaustive, though the algorithm got it wrong at one point + match (T::A, T::B) { + (T::A, _) => {} + (_, T::A) => {} + (T::B, T::B) => {} + } + let vec = vec![Some(42), None, Some(21)]; + let vec: &[Option<isize>] = &vec; + match *vec { //~ ERROR non-exhaustive patterns: `[]` not covered + [Some(..), None, ref tail @ ..] => {} + [Some(..), Some(..), ref tail @ ..] => {} + [None] => {} + } + let vec = vec![1]; + let vec: &[isize] = &vec; + match *vec { + [_, ref tail @ ..] => (), + [] => () + } + let vec = vec![0.5f32]; + let vec: &[f32] = &vec; + match *vec { //~ ERROR non-exhaustive patterns: `[_, _, _, _, ..]` not covered + [0.1, 0.2, 0.3] => (), + [0.1, 0.2] => (), + [0.1] => (), + [] => () + } + let vec = vec![Some(42), None, Some(21)]; + let vec: &[Option<isize>] = &vec; + match *vec { + [Some(..), None, ref tail @ ..] => {} + [Some(..), Some(..), ref tail @ ..] => {} + [None, None, ref tail @ ..] => {} + [None, Some(..), ref tail @ ..] => {} + [Some(_)] => {} + [None] => {} + [] => {} + } +} diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr new file mode 100644 index 000000000..f2362c316 --- /dev/null +++ b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr @@ -0,0 +1,124 @@ +error[E0004]: non-exhaustive patterns: `A` not covered + --> $DIR/non-exhaustive-match.rs:7:11 + | +LL | match x { T::B => { } } + | ^ pattern `A` not covered + | +note: `T` defined here + --> $DIR/non-exhaustive-match.rs:3:10 + | +LL | enum T { A, B } + | - ^ not covered + = note: the matched value is of type `T` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL | match x { T::B => { }, A => todo!() } + | ++++++++++++++ + +error[E0004]: non-exhaustive patterns: `false` not covered + --> $DIR/non-exhaustive-match.rs:8:11 + | +LL | match true { + | ^^^^ pattern `false` not covered + | + = note: the matched value is of type `bool` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ true => {} +LL + false => todo!() + | + +error[E0004]: non-exhaustive patterns: `Some(_)` not covered + --> $DIR/non-exhaustive-match.rs:11:11 + | +LL | match Some(10) { + | ^^^^^^^^ pattern `Some(_)` not covered + | +note: `Option<i32>` defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | pub enum Option<T> { + | ------------------ +... +LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^^^ not covered + = note: the matched value is of type `Option<i32>` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ None => {} +LL + Some(_) => todo!() + | + +error[E0004]: non-exhaustive patterns: `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered + --> $DIR/non-exhaustive-match.rs:14:11 + | +LL | match (2, 3, 4) { + | ^^^^^^^^^ patterns `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered + | + = note: the matched value is of type `(i32, i32, i32)` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ (_, _, 4) => {} +LL + (_, _, i32::MIN..=3_i32) | (_, _, 5_i32..=i32::MAX) => todo!() + | + +error[E0004]: non-exhaustive patterns: `(A, A)` and `(B, B)` not covered + --> $DIR/non-exhaustive-match.rs:18:11 + | +LL | match (T::A, T::A) { + | ^^^^^^^^^^^^ patterns `(A, A)` and `(B, B)` not covered + | + = note: the matched value is of type `(T, T)` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ (T::B, T::A) => {} +LL + (A, A) | (B, B) => todo!() + | + +error[E0004]: non-exhaustive patterns: `B` not covered + --> $DIR/non-exhaustive-match.rs:22:11 + | +LL | match T::A { + | ^^^^ pattern `B` not covered + | +note: `T` defined here + --> $DIR/non-exhaustive-match.rs:3:13 + | +LL | enum T { A, B } + | - ^ not covered + = note: the matched value is of type `T` +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 ~ T::A => {} +LL + B => todo!() + | + +error[E0004]: non-exhaustive patterns: `[]` not covered + --> $DIR/non-exhaustive-match.rs:33:11 + | +LL | match *vec { + | ^^^^ pattern `[]` not covered + | + = note: the matched value is of type `[Option<isize>]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ [None] => {} +LL + [] => todo!() + | + +error[E0004]: non-exhaustive patterns: `[_, _, _, _, ..]` not covered + --> $DIR/non-exhaustive-match.rs:46:11 + | +LL | match *vec { + | ^^^^ pattern `[_, _, _, _, ..]` not covered + | + = note: the matched value is of type `[f32]` +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 ~ [] => (), +LL + [_, _, _, _, ..] => todo!() + | + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.rs b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.rs new file mode 100644 index 000000000..abb4ea8da --- /dev/null +++ b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.rs @@ -0,0 +1,89 @@ +struct Foo { + first: bool, + second: Option<[usize; 4]> +} + +fn struct_with_a_nested_enum_and_vector() { + match (Foo { first: true, second: None }) { +//~^ ERROR non-exhaustive patterns: `Foo { first: false, second: Some([_, _, _, _]) }` not covered + Foo { first: true, second: None } => (), + Foo { first: true, second: Some(_) } => (), + Foo { first: false, second: None } => (), + Foo { first: false, second: Some([1, 2, 3, 4]) } => () + } +} + +enum Color { + Red, + Green, + CustomRGBA { a: bool, r: u8, g: u8, b: u8 } +} + +fn enum_with_single_missing_variant() { + match Color::Red { + //~^ ERROR non-exhaustive patterns: `Red` not covered + Color::CustomRGBA { .. } => (), + Color::Green => () + } +} + +enum Direction { + North, East, South, West +} + +fn enum_with_multiple_missing_variants() { + match Direction::North { + //~^ ERROR non-exhaustive patterns: `East`, `South` and `West` not covered + Direction::North => () + } +} + +enum ExcessiveEnum { + First, Second, Third, Fourth, Fifth, Sixth, Seventh, Eighth, Ninth, Tenth, Eleventh, Twelfth +} + +fn enum_with_excessive_missing_variants() { + match ExcessiveEnum::First { + //~^ ERROR `Second`, `Third`, `Fourth` and 8 more not covered + + ExcessiveEnum::First => () + } +} + +fn enum_struct_variant() { + match Color::Red { + //~^ ERROR non-exhaustive patterns: `CustomRGBA { a: true, .. }` not covered + Color::Red => (), + Color::Green => (), + Color::CustomRGBA { a: false, r: _, g: _, b: 0 } => (), + Color::CustomRGBA { a: false, r: _, g: _, b: _ } => () + } +} + +enum Enum { + First, + Second(bool) +} + +fn vectors_with_nested_enums() { + let x: &'static [Enum] = &[Enum::First, Enum::Second(false)]; + match *x { + //~^ ERROR non-exhaustive patterns: `[Second(true), Second(false)]` not covered + [] => (), + [_] => (), + [Enum::First, _] => (), + [Enum::Second(true), Enum::First] => (), + [Enum::Second(true), Enum::Second(true)] => (), + [Enum::Second(false), _] => (), + [_, _, ref tail @ .., _] => () + } +} + +fn missing_nil() { + match ((), false) { + //~^ ERROR non-exhaustive patterns: `((), false)` not covered + ((), true) => () + } +} + +fn main() {} diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr new file mode 100644 index 000000000..b0cfd631f --- /dev/null +++ b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr @@ -0,0 +1,129 @@ +error[E0004]: non-exhaustive patterns: `Foo { first: false, second: Some([_, _, _, _]) }` not covered + --> $DIR/non-exhaustive-pattern-witness.rs:7:11 + | +LL | match (Foo { first: true, second: None }) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { first: false, second: Some([_, _, _, _]) }` not covered + | +note: `Foo` defined here + --> $DIR/non-exhaustive-pattern-witness.rs:1:8 + | +LL | struct Foo { + | ^^^ + = note: the matched value is of type `Foo` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ Foo { first: false, second: Some([1, 2, 3, 4]) } => (), +LL + Foo { first: false, second: Some([_, _, _, _]) } => todo!() + | + +error[E0004]: non-exhaustive patterns: `Red` not covered + --> $DIR/non-exhaustive-pattern-witness.rs:23:11 + | +LL | match Color::Red { + | ^^^^^^^^^^ pattern `Red` not covered + | +note: `Color` defined here + --> $DIR/non-exhaustive-pattern-witness.rs:17:5 + | +LL | enum Color { + | ----- +LL | Red, + | ^^^ not covered + = note: the matched value is of type `Color` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ Color::Green => (), +LL + Red => todo!() + | + +error[E0004]: non-exhaustive patterns: `East`, `South` and `West` not covered + --> $DIR/non-exhaustive-pattern-witness.rs:35:11 + | +LL | match Direction::North { + | ^^^^^^^^^^^^^^^^ patterns `East`, `South` and `West` not covered + | +note: `Direction` defined here + --> $DIR/non-exhaustive-pattern-witness.rs:31:12 + | +LL | enum Direction { + | --------- +LL | North, East, South, West + | ^^^^ ^^^^^ ^^^^ not covered + | | | + | | not covered + | not covered + = note: the matched value is of type `Direction` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ Direction::North => (), +LL + East | South | West => todo!() + | + +error[E0004]: non-exhaustive patterns: `Second`, `Third`, `Fourth` and 8 more not covered + --> $DIR/non-exhaustive-pattern-witness.rs:46:11 + | +LL | match ExcessiveEnum::First { + | ^^^^^^^^^^^^^^^^^^^^ patterns `Second`, `Third`, `Fourth` and 8 more not covered + | +note: `ExcessiveEnum` defined here + --> $DIR/non-exhaustive-pattern-witness.rs:41:6 + | +LL | enum ExcessiveEnum { + | ^^^^^^^^^^^^^ + = note: the matched value is of type `ExcessiveEnum` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms + | +LL ~ ExcessiveEnum::First => (), +LL + _ => todo!() + | + +error[E0004]: non-exhaustive patterns: `CustomRGBA { a: true, .. }` not covered + --> $DIR/non-exhaustive-pattern-witness.rs:54:11 + | +LL | match Color::Red { + | ^^^^^^^^^^ pattern `CustomRGBA { a: true, .. }` not covered + | +note: `Color` defined here + --> $DIR/non-exhaustive-pattern-witness.rs:19:5 + | +LL | enum Color { + | ----- +... +LL | CustomRGBA { a: bool, r: u8, g: u8, b: u8 } + | ^^^^^^^^^^ not covered + = note: the matched value is of type `Color` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ Color::CustomRGBA { a: false, r: _, g: _, b: _ } => (), +LL + CustomRGBA { a: true, .. } => todo!() + | + +error[E0004]: non-exhaustive patterns: `[Second(true), Second(false)]` not covered + --> $DIR/non-exhaustive-pattern-witness.rs:70:11 + | +LL | match *x { + | ^^ pattern `[Second(true), Second(false)]` not covered + | + = note: the matched value is of type `[Enum]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ [_, _, ref tail @ .., _] => (), +LL + [Second(true), Second(false)] => todo!() + | + +error[E0004]: non-exhaustive patterns: `((), false)` not covered + --> $DIR/non-exhaustive-pattern-witness.rs:83:11 + | +LL | match ((), false) { + | ^^^^^^^^^^^ pattern `((), false)` not covered + | + = note: the matched value is of type `((), bool)` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ ((), true) => (), +LL + ((), false) => todo!() + | + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/refutable-pattern-errors.rs b/src/test/ui/pattern/usefulness/refutable-pattern-errors.rs new file mode 100644 index 000000000..7c9aa51e7 --- /dev/null +++ b/src/test/ui/pattern/usefulness/refutable-pattern-errors.rs @@ -0,0 +1,7 @@ +fn func((1, (Some(1), 2..=3)): (isize, (Option<isize>, isize))) { } +//~^ ERROR refutable pattern in function argument: `(_, _)` not covered + +fn main() { + let (1, (Some(1), 2..=3)) = (1, (None, 2)); + //~^ ERROR refutable pattern in local binding: `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered +} diff --git a/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr b/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr new file mode 100644 index 000000000..d1dacc822 --- /dev/null +++ b/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr @@ -0,0 +1,25 @@ +error[E0005]: refutable pattern in function argument: `(_, _)` not covered + --> $DIR/refutable-pattern-errors.rs:1:9 + | +LL | fn func((1, (Some(1), 2..=3)): (isize, (Option<isize>, isize))) { } + | ^^^^^^^^^^^^^^^^^^^^^ pattern `(_, _)` not covered + | + = note: the matched value is of type `(isize, (Option<isize>, isize))` + +error[E0005]: refutable pattern in local binding: `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered + --> $DIR/refutable-pattern-errors.rs:5:9 + | +LL | let (1, (Some(1), 2..=3)) = (1, (None, 2)); + | ^^^^^^^^^^^^^^^^^^^^^ patterns `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html + = note: the matched value is of type `(i32, (Option<i32>, i32))` +help: you might want to use `if let` to ignore the variants that aren't matched + | +LL | if let (1, (Some(1), 2..=3)) = (1, (None, 2)) { todo!() } + | ++ ~~~~~~~~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0005`. diff --git a/src/test/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs b/src/test/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs new file mode 100644 index 000000000..a2d9e1935 --- /dev/null +++ b/src/test/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs @@ -0,0 +1,5 @@ +fn main() { + let f = |3: isize| println!("hello"); + //~^ ERROR refutable pattern in function argument: `_` not covered + f(4); +} diff --git a/src/test/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr b/src/test/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr new file mode 100644 index 000000000..c9d8cf43f --- /dev/null +++ b/src/test/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr @@ -0,0 +1,11 @@ +error[E0005]: refutable pattern in function argument: `_` not covered + --> $DIR/refutable-pattern-in-fn-arg.rs:2:14 + | +LL | let f = |3: isize| println!("hello"); + | ^ pattern `_` not covered + | + = note: the matched value is of type `isize` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0005`. diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs b/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs new file mode 100644 index 000000000..4bf8d0fd2 --- /dev/null +++ b/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs @@ -0,0 +1,31 @@ +#![deny(unreachable_patterns)] + +fn main() { + let s = &[0x00; 4][..]; //Slice of any value + const MAGIC_TEST: &[u32] = &[4, 5, 6, 7]; //Const slice to pattern match with + match s { + MAGIC_TEST => (), + [0x00, 0x00, 0x00, 0x00] => (), + [4, 5, 6, 7] => (), //~ ERROR unreachable pattern + _ => (), + } + match s { + [0x00, 0x00, 0x00, 0x00] => (), + MAGIC_TEST => (), + [4, 5, 6, 7] => (), //~ ERROR unreachable pattern + _ => (), + } + match s { + [0x00, 0x00, 0x00, 0x00] => (), + [4, 5, 6, 7] => (), + MAGIC_TEST => (), //~ ERROR unreachable pattern + _ => (), + } + const FOO: [u32; 1] = [4]; + match [99] { + [0x00] => (), + [4] => (), + FOO => (), //~ ERROR unreachable pattern + _ => (), + } +} diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr b/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr new file mode 100644 index 000000000..dcad11a38 --- /dev/null +++ b/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr @@ -0,0 +1,32 @@ +error: unreachable pattern + --> $DIR/slice-pattern-const-2.rs:9:9 + | +LL | [4, 5, 6, 7] => (), + | ^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/slice-pattern-const-2.rs:1:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const-2.rs:15:9 + | +LL | [4, 5, 6, 7] => (), + | ^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const-2.rs:21:9 + | +LL | MAGIC_TEST => (), + | ^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const-2.rs:28:9 + | +LL | FOO => (), + | ^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-3.rs b/src/test/ui/pattern/usefulness/slice-pattern-const-3.rs new file mode 100644 index 000000000..2ca8323f0 --- /dev/null +++ b/src/test/ui/pattern/usefulness/slice-pattern-const-3.rs @@ -0,0 +1,31 @@ +#![deny(unreachable_patterns)] + +fn main() { + let s = &["0x00"; 4][..]; //Slice of any value + const MAGIC_TEST: &[&str] = &["4", "5", "6", "7"]; //Const slice to pattern match with + match s { + MAGIC_TEST => (), + ["0x00", "0x00", "0x00", "0x00"] => (), + ["4", "5", "6", "7"] => (), //~ ERROR unreachable pattern + _ => (), + } + match s { + ["0x00", "0x00", "0x00", "0x00"] => (), + MAGIC_TEST => (), + ["4", "5", "6", "7"] => (), //~ ERROR unreachable pattern + _ => (), + } + match s { + ["0x00", "0x00", "0x00", "0x00"] => (), + ["4", "5", "6", "7"] => (), + MAGIC_TEST => (), //~ ERROR unreachable pattern + _ => (), + } + const FOO: [&str; 1] = ["boo"]; + match ["baa"] { + ["0x00"] => (), + ["boo"] => (), + FOO => (), //~ ERROR unreachable pattern + _ => (), + } +} diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-3.stderr b/src/test/ui/pattern/usefulness/slice-pattern-const-3.stderr new file mode 100644 index 000000000..b90b3a88a --- /dev/null +++ b/src/test/ui/pattern/usefulness/slice-pattern-const-3.stderr @@ -0,0 +1,32 @@ +error: unreachable pattern + --> $DIR/slice-pattern-const-3.rs:9:9 + | +LL | ["4", "5", "6", "7"] => (), + | ^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/slice-pattern-const-3.rs:1:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const-3.rs:15:9 + | +LL | ["4", "5", "6", "7"] => (), + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const-3.rs:21:9 + | +LL | MAGIC_TEST => (), + | ^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const-3.rs:28:9 + | +LL | FOO => (), + | ^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const.rs b/src/test/ui/pattern/usefulness/slice-pattern-const.rs new file mode 100644 index 000000000..89195d5b1 --- /dev/null +++ b/src/test/ui/pattern/usefulness/slice-pattern-const.rs @@ -0,0 +1,54 @@ +#![deny(unreachable_patterns)] + +fn main() { + let s = &[0x00; 4][..]; //Slice of any value + const MAGIC_TEST: &[u8] = b"TEST"; //Const slice to pattern match with + match s { + MAGIC_TEST => (), + [0x00, 0x00, 0x00, 0x00] => (), + [84, 69, 83, 84] => (), //~ ERROR unreachable pattern + _ => (), + } + match s { + [0x00, 0x00, 0x00, 0x00] => (), + MAGIC_TEST => (), + [84, 69, 83, 84] => (), //~ ERROR unreachable pattern + _ => (), + } + match s { + [0x00, 0x00, 0x00, 0x00] => (), + [84, 69, 83, 84] => (), + MAGIC_TEST => (), //~ ERROR unreachable pattern + _ => (), + } + const FOO: [u8; 1] = [4]; + match [99] { + [0x00] => (), + [4] => (), + FOO => (), //~ ERROR unreachable pattern + _ => (), + } + const BAR: &[u8; 1] = &[4]; + match &[99] { + [0x00] => (), + [4] => (), + BAR => (), //~ ERROR unreachable pattern + b"a" => (), + _ => (), + } + + const BOO: &[u8; 0] = &[]; + match &[] { + [] => (), + BOO => (), //~ ERROR unreachable pattern + b"" => (), //~ ERROR unreachable pattern + _ => (), //~ ERROR unreachable pattern + } + + const CONST1: &[bool; 1] = &[true]; + match &[false] { + CONST1 => {} + [true] => {} //~ ERROR unreachable pattern + [false] => {} + } +} diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const.stderr b/src/test/ui/pattern/usefulness/slice-pattern-const.stderr new file mode 100644 index 000000000..1fffb9fed --- /dev/null +++ b/src/test/ui/pattern/usefulness/slice-pattern-const.stderr @@ -0,0 +1,62 @@ +error: unreachable pattern + --> $DIR/slice-pattern-const.rs:9:9 + | +LL | [84, 69, 83, 84] => (), + | ^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/slice-pattern-const.rs:1:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const.rs:15:9 + | +LL | [84, 69, 83, 84] => (), + | ^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const.rs:21:9 + | +LL | MAGIC_TEST => (), + | ^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const.rs:28:9 + | +LL | FOO => (), + | ^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const.rs:35:9 + | +LL | BAR => (), + | ^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const.rs:43:9 + | +LL | BOO => (), + | ^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const.rs:44:9 + | +LL | b"" => (), + | ^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const.rs:45:9 + | +LL | _ => (), + | ^ + +error: unreachable pattern + --> $DIR/slice-pattern-const.rs:51:9 + | +LL | [true] => {} + | ^^^^^^ + +error: aborting due to 9 previous errors + diff --git a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs new file mode 100644 index 000000000..46e0da5be --- /dev/null +++ b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs @@ -0,0 +1,129 @@ +fn main() { + let s: &[bool] = &[true; 0]; + let s1: &[bool; 1] = &[false; 1]; + let s2: &[bool; 2] = &[false; 2]; + let s3: &[bool; 3] = &[false; 3]; + let s10: &[bool; 10] = &[false; 10]; + + match s2 { + //~^ ERROR `&[false, _]` not covered + [true, .., true] => {} + } + match s3 { + //~^ ERROR `&[false, ..]` not covered + [true, .., true] => {} + } + match s10 { + //~^ ERROR `&[false, ..]` not covered + [true, .., true] => {} + } + + match s1 { + [true, ..] => {} + [.., false] => {} + } + match s2 { + //~^ ERROR `&[false, true]` not covered + [true, ..] => {} + [.., false] => {} + } + match s3 { + //~^ ERROR `&[false, .., true]` not covered + [true, ..] => {} + [.., false] => {} + } + match s { + //~^ ERROR `&[false, .., true]` not covered + [] => {} + [true, ..] => {} + [.., false] => {} + } + + match s { + //~^ ERROR `&[_, ..]` not covered + [] => {} + } + match s { + //~^ ERROR `&[_, _, ..]` not covered + [] => {} + [_] => {} + } + match s { + //~^ ERROR `&[false, ..]` not covered + [] => {} + [true, ..] => {} + } + match s { + //~^ ERROR `&[false, _, ..]` not covered + [] => {} + [_] => {} + [true, ..] => {} + } + match s { + //~^ ERROR `&[_, .., false]` not covered + [] => {} + [_] => {} + [.., true] => {} + } + + match s { + //~^ ERROR `&[_, _, .., true]` not covered + [] => {} + [_] => {} + [_, _] => {} + [.., false] => {} + } + match s { + //~^ ERROR `&[true, _, .., _]` not covered + [] => {} + [_] => {} + [_, _] => {} + [false, .., false] => {} + } + + const CONST: &[bool] = &[true]; + match s { + //~^ ERROR `&[]` and `&[_, _, ..]` not covered + &[true] => {} + } + match s { + //~^ ERROR `&[]` and `&[_, _, ..]` not covered + CONST => {} + } + match s { + //~^ ERROR `&[]` and `&[_, _, ..]` not covered + CONST => {} + &[false] => {} + } + match s { + //~^ ERROR `&[]` and `&[_, _, ..]` not covered + &[false] => {} + CONST => {} + } + match s { + //~^ ERROR `&[_, _, ..]` not covered + &[] => {} + CONST => {} + } + match s { + //~^ ERROR `&[false]` not covered + &[] => {} + CONST => {} + &[_, _, ..] => {} + } + match s { + [] => {} + [false] => {} + CONST => {} + [_, _, ..] => {} + } + const CONST1: &[bool; 1] = &[true]; + match s1 { + //~^ ERROR `&[false]` not covered + CONST1 => {} + } + match s1 { + CONST1 => {} + [false] => {} + } +} diff --git a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr new file mode 100644 index 000000000..5d1e170ae --- /dev/null +++ b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr @@ -0,0 +1,263 @@ +error[E0004]: non-exhaustive patterns: `&[false, _]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:8:11 + | +LL | match s2 { + | ^^ pattern `&[false, _]` not covered + | + = note: the matched value is of type `&[bool; 2]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ [true, .., true] => {} +LL + &[false, _] => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:12:11 + | +LL | match s3 { + | ^^ pattern `&[false, ..]` not covered + | + = note: the matched value is of type `&[bool; 3]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ [true, .., true] => {} +LL + &[false, ..] => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:16:11 + | +LL | match s10 { + | ^^^ pattern `&[false, ..]` not covered + | + = note: the matched value is of type `&[bool; 10]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ [true, .., true] => {} +LL + &[false, ..] => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[false, true]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:25:11 + | +LL | match s2 { + | ^^ pattern `&[false, true]` not covered + | + = note: the matched value is of type `&[bool; 2]` +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 ~ [.., false] => {} +LL + &[false, true] => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[false, .., true]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:30:11 + | +LL | match s3 { + | ^^ pattern `&[false, .., true]` not covered + | + = note: the matched value is of type `&[bool; 3]` +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 ~ [.., false] => {} +LL + &[false, .., true] => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[false, .., true]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:35:11 + | +LL | match s { + | ^ pattern `&[false, .., true]` not covered + | + = note: the matched value is of type `&[bool]` +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 ~ [.., false] => {} +LL + &[false, .., true] => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:42:11 + | +LL | match s { + | ^ pattern `&[_, ..]` not covered + | + = note: the matched value is of type `&[bool]` +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 ~ [] => {} +LL + &[_, ..] => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:46:11 + | +LL | match s { + | ^ pattern `&[_, _, ..]` not covered + | + = note: the matched value is of type `&[bool]` +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 ~ [_] => {} +LL + &[_, _, ..] => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:51:11 + | +LL | match s { + | ^ pattern `&[false, ..]` not covered + | + = note: the matched value is of type `&[bool]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ [true, ..] => {} +LL + &[false, ..] => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[false, _, ..]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:56:11 + | +LL | match s { + | ^ pattern `&[false, _, ..]` not covered + | + = note: the matched value is of type `&[bool]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ [true, ..] => {} +LL + &[false, _, ..] => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[_, .., false]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:62:11 + | +LL | match s { + | ^ pattern `&[_, .., false]` not covered + | + = note: the matched value is of type `&[bool]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ [.., true] => {} +LL + &[_, .., false] => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[_, _, .., true]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:69:11 + | +LL | match s { + | ^ pattern `&[_, _, .., true]` not covered + | + = note: the matched value is of type `&[bool]` +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 ~ [.., false] => {} +LL + &[_, _, .., true] => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[true, _, .., _]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:76:11 + | +LL | match s { + | ^ pattern `&[true, _, .., _]` not covered + | + = note: the matched value is of type `&[bool]` +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 ~ [false, .., false] => {} +LL + &[true, _, .., _] => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:85:11 + | +LL | match s { + | ^ patterns `&[]` and `&[_, _, ..]` not covered + | + = note: the matched value is of type `&[bool]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ &[true] => {} +LL + &[] | &[_, _, ..] => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:89:11 + | +LL | match s { + | ^ patterns `&[]` and `&[_, _, ..]` not covered + | + = note: the matched value is of type `&[bool]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ CONST => {} +LL + &[] | &[_, _, ..] => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:93:11 + | +LL | match s { + | ^ patterns `&[]` and `&[_, _, ..]` not covered + | + = note: the matched value is of type `&[bool]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ &[false] => {} +LL + &[] | &[_, _, ..] => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:98:11 + | +LL | match s { + | ^ patterns `&[]` and `&[_, _, ..]` not covered + | + = note: the matched value is of type `&[bool]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ CONST => {} +LL + &[] | &[_, _, ..] => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:103:11 + | +LL | match s { + | ^ pattern `&[_, _, ..]` not covered + | + = note: the matched value is of type `&[bool]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ CONST => {} +LL + &[_, _, ..] => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[false]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:108:11 + | +LL | match s { + | ^ pattern `&[false]` not covered + | + = note: the matched value is of type `&[bool]` +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 ~ &[_, _, ..] => {} +LL + &[false] => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[false]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:121:11 + | +LL | match s1 { + | ^^ pattern `&[false]` not covered + | + = note: the matched value is of type `&[bool; 1]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ CONST1 => {} +LL + &[false] => todo!() + | + +error: aborting due to 20 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/slice-patterns-irrefutable.rs b/src/test/ui/pattern/usefulness/slice-patterns-irrefutable.rs new file mode 100644 index 000000000..cbf64e2c5 --- /dev/null +++ b/src/test/ui/pattern/usefulness/slice-patterns-irrefutable.rs @@ -0,0 +1,26 @@ +// check-pass + +fn main() { + let s: &[bool] = &[true; 0]; + let s0: &[bool; 0] = &[]; + let s1: &[bool; 1] = &[false; 1]; + let s2: &[bool; 2] = &[false; 2]; + + let [] = s0; + let [_] = s1; + let [_, _] = s2; + + let [..] = s; + let [..] = s0; + let [..] = s1; + let [..] = s2; + + let [_, ..] = s1; + let [.., _] = s1; + let [_, ..] = s2; + let [.., _] = s2; + + let [_, _, ..] = s2; + let [_, .., _] = s2; + let [.., _, _] = s2; +} diff --git a/src/test/ui/pattern/usefulness/slice-patterns-reachability.rs b/src/test/ui/pattern/usefulness/slice-patterns-reachability.rs new file mode 100644 index 000000000..7c747b5e0 --- /dev/null +++ b/src/test/ui/pattern/usefulness/slice-patterns-reachability.rs @@ -0,0 +1,25 @@ +#![deny(unreachable_patterns)] + +fn main() { + let s: &[bool] = &[]; + + match s { + [true, ..] => {} + [true, ..] => {} //~ ERROR unreachable pattern + [true] => {} //~ ERROR unreachable pattern + [..] => {} + } + match s { + [.., true] => {} + [.., true] => {} //~ ERROR unreachable pattern + [true] => {} //~ ERROR unreachable pattern + [..] => {} + } + match s { + [false, .., true] => {} + [false, .., true] => {} //~ ERROR unreachable pattern + [false, true] => {} //~ ERROR unreachable pattern + [false] => {} + [..] => {} + } +} diff --git a/src/test/ui/pattern/usefulness/slice-patterns-reachability.stderr b/src/test/ui/pattern/usefulness/slice-patterns-reachability.stderr new file mode 100644 index 000000000..607ffb765 --- /dev/null +++ b/src/test/ui/pattern/usefulness/slice-patterns-reachability.stderr @@ -0,0 +1,44 @@ +error: unreachable pattern + --> $DIR/slice-patterns-reachability.rs:8:9 + | +LL | [true, ..] => {} + | ^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/slice-patterns-reachability.rs:1:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-patterns-reachability.rs:9:9 + | +LL | [true] => {} + | ^^^^^^ + +error: unreachable pattern + --> $DIR/slice-patterns-reachability.rs:14:9 + | +LL | [.., true] => {} + | ^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-patterns-reachability.rs:15:9 + | +LL | [true] => {} + | ^^^^^^ + +error: unreachable pattern + --> $DIR/slice-patterns-reachability.rs:20:9 + | +LL | [false, .., true] => {} + | ^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-patterns-reachability.rs:21:9 + | +LL | [false, true] => {} + | ^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/pattern/usefulness/stable-gated-fields.rs b/src/test/ui/pattern/usefulness/stable-gated-fields.rs new file mode 100644 index 000000000..90f40a8d6 --- /dev/null +++ b/src/test/ui/pattern/usefulness/stable-gated-fields.rs @@ -0,0 +1,16 @@ +// aux-build:unstable.rs + +extern crate unstable; + +use unstable::UnstableStruct; + +fn main() { + let UnstableStruct { stable } = UnstableStruct::default(); + //~^ pattern does not mention field `stable2` and inaccessible fields + + let UnstableStruct { stable, stable2 } = UnstableStruct::default(); + //~^ pattern requires `..` due to inaccessible fields + + // OK: stable field is matched + let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); +} diff --git a/src/test/ui/pattern/usefulness/stable-gated-fields.stderr b/src/test/ui/pattern/usefulness/stable-gated-fields.stderr new file mode 100644 index 000000000..cf98c51a2 --- /dev/null +++ b/src/test/ui/pattern/usefulness/stable-gated-fields.stderr @@ -0,0 +1,29 @@ +error[E0027]: pattern does not mention field `stable2` and inaccessible fields + --> $DIR/stable-gated-fields.rs:8:9 + | +LL | let UnstableStruct { stable } = UnstableStruct::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `stable2` and inaccessible fields + | +help: include the missing field in the pattern and ignore the inaccessible fields + | +LL | let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); + | ~~~~~~~~~~~~~~~ +help: if you don't care about this missing field, you can explicitly ignore it + | +LL | let UnstableStruct { stable, .. } = UnstableStruct::default(); + | ~~~~~~ + +error: pattern requires `..` due to inaccessible fields + --> $DIR/stable-gated-fields.rs:11:9 + | +LL | let UnstableStruct { stable, stable2 } = UnstableStruct::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: ignore the inaccessible and unused fields + | +LL | let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0027`. diff --git a/src/test/ui/pattern/usefulness/stable-gated-patterns.rs b/src/test/ui/pattern/usefulness/stable-gated-patterns.rs new file mode 100644 index 000000000..ff1c472e2 --- /dev/null +++ b/src/test/ui/pattern/usefulness/stable-gated-patterns.rs @@ -0,0 +1,18 @@ +// aux-build:unstable.rs + +extern crate unstable; + +use unstable::UnstableEnum; + +fn main() { + match UnstableEnum::Stable { + UnstableEnum::Stable => {} + } + //~^^^ non-exhaustive patterns: `Stable2` and `_` not covered + + match UnstableEnum::Stable { + UnstableEnum::Stable => {} + UnstableEnum::Stable2 => {} + } + //~^^^^ non-exhaustive patterns: `_` not covered +} diff --git a/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr b/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr new file mode 100644 index 000000000..98c75953a --- /dev/null +++ b/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr @@ -0,0 +1,42 @@ +error[E0004]: non-exhaustive patterns: `Stable2` and `_` not covered + --> $DIR/stable-gated-patterns.rs:8:11 + | +LL | match UnstableEnum::Stable { + | ^^^^^^^^^^^^^^^^^^^^ patterns `Stable2` and `_` not covered + | +note: `UnstableEnum` defined here + --> $DIR/auxiliary/unstable.rs:9:5 + | +LL | pub enum UnstableEnum { + | --------------------- +... +LL | Stable2, + | ^^^^^^^ not covered + = note: the matched value is of type `UnstableEnum` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ UnstableEnum::Stable => {} +LL + Stable2 | _ => todo!() + | + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/stable-gated-patterns.rs:13:11 + | +LL | match UnstableEnum::Stable { + | ^^^^^^^^^^^^^^^^^^^^ pattern `_` not covered + | +note: `UnstableEnum` defined here + --> $DIR/auxiliary/unstable.rs:5:1 + | +LL | pub enum UnstableEnum { + | ^^^^^^^^^^^^^^^^^^^^^ + = note: the matched value is of type `UnstableEnum` +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 ~ UnstableEnum::Stable2 => {} +LL + _ => todo!() + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/struct-like-enum-nonexhaustive.rs b/src/test/ui/pattern/usefulness/struct-like-enum-nonexhaustive.rs new file mode 100644 index 000000000..b1fc0f5ad --- /dev/null +++ b/src/test/ui/pattern/usefulness/struct-like-enum-nonexhaustive.rs @@ -0,0 +1,12 @@ +enum A { + B { x: Option<isize> }, + C +} + +fn main() { + let x = A::B { x: Some(3) }; + match x { //~ ERROR non-exhaustive patterns + A::C => {} + A::B { x: None } => {} + } +} diff --git a/src/test/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr b/src/test/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr new file mode 100644 index 000000000..6127fad3f --- /dev/null +++ b/src/test/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr @@ -0,0 +1,23 @@ +error[E0004]: non-exhaustive patterns: `B { x: Some(_) }` not covered + --> $DIR/struct-like-enum-nonexhaustive.rs:8:11 + | +LL | match x { + | ^ pattern `B { x: Some(_) }` not covered + | +note: `A` defined here + --> $DIR/struct-like-enum-nonexhaustive.rs:2:5 + | +LL | enum A { + | - +LL | B { x: Option<isize> }, + | ^ not covered + = note: the matched value is of type `A` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ A::B { x: None } => {} +LL + B { x: Some(_) } => todo!() + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/struct-pattern-match-useless.rs b/src/test/ui/pattern/usefulness/struct-pattern-match-useless.rs new file mode 100644 index 000000000..93f0a9317 --- /dev/null +++ b/src/test/ui/pattern/usefulness/struct-pattern-match-useless.rs @@ -0,0 +1,15 @@ +#![deny(unreachable_patterns)] + +struct Foo { + x: isize, + y: isize, +} + +pub fn main() { + let a = Foo { x: 1, y: 2 }; + match a { + Foo { x: _x, y: _y } => (), + Foo { .. } => () //~ ERROR unreachable pattern + } + +} diff --git a/src/test/ui/pattern/usefulness/struct-pattern-match-useless.stderr b/src/test/ui/pattern/usefulness/struct-pattern-match-useless.stderr new file mode 100644 index 000000000..fbee33de6 --- /dev/null +++ b/src/test/ui/pattern/usefulness/struct-pattern-match-useless.stderr @@ -0,0 +1,16 @@ +error: unreachable pattern + --> $DIR/struct-pattern-match-useless.rs:12:9 + | +LL | Foo { x: _x, y: _y } => (), + | -------------------- matches any value +LL | Foo { .. } => () + | ^^^^^^^^^^ unreachable pattern + | +note: the lint level is defined here + --> $DIR/struct-pattern-match-useless.rs:1:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/pattern/usefulness/top-level-alternation.rs b/src/test/ui/pattern/usefulness/top-level-alternation.rs new file mode 100644 index 000000000..076de8461 --- /dev/null +++ b/src/test/ui/pattern/usefulness/top-level-alternation.rs @@ -0,0 +1,59 @@ +#![feature(let_else)] + +#![deny(unreachable_patterns)] + +fn main() { + while let 0..=2 | 1 = 0 {} //~ ERROR unreachable pattern + if let 0..=2 | 1 = 0 {} //~ ERROR unreachable pattern + + match 0u8 { + 0 + | 0 => {} //~ ERROR unreachable pattern + _ => {} + } + match Some(0u8) { + Some(0) + | Some(0) => {} //~ ERROR unreachable pattern + _ => {} + } + match (0u8, 0u8) { + (0, _) | (_, 0) => {} + (0, 0) => {} //~ ERROR unreachable pattern + (1, 1) => {} + _ => {} + } + match (0u8, 0u8) { + (0, 1) | (2, 3) => {} + (0, 3) => {} + (2, 1) => {} + _ => {} + } + match (0u8, 0u8) { + (_, 0) | (_, 1) => {} + _ => {} + } + match (0u8, 0u8) { + (0, _) | (1, _) => {} + _ => {} + } + match Some(0u8) { + None | Some(_) => {} + _ => {} //~ ERROR unreachable pattern + } + match Some(0u8) { + None | Some(_) => {} + Some(_) => {} //~ ERROR unreachable pattern + None => {} //~ ERROR unreachable pattern + } + match Some(0u8) { + Some(_) => {} + None => {} + None | Some(_) => {} //~ ERROR unreachable pattern + } + match 0u8 { + 1 | 2 => {}, + 1..=2 => {}, //~ ERROR unreachable pattern + _ => {}, + } + let (0 | 0) = 0 else { return }; //~ ERROR unreachable pattern +} diff --git a/src/test/ui/pattern/usefulness/top-level-alternation.stderr b/src/test/ui/pattern/usefulness/top-level-alternation.stderr new file mode 100644 index 000000000..dd5936fdc --- /dev/null +++ b/src/test/ui/pattern/usefulness/top-level-alternation.stderr @@ -0,0 +1,74 @@ +error: unreachable pattern + --> $DIR/top-level-alternation.rs:6:23 + | +LL | while let 0..=2 | 1 = 0 {} + | ^ + | +note: the lint level is defined here + --> $DIR/top-level-alternation.rs:3:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/top-level-alternation.rs:7:20 + | +LL | if let 0..=2 | 1 = 0 {} + | ^ + +error: unreachable pattern + --> $DIR/top-level-alternation.rs:11:15 + | +LL | | 0 => {} + | ^ + +error: unreachable pattern + --> $DIR/top-level-alternation.rs:16:15 + | +LL | | Some(0) => {} + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/top-level-alternation.rs:21:9 + | +LL | (0, 0) => {} + | ^^^^^^ + +error: unreachable pattern + --> $DIR/top-level-alternation.rs:41:9 + | +LL | _ => {} + | ^ + +error: unreachable pattern + --> $DIR/top-level-alternation.rs:45:9 + | +LL | Some(_) => {} + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/top-level-alternation.rs:46:9 + | +LL | None => {} + | ^^^^ + +error: unreachable pattern + --> $DIR/top-level-alternation.rs:51:9 + | +LL | None | Some(_) => {} + | ^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/top-level-alternation.rs:55:9 + | +LL | 1..=2 => {}, + | ^^^^^ + +error: unreachable pattern + --> $DIR/top-level-alternation.rs:58:14 + | +LL | let (0 | 0) = 0 else { return }; + | ^ + +error: aborting due to 11 previous errors + diff --git a/src/test/ui/pattern/usefulness/tuple-struct-nonexhaustive.rs b/src/test/ui/pattern/usefulness/tuple-struct-nonexhaustive.rs new file mode 100644 index 000000000..76bcf3fbd --- /dev/null +++ b/src/test/ui/pattern/usefulness/tuple-struct-nonexhaustive.rs @@ -0,0 +1,9 @@ +struct Foo(isize, isize); + +fn main() { + let x = Foo(1, 2); + match x { //~ ERROR non-exhaustive + Foo(1, b) => println!("{}", b), + Foo(2, b) => println!("{}", b) + } +} diff --git a/src/test/ui/pattern/usefulness/tuple-struct-nonexhaustive.stderr b/src/test/ui/pattern/usefulness/tuple-struct-nonexhaustive.stderr new file mode 100644 index 000000000..e2a65ff85 --- /dev/null +++ b/src/test/ui/pattern/usefulness/tuple-struct-nonexhaustive.stderr @@ -0,0 +1,21 @@ +error[E0004]: non-exhaustive patterns: `Foo(_, _)` not covered + --> $DIR/tuple-struct-nonexhaustive.rs:5:11 + | +LL | match x { + | ^ pattern `Foo(_, _)` not covered + | +note: `Foo` defined here + --> $DIR/tuple-struct-nonexhaustive.rs:1:8 + | +LL | struct Foo(isize, isize); + | ^^^ + = note: the matched value is of type `Foo` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ Foo(2, b) => println!("{}", b), +LL + Foo(_, _) => todo!() + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/type_polymorphic_byte_str_literals.rs b/src/test/ui/pattern/usefulness/type_polymorphic_byte_str_literals.rs new file mode 100644 index 000000000..cb44c1da7 --- /dev/null +++ b/src/test/ui/pattern/usefulness/type_polymorphic_byte_str_literals.rs @@ -0,0 +1,36 @@ +#[deny(unreachable_patterns)] + +fn parse_data1(data: &[u8]) -> u32 { + match data { + b"" => 1, + _ => 2, + } +} + +fn parse_data2(data: &[u8]) -> u32 { + match data { //~ ERROR non-exhaustive patterns: `&[_, ..]` not covered + b"" => 1, + } +} + +fn parse_data3(data: &[u8; 0]) -> u8 { + match data { + b"" => 1, + } +} + +fn parse_data4(data: &[u8]) -> u8 { + match data { //~ ERROR non-exhaustive patterns + b"aaa" => 0, + [_, _, _] => 1, + } +} + +fn parse_data5(data: &[u8; 3]) -> u8 { + match data { + b"aaa" => 0, + [_, _, _] => 1, + } +} + +fn main() {} diff --git a/src/test/ui/pattern/usefulness/type_polymorphic_byte_str_literals.stderr b/src/test/ui/pattern/usefulness/type_polymorphic_byte_str_literals.stderr new file mode 100644 index 000000000..acae605da --- /dev/null +++ b/src/test/ui/pattern/usefulness/type_polymorphic_byte_str_literals.stderr @@ -0,0 +1,29 @@ +error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered + --> $DIR/type_polymorphic_byte_str_literals.rs:11:11 + | +LL | match data { + | ^^^^ pattern `&[_, ..]` not covered + | + = note: the matched value is of type `&[u8]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ b"" => 1, +LL ~ &[_, ..] => todo!(), + | + +error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 1 more not covered + --> $DIR/type_polymorphic_byte_str_literals.rs:23:11 + | +LL | match data { + | ^^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 1 more not covered + | + = note: the matched value is of type `&[u8]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms + | +LL ~ [_, _, _] => 1, +LL ~ _ => todo!(), + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/uninhabited.rs b/src/test/ui/pattern/usefulness/uninhabited.rs new file mode 100644 index 000000000..77cd0f400 --- /dev/null +++ b/src/test/ui/pattern/usefulness/uninhabited.rs @@ -0,0 +1,143 @@ +// check-pass +// aux-build:empty.rs +// +// This tests plays with matching and uninhabited types. This also serves as a test for the +// `tcx.is_ty_uninhabited_from()` function. +#![feature(never_type)] +#![feature(never_type_fallback)] +#![feature(exhaustive_patterns)] +#![deny(unreachable_patterns)] + +macro_rules! assert_empty { + ($ty:ty) => { + const _: () = { + fn assert_empty(x: $ty) { + match x {} + match Some(x) { + None => {} + } + } + }; + }; +} +macro_rules! assert_non_empty { + ($ty:ty) => { + const _: () = { + fn assert_non_empty(x: $ty) { + match x { + _ => {} + } + match Some(x) { + None => {} + Some(_) => {} + } + } + }; + }; +} + +extern crate empty; +assert_empty!(empty::EmptyForeignEnum); +assert_empty!(empty::VisiblyUninhabitedForeignStruct); +assert_non_empty!(empty::SecretlyUninhabitedForeignStruct); + +enum Void {} +assert_empty!(Void); + +enum Enum2 { + Foo(Void), + Bar(!), +} +assert_empty!(Enum2); + +enum Enum3 { + Foo(Void), + Bar { + x: u64, + y: !, + }, +} +assert_empty!(Enum3); + +enum Enum4 { + Foo(u64), + Bar(!), +} +assert_non_empty!(Enum4); + +struct Struct1(empty::EmptyForeignEnum); +assert_empty!(Struct1); + +struct Struct2 { + x: u64, + y: !, +} +assert_empty!(Struct2); + +union Union { + foo: !, +} +assert_non_empty!(Union); + +assert_empty!((!, String)); + +assert_non_empty!(&'static !); +assert_non_empty!(&'static Struct1); +assert_non_empty!(&'static &'static &'static !); + +assert_empty!([!; 1]); +assert_empty!([Void; 2]); +assert_non_empty!([!; 0]); +assert_non_empty!(&'static [!]); + +mod visibility { + /// This struct can only be seen to be inhabited in modules `b`, `c` or `d`, because otherwise + /// the uninhabitedness of both `SecretlyUninhabited` structs is hidden. + struct SometimesEmptyStruct { + x: a::b::SecretlyUninhabited, + y: c::AlsoSecretlyUninhabited, + } + + /// This enum can only be seen to be inhabited in module `d`. + enum SometimesEmptyEnum { + X(c::AlsoSecretlyUninhabited), + Y(c::d::VerySecretlyUninhabited), + } + + mod a { + use super::*; + pub mod b { + use super::*; + pub struct SecretlyUninhabited { + _priv: !, + } + assert_empty!(SometimesEmptyStruct); + } + + assert_non_empty!(SometimesEmptyStruct); + assert_non_empty!(SometimesEmptyEnum); + } + + mod c { + use super::*; + pub struct AlsoSecretlyUninhabited { + _priv: ::Struct1, + } + assert_empty!(SometimesEmptyStruct); + assert_non_empty!(SometimesEmptyEnum); + + pub mod d { + use super::*; + pub struct VerySecretlyUninhabited { + _priv: !, + } + assert_empty!(SometimesEmptyStruct); + assert_empty!(SometimesEmptyEnum); + } + } + + assert_non_empty!(SometimesEmptyStruct); + assert_non_empty!(SometimesEmptyEnum); +} + +fn main() {} diff --git a/src/test/ui/pattern/usefulness/unstable-gated-fields.rs b/src/test/ui/pattern/usefulness/unstable-gated-fields.rs new file mode 100644 index 000000000..2b473ae98 --- /dev/null +++ b/src/test/ui/pattern/usefulness/unstable-gated-fields.rs @@ -0,0 +1,18 @@ +#![feature(unstable_test_feature)] + +// aux-build:unstable.rs + +extern crate unstable; + +use unstable::UnstableStruct; + +fn main() { + let UnstableStruct { stable, stable2, } = UnstableStruct::default(); + //~^ pattern does not mention field `unstable` + + let UnstableStruct { stable, unstable, } = UnstableStruct::default(); + //~^ pattern does not mention field `stable2` + + // OK: stable field is matched + let UnstableStruct { stable, stable2, unstable } = UnstableStruct::default(); +} diff --git a/src/test/ui/pattern/usefulness/unstable-gated-fields.stderr b/src/test/ui/pattern/usefulness/unstable-gated-fields.stderr new file mode 100644 index 000000000..e4f5fa06b --- /dev/null +++ b/src/test/ui/pattern/usefulness/unstable-gated-fields.stderr @@ -0,0 +1,33 @@ +error[E0027]: pattern does not mention field `unstable` + --> $DIR/unstable-gated-fields.rs:10:9 + | +LL | let UnstableStruct { stable, stable2, } = UnstableStruct::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `unstable` + | +help: include the missing field in the pattern + | +LL | let UnstableStruct { stable, stable2, unstable } = UnstableStruct::default(); + | ~~~~~~~~~~~~ +help: if you don't care about this missing field, you can explicitly ignore it + | +LL | let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); + | ~~~~~~ + +error[E0027]: pattern does not mention field `stable2` + --> $DIR/unstable-gated-fields.rs:13:9 + | +LL | let UnstableStruct { stable, unstable, } = UnstableStruct::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `stable2` + | +help: include the missing field in the pattern + | +LL | let UnstableStruct { stable, unstable, stable2 } = UnstableStruct::default(); + | ~~~~~~~~~~~ +help: if you don't care about this missing field, you can explicitly ignore it + | +LL | let UnstableStruct { stable, unstable, .. } = UnstableStruct::default(); + | ~~~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0027`. diff --git a/src/test/ui/pattern/usefulness/unstable-gated-patterns.rs b/src/test/ui/pattern/usefulness/unstable-gated-patterns.rs new file mode 100644 index 000000000..bdab327fd --- /dev/null +++ b/src/test/ui/pattern/usefulness/unstable-gated-patterns.rs @@ -0,0 +1,22 @@ +#![feature(unstable_test_feature)] + +// aux-build:unstable.rs + +extern crate unstable; + +use unstable::UnstableEnum; + +fn main() { + match UnstableEnum::Stable { + UnstableEnum::Stable => {} + UnstableEnum::Stable2 => {} + } + //~^^^^ non-exhaustive patterns: `Unstable` not covered + + // Ok: all variants are explicitly matched + match UnstableEnum::Stable { + UnstableEnum::Stable => {} + UnstableEnum::Stable2 => {} + UnstableEnum::Unstable => {} + } +} diff --git a/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr b/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr new file mode 100644 index 000000000..f07a25ca8 --- /dev/null +++ b/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr @@ -0,0 +1,24 @@ +error[E0004]: non-exhaustive patterns: `Unstable` not covered + --> $DIR/unstable-gated-patterns.rs:10:11 + | +LL | match UnstableEnum::Stable { + | ^^^^^^^^^^^^^^^^^^^^ pattern `Unstable` not covered + | +note: `UnstableEnum` defined here + --> $DIR/auxiliary/unstable.rs:11:5 + | +LL | pub enum UnstableEnum { + | --------------------- +... +LL | Unstable, + | ^^^^^^^^ not covered + = note: the matched value is of type `UnstableEnum` +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 ~ UnstableEnum::Stable2 => {} +LL + Unstable => todo!() + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. |