https://github.com/cor3ntin updated 
https://github.com/llvm/llvm-project/pull/223645

>From 7be5dfb1f7e0a6fa2a8f62bde77bae02c55961f1 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <[email protected]>
Date: Tue, 15 Sep 2026 12:12:25 +0200
Subject: [PATCH 1/2] [Clang] Fix deduction from constant TP of reference type.

We were not implementing https://eel.is/c++draft/temp.deduct.type#13
properly.

Fixes #40328

Assisted-By: Opus 5
---
 clang/docs/ReleaseNotes.md                    |  3 ++
 clang/lib/Sema/SemaTemplateDeduction.cpp      | 30 ++++++------
 .../SemaTemplate/temp_arg_nontype_cxx1z.cpp   | 13 +++++
 .../SemaTemplate/temp_arg_nontype_ref.cpp     | 47 +++++++++++++++++++
 4 files changed, 79 insertions(+), 14 deletions(-)
 create mode 100644 clang/test/SemaTemplate/temp_arg_nontype_ref.cpp

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 043a0ddae2a6cd..b5dfb5930c3f4b 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -676,6 +676,9 @@ features cannot lower the translation-unit ABI level;
   class with an invalid non-static data member, such as one qualified with an
   address space. (#GH194605)
 
+- Fixed deduction of the template parameters appearing in the type of a
+  constant template parameter of reference type. (#GH40328)
+
 #### 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 b66152f2d971d5..795d199ee52243 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -261,6 +261,20 @@ getDeducedNTTParameterFromExpr(TemplateDeductionInfo 
&Info, Expr *E) {
   return getDeducedNTTParameterFromExpr(E, Info.getDeducedDepth());
 }
 
+/// C++26 [temp.deduct.type]p13:
+///   When the value of the argument corresponding to a constant template
+///   parameter P that is declared with a dependent type is deduced from an
+///   expression, the template parameters in the type of P are deduced from the
+///   type of the value.
+static QualType getTypeOfTemplateArgumentValue(TemplateDeductionInfo &Info,
+                                               const TemplateArgument &A) {
+  const Expr *E = unwrapExpressionForDeduction(A.getAsExpr());
+  if (NonTypeOrVarTemplateParmDecl NTTP =
+          getDeducedNTTParameterFromExpr(E, Info.getDeducedDepth()))
+    return NTTP.getType();
+  return E->getType();
+}
+
 /// Determine whether two declaration pointers refer to the same
 /// declaration.
 static bool isSameDeclaration(Decl *X, Decl *Y) {
@@ -497,17 +511,6 @@ DeduceNonTypeTemplateArgument(Sema &S, 
TemplateParameterList *TemplateParams,
   if (auto *Expansion = dyn_cast<PackExpansionType>(ParamType))
     ParamType = Expansion->getPattern();
 
-  // FIXME: It's not clear how deduction of a parameter of reference
-  // type from an argument (of non-reference type) should be performed.
-  // For now, we just make the argument have same reference type as the
-  // parameter.
-  if (ParamType->isReferenceType() && !ValueType->isReferenceType()) {
-    if (ParamType->isRValueReferenceType())
-      ValueType = S.Context.getRValueReferenceType(ValueType);
-    else
-      ValueType = S.Context.getLValueReferenceType(ValueType);
-  }
-
   return DeduceTemplateArgumentsByTypeMatch(
       S, TemplateParams, ParamType, ValueType, Info, Deduced,
       TDF_SkipNonDependent | TDF_IgnoreQualifiers,
@@ -2648,11 +2651,10 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList 
*TemplateParams,
             getDeducedNTTParameterFromExpr(Info, P.getAsExpr())) {
       switch (A.getKind()) {
       case TemplateArgument::Expression: {
-        // The type of the value is the type of the expression as written.
         return DeduceNonTypeTemplateArgument(
             S, TemplateParams, NTTP, DeducedTemplateArgument(A),
-            A.getAsExpr()->IgnoreImplicitAsWritten()->getType(), Info,
-            PartialOrdering, Deduced, HasDeducedAnyParam);
+            getTypeOfTemplateArgumentValue(Info, A), Info, PartialOrdering,
+            Deduced, HasDeducedAnyParam);
       }
       case TemplateArgument::Integral:
       case TemplateArgument::StructuralValue:
diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp 
b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
index 5077d5ff8ad892..a39bb02084aa7c 100644
--- a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
+++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
@@ -648,3 +648,16 @@ namespace GH58682 {
   template <decltype(auto) v> struct B<A<v>> { static constexpr int k = 1; };
   static_assert(B<A<(g)>>::k == 1, "");
 } // namespace GH58682
+
+// C++26 [temp.deduct.type]p13, Example 8.
+namespace temp_deduct_type_p13 {
+  template<long n> struct A { };
+
+  template<typename T> struct C;
+  template<typename T, T n> struct C<A<n>> {
+    using Q = T;
+  };
+
+  using R = long;
+  using R = C<A<2>>::Q;
+} // namespace temp_deduct_type_p13
diff --git a/clang/test/SemaTemplate/temp_arg_nontype_ref.cpp 
b/clang/test/SemaTemplate/temp_arg_nontype_ref.cpp
new file mode 100644
index 00000000000000..2020f564f68fca
--- /dev/null
+++ b/clang/test/SemaTemplate/temp_arg_nontype_ref.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++2c %s
+
+// expected-no-diagnostics
+
+namespace GH40328 {
+  template <typename T, T v> struct X {};
+  template <bool &v> struct X<bool &, v> {};
+
+  template <typename T, T v> struct A { static const int k = 0; };
+  template <bool &v>      struct A<bool &, v>      { static const int k = 1; };
+  template <const int &v> struct A<const int &, v> { static const int k = 2; };
+  template <int (&v)[3]>  struct A<int (&)[3], v>  { static const int k = 3; };
+  template <void (&v)()>  struct A<void (&)(), v>  { static const int k = 4; };
+  template <int *v>       struct A<int *, v>       { static const int k = 5; };
+
+  bool b;
+  extern const int ci;
+  const int ci = 0;
+  int arr[3];
+  void fn();
+  int n;
+
+  static_assert(A<bool, true>::k == 0, "");
+  static_assert(A<bool &, b>::k == 1, "");
+  static_assert(A<const int &, ci>::k == 2, "");
+  static_assert(A<int (&)[3], arr>::k == 3, "");
+  static_assert(A<void (&)(), fn>::k == 4, "");
+  static_assert(A<int *, &n>::k == 5, "");
+
+  template <typename T, T... v> struct P { static const int k = 0; };
+  template <bool &...v> struct P<bool &, v...> { static const int k = 1; };
+  static_assert(P<bool &, b, b>::k == 1, "");
+
+#if __cplusplus >= 201402L
+  template <typename T, T v> const int V = 0;
+  template <bool &v> const int V<bool &, v> = 1;
+  static_assert(V<bool &, b> == 1, "");
+#endif
+
+  template <typename T, T v> int f(A<T, v>);
+  template <bool &v> int *f(A<bool &, v>);
+  int *p = f(A<bool &, b>());
+} // namespace GH40328

>From a89045ae985ff432e079ec203e6ebcdc8d75da9d Mon Sep 17 00:00:00 2001
From: Corentin Jabot <[email protected]>
Date: Thu, 17 Sep 2026 12:08:54 +0200
Subject: [PATCH 2/2] cleanups

---
 clang/lib/Sema/SemaTemplateDeduction.cpp | 28 ++++++++++++------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp 
b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 795d199ee52243..653240092e64a7 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -261,20 +261,6 @@ getDeducedNTTParameterFromExpr(TemplateDeductionInfo 
&Info, Expr *E) {
   return getDeducedNTTParameterFromExpr(E, Info.getDeducedDepth());
 }
 
-/// C++26 [temp.deduct.type]p13:
-///   When the value of the argument corresponding to a constant template
-///   parameter P that is declared with a dependent type is deduced from an
-///   expression, the template parameters in the type of P are deduced from the
-///   type of the value.
-static QualType getTypeOfTemplateArgumentValue(TemplateDeductionInfo &Info,
-                                               const TemplateArgument &A) {
-  const Expr *E = unwrapExpressionForDeduction(A.getAsExpr());
-  if (NonTypeOrVarTemplateParmDecl NTTP =
-          getDeducedNTTParameterFromExpr(E, Info.getDeducedDepth()))
-    return NTTP.getType();
-  return E->getType();
-}
-
 /// Determine whether two declaration pointers refer to the same
 /// declaration.
 static bool isSameDeclaration(Decl *X, Decl *Y) {
@@ -2567,6 +2553,20 @@ static TemplateDeductionResult 
DeduceTemplateArgumentsByTypeMatch(
   llvm_unreachable("Invalid Type Class!");
 }
 
+/// C++26 [temp.deduct.type]p13:
+///   When the value of the argument corresponding to a constant template
+///   parameter P that is declared with a dependent type is deduced from an
+///   expression, the template parameters in the type of P are deduced from the
+///   type of the value.
+static QualType getTypeOfTemplateArgumentValue(TemplateDeductionInfo &Info,
+                                               const TemplateArgument &A) {
+  const Expr *E = A.getAsExpr();
+  if (NonTypeOrVarTemplateParmDecl NTTP =
+          getDeducedNTTParameterFromExpr(E, Info.getDeducedDepth()))
+    return NTTP.getType();
+  return unwrapExpressionForDeduction(E)->getType();
+}
+
 static TemplateDeductionResult
 DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
                         const TemplateArgument &P, TemplateArgument A,

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

Reply via email to