Index: include/clang/CodeGen/CGFunctionInfo.h =================================================================== --- include/clang/CodeGen/CGFunctionInfo.h +++ include/clang/CodeGen/CGFunctionInfo.h @@ -16,8 +16,10 @@ #ifndef LLVM_CLANG_CODEGEN_CGFUNCTIONINFO_H #define LLVM_CLANG_CODEGEN_CGFUNCTIONINFO_H +#include "clang/AST/Attr.h" #include "clang/AST/CanonicalType.h" #include "clang/AST/CharUnits.h" +#include "clang/AST/Decl.h" #include "clang/AST/Type.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/ADT/FoldingSet.h" @@ -25,8 +27,6 @@ #include namespace clang { -class Decl; - namespace CodeGen { /// ABIArgInfo - Helper class to encapsulate information about how a @@ -393,23 +393,34 @@ /// Compute the arguments required by the given formal prototype, /// given that there may be some additional, non-formal arguments /// in play. + /// + /// If FD is not null, this will consider pass_object_size params in FD. static RequiredArgs forPrototypePlus(const FunctionProtoType *prototype, - unsigned additional) { + unsigned additional, + const FunctionDecl *FD) { if (!prototype->isVariadic()) return All; + if (FD) + additional += std::count_if(FD->param_begin(), FD->param_end(), + [](const ParmVarDecl *PVD) { + return PVD->hasAttr(); + }); return RequiredArgs(prototype->getNumParams() + additional); } - static RequiredArgs forPrototype(const FunctionProtoType *prototype) { - return forPrototypePlus(prototype, 0); + static RequiredArgs forPrototype(const FunctionProtoType *prototype, + const FunctionDecl *FD) { + return forPrototypePlus(prototype, 0, FD); } - static RequiredArgs forPrototype(CanQual prototype) { - return forPrototype(prototype.getTypePtr()); + static RequiredArgs forPrototype(CanQual prototype, + const FunctionDecl *FD) { + return forPrototype(prototype.getTypePtr(), FD); } static RequiredArgs forPrototypePlus(CanQual prototype, - unsigned additional) { - return forPrototypePlus(prototype.getTypePtr(), additional); + unsigned additional, + const FunctionDecl *FD) { + return forPrototypePlus(prototype.getTypePtr(), additional, FD); } bool allowsOptionalArgs() const { return NumRequired != ~0U; } Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -139,7 +139,8 @@ CanQual FTP, const FunctionDecl *FD) { SmallVector paramInfos; - RequiredArgs required = RequiredArgs::forPrototypePlus(FTP, prefix.size()); + RequiredArgs Required = + RequiredArgs::forPrototypePlus(FTP, prefix.size(), FD); // FIXME: Kill copy. appendParameterTypes(CGT, prefix, paramInfos, FTP, FD); CanQualType resultType = FTP->getReturnType().getUnqualifiedType(); @@ -147,7 +148,7 @@ return CGT.arrangeLLVMFunctionInfo(resultType, instanceMethod, /*chainCall=*/false, prefix, FTP->getExtInfo(), paramInfos, - required); + Required); } /// Arrange the argument and result information for a value of the @@ -336,7 +337,7 @@ ArgTypes.push_back(Context.getCanonicalParamType(Arg.Ty)); CanQual FPT = GetFormalType(D); - RequiredArgs Required = RequiredArgs::forPrototypePlus(FPT, 1 + ExtraArgs); + RequiredArgs Required = RequiredArgs::forPrototypePlus(FPT, 1 + ExtraArgs, D); GlobalDecl GD(D, CtorKind); CanQualType ResultType = TheCXXABI.HasThisReturn(GD) ? ArgTypes.front() @@ -553,10 +554,11 @@ auto paramInfos = getExtParameterInfosForCall(proto, 1, params.size()); auto argTypes = getArgTypesForDeclaration(Context, params); - return arrangeLLVMFunctionInfo(GetReturnType(proto->getReturnType()), - /*instanceMethod*/ false, /*chainCall*/ false, - argTypes, proto->getExtInfo(), paramInfos, - RequiredArgs::forPrototypePlus(proto, 1)); + return arrangeLLVMFunctionInfo( + GetReturnType(proto->getReturnType()), + /*instanceMethod*/ false, /*chainCall*/ false, argTypes, + proto->getExtInfo(), paramInfos, + RequiredArgs::forPrototypePlus(proto, 1, nullptr)); } const CGFunctionInfo & Index: lib/CodeGen/CGExprCXX.cpp =================================================================== --- lib/CodeGen/CGExprCXX.cpp +++ lib/CodeGen/CGExprCXX.cpp @@ -54,7 +54,9 @@ } const FunctionProtoType *FPT = MD->getType()->castAs(); - RequiredArgs required = RequiredArgs::forPrototypePlus(FPT, Args.size()); + // Don't pass in the MethodDecl, because we should already have the + // pass_object_size values in the arglist. + RequiredArgs required = RequiredArgs::forPrototypePlus(FPT, Args.size(), MD); // And the rest of the call args. if (CE) { @@ -323,8 +325,7 @@ // Push the this ptr. Args.add(RValue::get(ThisPtrForCall), ThisType); - - RequiredArgs required = RequiredArgs::forPrototypePlus(FPT, 1); + RequiredArgs required = RequiredArgs::forPrototypePlus(FPT, 1, nullptr); // And the rest of the call args EmitCallArgs(Args, FPT, E->arguments(), E->getDirectCallee()); Index: lib/CodeGen/CGVTables.cpp =================================================================== --- lib/CodeGen/CGVTables.cpp +++ lib/CodeGen/CGVTables.cpp @@ -292,9 +292,8 @@ const FunctionProtoType *FPT = MD->getType()->getAs(); #ifndef NDEBUG - const CGFunctionInfo &CallFnInfo = - CGM.getTypes().arrangeCXXMethodCall(CallArgs, FPT, - RequiredArgs::forPrototypePlus(FPT, 1)); + const CGFunctionInfo &CallFnInfo = CGM.getTypes().arrangeCXXMethodCall( + CallArgs, FPT, RequiredArgs::forPrototypePlus(FPT, 1, MD)); assert(CallFnInfo.getRegParm() == CurFnInfo->getRegParm() && CallFnInfo.isNoReturn() == CurFnInfo->isNoReturn() && CallFnInfo.getCallingConvention() == CurFnInfo->getCallingConvention()); Index: test/CodeGen/pass-object-size.c =================================================================== --- test/CodeGen/pass-object-size.c +++ test/CodeGen/pass-object-size.c @@ -351,3 +351,18 @@ ObjectSize0(++p); ObjectSize0(p++); } + +// There was a bug where variadic functions with pass_object_size would cause +// problems in the form of failed assertions. +void my_sprintf(char *const c __attribute__((pass_object_size(0))), ...) {} + +// CHECK-LABEL: define void @test14 +void test14(char *c) { + // CHECK: @llvm.objectsize + // CHECK: call void (i8*, i64, ...) @my_sprintf + my_sprintf(c); + + // CHECK: @llvm.objectsize + // CHECK: call void (i8*, i64, ...) @my_sprintf + my_sprintf(c, 1, 2, 3); +} Index: test/CodeGenCXX/pass-object-size.cpp =================================================================== --- test/CodeGenCXX/pass-object-size.cpp +++ test/CodeGenCXX/pass-object-size.cpp @@ -43,3 +43,30 @@ (&OvlFoo)(nullptr); } } + +namespace variadic { +// We had an issue where variadic member/operator calls with pass_object_size +// would cause crashes. + +struct AsCtor { + AsCtor(const char *const c __attribute__((pass_object_size(0))), double a, + ...) {} +}; + +struct AsMember { + void bar(const char *const c __attribute__((pass_object_size(0))), double a, + ...) {} + void operator()(const char *const c __attribute__((pass_object_size(0))), + double a, ...) {} +}; + +// CHECK-LABEL: define void @_ZN8variadic4testEv() +void test() { + // CHECK-RE: call{{[^@]+}}@_ZN8variadic6AsCtorC1EPKcU17pass_object_size0dz + AsCtor("a", 1.0); + // CHECK-RE: call{{[^@]+}}@_ZN8variadic8AsMember3barEPKcU17pass_object_size0dz + AsMember{}.bar("a", 1.0); + // CHECK-RE: call{{[^@]+}}@_ZN8variadic8AsMemberclEPKcU17pass_object_size0dz + AsMember{}("a", 1.0); +} +}