@@ -7,6 +7,7 @@ use std::iter;
77use either:: Either ;
88use rustc_abi:: { FIRST_VARIANT , FieldIdx } ;
99use rustc_data_structures:: fx:: FxHashSet ;
10+ use rustc_hir:: Mutability ;
1011use rustc_index:: IndexSlice ;
1112use rustc_middle:: ty:: reborrow:: { self , CoerceSharedFieldPairError } ;
1213use rustc_middle:: ty:: { self , Instance , Ty } ;
@@ -207,28 +208,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
207208 }
208209
209210 Ref ( _, borrow_kind, place) => {
210- let src = self . eval_place ( place) ?;
211- let place = self . force_allocation ( & src) ?;
212- let mut val = ImmTy :: from_immediate ( place. to_ref ( self ) , dest. layout ) ;
213- // A fresh reference was created, make sure it gets retagged with the right mode.
214211 let mode = if borrow_kind. is_two_phase_borrow ( ) {
215212 RetagMode :: TwoPhase
216213 } else {
217214 RetagMode :: Default
218215 } ;
219- M :: with_retag_mode ( self , mode, |ecx| {
220- // If validation is disabled, we still want to do this retag. This is because
221- // const-eval disables validation for performance reasons but wants to retag
222- // shared references. So we add a bit of a hack here to do the retag manually
223- // if the write would not incur validation.
224- if !M :: enforce_validity ( ecx, val. layout ) {
225- if let Some ( new_val) = M :: retag_ptr_value ( ecx, & val, val. layout . ty ) ? {
226- val = new_val;
227- }
228- }
229- // Now do the actual write.
230- ecx. write_immediate ( * val, & dest)
231- } ) ?;
216+ self . write_ref_to_place ( place, & dest, mode) ?;
232217 }
233218
234219 Reborrow ( target_ty, _, place) => {
@@ -286,6 +271,31 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
286271 interp_ok ( ( ) )
287272 }
288273
274+ fn write_ref_to_place (
275+ & mut self ,
276+ source_place : mir:: Place < ' tcx > ,
277+ dest : & PlaceTy < ' tcx , M :: Provenance > ,
278+ mode : RetagMode ,
279+ ) -> InterpResult < ' tcx > {
280+ let src = self . eval_place ( source_place) ?;
281+ let place = self . force_allocation ( & src) ?;
282+ let mut val = ImmTy :: from_immediate ( place. to_ref ( self ) , dest. layout ) ;
283+ // A fresh reference was created, make sure it gets retagged with the right mode.
284+ M :: with_retag_mode ( self , mode, |ecx| {
285+ // If validation is disabled, we still want to do this retag. This is because
286+ // const-eval disables validation for performance reasons but wants to retag
287+ // shared references. So we add a bit of a hack here to do the retag manually
288+ // if the write would not incur validation.
289+ if !M :: enforce_validity ( ecx, val. layout ) {
290+ if let Some ( new_val) = M :: retag_ptr_value ( ecx, & val, val. layout . ty ) ? {
291+ val = new_val;
292+ }
293+ }
294+ // Now do the actual write.
295+ ecx. write_immediate ( * val, dest)
296+ } )
297+ }
298+
289299 fn eval_reborrow_into_place (
290300 & mut self ,
291301 target_ty : Ty < ' tcx > ,
@@ -301,6 +311,27 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
301311 let ( ty:: Adt ( source_def, source_args) , ty:: Adt ( target_def, target_args) ) =
302312 ( source_ty. kind ( ) , target_ty. kind ( ) )
303313 else {
314+ let is_mut_to_shared_ref = if let (
315+ ty:: Ref ( _, source_pointee, Mutability :: Mut ) ,
316+ ty:: Ref ( _, target_pointee, Mutability :: Not ) ,
317+ ) = ( source_ty. kind ( ) , target_ty. kind ( ) )
318+ {
319+ util:: relate_types (
320+ tcx,
321+ self . typing_env ,
322+ ty:: Variance :: Covariant ,
323+ * source_pointee,
324+ * target_pointee,
325+ )
326+ } else {
327+ false
328+ } ;
329+ if is_mut_to_shared_ref {
330+ let deref_source = source_place. project_deeper ( & [ mir:: ProjectionElem :: Deref ] , tcx) ;
331+ self . write_ref_to_place ( deref_source, dest, RetagMode :: Default ) ?;
332+ return interp_ok ( ( ) ) ;
333+ }
334+
304335 let op = self . eval_place_to_op ( source_place, Some ( dest. layout ) ) ?;
305336 self . copy_op ( & op, dest) ?;
306337 return interp_ok ( ( ) ) ;
0 commit comments