@@ -349,7 +349,7 @@ impl<'tcx> GotocCtx<'tcx> {
349349 ) -> Expr {
350350 let instance =
351351 Instance :: resolve ( self . tcx , ty:: ParamEnv :: reveal_all ( ) , d, substs) . unwrap ( ) . unwrap ( ) ;
352- self . codegen_func_expr ( instance, span)
352+ self . codegen_fn_item ( instance, span)
353353 }
354354
355355 fn codegen_alloc_pointer (
@@ -627,11 +627,17 @@ impl<'tcx> GotocCtx<'tcx> {
627627 self . find_function ( & fname) . unwrap ( ) . call ( vec ! [ init] )
628628 }
629629
630- pub fn codegen_func_expr ( & mut self , instance : Instance < ' tcx > , span : Option < & Span > ) -> Expr {
630+ /// Ensure that the given instance is in the symbol table, returning the symbol.
631+ ///
632+ /// FIXME: The function should not have to return the type of the function symbol as well
633+ /// because the symbol should have the type. The problem is that the type in the symbol table
634+ /// sometimes subtly differs from the type that codegen_function_sig returns.
635+ /// This is tracked in <https://github.com/model-checking/kani/issues/1350>.
636+ pub fn codegen_func_symbol ( & mut self , instance : Instance < ' tcx > ) -> ( & Symbol , Type ) {
631637 let func = self . symbol_name ( instance) ;
632638 let funct = self . codegen_function_sig ( self . fn_sig_of_instance ( instance) . unwrap ( ) ) ;
633639 // make sure the functions imported from other modules are in the symbol table
634- self . ensure ( & func, |ctx, _| {
640+ let sym = self . ensure ( & func, |ctx, _| {
635641 Symbol :: function (
636642 & func,
637643 funct. clone ( ) ,
@@ -641,6 +647,40 @@ impl<'tcx> GotocCtx<'tcx> {
641647 )
642648 . with_is_extern ( true )
643649 } ) ;
644- Expr :: symbol_expression ( func, funct) . with_location ( self . codegen_span_option ( span. cloned ( ) ) )
650+ ( sym, funct)
651+ }
652+
653+ /// For a given function instance, generates an expression for the function symbol of type `Code`.
654+ ///
655+ /// Note: use `codegen_func_expr_zst` in the general case because GotoC does not allow functions to be used in all contexts
656+ /// (e.g. struct fields).
657+ ///
658+ /// For details, see <https://github.com/model-checking/kani/pull/1338>
659+ pub fn codegen_func_expr ( & mut self , instance : Instance < ' tcx > , span : Option < & Span > ) -> Expr {
660+ let ( func_symbol, func_typ) = self . codegen_func_symbol ( instance) ;
661+ Expr :: symbol_expression ( func_symbol. name , func_typ)
662+ . with_location ( self . codegen_span_option ( span. cloned ( ) ) )
663+ }
664+
665+ /// For a given function instance, generates a zero-sized dummy symbol of type `Struct`.
666+ ///
667+ /// This is often necessary because GotoC does not allow functions to be used in all contexts (e.g. struct fields).
668+ /// For details, see <https://github.com/model-checking/kani/pull/1338>
669+ ///
670+ /// Note: use `codegen_func_expr` instead if you want to call the function immediately.
671+ fn codegen_fn_item ( & mut self , instance : Instance < ' tcx > , span : Option < & Span > ) -> Expr {
672+ let ( func_symbol, _) = self . codegen_func_symbol ( instance) ;
673+ let func = func_symbol. name ;
674+ let fn_struct_ty = self . codegen_fndef_type ( instance) ;
675+ // This zero-sized object that a function name refers to in Rust is globally unique, so we create such a global object.
676+ let fn_singleton_name = format ! ( "{func}::FnDefSingleton" ) ;
677+ let fn_singleton = self . ensure_global_var (
678+ & fn_singleton_name,
679+ false ,
680+ fn_struct_ty. clone ( ) ,
681+ Location :: none ( ) ,
682+ |_, _| None , // zero-sized, so no initialization necessary
683+ ) ;
684+ fn_singleton. with_location ( self . codegen_span_option ( span. cloned ( ) ) )
645685 }
646686}
0 commit comments