diff options
Diffstat (limited to 'clang/lib/CodeGen/CGExpr.cpp')
-rw-r--r-- | clang/lib/CodeGen/CGExpr.cpp | 32 |
1 files changed, 30 insertions, 2 deletions
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index f4c552b0850..62be62b79ed 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -18,6 +18,7 @@ #include "CGDebugInfo.h" #include "CGRecordLayout.h" #include "CGObjCRuntime.h" +#include "TargetInfo.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/Frontend/CodeGenOptions.h" @@ -2414,8 +2415,35 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee, CallArgList Args; EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), ArgBeg, ArgEnd); - return EmitCall(CGM.getTypes().getFunctionInfo(Args, FnType), - Callee, ReturnValue, Args, TargetDecl); + const CGFunctionInfo &FnInfo = CGM.getTypes().getFunctionInfo(Args, FnType); + + // C99 6.5.2.2p6: + // If the expression that denotes the called function has a type + // that does not include a prototype, [the default argument + // promotions are performed]. If the number of arguments does not + // equal the number of parameters, the behavior is undefined. If + // the function is defined with a type that includes a prototype, + // and either the prototype ends with an ellipsis (, ...) or the + // types of the arguments after promotion are not compatible with + // the types of the parameters, the behavior is undefined. If the + // function is defined with a type that does not include a + // prototype, and the types of the arguments after promotion are + // not compatible with those of the parameters after promotion, + // the behavior is undefined [except in some trivial cases]. + // That is, in the general case, we should assume that a call + // through an unprototyped function type works like a *non-variadic* + // call. The way we make this work is to cast to the exact type + // of the promoted arguments. + if (isa<FunctionNoProtoType>(FnType) && + !getTargetHooks().isNoProtoCallVariadic(FnType->getCallConv())) { + assert(cast<llvm::FunctionType>(Callee->getType()->getContainedType(0)) + ->isVarArg()); + llvm::Type *CalleeTy = getTypes().GetFunctionType(FnInfo, false); + CalleeTy = CalleeTy->getPointerTo(); + Callee = Builder.CreateBitCast(Callee, CalleeTy, "callee.knr.cast"); + } + + return EmitCall(FnInfo, Callee, ReturnValue, Args, TargetDecl); } LValue CodeGenFunction:: |