tambre updated this revision to Diff 265850. tambre marked 5 inline comments as done. tambre added a comment.
Handle multiple parameter packs interleaved with default values. Mark DR777 as superseded by DR2233. Mark DR2233 as resolved. Moved tests from dr7xx.cpp to dr22xx.cpp. Added note in dr7xx.cpp about DR777 being superseded. Add more tests that cover bugs observed in other implementations and the deficiency in my first implementation. 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/dr22xx.cpp clang/test/CXX/drs/dr7xx.cpp clang/www/cxx_dr_status.html
Index: clang/www/cxx_dr_status.html =================================================================== --- clang/www/cxx_dr_status.html +++ clang/www/cxx_dr_status.html @@ -4681,7 +4681,7 @@ <td><a href="https://wg21.link/cwg777">777</a></td> <td>CD2</td> <td>Default arguments and parameter packs</td> - <td class="full" align="center">Clang 3.7</td> + <td class="full" align="center">Superseded by <a href="#2233">2233</a></td> </tr> <tr id="778"> <td><a href="https://wg21.link/cwg778">778</a></td> @@ -13213,7 +13213,7 @@ <td><a href="https://wg21.link/cwg2233">2233</a></td> <td>DRWP</td> <td>Function parameter packs following default arguments</td> - <td class="none" align="center">Unknown</td> + <td class="full" align="center">Clang 11</td> </tr> <tr id="2234"> <td><a href="https://wg21.link/cwg2234">2234</a></td> Index: clang/test/CXX/drs/dr7xx.cpp =================================================================== --- clang/test/CXX/drs/dr7xx.cpp +++ clang/test/CXX/drs/dr7xx.cpp @@ -219,16 +219,4 @@ Collision<int, int> c; // expected-note {{in instantiation of}} } -namespace dr777 { // dr777: 3.7 -#if __cplusplus >= 201103L -template <typename... T> -void f(int i = 0, T ...args) {} -void ff() { f(); } - -template <typename... T> -void g(int i = 0, T ...args, T ...args2) {} - -template <typename... T> -void h(int i = 0, T ...args, int j = 1) {} -#endif -} +// dr777 superseded by dr2233 Index: clang/test/CXX/drs/dr22xx.cpp =================================================================== --- clang/test/CXX/drs/dr22xx.cpp +++ clang/test/CXX/drs/dr22xx.cpp @@ -35,3 +35,44 @@ } #endif } + +namespace dr2233 { // dr2233: 11 +#if __cplusplus >= 201103L +template <typename... T> +void f(int i = 0, T... args) {} + +template <typename... T> +void g(int i = 0, T... args, T... args2) {} + +template <typename... T> +void h(int i = 0, T... args, int j = 1) {} + +template <typename... T, typename... U> +void i(int i = 0, T... args, int j = 1, U... args2) {} + +template <class... Ts> +void j(int i = 0, Ts... ts) {} + +template <> +void j<int>(int i, int j) {} + +// PR23029 +// Ensure instantiating the templates works. +void use() { + f(); + f(0, 1); + f<int>(1, 2); + g<int>(1, 2, 3); + h(0, 1); + i(); + i(3); + i<int>(3, 2); + i<int>(3, 2, 1); + i<int, int>(1, 2, 3, 4, 5); + j(); + j(1); + j(1, 2); + j<int>(1, 2); +} +#endif +} // namespace dr2233 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); + + // 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<unsigned> 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
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits