64
64
* We store information about the bound variables for each arm as part of the
65
65
* per-arm `ArmData` struct. There is a mapping from identifiers to
66
66
* `BindingInfo` structs. These structs contain the mode/id/type of the
67
- * binding, but they also contain up to two LLVM values, called `llmatch` and
68
- * `llbinding` respectively (the `llbinding`, as will be described shortly, is
69
- * optional and only present for by-value bindings---therefore it is bundled
70
- * up as part of the `TransBindingMode` type). Both point at allocas.
67
+ * binding, but they also contain an LLVM value which points at an alloca
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.
71
73
*
72
74
* The `llmatch` binding always stores a pointer into the value being matched
73
75
* which points at the data for the binding. If the value being matched has
83
85
* up against an identifier, we store the current pointer into the
84
86
* corresponding alloca.
85
87
*
86
- * In addition, for each by-value binding (copy or move), we will create a
87
- * second alloca (`llbinding`) that will hold the final value. In this
88
- * example, that means that `d` would have this second alloca of type `D` (and
89
- * hence `llbinding` has type `D*`).
90
- *
91
88
* Once a pattern is completely matched, and assuming that there is no guard
92
89
* pattern, we will branch to a block that leads to the body itself. For any
93
90
* by-value bindings, this block will first load the ptr from `llmatch` (the
94
- * one of type `D*`) and copy/move the value into `llbinding` (the one of type
95
- * `D`). The second alloca then becomes the value of the local variable. For
96
- * by ref bindings, the value of the local variable is simply the first
97
- * alloca.
91
+ * one of type `D*`) and then load a second time to get the actual value (the
92
+ * one of type `D`). For by ref bindings, the value of the local variable is
93
+ * simply the first alloca.
98
94
*
99
95
* So, for the example above, we would generate a setup kind of like this:
100
96
*
101
97
* +-------+
102
98
* | Entry |
103
99
* +-------+
104
100
* |
105
- * +-------------------------------------------+
106
- * | llmatch_c = (addr of first half of tuple) |
107
- * | llmatch_d = (addr of first half of tuple) |
108
- * +-------------------------------------------+
101
+ * +-------------------------------------------- +
102
+ * | llmatch_c = (addr of first half of tuple) |
103
+ * | llmatch_d = (addr of second half of tuple) |
104
+ * +-------------------------------------------- +
109
105
* |
110
106
* +--------------------------------------+
111
- * | *llbinding_d = **llmatch_dlbinding_d |
107
+ * | *llbinding_d = **llmatch_d |
112
108
* +--------------------------------------+
113
109
*
114
110
* If there is a guard, the situation is slightly different, because we must
127
123
* +-------------------------------------------+
128
124
* |
129
125
* +-------------------------------------------------+
130
- * | *llbinding_d = **llmatch_dlbinding_d |
126
+ * | *llbinding_d = **llmatch_d |
131
127
* | check condition |
132
- * | if false { free *llbinding_d, goto next case } |
128
+ * | if false { goto next case } |
133
129
* | if true { goto body } |
134
130
* +-------------------------------------------------+
135
131
*
136
132
* The handling for the cleanups is a bit... sensitive. Basically, the body
137
133
* is the one that invokes `add_clean()` for each binding. During the guard
138
134
* evaluation, we add temporary cleanups and revoke them after the guard is
139
- * evaluated (it could fail, after all). Presuming the guard fails, we drop
140
- * the various values we copied explicitly. Note that guards and moves are
135
+ * evaluated (it could fail, after all). Note that guards and moves are
141
136
* just plain incompatible.
142
137
*
143
138
* Some relevant helper functions that manage bindings:
144
139
* - `create_bindings_map()`
145
- * - `store_non_ref_bindings()`
146
140
* - `insert_lllocals()`
147
141
*
148
142
*
@@ -216,7 +210,6 @@ use middle::trans::datum;
216
210
use middle:: trans:: datum:: * ;
217
211
use middle:: trans:: expr:: Dest ;
218
212
use middle:: trans:: expr;
219
- use middle:: trans:: glue;
220
213
use middle:: trans:: tvec;
221
214
use middle:: trans:: type_of;
222
215
use middle:: trans:: debuginfo;
@@ -355,8 +348,9 @@ fn variant_opt(bcx: &Block, pat_id: ast::NodeId) -> Opt {
355
348
}
356
349
357
350
#[ deriving( Clone ) ]
358
- enum TransBindingMode {
359
- TrByValue ( /*llbinding:*/ ValueRef ) ,
351
+ pub enum TransBindingMode {
352
+ TrByCopy ( /* llbinding */ ValueRef ) ,
353
+ TrByMove ,
360
354
TrByRef ,
361
355
}
362
356
@@ -369,12 +363,12 @@ enum TransBindingMode {
369
363
* - `id` is the node id of the binding
370
364
* - `ty` is the Rust type of the binding */
371
365
#[ deriving( Clone ) ]
372
- struct BindingInfo {
373
- llmatch : ValueRef ,
374
- trmode : TransBindingMode ,
375
- id : ast:: NodeId ,
376
- span : Span ,
377
- ty : ty:: t ,
366
+ pub struct BindingInfo {
367
+ pub llmatch : ValueRef ,
368
+ pub trmode : TransBindingMode ,
369
+ pub id : ast:: NodeId ,
370
+ pub span : Span ,
371
+ pub ty : ty:: t ,
378
372
}
379
373
380
374
type BindingsMap = HashMap < Ident , BindingInfo > ;
@@ -968,64 +962,34 @@ fn compare_values<'a>(
968
962
}
969
963
}
970
964
971
- fn store_non_ref_bindings < ' a > (
972
- bcx : & ' a Block < ' a > ,
973
- bindings_map : & BindingsMap ,
974
- opt_cleanup_scope : Option < cleanup:: ScopeId > )
975
- -> & ' a Block < ' a >
976
- {
977
- /*!
978
- * For each copy/move binding, copy the value from the value being
979
- * matched into its final home. This code executes once one of
980
- * the patterns for a given arm has completely matched. It adds
981
- * cleanups to the `opt_cleanup_scope`, if one is provided.
982
- */
983
-
984
- let fcx = bcx. fcx ;
985
- let mut bcx = bcx;
986
- for ( _, & binding_info) in bindings_map. iter ( ) {
987
- match binding_info. trmode {
988
- TrByValue ( lldest) => {
989
- let llval = Load ( bcx, binding_info. llmatch ) ; // get a T*
990
- let datum = Datum :: new ( llval, binding_info. ty , Lvalue ) ;
991
- bcx = datum. store_to ( bcx, lldest) ;
992
-
993
- match opt_cleanup_scope {
994
- None => { }
995
- Some ( s) => {
996
- fcx. schedule_drop_mem ( s, lldest, binding_info. ty ) ;
997
- }
998
- }
999
- }
1000
- TrByRef => { }
1001
- }
1002
- }
1003
- return bcx;
1004
- }
1005
-
1006
- fn insert_lllocals < ' a > ( bcx : & ' a Block < ' a > ,
1007
- bindings_map : & BindingsMap ,
1008
- cleanup_scope : cleanup:: ScopeId )
965
+ fn insert_lllocals < ' a > ( mut bcx : & ' a Block < ' a > ,
966
+ bindings_map : & BindingsMap )
1009
967
-> & ' a Block < ' a > {
1010
968
/*!
1011
969
* For each binding in `data.bindings_map`, adds an appropriate entry into
1012
- * the `fcx.lllocals` map, scheduling cleanup in `cleanup_scope`.
970
+ * the `fcx.lllocals` map
1013
971
*/
1014
972
1015
- let fcx = bcx. fcx ;
1016
-
1017
973
for ( & ident, & binding_info) in bindings_map. iter ( ) {
1018
974
let llval = match binding_info. trmode {
1019
- // By value bindings: use the stack slot that we
1020
- // copied/moved the value into
1021
- TrByValue ( lldest) => lldest,
975
+ // By value mut binding for a copy type: load from the ptr
976
+ // into the matched value and copy to our alloca
977
+ TrByCopy ( llbinding) => {
978
+ let llval = Load ( bcx, binding_info. llmatch ) ;
979
+ let datum = Datum :: new ( llval, binding_info. ty , Lvalue ) ;
980
+ bcx = datum. store_to ( bcx, llbinding) ;
981
+
982
+ llbinding
983
+ } ,
984
+
985
+ // By value move bindings: load from the ptr into the matched value
986
+ TrByMove => Load ( bcx, binding_info. llmatch ) ,
1022
987
1023
988
// By ref binding: use the ptr into the matched value
1024
989
TrByRef => binding_info. llmatch
1025
990
} ;
1026
991
1027
992
let datum = Datum :: new ( llval, binding_info. ty , Lvalue ) ;
1028
- fcx. schedule_drop_mem ( cleanup_scope, llval, binding_info. ty ) ;
1029
993
1030
994
debug ! ( "binding {:?} to {}" ,
1031
995
binding_info. id,
@@ -1035,9 +999,7 @@ fn insert_lllocals<'a>(bcx: &'a Block<'a>,
1035
999
if bcx. sess ( ) . opts . debuginfo == FullDebugInfo {
1036
1000
debuginfo:: create_match_binding_metadata ( bcx,
1037
1001
ident,
1038
- binding_info. id ,
1039
- binding_info. span ,
1040
- datum) ;
1002
+ binding_info) ;
1041
1003
}
1042
1004
}
1043
1005
bcx
@@ -1059,28 +1021,16 @@ fn compile_guard<'a, 'b>(
1059
1021
vec_map_to_str( vals, |v| bcx. val_to_str( * v) ) ) ;
1060
1022
let _indenter = indenter ( ) ;
1061
1023
1062
- // Lest the guard itself should fail, introduce a temporary cleanup
1063
- // scope for any non-ref bindings we create.
1064
- let temp_scope = bcx. fcx . push_custom_cleanup_scope ( ) ;
1065
-
1066
- let mut bcx = bcx;
1067
- bcx = store_non_ref_bindings ( bcx, & data. bindings_map ,
1068
- Some ( cleanup:: CustomScope ( temp_scope) ) ) ;
1069
- bcx = insert_lllocals ( bcx, & data. bindings_map ,
1070
- cleanup:: CustomScope ( temp_scope) ) ;
1024
+ let mut bcx = insert_lllocals ( bcx, & data. bindings_map ) ;
1071
1025
1072
1026
let val = unpack_datum ! ( bcx, expr:: trans( bcx, guard_expr) ) ;
1073
1027
let val = val. to_llbool ( bcx) ;
1074
1028
1075
- // Cancel cleanups now that the guard successfully executed. If
1076
- // the guard was false, we will drop the values explicitly
1077
- // below. Otherwise, we'll add lvalue cleanups at the end.
1078
- bcx. fcx . pop_custom_cleanup_scope ( temp_scope) ;
1079
-
1080
1029
return with_cond ( bcx, Not ( bcx, val) , |bcx| {
1081
- // Guard does not match: free the values we copied,
1082
- // and remove all bindings from the lllocals table
1083
- let bcx = drop_bindings ( bcx, data) ;
1030
+ // Guard does not match: remove all bindings from the lllocals table
1031
+ for ( _, & binding_info) in data. bindings_map . iter ( ) {
1032
+ bcx. fcx . lllocals . borrow_mut ( ) . remove ( & binding_info. id ) ;
1033
+ }
1084
1034
match chk {
1085
1035
// If the default arm is the only one left, move on to the next
1086
1036
// condition explicitly rather than (possibly) falling back to
@@ -1094,21 +1044,6 @@ fn compile_guard<'a, 'b>(
1094
1044
} ;
1095
1045
bcx
1096
1046
} ) ;
1097
-
1098
- fn drop_bindings < ' a > ( bcx : & ' a Block < ' a > , data : & ArmData )
1099
- -> & ' a Block < ' a > {
1100
- let mut bcx = bcx;
1101
- for ( _, & binding_info) in data. bindings_map . iter ( ) {
1102
- match binding_info. trmode {
1103
- TrByValue ( llval) => {
1104
- bcx = glue:: drop_ty ( bcx, llval, binding_info. ty ) ;
1105
- }
1106
- TrByRef => { }
1107
- }
1108
- bcx. fcx . lllocals . borrow_mut ( ) . remove ( & binding_info. id ) ;
1109
- }
1110
- return bcx;
1111
- }
1112
1047
}
1113
1048
1114
1049
fn compile_submatch < ' a , ' b > (
@@ -1433,18 +1368,28 @@ fn create_bindings_map(bcx: &Block, pat: Gc<ast::Pat>) -> BindingsMap {
1433
1368
let ident = path1. node ;
1434
1369
let variable_ty = node_id_type ( bcx, p_id) ;
1435
1370
let llvariable_ty = type_of:: type_of ( ccx, variable_ty) ;
1371
+ let tcx = bcx. tcx ( ) ;
1436
1372
1437
1373
let llmatch;
1438
1374
let trmode;
1439
1375
match bm {
1376
+ ast:: BindByValue ( _)
1377
+ if !ty:: type_moves_by_default ( tcx, variable_ty) => {
1378
+ llmatch = alloca ( bcx,
1379
+ llvariable_ty. ptr_to ( ) ,
1380
+ "__llmatch" ) ;
1381
+ trmode = TrByCopy ( alloca ( bcx,
1382
+ llvariable_ty,
1383
+ bcx. ident ( ident) . as_slice ( ) ) ) ;
1384
+ }
1440
1385
ast:: BindByValue ( _) => {
1441
1386
// in this case, the final type of the variable will be T,
1442
1387
// but during matching we need to store a *T as explained
1443
1388
// above
1444
- llmatch = alloca ( bcx, llvariable_ty . ptr_to ( ) , "__llmatch" ) ;
1445
- trmode = TrByValue ( alloca ( bcx ,
1446
- llvariable_ty ,
1447
- bcx . ident ( ident ) . as_slice ( ) ) ) ;
1389
+ llmatch = alloca ( bcx,
1390
+ llvariable_ty . ptr_to ( ) ,
1391
+ bcx . ident ( ident ) . as_slice ( ) ) ;
1392
+ trmode = TrByMove ;
1448
1393
}
1449
1394
ast:: BindByRef ( _) => {
1450
1395
llmatch = alloca ( bcx,
@@ -1530,20 +1475,9 @@ fn trans_match_inner<'a>(scope_cx: &'a Block<'a>,
1530
1475
for arm_data in arm_datas. iter ( ) {
1531
1476
let mut bcx = arm_data. bodycx ;
1532
1477
1533
- // If this arm has a guard, then the various by-value bindings have
1534
- // already been copied into their homes. If not, we do it here. This
1535
- // is just to reduce code space. See extensive comment at the start
1536
- // of the file for more details.
1537
- if arm_data. arm . guard . is_none ( ) {
1538
- bcx = store_non_ref_bindings ( bcx, & arm_data. bindings_map , None ) ;
1539
- }
1540
-
1541
- // insert bindings into the lllocals map and add cleanups
1542
- let cleanup_scope = fcx. push_custom_cleanup_scope ( ) ;
1543
- bcx = insert_lllocals ( bcx, & arm_data. bindings_map ,
1544
- cleanup:: CustomScope ( cleanup_scope) ) ;
1478
+ // insert bindings into the lllocals map
1479
+ bcx = insert_lllocals ( bcx, & arm_data. bindings_map ) ;
1545
1480
bcx = expr:: trans_into ( bcx, & * arm_data. arm . body , dest) ;
1546
- bcx = fcx. pop_and_trans_custom_cleanup_scope ( bcx, cleanup_scope) ;
1547
1481
arm_cxs. push ( bcx) ;
1548
1482
}
1549
1483
0 commit comments