[clang] [Clang] Fix synthesis of alias CTAD constraints (PR #223340)
Younan Zhang via cfe-commits
cfe-commits at lists.llvm.org
Mon Sep 14 02:35:27 PDT 2026
https://github.com/zyn0217 created https://github.com/llvm/llvm-project/pull/223340
buildAssociatedConstraints reconstructs a template parameter list relative to its primary template. However it didn't match the construction of the CTAD guide very precisely.
Fixes https://github.com/llvm/llvm-project/issues/124715
>From f7ae9a62e7d82a71be4f2c1c8f153a85b0d2f2a7 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Mon, 14 Sep 2026 17:31:25 +0800
Subject: [PATCH] [Clang] Fix synthesizing of alias CTAD constraints
buildAssociatedConstraints reconstructs a template parameter list relative
to its primary template. However it didn't match the construction of
the CTAD guide very precisely.
---
clang/docs/ReleaseNotes.md | 2 ++
clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 29 ++++++++++++-------
clang/test/SemaCXX/ctad.cpp | 29 +++++++++++++++++++
3 files changed, 50 insertions(+), 10 deletions(-)
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 043a0ddae2a6cd..be67a1b3779d8c 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -579,6 +579,8 @@ features cannot lower the translation-unit ABI level;
- Fixed a crash when a using-declaration naming an unresolvable member of a
dependent base was shadowed by an invalid using-declaration. (#GH209427)
+- Fixed a CTAD bug when combining with concepts. (#GH124715)
+
- Fixed a regression where an internal-linkage function (e.g. a `static` or
anonymous-namespace helper) declared in the global module fragment of the
current translation unit was removed from the overload set when the calling
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 1a488ece55d258..e1000372985fc6 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -998,11 +998,19 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
AliasTemplate->getInstantiatedFromMemberTemplate())
AdjustDepth = PrimaryTemplate->getTemplateDepth();
+ // FIXME: We're rebuilding the synthesized template parameter list again
+ // Consider reuse the template parameter from its caller.
+
// We rebuild all template parameters with the uninstantiated depth, and
// build template arguments refer to them.
- SmallVector<TemplateArgument> AdjustedAliasTemplateArgs;
+ SmallVector<TemplateArgument> AdjustedAliasTemplateArgs(
+ AliasTemplate->getTemplateParameters()->size());
- for (auto *TP : *AliasTemplate->getTemplateParameters()) {
+ unsigned N = 0;
+ for (unsigned Index = 0; Index != AdjustedAliasTemplateArgs.size(); ++Index) {
+ if (DeduceResults[Index].isNull())
+ continue;
+ auto *TP = AliasTemplate->getTemplateParameters()->getParam(Index);
// Rebuild any internal references to earlier parameters and reindex
// as we go.
MultiLevelTemplateArgumentList Args;
@@ -1010,21 +1018,22 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
Args.addOuterTemplateArguments(AdjustedAliasTemplateArgs);
NamedDecl *NewParam = transformTemplateParameter(
SemaRef, AliasTemplate->getDeclContext(), TP, Args,
- /*NewIndex=*/AdjustedAliasTemplateArgs.size(),
- getDepthAndIndex(TP).first + AdjustDepth);
+ /*NewIndex=*/N++, getDepthAndIndex(TP).first + AdjustDepth);
TemplateArgument NewTemplateArgument =
Context.getInjectedTemplateArg(NewParam);
- AdjustedAliasTemplateArgs.push_back(NewTemplateArgument);
+ AdjustedAliasTemplateArgs[Index] = NewTemplateArgument;
}
+ assert(FirstUndeducedParamIdx == N);
+
// Template arguments used to transform the template arguments in
// DeducedResults.
SmallVector<TemplateArgument> TemplateArgsForBuildingRC(
F->getTemplateParameters()->size());
// Transform the transformed template args
- MultiLevelTemplateArgumentList Args;
- Args.setKind(TemplateSubstitutionKind::Rewrite);
- Args.addOuterTemplateArguments(AdjustedAliasTemplateArgs);
+ MultiLevelTemplateArgumentList ArgsForDeducedParams;
+ ArgsForDeducedParams.setKind(TemplateSubstitutionKind::Rewrite);
+ ArgsForDeducedParams.addOuterTemplateArguments(AdjustedAliasTemplateArgs);
for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) {
const auto &D = DeduceResults[Index];
@@ -1047,7 +1056,7 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
TemplateArgumentLoc Input =
SemaRef.getTrivialTemplateArgumentLoc(D, QualType(), SourceLocation{});
TemplateArgumentLoc Output;
- if (!SemaRef.SubstTemplateArgument(Input, Args, Output)) {
+ if (!SemaRef.SubstTemplateArgument(Input, ArgsForDeducedParams, Output)) {
assert(TemplateArgsForBuildingRC[Index].isNull() &&
"InstantiatedArgs must be null before setting");
TemplateArgsForBuildingRC[Index] = Output.getArgument();
@@ -1119,7 +1128,7 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
Expr *buildIsDeducibleConstraint(Sema &SemaRef,
TypeAliasTemplateDecl *AliasTemplate,
QualType ReturnType,
- SmallVector<NamedDecl *> TemplateParams) {
+ ArrayRef<NamedDecl *> TemplateParams) {
ASTContext &Context = SemaRef.Context;
// Constraint AST nodes must use uninstantiated depth.
if (auto *PrimaryTemplate =
diff --git a/clang/test/SemaCXX/ctad.cpp b/clang/test/SemaCXX/ctad.cpp
index 2a4e1c571ac5cd..6517e88a8a8312 100644
--- a/clang/test/SemaCXX/ctad.cpp
+++ b/clang/test/SemaCXX/ctad.cpp
@@ -197,3 +197,32 @@ namespace GH131342 {
template <class T> using AA = A<T, val<T>>;
AA a{0};
} // namespace GH131342
+
+namespace GH124715_2 {
+
+template <class F, class... Args>
+using invoke_result_t = decltype(F()(Args()...));
+
+template <class F, class... Args>
+invoke_result_t<F, Args...> invoke(F f, Args... args);
+
+template <class F, class... Args>
+concept invocable = requires(F f, Args... args) {
+ invoke(f, args...);
+};
+
+template <class Ret, class... Args>
+struct A {
+ A(auto&&...) {}
+};
+
+template <class Lambda, class... Args>
+ requires invocable<Lambda, Args...>
+A(Lambda, Args...) -> A<invoke_result_t<Lambda, Args...>, Args...>;
+
+template <class T, class... Ts>
+using AliasName = A<T, Ts...>;
+
+AliasName aa([](int){}, 0);
+
+}
More information about the cfe-commits
mailing list