@@ -7,14 +7,16 @@ use crate::codegen_cprover_gotoc::{GotocCtx, VtableCtx};
77use crate :: unwrap_or_return_codegen_unimplemented_stmt;
88use cbmc:: goto_program:: { Expr , Location , Stmt , Type } ;
99use rustc_middle:: ty:: layout:: LayoutOf ;
10+ use rustc_middle:: ty:: { List , ParamEnv } ;
1011use rustc_smir:: rustc_internal;
1112use rustc_target:: abi:: { FieldsShape , Primitive , TagEncoding , Variants } ;
13+ use stable_mir:: abi:: { ArgAbi , FnAbi , PassMode } ;
1214use stable_mir:: mir:: mono:: { Instance , InstanceKind } ;
1315use stable_mir:: mir:: {
1416 AssertMessage , BasicBlockIdx , CopyNonOverlapping , NonDivergingIntrinsic , Operand , Place ,
1517 Statement , StatementKind , SwitchTargets , Terminator , TerminatorKind , RETURN_LOCAL ,
1618} ;
17- use stable_mir:: ty:: { RigidTy , Span , Ty , TyKind , VariantIdx } ;
19+ use stable_mir:: ty:: { Abi , RigidTy , Span , Ty , TyKind , VariantIdx } ;
1820use tracing:: { debug, debug_span, trace} ;
1921
2022impl < ' tcx > GotocCtx < ' tcx > {
@@ -432,31 +434,21 @@ impl<'tcx> GotocCtx<'tcx> {
432434 /// as subsequent parameters.
433435 ///
434436 /// See [GotocCtx::ty_needs_untupled_args] for more details.
435- fn codegen_untupled_args (
436- & mut self ,
437- instance : Instance ,
438- fargs : & mut Vec < Expr > ,
439- last_mir_arg : Option < & Operand > ,
440- ) {
441- debug ! ( "codegen_untuple_closure_args instance: {:?}, fargs {:?}" , instance. name( ) , fargs) ;
442- if !fargs. is_empty ( ) {
443- let tuple_ty = self . operand_ty_stable ( last_mir_arg. unwrap ( ) ) ;
444- if self . is_zst_stable ( tuple_ty) {
445- // Don't pass anything if all tuple elements are ZST.
446- // ZST arguments are ignored.
447- return ;
448- }
449- let tupe = fargs. remove ( fargs. len ( ) - 1 ) ;
450- if let TyKind :: RigidTy ( RigidTy :: Tuple ( tupled_args) ) = tuple_ty. kind ( ) {
451- for ( idx, arg_ty) in tupled_args. iter ( ) . enumerate ( ) {
452- if !self . is_zst_stable ( * arg_ty) {
453- // Access the tupled parameters through the `member` operation
454- let idx_expr = tupe. clone ( ) . member ( & idx. to_string ( ) , & self . symbol_table ) ;
455- fargs. push ( idx_expr) ;
456- }
457- }
458- }
459- }
437+ fn codegen_untupled_args ( & mut self , op : & Operand , args_abi : & [ ArgAbi ] ) -> Vec < Expr > {
438+ let tuple_ty = self . operand_ty_stable ( op) ;
439+ let tuple_expr = self . codegen_operand_stable ( op) ;
440+ let TyKind :: RigidTy ( RigidTy :: Tuple ( tupled_args) ) = tuple_ty. kind ( ) else { unreachable ! ( ) } ;
441+ tupled_args
442+ . iter ( )
443+ . enumerate ( )
444+ . filter_map ( |( idx, _) | {
445+ let arg_abi = & args_abi[ idx] ;
446+ ( arg_abi. mode != PassMode :: Ignore ) . then ( || {
447+ // Access the tupled parameters through the `member` operation
448+ tuple_expr. clone ( ) . member ( idx. to_string ( ) , & self . symbol_table )
449+ } )
450+ } )
451+ . collect ( )
460452 }
461453
462454 /// Because function calls terminate basic blocks, to "end" a function call, we
@@ -472,25 +464,24 @@ impl<'tcx> GotocCtx<'tcx> {
472464 /// Generate Goto-C for each argument to a function call.
473465 ///
474466 /// N.B. public only because instrinsics use this directly, too.
475- /// When `skip_zst` is set to `true`, the return value will not include any argument that is ZST.
476- /// This is used because we ignore ZST arguments, except for intrinsics.
477- pub ( crate ) fn codegen_funcall_args ( & mut self , args : & [ Operand ] , skip_zst : bool ) -> Vec < Expr > {
478- let fargs = args
467+ pub ( crate ) fn codegen_funcall_args ( & mut self , fn_abi : & FnAbi , args : & [ Operand ] ) -> Vec < Expr > {
468+ let fargs: Vec < Expr > = args
479469 . iter ( )
480- . filter_map ( |op| {
481- let op_ty = self . operand_ty_stable ( op) ;
482- if op_ty. kind ( ) . is_bool ( ) {
470+ . enumerate ( )
471+ . filter_map ( |( i, op) | {
472+ // Functions that require caller info will have an extra parameter.
473+ let arg_abi = & fn_abi. args . get ( i) ;
474+ let ty = self . operand_ty_stable ( op) ;
475+ if ty. kind ( ) . is_bool ( ) {
483476 Some ( self . codegen_operand_stable ( op) . cast_to ( Type :: c_bool ( ) ) )
484- } else if ! self . is_zst_stable ( op_ty ) || !skip_zst {
477+ } else if arg_abi . map_or ( true , |abi| abi . mode != PassMode :: Ignore ) {
485478 Some ( self . codegen_operand_stable ( op) )
486479 } else {
487- // We ignore ZST types.
488- debug ! ( arg=?op, "codegen_funcall_args ignore" ) ;
489480 None
490481 }
491482 } )
492483 . collect ( ) ;
493- debug ! ( ?fargs, "codegen_funcall_args" ) ;
484+ debug ! ( ?fargs, args_abi=?fn_abi . args , "codegen_funcall_args" ) ;
494485 fargs
495486 }
496487
@@ -515,9 +506,12 @@ impl<'tcx> GotocCtx<'tcx> {
515506 span : Span ,
516507 ) -> Stmt {
517508 debug ! ( ?func, ?args, ?destination, ?span, "codegen_funcall" ) ;
518- if self . is_intrinsic ( & func) {
509+ let instance_opt = self . get_instance ( func) ;
510+ if let Some ( instance) = instance_opt
511+ && matches ! ( instance. kind, InstanceKind :: Intrinsic )
512+ {
519513 return self . codegen_funcall_of_intrinsic (
520- & func ,
514+ instance ,
521515 & args,
522516 & destination,
523517 target. map ( |bb| bb) ,
@@ -526,16 +520,23 @@ impl<'tcx> GotocCtx<'tcx> {
526520 }
527521
528522 let loc = self . codegen_span_stable ( span) ;
529- let funct = self . operand_ty_stable ( func) ;
530- let mut fargs = self . codegen_funcall_args ( & args, true ) ;
531- match funct. kind ( ) {
532- TyKind :: RigidTy ( RigidTy :: FnDef ( def, subst) ) => {
533- let instance = Instance :: resolve ( def, & subst) . unwrap ( ) ;
534-
535- // TODO(celina): Move this check to be inside codegen_funcall_args.
536- if self . ty_needs_untupled_args ( rustc_internal:: internal ( self . tcx , funct) ) {
537- self . codegen_untupled_args ( instance, & mut fargs, args. last ( ) ) ;
538- }
523+ let fn_ty = self . operand_ty_stable ( func) ;
524+ match fn_ty. kind ( ) {
525+ fn_def @ TyKind :: RigidTy ( RigidTy :: FnDef ( ..) ) => {
526+ let instance = instance_opt. unwrap ( ) ;
527+ let fn_abi = instance. fn_abi ( ) . unwrap ( ) ;
528+ let mut fargs = if args. is_empty ( )
529+ || fn_def. fn_sig ( ) . unwrap ( ) . value . abi != Abi :: RustCall
530+ {
531+ self . codegen_funcall_args ( & fn_abi, & args)
532+ } else {
533+ let ( untupled, first_args) = args. split_last ( ) . unwrap ( ) ;
534+ let mut fargs = self . codegen_funcall_args ( & fn_abi, & first_args) ;
535+ fargs. append (
536+ & mut self . codegen_untupled_args ( untupled, & fn_abi. args [ first_args. len ( ) ..] ) ,
537+ ) ;
538+ fargs
539+ } ;
539540
540541 if let Some ( hk) = self . hooks . hook_applies ( self . tcx , instance) {
541542 return hk. handle ( self , instance, fargs, destination, * target, span) ;
@@ -573,7 +574,16 @@ impl<'tcx> GotocCtx<'tcx> {
573574 Stmt :: block ( stmts, loc)
574575 }
575576 // Function call through a pointer
576- TyKind :: RigidTy ( RigidTy :: FnPtr ( _) ) => {
577+ TyKind :: RigidTy ( RigidTy :: FnPtr ( fn_sig) ) => {
578+ let fn_sig_internal = rustc_internal:: internal ( self . tcx , fn_sig) ;
579+ let fn_ptr_abi = rustc_internal:: stable (
580+ self . tcx
581+ . fn_abi_of_fn_ptr (
582+ ParamEnv :: reveal_all ( ) . and ( ( fn_sig_internal, & List :: empty ( ) ) ) ,
583+ )
584+ . unwrap ( ) ,
585+ ) ;
586+ let fargs = self . codegen_funcall_args ( & fn_ptr_abi, & args) ;
577587 let func_expr = self . codegen_operand_stable ( func) . dereference ( ) ;
578588 // Actually generate the function call and return.
579589 Stmt :: block (
0 commit comments