@@ -97,7 +97,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
97
97
let body = self . hir . mirror ( arm. body . clone ( ) ) ;
98
98
let scope = self . declare_bindings ( None , body. span ,
99
99
LintLevel :: Inherited ,
100
- & arm. patterns [ 0 ] ,
100
+ & arm. patterns [ .. ] ,
101
101
ArmHasGuard ( arm. guard . is_some ( ) ) ,
102
102
Some ( ( Some ( & discriminant_place) , discriminant_span) ) ) ;
103
103
( body, scope. unwrap_or ( self . source_scope ) )
@@ -118,11 +118,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
118
118
arms. iter ( )
119
119
. enumerate ( )
120
120
. flat_map ( |( arm_index, arm) | {
121
- arm. patterns . iter ( )
122
- . map ( move |pat| ( arm_index, pat, arm. guard . clone ( ) ) )
121
+ arm. patterns . iter ( ) . enumerate ( )
122
+ . map ( move |( pat_index, pat) | {
123
+ ( arm_index, pat_index, pat, arm. guard . clone ( ) )
124
+ } )
123
125
} )
124
126
. zip ( pre_binding_blocks. iter ( ) . zip ( pre_binding_blocks. iter ( ) . skip ( 1 ) ) )
125
- . map ( |( ( arm_index, pattern, guard) ,
127
+ . map ( |( ( arm_index, pat_index , pattern, guard) ,
126
128
( pre_binding_block, next_candidate_pre_binding_block) ) | {
127
129
128
130
if let ( true , Some ( borrow_temp) ) = ( tcx. emit_read_for_match ( ) ,
@@ -168,6 +170,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
168
170
bindings : vec ! [ ] ,
169
171
guard,
170
172
arm_index,
173
+ pat_index,
171
174
pre_binding_block : * pre_binding_block,
172
175
next_candidate_pre_binding_block : * next_candidate_pre_binding_block,
173
176
}
@@ -277,6 +280,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
277
280
278
281
// since we don't call `match_candidates`, next fields is unused
279
282
arm_index : 0 ,
283
+ pat_index : 0 ,
280
284
pre_binding_block : block,
281
285
next_candidate_pre_binding_block : block
282
286
} ;
@@ -324,14 +328,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
324
328
mut visibility_scope : Option < SourceScope > ,
325
329
scope_span : Span ,
326
330
lint_level : LintLevel ,
327
- pattern : & Pattern < ' tcx > ,
331
+ patterns : & [ Pattern < ' tcx > ] ,
328
332
has_guard : ArmHasGuard ,
329
333
opt_match_place : Option < ( Option < & Place < ' tcx > > , Span ) > )
330
334
-> Option < SourceScope > {
331
335
assert ! ( !( visibility_scope. is_some( ) && lint_level. is_explicit( ) ) ,
332
336
"can't have both a visibility and a lint scope at the same time" ) ;
333
337
let mut scope = self . source_scope ;
334
- self . visit_bindings ( pattern, & mut |this, mutability, name, mode, var, span, ty| {
338
+ let num_patterns = patterns. len ( ) ;
339
+ self . visit_bindings ( & patterns[ 0 ] , & mut |this, mutability, name, mode, var, span, ty| {
335
340
if visibility_scope. is_none ( ) {
336
341
visibility_scope = Some ( this. new_source_scope ( scope_span,
337
342
LintLevel :: Inherited ,
@@ -349,8 +354,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
349
354
scope,
350
355
} ;
351
356
let visibility_scope = visibility_scope. unwrap ( ) ;
352
- this. declare_binding ( source_info, visibility_scope, mutability, name, mode, var,
353
- ty, has_guard, opt_match_place. map ( |( x, y) | ( x. cloned ( ) , y) ) ) ;
357
+ this. declare_binding ( source_info, visibility_scope, mutability, name, mode,
358
+ num_patterns, var, ty, has_guard,
359
+ opt_match_place. map ( |( x, y) | ( x. cloned ( ) , y) ) ) ;
354
360
} ) ;
355
361
visibility_scope
356
362
}
@@ -453,6 +459,9 @@ pub struct Candidate<'pat, 'tcx:'pat> {
453
459
// ...and the blocks for add false edges between candidates
454
460
pre_binding_block : BasicBlock ,
455
461
next_candidate_pre_binding_block : BasicBlock ,
462
+
463
+ // This uniquely identifies this candidate *within* the arm.
464
+ pat_index : usize ,
456
465
}
457
466
458
467
#[ derive( Clone , Debug ) ]
@@ -972,7 +981,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
972
981
let autoref = self . hir . tcx ( ) . all_pat_vars_are_implicit_refs_within_guards ( ) ;
973
982
if let Some ( guard) = candidate. guard {
974
983
if autoref {
975
- self . bind_matched_candidate_for_guard ( block, & candidate. bindings ) ;
984
+ self . bind_matched_candidate_for_guard (
985
+ block, candidate. pat_index , & candidate. bindings ) ;
976
986
let guard_frame = GuardFrame {
977
987
locals : candidate. bindings . iter ( )
978
988
. map ( |b| GuardFrameLocal :: new ( b. var_id , b. binding_mode ) )
@@ -1058,9 +1068,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1058
1068
// and thus all code/comments assume we are in that context.
1059
1069
fn bind_matched_candidate_for_guard ( & mut self ,
1060
1070
block : BasicBlock ,
1071
+ pat_index : usize ,
1061
1072
bindings : & [ Binding < ' tcx > ] ) {
1062
- debug ! ( "bind_matched_candidate_for_guard(block={:?}, bindings={:?})" ,
1063
- block, bindings) ;
1073
+ debug ! ( "bind_matched_candidate_for_guard(block={:?}, pat_index={:?}, bindings={:?})" ,
1074
+ block, pat_index , bindings) ;
1064
1075
1065
1076
// Assign each of the bindings. Since we are binding for a
1066
1077
// guard expression, this will never trigger moves out of the
@@ -1099,8 +1110,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1099
1110
// used by the arm body itself. This eases
1100
1111
// observing two-phase borrow restrictions.
1101
1112
let val_for_guard = self . storage_live_binding (
1102
- block, binding. var_id , binding. span , ValWithinGuard ) ;
1103
- self . schedule_drop_for_binding ( binding. var_id , binding. span , ValWithinGuard ) ;
1113
+ block, binding. var_id , binding. span , ValWithinGuard ( pat_index) ) ;
1114
+ self . schedule_drop_for_binding (
1115
+ binding. var_id , binding. span , ValWithinGuard ( pat_index) ) ;
1104
1116
1105
1117
// rust-lang/rust#27282: We reuse the two-phase
1106
1118
// borrow infrastructure so that the mutable
@@ -1146,16 +1158,26 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1146
1158
1147
1159
/// Each binding (`ref mut var`/`ref var`/`mut var`/`var`, where
1148
1160
/// the bound `var` has type `T` in the arm body) in a pattern
1149
- /// maps to *two* locals. The first local is a binding for
1161
+ /// maps to `2+N` locals. The first local is a binding for
1150
1162
/// occurrences of `var` in the guard, which will all have type
1151
- /// `&T`. The second local is a binding for occurrences of `var`
1152
- /// in the arm body, which will have type `T`.
1163
+ /// `&T`. The N locals are bindings for the `T` that is referenced
1164
+ /// by the first local; they are not used outside of the
1165
+ /// guard. The last local is a binding for occurrences of `var` in
1166
+ /// the arm body, which will have type `T`.
1167
+ ///
1168
+ /// The reason we have N locals rather than just 1 is to
1169
+ /// accommodate rust-lang/rust#51348: If the arm has N candidate
1170
+ /// patterns, then in general they can correspond to distinct
1171
+ /// parts of the matched data, and we want them to be distinct
1172
+ /// temps in order to simplify checks performed by our internal
1173
+ /// leveraging of two-phase borrows).
1153
1174
fn declare_binding ( & mut self ,
1154
1175
source_info : SourceInfo ,
1155
1176
visibility_scope : SourceScope ,
1156
1177
mutability : Mutability ,
1157
1178
name : Name ,
1158
1179
mode : BindingMode ,
1180
+ num_patterns : usize ,
1159
1181
var_id : NodeId ,
1160
1182
var_ty : Ty < ' tcx > ,
1161
1183
has_guard : ArmHasGuard ,
@@ -1189,7 +1211,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1189
1211
} ;
1190
1212
let for_arm_body = self . local_decls . push ( local. clone ( ) ) ;
1191
1213
let locals = if has_guard. 0 && tcx. all_pat_vars_are_implicit_refs_within_guards ( ) {
1192
- let val_for_guard = self . local_decls . push ( local) ;
1214
+ let mut vals_for_guard = Vec :: with_capacity ( num_patterns) ;
1215
+ for _ in 0 ..num_patterns {
1216
+ let val_for_guard_idx = self . local_decls . push ( local. clone ( ) ) ;
1217
+ vals_for_guard. push ( val_for_guard_idx) ;
1218
+ }
1193
1219
let ref_for_guard = self . local_decls . push ( LocalDecl :: < ' tcx > {
1194
1220
mutability,
1195
1221
ty : tcx. mk_imm_ref ( tcx. types . re_empty , var_ty) ,
@@ -1200,7 +1226,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1200
1226
internal : false ,
1201
1227
is_user_variable : Some ( ClearCrossCrate :: Set ( BindingForm :: RefForGuard ) ) ,
1202
1228
} ) ;
1203
- LocalsForNode :: Three { val_for_guard , ref_for_guard, for_arm_body }
1229
+ LocalsForNode :: ForGuard { vals_for_guard , ref_for_guard, for_arm_body }
1204
1230
} else {
1205
1231
LocalsForNode :: One ( for_arm_body)
1206
1232
} ;
0 commit comments