@@ -99,6 +99,7 @@ pub enum LoanCause {
9999 ClosureCapture ( Span ) ,
100100 AddrOf ,
101101 AutoRef ,
102+ AutoUnsafe ,
102103 RefBinding ,
103104 OverloadedOperator ,
104105 ClosureInvocation ,
@@ -800,18 +801,8 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
800801 return_if_err ! ( self . mc. cat_expr_unadjusted( expr) ) ;
801802 self . delegate_consume ( expr. id , expr. span , cmt_unadjusted) ;
802803 }
803- ty:: AdjustDerefRef ( ty:: AutoDerefRef {
804- autoref : ref opt_autoref,
805- autoderefs : n
806- } ) => {
807- self . walk_autoderefs ( expr, n) ;
808-
809- match * opt_autoref {
810- None => { }
811- Some ( ref r) => {
812- self . walk_autoref ( expr, r, n) ;
813- }
814- }
804+ ty:: AdjustDerefRef ( ref adj) => {
805+ self . walk_autoderefref ( expr, adj) ;
815806 }
816807 }
817808 }
@@ -852,39 +843,171 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
852843 }
853844 }
854845
846+ fn walk_autoderefref ( & mut self ,
847+ expr : & ast:: Expr ,
848+ adj : & ty:: AutoDerefRef < ' tcx > ) {
849+ debug ! ( "walk_autoderefref expr={} adj={}" ,
850+ expr. repr( self . tcx( ) ) ,
851+ adj. repr( self . tcx( ) ) ) ;
852+
853+ self . walk_autoderefs ( expr, adj. autoderefs ) ;
854+
855+ // Weird hacky special case: AutoUnsizeUniq, which converts
856+ // from a ~T to a ~Trait etc, always comes in a stylized
857+ // fashion. In particular, we want to consume the ~ pointer
858+ // being dereferenced, not the dereferenced content (as the
859+ // content is, at least for upcasts, unsized).
860+ match adj. autoref {
861+ Some ( ty:: AutoUnsizeUniq ( _) ) => {
862+ assert ! ( adj. autoderefs == 1 ,
863+ format!( "Expected exactly 1 deref with Uniq AutoRefs, found: {}" ,
864+ adj. autoderefs) ) ;
865+ let cmt_unadjusted =
866+ return_if_err ! ( self . mc. cat_expr_unadjusted( expr) ) ;
867+ self . delegate_consume ( expr. id , expr. span , cmt_unadjusted) ;
868+ return ;
869+ }
870+ _ => { }
871+ }
872+
873+ let autoref = adj. autoref . as_ref ( ) ;
874+ let cmt_derefd = return_if_err ! (
875+ self . mc. cat_expr_autoderefd( expr, adj. autoderefs) ) ;
876+ self . walk_autoref ( expr, & cmt_derefd, autoref) ;
877+ }
878+
879+ /// Walks the autoref `opt_autoref` applied to the autoderef'd
880+ /// `expr`. `cmt_derefd` is the mem-categorized form of `expr`
881+ /// after all relevant autoderefs have occurred. Because AutoRefs
882+ /// can be recursive, this function is recursive: it first walks
883+ /// deeply all the way down the autoref chain, and then processes
884+ /// the autorefs on the way out. At each point, it returns the
885+ /// `cmt` for the rvalue that will be produced by introduced an
886+ /// autoref.
855887 fn walk_autoref ( & mut self ,
856888 expr : & ast:: Expr ,
857- autoref : & ty:: AutoRef ,
858- n : usize ) {
859- debug ! ( "walk_autoref expr={}" , expr. repr( self . tcx( ) ) ) ;
889+ cmt_derefd : & mc:: cmt < ' tcx > ,
890+ opt_autoref : Option < & ty:: AutoRef < ' tcx > > )
891+ -> mc:: cmt < ' tcx >
892+ {
893+ debug ! ( "walk_autoref(expr.id={} cmt_derefd={} opt_autoref={:?})" ,
894+ expr. id,
895+ cmt_derefd. repr( self . tcx( ) ) ,
896+ opt_autoref) ;
897+
898+ let autoref = match opt_autoref {
899+ Some ( autoref) => autoref,
900+ None => {
901+ // No recursive step here, this is a base case.
902+ return cmt_derefd. clone ( ) ;
903+ }
904+ } ;
860905
861906 match * autoref {
862- ty:: AutoPtr ( r, m, _) => {
863- let cmt_derefd = return_if_err ! (
864- self . mc. cat_expr_autoderefd( expr, n) ) ;
865- debug ! ( "walk_adjustment: cmt_derefd={}" ,
866- cmt_derefd. repr( self . tcx( ) ) ) ;
907+ ty:: AutoPtr ( r, m, ref baseref) => {
908+ let cmt_base = self . walk_autoref_recursively ( expr, cmt_derefd, baseref) ;
909+
910+ debug ! ( "walk_autoref: expr.id={} cmt_base={}" ,
911+ expr. id,
912+ cmt_base. repr( self . tcx( ) ) ) ;
867913
868914 self . delegate . borrow ( expr. id ,
869915 expr. span ,
870- cmt_derefd ,
916+ cmt_base ,
871917 r,
872918 ty:: BorrowKind :: from_mutbl ( m) ,
873919 AutoRef ) ;
874920 }
875- ty:: AutoUnsize ( _) |
921+
922+ ty:: AutoUnsize ( _) => {
923+ // Converting a `[T; N]` to `[T]` or `T` to `Trait`
924+ // isn't really a borrow, move, etc, in and of itself.
925+ // Also, no recursive step here, this is a base case.
926+
927+ // FIXME. It's a bit of a hack to just return `cmt_derefd` here,
928+ // because we are converting from a thin pointer to a fat pointer,
929+ // but we lack a correct "categorization" for this. Perhaps just adding
930+ // `cmt_unsize` is the right fix. I first tried `cmt_rvalue`, as that seemed
931+ // appropriate, but that led to errors in code like this:
932+ //
933+ // fn foo<'a>(&'a self) -> &'a Trait { self }
934+ //
935+ // The reason is simple: the (implicit) conversion from &T to &Self is
936+ // an autoref like:
937+ //
938+ // {autoderefs: 1, autoref: Some(Autoref(Autounsize(..)))}
939+ //
940+ // and if we categorized the autounsize as an rvalue,
941+ // then it would only be valid for the temporary
942+ // scope, which isn't enough to justify the return
943+ // value, which have the lifetime 'a.
944+ //
945+ // So I am now returning the unmodified cmt, which
946+ // while it doesn't feel complete, also doesn't seem
947+ // *wrong* -- after all, what is being borrowed *is*
948+ // `*self`, albeit with an extra vtable. Put another
949+ // way, having Autounsized nestled inside of Autoref
950+ // is somewhat misleading, in that it is not that the
951+ // autounsize products a new value in and of itself,
952+ // but rather that it "modifies" the enclosing
953+ // autoref. So perhaps it is the Adjustment that
954+ // should be changed? Unclear, so I am leaving this
955+ // as a lonely comment to be ignored for all
956+ // time. -nmatsakis
957+ return cmt_derefd. clone ( ) ;
958+ }
959+
876960 ty:: AutoUnsizeUniq ( _) => {
877- assert ! ( n == 1 , format!( "Expected exactly 1 deref with Uniq \
878- AutoRefs, found: {}", n) ) ;
879- let cmt_unadjusted =
880- return_if_err ! ( self . mc. cat_expr_unadjusted( expr) ) ;
881- self . delegate_consume ( expr. id , expr. span , cmt_unadjusted) ;
961+ // these are handled via special case above
962+ self . tcx ( ) . sess . span_bug ( expr. span , "nexpected AutoUnsizeUniq" ) ;
882963 }
883- ty:: AutoUnsafe ( ..) => {
964+
965+ ty:: AutoUnsafe ( m, ref baseref) => {
966+ let cmt_base = self . walk_autoref_recursively ( expr, cmt_derefd, baseref) ;
967+
968+ debug ! ( "walk_autoref: expr.id={} cmt_base={}" ,
969+ expr. id,
970+ cmt_base. repr( self . tcx( ) ) ) ;
971+
972+ // Converting from a &T to *T (or &mut T to *mut T) is
973+ // treated as borrowing it for the enclosing temporary
974+ // scope.
975+ let r = ty:: ReScope ( region:: CodeExtent :: from_node_id ( expr. id ) ) ;
976+
977+ self . delegate . borrow ( expr. id ,
978+ expr. span ,
979+ cmt_base,
980+ r,
981+ ty:: BorrowKind :: from_mutbl ( m) ,
982+ AutoUnsafe ) ;
884983 }
885984 }
985+
986+ // Construct the categorization for the result of the autoref.
987+ // This is always an rvalue, since we are producing a new
988+ // (temporary) indirection.
989+
990+ let adj_ty =
991+ ty:: adjust_ty_for_autoref ( self . tcx ( ) ,
992+ expr. span ,
993+ cmt_derefd. ty ,
994+ opt_autoref) ;
995+
996+ self . mc . cat_rvalue_node ( expr. id , expr. span , adj_ty)
886997 }
887998
999+ fn walk_autoref_recursively ( & mut self ,
1000+ expr : & ast:: Expr ,
1001+ cmt_derefd : & mc:: cmt < ' tcx > ,
1002+ autoref : & Option < Box < ty:: AutoRef < ' tcx > > > )
1003+ -> mc:: cmt < ' tcx >
1004+ {
1005+ // Shuffle from a ref to an optional box to an optional ref.
1006+ let autoref: Option < & ty:: AutoRef < ' tcx > > = autoref. as_ref ( ) . map ( |b| & * * b) ;
1007+ self . walk_autoref ( expr, cmt_derefd, autoref)
1008+ }
1009+
1010+
8881011 // When this returns true, it means that the expression *is* a
8891012 // method-call (i.e. via the operator-overload). This true result
8901013 // also implies that walk_overloaded_operator already took care of
0 commit comments