@@ -67,7 +67,7 @@ use rustc::hir::def_id::DefId;
67
67
use rustc:: infer:: { Coercion , InferResult , InferOk } ;
68
68
use rustc:: infer:: type_variable:: TypeVariableOrigin ;
69
69
use rustc:: traits:: { self , ObligationCause , ObligationCauseCode } ;
70
- use rustc:: ty:: adjustment:: { Adjustment , Adjust , AutoBorrow , AutoBorrowMutability } ;
70
+ use rustc:: ty:: adjustment:: { Adjustment , Adjust , AllowTwoPhase , AutoBorrow , AutoBorrowMutability } ;
71
71
use rustc:: ty:: { self , TypeAndMut , Ty , ClosureSubsts } ;
72
72
use rustc:: ty:: fold:: TypeFoldable ;
73
73
use rustc:: ty:: error:: TypeError ;
@@ -84,6 +84,13 @@ 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
+ /// See docs on the "AllowTwoPhase" type for a more detailed discussion
93
+ allow_two_phase : AllowTwoPhase ,
87
94
}
88
95
89
96
impl < ' a , ' gcx , ' tcx > Deref for Coerce < ' a , ' gcx , ' tcx > {
@@ -123,10 +130,13 @@ fn success<'tcx>(adj: Vec<Adjustment<'tcx>>,
123
130
}
124
131
125
132
impl < ' 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 {
127
136
Coerce {
128
137
fcx,
129
138
cause,
139
+ allow_two_phase,
130
140
use_lub : false ,
131
141
}
132
142
}
@@ -423,10 +433,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
423
433
let mutbl = match mt_b. mutbl {
424
434
hir:: MutImmutable => AutoBorrowMutability :: Immutable ,
425
435
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 ,
430
437
}
431
438
} ;
432
439
adjustments. push ( Adjustment {
@@ -472,7 +479,10 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
472
479
let mutbl = match mt_b. mutbl {
473
480
hir:: MutImmutable => AutoBorrowMutability :: Immutable ,
474
481
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 ,
476
486
}
477
487
} ;
478
488
Some ( ( Adjustment {
@@ -750,13 +760,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
750
760
pub fn try_coerce ( & self ,
751
761
expr : & hir:: Expr ,
752
762
expr_ty : Ty < ' tcx > ,
753
- target : Ty < ' tcx > )
763
+ target : Ty < ' tcx > ,
764
+ allow_two_phase : AllowTwoPhase )
754
765
-> RelateResult < ' tcx , Ty < ' tcx > > {
755
766
let source = self . resolve_type_vars_with_obligations ( expr_ty) ;
756
767
debug ! ( "coercion::try({:?}: {:?} -> {:?})" , expr, source, target) ;
757
768
758
769
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 ) ;
760
771
let ok = self . commit_if_ok ( |_| coerce. coerce ( source, target) ) ?;
761
772
762
773
let ( adjustments, _) = self . register_infer_ok_obligations ( ok) ;
@@ -770,7 +781,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
770
781
debug ! ( "coercion::can({:?} -> {:?})" , source, target) ;
771
782
772
783
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 ) ;
774
786
self . probe ( |_| coerce. coerce ( source, target) ) . is_ok ( )
775
787
}
776
788
@@ -839,7 +851,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
839
851
return Ok ( fn_ptr) ;
840
852
}
841
853
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 ) ;
843
860
coerce. use_lub = true ;
844
861
845
862
// 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>
1105
1122
if self . pushed == 0 {
1106
1123
// Special-case the first expression we are coercing.
1107
1124
// 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 )
1109
1127
} else {
1110
1128
match self . expressions {
1111
1129
Expressions :: Dynamic ( ref exprs) =>
0 commit comments