https://github.com/cor3ntin created 
https://github.com/llvm/llvm-project/pull/229024

The tentative resolution for CWG1432 was not consistent for the resolution of 
CWG1395.

This fixes the crash reported in #228870.

Additionally, this update the status of related core issues and papers touching 
the same wording. Clang was never affected because we never fully implemented 
CWG1395.

Fixes #228870
Fixes #27357

Assisted-by: Opus 5.5

>From 58f5d1f3b776ed6c1462fd2adaf16d66d0b8aed3 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <[email protected]>
Date: Mon, 5 Oct 2026 11:21:16 +0200
Subject: [PATCH] [Clang] Fix pack vs non-pack tie breaker.

The tentative resolution for CWG1432 was not consistent for
the resolution of CWG1395.

This fixes the crash reported in #228870.

Additionally, this update the status of related core issues
and papers touching the same wording. Clang was never affected
because we never fully implemented CWG1395.

Fixes #228870
Fixes #27357

Assisted-by: Opus 5.5
---
 clang/docs/ReleaseNotes.md                      |  4 ++++
 clang/lib/Sema/SemaTemplateDeduction.cpp        | 16 ++++++++++++----
 clang/test/CXX/drs/cwg13xx.cpp                  |  4 ++++
 clang/test/CXX/drs/cwg18xx.cpp                  | 13 +++++++++++++
 .../SemaCXX/cxx2d-pack-indexing-template.cpp    | 13 +++++++++++++
 clang/test/SemaTemplate/partial-order.cpp       | 17 +++++++++++++++++
 clang/www/cxx_dr_status.html                    |  2 +-
 clang/www/cxx_status.html                       |  2 +-
 8 files changed, 65 insertions(+), 6 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 7ec126a065ae5ab..f0345e086d07f34 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -834,6 +834,10 @@ features cannot lower the translation-unit ABI level;
   the initializer of another specialization of the same variable template.
   (#GH134148)
 
+- Fixed an assertion failure in partial ordering of function templates whose
+  parameters use pack-indexed template template parameters (`TT...[N]<int>`)
+  with different template parameter lists. (#GH228870)
+
 #### Bug Fixes to AST Handling
 
 - Fixed a non-deterministic ordering of unused local typedefs that made
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp 
b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 2257964a4310bbc..3c8d6b1a8b05d20 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -6033,11 +6033,19 @@ getMoreSpecializedTrailingPackTieBreaker(
   ArrayRef<TemplateArgument> As1 = TST1->template_arguments(),
                              As2 = TST2->template_arguments();
   const TemplateArgument &TA1 = As1.back(), &TA2 = As2.back();
-  bool IsPack = TA1.getKind() == TemplateArgument::Pack;
-  assert(IsPack == (TA2.getKind() == TemplateArgument::Pack));
-  if (!IsPack)
+  // C++26 [temp.deduct.partial]p11:
+  //   If, after considering the above, function template F is at least as
+  //   specialized as function template G and vice-versa, and if G has a
+  //   trailing function parameter pack for which F does not have a
+  //   corresponding parameter, and if F does not have a trailing function
+  //   parameter pack, then F is more specialized than G.
+  bool IsPack1 = TA1.getKind() == TemplateArgument::Pack;
+  bool IsPack2 = TA2.getKind() == TemplateArgument::Pack;
+  if (IsPack1 != IsPack2)
+    return IsPack1 ? MoreSpecializedTrailingPackTieBreakerResult::More
+                   : MoreSpecializedTrailingPackTieBreakerResult::Less;
+  if (!IsPack1 || As1.size() != As2.size())
     return MoreSpecializedTrailingPackTieBreakerResult::Equal;
-  assert(As1.size() == As2.size());
 
   unsigned PackSize1 = TA1.pack_size(), PackSize2 = TA2.pack_size();
   bool IsPackExpansion1 =
diff --git a/clang/test/CXX/drs/cwg13xx.cpp b/clang/test/CXX/drs/cwg13xx.cpp
index 8e33fc98301d27b..e20ea3089a9db71 100644
--- a/clang/test/CXX/drs/cwg13xx.cpp
+++ b/clang/test/CXX/drs/cwg13xx.cpp
@@ -730,9 +730,13 @@ namespace cwg1395 { // cwg1395: 16
 #if __cplusplus >= 201103L
   template <typename T, typename... U> void f(T, U...);
   template <typename T> void f(T);
+  // The non-pack overload is more specialized.
+  template <typename T, typename... U> constexpr int g(T, U...) { return 1; }
+  template <typename T> constexpr int g(T) { return 2; }
   void h(int i) {
     // This is made ambiguous by cwg692, but made valid again by cwg1395.
     f(&i);
+    static_assert(g(0) == 2, "");
   }
 #endif
 } // namespace cwg1395
diff --git a/clang/test/CXX/drs/cwg18xx.cpp b/clang/test/CXX/drs/cwg18xx.cpp
index 32ff4d72d30f334..548bd7c7b0ab701 100644
--- a/clang/test/CXX/drs/cwg18xx.cpp
+++ b/clang/test/CXX/drs/cwg18xx.cpp
@@ -316,6 +316,19 @@ struct S {
 };
 } // namespace cwg1824
 
+namespace cwg1825 { // cwg1825: sup P4004R1
+#if __cplusplus >= 201103L
+template <class... T> int f(T *...); // #cwg1825-variadic
+template <class T> int f(const T &); // #cwg1825-nonvariadic
+int g() {
+  return f((int *)0);
+  // since-cxx11-error@-1 {{call to 'f' is ambiguous}}
+  //   since-cxx11-note@#cwg1825-variadic {{candidate function [with T = 
<int>]}}
+  //   since-cxx11-note@#cwg1825-nonvariadic {{candidate function [with T = 
int *]}}
+}
+#endif
+} // namespace cwg1825
+
 namespace cwg1832 { // cwg1832: 3.0
 enum E { // #cwg1832-E
   a = static_cast<int>(static_cast<E>(0))
diff --git a/clang/test/SemaCXX/cxx2d-pack-indexing-template.cpp 
b/clang/test/SemaCXX/cxx2d-pack-indexing-template.cpp
index 83fb5e94071a9e0..1c0a12c21da80b5 100644
--- a/clang/test/SemaCXX/cxx2d-pack-indexing-template.cpp
+++ b/clang/test/SemaCXX/cxx2d-pack-indexing-template.cpp
@@ -482,3 +482,16 @@ static_assert(!Lambda2<1>.operator()<int, Always, 
Never>());
 static_assert(Lambda2<0>.operator()<int, Always, Never>());
 static_assert(Lambda2<0, 0>.operator()<int, Always, Never>());
 static_assert(!Lambda2<1, 1>.operator()<int, Always, Never>());
+
+namespace GH228870 {
+template <class> struct S {};
+
+template <unsigned N, template <class...> class... TT> char f(TT...[N]<int>);
+template <unsigned N, template <class> class... TT> int f(TT...[N]<int>);
+template <unsigned N, template <class, class...> class... TT> char 
f(TT...[N]<int>);
+static_assert(__is_same(decltype(f<0, S>(S<int>{})), int));
+
+template <unsigned N, template <class...> class... TT> int g(TT...[N]<int>); 
// expected-note {{candidate function}}
+template <unsigned N, template <class, class...> class... TT> int 
g(TT...[N]<int>); // expected-note {{candidate function}}
+int x = g<0, S>(S<int>{}); // expected-error {{call to 'g' is ambiguous}}
+}
diff --git a/clang/test/SemaTemplate/partial-order.cpp 
b/clang/test/SemaTemplate/partial-order.cpp
index 2619524b147ae56..b06c2ced9f66d66 100644
--- a/clang/test/SemaTemplate/partial-order.cpp
+++ b/clang/test/SemaTemplate/partial-order.cpp
@@ -73,3 +73,20 @@ Trait<Y> t;
 // expected-note@#gh51866-one{{partial specialization matches}}
 // expected-note@#gh51866-two{{partial specialization matches}}
 }
+
+namespace GH27357 {
+struct S {
+  using type = int;
+};
+
+// T is used in a non-deduced context and has no value, so deduction fails in
+// both directions ([temp.deduct.partial]p12).
+template <class T> int add(typename T::type); // #gh27357-1
+template <class T, class... Ts>
+int add(typename T::type, typename Ts::type...); // #gh27357-2
+
+int x = add<S>(0);
+// expected-error@-1 {{call to 'add' is ambiguous}}
+// expected-note@#gh27357-1 {{candidate function [with T = GH27357::S]}}
+// expected-note@#gh27357-2 {{candidate function [with T = GH27357::S, Ts = 
<>]}}
+} // namespace GH27357
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index e7679da30d5c29e..b7d30a549d22d0b 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -12560,7 +12560,7 @@ <h2 id="cxxdr">C++ defect report implementation 
status</h2>
     <td>[<a 
href="https://wg21.link/temp.deduct.partial";>temp.deduct.partial</a>]</td>
     <td>C++17</td>
     <td>Partial ordering between variadic and non-variadic function 
templates</td>
-    <td class="unknown" align="center">Unknown</td>
+    <td class="na" align="center">Superseded by <a 
href="https://wg21.link/P4004R1";>P4004R1</a></td>
   </tr>
   <tr id="1826">
     <td><a 
href="https://cplusplus.github.io/CWG/issues/1826.html";>1826</a></td>
diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index 61d0f38bce87a5f..3f105f831f9b761 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -469,7 +469,7 @@ <h2 id="cxx26">C++2c implementation status</h2>
  <tr>
    <td>Reconsider CWG 1395 "Partial ordering of variadic templates 
reconsidered"</td>
    <td><a href="https://wg21.link/P4004R1";>P4004R1</a> (<a 
href="#dr">DR</a>)</td>
-   <td class="none" align="center">No</td>
+   <td class="full" align="center">Clang 2.7</td>
  </tr>
  <tr>
    <td>CTAD for type template template parameters</td>

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to