Add tests

This commit is contained in:
Nadrieril 2024-03-10 14:15:03 +01:00
parent ceab6128fa
commit 50103ab14d
4 changed files with 165 additions and 67 deletions

View file

@ -3,15 +3,43 @@
#![feature(if_let_guard)] #![feature(if_let_guard)]
#[rustfmt::skip]
fn all_patterns_are_tested() {
// Even though `x` is never actually moved out of, we don't want borrowck results to be based on
// whether MIR lowering reveals which patterns are unreachable.
let x = String::new();
let _ = match true {
_ => {},
_ => drop(x),
};
// Borrowck must not know the second arm is never run.
drop(x); //~ ERROR use of moved value
let x = (String::new(), String::new());
match x {
(y, _) | (_, y) => (),
}
&x.0; //~ ERROR borrow of moved value
// Borrowck must not know the second pattern never matches.
&x.1; //~ ERROR borrow of moved value
}
#[rustfmt::skip]
fn guard_always_precedes_arm(y: i32) { fn guard_always_precedes_arm(y: i32) {
let mut x;
// x should always be initialized, as the only way to reach the arm is // x should always be initialized, as the only way to reach the arm is
// through the guard. // through the guard.
let mut x;
match y { match y {
0 | 2 if { x = 2; true } => x, 0 | 2 if { x = 2; true } => x,
_ => 2, _ => 2,
}; };
let mut x;
match y {
_ => 2,
0 | 2 if { x = 2; true } => x,
};
let mut x; let mut x;
match y { match y {
0 | 2 if let Some(()) = { x = 2; Some(()) } => x, 0 | 2 if let Some(()) = { x = 2; Some(()) } => x,
@ -19,51 +47,58 @@ fn guard_always_precedes_arm(y: i32) {
}; };
} }
#[rustfmt::skip]
fn guard_may_be_skipped(y: i32) { fn guard_may_be_skipped(y: i32) {
// Even though x *is* always initialized, we don't want to have borrowck results be based on
// whether MIR lowering reveals which patterns are exhaustive.
let x;
match y {
_ if { x = 2; true } => {},
// Borrowck must not know the guard is always run.
_ => drop(x), //~ ERROR used binding `x` is possibly-uninitialized
};
let x; let x;
// Even though x *is* always initialized, we don't want to have borrowck
// results be based on whether patterns are exhaustive.
match y { match y {
_ if { x = 2; true } => 1, _ if { x = 2; true } => 1,
_ if { // Borrowck must not know the guard is always run.
x; //~ ERROR E0381 _ if { x; false } => 2, //~ ERROR used binding `x` isn't initialized
false
} => 2,
_ => 3, _ => 3,
}; };
let x; let x;
match y { match y {
_ if let Some(()) = { x = 2; Some(()) } => 1, _ if let Some(()) = { x = 2; Some(()) } => 1,
_ if let Some(()) = { _ if let Some(()) = { x; None } => 2, //~ ERROR used binding `x` isn't initialized
x; //~ ERROR E0381
None
} => 2,
_ => 3, _ => 3,
}; };
} }
#[rustfmt::skip]
fn guard_may_be_taken(y: bool) { fn guard_may_be_taken(y: bool) {
let x = String::new();
// Even though x *is* never moved before the use, we don't want to have // Even though x *is* never moved before the use, we don't want to have
// borrowck results be based on whether patterns are disjoint. // borrowck results be based on whether patterns are disjoint.
let x = String::new();
match y { match y {
false if { drop(x); true } => 1, false if { drop(x); true } => {},
true => { // Borrowck must not know the guard is not run in the `true` case.
x; //~ ERROR use of moved value: `x` true => drop(x), //~ ERROR use of moved value: `x`
2 false => {},
} };
false => 3,
// Fine in the other order.
let x = String::new();
match y {
true => drop(x),
false if { drop(x); true } => {},
false => {},
}; };
let x = String::new(); let x = String::new();
match y { match y {
false if let Some(()) = { drop(x); Some(()) } => 1, false if let Some(()) = { drop(x); Some(()) } => {},
true => { true => drop(x), //~ ERROR use of moved value: `x`
x; //~ ERROR use of moved value: `x` false => {},
2
}
false => 3,
}; };
} }

View file

@ -1,14 +1,72 @@
error[E0381]: used binding `x` isn't initialized error[E0382]: use of moved value: `x`
--> $DIR/match-cfg-fake-edges.rs:29:13 --> $DIR/match-cfg-fake-edges.rs:16:10
|
LL | let x = String::new();
| - move occurs because `x` has type `String`, which does not implement the `Copy` trait
...
LL | _ => drop(x),
| - value moved here
...
LL | drop(x);
| ^ value used here after move
|
help: consider cloning the value if the performance cost is acceptable
|
LL | _ => drop(x.clone()),
| ++++++++
error[E0382]: borrow of moved value: `x.0`
--> $DIR/match-cfg-fake-edges.rs:22:5
|
LL | (y, _) | (_, y) => (),
| - value moved here
LL | }
LL | &x.0;
| ^^^^ value borrowed here after move
|
= note: move occurs because `x.0` has type `String`, which does not implement the `Copy` trait
help: borrow this binding in the pattern to avoid moving the value
|
LL | (ref y, _) | (_, y) => (),
| +++
error[E0382]: borrow of moved value: `x.1`
--> $DIR/match-cfg-fake-edges.rs:24:5
|
LL | (y, _) | (_, y) => (),
| - value moved here
...
LL | &x.1;
| ^^^^ value borrowed here after move
|
= note: move occurs because `x.1` has type `String`, which does not implement the `Copy` trait
help: borrow this binding in the pattern to avoid moving the value
|
LL | (y, _) | (_, ref y) => (),
| +++
error[E0381]: used binding `x` is possibly-uninitialized
--> $DIR/match-cfg-fake-edges.rs:58:19
| |
LL | let x; LL | let x;
| - binding declared here but left uninitialized | - binding declared here but left uninitialized
... ...
LL | _ => drop(x),
| - ^ `x` used here but it is possibly-uninitialized
| |
| if this pattern is matched, `x` is not initialized
error[E0381]: used binding `x` isn't initialized
--> $DIR/match-cfg-fake-edges.rs:65:16
|
LL | let x;
| - binding declared here but left uninitialized
LL | match y {
LL | _ if { x = 2; true } => 1, LL | _ if { x = 2; true } => 1,
| ----- binding initialized here in some conditions | ----- binding initialized here in some conditions
LL | _ if { LL | // Borrowck must not know the guard is always run.
LL | x; LL | _ if { x; false } => 2,
| ^ `x` used here but it isn't initialized | ^ `x` used here but it isn't initialized
| |
help: consider assigning a value help: consider assigning a value
| |
@ -16,16 +74,15 @@ LL | let x = 0;
| +++ | +++
error[E0381]: used binding `x` isn't initialized error[E0381]: used binding `x` isn't initialized
--> $DIR/match-cfg-fake-edges.rs:39:13 --> $DIR/match-cfg-fake-edges.rs:72:31
| |
LL | let x; LL | let x;
| - binding declared here but left uninitialized | - binding declared here but left uninitialized
LL | match y { LL | match y {
LL | _ if let Some(()) = { x = 2; Some(()) } => 1, LL | _ if let Some(()) = { x = 2; Some(()) } => 1,
| ----- binding initialized here in some conditions | ----- binding initialized here in some conditions
LL | _ if let Some(()) = { LL | _ if let Some(()) = { x; None } => 2,
LL | x; | ^ `x` used here but it isn't initialized
| ^ `x` used here but it isn't initialized
| |
help: consider assigning a value help: consider assigning a value
| |
@ -33,40 +90,39 @@ LL | let x = 0;
| +++ | +++
error[E0382]: use of moved value: `x` error[E0382]: use of moved value: `x`
--> $DIR/match-cfg-fake-edges.rs:53:13 --> $DIR/match-cfg-fake-edges.rs:85:22
|
LL | let x = String::new();
| - move occurs because `x` has type `String`, which does not implement the `Copy` trait
...
LL | false if { drop(x); true } => 1,
| - value moved here
LL | true => {
LL | x;
| ^ value used here after move
|
help: consider cloning the value if the performance cost is acceptable
|
LL | false if { drop(x.clone()); true } => 1,
| ++++++++
error[E0382]: use of moved value: `x`
--> $DIR/match-cfg-fake-edges.rs:63:13
| |
LL | let x = String::new(); LL | let x = String::new();
| - move occurs because `x` has type `String`, which does not implement the `Copy` trait | - move occurs because `x` has type `String`, which does not implement the `Copy` trait
LL | match y { LL | match y {
LL | false if let Some(()) = { drop(x); Some(()) } => 1, LL | false if { drop(x); true } => {},
| - value moved here | - value moved here
LL | true => { LL | // Borrowck must not know the guard is not run in the `true` case.
LL | x; LL | true => drop(x),
| ^ value used here after move | ^ value used here after move
| |
help: consider cloning the value if the performance cost is acceptable help: consider cloning the value if the performance cost is acceptable
| |
LL | false if let Some(()) = { drop(x.clone()); Some(()) } => 1, LL | false if { drop(x.clone()); true } => {},
| ++++++++
error[E0382]: use of moved value: `x`
--> $DIR/match-cfg-fake-edges.rs:100:22
|
LL | let x = String::new();
| - move occurs because `x` has type `String`, which does not implement the `Copy` trait
LL | match y {
LL | false if let Some(()) = { drop(x); Some(()) } => {},
| - value moved here
LL | true => drop(x),
| ^ value used here after move
|
help: consider cloning the value if the performance cost is acceptable
|
LL | false if let Some(()) = { drop(x.clone()); Some(()) } => {},
| ++++++++ | ++++++++
error: aborting due to 4 previous errors error: aborting due to 8 previous errors
Some errors have detailed explanations: E0381, E0382. Some errors have detailed explanations: E0381, E0382.
For more information about an error, try `rustc --explain E0381`. For more information about an error, try `rustc --explain E0381`.

View file

@ -5,13 +5,20 @@ fn all_previous_tests_may_be_done(y: &mut (bool, bool)) {
let r = &mut y.1; let r = &mut y.1;
// We don't actually test y.1 to select the second arm, but we don't want // We don't actually test y.1 to select the second arm, but we don't want
// borrowck results to be based on the order we match patterns. // borrowck results to be based on the order we match patterns.
match y { //~ ERROR cannot use `y.1` because it was mutably borrowed match y {
(false, true) => 1, //~^ ERROR cannot use `y.1` because it was mutably borrowed
(true, _) => { (false, true) => {}
r; // Borrowck must not know we don't test `y.1` when `y.0` is `true`.
2 (true, _) => drop(r),
} (false, _) => {}
(false, _) => 3, };
// Fine in the other order.
let r = &mut y.1;
match y {
(true, _) => drop(r),
(false, true) => {}
(false, _) => {}
}; };
} }

View file

@ -7,8 +7,8 @@ LL | let r = &mut y.1;
LL | match y { LL | match y {
| ^^^^^^^ use of borrowed `y.1` | ^^^^^^^ use of borrowed `y.1`
... ...
LL | r; LL | (true, _) => drop(r),
| - borrow later used here | - borrow later used here
error: aborting due to 1 previous error error: aborting due to 1 previous error