[clang] [Clang] Fix deduction from constant TP of reference type. (PR #223645)
Corentin Jabot via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 15 03:17:39 PDT 2026
https://github.com/cor3ntin created https://github.com/llvm/llvm-project/pull/223645
We were not implementing https://eel.is/c++draft/temp.deduct.type#13 properly.
Fixes #40328
Assisted-By: Opus 5
>From c219d31ac01331b4937d31360b2d2ad2ebf5e0bd Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Tue, 15 Sep 2026 12:12:25 +0200
Subject: [PATCH] [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 ++++++++
3 files changed, 32 insertions(+), 14 deletions(-)
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
More information about the cfe-commits
mailing list