about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc_borrowck/borrowck/mir/elaborate_drops.rs1
-rw-r--r--src/librustc_mir/build/block.rs5
-rw-r--r--src/librustc_mir/build/matches/mod.rs120
-rw-r--r--src/test/mir-opt/storage_ranges.rs2
-rw-r--r--src/test/run-pass/mir_drop_order.rs42
5 files changed, 98 insertions, 72 deletions
diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
index 13f898219bc..a71d23e7e1e 100644
--- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
+++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
@@ -161,6 +161,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
     fn create_drop_flag(&mut self, index: MovePathIndex) {
         let tcx = self.tcx;
         let patch = &mut self.patch;
+        debug!("create_drop_flag({:?})", self.mir.span);
         self.drop_flags.entry(index).or_insert_with(|| {
             patch.new_temp(tcx.types.bool)
         });
diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs
index 121d592da03..3305cfc0dfe 100644
--- a/src/librustc_mir/build/block.rs
+++ b/src/librustc_mir/build/block.rs
@@ -67,7 +67,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                                 this.expr_into_pattern(block, pattern, init)
                             }));
                         } else {
-                            this.storage_live_for_bindings(block, &pattern);
+                            this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| {
+                                this.storage_live_binding(block, node, span);
+                                this.schedule_drop_for_binding(node, span);
+                            })
                         }
 
                         // Enter the visibility scope, after evaluating the initializer.
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 6b6acb054b1..fd39f511e6d 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -123,16 +123,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             PatternKind::Binding { mode: BindingMode::ByValue,
                                    var,
                                    subpattern: None, .. } => {
-                self.storage_live_for_bindings(block, &irrefutable_pat);
-                let lvalue = Lvalue::Local(self.var_indices[&var]);
-                return self.into(&lvalue, block, initializer);
+                let lvalue = self.storage_live_binding(block, var, irrefutable_pat.span);
+                unpack!(block = self.into(&lvalue, block, initializer));
+                self.schedule_drop_for_binding(var, irrefutable_pat.span);
+                block.unit()
+            }
+            _ => {
+                let lvalue = unpack!(block = self.as_lvalue(block, initializer));
+                self.lvalue_into_pattern(block, irrefutable_pat, &lvalue)
             }
-            _ => {}
         }
