@@ -4,9 +4,9 @@ use rustc::hir::def_id::DefId;
4
4
use rustc:: mir:: {
5
5
AggregateKind , Constant , Field , Local , LocalKind , Location , Operand ,
6
6
Place , PlaceBase , ProjectionElem , Rvalue , Statement , StatementKind , Static ,
7
- StaticKind , TerminatorKind ,
7
+ StaticKind , Terminator , TerminatorKind ,
8
8
} ;
9
- use rustc:: ty:: { self , DefIdTree , Ty } ;
9
+ use rustc:: ty:: { self , DefIdTree , Ty , TyCtxt } ;
10
10
use rustc:: ty:: layout:: VariantIdx ;
11
11
use rustc:: ty:: print:: Print ;
12
12
use rustc_errors:: DiagnosticBuilder ;
@@ -15,6 +15,7 @@ use syntax::symbol::sym;
15
15
16
16
use super :: borrow_set:: BorrowData ;
17
17
use super :: { MirBorrowckCtxt } ;
18
+ use crate :: dataflow:: move_paths:: { InitLocation , LookupResult } ;
18
19
19
20
pub ( super ) struct IncludingDowncast ( pub ( super ) bool ) ;
20
21
@@ -401,6 +402,70 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
401
402
err. note ( & message) ;
402
403
}
403
404
}
405
+
406
+ pub ( super ) fn borrowed_content_source (
407
+ & self ,
408
+ deref_base : & Place < ' tcx > ,
409
+ ) -> BorrowedContentSource < ' tcx > {
410
+ let tcx = self . infcx . tcx ;
411
+
412
+ // Look up the provided place and work out the move path index for it,
413
+ // we'll use this to check whether it was originally from an overloaded
414
+ // operator.
415
+ match self . move_data . rev_lookup . find ( deref_base) {
416
+ LookupResult :: Exact ( mpi) | LookupResult :: Parent ( Some ( mpi) ) => {
417
+ debug ! ( "borrowed_content_source: mpi={:?}" , mpi) ;
418
+
419
+ for i in & self . move_data . init_path_map [ mpi] {
420
+ let init = & self . move_data . inits [ * i] ;
421
+ debug ! ( "borrowed_content_source: init={:?}" , init) ;
422
+ // We're only interested in statements that initialized a value, not the
423
+ // initializations from arguments.
424
+ let loc = match init. location {
425
+ InitLocation :: Statement ( stmt) => stmt,
426
+ _ => continue ,
427
+ } ;
428
+
429
+ let bbd = & self . body [ loc. block ] ;
430
+ let is_terminator = bbd. statements . len ( ) == loc. statement_index ;
431
+ debug ! (
432
+ "borrowed_content_source: loc={:?} is_terminator={:?}" ,
433
+ loc,
434
+ is_terminator,
435
+ ) ;
436
+ if !is_terminator {
437
+ continue ;
438
+ } else if let Some ( Terminator {
439
+ kind : TerminatorKind :: Call {
440
+ ref func,
441
+ from_hir_call : false ,
442
+ ..
443
+ } ,
444
+ ..
445
+ } ) = bbd. terminator {
446
+ if let Some ( source)
447
+ = BorrowedContentSource :: from_call ( func. ty ( self . body , tcx) , tcx)
448
+ {
449
+ return source;
450
+ }
451
+ }
452
+ }
453
+ }
454
+ // Base is a `static` so won't be from an overloaded operator
455
+ _ => ( ) ,
456
+ } ;
457
+
458
+ // If we didn't find an overloaded deref or index, then assume it's a
459
+ // built in deref and check the type of the base.
460
+ let base_ty = deref_base. ty ( self . body , tcx) . ty ;
461
+ if base_ty. is_unsafe_ptr ( ) {
462
+ BorrowedContentSource :: DerefRawPointer
463
+ } else if base_ty. is_mutable_pointer ( ) {
464
+ BorrowedContentSource :: DerefMutableRef
465
+ } else {
466
+ BorrowedContentSource :: DerefSharedRef
467
+ }
468
+ }
404
469
}
405
470
406
471
impl < ' cx , ' tcx > MirBorrowckCtxt < ' cx , ' tcx > {
@@ -547,6 +612,90 @@ impl UseSpans {
547
612
}
548
613
}
549
614
615
+ pub ( super ) enum BorrowedContentSource < ' tcx > {
616
+ DerefRawPointer ,
617
+ DerefMutableRef ,
618
+ DerefSharedRef ,
619
+ OverloadedDeref ( Ty < ' tcx > ) ,
620
+ OverloadedIndex ( Ty < ' tcx > ) ,
621
+ }
622
+
623
+ impl BorrowedContentSource < ' tcx > {
624
+ pub ( super ) fn describe_for_unnamed_place ( & self ) -> String {
625
+ match * self {
626
+ BorrowedContentSource :: DerefRawPointer => format ! ( "a raw pointer" ) ,
627
+ BorrowedContentSource :: DerefSharedRef => format ! ( "a shared reference" ) ,
628
+ BorrowedContentSource :: DerefMutableRef => {
629
+ format ! ( "a mutable reference" )
630
+ }
631
+ BorrowedContentSource :: OverloadedDeref ( ty) => {
632
+ if ty. is_rc ( ) {
633
+ format ! ( "an `Rc`" )
634
+ } else if ty. is_arc ( ) {
635
+ format ! ( "an `Arc`" )
636
+ } else {
637
+ format ! ( "dereference of `{}`" , ty)
638
+ }
639
+ }
640
+ BorrowedContentSource :: OverloadedIndex ( ty) => format ! ( "index of `{}`" , ty) ,
641
+ }
642
+ }
643
+
644
+ pub ( super ) fn describe_for_named_place ( & self ) -> Option < & ' static str > {
645
+ match * self {
646
+ BorrowedContentSource :: DerefRawPointer => Some ( "raw pointer" ) ,
647
+ BorrowedContentSource :: DerefSharedRef => Some ( "shared reference" ) ,
648
+ BorrowedContentSource :: DerefMutableRef => Some ( "mutable reference" ) ,
649
+ // Overloaded deref and index operators should be evaluated into a
650
+ // temporary. So we don't need a description here.
651
+ BorrowedContentSource :: OverloadedDeref ( _)
652
+ | BorrowedContentSource :: OverloadedIndex ( _) => None
653
+ }
654
+ }
655
+
656
+ pub ( super ) fn describe_for_immutable_place ( & self ) -> String {
657
+ match * self {
658
+ BorrowedContentSource :: DerefRawPointer => format ! ( "a `*const` pointer" ) ,
659
+ BorrowedContentSource :: DerefSharedRef => format ! ( "a `&` reference" ) ,
660
+ BorrowedContentSource :: DerefMutableRef => {
661
+ bug ! ( "describe_for_immutable_place: DerefMutableRef isn't immutable" )
662
+ } ,
663
+ BorrowedContentSource :: OverloadedDeref ( ty) => {
664
+ if ty. is_rc ( ) {
665
+ format ! ( "an `Rc`" )
666
+ } else if ty. is_arc ( ) {
667
+ format ! ( "an `Arc`" )
668
+ } else {
669
+ format ! ( "a dereference of `{}`" , ty)
670
+ }
671
+ }
672
+ BorrowedContentSource :: OverloadedIndex ( ty) => format ! ( "an index of `{}`" , ty) ,
673
+ }
674
+ }
675
+
676
+ fn from_call ( func : Ty < ' tcx > , tcx : TyCtxt < ' tcx > ) -> Option < Self > {
677
+ match func. sty {
678
+ ty:: FnDef ( def_id, substs) => {
679
+ let trait_id = tcx. trait_of_item ( def_id) ?;
680
+
681
+ let lang_items = tcx. lang_items ( ) ;
682
+ if Some ( trait_id) == lang_items. deref_trait ( )
683
+ || Some ( trait_id) == lang_items. deref_mut_trait ( )
684
+ {
685
+ Some ( BorrowedContentSource :: OverloadedDeref ( substs. type_at ( 0 ) ) )
686
+ } else if Some ( trait_id) == lang_items. index_trait ( )
687
+ || Some ( trait_id) == lang_items. index_mut_trait ( )
688
+ {
689
+ Some ( BorrowedContentSource :: OverloadedIndex ( substs. type_at ( 0 ) ) )
690
+ } else {
691
+ None
692
+ }
693
+ }
694
+ _ => None ,
695
+ }
696
+ }
697
+ }
698
+
550
699
impl < ' cx , ' tcx > MirBorrowckCtxt < ' cx , ' tcx > {
551
700
/// Finds the spans associated to a move or copy of move_place at location.
552
701
pub ( super ) fn move_spans (
0 commit comments