about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2019-06-29 15:38:20 +0100
committerMatthew Jasper <mjjasper1@gmail.com>2019-07-06 21:56:03 +0100
commitde5c6ec1f4a6bbd8600fda0e7c1574d914ac35bd (patch)
tree7f35c15a9f202554d9491e1b6a38782b7993dca8
parentdb6f77f0d74934a95eb91d74bda19e5b0e8258e3 (diff)
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.
-rw-r--r--src/librustc/cfg/construct.rs13
-rw-r--r--src/test/ui/borrowck/issue-62107-match-arm-scopes.rs12
-rw-r--r--src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr9
3 files changed, 28 insertions, 6 deletions
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index f81d1869413..ca852fe7622 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 00000000000..220b2ecf04d
--- /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 00000000000..9701343d2b1
--- /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`.