Skip to content

Commit c15437c

Browse files
committed
Improve error message and add tests for borrowck match handling
1 parent f66e469 commit c15437c

File tree

5 files changed

+144
-43
lines changed

5 files changed

+144
-43
lines changed

src/librustc_mir/borrow_check/error_reporting.rs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1330,22 +1330,30 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
13301330
let loan_span = loan_spans.args_or_use();
13311331

13321332
let tcx = self.infcx.tcx;
1333-
let mut err = if loan.kind == BorrowKind::Shallow {
1334-
tcx.cannot_mutate_in_match_guard(
1333+
if loan.kind == BorrowKind::Shallow {
1334+
let mut err = tcx.cannot_mutate_in_match_guard(
13351335
span,
13361336
loan_span,
13371337
&self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
13381338
"assign",
13391339
Origin::Mir,
1340-
)
1341-
} else {
1342-
tcx.cannot_assign_to_borrowed(
1343-
span,
1344-
loan_span,
1345-
&self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
1346-
Origin::Mir,
1347-
)
1348-
};
1340+
);
1341+
loan_spans.var_span_label(
1342+
&mut err,
1343+
format!("borrow occurs due to use{}", loan_spans.describe()),
1344+
);
1345+
1346+
err.buffer(&mut self.errors_buffer);
1347+
1348+
return;
1349+
}
1350+
1351+
let mut err = tcx.cannot_assign_to_borrowed(
1352+
span,
1353+
loan_span,
1354+
&self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
1355+
Origin::Mir,
1356+
);
13491357

