@@ -67,7 +67,7 @@ use rustc::hir::def_id::DefId;
6767use rustc:: infer:: { Coercion , InferResult , InferOk } ;
6868use rustc:: infer:: type_variable:: TypeVariableOrigin ;
6969use rustc:: traits:: { self , ObligationCause , ObligationCauseCode } ;
70- use rustc:: ty:: adjustment:: { Adjustment , Adjust , AutoBorrow , AutoBorrowMutability } ;
70+ use rustc:: ty:: adjustment:: { Adjustment , Adjust , AllowTwoPhase , AutoBorrow , AutoBorrowMutability } ;
7171use rustc:: ty:: { self , TypeAndMut , Ty , ClosureSubsts } ;
7272use rustc:: ty:: fold:: TypeFoldable ;
7373use rustc:: ty:: error:: TypeError ;
@@ -84,6 +84,13 @@ struct Coerce<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
8484 fcx : & ' a FnCtxt < ' a , ' gcx , ' tcx > ,
8585 cause : ObligationCause < ' tcx > ,
8686 use_lub : bool ,
87+ /// Determines whether or not allow_two_phase_borrow is set on any
88+ /// autoref adjustments we create while coercing. We don't want to
89+ /// allow deref coercions to create two-phase borrows, at least initially,
90+ /// but we do need two-phase borrows for function argument reborrows.
91+ /// See #47489 and #48598
92+ /// See docs on the "AllowTwoPhase" type for a more detailed discussion
93+ allow_two_phase : AllowTwoPhase ,
8794}
8895
8996impl < ' a , ' gcx , ' tcx > Deref for Coerce < ' a , ' gcx , ' tcx > {
@@ -123,10 +130,13 @@ fn success<'tcx>(adj: Vec<Adjustment<'tcx>>,
123130}
124131
125132impl < ' f , ' gcx , ' tcx > Coerce < ' f , ' gcx , ' tcx > {
126- fn new ( fcx : & ' f FnCtxt < ' f , ' gcx , ' tcx > , cause : ObligationCause < ' tcx > ) -> Self {
133+ fn new ( fcx : & ' f FnCtxt < ' f , ' gcx , ' tcx > ,
134+ cause : ObligationCause < ' tcx > ,
135+ allow_two_phase : AllowTwoPhase ) -> Self {
127136 Coerce {
128137 fcx,
129138 cause,
139+ allow_two_phase,
130140 use_lub : false ,
131141 }
132142 }
@@ -423,10 +433,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
423433 let mutbl = match mt_b. mutbl {
424434 hir:: MutImmutable => AutoBorrowMutability :: Immutable ,
425435 hir:: MutMutable => AutoBorrowMutability :: Mutable {
426- // Deref-coercion is a case where we deliberately
427- // disallow two-phase borrows in its initial
428- // deployment; see discussion on PR #47489.
429- allow_two_phase_borrow : false ,
436+ allow_two_phase_borrow : self . allow_two_phase ,
430437 }
431438 } ;
432439 adjustments. push ( Adjustment {
@@ -472,7 +479,10 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
472479 let mutbl = match mt_b. mutbl {
473480 hir:: MutImmutable => AutoBorrowMutability :: Immutable ,
474481 hir:: MutMutable => AutoBorrowMutability :: Mutable {
475- allow_two_phase_borrow : false ,
482+ // We don't allow two-phase borrows here, at least for initial
483+ // implementation. If it happens that this coercion is a function argument,
484+ // the reborrow in coerce_borrowed_ptr will pick it up.
485+ allow_two_phase_borrow : AllowTwoPhase :: No ,
476486 }
477487 } ;
478488 Some ( ( Adjustment {
@@ -750,13 +760,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
750760 pub fn try_coerce ( & self ,
751761 expr : & hir:: Expr ,
752762 expr_ty : Ty < ' tcx > ,
753- target : Ty < ' tcx > )
763+ target : Ty < ' tcx > ,
764+ allow_two_phase : AllowTwoPhase )
754765 -> RelateResult < ' tcx , Ty < ' tcx > > {
755766 let source = self . resolve_type_vars_with_obligations ( expr_ty) ;
756767 debug ! ( "coercion::try({:?}: {:?} -> {:?})" , expr, source, target) ;
757768
758769 let cause = self . cause ( expr. span , ObligationCauseCode :: ExprAssignable ) ;
759- let coerce = Coerce :: new ( self , cause) ;
770+ let coerce = Coerce :: new ( self , cause, allow_two_phase ) ;
760771 let ok = self . commit_if_ok ( |_| coerce. coerce ( source, target) ) ?;
761772
762773 let ( adjustments, _) = self . register_infer_ok_obligations ( ok) ;
@@ -770,7 +781,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
770781 debug ! ( "coercion::can({:?} -> {:?})" , source, target) ;
771782
772783 let cause = self . cause ( syntax_pos:: DUMMY_SP , ObligationCauseCode :: ExprAssignable ) ;
773- let coerce = Coerce :: new ( self , cause) ;
784+ // We don't ever need two-phase here since we throw out the result of the coercion
785+ let coerce = Coerce :: new ( self , cause, AllowTwoPhase :: No ) ;
774786 self . probe ( |_| coerce. coerce ( source, target) ) . is_ok ( )
775787 }
776788
@@ -839,7 +851,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
839851 return Ok ( fn_ptr) ;
840852 }
841853
842- let mut coerce = Coerce :: new ( self , cause. clone ( ) ) ;
854+ // Configure a Coerce instance to compute the LUB.
855+ // We don't allow two-phase borrows on any autorefs this creates since we
856+ // probably aren't processing function arguments here and even if we were,
857+ // they're going to get autorefed again anyway and we can apply 2-phase borrows
858+ // at that time.
859+ let mut coerce = Coerce :: new ( self , cause. clone ( ) , AllowTwoPhase :: No ) ;
843860 coerce. use_lub = true ;
844861
845862 // First try to coerce the new expression to the type of the previous ones,
@@ -1105,7 +1122,8 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
11051122 if self . pushed == 0 {
11061123 // Special-case the first expression we are coercing.
11071124 // To be honest, I'm not entirely sure why we do this.
1108- fcx. try_coerce ( expression, expression_ty, self . expected_ty )
1125+ // We don't allow two-phase borrows, see comment in try_find_coercion_lub for why
1126+ fcx. try_coerce ( expression, expression_ty, self . expected_ty , AllowTwoPhase :: No )
11091127 } else {
11101128 match self . expressions {
11111129 Expressions :: Dynamic ( ref exprs) =>
0 commit comments