@@ -99,6 +99,7 @@ pub enum LoanCause {
99
99
ClosureCapture ( Span ) ,
100
100
AddrOf ,
101
101
AutoRef ,
102
+ AutoUnsafe ,
102
103
RefBinding ,
103
104
OverloadedOperator ,
104
105
ClosureInvocation ,
@@ -800,18 +801,8 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
800
801
return_if_err ! ( self . mc. cat_expr_unadjusted( expr) ) ;
801
802
self . delegate_consume ( expr. id , expr. span , cmt_unadjusted) ;
802
803
}
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) ;
815
806
}
816
807
}
817
808
}
@@ -852,39 +843,171 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
852
843
}
853
844
}
854
845
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.
855
887
fn walk_autoref ( & mut self ,
856
888
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
+ } ;
860
905
861
906
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( ) ) ) ;
867
913
868
914
self . delegate . borrow ( expr. id ,
869
915
expr. span ,
870
- cmt_derefd ,
916
+ cmt_base ,
871
917
r,
872
918
ty:: BorrowKind :: from_mutbl ( m) ,
873
919
AutoRef ) ;
874
920
}
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
+
876
960
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" ) ;
882
963
}
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 ) ;
884
983
}
885
984
}
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)
886
997
}
887
998
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
+
888
1011
// When this returns true, it means that the expression *is* a
889
1012
// method-call (i.e. via the operator-overload). This true result
890
1013
// also implies that walk_overloaded_operator already took care of
0 commit comments