@@ -11,7 +11,7 @@ use crate::codegen_cprover_gotoc::codegen::typ::std_pointee_type;
11
11
use crate :: codegen_cprover_gotoc:: utils:: { dynamic_fat_ptr, slice_fat_ptr} ;
12
12
use crate :: codegen_cprover_gotoc:: GotocCtx ;
13
13
use crate :: unwrap_or_return_codegen_unimplemented;
14
- use cbmc:: goto_program:: { Expr , Location , Type } ;
14
+ use cbmc:: goto_program:: { Expr , ExprValue , Location , Stmt , Type } ;
15
15
use rustc_middle:: ty:: layout:: LayoutOf ;
16
16
use rustc_smir:: rustc_internal;
17
17
use rustc_target:: abi:: { TagEncoding , Variants } ;
@@ -636,6 +636,14 @@ impl<'tcx> GotocCtx<'tcx> {
636
636
}
637
637
}
638
638
639
+ fn is_zst_object ( & self , expr : & Expr ) -> bool {
640
+ match expr. value ( ) {
641
+ ExprValue :: Symbol { .. } => expr. typ ( ) . sizeof ( & self . symbol_table ) == 0 ,
642
+ ExprValue :: Member { lhs, .. } => self . is_zst_object ( lhs) ,
643
+ _ => false ,
644
+ }
645
+ }
646
+
639
647
/// Codegen the reference to a given place.
640
648
/// We currently have a somewhat weird way of handling ZST.
641
649
/// - For `*(&T)` where `T: Unsized`, the projection's `goto_expr` is a thin pointer, so we
@@ -647,8 +655,33 @@ impl<'tcx> GotocCtx<'tcx> {
647
655
let projection =
648
656
unwrap_or_return_codegen_unimplemented ! ( self , self . codegen_place_stable( place) ) ;
649
657
if self . use_thin_pointer_stable ( place_ty) {
650
- // Just return the address of the place dereferenced.
651
- projection. goto_expr . address_of ( )
658
+ // For ZST objects rustc does not necessarily generate any actual objects.
659
+ let need_not_be_an_object = self . is_zst_object ( & projection. goto_expr ) ;
660
+ let address_of = projection. goto_expr . clone ( ) . address_of ( ) ;
661
+ if need_not_be_an_object {
662
+ // Create a non-deterministic numeric value, assume it is non-zero and (when
663
+ // interpreted as an address) of proper alignment for the type, and cast that
664
+ // numeric value to a pointer type.
665
+ let loc = projection. goto_expr . location ( ) ;
666
+ let ( var, decl) =
667
+ self . decl_temp_variable ( Type :: size_t ( ) , Some ( Type :: size_t ( ) . nondet ( ) ) , * loc) ;
668
+ let assume_non_zero =
669
+ Stmt :: assume ( var. clone ( ) . neq ( Expr :: int_constant ( 0 , var. typ ( ) . clone ( ) ) ) , * loc) ;
670
+ let layout = self . layout_of_stable ( place_ty) ;
671
+ let alignment = Expr :: int_constant ( layout. align . abi . bytes ( ) , var. typ ( ) . clone ( ) ) ;
672
+ let assume_aligned = Stmt :: assume (
673
+ var. clone ( ) . rem ( alignment) . eq ( Expr :: int_constant ( 0 , var. typ ( ) . clone ( ) ) ) ,
674
+ * loc,
675
+ ) ;
676
+ let cast_to_pointer_type = var. cast_to ( address_of. typ ( ) . clone ( ) ) . as_stmt ( * loc) ;
677
+ Expr :: statement_expression (
678
+ vec ! [ decl, assume_non_zero, assume_aligned, cast_to_pointer_type] ,
679
+ address_of. typ ( ) . clone ( ) ,
680
+ )
681
+ } else {
682
+ // Just return the address of the place dereferenced.
683
+ address_of
684
+ }
652
685
} else if place_ty == pointee_type ( self . local_ty_stable ( place. local ) ) . unwrap ( ) {
653
686
// Just return the fat pointer if this is a simple &(*local).
654
687
projection. fat_ptr_goto_expr . unwrap ( )
0 commit comments