13501358
loan_spans.var_span_label(
13511359
&mut err,
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Test that we have enough false edges to avoid exposing the exact matching
2+
// algorithm in borrow checking.
3+
4+
#![feature(nll, bind_by_move_pattern_guards)]
5+
6+
fn guard_always_precedes_arm(y: i32) {
7+
let mut x;
8+
// x should always be initialized, as the only way to reach the arm is
9+
// through the guard.
10+
match y {
11+
0 | 2 if { x = 2; true } => x,
12+
_ => 2,
13+
};
14+
}
15+
16+
fn guard_may_be_skipped(y: i32) {
17+
let x;
18+
// Even though x *is* always initialized, we don't want to have borrowck
19+
// results be based on whether patterns are exhaustive.
20+
match y {
21+
_ if { x = 2; true } => 1,
22+
_ if {
23+
x; //~ ERROR use of possibly uninitialized variable: `x`
24+
false
25+
} => 2,
26+
_ => 3,
27+
};
28+
}
29+
30+
fn guard_may_be_taken(y: bool) {
31+
let x = String::new();
32+
// Even though x *is* never moved before the use, we don't want to have
33+
// borrowck results be based on whether patterns are disjoint.
34+
match y {
35+
false if { drop(x); true } => 1,
36+
true => {
37+
x; //~ ERROR use of moved value: `x`
38+
2
39+
}
40+
false => 3,
41+
};
42+
}
43+
44+
fn all_previous_tests_may_be_done(y: &mut (bool, bool)) {
45+
let r = &mut y.1;
46+
// We don't actually test y.1 to select the second arm, but we don't want
47+
// borrowck results to be based on the order we match patterns.
48+
match y {
49+
(false, true) => 1, //~ ERROR cannot use `y.1` because it was mutably borrowed
50+
(true, _) => {
51+
r;
52+
2
53+
}
54+
(false, _) => 3,
55+
};
56+
}
57+
58+
fn main() {}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
error[E0381]: use of possibly uninitialized variable: `x`
2+
--> $DIR/match-cfg-fake-edges.rs:23:13
3+
|
4+
LL | x; //~ ERROR use of possibly uninitialized variable: `x`
5+
| ^ use of possibly uninitialized `x`
6+
7+
error[E0382]: use of moved value: `x`
8+
--> $DIR/match-cfg-fake-edges.rs:37:13
9+
|
10+
LL | let x = String::new();
11+
| - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
12+
...
13+
LL | false if { drop(x); true } => 1,
14+
| - value moved here
15+
LL | true => {
16+
LL | x; //~ ERROR use of moved value: `x`
17+
| ^ value used here after move
18+
19+
error[E0503]: cannot use `y.1` because it was mutably borrowed
20+
--> $DIR/match-cfg-fake-edges.rs:49:17
21+
|
22+
LL | let r = &mut y.1;
23+
| -------- borrow of `y.1` occurs here
24+
...
25+
LL | (false, true) => 1, //~ ERROR cannot use `y.1` because it was mutably borrowed
26+
| ^^^^ use of borrowed `y.1`
27+
LL | (true, _) => {
28+
LL | r;
29+
| - borrow later used here
30+
31+
error: aborting due to 3 previous errors
32+
33+
Some errors occurred: E0381, E0382, E0503.
34+
For more information about an error, try `rustc --explain E0381`.

src/test/ui/nll/match-guards-partially-borrow.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ fn ok_indirect_mutation_in_guard(mut p: &bool) {
3030

3131
fn mutation_invalidates_pattern_in_guard(mut q: bool) {
3232
match q {
33-
// s doesn't match the pattern with the guard by the end of the guard.
33+
// q doesn't match the pattern with the guard by the end of the guard.
3434
false if {
3535
q = true; //~ ERROR
3636
true
@@ -41,7 +41,7 @@ fn mutation_invalidates_pattern_in_guard(mut q: bool) {
4141

4242
fn mutation_invalidates_previous_pattern_in_guard(mut r: bool) {
4343
match r {
44-
// s matches a previous pattern by the end of the guard.
44+
// r matches a previous pattern by the end of the guard.
4545
true => (),
4646
_ if {
4747
r = true; //~ ERROR
@@ -116,6 +116,16 @@ fn bad_mutation_in_guard4(mut w: (&mut bool,)) {
116116
}
117117
}
118118

119+
fn bad_mutation_in_guard5(mut t: bool) {
120+
match t {
121+
s if {
122+
t = !t; //~ ERROR
123+
false
124+
} => (), // What value should `s` have in the arm?
125+
_ => (),
126+
}
127+
}
128+
119129
fn bad_indirect_mutation_in_guard(mut y: &bool) {
120130
match *y {
121131
true => (),

src/test/ui/nll/match-guards-partially-borrow.stderr

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@ LL | match q {
66
...
77
LL | q = true; //~ ERROR
88
| ^^^^^^^^ cannot assign
9-
...
10-
LL | _ => (),
11-
| - borrow later used here
129

1310
error[E0510]: cannot assign `r` in match guard
1411
--> $DIR/match-guards-partially-borrow.rs:47:13
@@ -18,9 +15,6 @@ LL | match r {
1815
...
1916
LL | r = true; //~ ERROR
2017
| ^^^^^^^^ cannot assign
21-
...
22-
LL | _ => (),
23-
| - borrow later used here
2418

2519
error[E0503]: cannot use `s` because it was mutably borrowed
2620
--> $DIR/match-guards-partially-borrow.rs:56:11
@@ -41,9 +35,6 @@ LL | match t {
4135
...
4236
LL | t = true; //~ ERROR
4337
| ^^^^^^^^ cannot assign
44-
...
45-
LL | false => (),
46-
| ----- borrow later used here
4738

4839
error[E0506]: cannot assign to `u` because it is borrowed
4940
--> $DIR/match-guards-partially-borrow.rs:83:13
@@ -53,8 +44,8 @@ LL | match u {
5344
...
5445
LL | u = true; //~ ERROR
5546
| ^^^^^^^^ assignment to borrowed `u` occurs here
56-
...
57-
LL | x => (),
47+
LL | false
48+
LL | } => (),
5849
| - borrow later used here
5950

6051
error[E0510]: cannot mutably borrow `x.0` in match guard
@@ -74,59 +65,59 @@ LL | match w {
7465
...
7566
LL | *w.0 = true; //~ ERROR
7667
| ^^^^^^^^^^^ assignment to borrowed `*w.0` occurs here
77-
...
78-
LL | x => (),
68+
LL | false
69+
LL | } => (),
70+
| - borrow later used here
71+
72+
error[E0506]: cannot assign to `t` because it is borrowed
73+
--> $DIR/match-guards-partially-borrow.rs:122:13
74+
|
75+
LL | match t {
76+
| - borrow of `t` occurs here
77+
LL | s if {
78+
LL | t = !t; //~ ERROR
79+
| ^^^^^^ assignment to borrowed `t` occurs here
80+
LL | false
81+
LL | } => (), // What value should `s` have in the arm?
7982
| - borrow later used here
8083

8184
error[E0510]: cannot assign `y` in match guard
82-
--> $DIR/match-guards-partially-borrow.rs:123:13
85+
--> $DIR/match-guards-partially-borrow.rs:133:13
8386
|
8487
LL | match *y {
8588
| -- value is immutable in match guard
8689
...
8790
LL | y = &true; //~ ERROR
8891
| ^^^^^^^^^ cannot assign
89-
...
90-
LL | false => (),
91-
| ----- borrow later used here
9292

9393
error[E0510]: cannot assign `z` in match guard
94-
--> $DIR/match-guards-partially-borrow.rs:134:13
94+
--> $DIR/match-guards-partially-borrow.rs:144:13
9595
|
9696
LL | match z {
9797
| - value is immutable in match guard
9898
...
9999
LL | z = &true; //~ ERROR
100100
| ^^^^^^^^^ cannot assign
101-
...
102-
LL | &false => (),
103-
| ------ borrow later used here
104101

105102
error[E0510]: cannot assign `a` in match guard
106-
--> $DIR/match-guards-partially-borrow.rs:146:13
103+
--> $DIR/match-guards-partially-borrow.rs:156:13
107104
|
108105
LL | match a {
109106
| - value is immutable in match guard
110107
...
111108
LL | a = &true; //~ ERROR
112109
| ^^^^^^^^^ cannot assign
113-
...
114-
LL | false => (),
115-
| ----- borrow later used here
116110

117111
error[E0510]: cannot assign `b` in match guard
118-
--> $DIR/match-guards-partially-borrow.rs:157:13
112+
--> $DIR/match-guards-partially-borrow.rs:167:13
119113
|
120114
LL | match b {
121115
| - value is immutable in match guard
122116
...
123117
LL | b = &true; //~ ERROR
124118
| ^^^^^^^^^ cannot assign
125-
...
126-
LL | &b => (),
127-
| -- borrow later used here
128119

129-
error: aborting due to 11 previous errors
120+
error: aborting due to 12 previous errors
130121

131122
Some errors occurred: E0503, E0506, E0510.
132123
For more information about an error, try `rustc --explain E0503`.

0 commit comments

Comments
 (0)