@@ -9,7 +9,7 @@ use itertools::Itertools as _;
9
9
use rspirv:: spirv:: Word ;
10
10
use rustc_abi:: { self as abi, AddressSpace , Float , HasDataLayout , Integer , Primitive , Size } ;
11
11
use rustc_codegen_ssa:: traits:: { ConstCodegenMethods , MiscCodegenMethods , StaticCodegenMethods } ;
12
- use rustc_middle:: mir:: interpret:: { ConstAllocation , GlobalAlloc , Scalar , alloc_range} ;
12
+ use rustc_middle:: mir:: interpret:: { AllocError , ConstAllocation , GlobalAlloc , Scalar , alloc_range} ;
13
13
use rustc_middle:: ty:: layout:: LayoutOf ;
14
14
use rustc_span:: { DUMMY_SP , Span } ;
15
15
@@ -298,24 +298,7 @@ impl ConstCodegenMethods for CodegenCx<'_> {
298
298
( self . get_static ( def_id) , AddressSpace :: DATA )
299
299
}
300
300
} ;
301
- let value = if offset. bytes ( ) == 0 {
302
- base_addr
303
- } else {
304
- self . tcx
305
- . dcx ( )
306
- . fatal ( "Non-zero scalar_to_backend ptr.offset not supported" )
307
- // let offset = self.constant_bit64(ptr.offset.bytes());
308
- // self.gep(base_addr, once(offset))
309
- } ;
310
- if let Primitive :: Pointer ( _) = layout. primitive ( ) {
311
- assert_ty_eq ! ( self , value. ty, ty) ;
312
- value
313
- } else {
314
- self . tcx
315
- . dcx ( )
316
- . fatal ( "Non-pointer-typed scalar_to_backend Scalar::Ptr not supported" ) ;
317
- // unsafe { llvm::LLVMConstPtrToInt(llval, llty) }
318
- }
301
+ self . const_bitcast ( self . const_ptr_byte_offset ( base_addr, offset) , ty)
319
302
}
320
303
}
321
304
}
@@ -448,18 +431,82 @@ impl<'tcx> CodegenCx<'tcx> {
448
431
SpirvType :: Pointer { .. } => Primitive :: Pointer ( AddressSpace :: DATA ) ,
449
432
_ => unreachable ! ( ) ,
450
433
} ;
451
- let value = match alloc. inner ( ) . read_scalar (
452
- self ,
453
- alloc_range ( offset, size) ,
454
- matches ! ( primitive, Primitive :: Pointer ( _) ) ,
455
- ) {
434
+
435
+ let range = alloc_range ( offset, size) ;
436
+ let read_provenance = matches ! ( primitive, Primitive :: Pointer ( _) ) ;
437
+
438
+ let mut primitive = primitive;
439
+ let mut read_result = alloc. inner ( ) . read_scalar ( self , range, read_provenance) ;
440
+
441
+ // HACK(eddyb) while reading a pointer as an integer will fail,
442
+ // the pointer itself can be read as a pointer, and then passed
443
+ // to `scalar_to_backend`, which will `const_bitcast` it to `ty`.
444
+ if read_result. is_err ( )
445
+ && !read_provenance
446
+ && let read_ptr_result @ Ok ( Scalar :: Ptr ( ptr, _) ) = alloc
447
+ . inner ( )
448
+ . read_scalar ( self , range, /* read_provenance */ true )
449
+ {
450
+ let ( prov, _offset) = ptr. into_parts ( ) ;
451
+ primitive = Primitive :: Pointer (
452
+ self . tcx . global_alloc ( prov. alloc_id ( ) ) . address_space ( self ) ,
453
+ ) ;
454
+ read_result = read_ptr_result;
455
+ }
456
+
457
+ let scalar_or_zombie = match read_result {
456
458
Ok ( scalar) => {
457
- self . scalar_to_backend ( scalar, self . primitive_to_scalar ( primitive) , ty)
459
+ Ok ( self . scalar_to_backend ( scalar, self . primitive_to_scalar ( primitive) , ty) )
458
460
}
459
- // FIXME(eddyb) this is really unsound, could be an error!
460
- _ => self . undef ( ty) ,
461
+
462
+ // FIXME(eddyb) could some of these use e.g. `const_bitcast`?
463
+ // (or, in general, assembling one constant out of several)
464
+ Err ( err) => match err {
465
+ // The scalar is only `undef` if the entire byte range
466
+ // it covers is completely uninitialized - all other
467
+ // failure modes of `read_scalar` are various errors.
468
+ AllocError :: InvalidUninitBytes ( _) => {
469
+ let uninit_range = alloc
470
+ . inner ( )
471
+ . init_mask ( )
472
+ . is_range_initialized ( range)
473
+ . unwrap_err ( ) ;
474
+ let uninit_size = {
475
+ let [ start, end] = [ uninit_range. start , uninit_range. end ( ) ]
476
+ . map ( |x| x. clamp ( range. start , range. end ( ) ) ) ;
477
+ end - start
478
+ } ;
479
+ if uninit_size == size {
480
+ Ok ( self . undef ( ty) )
481
+ } else {
482
+ Err ( format ! (
483
+ "overlaps {} uninitialized bytes" ,
484
+ uninit_size. bytes( )
485
+ ) )
486
+ }
487
+ }
488
+ AllocError :: ReadPointerAsInt ( _) => Err ( "overlaps pointer bytes" . into ( ) ) ,
489
+ AllocError :: ReadPartialPointer ( _) => {
490
+ Err ( "partially overlaps another pointer" . into ( ) )
491
+ }
492
+
493
+ // HACK(eddyb) these should never happen when using
494
+ // `read_scalar`, but better not outright crash.
495
+ AllocError :: ScalarSizeMismatch ( _)
496
+ | AllocError :: OverwritePartialPointer ( _) => {
497
+ Err ( format ! ( "unrecognized `AllocError::{err:?}`" ) )
498
+ }
499
+ } ,
461
500
} ;
462
- ( value, size)
501
+ let result = scalar_or_zombie. unwrap_or_else ( |reason| {
502
+ let result = self . undef ( ty) ;
503
+ self . zombie_no_span (
504
+ result. def_cx ( self ) ,
505
+ & format ! ( "unsupported `{}` constant: {reason}" , self . debug_type( ty) , ) ,
506
+ ) ;
507
+ result
508
+ } ) ;
509
+ ( result, size)
463
510
}
464
511
SpirvType :: Adt {
465
512
field_types,
0 commit comments