if (ArgMemory) {
llvm::Value *Arg = ArgMemory;
- llvm::Type *LastParamTy =
- IRFuncTy->getParamType(IRFuncTy->getNumParams() - 1);
- if (Arg->getType() != LastParamTy) {
+ if (CallInfo.isVariadic()) {
+ // When passing non-POD arguments by value to variadic functions, we will
+ // end up with a variadic prototype and an inalloca call site. In such
+ // cases, we can't do any parameter mismatch checks. Give up and bitcast
+ // the callee.
+ unsigned CalleeAS =
+ cast<llvm::PointerType>(Callee->getType())->getAddressSpace();
+ Callee = Builder.CreateBitCast(
+ Callee, getTypes().GetFunctionType(CallInfo)->getPointerTo(CalleeAS));
+ } else {
+ llvm::Type *LastParamTy =
+ IRFuncTy->getParamType(IRFuncTy->getNumParams() - 1);
+ if (Arg->getType() != LastParamTy) {
#ifndef NDEBUG
- // Assert that these structs have equivalent element types.
- llvm::StructType *FullTy = CallInfo.getArgStruct();
- llvm::StructType *Prefix = cast<llvm::StructType>(
- cast<llvm::PointerType>(LastParamTy)->getElementType());
-
- // For variadic functions, the caller might supply a larger struct than
- // the callee expects, and that's OK.
- assert(Prefix->getNumElements() == FullTy->getNumElements() ||
- (CallInfo.isVariadic() &&
- Prefix->getNumElements() <= FullTy->getNumElements()));
-
- for (llvm::StructType::element_iterator PI = Prefix->element_begin(),
- PE = Prefix->element_end(),
- FI = FullTy->element_begin();
- PI != PE; ++PI, ++FI)
- assert(*PI == *FI);
+ // Assert that these structs have equivalent element types.
+ llvm::StructType *FullTy = CallInfo.getArgStruct();
+ llvm::StructType *DeclaredTy = cast<llvm::StructType>(
+ cast<llvm::PointerType>(LastParamTy)->getElementType());
+ assert(DeclaredTy->getNumElements() == FullTy->getNumElements());
+ for (llvm::StructType::element_iterator DI = DeclaredTy->element_begin(),
+ DE = DeclaredTy->element_end(),
+ FI = FullTy->element_begin();
+ DI != DE; ++DI, ++FI)
+ assert(*DI == *FI);
#endif
- Arg = Builder.CreateBitCast(Arg, LastParamTy);
+ Arg = Builder.CreateBitCast(Arg, LastParamTy);
+ }
}
Args.push_back(Arg);
}
-// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i686-pc-win32 -mconstructor-aliases -fno-rtti | FileCheck %s
+// RUN: %clang_cc1 -Wno-non-pod-varargs -emit-llvm %s -o - -triple=i686-pc-win32 -mconstructor-aliases -fno-rtti | FileCheck %s
#include <stdarg.h>
return sum;
}
+// CHECK-LABEL: define i32 @"\01?foo@@YAHUA@@ZZ"(<{ %struct.A }>* inalloca, ...)
+
int main() {
return foo(A(3), 1, 2, 3);
}
// CHECK-LABEL: define i32 @main()
-// CHECK: %[[argmem_cast:[^ ]*]] = bitcast <{ %struct.A, i32, i32, i32 }>* %argmem to <{ %struct.A }>*
-// CHECK: call i32 (<{ %struct.A }>*, ...)* @"\01?foo@@YAHUA@@ZZ"(<{ %struct.A }>* inalloca %[[argmem_cast]])
+// CHECK: %[[argmem:[^ ]*]] = alloca inalloca <{ %struct.A, i32, i32, i32 }>
+// CHECK: call i32 {{.*bitcast.*}}@"\01?foo@@YAHUA@@ZZ"{{.*}}(<{ %struct.A, i32, i32, i32 }>* inalloca %[[argmem]])
+
+void varargs_zero(...);
+void varargs_one(int, ...);
+void varargs_two(int, int, ...);
+void varargs_three(int, int, int, ...);
+void call_var_args() {
+ A x(3);
+ varargs_zero(x);
+ varargs_one(1, x);
+ varargs_two(1, 2, x);
+ varargs_three(1, 2, 3, x);
+}
+
+// CHECK-LABEL: define void @"\01?call_var_args@@YAXXZ"()
+// CHECK: call void {{.*bitcast.*varargs_zero.*}}(<{ %struct.A }>* inalloca %{{.*}})
+// CHECK: call void {{.*bitcast.*varargs_one.*}}(<{ i32, %struct.A }>* inalloca %{{.*}})
+// CHECK: call void {{.*bitcast.*varargs_two.*}}(<{ i32, i32, %struct.A }>* inalloca %{{.*}})
+// CHECK: call void {{.*bitcast.*varargs_three.*}}(<{ i32, i32, i32, %struct.A }>* inalloca %{{.*}})
+
+// CHECK-LABEL: declare void @"\01?varargs_zero@@YAXZZ"(...)
+// CHECK-LABEL: declare void @"\01?varargs_one@@YAXHZZ"(i32, ...)
+// CHECK-LABEL: declare void @"\01?varargs_two@@YAXHHZZ"(i32, i32, ...)
+// CHECK-LABEL: declare void @"\01?varargs_three@@YAXHHHZZ"(i32, i32, i32, ...)