diff options
author | Reid Kleckner <reid@kleckner.net> | 2014-07-08 02:24:27 +0000 |
---|---|---|
committer | Reid Kleckner <reid@kleckner.net> | 2014-07-08 02:24:27 +0000 |
commit | afba553ede21c96fb7b2cf6473de102e11722493 (patch) | |
tree | 915b9980595edb99045cb116a934e6972ceb061d /clang/lib/CodeGen/CGCall.cpp | |
parent | 3f762ef111a69ff7c7cf08a23c3769aa8ada1945 (diff) | |
download | bcm5719-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.cpp | 45 |
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); } |