[clang] 1fb728e - [c++] implements tentative DR1432 for partial ordering of function template

Yuanfang Chen via cfe-commits cfe-commits at lists.llvm.org
Mon Oct 3 16:31:18 PDT 2022


Author: Yuanfang Chen
Date: 2022-10-03T16:30:27-07:00
New Revision: 1fb728e95c74bf72698c00094f18fa8d2eb42cda

URL: https://github.com/llvm/llvm-project/commit/1fb728e95c74bf72698c00094f18fa8d2eb42cda
DIFF: https://github.com/llvm/llvm-project/commit/1fb728e95c74bf72698c00094f18fa8d2eb42cda.diff

LOG: [c++] implements tentative DR1432 for partial ordering of function template

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 simplifies the previous implementation to
be more close to the wording without functional changes.

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

Reviewed By: erichkeane, #clang-language-wg, mizvekov

Differential Revision: https://reviews.llvm.org/D133683

Added: 
    clang/test/SemaCXX/pre-dr692.cpp

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/Sema/SemaTemplateDeduction.cpp
    clang/test/CXX/drs/dr6xx.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 2320f4a7a4fa..d113d9b450b7 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -363,7 +363,9 @@ C2x Feature Support
 C++ Language Changes in Clang
 -----------------------------
 - Implemented DR692, DR1395 and DR1432. Use the ``-fclang-abi-compat=15`` option
-  to get the old partial ordering behavior regarding packs.
+  to get the old partial ordering behavior regarding packs. Note that the fix for
+  DR1432 is speculative that there is no wording or even resolution for this issue.
+  A speculative fix for DR1432 is needed because it fixes regressions caused by DR692.
 - Clang's default C++/ObjC++ standard is now ``gnu++17`` instead of ``gnu++14``.
   This means Clang will by default accept code using features from C++17 and
   conforming GNU extensions. Projects incompatible with C++17 can add

diff  --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 6ddbd9055870..e3301081da55 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -5222,6 +5222,39 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
       return FT1;
   }
 
+  // This a speculative fix for CWG1432 (Similar to the fix for CWG1395) that
+  // there is no wording or even resolution for this issue.
+  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().getCanonicalType();
+      QualType T2 = FD2->getParamDecl(i)->getType().getCanonicalType();
+      auto *TST1 = dyn_cast<TemplateSpecializationType>(T1);
+      auto *TST2 = dyn_cast<TemplateSpecializationType>(T2);
+      if (!TST1 || !TST2)
+        continue;
+      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 FT2;
+          if (PackSize1 < PackSize2 && IsPackExpansion2)
+            return FT1;
+        }
+      }
+    }
+  }
+
   return JudgeByConstraints();
 }
 
@@ -5457,30 +5490,29 @@ getMoreSpecialized(Sema &S, QualType T1, QualType T2, TemplateLikeDecl *P1,
     return nullptr;
 
   if (Better1 && Better2) {
+    // This a speculative fix for CWG1432 (Similar to the fix for CWG1395) that
+    // there is no wording or even resolution for this issue.
     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;
-          }
+      auto *TST1 = cast<TemplateSpecializationType>(T1);
+      auto *TST2 = cast<TemplateSpecializationType>(T2);
+      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;
         }
       }
     }

diff  --git a/clang/test/CXX/drs/dr6xx.cpp b/clang/test/CXX/drs/dr6xx.cpp
index 8c0da27e78c9..6e61b56555b2 100644
--- a/clang/test/CXX/drs/dr6xx.cpp
+++ b/clang/test/CXX/drs/dr6xx.cpp
@@ -1083,13 +1083,23 @@ namespace dr692 { // dr692: no
   // 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 U> int &f(U, A<U, U> *p = 0); // expected-note {{candidate}}
+    template <typename... T> struct A1 {}; // expected-error 0-1{{C++11}}
+    template <typename U, typename... T> struct A2 {}; // expected-error 0-1{{C++11}}
+    template <class T1, class... U> void e1(A1<T1, U...>) = delete; // expected-error 0-2{{C++11}}
+    template <class T1> void e1(A1<T1>);
+    template <class T1, class... U> void e2(A2<T1, U...>) = delete; // expected-error 0-2{{C++11}}
+    template <class T1> void e2(A2<T1>);
+    template <typename T, typename U> void f(U, A1<U, T> *p = 0) = delete; // expected-note {{candidate}} expected-error 0-1{{C++11}}
+    template <typename U> int &f(U, A1<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);
+      A1<int, int> a;
+      int &r = f<int>(42, &a);
+      A1<int> b1;
+      e1(b1);
+      A2<int> b2;
+      e2(b2);
       f<int>(42); // expected-error {{ambiguous}}
       g(42); // expected-error {{ambiguous}}
     }

diff  --git a/clang/test/SemaCXX/pre-dr692.cpp b/clang/test/SemaCXX/pre-dr692.cpp
new file mode 100644
index 000000000000..87eac318dc06
--- /dev/null
+++ b/clang/test/SemaCXX/pre-dr692.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 %s -std=c++11 -verify -fexceptions -fcxx-exceptions -pedantic-errors -fno-spell-checking -fclang-abi-compat=15
+
+template <typename... T> struct A1 {};
+template <typename U, typename... T> struct A2 {};
+template <class T1, class... U> void e1(A1<T1, U...>);  // expected-note {{candidate}}
+template <class T1> void e1(A1<T1>);  // expected-note {{candidate}}
+template <class T1, class... U> void e2(A2<T1, U...>);  // expected-note {{candidate}}
+template <class T1> void e2(A2<T1>);  // expected-note {{candidate}}
+void h() {
+  A1<int> b1;
+  e1(b1); // expected-error{{call to 'e1' is ambiguous}}
+  A2<int> b2;
+  e2(b2); // expected-error{{call to 'e2' is ambiguous}}
+}


        


More information about the cfe-commits mailing list