@@ -11,7 +11,7 @@ use crate::codegen_cprover_gotoc::codegen::typ::std_pointee_type;
1111use crate :: codegen_cprover_gotoc:: utils:: { dynamic_fat_ptr, slice_fat_ptr} ;
1212use crate :: codegen_cprover_gotoc:: GotocCtx ;
1313use crate :: unwrap_or_return_codegen_unimplemented;
14- use cbmc:: goto_program:: { Expr , Location , Type } ;
14+ use cbmc:: goto_program:: { Expr , ExprValue , Location , Stmt , Type } ;
1515use rustc_middle:: ty:: layout:: LayoutOf ;
1616use rustc_smir:: rustc_internal;
1717use rustc_target:: abi:: { TagEncoding , Variants } ;
@@ -636,6 +636,14 @@ impl<'tcx> GotocCtx<'tcx> {
636636 }
637637 }
638638
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+
639647 /// Codegen the reference to a given place.
640648 /// We currently have a somewhat weird way of handling ZST.
641649 /// - For `*(&T)` where `T: Unsized`, the projection's `goto_expr` is a thin pointer, so we
@@ -647,8 +655,33 @@ impl<'tcx> GotocCtx<'tcx> {
647655 let projection =
648656 unwrap_or_return_codegen_unimplemented ! ( self , self . codegen_place_stable( place) ) ;
649657 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+ }
652685 } else if place_ty == pointee_type ( self . local_ty_stable ( place. local ) ) . unwrap ( ) {
653686 // Just return the fat pointer if this is a simple &(*local).
654687 projection. fat_ptr_goto_expr . unwrap ( )
0 commit comments