@@ -301,28 +301,9 @@ impl<'tcx> GotocCtx<'tcx> {
301
301
match intrinsic {
302
302
"add_with_overflow" => codegen_op_with_overflow ! ( add_overflow) ,
303
303
"arith_offset" => codegen_wrapping_op ! ( plus) ,
304
- "assert_inhabited" => {
305
- let ty = instance. substs . type_at ( 0 ) ;
306
- let layout = self . layout_of ( ty) ;
307
- if layout. abi . is_uninhabited ( ) {
308
- let loc = self . codegen_span_option ( span) ;
309
- Stmt :: assert_false ( & format ! ( "type is uninhabited: {:?}" , ty) , loc)
310
- } else {
311
- Stmt :: skip ( loc)
312
- }
313
- }
314
- // https://doc.rust-lang.org/std/intrinsics/fn.assert_uninit_valid.html
315
- // assert_uninit_valid is guard for unsafe functions that cannot ever be executed if T
316
- // has invalid bit patterns: This will statically either panic, or do nothing. For now
317
- // we map this into a no-op.
318
- // TODO: https://github.com/model-checking/rmc/issues/6
319
- "assert_uninit_valid" => Stmt :: skip ( loc) ,
320
- // https://doc.rust-lang.org/std/intrinsics/fn.assert_zero_valid.html
321
- // assert_zero_valid is a guard for unsafe functions that cannot ever be executed if T
322
- // does not permit zero-initialization: This will statically either panic, or do
323
- // nothing. For now we map this into a no-op.
324
- // TODO: https://github.com/model-checking/rmc/issues/7
325
- "assert_zero_valid" => Stmt :: skip ( loc) ,
304
+ "assert_inhabited" => self . codegen_assert_intrinsic ( instance, intrinsic, span) ,
305
+ "assert_uninit_valid" => self . codegen_assert_intrinsic ( instance, intrinsic, span) ,
306
+ "assert_zero_valid" => self . codegen_assert_intrinsic ( instance, intrinsic, span) ,
326
307
// https://doc.rust-lang.org/core/intrinsics/fn.assume.html
327
308
// Informs the optimizer that a condition is always true.
328
309
// If the condition is false, the behavior is undefined.
@@ -567,6 +548,54 @@ impl<'tcx> GotocCtx<'tcx> {
567
548
)
568
549
}
569
550
551
+ /// Generates either a panic or no-op for `assert_*` intrinsics.
552
+ /// These are intrinsics that statically compile to panics if the type
553
+ /// layout is invalid so we get a message that mentions the offending type.
554
+ ///
555
+ /// https://doc.rust-lang.org/std/intrinsics/fn.assert_inhabited.html
556
+ /// https://doc.rust-lang.org/std/intrinsics/fn.assert_uninit_valid.html
557
+ /// https://doc.rust-lang.org/std/intrinsics/fn.assert_zero_valid.html
558
+ fn codegen_assert_intrinsic (
559
+ & mut self ,
560
+ instance : Instance < ' tcx > ,
561
+ intrinsic : & str ,
562
+ span : Option < Span > ,
563
+ ) -> Stmt {
564
+ let ty = instance. substs . type_at ( 0 ) ;
565
+ let layout = self . layout_of ( ty) ;
566
+ // Note: We follow the pattern seen in `codegen_panic_intrinsic` from `rustc_codegen_ssa`
567
+ // https://github.com/rust-lang/rust/blob/master/compiler/rustc_codegen_ssa/src/mir/block.rs
568
+
569
+ // For all intrinsics we first check `is_uninhabited` to give a more
570
+ // precise error message
571
+ if layout. abi . is_uninhabited ( ) {
572
+ return self . codegen_fatal_error (
573
+ & format ! ( "attempted to instantiate uninhabited type `{}`" , ty) ,
574
+ span,
575
+ ) ;
576
+ }
577
+
578
+ // Then we check if the type allows "raw" initialization for the cases
579
+ // where memory is zero-initialized or entirely uninitialized
580
+ if intrinsic == "assert_zero_valid" && !layout. might_permit_raw_init ( self , true ) {
581
+ return self . codegen_fatal_error (
582
+ & format ! ( "attempted to zero-initialize type `{}`, which is invalid" , ty) ,
583
+ span,
584
+ ) ;
585
+ }
586
+
587
+ if intrinsic == "assert_uninit_valid" && !layout. might_permit_raw_init ( self , false ) {
588
+ return self . codegen_fatal_error (
589
+ & format ! ( "attempted to leave type `{}` uninitialized, which is invalid" , ty) ,
590
+ span,
591
+ ) ;
592
+ }
593
+
594
+ // Otherwise we generate a no-op statement
595
+ let loc = self . codegen_span_option ( span) ;
596
+ return Stmt :: skip ( loc) ;
597
+ }
598
+
570
599
/// An atomic load simply returns the value referenced
571
600
/// in its argument (as in other atomic operations)
572
601
/// -------------------------
0 commit comments