@@ -9,7 +9,7 @@ use rustc_hir::def::Namespace;
9
9
use rustc_macros:: HashStable ;
10
10
use rustc_middle:: ty:: layout:: { LayoutOf , PrimitiveExt , TyAndLayout } ;
11
11
use rustc_middle:: ty:: print:: { FmtPrinter , PrettyPrinter , Printer } ;
12
- use rustc_middle:: ty:: { ConstInt , Ty } ;
12
+ use rustc_middle:: ty:: { ConstInt , Ty , TyCtxt } ;
13
13
use rustc_middle:: { mir, ty} ;
14
14
use rustc_target:: abi:: { Abi , HasDataLayout , Size , TagEncoding } ;
15
15
use rustc_target:: abi:: { VariantIdx , Variants } ;
@@ -246,6 +246,57 @@ impl<'tcx, Tag: Provenance> ImmTy<'tcx, Tag> {
246
246
}
247
247
}
248
248
249
+ /// See `try_read_immediate_from_mplace` for what this function is about.
250
+ /// Exposed to the rest of the crate since some hacky code in `eval_queries.rs` (that shouldn't
251
+ /// exist) also needs it.
252
+ pub ( crate ) fn type_is_scalar < ' tcx > ( tcx : TyCtxt < ' tcx > , ty : Ty < ' tcx > ) -> bool {
253
+ match ty. kind ( ) {
254
+ // Primitive types. We *have to* handle these since the primitive operations that
255
+ // act on them require it.
256
+ ty:: Bool
257
+ | ty:: Char
258
+ | ty:: Float ( _)
259
+ | ty:: Int ( _)
260
+ | ty:: Uint ( _)
261
+ | ty:: RawPtr ( ..)
262
+ | ty:: Ref ( ..)
263
+ | ty:: FnPtr ( ..)
264
+ | ty:: FnDef ( ..)
265
+ | ty:: Never => true ,
266
+ // Compound types. We have to exclude unions here.
267
+ ty:: Adt ( adt_def, substs) => {
268
+ if adt_def. is_union ( ) {
269
+ // Unions are explicitly allowed to be partially initialized, so we have to
270
+ // exclude them here.
271
+ false
272
+ } else {
273
+ // Check all fields of all variants, to make sure there is no union hiding here.
274
+ adt_def. all_fields ( ) . all ( |field| type_is_scalar ( tcx, field. ty ( tcx, substs) ) )
275
+ }
276
+ }
277
+ ty:: Tuple ( ..) => {
278
+ // If all fields are scalar, we are good.
279
+ ty. tuple_fields ( ) . iter ( ) . all ( |field| type_is_scalar ( tcx, field) )
280
+ }
281
+ // FIXME: can these ever have Scalar ABI?
282
+ ty:: Closure ( ..) | ty:: Generator ( ..) => false ,
283
+ // Types that don't have scalar layout to begin with.
284
+ ty:: Array ( ..) | ty:: Slice ( ..) | ty:: Str | ty:: Dynamic ( ..) | ty:: Foreign ( ..) => {
285
+ false
286
+ }
287
+ // Types we should not uusally see here, but when called from CTFE op_to_const these can
288
+ // actually happen.
289
+ ty:: Error ( _)
290
+ | ty:: Infer ( ..)
291
+ | ty:: Placeholder ( ..)
292
+ | ty:: Bound ( ..)
293
+ | ty:: Param ( ..)
294
+ | ty:: Opaque ( ..)
295
+ | ty:: Projection ( ..)
296
+ | ty:: GeneratorWitness ( ..) => false ,
297
+ }
298
+ }
299
+
249
300
impl < ' mir , ' tcx : ' mir , M : Machine < ' mir , ' tcx > > InterpCx < ' mir , ' tcx , M > {
250
301
/// Try reading an immediate in memory; this is interesting particularly for `ScalarPair`.
251
302
/// Returns `None` if the layout does not permit loading this as a value.
@@ -266,12 +317,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
266
317
} ) ) ;
267
318
} ;
268
319
320
+ // It may seem like all types with `Scalar` or `ScalarPair` ABI are fair game at this point.
321
+ // However, `MaybeUninit<u64>` is considered a `Scalar` as far as its layout is concerned --
322
+ // and yet cannot be represented by an interpreter `Scalar`, since we have to handle the
323
+ // case where some of the bytes are initialized and others are not. So, we need an extra
324
+ // check that walks over the type of `mplace` to make sure it is truly correct to treat this
325
+ // like a `Scalar` (or `ScalarPair`).
269
326
match mplace. layout . abi {
270
- Abi :: Scalar ( ..) => {
327
+ Abi :: Scalar ( ..) if type_is_scalar ( self . tcx . tcx , mplace . layout . ty ) => {
271
328
let scalar = alloc. read_scalar ( alloc_range ( Size :: ZERO , mplace. layout . size ) ) ?;
272
329
Ok ( Some ( ImmTy { imm : scalar. into ( ) , layout : mplace. layout } ) )
273
330
}
274
- Abi :: ScalarPair ( a, b) => {
331
+ Abi :: ScalarPair ( a, b) if type_is_scalar ( self . tcx . tcx , mplace . layout . ty ) => {
275
332
// We checked `ptr_align` above, so all fields will have the alignment they need.
276
333
// We would anyway check against `ptr_align.restrict_for_offset(b_offset)`,
277
334
// which `ptr.offset(b_offset)` cannot possibly fail to satisfy.
0 commit comments