@@ -18,7 +18,7 @@ use rustc_middle::ty::query::TyCtxtAt;
18
18
use rustc_middle:: ty:: subst:: SubstsRef ;
19
19
use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeFoldable } ;
20
20
use rustc_span:: source_map:: DUMMY_SP ;
21
- use rustc_target:: abi:: { Align , HasDataLayout , LayoutOf , Size , TargetDataLayout } ;
21
+ use rustc_target:: abi:: { Abi , Align , HasDataLayout , LayoutOf , Size , TargetDataLayout } ;
22
22
23
23
use super :: {
24
24
Immediate , MPlaceTy , Machine , MemPlace , MemPlaceMeta , Memory , OpTy , Operand , Place , PlaceTy ,
@@ -210,6 +210,53 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf for InterpCx<'mir, 'tcx, M> {
210
210
}
211
211
}
212
212
213
+ /// Test if it is valid for a MIR assignment to assign `src`-typed place to `dest`-typed value.
214
+ /// This test should be symmetric, as it is primarily about layout compatibility.
215
+ pub ( super ) fn mir_assign_valid_types < ' tcx > (
216
+ src : TyAndLayout < ' tcx > ,
217
+ dest : TyAndLayout < ' tcx > ,
218
+ ) -> bool {
219
+ if src. ty == dest. ty {
220
+ // Equal types, all is good.
221
+ return true ;
222
+ }
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 ,
233
+ }
234
+ }
235
+
236
+ /// Use the already known layout if given (but sanity check in debug mode),
237
+ /// or compute the layout.
238
+ #[ cfg_attr( not( debug_assertions) , inline( always) ) ]
239
+ pub ( super ) fn from_known_layout < ' tcx > (
240
+ known_layout : Option < TyAndLayout < ' tcx > > ,
241
+ compute : impl FnOnce ( ) -> InterpResult < ' tcx , TyAndLayout < ' tcx > > ,
242
+ ) -> InterpResult < ' tcx , TyAndLayout < ' tcx > > {
243
+ match known_layout {
244
+ None => compute ( ) ,
245
+ Some ( known_layout) => {
246
+ if cfg ! ( debug_assertions) {
247
+ let check_layout = compute ( ) ?;
248
+ assert ! (
249
+ mir_assign_valid_types( check_layout, known_layout) ,
250
+ "expected type differs from actual type.\n expected: {:?}\n actual: {:?}" ,
251
+ known_layout. ty,
252
+ check_layout. ty,
253
+ ) ;
254
+ }
255
+ Ok ( known_layout)
256
+ }
257
+ }
258
+ }
259
+
213
260
impl < ' mir , ' tcx , M : Machine < ' mir , ' tcx > > InterpCx < ' mir , ' tcx , M > {
214
261
pub fn new (
215
262
tcx : TyCtxtAt < ' tcx > ,
@@ -377,7 +424,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
377
424
// have to support that case (mostly by skipping all caching).
378
425
match frame. locals . get ( local) . and_then ( |state| state. layout . get ( ) ) {
379
426
None => {
380
- let layout = crate :: interpret :: operand :: from_known_layout ( layout, || {
427
+ let layout = from_known_layout ( layout, || {
381
428
let local_ty = frame. body . local_decls [ local] . ty ;
382
429
let local_ty =
383
430
self . subst_from_frame_and_normalize_erasing_regions ( frame, local_ty) ;
0 commit comments