summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen/CGCall.cpp
diff options
context:
space:
mode:
authorReid Kleckner <reid@kleckner.net>2014-07-08 02:24:27 +0000
committerReid Kleckner <reid@kleckner.net>2014-07-08 02:24:27 +0000
commitafba553ede21c96fb7b2cf6473de102e11722493 (patch)
tree915b9980595edb99045cb116a934e6972ceb061d /clang/lib/CodeGen/CGCall.cpp
parent3f762ef111a69ff7c7cf08a23c3769aa8ada1945 (diff)
downloadbcm5719-llvm-afba553ede21c96fb7b2cf6473de102e11722493.tar.gz
bcm5719-llvm-afba553ede21c96fb7b2cf6473de102e11722493.zip
MS ABI: "Fix" passing non-POD structs by value to variadic functions
Of course, such code is horribly broken and will explode on impact. That said, ATL does it, and we have to support them, at least a little bit. Fixes PR20191. llvm-svn: 212508
Diffstat (limited to 'clang/lib/CodeGen/CGCall.cpp')
-rw-r--r--clang/lib/CodeGen/CGCall.cpp45
1 files changed, 25 insertions, 20 deletions
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 5ccb8bdf2c0..44fd4d8b597 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -2859,28 +2859,33 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
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);
}
OpenPOWER on IntegriCloud