@@ -258,7 +258,7 @@ impl ArgTypeExt<'ll, 'tcx> for ArgType<'tcx, Ty<'tcx>> {
258258 val
259259 } ;
260260 match self . mode {
261- PassMode :: Ignore => { } ,
261+ PassMode :: Ignore ( _ ) => { }
262262 PassMode :: Pair ( ..) => {
263263 OperandValue :: Pair ( next ( ) , next ( ) ) . store ( bx, dst) ;
264264 }
@@ -507,6 +507,14 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
507507 }
508508 } ;
509509
510+ // Store the index of the last argument. This is useful for working with
511+ // C-compatible variadic arguments.
512+ let last_arg_idx = if sig. inputs ( ) . is_empty ( ) {
513+ None
514+ } else {
515+ Some ( sig. inputs ( ) . len ( ) - 1 )
516+ } ;
517+
510518 let arg_of = |ty : Ty < ' tcx > , arg_idx : Option < usize > | {
511519 let is_return = arg_idx. is_none ( ) ;
512520 let mut arg = mk_arg_type ( ty, arg_idx) ;
@@ -516,7 +524,30 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
516524 // The same is true for s390x-unknown-linux-gnu
517525 // and sparc64-unknown-linux-gnu.
518526 if is_return || rust_abi || ( !win_x64_gnu && !linux_s390x && !linux_sparc64) {
519- arg. mode = PassMode :: Ignore ;
527+ arg. mode = PassMode :: Ignore ( IgnoreMode :: Zst ) ;
528+ }
529+ }
530+
531+ // If this is a C-variadic function, this is not the return value,
532+ // and there is one or more fixed arguments; ensure that the `VaList`
533+ // is ignored as an argument.
534+ if sig. variadic {
535+ match ( last_arg_idx, arg_idx) {
536+ ( Some ( last_idx) , Some ( cur_idx) ) if last_idx == cur_idx => {
537+ let va_list_did = match cx. tcx . lang_items ( ) . va_list ( ) {
538+ Some ( did) => did,
539+ None => bug ! ( "`va_list` lang item required for C-variadic functions" ) ,
540+ } ;
541+ match ty. sty {
542+ ty:: Adt ( def, _) if def. did == va_list_did => {
543+ // This is the "spoofed" `VaList`. Set the arguments mode
544+ // so that it will be ignored.
545+ arg. mode = PassMode :: Ignore ( IgnoreMode :: CVarArgs ) ;
546+ } ,
547+ _ => ( ) ,
548+ }
549+ }
550+ _ => { }
520551 }
521552 }
522553
@@ -646,7 +677,9 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
646677 ) ;
647678
648679 let llreturn_ty = match self . ret . mode {
649- PassMode :: Ignore => cx. type_void ( ) ,
680+ PassMode :: Ignore ( IgnoreMode :: Zst ) => cx. type_void ( ) ,
681+ PassMode :: Ignore ( IgnoreMode :: CVarArgs ) =>
682+ bug ! ( "`va_list` should never be a return type" ) ,
650683 PassMode :: Direct ( _) | PassMode :: Pair ( ..) => {
651684 self . ret . layout . immediate_llvm_type ( cx)
652685 }
@@ -664,7 +697,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
664697 }
665698
666699 let llarg_ty = match arg. mode {
667- PassMode :: Ignore => continue ,
700+ PassMode :: Ignore ( _ ) => continue ,
668701 PassMode :: Direct ( _) => arg. layout . immediate_llvm_type ( cx) ,
669702 PassMode :: Pair ( ..) => {
670703 llargument_tys. push ( arg. layout . scalar_pair_element_llvm_type ( cx, 0 , true ) ) ;
@@ -733,7 +766,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
733766 apply ( & ArgAttributes :: new ( ) ) ;
734767 }
735768 match arg. mode {
736- PassMode :: Ignore => { }
769+ PassMode :: Ignore ( _ ) => { }
737770 PassMode :: Direct ( ref attrs) |
738771 PassMode :: Indirect ( ref attrs, None ) => apply ( attrs) ,
739772 PassMode :: Indirect ( ref attrs, Some ( ref extra_attrs) ) => {
@@ -780,7 +813,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
780813 apply ( & ArgAttributes :: new ( ) ) ;
781814 }
782815 match arg. mode {
783- PassMode :: Ignore => { }
816+ PassMode :: Ignore ( _ ) => { }
784817 PassMode :: Direct ( ref attrs) |
785818 PassMode :: Indirect ( ref attrs, None ) => apply ( attrs) ,
786819 PassMode :: Indirect ( ref attrs, Some ( ref extra_attrs) ) => {
0 commit comments