ychen created this revision.
ychen added reviewers: aaron.ballman, erichkeane.
Herald added a project: All.
ychen requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

D128745 <https://reviews.llvm.org/D128745> handled DR1432 for the partial 
ordering of partial specializations, but
missed the handling for the partial ordering of function templates. This patch
implements the latter. While at it, also simplies the previous implementation to
be more close the wording without funtional changes.

Fixes https://github.com/llvm/llvm-project/issues/56090


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D133683

Files:
  clang/lib/Sema/SemaTemplateDeduction.cpp
  clang/test/CXX/drs/dr6xx.cpp

Index: clang/test/CXX/drs/dr6xx.cpp
===================================================================
--- clang/test/CXX/drs/dr6xx.cpp
+++ clang/test/CXX/drs/dr6xx.cpp
@@ -1083,13 +1083,18 @@
   // Also see dr1395.
 
   namespace temp_func_order_example2 {
-    template <typename T, typename U> struct A {};
-    template <typename T, typename U> void f(U, A<U, T> *p = 0); // expected-note {{candidate}}
+    template <typename... T> struct A {}; // expected-error 0-1{{C++11}}
+    template <class T1, class... U> void e(A<T1, U...>) = delete; // expected-error 0-2{{C++11}}
+    template <class T1> void e(A<T1>);
+    template <typename T, typename U> void f(U, A<U, T> *p = 0) = delete; // expected-note {{candidate}} expected-error 0-1{{C++11}}
     template <typename U> int &f(U, A<U, U> *p = 0); // expected-note {{candidate}}
     template <typename T> void g(T, T = T()); // expected-note {{candidate}}
     template <typename T, typename... U> void g(T, U...); // expected-note {{candidate}} expected-error 0-1{{C++11}}
     void h() {
-      int &r = f<int>(42, (A<int, int> *)0);
+      A<int, int> a;
+      int &r = f<int>(42, &a);
+      A<int> b;
+      e(b);
       f<int>(42); // expected-error {{ambiguous}}
       g(42); // expected-error {{ambiguous}}
     }
Index: clang/lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateDeduction.cpp
+++ clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -5187,6 +5187,32 @@
       return FT1;
   }
 
+  // Consider this a fix for CWG1432. Similar to the fix for CWG1395.
+  bool ClangABICompat15 =
+      Context.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver15;
+  if (!ClangABICompat15) {
+    for (int i = 0, e = std::min(NumParams1, NumParams2); i < e; ++i) {
+      QualType T1 = FD1->getParamDecl(i)->getType().getDesugaredType(Context);
+      QualType T2 = FD2->getParamDecl(i)->getType().getDesugaredType(Context);
+      auto *TST1 = dyn_cast<TemplateSpecializationType>(T1);
+      auto *TST2 = dyn_cast<TemplateSpecializationType>(T2);
+      if (TST1 && TST2) {
+        unsigned NumArgs1 = TST1->getNumArgs();
+        unsigned NumArgs2 = TST2->getNumArgs();
+        bool IsPackExpansion1 =
+            NumArgs1 && TST1->template_arguments().back().isPackExpansion();
+        bool IsPackExpansion2 =
+            NumArgs2 && TST2->template_arguments().back().isPackExpansion();
+        if (NumArgs1 != NumArgs2 && IsPackExpansion1 != IsPackExpansion2) {
+          if (NumArgs1 > NumArgs2 && IsPackExpansion1)
+            return FT2;
+          if (NumArgs1 < NumArgs2 && IsPackExpansion2)
+            return FT1;
+        }
+      }
+    }
+  }
+
   return JudgeByConstraints();
 }
 
@@ -5422,31 +5448,29 @@
     return nullptr;
 
   if (Better1 && Better2) {
+    // Consider this a fix for CWG1432. Similar to the fix for CWG1395.
     bool ClangABICompat15 = S.Context.getLangOpts().getClangABICompat() <=
                             LangOptions::ClangABI::Ver15;
     if (!ClangABICompat15) {
-      // Consider this a fix for CWG1432. Similar to the fix for CWG1395.
       auto *TST1 = T1->castAs<TemplateSpecializationType>();
       auto *TST2 = T2->castAs<TemplateSpecializationType>();
-      if (TST1->getNumArgs()) {
-        const TemplateArgument &TA1 = TST1->template_arguments().back();
-        if (TA1.getKind() == TemplateArgument::Pack) {
-          assert(TST1->getNumArgs() == TST2->getNumArgs());
-          const TemplateArgument &TA2 = TST2->template_arguments().back();
-          assert(TA2.getKind() == TemplateArgument::Pack);
-          unsigned PackSize1 = TA1.pack_size();
-          unsigned PackSize2 = TA2.pack_size();
-          bool IsPackExpansion1 =
-              PackSize1 && TA1.pack_elements().back().isPackExpansion();
-          bool IsPackExpansion2 =
-              PackSize2 && TA2.pack_elements().back().isPackExpansion();
-          if (PackSize1 != PackSize2 && IsPackExpansion1 != IsPackExpansion2) {
-            if (PackSize1 > PackSize2 && IsPackExpansion1)
-              return GetP2()(P1, P2);
-            if (PackSize1 < PackSize2 && IsPackExpansion2)
-              return P1;
-          }
-        }
+      const TemplateArgument &TA1 = TST1->template_arguments().back();
+      const TemplateArgument &TA2 = TST2->template_arguments().back();
+      unsigned PackSize1 =
+          TA1.getKind() == TemplateArgument::Pack ? TA1.pack_size() : 0u;
+      unsigned PackSize2 =
+          TA2.getKind() == TemplateArgument::Pack ? TA2.pack_size() : 0u;
+      bool IsPackExpansion1 =
+          PackSize1 && TA1.pack_elements().back().isPackExpansion();
+      bool IsPackExpansion2 =
+          PackSize2 && TA2.pack_elements().back().isPackExpansion();
+      unsigned NumArgs1 = TST1->getNumArgs() + PackSize1;
+      unsigned NumArgs2 = TST2->getNumArgs() + PackSize2;
+      if (NumArgs1 != NumArgs2 && IsPackExpansion1 != IsPackExpansion2) {
+        if (NumArgs1 > NumArgs2 && IsPackExpansion1)
+          return GetP2()(P1, P2);
+        if (NumArgs1 < NumArgs2 && IsPackExpansion2)
+          return P1;
       }
     }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to