Index: cfe/trunk/lib/CodeGen/CGCall.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGCall.cpp +++ cfe/trunk/lib/CodeGen/CGCall.cpp @@ -2728,6 +2728,24 @@ args.add(EmitAnyExprToTemp(E), type); } +QualType CodeGenFunction::getVarArgType(const Expr *Arg) { + // System headers on Windows define NULL to 0 instead of 0LL on Win64. MSVC + // implicitly widens null pointer constants that are arguments to varargs + // functions to pointer-sized ints. + if (!getTarget().getTriple().isOSWindows()) + return Arg->getType(); + + if (Arg->getType()->isIntegerType() && + getContext().getTypeSize(Arg->getType()) < + getContext().getTargetInfo().getPointerWidth(0) && + Arg->isNullPointerConstant(getContext(), + Expr::NPC_ValueDependentIsNotNull)) { + return getContext().getIntPtrType(); + } + + return Arg->getType(); +} + // In ObjC ARC mode with no ObjC ARC exception safety, tell the ARC // optimizer it can aggressively ignore unwind edges. void @@ -3023,6 +3041,11 @@ else V = Builder.CreateLoad(RV.getAggregateAddr()); + // We might have to widen integers, but we should never truncate. + if (ArgInfo.getCoerceToType() != V->getType() && + V->getType()->isIntegerTy()) + V = Builder.CreateZExt(V, ArgInfo.getCoerceToType()); + // If the argument doesn't match, perform a bitcast to coerce it. This // can happen due to trivial type mismatches. if (FirstIRArg < IRFuncTy->getNumParams() && Index: cfe/trunk/lib/CodeGen/CodeGenFunction.h =================================================================== --- cfe/trunk/lib/CodeGen/CodeGenFunction.h +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h @@ -2752,7 +2752,7 @@ // If we still have any arguments, emit them using the type of the argument. for (; Arg != ArgEnd; ++Arg) - ArgTypes.push_back(Arg->getType()); + ArgTypes.push_back(getVarArgType(*Arg)); EmitCallArgs(Args, ArgTypes, ArgBeg, ArgEnd, CalleeDecl, ParamsToSkip, ForceColumnInfo); @@ -2765,6 +2765,8 @@ unsigned ParamsToSkip = 0, bool ForceColumnInfo = false); private: + QualType getVarArgType(const Expr *Arg); + const TargetCodeGenInfo &getTargetHooks() const { return CGM.getTargetCodeGenInfo(); } Index: cfe/trunk/test/CodeGen/variadic-null-win64.c =================================================================== --- cfe/trunk/test/CodeGen/variadic-null-win64.c +++ cfe/trunk/test/CodeGen/variadic-null-win64.c @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - -triple x86_64-windows-msvc | FileCheck %s --check-prefix=WINDOWS +// RUN: %clang_cc1 %s -emit-llvm -o - -triple x86_64-linux | FileCheck %s --check-prefix=LINUX + +// Make it possible to pass NULL through variadic functions on platforms where +// NULL has an integer type that is more narrow than a pointer. On such +// platforms we widen null pointer constants to a pointer-sized integer. + +#define NULL 0 + +void v(const char *f, ...); +void f(const char *f) { + v(f, 1, 2, 3, NULL); +} +// WINDOWS: define void @f(i8* %f) +// WINDOWS: call void (i8*, ...)* @v(i8* {{.*}}, i32 1, i32 2, i32 3, i64 0) +// LINUX: define void @f(i8* %f) +// LINUX: call void (i8*, ...)* @v(i8* {{.*}}, i32 1, i32 2, i32 3, i32 0)