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 043a0ddae2a6c..b5dfb5930c3f4 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 b66152f2d971d..795d199ee5224 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 5077d5ff8ad89..a39bb02084aa7 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 0000000000000..2020f564f68fc
--- /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 730bbdec0c794a1aefc15a27cc0c3ebd4563dae1 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <[email protected]>
Date: Tue, 15 Sep 2026 20:53:10 +0200
Subject: [PATCH 2/2] cwg 2900 (wip)

---
 clang/docs/ReleaseNotes.md                    |  4 ++
 clang/include/clang/Sema/Sema.h               |  6 ++
 clang/lib/Sema/SemaTemplate.cpp               | 19 ++++++
 clang/lib/Sema/SemaTemplateDeduction.cpp      | 63 ++++++++++---------
 clang/test/CXX/drs/cwg29xx.cpp                | 32 ++++++++++
 .../temp_arg_nontype_arg_type.cpp             | 63 +++++++++++++++++++
 clang/www/cxx_dr_status.html                  |  2 +-
 7 files changed, 160 insertions(+), 29 deletions(-)
 create mode 100644 clang/test/SemaTemplate/temp_arg_nontype_arg_type.cpp

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index b5dfb5930c3f4..7777a2a103cac 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -183,6 +183,10 @@ features cannot lower the translation-unit ABI level;
   them to an enumeration type with a fixed `bool` underlying type. This
   resolves [CWG1094](https://wg21.link/cwg1094).
 
+- Implemented [CWG2900](https://wg21.link/cwg2900), removing a spurious
+  ambiguity when partial ordering constant template parameters declared
+  with placeholder types.
+
 ### C Language Changes
 
 #### C2y Feature Support
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index d32eb3600ce54..8c0f9bbb2f17e 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -12955,6 +12955,12 @@ class Sema final : public SemaBase {
       const DefaultArguments &DefaultArgs, SourceLocation ArgLoc,
       bool PartialOrdering, bool *StrictPackMatch);
 
+  /// Determine the declared type of the constant template parameter that \p A
+  /// names, if any.
+  static QualType
+  getTypeOfConstantTemplateParameter(const TemplateArgument &A,
+                                     UnsignedOrNone Depth = std::nullopt);
+
   /// Mark which template parameters are used in a given expression.
   ///
   /// \param E the expression from which template parameters will be deduced.
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index b8b0c71894daa..507ea8693e112 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -5544,6 +5544,14 @@ convertTypeTemplateArgumentToTemplate(ASTContext 
&Context, TypeLoc TLoc) {
                              TagLoc.getQualifierLoc(), TagLoc.getNameLoc());
 }
 
+/// Determine whether \p T is an undeduced 'decltype(auto)', or an undeduced
+/// placeholder of the form 'type-constraint_opt auto'.
+static bool isUndeducedAuto(QualType T, bool DecltypeAuto) {
+  const AutoType *AT = T->getContainedAutoType();
+  return AT && AT->isDecltypeAuto() == DecltypeAuto &&
+         AT->getDeducedType().isNull();
+}
+
 bool Sema::CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &ArgLoc,
                                  NamedDecl *Template,
                                  SourceLocation TemplateLoc,
@@ -5566,6 +5574,17 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, 
TemplateArgumentLoc &ArgLoc,
     if (NTTP->isParameterPack() && NTTP->isExpandedParameterPack())
       NTTPType = NTTP->getExpansionType(ArgumentPackIndex);
 
+    // C++26 [dcl.type.auto.deduct]p3:
+    //   If the placeholder-type-specifier is of the form type-constraint_opt
+    //   auto, [...] If E is a value synthesized for a constant template
+    //   parameter of type decltype(auto) ([temp.func.order]), the declaration
+    //   is ill-formed.
+    if (CTAI.PartialOrdering &&
+        isUndeducedAuto(NTTPType, /*DecltypeAuto=*/false) &&
+        isUndeducedAuto(getTypeOfConstantTemplateParameter(Arg),
+                        /*DecltypeAuto=*/true))
+      return true;
+
     if (NTTPType->isInstantiationDependentType()) {
       // Do substitution on the type of the non-type template parameter.
       InstantiatingTemplate Inst(*this, TemplateLoc, Template, NTTP,
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp 
b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 795d199ee5224..2247fba693a23 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -234,31 +234,39 @@ class NonTypeOrVarTemplateParmDecl {
   const NamedDecl *Template;
 };
 
-/// If the given expression is of a form that permits the deduction
-/// of a non-type template parameter, return the declaration of that
-/// non-type template parameter.
+/// If the given expression is of a form that names a non-type template
+/// parameter, return the declaration of that parameter. A null \p Depth
+/// accepts a parameter at any depth.
 static NonTypeOrVarTemplateParmDecl
-getDeducedNTTParameterFromExpr(const Expr *E, unsigned Depth) {
+getNTTParameterFromExpr(const Expr *E, UnsignedOrNone Depth) {
   // If we are within an alias template, the expression may have undergone
   // any number of parameter substitutions already.
   E = unwrapExpressionForDeduction(E);
   if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
     if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl()))
-      if (NTTP->getDepth() == Depth)
+      if (!Depth || NTTP->getDepth() == *Depth)
         return NTTP;
 
   // A pack-index-template-name is not deducible.
   if (const auto *DTI = dyn_cast<DependentTemplateIdExpr>(E))
     if (!DTI->getTemplateName().getAsPackIndexingTemplate() &&
-        DTI->getParameter()->getDepth() == Depth)
+        (!Depth || DTI->getParameter()->getDepth() == *Depth))
       return DTI->getParameter();
 
   return nullptr;
 }
 
+QualType Sema::getTypeOfConstantTemplateParameter(const TemplateArgument &A,
+                                                  UnsignedOrNone Depth) {
+  if (NonTypeOrVarTemplateParmDecl NTTP =
+          getNTTParameterFromExpr(A.getAsExpr(), Depth))
+    return NTTP.getType();
+  return QualType();
+}
+
 static const NonTypeOrVarTemplateParmDecl
-getDeducedNTTParameterFromExpr(TemplateDeductionInfo &Info, Expr *E) {
-  return getDeducedNTTParameterFromExpr(E, Info.getDeducedDepth());
+getNTTParameterFromExpr(TemplateDeductionInfo &Info, Expr *E) {
+  return getNTTParameterFromExpr(E, Info.getDeducedDepth());
 }
 
 /// C++26 [temp.deduct.type]p13:
@@ -268,11 +276,11 @@ getDeducedNTTParameterFromExpr(TemplateDeductionInfo 
&Info, Expr *E) {
 ///   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();
+  if (QualType T =
+          Sema::getTypeOfConstantTemplateParameter(A, Info.getDeducedDepth());
+      !T.isNull())
+    return T;
+  return unwrapExpressionForDeduction(A.getAsExpr())->getType();
 }
 
 /// Determine whether two declaration pointers refer to the same
@@ -2010,7 +2018,7 @@ static TemplateDeductionResult 
DeduceTemplateArgumentsByTypeMatch(
 
       // Determine the array bound is something we can deduce.
       NonTypeOrVarTemplateParmDecl NTTP =
-          getDeducedNTTParameterFromExpr(Info, DAP->getSizeExpr());
+          getNTTParameterFromExpr(Info, DAP->getSizeExpr());
       if (!NTTP)
         return TemplateDeductionResult::Success;
 
@@ -2074,7 +2082,7 @@ static TemplateDeductionResult 
DeduceTemplateArgumentsByTypeMatch(
       // type. libstdc++ relies on this.
       Expr *NoexceptExpr = FPP->getNoexceptExpr();
       if (NonTypeOrVarTemplateParmDecl NTTP =
-              NoexceptExpr ? getDeducedNTTParameterFromExpr(Info, NoexceptExpr)
+              NoexceptExpr ? getNTTParameterFromExpr(Info, NoexceptExpr)
                            : nullptr) {
         assert(NTTP.getDepth() == Info.getDeducedDepth() &&
                "saw non-type template parameter with wrong depth");
@@ -2264,7 +2272,7 @@ static TemplateDeductionResult 
DeduceTemplateArgumentsByTypeMatch(
 
         // Perform deduction on the vector size, if we can.
         NonTypeOrVarTemplateParmDecl NTTP =
-            getDeducedNTTParameterFromExpr(Info, VP->getSizeExpr());
+            getNTTParameterFromExpr(Info, VP->getSizeExpr());
         if (!NTTP)
           return TemplateDeductionResult::Success;
 
@@ -2290,7 +2298,7 @@ static TemplateDeductionResult 
DeduceTemplateArgumentsByTypeMatch(
 
         // Perform deduction on the vector size, if we can.
         NonTypeOrVarTemplateParmDecl NTTP =
-            getDeducedNTTParameterFromExpr(Info, VP->getSizeExpr());
+            getNTTParameterFromExpr(Info, VP->getSizeExpr());
         if (!NTTP)
           return TemplateDeductionResult::Success;
 
@@ -2319,7 +2327,7 @@ static TemplateDeductionResult 
DeduceTemplateArgumentsByTypeMatch(
 
         // Perform deduction on the vector size, if we can.
         NonTypeOrVarTemplateParmDecl NTTP =
-            getDeducedNTTParameterFromExpr(Info, VP->getSizeExpr());
+            getNTTParameterFromExpr(Info, VP->getSizeExpr());
         if (!NTTP)
           return TemplateDeductionResult::Success;
 
@@ -2344,7 +2352,7 @@ static TemplateDeductionResult 
DeduceTemplateArgumentsByTypeMatch(
 
         // Perform deduction on the vector size, if we can.
         NonTypeOrVarTemplateParmDecl NTTP =
-            getDeducedNTTParameterFromExpr(Info, VP->getSizeExpr());
+            getNTTParameterFromExpr(Info, VP->getSizeExpr());
         if (!NTTP)
           return TemplateDeductionResult::Success;
 
@@ -2421,7 +2429,7 @@ static TemplateDeductionResult 
DeduceTemplateArgumentsByTypeMatch(
             }
 
             NonTypeOrVarTemplateParmDecl NTTP =
-                getDeducedNTTParameterFromExpr(Info, ParamExpr);
+                getNTTParameterFromExpr(Info, ParamExpr);
             if (!NTTP)
               return TemplateDeductionResult::Success;
 
@@ -2468,7 +2476,7 @@ static TemplateDeductionResult 
DeduceTemplateArgumentsByTypeMatch(
 
         // Perform deduction on the address space, if we can.
         NonTypeOrVarTemplateParmDecl NTTP =
-            getDeducedNTTParameterFromExpr(Info, ASP->getAddrSpaceExpr());
+            getNTTParameterFromExpr(Info, ASP->getAddrSpaceExpr());
         if (!NTTP)
           return TemplateDeductionResult::Success;
 
@@ -2493,7 +2501,7 @@ static TemplateDeductionResult 
DeduceTemplateArgumentsByTypeMatch(
 
         // Perform deduction on the address space, if we can.
         NonTypeOrVarTemplateParmDecl NTTP =
-            getDeducedNTTParameterFromExpr(Info, ASP->getAddrSpaceExpr());
+            getNTTParameterFromExpr(Info, ASP->getAddrSpaceExpr());
         if (!NTTP)
           return TemplateDeductionResult::Success;
 
@@ -2513,7 +2521,7 @@ static TemplateDeductionResult 
DeduceTemplateArgumentsByTypeMatch(
           return TemplateDeductionResult::NonDeducedMismatch;
 
         NonTypeOrVarTemplateParmDecl NTTP =
-            getDeducedNTTParameterFromExpr(Info, IP->getNumBitsExpr());
+            getNTTParameterFromExpr(Info, IP->getNumBitsExpr());
         if (!NTTP)
           return TemplateDeductionResult::Success;
 
@@ -2648,7 +2656,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList 
*TemplateParams,
 
   case TemplateArgument::Expression:
     if (NonTypeOrVarTemplateParmDecl NTTP =
-            getDeducedNTTParameterFromExpr(Info, P.getAsExpr())) {
+            getNTTParameterFromExpr(Info, P.getAsExpr())) {
       switch (A.getKind()) {
       case TemplateArgument::Expression: {
         return DeduceNonTypeTemplateArgument(
@@ -4569,8 +4577,8 @@ static TemplateDeductionResult DeduceFromInitializerList(
   //   from the length of the initializer list.
   if (auto *DependentArrTy = dyn_cast_or_null<DependentSizedArrayType>(ArrTy)) 
{
     // Determine the array bound is something we can deduce.
-    if (NonTypeOrVarTemplateParmDecl NTTP = getDeducedNTTParameterFromExpr(
-            Info, DependentArrTy->getSizeExpr())) {
+    if (NonTypeOrVarTemplateParmDecl NTTP =
+            getNTTParameterFromExpr(Info, DependentArrTy->getSizeExpr())) {
       // We can perform template argument deduction for the given non-type
       // template parameter.
       // C++ [temp.deduct.type]p13:
@@ -6920,8 +6928,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx,
     return;
   }
 
-  const NonTypeOrVarTemplateParmDecl NTTP =
-      getDeducedNTTParameterFromExpr(E, Depth);
+  const NonTypeOrVarTemplateParmDecl NTTP = getNTTParameterFromExpr(E, Depth);
   if (!NTTP)
     return;
   if (NTTP.getDepth() == Depth)
diff --git a/clang/test/CXX/drs/cwg29xx.cpp b/clang/test/CXX/drs/cwg29xx.cpp
index 165c2943b6b4a..88f57afbf7e99 100644
--- a/clang/test/CXX/drs/cwg29xx.cpp
+++ b/clang/test/CXX/drs/cwg29xx.cpp
@@ -8,6 +8,38 @@
 
 // cxx98-no-diagnostics
 
+namespace cwg2900 { // cwg2900: 24
+#if __cplusplus >= 201703L
+// [temp.deduct.type] Example 13.
+template <int &> struct E;
+template <auto x> void f(E<x> *); // #cwg2900-f-E
+int v;
+void g(E<v> *bp) {
+  f(bp);
+  // since-cxx11-error@-1 {{no matching function for call to 'f'}}
+  //   since-cxx11-note@#cwg2900-f-E {{candidate template ignored: 
substitution failure: non-type template argument is not a constant expression}}
+}
+
+template <const int &> struct F;
+template <decltype(auto) x> void f(F<x> *);
+int i;
+void g(F<i> *ap) {
+  f(ap); // OK, deduces x as a constant template parameter of type const int &
+}
+
+template <decltype(auto) q> struct G;
+template <auto x> long *f(G<x> *);            // #1
+template <decltype(auto) x> short *f(G<x> *); // #2
+const int j = 0;
+short *g(G<(j)> *ap) { // OK, q has type const int &
+  return f(ap);        // OK, only #2 matches
+}
+long *g(G<j> *ap) { // OK, q has type int
+  return f(ap);     // OK, #1 is more specialized
+}
+#endif
+} // namespace cwg2900
+
 namespace cwg2913 { // cwg2913: 20
 
 #if __cplusplus >= 202002L
diff --git a/clang/test/SemaTemplate/temp_arg_nontype_arg_type.cpp 
b/clang/test/SemaTemplate/temp_arg_nontype_arg_type.cpp
new file mode 100644
index 0000000000000..01290d91a2e84
--- /dev/null
+++ b/clang/test/SemaTemplate/temp_arg_nontype_arg_type.cpp
@@ -0,0 +1,63 @@
+// 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
+
+namespace ex1 {
+  template<int i> class A { };
+  template<short s> void f(A<s>);
+  // expected-note@-1 {{candidate template ignored: substitution failure: 
deduced non-type template argument does not have the same type as the 
corresponding template parameter ('int' vs 'short')}}
+  void k1() {
+    A<1> a;
+    f(a); // expected-error {{no matching function for call to 'f'}}
+    f<1>(a);
+  }
+}
+
+namespace ex2 {
+  template<const short cs> class B { };
+  template<short s> void g(B<s>);
+  void k2() {
+    B<1> b;
+    g(b);
+  }
+}
+
+#if __cplusplus >= 201703L
+namespace ex3 {
+  template<auto> struct C;
+  template<long long x> void f(C<x> *);
+  void g(C<0LL> *ap) { f(ap); }
+}
+
+namespace ex4 {
+  template<int> struct D;
+  template<auto x> void f(D<x> *);
+  void g(D<0LL> *ap) { f(ap); }
+}
+
+namespace ex5 {
+  template<int &> struct E;
+  template<auto x> void f(E<x> *);
+  // expected-note@-1 {{candidate template ignored: substitution failure: 
non-type template argument is not a constant expression}}
+  int v;
+  void g(E<v> *bp) { f(bp); } // expected-error {{no matching function for 
call to 'f'}}
+}
+
+namespace ex6 {
+  template<const int &> struct F;
+  template<decltype(auto) x> void f(F<x> *);
+  int i;
+  void g(F<i> *ap) { f(ap); }
+}
+
+namespace ex7 {
+  template <decltype(auto) q> struct G;
+  template <auto x> long *f(G<x> *);
+  template <decltype(auto) x> short *f(G<x> *);
+  const int j = 0;
+  short *g1(G<(j)> *ap) { return f(ap); }
+  long *g2(G<j> *ap) { return f(ap); }
+}
+#endif
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index e7679da30d5c2..4970d64f754f4 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -20117,7 +20117,7 @@ <h2 id="cxxdr">C++ defect report implementation 
status</h2>
     <td>[<a 
href="https://wg21.link/temp.deduct.type";>temp.deduct.type</a>]</td>
     <td>C++26</td>
     <td>Deduction of non-type template arguments with placeholder types</td>
-    <td class="unknown" align="center">Unknown</td>
+    <td class="unreleased" align="center">Clang 24</td>
   </tr>
   <tr id="2901">
     <td><a 
href="https://cplusplus.github.io/CWG/issues/2901.html";>2901</a></td>

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

Reply via email to