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;
@@ -357,8 +350,9 @@ fn variant_opt(bcx: &Block, pat_id: ast::NodeId) -> Opt {
357
350
}
358
351
359
352
#[ deriving( Clone ) ]
360
- enum TransBindingMode {
361
- TrByValue ( /*llbinding:*/ ValueRef ) ,
353
+ pub enum TransBindingMode {
354
+ TrByCopy ( /* llbinding */ ValueRef ) ,
355
+ TrByMove ,
362
356
TrByRef ,
363
357
}
364
358
@@ -371,12 +365,12 @@ enum TransBindingMode {
371
365
* - `id` is the node id of the binding
372
366
* - `ty` is the Rust type of the binding */
373
367
#[ deriving( Clone ) ]
374
- struct BindingInfo {
375
- llmatch : ValueRef ,
376
- trmode : TransBindingMode ,
377
- id : ast:: NodeId ,
378
- span : Span ,
379
- ty : ty:: t ,
368
+ pub struct BindingInfo {
369
+ pub llmatch : ValueRef ,
370
+ pub trmode : TransBindingMode ,
371
+ pub id : ast:: NodeId ,
372
+ pub span : Span ,
373
+ pub ty : ty:: t ,
380
374
}
381
375
382
376
type BindingsMap = HashMap < Ident , BindingInfo > ;
@@ -970,64 +964,34 @@ fn compare_values<'a>(
970
964
}
971
965
}
972
966
973
- fn store_non_ref_bindings < ' a > (
974
- bcx : & ' a Block < ' a > ,
975
- bindings_map : & BindingsMap ,
976
- opt_cleanup_scope : Option < cleanup:: ScopeId > )
977
- -> & ' a Block < ' a >
978
- {
979
- /*!
980
- * For each copy/move binding, copy the value from the value being
981
- * matched into its final home. This code executes once one of
982
- * the patterns for a given arm has completely matched. It adds
983
- * cleanups to the `opt_cleanup_scope`, if one is provided.
984
- */
985
-
986
- let fcx = bcx. fcx ;
987
- let mut bcx = bcx;
988
- for ( _, & binding_info) in bindings_map. iter ( ) {
989
- match binding_info. trmode {
990
- TrByValue ( lldest) => {
991
- let llval = Load ( bcx, binding_info. llmatch ) ; // get a T*
992
- let datum = Datum :: new ( llval, binding_info. ty , Lvalue ) ;
993
- bcx = datum. store_to ( bcx, lldest) ;
994
-
995
- match opt_cleanup_scope {
996
- None => { }
997
- Some ( s) => {
998
- fcx. schedule_drop_mem ( s, lldest, binding_info. ty ) ;
999
- }
1000
- }
1001
- }
1002
- TrByRef => { }
1003
- }
1004
- }
1005
- return bcx;
1006
- }
1007
-
1008
- fn insert_lllocals < ' a > ( bcx : & ' a Block < ' a > ,
1009
- bindings_map : & BindingsMap ,
1010
- cleanup_scope : cleanup:: ScopeId )
967
+ fn insert_lllocals < ' a > ( mut bcx : & ' a Block < ' a > ,
968
+ bindings_map : & BindingsMap )
1011
969
-> & ' a Block < ' a > {
1012
970
/*!
1013
971
* For each binding in `data.bindings_map`, adds an appropriate entry into
1014
- * the `fcx.lllocals` map, scheduling cleanup in `cleanup_scope`.
972
+ * the `fcx.lllocals` map
1015
973
*/
1016
974
1017
- let fcx = bcx. fcx ;
1018
-
1019
975
for ( & ident, & binding_info) in bindings_map. iter ( ) {
1020
976
let llval = match binding_info. trmode {
1021
- // By value bindings: use the stack slot that we
1022
- // copied/moved the value into
1023
- TrByValue ( lldest) => lldest,
977
+ // By value mut binding for a copy type: load from the ptr
978
+ // into the matched value and copy to our alloca
979
+ TrByCopy ( llbinding) => {
980
+ let llval = Load ( bcx, binding_info. llmatch ) ;
981
+ let datum = Datum :: new ( llval, binding_info. ty , Lvalue ) ;
982
+ bcx = datum. store_to ( bcx, llbinding) ;
983
+
984
+ llbinding
985
+ } ,
986
+
987
+ // By value move bindings: load from the ptr into the matched value
988
+ TrByMove => Load ( bcx, binding_info. llmatch ) ,
1024
989
1025
990
// By ref binding: use the ptr into the matched value
1026
991
TrByRef => binding_info. llmatch
1027
992
} ;
1028
993
1029
994
let datum = Datum :: new ( llval, binding_info. ty , Lvalue ) ;
1030
- fcx. schedule_drop_mem ( cleanup_scope, llval, binding_info. ty ) ;
1031
995
1032
996
debug ! ( "binding {:?} to {}" ,
1033
997
binding_info. id,
@@ -1037,9 +1001,7 @@ fn insert_lllocals<'a>(bcx: &'a Block<'a>,
1037
1001
if bcx. sess ( ) . opts . debuginfo == FullDebugInfo {
1038
1002
debuginfo:: create_match_binding_metadata ( bcx,
1039
1003
ident,
1040
- binding_info. id ,
1041
- binding_info. span ,
1042
- datum) ;
1004
+ binding_info) ;
1043
1005
}
1044
1006
}
1045
1007
bcx
@@ -1061,28 +1023,16 @@ fn compile_guard<'a, 'b>(
1061
1023
vec_map_to_str( vals, |v| bcx. val_to_str( * v) ) ) ;
1062
1024
let _indenter = indenter ( ) ;
1063
1025
1064
- // Lest the guard itself should fail, introduce a temporary cleanup
1065
- // scope for any non-ref bindings we create.
1066
- let temp_scope = bcx. fcx . push_custom_cleanup_scope ( ) ;
1067
-
1068
- let mut bcx = bcx;
1069
- bcx = store_non_ref_bindings ( bcx, & data. bindings_map ,
1070
- Some ( cleanup:: CustomScope ( temp_scope) ) ) ;
1071
- bcx = insert_lllocals ( bcx, & data. bindings_map ,
1072
- cleanup:: CustomScope ( temp_scope) ) ;
1026
+ let mut bcx = insert_lllocals ( bcx, & data. bindings_map ) ;
1073
1027
1074
1028
let val = unpack_datum ! ( bcx, expr:: trans( bcx, guard_expr) ) ;
1075
1029
let val = val. to_llbool ( bcx) ;
1076
1030
1077
- // Cancel cleanups now that the guard successfully executed. If
1078
- // the guard was false, we will drop the values explicitly
1079
- // below. Otherwise, we'll add lvalue cleanups at the end.
1080
- bcx. fcx . pop_custom_cleanup_scope ( temp_scope) ;
1081
-
1082
1031
return with_cond ( bcx, Not ( bcx, val) , |bcx| {
1083
- // Guard does not match: free the values we copied,
1084
- // and remove all bindings from the lllocals table
1085
- let bcx = drop_bindings ( bcx, data) ;
1032
+ // Guard does not match: remove all bindings from the lllocals table
1033
+ for ( _, & binding_info) in data. bindings_map . iter ( ) {
1034
+ bcx. fcx . lllocals . borrow_mut ( ) . remove ( & binding_info. id ) ;
1035
+ }
1086
1036
match chk {
1087
1037
// If the default arm is the only one left, move on to the next
1088
1038
// condition explicitly rather than (possibly) falling back to
@@ -1096,21 +1046,6 @@ fn compile_guard<'a, 'b>(
1096
1046
} ;
1097
1047
bcx
1098
1048
} ) ;
1099
-
1100
- fn drop_bindings < ' a > ( bcx : & ' a Block < ' a > , data : & ArmData )
1101
- -> & ' a Block < ' a > {
1102
- let mut bcx = bcx;
1103
- for ( _, & binding_info) in data. bindings_map . iter ( ) {
1104
- match binding_info. trmode {
1105
- TrByValue ( llval) => {
1106
- bcx = glue:: drop_ty ( bcx, llval, binding_info. ty ) ;
1107
- }
1108
- TrByRef => { }
1109
- }
1110
- bcx. fcx . lllocals . borrow_mut ( ) . remove ( & binding_info. id ) ;
1111
- }
1112
- return bcx;
1113
- }
1114
1049
}
1115
1050
1116
1051
fn compile_submatch < ' a , ' b > (
@@ -1435,18 +1370,28 @@ fn create_bindings_map(bcx: &Block, pat: Gc<ast::Pat>) -> BindingsMap {
1435
1370
let ident = path_to_ident ( path) ;
1436
1371
let variable_ty = node_id_type ( bcx, p_id) ;
1437
1372
let llvariable_ty = type_of:: type_of ( ccx, variable_ty) ;
1373
+ let tcx = bcx. tcx ( ) ;
1438
1374
1439
1375
let llmatch;
1440
1376
let trmode;
1441
1377
match bm {
1378
+ ast:: BindByValue ( _)
1379
+ if !ty:: type_moves_by_default ( tcx, variable_ty) => {
1380
+ llmatch = alloca ( bcx,
1381
+ llvariable_ty. ptr_to ( ) ,
1382
+ "__llmatch" ) ;
1383
+ trmode = TrByCopy ( alloca ( bcx,
1384
+ llvariable_ty,
1385
+ bcx. ident ( ident) . as_slice ( ) ) ) ;
1386
+ }
1442
1387
ast:: BindByValue ( _) => {
1443
1388
// in this case, the final type of the variable will be T,
1444
1389
// but during matching we need to store a *T as explained
1445
1390
// above
1446
- llmatch = alloca ( bcx, llvariable_ty . ptr_to ( ) , "__llmatch" ) ;
1447
- trmode = TrByValue ( alloca ( bcx ,
1448
- llvariable_ty ,
1449
- bcx . ident ( ident ) . as_slice ( ) ) ) ;
1391
+ llmatch = alloca ( bcx,
1392
+ llvariable_ty . ptr_to ( ) ,
1393
+ bcx . ident ( ident ) . as_slice ( ) ) ;
1394
+ trmode = TrByMove ;
1450
1395
}
1451
1396
ast:: BindByRef ( _) => {
1452
1397
llmatch = alloca ( bcx,
@@ -1532,20 +1477,9 @@ fn trans_match_inner<'a>(scope_cx: &'a Block<'a>,
1532
1477
for arm_data in arm_datas. iter ( ) {
1533
1478
let mut bcx = arm_data. bodycx ;
1534
1479
1535
- // If this arm has a guard, then the various by-value bindings have
1536
- // already been copied into their homes. If not, we do it here. This
1537
- // is just to reduce code space. See extensive comment at the start
1538
- // of the file for more details.
1539
- if arm_data. arm . guard . is_none ( ) {
1540
- bcx = store_non_ref_bindings ( bcx, & arm_data. bindings_map , None ) ;
1541
- }
1542
-
1543
- // insert bindings into the lllocals map and add cleanups
1544
- let cleanup_scope = fcx. push_custom_cleanup_scope ( ) ;
1545
- bcx = insert_lllocals ( bcx, & arm_data. bindings_map ,
1546
- cleanup:: CustomScope ( cleanup_scope) ) ;
1480
+ // insert bindings into the lllocals map
1481
+ bcx = insert_lllocals ( bcx, & arm_data. bindings_map ) ;
1547
1482
bcx = expr:: trans_into ( bcx, & * arm_data. arm . body , dest) ;
1548
- bcx = fcx. pop_and_trans_custom_cleanup_scope ( bcx, cleanup_scope) ;
1549
1483
arm_cxs. push ( bcx) ;
1550
1484
}
1551
1485
0 commit comments