Improve error message and add tests for borrowck match handling

This commit is contained in:
Matthew Jasper 2019-02-02 10:45:20 +00:00
parent f66e4697ae
commit c15437c0c6
5 changed files with 144 additions and 43 deletions

View File

@ -1330,22 +1330,30 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
let loan_span = loan_spans.args_or_use();
let tcx = self.infcx.tcx;
let mut err = if loan.kind == BorrowKind::Shallow {
tcx.cannot_mutate_in_match_guard(
if loan.kind == BorrowKind::Shallow {
let mut err = tcx.cannot_mutate_in_match_guard(
span,
loan_span,
&self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
"assign",
Origin::Mir,
)
} else {
tcx.cannot_assign_to_borrowed(
span,
loan_span,
&self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
Origin::Mir,
)
};
);
loan_spans.var_span_label(
&mut err,
format!("borrow occurs due to use{}", loan_spans.describe()),
);
err.buffer(&mut self.errors_buffer);
return;
}
let mut err = tcx.cannot_assign_to_borrowed(
span,
loan_span,
&self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
Origin::Mir,
);
loan_spans.var_span_label(
&mut err,

View File

@ -0,0 +1,58 @@
// Test that we have enough false edges to avoid exposing the exact matching
// algorithm in borrow checking.
#![feature(nll, bind_by_move_pattern_guards)]
fn guard_always_precedes_arm(y: i32) {
let mut x;
// x should always be initialized, as the only way to reach the arm is
// through the guard.
match y {
0 | 2 if { x = 2; true } => x,
_ => 2,
};
}
fn guard_may_be_skipped(y: i32) {
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 {
_ if { x = 2; true } => 1,
_ if {
x; //~ ERROR use of possibly uninitialized variable: `x`
false
} => 2,
_ => 3,
};
}
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
// borrowck results be based on whether patterns are disjoint.
match y {
false if { drop(x); true } => 1,
true => {
x; //~ ERROR use of moved value: `x`
2
}
false => 3,
};
}
fn all_previous_tests_may_be_done(y: &mut (bool, bool)) {
let r = &mut y.1;
// 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.
match y {
(false, true) => 1, //~ ERROR cannot use `y.1` because it was mutably borrowed
(true, _) => {
r;
2
}
(false, _) => 3,
};
}
fn main() {}

View File

