@@ -114,15 +114,10 @@ impl<'a, 'tcx> UnlowerVisitor<'a, 'tcx> {
114
114
}
115
115
116
116
fn operand_desc ( & self , op : & Operand < ' tcx > ) -> MirOriginDesc {
117
- match * op {
118
- mir:: Operand :: Copy ( pl) | mir:: Operand :: Move ( pl) => {
119
- if is_temp_var ( self . mir , pl. as_ref ( ) ) {
120
- MirOriginDesc :: LoadFromTemp
121
- } else {
122
- MirOriginDesc :: Expr
123
- }
124
- }
125
- mir:: Operand :: Constant ( ..) => MirOriginDesc :: Expr ,
117
+ if is_temp_var_operand ( self . mir , op) {
118
+ MirOriginDesc :: LoadFromTemp
119
+ } else {
120
+ MirOriginDesc :: Expr
126
121
}
127
122
}
128
123
@@ -215,20 +210,16 @@ impl<'a, 'tcx> UnlowerVisitor<'a, 'tcx> {
215
210
match ex. kind {
216
211
hir:: ExprKind :: Assign ( pl, rv, _span) => {
217
212
// For `Assign`, we expect the assignment to be the whole thing.
218
- let ( loc, _mir_pl , mir_rv) = match self . get_sole_assign ( & locs) {
213
+ let ( loc, mir_pl , mir_rv) = match self . get_sole_assign ( & locs) {
219
214
Some ( x) => x,
220
215
None => {
221
216
warn ( "expected exactly one StatementKind::Assign" ) ;
222
217
return ;
223
218
}
224
219
} ;
225
- let desc = match mir_rv {
226
- mir:: Rvalue :: Use ( op) => self . operand_desc ( op) ,
227
- _ => MirOriginDesc :: Expr ,
228
- } ;
229
220
self . record ( loc, & [ ] , ex) ;
230
- self . record ( loc, & [ SubLoc :: Dest ] , pl ) ;
231
- self . record_desc ( loc, & [ SubLoc :: Rvalue ] , rv , desc ) ;
221
+ self . visit_expr_place ( pl , loc, vec ! [ SubLoc :: Dest ] , mir_pl , & [ ] ) ;
222
+ self . visit_expr_rvalue ( rv , loc, vec ! [ SubLoc :: Rvalue ] , mir_rv , & [ ] ) ;
232
223
}
233
224
234
225
hir:: ExprKind :: Call ( _, args) | hir:: ExprKind :: MethodCall ( _, args, _) => {
@@ -275,8 +266,9 @@ impl<'a, 'tcx> UnlowerVisitor<'a, 'tcx> {
275
266
276
267
self . record ( loc, & [ SubLoc :: Rvalue ] , ex) ;
277
268
for ( i, ( arg, mir_arg) ) in args. iter ( ) . zip ( mir_args) . enumerate ( ) {
278
- self . record_operand ( loc, & [ SubLoc :: Rvalue , SubLoc :: CallArg ( i) ] , arg, mir_arg) ;
279
- self . visit_expr_operand ( arg, mir_arg, & [ ] ) ;
269
+ let sub_loc = vec ! [ SubLoc :: Rvalue , SubLoc :: CallArg ( i) ] ;
270
+ self . record_operand ( loc, & sub_loc, arg, mir_arg) ;
271
+ self . visit_expr_operand ( arg, loc, sub_loc, mir_arg, & [ ] ) ;
280
272
}
281
273
282
274
if extra_locs. len ( ) > 0 {
@@ -306,8 +298,7 @@ impl<'a, 'tcx> UnlowerVisitor<'a, 'tcx> {
306
298
}
307
299
} ;
308
300
self . record_desc ( cursor. loc , & [ ] , ex, MirOriginDesc :: StoreIntoLocal ) ;
309
- self . peel_adjustments ( ex, & mut cursor) ;
310
- self . record_desc ( cursor. loc , & cursor. sub_loc , ex, MirOriginDesc :: Expr ) ;
301
+ self . walk_expr ( ex, & mut cursor) ;
311
302
self . finish_visit_expr_cursor ( ex, cursor) ;
312
303
}
313
304
}
@@ -436,14 +427,124 @@ impl<'a, 'tcx> UnlowerVisitor<'a, 'tcx> {
436
427
}
437
428
}
438
429
430
+ fn visit_expr_rvalue (
431
+ & mut self ,
432
+ ex : & ' tcx hir:: Expr < ' tcx > ,
433
+ loc : Location ,
434
+ sub_loc : Vec < SubLoc > ,
435
+ rv : & ' a mir:: Rvalue < ' tcx > ,
436
+ extra_locs : & [ Location ] ,
437
+ ) {
438
+ let _g = panic_detail:: set_current_span ( ex. span ) ;
439
+
440
+ // TODO: We do this check early to ensure that the `LoadFromTemp` is emitted with subloc
441
+ // `[Rvalue]` rather than `[Rvalue, RvalueOperand(0)]`, since `mir_op` emits rewrites with
442
+ // just `[Rvalue]`. For `Rvalue::Use`, the rvalue and its operand are basically
443
+ // synonymous, so ideally we would accept both sublocs as well. We should probably add an
444
+ // aliasing system or some kind of cleverness in `distribute` to make both versions work,
445
+ // or else modify the definition of `SubLoc` so there's only one way to express this
446
+ // location.
447
+ if is_temp_var_rvalue ( self . mir , rv) {
448
+ self . record_desc ( loc, & sub_loc, ex, MirOriginDesc :: LoadFromTemp ) ;
449
+ return ;
450
+ }
451
+
452
+ let mut cursor = VisitExprCursor :: new (
453
+ self . mir ,
454
+ ExprMir :: Rvalue ( rv) ,
455
+ extra_locs,
456
+ loc,
457
+ sub_loc. to_owned ( ) ,
458
+ ) ;
459
+ self . walk_expr ( ex, & mut cursor) ;
460
+
461
+ self . finish_visit_expr_cursor ( ex, cursor) ;
462
+ }
463
+
439
464
fn visit_expr_operand (
440
465
& mut self ,
441
466
ex : & ' tcx hir:: Expr < ' tcx > ,
442
- _rv : & ' a mir:: Operand < ' tcx > ,
443
- _extra_locs : & [ Location ] ,
467
+ loc : Location ,
468
+ sub_loc : Vec < SubLoc > ,
469
+ op : & ' a mir:: Operand < ' tcx > ,
470
+ extra_locs : & [ Location ] ,
471
+ ) {
472
+ let _g = panic_detail:: set_current_span ( ex. span ) ;
473
+
474
+ if is_temp_var_operand ( self . mir , op) {
475
+ self . record_desc ( loc, & sub_loc, ex, MirOriginDesc :: LoadFromTemp ) ;
476
+ return ;
477
+ }
478
+
479
+ let mut cursor = VisitExprCursor :: new (
480
+ self . mir ,
481
+ ExprMir :: Operand ( op) ,
482
+ extra_locs,
483
+ loc,
484
+ sub_loc. to_owned ( ) ,
485
+ ) ;
486
+ self . walk_expr ( ex, & mut cursor) ;
487
+
488
+ self . finish_visit_expr_cursor ( ex, cursor) ;
489
+ }
490
+
491
+ fn visit_expr_place (
492
+ & mut self ,
493
+ ex : & ' tcx hir:: Expr < ' tcx > ,
494
+ loc : Location ,
495
+ sub_loc : Vec < SubLoc > ,
496
+ pl : mir:: Place < ' tcx > ,
497
+ extra_locs : & [ Location ] ,
444
498
) {
445
499
let _g = panic_detail:: set_current_span ( ex. span ) ;
446
- // TODO: handle adjustments, overloaded operators, etc
500
+
501
+ let mut cursor = VisitExprCursor :: new (
502
+ self . mir ,
503
+ ExprMir :: Place ( pl. as_ref ( ) ) ,
504
+ extra_locs,
505
+ loc,
506
+ sub_loc. to_owned ( ) ,
507
+ ) ;
508
+ self . walk_expr ( ex, & mut cursor) ;
509
+
510
+ self . finish_visit_expr_cursor ( ex, cursor) ;
511
+ }
512
+
513
+ fn walk_expr ( & mut self , ex : & ' tcx hir:: Expr < ' tcx > , cursor : & mut VisitExprCursor < ' a , ' _ , ' tcx > ) {
514
+ let mut ex = ex;
515
+ loop {
516
+ self . peel_adjustments ( ex, cursor) ;
517
+ if cursor. is_temp_var ( ) {
518
+ self . record_desc ( cursor. loc , & cursor. sub_loc , ex, MirOriginDesc :: LoadFromTemp ) ;
519
+ break ;
520
+ } else {
521
+ self . record_desc ( cursor. loc , & cursor. sub_loc , ex, MirOriginDesc :: Expr ) ;
522
+ }
523
+
524
+ match ex. kind {
525
+ hir:: ExprKind :: Unary ( hir:: UnOp :: Deref , ptr_ex) => {
526
+ if let Some ( ( ) ) = cursor. peel_deref ( ) {
527
+ ex = ptr_ex;
528
+ continue ;
529
+ }
530
+ }
531
+ hir:: ExprKind :: Field ( base_ex, _field_ident) => {
532
+ if let Some ( ( ) ) = cursor. peel_field ( ) {
533
+ ex = base_ex;
534
+ continue ;
535
+ }
536
+ }
537
+ hir:: ExprKind :: Index ( arr_ex, _idx_ex) => {
538
+ if let Some ( ( ) ) = cursor. peel_index ( ) {
539
+ ex = arr_ex;
540
+ continue ;
541
+ }
542
+ }
543
+ _ => { }
544
+ }
545
+ // Keep looping only in cases that we specifically recognize.
546
+ break ;
547
+ }
447
548
}
448
549
}
449
550
@@ -526,6 +627,16 @@ impl<'a, 'b, 'tcx> VisitExprCursor<'a, 'b, 'tcx> {
526
627
}
527
628
}
528
629
630
+ /// Check whether the current MIR is a temporary.
631
+ pub fn is_temp_var ( & self ) -> bool {
632
+ match self . cur {
633
+ ExprMir :: Rvalue ( rv) => is_temp_var_rvalue ( self . mir , rv) ,
634
+ ExprMir :: Operand ( op) => is_temp_var_operand ( self . mir , op) ,
635
+ ExprMir :: Place ( pl) => is_temp_var ( self . mir , pl) ,
636
+ ExprMir :: Call ( _) => false ,
637
+ }
638
+ }
639
+
529
640
/// If the current MIR is a temporary, and the previous `Location` is an assignment to
530
641
/// that temporary, peel it off, leaving the temporary's initializer as the current
531
642
/// `Rvalue`. This also adds `LoadFromTemp` and `StoreIntoLocal` entries in `self.temp_info`
@@ -673,12 +784,37 @@ impl<'a, 'b, 'tcx> VisitExprCursor<'a, 'b, 'tcx> {
673
784
if let Some ( ( & outer_proj, remaining_proj) ) = pl. projection . split_last ( ) {
674
785
if matches ! ( outer_proj, mir:: PlaceElem :: Deref ) {
675
786
pl. projection = remaining_proj;
676
- // Number of derefs, not counting the outermost one we just peeled off.
677
- let num_inner_derefs = remaining_proj
678
- . iter ( )
679
- . filter ( |p| matches ! ( p, mir:: PlaceElem :: Deref ) )
680
- . count ( ) ;
681
- self . sub_loc . push ( SubLoc :: PlacePointer ( num_inner_derefs) ) ;
787
+ self . sub_loc . push ( SubLoc :: PlaceDerefPointer ) ;
788
+ return Some ( ( ) ) ;
789
+ }
790
+ }
791
+ self . peel_temp ( ) ?;
792
+ }
793
+ }
794
+
795
+ /// If the current MIR is a `Place` ending with a `Field` projection, peel off the `Field`.
796
+ pub fn peel_field ( & mut self ) -> Option < ( ) > {
797
+ loop {
798
+ let pl = self . require_place_mut ( ) ?;
799
+ if let Some ( ( & outer_proj, remaining_proj) ) = pl. projection . split_last ( ) {
800
+ if matches ! ( outer_proj, mir:: PlaceElem :: Field ( _idx, _ty) ) {
801
+ pl. projection = remaining_proj;
802
+ self . sub_loc . push ( SubLoc :: PlaceFieldBase ) ;
803
+ return Some ( ( ) ) ;
804
+ }
805
+ }
806
+ self . peel_temp ( ) ?;
807
+ }
808
+ }
809
+
810
+ /// If the current MIR is a `Place` ending with an `Index` projection, peel off the `Index`.
811
+ pub fn peel_index ( & mut self ) -> Option < ( ) > {
812
+ loop {
813
+ let pl = self . require_place_mut ( ) ?;
814
+ if let Some ( ( & outer_proj, remaining_proj) ) = pl. projection . split_last ( ) {
815
+ if matches ! ( outer_proj, mir:: PlaceElem :: Index ( _) ) {
816
+ pl. projection = remaining_proj;
817
+ self . sub_loc . push ( SubLoc :: PlaceIndexArray ) ;
682
818
return Some ( ( ) ) ;
683
819
}
684
820
}
@@ -712,25 +848,77 @@ fn is_temp_var(mir: &Body, pl: mir::PlaceRef) -> bool {
712
848
pl. projection . len ( ) == 0 && mir. local_kind ( pl. local ) == mir:: LocalKind :: Temp
713
849
}
714
850
851
+ fn is_temp_var_operand ( mir : & Body , op : & mir:: Operand ) -> bool {
852
+ match get_operand_place ( op) {
853
+ Some ( pl) => is_temp_var ( mir, pl. as_ref ( ) ) ,
854
+ None => false ,
855
+ }
856
+ }
857
+
858
+ fn is_temp_var_rvalue ( mir : & Body , rv : & mir:: Rvalue ) -> bool {
859
+ match get_rvalue_operand ( rv) {
860
+ Some ( op) => is_temp_var_operand ( mir, op) ,
861
+ None => false ,
862
+ }
863
+ }
864
+
865
+ fn get_rvalue_operand < ' a , ' tcx > ( rv : & ' a mir:: Rvalue < ' tcx > ) -> Option < & ' a mir:: Operand < ' tcx > > {
866
+ match * rv {
867
+ mir:: Rvalue :: Use ( ref op) => Some ( op) ,
868
+ _ => None ,
869
+ }
870
+ }
871
+
872
+ fn get_operand_place < ' tcx > ( op : & mir:: Operand < ' tcx > ) -> Option < mir:: Place < ' tcx > > {
873
+ match * op {
874
+ mir:: Operand :: Copy ( pl) | mir:: Operand :: Move ( pl) => Some ( pl) ,
875
+ _ => None ,
876
+ }
877
+ }
878
+
879
+ /// Indicate whether a given MIR statement should be considered when building the unlowering map.
880
+ fn filter_stmt ( stmt : & mir:: Statement ) -> bool {
881
+ match stmt. kind {
882
+ // Ignore `AscribeUserType` annotations. These appear in the middle of some expressions.
883
+ // It's easier to ignore them all at this level rather than try to handle them in all the
884
+ // places they might appear.
885
+ mir:: StatementKind :: AscribeUserType ( ..) => false ,
886
+ _ => true ,
887
+ }
888
+ }
889
+
890
+ /// Indicate whether a given MIR terminator should be considered when building the unlowering map.
891
+ fn filter_term ( term : & mir:: Terminator ) -> bool {
892
+ match term. kind {
893
+ _ => true ,
894
+ }
895
+ }
896
+
715
897
fn build_span_index ( mir : & Body < ' _ > ) -> SpanIndex < Location > {
716
- eprintln ! ( "building span index for {:?}:" , mir. source) ;
898
+ debug ! ( "building span index for {:?}:" , mir. source) ;
717
899
let mut span_index_items = Vec :: new ( ) ;
718
900
for ( bb, bb_data) in mir. basic_blocks ( ) . iter_enumerated ( ) {
719
901
for ( i, stmt) in bb_data. statements . iter ( ) . enumerate ( ) {
902
+ if !filter_stmt ( stmt) {
903
+ continue ;
904
+ }
720
905
let loc = Location {
721
906
block : bb,
722
907
statement_index : i,
723
908
} ;
724
- eprintln ! ( " {:?}: {:?}" , loc, stmt. source_info. span) ;
909
+ debug ! ( " {:?}: {:?}" , loc, stmt. source_info. span) ;
725
910
span_index_items. push ( ( stmt. source_info . span , loc) ) ;
726
911
}
727
912
728
- let loc = Location {
729
- block : bb,
730
- statement_index : bb_data. statements . len ( ) ,
731
- } ;
732
- eprintln ! ( " {:?}: {:?}" , loc, bb_data. terminator( ) . source_info. span) ;
733
- span_index_items. push ( ( bb_data. terminator ( ) . source_info . span , loc) ) ;
913
+ let term = bb_data. terminator ( ) ;
914
+ if filter_term ( term) {
915
+ let loc = Location {
916
+ block : bb,
917
+ statement_index : bb_data. statements . len ( ) ,
918
+ } ;
919
+ debug ! ( " {:?}: {:?}" , loc, term. source_info. span) ;
920
+ span_index_items. push ( ( term. source_info . span , loc) ) ;
921
+ }
734
922
}
735
923
736
924
SpanIndex :: new ( span_index_items)
0 commit comments