6464 * We store information about the bound variables for each arm as part of the
6565 * per-arm `ArmData` struct. There is a mapping from identifiers to
6666 * `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.
7173 *
7274 * The `llmatch` binding always stores a pointer into the value being matched
7375 * which points at the data for the binding. If the value being matched has
8385 * up against an identifier, we store the current pointer into the
8486 * corresponding alloca.
8587 *
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- *
9188 * Once a pattern is completely matched, and assuming that there is no guard
9289 * pattern, we will branch to a block that leads to the body itself. For any
9390 * 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.
9894 *
9995 * So, for the example above, we would generate a setup kind of like this:
10096 *
10197 * +-------+
10298 * | Entry |
10399 * +-------+
104100 * |
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+ * +-------------------------------------------- +
109105 * |
110106 * +--------------------------------------+
111- * | *llbinding_d = **llmatch_dlbinding_d |
107+ * | *llbinding_d = **llmatch_d |
112108 * +--------------------------------------+
113109 *
114110 * If there is a guard, the situation is slightly different, because we must
127123 * +-------------------------------------------+
128124 * |
129125 * +-------------------------------------------------+
130- * | *llbinding_d = **llmatch_dlbinding_d |
126+ * | *llbinding_d = **llmatch_d |
131127 * | check condition |
132- * | if false { free *llbinding_d, goto next case } |
128+ * | if false { goto next case } |
133129 * | if true { goto body } |
134130 * +-------------------------------------------------+
135131 *
136132 * The handling for the cleanups is a bit... sensitive. Basically, the body
137133 * is the one that invokes `add_clean()` for each binding. During the guard
138134 * 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
141136 * just plain incompatible.
142137 *
143138 * Some relevant helper functions that manage bindings:
144139 * - `create_bindings_map()`
145- * - `store_non_ref_bindings()`
146140 * - `insert_lllocals()`
147141 *
148142 *
@@ -216,7 +210,6 @@ use middle::trans::datum;
216210use middle:: trans:: datum:: * ;
217211use middle:: trans:: expr:: Dest ;
218212use middle:: trans:: expr;
219- use middle:: trans:: glue;
220213use middle:: trans:: tvec;
221214use middle:: trans:: type_of;
222215use middle:: trans:: debuginfo;
@@ -357,8 +350,9 @@ fn variant_opt(bcx: &Block, pat_id: ast::NodeId) -> Opt {
357350}
358351
359352#[ deriving( Clone ) ]
360- enum TransBindingMode {
361- TrByValue ( /*llbinding:*/ ValueRef ) ,
353+ pub enum TransBindingMode {
354+ TrByCopy ( /* llbinding */ ValueRef ) ,
355+ TrByMove ,
362356 TrByRef ,
363357}
364358
@@ -371,12 +365,12 @@ enum TransBindingMode {
371365 * - `id` is the node id of the binding
372366 * - `ty` is the Rust type of the binding */
373367 #[ 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 ,
380374}
381375
382376type BindingsMap = HashMap < Ident , BindingInfo > ;
@@ -970,64 +964,34 @@ fn compare_values<'a>(
970964 }
971965}
972966
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 )
1011969 -> & ' a Block < ' a > {
1012970 /*!
1013971 * 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
1015973 */
1016974
1017- let fcx = bcx. fcx ;
1018-
1019975 for ( & ident, & binding_info) in bindings_map. iter ( ) {
1020976 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 ) ,
1024989
1025990 // By ref binding: use the ptr into the matched value
1026991 TrByRef => binding_info. llmatch
1027992 } ;
1028993
1029994 let datum = Datum :: new ( llval, binding_info. ty , Lvalue ) ;
1030- fcx. schedule_drop_mem ( cleanup_scope, llval, binding_info. ty ) ;
1031995
1032996 debug ! ( "binding {:?} to {}" ,
1033997 binding_info. id,
@@ -1037,9 +1001,7 @@ fn insert_lllocals<'a>(bcx: &'a Block<'a>,
10371001 if bcx. sess ( ) . opts . debuginfo == FullDebugInfo {
10381002 debuginfo:: create_match_binding_metadata ( bcx,
10391003 ident,
1040- binding_info. id ,
1041- binding_info. span ,
1042- datum) ;
1004+ binding_info) ;
10431005 }
10441006 }
10451007 bcx
@@ -1061,28 +1023,16 @@ fn compile_guard<'a, 'b>(
10611023 vec_map_to_str( vals, |v| bcx. val_to_str( * v) ) ) ;
10621024 let _indenter = indenter ( ) ;
10631025
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 ) ;
10731027
10741028 let val = unpack_datum ! ( bcx, expr:: trans( bcx, guard_expr) ) ;
10751029 let val = val. to_llbool ( bcx) ;
10761030
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-
10821031 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+ }
10861036 match chk {
10871037 // If the default arm is the only one left, move on to the next
10881038 // condition explicitly rather than (possibly) falling back to
@@ -1096,21 +1046,6 @@ fn compile_guard<'a, 'b>(
10961046 } ;
10971047 bcx
10981048 } ) ;
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- }
11141049}
11151050
11161051fn compile_submatch < ' a , ' b > (
@@ -1435,18 +1370,28 @@ fn create_bindings_map(bcx: &Block, pat: Gc<ast::Pat>) -> BindingsMap {
14351370 let ident = path_to_ident ( path) ;
14361371 let variable_ty = node_id_type ( bcx, p_id) ;
14371372 let llvariable_ty = type_of:: type_of ( ccx, variable_ty) ;
1373+ let tcx = bcx. tcx ( ) ;
14381374
14391375 let llmatch;
14401376 let trmode;
14411377 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+ }
14421387 ast:: BindByValue ( _) => {
14431388 // in this case, the final type of the variable will be T,
14441389 // but during matching we need to store a *T as explained
14451390 // 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 ;
14501395 }
14511396 ast:: BindByRef ( _) => {
14521397 llmatch = alloca ( bcx,
@@ -1532,20 +1477,9 @@ fn trans_match_inner<'a>(scope_cx: &'a Block<'a>,
15321477 for arm_data in arm_datas. iter ( ) {
15331478 let mut bcx = arm_data. bodycx ;
15341479
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 ) ;
15471482 bcx = expr:: trans_into ( bcx, & * arm_data. arm . body , dest) ;
1548- bcx = fcx. pop_and_trans_custom_cleanup_scope ( bcx, cleanup_scope) ;
15491483 arm_cxs. push ( bcx) ;
15501484 }
15511485
0 commit comments