@ -0,0 +1,34 @@
error[E0381]: use of possibly uninitialized variable: `x`
--> $DIR/match-cfg-fake-edges.rs:23:13
|
LL | x; //~ ERROR use of possibly uninitialized variable: `x`
| ^ use of possibly uninitialized `x`
error[E0382]: use of moved value: `x`
--> $DIR/match-cfg-fake-edges.rs:37:13
|
LL | let x = String::new();
| - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
...
LL | false if { drop(x); true } => 1,
| - value moved here
LL | true => {
LL | x; //~ ERROR use of moved value: `x`
| ^ value used here after move
error[E0503]: cannot use `y.1` because it was mutably borrowed
--> $DIR/match-cfg-fake-edges.rs:49:17
|
LL | let r = &mut y.1;
| -------- borrow of `y.1` occurs here
...
LL | (false, true) => 1, //~ ERROR cannot use `y.1` because it was mutably borrowed
| ^^^^ use of borrowed `y.1`
LL | (true, _) => {
LL | r;
| - borrow later used here
error: aborting due to 3 previous errors
Some errors occurred: E0381, E0382, E0503.
For more information about an error, try `rustc --explain E0381`.

View File

@ -30,7 +30,7 @@ fn ok_indirect_mutation_in_guard(mut p: &bool) {
fn mutation_invalidates_pattern_in_guard(mut q: bool) {
match q {
// s doesn't match the pattern with the guard by the end of the guard.
// q doesn't match the pattern with the guard by the end of the guard.
false if {
q = true; //~ ERROR
true
@ -41,7 +41,7 @@ fn mutation_invalidates_pattern_in_guard(mut q: bool) {
fn mutation_invalidates_previous_pattern_in_guard(mut r: bool) {
match r {
// s matches a previous pattern by the end of the guard.
// r matches a previous pattern by the end of the guard.
true => (),
_ if {
r = true; //~ ERROR
@ -116,6 +116,16 @@ fn bad_mutation_in_guard4(mut w: (&mut bool,)) {
}
}
fn bad_mutation_in_guard5(mut t: bool) {
match t {
s if {
t = !t; //~ ERROR
false
} => (), // What value should `s` have in the arm?
_ => (),
}
}
fn bad_indirect_mutation_in_guard(mut y: &bool) {
match *y {
true => (),

View File

@ -6,9 +6,6 @@ LL | match q {
...
LL | q = true; //~ ERROR
| ^^^^^^^^ cannot assign
...
LL | _ => (),
| - borrow later used here
error[E0510]: cannot assign `r` in match guard
--> $DIR/match-guards-partially-borrow.rs:47:13
@ -18,9 +15,6 @@ LL | match r {
...
LL | r = true; //~ ERROR
| ^^^^^^^^ cannot assign
...
LL | _ => (),
| - borrow later used here
error[E0503]: cannot use `s` because it was mutably borrowed
--> $DIR/match-guards-partially-borrow.rs:56:11
@ -41,9 +35,6 @@ LL | match t {
...
LL | t = true; //~ ERROR
| ^^^^^^^^ cannot assign
...
LL | false => (),
| ----- borrow later used here
error[E0506]: cannot assign to `u` because it is borrowed
--> $DIR/match-guards-partially-borrow.rs:83:13
@ -53,8 +44,8 @@ LL | match u {
...
LL | u = true; //~ ERROR
| ^^^^^^^^ assignment to borrowed `u` occurs here
...
LL | x => (),
LL | false
LL | } => (),
| - borrow later used here
error[E0510]: cannot mutably borrow `x.0` in match guard
@ -74,59 +65,59 @@ LL | match w {
...
LL | *w.0 = true; //~ ERROR
| ^^^^^^^^^^^ assignment to borrowed `*w.0` occurs here
...
LL | x => (),
LL | false
LL | } => (),
| - borrow later used here
error[E0506]: cannot assign to `t` because it is borrowed
--> $DIR/match-guards-partially-borrow.rs:122:13
|
LL | match t {
| - borrow of `t` occurs here
LL | s if {
LL | t = !t; //~ ERROR
| ^^^^^^ assignment to borrowed `t` occurs here
LL | false
LL | } => (), // What value should `s` have in the arm?
| - borrow later used here
error[E0510]: cannot assign `y` in match guard
--> $DIR/match-guards-partially-borrow.rs:123:13
--> $DIR/match-guards-partially-borrow.rs:133:13
|
LL | match *y {
| -- value is immutable in match guard
...
LL | y = &true; //~ ERROR
| ^^^^^^^^^ cannot assign
...
LL | false => (),
| ----- borrow later used here
error[E0510]: cannot assign `z` in match guard
--> $DIR/match-guards-partially-borrow.rs:134:13
--> $DIR/match-guards-partially-borrow.rs:144:13
|
LL | match z {
| - value is immutable in match guard
...
LL | z = &true; //~ ERROR
| ^^^^^^^^^ cannot assign
...
LL | &false => (),
| ------ borrow later used here
error[E0510]: cannot assign `a` in match guard
--> $DIR/match-guards-partially-borrow.rs:146:13
--> $DIR/match-guards-partially-borrow.rs:156:13
|
LL | match a {
| - value is immutable in match guard
...
LL | a = &true; //~ ERROR
| ^^^^^^^^^ cannot assign
...
LL | false => (),
| ----- borrow later used here
error[E0510]: cannot assign `b` in match guard
--> $DIR/match-guards-partially-borrow.rs:157:13
--> $DIR/match-guards-partially-borrow.rs:167:13
|
LL | match b {
| - value is immutable in match guard
...
LL | b = &true; //~ ERROR
| ^^^^^^^^^ cannot assign
...
LL | &b => (),
| -- borrow later used here
error: aborting due to 11 previous errors
error: aborting due to 12 previous errors
Some errors occurred: E0503, E0506, E0510.
For more information about an error, try `rustc --explain E0503`.