]> git.lizzy.rs Git - rust.git/commitdiff
librustc: Use different alloca slot for non-move bindings.
authorLuqman Aden <laden@csclub.uwaterloo.ca>
Sat, 21 Jun 2014 21:05:05 +0000 (17:05 -0400)
committerLuqman Aden <me@luqman.ca>
Thu, 3 Jul 2014 03:22:34 +0000 (20:22 -0700)
src/librustc/middle/trans/_match.rs
src/librustc/middle/trans/debuginfo.rs

index 6ec126edf0b6fdeaf21ec88954358a410ab52b39..a305f26406556ff3cafaba6a7b2bec0baa791bde 100644 (file)
  * per-arm `ArmData` struct.  There is a mapping from identifiers to
  * `BindingInfo` structs.  These structs contain the mode/id/type of the
  * binding, but they also contain an LLVM value which points at an alloca
- * called `llmatch`.
+ * called `llmatch`. For by value bindings that are Copy, we also create
+ * an extra alloca that we copy the matched value to so that any changes
+ * we do to our copy is not reflected in the original and vice-versa.
+ * We don't do this if it's a move since the original value can't be used
+ * and thus allowing us to cheat in not creating an extra alloca.
  *
  * The `llmatch` binding always stores a pointer into the value being matched
  * which points at the data for the binding.  If the value being matched has
@@ -352,7 +356,8 @@ fn variant_opt(bcx: &Block, pat_id: ast::NodeId) -> Opt {
 
 #[deriving(Clone)]
 pub enum TransBindingMode {
-    TrByValue,
+    TrByCopy(/* llbinding */ ValueRef),
+    TrByMove,
     TrByRef,
 }
 
@@ -1249,7 +1254,7 @@ fn compare_str<'a>(cx: &'a Block<'a>,
     }
 }
 
-fn insert_lllocals<'a>(bcx: &'a Block<'a>,
+fn insert_lllocals<'a>(mut bcx: &'a Block<'a>,
                        bindings_map: &BindingsMap,
                        cleanup_scope: cleanup::ScopeId)
                        -> &'a Block<'a> {
@@ -1262,8 +1267,18 @@ fn insert_lllocals<'a>(bcx: &'a Block<'a>,
 
     for (&ident, &binding_info) in bindings_map.iter() {
         let llval = match binding_info.trmode {
-            // By value bindings: load from the ptr into the matched value
-            TrByValue => Load(bcx, binding_info.llmatch),
+            // By value mut binding for a copy type: load from the ptr
+            // into the matched value and copy to our alloca
+            TrByCopy(llbinding) => {
+                let llval = Load(bcx, binding_info.llmatch);
+                let datum = Datum::new(llval, binding_info.ty, Lvalue);
+                bcx = datum.store_to(bcx, llbinding);
+
+                llbinding
+            },
+
+            // By value move bindings: load from the ptr into the matched value
+            TrByMove => Load(bcx, binding_info.llmatch),
 
             // By ref binding: use the ptr into the matched value
             TrByRef => binding_info.llmatch
@@ -1762,10 +1777,20 @@ fn create_bindings_map(bcx: &Block, pat: Gc<ast::Pat>) -> BindingsMap {
         let ident = path_to_ident(path);
         let variable_ty = node_id_type(bcx, p_id);
         let llvariable_ty = type_of::type_of(ccx, variable_ty);
+        let tcx = bcx.tcx();
 
         let llmatch;
         let trmode;
         match bm {
+            ast::BindByValue(_)
+                if !ty::type_moves_by_default(tcx, variable_ty) => {
+                llmatch = alloca(bcx,
+                                 llvariable_ty.ptr_to(),
+                                 "__llmatch");
+                trmode = TrByCopy(alloca(bcx,
+                                         llvariable_ty,
+                                         bcx.ident(ident).as_slice()));
+            }
             ast::BindByValue(_) => {
                 // in this case, the final type of the variable will be T,
                 // but during matching we need to store a *T as explained
@@ -1773,7 +1798,7 @@ fn create_bindings_map(bcx: &Block, pat: Gc<ast::Pat>) -> BindingsMap {
                 llmatch = alloca(bcx,
                                  llvariable_ty.ptr_to(),
                                  bcx.ident(ident).as_slice());
-                trmode = TrByValue;
+                trmode = TrByMove;
             }
             ast::BindByRef(_) => {
                 llmatch = alloca(bcx,
index 27d32f2c4d8e9e416f39a43deaa1b2fd828b9c31..83b956290ef696bf5e3ee4401886439c12104570 100644 (file)
@@ -188,7 +188,7 @@ struct List {
 use middle::trans::adt;
 use middle::trans::common::*;
 use middle::trans::machine;
-use middle::trans::_match::{BindingInfo, TrByValue, TrByRef};
+use middle::trans::_match::{BindingInfo, TrByCopy, TrByMove, TrByRef};
 use middle::trans::type_of;
 use middle::trans::type_::Type;
 use middle::trans;
@@ -948,11 +948,14 @@ pub fn create_match_binding_metadata(bcx: &Block,
         [llvm::LLVMDIBuilderCreateOpDeref(bcx.ccx().int_type.to_ref())]
     };
     // Regardless of the actual type (`T`) we're always passed the stack slot (alloca)
-    // for the binding. For ByRef bindings that's a `T*` but for ByValue bindings we
+    // for the binding. For ByRef bindings that's a `T*` but for ByMove bindings we
     // actually have `T**`. So to get the actual variable we need to dereference once
-    // more.
+    // more. For ByCopy we just use the stack slot we created for the binding.
     let var_type = match binding.trmode {
-        TrByValue => IndirectVariable {
+        TrByCopy(llbinding) => DirectVariable {
+            alloca: llbinding
+        },
+        TrByMove => IndirectVariable {
             alloca: binding.llmatch,
             address_operations: aops
         },