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

Reply via email to