@@ -4,9 +4,9 @@ use rustc::hir::def_id::DefId;
44use rustc:: mir:: {
55 AggregateKind , Constant , Field , Local , LocalKind , Location , Operand ,
66 Place , PlaceBase , ProjectionElem , Rvalue , Statement , StatementKind , Static ,
7- StaticKind , TerminatorKind ,
7+ StaticKind , Terminator , TerminatorKind ,
88} ;
9- use rustc:: ty:: { self , DefIdTree , Ty } ;
9+ use rustc:: ty:: { self , DefIdTree , Ty , TyCtxt } ;
1010use rustc:: ty:: layout:: VariantIdx ;
1111use rustc:: ty:: print:: Print ;
1212use rustc_errors:: DiagnosticBuilder ;
@@ -15,6 +15,7 @@ use syntax::symbol::sym;
1515
1616use super :: borrow_set:: BorrowData ;
1717use super :: { MirBorrowckCtxt } ;
18+ use crate :: dataflow:: move_paths:: { InitLocation , LookupResult } ;
1819
1920pub ( super ) struct IncludingDowncast ( pub ( super ) bool ) ;
2021
@@ -401,6 +402,70 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
401402 err. note ( & message) ;
402403 }
403404 }
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+ }
404469}
405470
406471impl < ' cx , ' tcx > MirBorrowckCtxt < ' cx , ' tcx > {
@@ -547,6 +612,90 @@ impl UseSpans {
547612 }
548613}
549614
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+
550699impl < ' cx , ' tcx > MirBorrowckCtxt < ' cx , ' tcx > {
551700 /// Finds the spans associated to a move or copy of move_place at location.
552701 pub ( super ) fn move_spans (
0 commit comments