@@ -21,7 +21,7 @@ use rustc::mir::*;
21
21
use rustc:: hir;
22
22
use hair:: * ;
23
23
use syntax:: ast:: { Name , NodeId } ;
24
- use syntax_pos:: { DUMMY_SP , Span } ;
24
+ use syntax_pos:: Span ;
25
25
26
26
// helper functions, broken out by category:
27
27
mod simplify;
@@ -54,29 +54,43 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
54
54
( body, scope. unwrap_or ( self . visibility_scope ) )
55
55
} ) . collect ( ) ;
56
56
57
+ // create binding start block for link them by false edges
58
+ let candidate_count = arms. iter ( ) . fold ( 0 , |ac, c| ac + c. patterns . len ( ) ) ;
59
+ let pre_binding_blocks: Vec < _ > = ( 0 ..candidate_count + 1 )
60
+ . map ( |_| self . cfg . start_new_block ( ) ) . collect ( ) ;
61
+
57
62
// assemble a list of candidates: there is one candidate per
58
63
// pattern, which means there may be more than one candidate
59
64
// *per arm*. These candidates are kept sorted such that the
60
65
// highest priority candidate comes first in the list.
61
66
// (i.e. same order as in source)
67
+
62
68
let candidates: Vec < _ > =
63
69
arms. iter ( )
64
70
. enumerate ( )
65
71
. flat_map ( |( arm_index, arm) | {
66
72
arm. patterns . iter ( )
67
73
. map ( move |pat| ( arm_index, pat, arm. guard . clone ( ) ) )
68
74
} )
69
- . map ( |( arm_index, pattern, guard) | {
75
+ . zip ( pre_binding_blocks. iter ( ) . zip ( pre_binding_blocks. iter ( ) . skip ( 1 ) ) )
76
+ . map ( |( ( arm_index, pattern, guard) ,
77
+ ( pre_binding_block, next_candidate_pre_binding_block) ) | {
70
78
Candidate {
71
79
span : pattern. span ,
72
80
match_pairs : vec ! [ MatchPair :: new( discriminant_lvalue. clone( ) , pattern) ] ,
73
81
bindings : vec ! [ ] ,
74
82
guard,
75
83
arm_index,
84
+ pre_binding_block : * pre_binding_block,
85
+ next_candidate_pre_binding_block : * next_candidate_pre_binding_block,
76
86
}
77
87
} )
78
88
. collect ( ) ;
79
89
90
+ let outer_source_info = self . source_info ( span) ;
91
+ self . cfg . terminate ( * pre_binding_blocks. last ( ) . unwrap ( ) ,
92
+ outer_source_info, TerminatorKind :: Unreachable ) ;
93
+
80
94
// this will generate code to test discriminant_lvalue and
81
95
// branch to the appropriate arm block
82
96
let otherwise = self . match_candidates ( span, & mut arm_blocks, candidates, block) ;
@@ -148,7 +162,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
148
162
match_pairs : vec ! [ MatchPair :: new( initializer. clone( ) , & irrefutable_pat) ] ,
149
163
bindings : vec ! [ ] ,
150
164
guard : None ,
151
- arm_index : 0 , // since we don't call `match_candidates`, this field is unused
165
+
166
+ // since we don't call `match_candidates`, next fields is unused
167
+ arm_index : 0 ,
168
+ pre_binding_block : block,
169
+ next_candidate_pre_binding_block : block
152
170
} ;
153
171
154
172
// Simplify the candidate. Since the pattern is irrefutable, this should
@@ -278,6 +296,10 @@ pub struct Candidate<'pat, 'tcx:'pat> {
278
296
279
297
// ...and then we branch to arm with this index.
280
298
arm_index : usize ,
299
+
300
+ // ...and the blocks for add false edges between candidates
301
+ pre_binding_block : BasicBlock ,
302
+ next_candidate_pre_binding_block : BasicBlock ,
281
303
}
282
304
283
305
#[ derive( Clone , Debug ) ]
@@ -398,17 +420,43 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
398
420
candidates. iter ( ) . take_while ( |c| c. match_pairs . is_empty ( ) ) . count ( ) ;
399
421
debug ! ( "match_candidates: {:?} candidates fully matched" , fully_matched) ;
400
422
let mut unmatched_candidates = candidates. split_off ( fully_matched) ;
401
- for ( index, candidate) in candidates. into_iter ( ) . enumerate ( ) {
423
+
424
+ let fully_matched_with_guard =
425
+ candidates. iter ( ) . take_while ( |c| c. guard . is_some ( ) ) . count ( ) ;
426
+
427
+ let unreachable_candidates = if fully_matched_with_guard + 1 < candidates. len ( ) {
428
+ candidates. split_off ( fully_matched_with_guard + 1 )
429
+ } else {
430
+ vec ! [ ]
431
+ } ;
432
+
433
+ for candidate in candidates {
402
434
// If so, apply any bindings, test the guard (if any), and
403
435
// branch to the arm.
404
- let is_last = index == fully_matched - 1 ;
405
- if let Some ( b) = self . bind_and_guard_matched_candidate ( block, arm_blocks,
406
- candidate, is_last) {
436
+ if let Some ( b) = self . bind_and_guard_matched_candidate ( block, arm_blocks, candidate) {
407
437
block = b;
408
438
} else {
409
439
// if None is returned, then any remaining candidates
410
440
// are unreachable (at least not through this path).
411
- return vec ! [ ] ;
441
+ // Link them with false edges.
442
+ debug ! ( "match_candidates: add false edges for unreachable {:?} and unmatched {:?}" ,
443
+ unreachable_candidates, unmatched_candidates) ;
444
+ for candidate in unreachable_candidates {
445
+ let source_info = self . source_info ( candidate. span ) ;
446
+ let target = self . cfg . start_new_block ( ) ;
447
+ if let Some ( otherwise) = self . bind_and_guard_matched_candidate ( target,
448
+ arm_blocks,
449
+ candidate) {
450
+ self . cfg . terminate ( otherwise, source_info, TerminatorKind :: Unreachable ) ;
451
+ }
452
+ }
453
+
454
+ if unmatched_candidates. is_empty ( ) {
455
+ return vec ! [ ]
456
+ } else {
457
+ let target = self . cfg . start_new_block ( ) ;
458
+ return self . match_candidates ( span, arm_blocks, unmatched_candidates, target) ;
459
+ }
412
460
}
413
461
}
414
462
@@ -423,9 +471,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
423
471
self . test_candidates ( span, arm_blocks, & unmatched_candidates, block) ;
424
472
425
473
// If the target candidates were exhaustive, then we are done.
426
- if otherwise. is_empty ( ) {
427
- return vec ! [ ] ;
428
- }
474
+ // But for borrowck continue build decision tree.
429
475
430
476
// If all candidates were sorted into `target_candidates` somewhere, then
431
477
// the initial set was inexhaustive.
@@ -666,48 +712,50 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
666
712
fn bind_and_guard_matched_candidate < ' pat > ( & mut self ,
667
713
mut block : BasicBlock ,
668
714
arm_blocks : & mut ArmBlocks ,
669
- candidate : Candidate < ' pat , ' tcx > ,
670
- is_last_arm : bool )
715
+ candidate : Candidate < ' pat , ' tcx > )
671
716
-> Option < BasicBlock > {
672
717
debug ! ( "bind_and_guard_matched_candidate(block={:?}, candidate={:?})" ,
673
718
block, candidate) ;
674
719
675
720
debug_assert ! ( candidate. match_pairs. is_empty( ) ) ;
676
721
677
- self . bind_matched_candidate ( block, candidate. bindings ) ;
678
-
679
722
let arm_block = arm_blocks. blocks [ candidate. arm_index ] ;
723
+ let candidate_source_info = self . source_info ( candidate. span ) ;
724
+
725
+ self . cfg . terminate ( block, candidate_source_info,
726
+ TerminatorKind :: Goto { target : candidate. pre_binding_block } ) ;
727
+
728
+ block = self . cfg . start_new_block ( ) ;
729
+ self . cfg . terminate ( candidate. pre_binding_block , candidate_source_info,
730
+ TerminatorKind :: FalseEdges {
731
+ real_target : block,
732
+ imaginary_targets :
733
+ vec ! [ candidate. next_candidate_pre_binding_block] } ) ;
734
+
735
+ self . bind_matched_candidate ( block, candidate. bindings ) ;
680
736
681
737
if let Some ( guard) = candidate. guard {
682
738
// the block to branch to if the guard fails; if there is no
683
739
// guard, this block is simply unreachable
684
740
let guard = self . hir . mirror ( guard) ;
685
741
let source_info = self . source_info ( guard. span ) ;
686
742
let cond = unpack ! ( block = self . as_local_operand( block, guard) ) ;
687
- let otherwise = self . cfg . start_new_block ( ) ;
743
+
744
+ let false_edge_block = self . cfg . start_new_block ( ) ;
688
745
self . cfg . terminate ( block, source_info,
689
- TerminatorKind :: if_ ( self . hir . tcx ( ) , cond, arm_block, otherwise) ) ;
690
- Some ( otherwise)
691
- } else if !is_last_arm {
692
- // Add always true guard in case of more than one arm
693
- // it creates false edges and allow MIR borrowck detects errors
694
- // FIXME(#45184) -- permit "false edges"
695
- let source_info = self . source_info ( candidate. span ) ;
696
- let true_expr = Expr {
697
- temp_lifetime : None ,
698
- ty : self . hir . tcx ( ) . types . bool ,
699
- span : DUMMY_SP ,
700
- kind : ExprKind :: Literal { literal : self . hir . true_literal ( ) } ,
701
- } ;
702
- let cond = unpack ! ( block = self . as_local_operand( block, true_expr) ) ;
746
+ TerminatorKind :: if_ ( self . hir . tcx ( ) , cond, arm_block,
747
+ false_edge_block) ) ;
748
+
703
749
let otherwise = self . cfg . start_new_block ( ) ;
704
- self . cfg . terminate ( block, source_info,
705
- TerminatorKind :: if_ ( self . hir . tcx ( ) , cond, arm_block, otherwise) ) ;
750
+ self . cfg . terminate ( false_edge_block, source_info,
751
+ TerminatorKind :: FalseEdges {
752
+ real_target : otherwise,
753
+ imaginary_targets :
754
+ vec ! [ candidate. next_candidate_pre_binding_block] } ) ;
706
755
Some ( otherwise)
707
756
} else {
708
- let source_info = self . source_info ( candidate. span ) ;
709
- self . cfg . terminate ( block, source_info,
710
- TerminatorKind :: Goto { target : arm_block } ) ;
757
+ self . cfg . terminate ( block, candidate_source_info,
758
+ TerminatorKind :: Goto { target : arm_block } ) ;
711
759
None
712
760
}
713
761
}
0 commit comments