@@ -84,6 +84,12 @@ struct Coerce<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
84
84
fcx : & ' a FnCtxt < ' a , ' gcx , ' tcx > ,
85
85
cause : ObligationCause < ' tcx > ,
86
86
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
+ allow_two_phase : bool ,
87
93
}
88
94
89
95
impl < ' a , ' gcx , ' tcx > Deref for Coerce < ' a , ' gcx , ' tcx > {
@@ -123,10 +129,13 @@ fn success<'tcx>(adj: Vec<Adjustment<'tcx>>,
123
129
}
124
130
125
131
impl < ' f , ' gcx , ' tcx > Coerce < ' f , ' gcx , ' tcx > {
126
- fn new ( fcx : & ' f FnCtxt < ' f , ' gcx , ' tcx > , cause : ObligationCause < ' tcx > ) -> Self {
132
+ fn new ( fcx : & ' f FnCtxt < ' f , ' gcx , ' tcx > ,
133
+ cause : ObligationCause < ' tcx > ,
134
+ allow_two_phase : bool ) -> Self {
127
135
Coerce {
128
136
fcx,
129
137
cause,
138
+ allow_two_phase,
130
139
use_lub : false ,
131
140
}
132
141
}
@@ -424,10 +433,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
424
433
let mutbl = match mt_b. mutbl {
425
434
hir:: MutImmutable => AutoBorrowMutability :: Immutable ,
426
435
hir:: MutMutable => AutoBorrowMutability :: Mutable {
427
- // Deref-coercion is a case where we deliberately
428
- // disallow two-phase borrows in its initial
429
- // deployment; see discussion on PR #47489.
430
- allow_two_phase_borrow : false ,
436
+ allow_two_phase_borrow : self . allow_two_phase ,
431
437
}
432
438
} ;
433
439
adjustments. push ( Adjustment {
@@ -473,6 +479,9 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
473
479
let mutbl = match mt_b. mutbl {
474
480
hir:: MutImmutable => AutoBorrowMutability :: Immutable ,
475
481
hir:: MutMutable => AutoBorrowMutability :: Mutable {
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.
476
485
allow_two_phase_borrow : false ,
477
486
}
478
487
} ;
@@ -751,13 +760,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
751
760
pub fn try_coerce ( & self ,
752
761
expr : & hir:: Expr ,
753
762
expr_ty : Ty < ' tcx > ,
754
- target : Ty < ' tcx > )
763
+ target : Ty < ' tcx > ,
764
+ allow_two_phase : bool )
755
765
-> RelateResult < ' tcx , Ty < ' tcx > > {
756
766
let source = self . resolve_type_vars_with_obligations ( expr_ty) ;
757
767
debug ! ( "coercion::try({:?}: {:?} -> {:?})" , expr, source, target) ;
758
768
759
769
let cause = self . cause ( expr. span , ObligationCauseCode :: ExprAssignable ) ;
760
- let coerce = Coerce :: new ( self , cause) ;
770
+ let coerce = Coerce :: new ( self , cause, allow_two_phase ) ;
761
771
let ok = self . commit_if_ok ( |_| coerce. coerce ( source, target) ) ?;
762
772
763
773
let ( adjustments, _) = self . register_infer_ok_obligations ( ok) ;
@@ -771,7 +781,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
771
781
debug ! ( "coercion::can({:?} -> {:?})" , source, target) ;
772
782
773
783
let cause = self . cause ( syntax_pos:: DUMMY_SP , ObligationCauseCode :: ExprAssignable ) ;
774
- 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, false ) ;
775
786
self . probe ( |_| coerce. coerce ( source, target) ) . is_ok ( )
776
787
}
777
788
@@ -840,7 +851,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
840
851
return Ok ( fn_ptr) ;
841
852
}
842
853
843
- 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 ( ) , false ) ;
844
860
coerce. use_lub = true ;
845
861
846
862
// First try to coerce the new expression to the type of the previous ones,
@@ -1106,7 +1122,8 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
1106
1122
if self . pushed == 0 {
1107
1123
// Special-case the first expression we are coercing.
1108
1124
// To be honest, I'm not entirely sure why we do this.
1109
- 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 , false )
1110
1127
} else {
1111
1128
match self . expressions {
1112
1129
Expressions :: Dynamic ( ref exprs) =>
0 commit comments