-        let lvalue = unpack!(block = self.as_lvalue(block, initializer));
-        self.lvalue_into_pattern(block,
-                                 irrefutable_pat,
-                                 &lvalue)
     }
 
     pub fn lvalue_into_pattern(&mut self,
@@ -174,79 +174,70 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                             scope_span: Span,
                             pattern: &Pattern<'tcx>)
                             -> Option<VisibilityScope> {
-        match *pattern.kind {
-            PatternKind::Binding { mutability, name, mode: _, var, ty, ref subpattern } => {
-                if var_scope.is_none() {
-                    var_scope = Some(self.new_visibility_scope(scope_span));
-                }
-                let source_info = SourceInfo {
-                    span: pattern.span,
-                    scope: var_scope.unwrap()
-                };
-                self.declare_binding(source_info, mutability, name, var, ty);
-                if let Some(subpattern) = subpattern.as_ref() {
-                    var_scope = self.declare_bindings(var_scope, scope_span, subpattern);
-                }
-            }
-            PatternKind::Array { ref prefix, ref slice, ref suffix } |
-            PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
-                for subpattern in prefix.iter().chain(slice).chain(suffix) {
-                    var_scope = self.declare_bindings(var_scope, scope_span, subpattern);
-                }
-            }
-            PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {
-            }
-            PatternKind::Deref { ref subpattern } => {
-                var_scope = self.declare_bindings(var_scope, scope_span, subpattern);
-            }
-            PatternKind::Leaf { ref subpatterns } |
-            PatternKind::Variant { ref subpatterns, .. } => {
-                for subpattern in subpatterns {
-                    var_scope = self.declare_bindings(var_scope, scope_span, &subpattern.pattern);
-                }
+        self.visit_bindings(pattern, &mut |this, mutability, name, var, span, ty| {
+            if var_scope.is_none() {
+                var_scope = Some(this.new_visibility_scope(scope_span));
             }
-        }
+            let source_info = SourceInfo {
+                span: span,
+                scope: var_scope.unwrap()
+            };
+            this.declare_binding(source_info, mutability, name, var, ty);
+        });
         var_scope
     }
 
-    /// Emit `StorageLive` for every binding in the pattern.
-    pub fn storage_live_for_bindings(&mut self,
-                                     block: BasicBlock,
-                                     pattern: &Pattern<'tcx>) {
-        match *pattern.kind {
-            PatternKind::Binding { var, ref subpattern, .. } => {
-                let lvalue = Lvalue::Local(self.var_indices[&var]);
-                let source_info = self.source_info(pattern.span);
-                self.cfg.push(block, Statement {
-                    source_info: source_info,
-                    kind: StatementKind::StorageLive(lvalue)
-                });
+    pub fn storage_live_binding(&mut self, block: BasicBlock, var: NodeId, span: Span)
+                            -> Lvalue<'tcx>
+    {
+        let local_id = self.var_indices[&var];
+        let source_info = self.source_info(span);
+        self.cfg.push(block, Statement {
+            source_info: source_info,
+            kind: StatementKind::StorageLive(Lvalue::Local(local_id))
+        });
+        Lvalue::Local(local_id)
+    }
 
+    pub fn schedule_drop_for_binding(&mut self, var: NodeId, span: Span) {
+        let local_id = self.var_indices[&var];
+        let var_ty = self.local_decls[local_id].ty;
+        let extent = self.hir.tcx().region_maps.var_scope(var);
+        self.schedule_drop(span, extent, &Lvalue::Local(local_id), var_ty);
+    }
+
+    pub fn visit_bindings<F>(&mut self, pattern: &Pattern<'tcx>, mut f: &mut F)
+        where F: FnMut(&mut Self, Mutability, Name, NodeId, Span, Ty<'tcx>)
+    {
+        match *pattern.kind {
+            PatternKind::Binding { mutability, name, var, ty, ref subpattern, .. } => {
+                f(self, mutability, name, var, pattern.span, ty);
                 if let Some(subpattern) = subpattern.as_ref() {
-                    self.storage_live_for_bindings(block, subpattern);
+                    self.visit_bindings(subpattern, f);
                 }
             }
             PatternKind::Array { ref prefix, ref slice, ref suffix } |
             PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
                 for subpattern in prefix.iter().chain(slice).chain(suffix) {
-                    self.storage_live_for_bindings(block, subpattern);
+                    self.visit_bindings(subpattern, f);
                 }
             }
             PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {
             }
             PatternKind::Deref { ref subpattern } => {
-                self.storage_live_for_bindings(block, subpattern);
+                self.visit_bindings(subpattern, f);
             }
             PatternKind::Leaf { ref subpatterns } |
             PatternKind::Variant { ref subpatterns, .. } => {
                 for subpattern in subpatterns {
-                    self.storage_live_for_bindings(block, &subpattern.pattern);
+                    self.visit_bindings(&subpattern.pattern, f);
                 }
             }
         }
     }
 }
 
+
 /// List of blocks for each arm (and potentially other metadata in the
 /// future).
 struct ArmBlocks {
@@ -691,25 +682,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
         // Assign each of the bindings. This may trigger moves out of the candidate.
         for binding in bindings {
-            // Find the variable for the `var_id` being bound. It
-            // should have been created by a previous call to
-            // `declare_bindings`.
-            let var_index = self.var_indices[&binding.var_id];
-
+            let source_info = self.source_info(binding.span);
+            let local = self.storage_live_binding(block, binding.var_id, binding.span);
+            self.schedule_drop_for_binding(binding.var_id, binding.span);
             let rvalue = match binding.binding_mode {
                 BindingMode::ByValue =>
                     Rvalue::Use(Operand::Consume(binding.source)),
                 BindingMode::ByRef(region, borrow_kind) =>
                     Rvalue::Ref(region, borrow_kind, binding.source),
             };
-
-            let source_info = self.source_info(binding.span);
-            self.cfg.push(block, Statement {
-                source_info: source_info,
-                kind: StatementKind::StorageLive(Lvalue::Local(var_index))
-            });
-            self.cfg.push_assign(block, source_info,
-                                 &Lvalue::Local(var_index), rvalue);
+            self.cfg.push_assign(block, source_info, &local, rvalue);
         }
     }
 
@@ -730,8 +712,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             name: Some(name),
             source_info: Some(source_info),
         });
-        let extent = self.hir.tcx().region_maps.var_scope(var_id);
-        self.schedule_drop(source_info.span, extent, &Lvalue::Local(var), var_ty);
         self.var_indices.insert(var_id, var);
 
         debug!("declare_binding: var={:?}", var);
diff --git a/src/test/mir-opt/storage_ranges.rs b/src/test/mir-opt/storage_ranges.rs
index 933bfa8df2e..c63db741e5a 100644
--- a/src/test/mir-opt/storage_ranges.rs
+++ b/src/test/mir-opt/storage_ranges.rs
@@ -31,8 +31,8 @@ fn main() {
 //         _3 = &_4;
 //         StorageDead(_5);
 //         _2 = ();
-//         StorageDead(_4);
 //         StorageDead(_3);
+//         StorageDead(_4);
 //         StorageLive(_6);
 //         _6 = const 1i32;
 //         _0 = ();
diff --git a/src/test/run-pass/mir_drop_order.rs b/src/test/run-pass/mir_drop_order.rs
new file mode 100644
index 00000000000..55ac5ca067b
--- /dev/null
+++ b/src/test/run-pass/mir_drop_order.rs
@@ -0,0 +1,42 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::cell::RefCell;
+
+pub struct DropLogger<'a> {
+    id: usize,
+    log: &'a RefCell<Vec<usize>>
+}
+
+impl<'a> Drop for DropLogger<'a> {
+    fn drop(&mut self) {
+        self.log.borrow_mut().push(self.id);
+    }
+}
+
+fn main() {
+    let log = RefCell::new(vec![]);
+    let d = |id| DropLogger { id: id, log: &log };
+    let get = || -> Vec<_> {
+        let mut m = log.borrow_mut();
+        let n = m.drain(..);
+        n.collect()
+    };
+
+    {
+        let _x = (d(0), &d(1), d(2), &d(3));
+        // all borrows are extended - nothing has been dropped yet
+        assert_eq!(get(), vec![]);
+    }
+    // in a let-statement, extended lvalues are dropped
+    // *after* the let result (tho they have the same scope
+    // as far as scope-based borrowck goes).
+    assert_eq!(get(), vec![0, 2, 3, 1]);
+}