diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp old mode 100755 new mode 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1974,6 +1974,47 @@ TemplateArgumentList::CreateCopy(SemaRef.Context, Innermost), /*InsertPos=*/nullptr); + + // DR777, DR2233. + // Parameter packs are allowed after and inbetween parameters with default + // values. We need to remove default arguments for parameters before the + // first expanded parameter pack to prevent prevent it being diagnosed as + // invalid code due to the expanded parameters lacking default values. This + // is safe to do because if a parameter pack is expanded the user must've + // provided arguments for all parameters before it. + FunctionDecl *TemplatedDecl = FunctionTemplate->getTemplatedDecl(); + unsigned FirstPack = Function->getNumParams(); + bool RemoveDefaults = false; + + // Go backwards through the template declaration parameters and find the + // first parameter pack, which has non-zero number of arguments. + for (unsigned p = TemplatedDecl->getNumParams(); p-- > 0;) { + ParmVarDecl *Param = TemplatedDecl->getParamDecl(p); + + if (Param->isParameterPack()) { + llvm::Optional Args = + SemaRef.getNumArgumentsInExpansion(Param->getType(), TemplateArgs); + assert(Args != None && "Unknown number of pack expansion arguments."); + + if (Args.getValue() == 0) + continue; + + FirstPack -= Args.getValue(); + RemoveDefaults = true; + break; + } else { + FirstPack--; + } + } + + // If we found such a parameter pack, then remove default arguments for all + // parameters before it. + if (RemoveDefaults) { + for (unsigned p = 0; p < FirstPack; p++) { + ParmVarDecl *Param = Function->getParamDecl(p); + Param->setDefaultArg(nullptr); + } + } } 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 diff --git a/clang/test/CXX/drs/dr22xx.cpp b/clang/test/CXX/drs/dr22xx.cpp --- a/clang/test/CXX/drs/dr22xx.cpp +++ b/clang/test/CXX/drs/dr22xx.cpp @@ -35,3 +35,44 @@ } #endif } + +namespace dr2233 { // dr2233: 11 +#if __cplusplus >= 201103L +template +void f(int i = 0, T... args) {} + +template +void g(int i = 0, T... args, T... args2) {} + +template +void h(int i = 0, T... args, int j = 1) {} + +template +void i(int i = 0, T... args, int j = 1, U... args2) {} + +template +void j(int i = 0, Ts... ts) {} + +template <> +void j(int i, int j) {} + +// PR23029 +// Ensure instantiating the templates works. +void use() { + f(); + f(0, 1); + f(1, 2); + g(1, 2, 3); + h(0, 1); + i(); + i(3); + i(3, 2); + i(3, 2, 1); + i(1, 2, 3, 4, 5); + j(); + j(1); + j(1, 2); + j(1, 2); +} +#endif +} // namespace dr2233 diff --git a/clang/test/CXX/drs/dr7xx.cpp b/clang/test/CXX/drs/dr7xx.cpp --- a/clang/test/CXX/drs/dr7xx.cpp +++ b/clang/test/CXX/drs/dr7xx.cpp @@ -219,16 +219,4 @@ Collision c; // expected-note {{in instantiation of}} } -namespace dr777 { // dr777: 3.7 -#if __cplusplus >= 201103L -template -void f(int i = 0, T ...args) {} -void ff() { f(); } - -template -void g(int i = 0, T ...args, T ...args2) {} - -template -void h(int i = 0, T ...args, int j = 1) {} -#endif -} +// dr777 superseded by dr2233 diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -4681,7 +4681,7 @@ 777 CD2 Default arguments and parameter packs - Clang 3.7 + Superseded by 2233 778 @@ -13213,7 +13213,7 @@ 2233 DRWP Function parameter packs following default arguments - Unknown + Clang 11 2234