@@ -7,14 +7,16 @@ use crate::codegen_cprover_gotoc::{GotocCtx, VtableCtx};
7
7
use crate :: unwrap_or_return_codegen_unimplemented_stmt;
8
8
use cbmc:: goto_program:: { Expr , Location , Stmt , Type } ;
9
9
use rustc_middle:: ty:: layout:: LayoutOf ;
10
+ use rustc_middle:: ty:: { List , ParamEnv } ;
10
11
use rustc_smir:: rustc_internal;
11
12
use rustc_target:: abi:: { FieldsShape , Primitive , TagEncoding , Variants } ;
13
+ use stable_mir:: abi:: { ArgAbi , FnAbi , PassMode } ;
12
14
use stable_mir:: mir:: mono:: { Instance , InstanceKind } ;
13
15
use stable_mir:: mir:: {
14
16
AssertMessage , BasicBlockIdx , CopyNonOverlapping , NonDivergingIntrinsic , Operand , Place ,
15
17
Statement , StatementKind , SwitchTargets , Terminator , TerminatorKind , RETURN_LOCAL ,
16
18
} ;
17
- use stable_mir:: ty:: { RigidTy , Span , Ty , TyKind , VariantIdx } ;
19
+ use stable_mir:: ty:: { Abi , RigidTy , Span , Ty , TyKind , VariantIdx } ;
18
20
use tracing:: { debug, debug_span, trace} ;
19
21
20
22
impl < ' tcx > GotocCtx < ' tcx > {
@@ -432,31 +434,21 @@ impl<'tcx> GotocCtx<'tcx> {
432
434
/// as subsequent parameters.
433
435
///
434
436
/// 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 ( )
460
452
}
461
453
462
454
/// Because function calls terminate basic blocks, to "end" a function call, we
@@ -472,25 +464,24 @@ impl<'tcx> GotocCtx<'tcx> {
472
464
/// Generate Goto-C for each argument to a function call.
473
465
///
474
466
/// 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
479
469
. 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 ( ) {
483
476
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 ) {
485
478
Some ( self . codegen_operand_stable ( op) )
486
479
} else {
487
- // We ignore ZST types.
488
- debug ! ( arg=?op, "codegen_funcall_args ignore" ) ;
489
480
None
490
481
}
491
482
} )
492
483
. collect ( ) ;
493
- debug ! ( ?fargs, "codegen_funcall_args" ) ;
484
+ debug ! ( ?fargs, args_abi=?fn_abi . args , "codegen_funcall_args" ) ;
494
485
fargs
495
486
}
496
487
@@ -515,9 +506,12 @@ impl<'tcx> GotocCtx<'tcx> {
515
506
span : Span ,
516
507
) -> Stmt {
517
508
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
+ {
519
513
return self . codegen_funcall_of_intrinsic (
520
- & func ,
514
+ instance ,
521
515
& args,
522
516
& destination,
523
517
target. map ( |bb| bb) ,
@@ -526,16 +520,23 @@ impl<'tcx> GotocCtx<'tcx> {
526
520
}
527
521
528
522
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
+ } ;
539
540
540
541
if let Some ( hk) = self . hooks . hook_applies ( self . tcx , instance) {
541
542
return hk. handle ( self , instance, fargs, destination, * target, span) ;
@@ -573,7 +574,16 @@ impl<'tcx> GotocCtx<'tcx> {
573
574
Stmt :: block ( stmts, loc)
574
575
}
575
576
// 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) ;
577
587
let func_expr = self . codegen_operand_stable ( func) . dereference ( ) ;
578
588
// Actually generate the function call and return.
579
589
Stmt :: block (
0 commit comments