tambre updated this revision to Diff 263759. tambre added a comment. Simplify code, improve comments.
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D79800/new/ https://reviews.llvm.org/D79800 Files: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp clang/test/CXX/drs/dr7xx.cpp Index: clang/test/CXX/drs/dr7xx.cpp =================================================================== --- clang/test/CXX/drs/dr7xx.cpp +++ clang/test/CXX/drs/dr7xx.cpp @@ -230,5 +230,12 @@ template <typename... T> void h(int i = 0, T ...args, int j = 1) {} + +// PR23029 +// Ensure passing parameters using the parameter packs actually works. +void use() { + f(0, 1); + h(0, 1); +} #endif } Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1974,6 +1974,47 @@ TemplateArgumentList::CreateCopy(SemaRef.Context, Innermost), /*InsertPos=*/nullptr); + + // Parameter packs are allowed after parameters with default values. + // If the specialized Function has more parameters than the TemplatedDecl + // then the default values aren't used and the parameter pack is used and we + // need to remove default values from non-pack parameters to prevent it + // being diagnosed as invalid code due to the expanded parameters lacking + // default values. + FunctionDecl *TemplatedDecl = FunctionTemplate->getTemplatedDecl(); + unsigned NumTemplatedParams = TemplatedDecl->getNumParams(); + + if (Function->getNumParams() >= NumTemplatedParams) { + unsigned FirstDefault = 0; + bool FoundDefault = false; + + for (unsigned p = 0; p < NumTemplatedParams; ++p) { + ParmVarDecl *Param = TemplatedDecl->getParamDecl(p); + + if (FoundDefault) { + if (Param->isParameterPack()) { + // Found a parameter pack. Remove default arguments for all + // parameters prior to this since we now know this is valid code + // without them. + for (unsigned d = FirstDefault; d < p; ++d) { + ParmVarDecl *Param = Function->getParamDecl(d); + Param->setDefaultArg(nullptr); + } + + break; + } + + // If we encounter a regular parameter with no default value after + // we've encountered any with a default, then this is invalid code and + // we bail out. This is diagnosed later in CheckCXXDefaultArguments(). + if (!Param->hasDefaultArg()) + break; + } else if (Param->hasDefaultArg()) { + FirstDefault = p; + FoundDefault = true; + } + } + } } else if (isFriend && D->isThisDeclarationADefinition()) { // Do not connect the friend to the template unless it's actually a // definition. We don't want non-template functions to be marked as being
Index: clang/test/CXX/drs/dr7xx.cpp =================================================================== --- clang/test/CXX/drs/dr7xx.cpp +++ clang/test/CXX/drs/dr7xx.cpp @@ -230,5 +230,12 @@ template <typename... T> void h(int i = 0, T ...args, int j = 1) {} + +// PR23029 +// Ensure passing parameters using the parameter packs actually works. +void use() { + f(0, 1); + h(0, 1); +} #endif } Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1974,6 +1974,47 @@ TemplateArgumentList::CreateCopy(SemaRef.Context, Innermost), /*InsertPos=*/nullptr); + + // Parameter packs are allowed after parameters with default values. + // If the specialized Function has more parameters than the TemplatedDecl + // then the default values aren't used and the parameter pack is used and we + // need to remove default values from non-pack parameters to prevent it + // being diagnosed as invalid code due to the expanded parameters lacking + // default values. + FunctionDecl *TemplatedDecl = FunctionTemplate->getTemplatedDecl(); + unsigned NumTemplatedParams = TemplatedDecl->getNumParams(); + + if (Function->getNumParams() >= NumTemplatedParams) { + unsigned FirstDefault = 0; + bool FoundDefault = false; + + for (unsigned p = 0; p < NumTemplatedParams; ++p) { + ParmVarDecl *Param = TemplatedDecl->getParamDecl(p); + + if (FoundDefault) { + if (Param->isParameterPack()) { + // Found a parameter pack. Remove default arguments for all + // parameters prior to this since we now know this is valid code + // without them. + for (unsigned d = FirstDefault; d < p; ++d) { + ParmVarDecl *Param = Function->getParamDecl(d); + Param->setDefaultArg(nullptr); + } + + break; + } + + // If we encounter a regular parameter with no default value after + // we've encountered any with a default, then this is invalid code and + // we bail out. This is diagnosed later in CheckCXXDefaultArguments(). + if (!Param->hasDefaultArg()) + break; + } else if (Param->hasDefaultArg()) { + FirstDefault = p; + FoundDefault = true; + } + } + } } else if (isFriend && D->isThisDeclarationADefinition()) { // Do not connect the friend to the template unless it's actually a // definition. We don't want non-template functions to be marked as being
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits