From de5c6ec1f4a6bbd8600fda0e7c1574d914ac35bd Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 29 Jun 2019 15:38:20 +0100 Subject: [PATCH] Exit arm scopes correctly in the HIR CFG When a match evaluates to false we jump to the next arm, when we do so we need to make sure that we exit the scope for that arm. --- src/librustc/cfg/construct.rs | 13 +++++++------ .../ui/borrowck/issue-62107-match-arm-scopes.rs | 12 ++++++++++++ .../ui/borrowck/issue-62107-match-arm-scopes.stderr | 9 +++++++++ 3 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/borrowck/issue-62107-match-arm-scopes.rs create mode 100644 src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index f81d18694136e..ca852fe7622cc 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -371,7 +371,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { let expr_exit = self.add_ast_node(id, &[]); // Keep track of the previous guard expressions - let mut prev_guards = Vec::new(); + let mut prev_guard = None; + let match_scope = region::Scope { id, data: region::ScopeData::Node }; for arm in arms { // Add an exit node for when we've visited all the @@ -389,7 +390,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { let guard_start = self.add_dummy_node(&[pat_exit]); // Visit the guard expression let guard_exit = match guard { - hir::Guard::If(ref e) => self.expr(e, guard_start), + hir::Guard::If(ref e) => (&**e, self.expr(e, guard_start)), }; // #47295: We used to have very special case code // here for when a pair of arms are both formed @@ -397,15 +398,15 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { // edges. But this was not actually sound without // other constraints that we stopped enforcing at // some point. - while let Some(prev) = prev_guards.pop() { - self.add_contained_edge(prev, guard_start); + if let Some((prev_guard, prev_index)) = prev_guard.take() { + self.add_exiting_edge(prev_guard, prev_index, match_scope, guard_start); } // Push the guard onto the list of previous guards - prev_guards.push(guard_exit); + prev_guard = Some(guard_exit); // Update the exit node for the pattern - pat_exit = guard_exit; + pat_exit = guard_exit.1; } // Add an edge from the exit of this pattern to the diff --git a/src/test/ui/borrowck/issue-62107-match-arm-scopes.rs b/src/test/ui/borrowck/issue-62107-match-arm-scopes.rs new file mode 100644 index 0000000000000..220b2ecf04d38 --- /dev/null +++ b/src/test/ui/borrowck/issue-62107-match-arm-scopes.rs @@ -0,0 +1,12 @@ +fn main() { + let e: i32; + match e { + //~^ ERROR use of possibly uninitialized variable + ref u if true => {} + ref v if true => { + let tx = 0; + &tx; + } + _ => (), + } +} diff --git a/src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr b/src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr new file mode 100644 index 0000000000000..9701343d2b1dd --- /dev/null +++ b/src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr @@ -0,0 +1,9 @@ +error[E0381]: use of possibly uninitialized variable: `e` + --> $DIR/issue-62107-match-arm-scopes.rs:3:11 + | +LL | match e { + | ^ use of possibly uninitialized `e` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`.