@@ -15,7 +15,7 @@ use rustc_middle::mir::interpret::{
15
15
} ;
16
16
use rustc_middle:: ty:: layout:: { self , TyAndLayout } ;
17
17
use rustc_middle:: ty:: {
18
- self , fold :: BottomUpFolder , query:: TyCtxtAt , subst:: SubstsRef , Ty , TyCtxt , TypeFoldable ,
18
+ self , query:: TyCtxtAt , subst:: SubstsRef , ParamEnv , Ty , TyCtxt , TypeFoldable ,
19
19
} ;
20
20
use rustc_span:: { source_map:: DUMMY_SP , Span } ;
21
21
use rustc_target:: abi:: { Align , HasDataLayout , LayoutOf , Size , TargetDataLayout } ;
@@ -24,6 +24,7 @@ use super::{
24
24
Immediate , MPlaceTy , Machine , MemPlace , MemPlaceMeta , Memory , OpTy , Operand , Place , PlaceTy ,
25
25
ScalarMaybeUninit , StackPopJump ,
26
26
} ;
27
+ use crate :: transform:: validate:: equal_up_to_regions;
27
28
use crate :: util:: storage:: AlwaysLiveLocals ;
28
29
29
30
pub struct InterpCx < ' mir , ' tcx , M : Machine < ' mir , ' tcx > > {
@@ -220,49 +221,35 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> LayoutOf for InterpCx<'mir, 'tcx,
220
221
/// This test should be symmetric, as it is primarily about layout compatibility.
221
222
pub ( super ) fn mir_assign_valid_types < ' tcx > (
222
223
tcx : TyCtxt < ' tcx > ,
224
+ param_env : ParamEnv < ' tcx > ,
223
225
src : TyAndLayout < ' tcx > ,
224
226
dest : TyAndLayout < ' tcx > ,
225
227
) -> bool {
226
- if src. ty == dest. ty {
227
- // Equal types, all is good.
228
- return true ;
229
- }
230
- if src. layout != dest. layout {
231
- // Layout differs, definitely not equal.
232
- // We do this here because Miri would *do the wrong thing* if we allowed layout-changing
233
- // assignments.
234
- return false ;
235
- }
236
-
237
- // Type-changing assignments can happen for (at least) two reasons:
238
- // 1. `&mut T` -> `&T` gets optimized from a reborrow to a mere assignment.
239
- // 2. Subtyping is used. While all normal lifetimes are erased, higher-ranked types
240
- // with their late-bound lifetimes are still around and can lead to type differences.
241
- // Normalize both of them away.
242
- let normalize = |ty : Ty < ' tcx > | {
243
- ty. fold_with ( & mut BottomUpFolder {
244
- tcx,
245
- // Normalize all references to immutable.
246
- ty_op : |ty| match ty. kind {
247
- ty:: Ref ( _, pointee, _) => tcx. mk_imm_ref ( tcx. lifetimes . re_erased , pointee) ,
248
- _ => ty,
249
- } ,
250
- // We just erase all late-bound lifetimes, but this is not fully correct (FIXME):
251
- // lifetimes in invariant positions could matter (e.g. through associated types).
252
- // We rely on the fact that layout was confirmed to be equal above.
253
- lt_op : |_| tcx. lifetimes . re_erased ,
254
- // Leave consts unchanged.
255
- ct_op : |ct| ct,
256
- } )
257
- } ;
258
- normalize ( src. ty ) == normalize ( dest. ty )
228
+ // Type-changing assignments can happen when subtyping is used. While
229
+ // all normal lifetimes are erased, higher-ranked types with their
230
+ // late-bound lifetimes are still around and can lead to type
231
+ // differences. So we compare ignoring lifetimes.
232
+ if equal_up_to_regions ( tcx, param_env, src. ty , dest. ty ) {
233
+ // Make sure the layout is equal, too -- just to be safe. Miri really
234
+ // needs layout equality. For performance reason we skip this check when
235
+ // the types are equal. Equal types *can* have different layouts when
236
+ // enum downcast is involved (as enum variants carry the type of the
237
+ // enum), but those should never occur in assignments.
238
+ if cfg ! ( debug_assertions) || src. ty != dest. ty {
239
+ assert_eq ! ( src. layout, dest. layout) ;
240
+ }
241
+ true
242
+ } else {
243
+ false
244
+ }
259
245
}
260
246
261
247
/// Use the already known layout if given (but sanity check in debug mode),
262
248
/// or compute the layout.
263
249
#[ cfg_attr( not( debug_assertions) , inline( always) ) ]
264
250
pub ( super ) fn from_known_layout < ' tcx > (
265
251
tcx : TyCtxtAt < ' tcx > ,
252
+ param_env : ParamEnv < ' tcx > ,
266
253
known_layout : Option < TyAndLayout < ' tcx > > ,
267
254
compute : impl FnOnce ( ) -> InterpResult < ' tcx , TyAndLayout < ' tcx > > ,
268
255
) -> InterpResult < ' tcx , TyAndLayout < ' tcx > > {
@@ -271,7 +258,7 @@ pub(super) fn from_known_layout<'tcx>(
271
258
Some ( known_layout) => {
272
259
if cfg ! ( debug_assertions) {
273
260
let check_layout = compute ( ) ?;
274
- if !mir_assign_valid_types ( tcx. tcx , check_layout, known_layout) {
261
+ if !mir_assign_valid_types ( tcx. tcx , param_env , check_layout, known_layout) {
275
262
span_bug ! (
276
263
tcx. span,
277
264
"expected type differs from actual type.\n expected: {:?}\n actual: {:?}" ,
@@ -475,7 +462,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
475
462
// have to support that case (mostly by skipping all caching).
476
463
match frame. locals . get ( local) . and_then ( |state| state. layout . get ( ) ) {
477
464
None => {
478
- let layout = from_known_layout ( self . tcx , layout, || {
465
+ let layout = from_known_layout ( self . tcx , self . param_env , layout, || {
479
466
let local_ty = frame. body . local_decls [ local] . ty ;
480
467
let local_ty =
481
468
self . subst_from_frame_and_normalize_erasing_regions ( frame, local_ty) ;
0 commit comments