@@ -14,11 +14,11 @@ use rustc_middle::mir::interpret::{
14
14
sign_extend, truncate, AllocId , FrameInfo , GlobalId , InterpResult , Pointer , Scalar ,
15
15
} ;
16
16
use rustc_middle:: ty:: layout:: { self , TyAndLayout } ;
17
- use rustc_middle:: ty:: query :: TyCtxtAt ;
18
- use rustc_middle :: ty :: subst:: SubstsRef ;
19
- use rustc_middle :: ty :: { self , Ty , TyCtxt , TypeFoldable } ;
17
+ use rustc_middle:: ty:: {
18
+ self , fold :: BottomUpFolder , query :: TyCtxtAt , subst:: SubstsRef , Ty , TyCtxt , TypeFoldable ,
19
+ } ;
20
20
use rustc_span:: source_map:: DUMMY_SP ;
21
- use rustc_target:: abi:: { Abi , Align , HasDataLayout , LayoutOf , Size , TargetDataLayout } ;
21
+ use rustc_target:: abi:: { Align , HasDataLayout , LayoutOf , Size , TargetDataLayout } ;
22
22
23
23
use super :: {
24
24
Immediate , MPlaceTy , Machine , MemPlace , MemPlaceMeta , Memory , OpTy , Operand , Place , PlaceTy ,
@@ -213,30 +213,50 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf for InterpCx<'mir, 'tcx, M> {
213
213
/// Test if it is valid for a MIR assignment to assign `src`-typed place to `dest`-typed value.
214
214
/// This test should be symmetric, as it is primarily about layout compatibility.
215
215
pub ( super ) fn mir_assign_valid_types < ' tcx > (
216
+ tcx : TyCtxt < ' tcx > ,
216
217
src : TyAndLayout < ' tcx > ,
217
218
dest : TyAndLayout < ' tcx > ,
218
219
) -> bool {
219
220
if src. ty == dest. ty {
220
221
// Equal types, all is good.
221
222
return true ;
222
223
}
223
- // Type-changing assignments can happen for (at least) two reasons:
224
- // - `&mut T` -> `&T` gets optimized from a reborrow to a mere assignment.
225
- // - Subtyping is used. While all normal lifetimes are erased, higher-ranked lifetime
226
- // bounds are still around and can lead to type differences.
227
- // There is no good way to check the latter, so we compare layouts instead -- but only
228
- // for values with `Scalar`/`ScalarPair` abi.
229
- // FIXME: Do something more accurate, type-based.
230
- match & src. abi {
231
- Abi :: Scalar ( ..) | Abi :: ScalarPair ( ..) => src. layout == dest. layout ,
232
- _ => false ,
224
+ if src. layout != dest. layout {
225
+ // Layout differs, definitely not equal.
226
+ // We do this here because Miri would *do the wrong thing* if we allowed layout-changing
227
+ // assignments.
228
+ return false ;
233
229
}
230
+
231
+ // Type-changing assignments can happen for (at least) two reasons:
232
+ // 1. `&mut T` -> `&T` gets optimized from a reborrow to a mere assignment.
233
+ // 2. Subtyping is used. While all normal lifetimes are erased, higher-ranked types
234
+ // with their late-bound lifetimes are still around and can lead to type differences.
235
+ // Normalize both of them away.
236
+ let normalize = |ty : Ty < ' tcx > | {
237
+ ty. fold_with ( & mut BottomUpFolder {
238
+ tcx,
239
+ // Normalize all references to immutable.
240
+ ty_op : |ty| match ty. kind {
241
+ ty:: Ref ( _, pointee, _) => tcx. mk_imm_ref ( tcx. lifetimes . re_erased , pointee) ,
242
+ _ => ty,
243
+ } ,
244
+ // We just erase all late-bound lifetimes, but this is not fully correct (FIXME):
245
+ // lifetimes in invariant positions could matter (e.g. through associated types).
246
+ // We rely on the fact that layout was confirmed to be equal above.
247
+ lt_op : |_| tcx. lifetimes . re_erased ,
248
+ // Leave consts unchanged.
249
+ ct_op : |ct| ct,
250
+ } )
251
+ } ;
252
+ normalize ( src. ty ) == normalize ( dest. ty )
234
253
}
235
254
236
255
/// Use the already known layout if given (but sanity check in debug mode),
237
256
/// or compute the layout.
238
257
#[ cfg_attr( not( debug_assertions) , inline( always) ) ]
239
258
pub ( super ) fn from_known_layout < ' tcx > (
259
+ tcx : TyCtxt < ' tcx > ,
240
260
known_layout : Option < TyAndLayout < ' tcx > > ,
241
261
compute : impl FnOnce ( ) -> InterpResult < ' tcx , TyAndLayout < ' tcx > > ,
242
262
) -> InterpResult < ' tcx , TyAndLayout < ' tcx > > {
@@ -246,7 +266,7 @@ pub(super) fn from_known_layout<'tcx>(
246
266
if cfg ! ( debug_assertions) {
247
267
let check_layout = compute ( ) ?;
248
268
assert ! (
249
- mir_assign_valid_types( check_layout, known_layout) ,
269
+ mir_assign_valid_types( tcx , check_layout, known_layout) ,
250
270
"expected type differs from actual type.\n expected: {:?}\n actual: {:?}" ,
251
271
known_layout. ty,
252
272
check_layout. ty,
@@ -424,7 +444,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
424
444
// have to support that case (mostly by skipping all caching).
425
445
match frame. locals . get ( local) . and_then ( |state| state. layout . get ( ) ) {
426
446
None => {
427
- let layout = from_known_layout ( layout, || {
447
+ let layout = from_known_layout ( self . tcx . tcx , layout, || {
428
448
let local_ty = frame. body . local_decls [ local] . ty ;
429
449
let local_ty =
430
450
self . subst_from_frame_and_normalize_erasing_regions ( frame, local_ty) ;
0 commit comments