Skip to content

Commit bedc41b

Browse files
committed
librustc: Use different alloca slot for non-move bindings.
1 parent 94a56a3 commit bedc41b

File tree

2 files changed

+38
-10
lines changed

2 files changed

+38
-10
lines changed

src/librustc/middle/trans/_match.rs

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,11 @@
6565
* per-arm `ArmData` struct. There is a mapping from identifiers to
6666
* `BindingInfo` structs. These structs contain the mode/id/type of the
6767
* binding, but they also contain an LLVM value which points at an alloca
68-
* called `llmatch`.
68+
* called `llmatch`. For by value bindings that are Copy, we also create
69+
* an extra alloca that we copy the matched value to so that any changes
70+
* we do to our copy is not reflected in the original and vice-versa.
71+
* We don't do this if it's a move since the original value can't be used
72+
* and thus allowing us to cheat in not creating an extra alloca.
6973
*
7074
* The `llmatch` binding always stores a pointer into the value being matched
7175
* 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 {
352356

353357
#[deriving(Clone)]
354358
pub enum TransBindingMode {
355-
TrByValue,
359+
TrByCopy(/* llbinding */ ValueRef),
360+
TrByMove,
356361
TrByRef,
357362
}
358363

@@ -1249,7 +1254,7 @@ fn compare_values<'a>(
12491254
}
12501255
}
12511256

1252-
fn insert_lllocals<'a>(bcx: &'a Block<'a>,
1257+
fn insert_lllocals<'a>(mut bcx: &'a Block<'a>,
12531258
bindings_map: &BindingsMap,
12541259
cleanup_scope: cleanup::ScopeId)
12551260
-> &'a Block<'a> {
@@ -1262,8 +1267,18 @@ fn insert_lllocals<'a>(bcx: &'a Block<'a>,
12621267

12631268
for (&ident, &binding_info) in bindings_map.iter() {
12641269
let llval = match binding_info.trmode {
1265-
// By value bindings: load from the ptr into the matched value
1266-
TrByValue => Load(bcx, binding_info.llmatch),
1270+
// By value mut binding for a copy type: load from the ptr
1271+
// into the matched value and copy to our alloca
1272+
TrByCopy(llbinding) => {
1273+
let llval = Load(bcx, binding_info.llmatch);
1274+
let datum = Datum::new(llval, binding_info.ty, Lvalue);
1275+
bcx = datum.store_to(bcx, llbinding);
1276+
1277+
llbinding
1278+
},
1279+
1280+
// By value move bindings: load from the ptr into the matched value
1281+
TrByMove => Load(bcx, binding_info.llmatch),
12671282

12681283
// By ref binding: use the ptr into the matched value
12691284
TrByRef => binding_info.llmatch
@@ -1762,18 +1777,28 @@ fn create_bindings_map(bcx: &Block, pat: Gc<ast::Pat>) -> BindingsMap {
17621777
let ident = path_to_ident(path);
17631778
let variable_ty = node_id_type(bcx, p_id);
17641779
let llvariable_ty = type_of::type_of(ccx, variable_ty);
1780+
let tcx = bcx.tcx();
17651781

17661782
let llmatch;
17671783
let trmode;
17681784
match bm {
1785+
ast::BindByValue(_)
1786+
if !ty::type_moves_by_default(tcx, variable_ty) => {
1787+
llmatch = alloca(bcx,
1788+
llvariable_ty.ptr_to(),
1789+
"__llmatch");
1790+
trmode = TrByCopy(alloca(bcx,
1791+
llvariable_ty,
1792+
bcx.ident(ident).as_slice()));
1793+
}
17691794
ast::BindByValue(_) => {
17701795
// in this case, the final type of the variable will be T,
17711796
// but during matching we need to store a *T as explained
17721797
// above
17731798
llmatch = alloca(bcx,
17741799
llvariable_ty.ptr_to(),
17751800
bcx.ident(ident).as_slice());
1776-
trmode = TrByValue;
1801+
trmode = TrByMove;
17771802
}
17781803
ast::BindByRef(_) => {
17791804
llmatch = alloca(bcx,

src/librustc/middle/trans/debuginfo.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ use middle::subst;
188188
use middle::trans::adt;
189189
use middle::trans::common::*;
190190
use middle::trans::machine;
191-
use middle::trans::_match::{BindingInfo, TrByValue, TrByRef};
191+
use middle::trans::_match::{BindingInfo, TrByCopy, TrByMove, TrByRef};
192192
use middle::trans::type_of;
193193
use middle::trans::type_::Type;
194194
use middle::trans;
@@ -948,11 +948,14 @@ pub fn create_match_binding_metadata(bcx: &Block,
948948
[llvm::LLVMDIBuilderCreateOpDeref(bcx.ccx().int_type.to_ref())]
949949
};
950950
// Regardless of the actual type (`T`) we're always passed the stack slot (alloca)
951-
// for the binding. For ByRef bindings that's a `T*` but for ByValue bindings we
951+
// for the binding. For ByRef bindings that's a `T*` but for ByMove bindings we
952952
// actually have `T**`. So to get the actual variable we need to dereference once
953-
// more.
953+
// more. For ByCopy we just use the stack slot we created for the binding.
954954
let var_type = match binding.trmode {
955-
TrByValue => IndirectVariable {
955+
TrByCopy(llbinding) => DirectVariable {
956+
alloca: llbinding
957+
},
958+
TrByMove => IndirectVariable {
956959
alloca: binding.llmatch,
957960
address_operations: aops
958961
},

0 commit comments

Comments
 (0)