librustc: Disallow mutation and assignment in pattern guards, and modify
the CFG for match statements. There were two bugs in issue #14684. One was simply that the borrow check didn't know about the correct CFG for match statements: the pattern must be a predecessor of the guard. This disallows the bad behavior if there are bindings in the pattern. But it isn't enough to prevent the memory safety problem, because of wildcards; thus, this patch introduces a more restrictive rule, which disallows assignments and mutable borrows inside guards outright. I discussed this with Niko and we decided this was the best plan of action. This breaks code that performs mutable borrows in pattern guards. Most commonly, the code looks like this: impl Foo { fn f(&mut self, ...) {} fn g(&mut self, ...) { match bar { Baz if self.f(...) => { ... } _ => { ... } } } } Change this code to not use a guard. For example: impl Foo { fn f(&mut self, ...) {} fn g(&mut self, ...) { match bar { Baz => { if self.f(...) { ... } else { ... } } _ => { ... } } } } Sometimes this can result in code duplication, but often it illustrates a hidden memory safety problem. Closes #14684. [breaking-change]
This commit is contained in:
parent
66a0b528a6
commit
b2eb88843d
10 changed files with 384 additions and 272 deletions
|
@ -333,32 +333,37 @@ impl<'a> CFGBuilder<'a> {
|
|||
// [discr]
|
||||
// |
|
||||
// v 2
|
||||
// [guard1]
|
||||
// [cond1]
|
||||
// / \
|
||||
// | \
|
||||
// v 3 |
|
||||
// [pat1] |
|
||||
// |
|
||||
// v 4 |
|
||||
// [body1] v
|
||||
// | [guard2]
|
||||
// | / \
|
||||
// | [body2] \
|
||||
// | | ...
|
||||
// | | |
|
||||
// v 5 v v
|
||||
// [....expr....]
|
||||
// v 3 \
|
||||
// [pat1] \
|
||||
// | |
|
||||
// v 4 |
|
||||
// [guard1] |
|
||||
// | |
|
||||
// | |
|
||||
// v 5 v
|
||||
// [body1] [cond2]
|
||||
// | / \
|
||||
// | ... ...
|
||||
// | | |
|
||||
// v 6 v v
|
||||
// [.....expr.....]
|
||||
//
|
||||
let discr_exit = self.expr(discr.clone(), pred); // 1
|
||||
|
||||
let expr_exit = self.add_node(expr.id, []);
|
||||
let mut guard_exit = discr_exit;
|
||||
let mut cond_exit = discr_exit;
|
||||
for arm in arms.iter() {
|
||||
guard_exit = self.opt_expr(arm.guard, guard_exit); // 2
|
||||
cond_exit = self.add_dummy_node([cond_exit]); // 2
|
||||
let pats_exit = self.pats_any(arm.pats.as_slice(),
|
||||
guard_exit); // 3
|
||||
let body_exit = self.expr(arm.body.clone(), pats_exit); // 4
|
||||
self.add_contained_edge(body_exit, expr_exit); // 5
|
||||
cond_exit); // 3
|
||||
let guard_exit = self.opt_expr(arm.guard,
|
||||
pats_exit); // 4
|
||||
let body_exit = self.expr(arm.body.clone(),
|
||||
guard_exit); // 5
|
||||
self.add_contained_edge(body_exit, expr_exit); // 6
|
||||
}
|
||||
expr_exit
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue