Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -96,27 +96,36 @@ /// Adds the formal paramaters in FPT to the given prefix. If any parameter in /// FPT has pass_object_size attrs, then we'll add parameters for those, too. +/// +/// If NumSynthesizedParams is non-null, the number of pass_object_size +/// parameters that we encounter will be stored in it. static void appendParameterTypes(const CodeGenTypes &CGT, SmallVectorImpl &prefix, const CanQual &FPT, - const FunctionDecl *FD) { - // Fast path: unknown target. - if (FD == nullptr) { + const FunctionDecl *FD, + unsigned *NumSynthesizedParams = nullptr) { + unsigned NumPassObjSizeParams = 0; + if (!FD) { + // Fast path: unknown target. prefix.append(FPT->param_type_begin(), FPT->param_type_end()); - return; + } else { + // In the vast majority of cases, we'll have precisely FPT->getNumParams() + // parameters; the only thing that can change this is the presence of + // pass_object_size. So, we preallocate for the common case. + prefix.reserve(prefix.size() + FPT->getNumParams()); + + assert(FD->getNumParams() == FPT->getNumParams()); + for (unsigned I = 0, E = FPT->getNumParams(); I != E; ++I) { + prefix.push_back(FPT->getParamType(I)); + if (FD->getParamDecl(I)->hasAttr()) { + ++NumPassObjSizeParams; + prefix.push_back(CGT.getContext().getSizeType()); + } + } } - // In the vast majority cases, we'll have precisely FPT->getNumParams() - // parameters; the only thing that can change this is the presence of - // pass_object_size. So, we preallocate for the common case. - prefix.reserve(prefix.size() + FPT->getNumParams()); - - assert(FD->getNumParams() == FPT->getNumParams()); - for (unsigned I = 0, E = FPT->getNumParams(); I != E; ++I) { - prefix.push_back(FPT->getParamType(I)); - if (FD->getParamDecl(I)->hasAttr()) - prefix.push_back(CGT.getContext().getSizeType()); - } + if (NumSynthesizedParams) + *NumSynthesizedParams = NumPassObjSizeParams; } /// Arrange the LLVM function layout for a value of the given function @@ -126,13 +135,16 @@ SmallVectorImpl &prefix, CanQual FTP, const FunctionDecl *FD) { - RequiredArgs required = RequiredArgs::forPrototypePlus(FTP, prefix.size()); + unsigned StartParams = prefix.size(); + unsigned SynthesizedParams; // FIXME: Kill copy. - appendParameterTypes(CGT, prefix, FTP, FD); + appendParameterTypes(CGT, prefix, FTP, FD, &SynthesizedParams); + RequiredArgs Required = + RequiredArgs::forPrototypePlus(FTP, StartParams + SynthesizedParams); CanQualType resultType = FTP->getReturnType().getUnqualifiedType(); return CGT.arrangeLLVMFunctionInfo(resultType, instanceMethod, /*chainCall=*/false, prefix, - FTP->getExtInfo(), required); + FTP->getExtInfo(), Required); } /// Arrange the argument and result information for a value of the 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); +}