Skip to content

Commit 4d2a1bf

Browse files
authored
[clang] CTAD alias: Respect explicit deduction guides defined after the first use of the alias template. (#125478)
Fixes #103016 This is the last missing piece for the C++20 CTAD alias feature. No release note being added in this PR yet, I will send out a follow-up patch to mark this feature done. (Since the release 20 branch is cut, I think we should target on clang21).
1 parent 71adb05 commit 4d2a1bf

File tree

2 files changed

+44
-11
lines changed

2 files changed

+44
-11
lines changed

clang/lib/Sema/SemaTemplateDeductionGuide.cpp

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,28 @@ bool hasDeclaredDeductionGuides(DeclarationName Name, DeclContext *DC) {
740740
return false;
741741
}
742742

743+
// Returns all source deduction guides associated with the declared
744+
// deduction guides that have the specified deduction guide name.
745+
llvm::DenseSet<const NamedDecl *> getSourceDeductionGuides(DeclarationName Name,
746+
DeclContext *DC) {
747+
assert(Name.getNameKind() ==
748+
DeclarationName::NameKind::CXXDeductionGuideName &&
749+
"name must be a deduction guide name");
750+
llvm::DenseSet<const NamedDecl *> Result;
751+
for (auto *D : DC->lookup(Name)) {
752+
if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
753+
D = FTD->getTemplatedDecl();
754+
755+
if (const auto *GD = dyn_cast<CXXDeductionGuideDecl>(D)) {
756+
assert(GD->getSourceDeductionGuide() &&
757+
"deduction guide for alias template must have a source deduction "
758+
"guide");
759+
Result.insert(GD->getSourceDeductionGuide());
760+
}
761+
}
762+
return Result;
763+
}
764+
743765
// Build the associated constraints for the alias deduction guides.
744766
// C++ [over.match.class.deduct]p3.3:
745767
// The associated constraints ([temp.constr.decl]) are the conjunction of the
@@ -1191,17 +1213,14 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
11911213
if (AliasTemplate->isInvalidDecl())
11921214
return;
11931215
auto &Context = SemaRef.Context;
1194-
// FIXME: if there is an explicit deduction guide after the first use of the
1195-
// type alias usage, we will not cover this explicit deduction guide. fix this
1196-
// case.
1197-
if (hasDeclaredDeductionGuides(
1198-
Context.DeclarationNames.getCXXDeductionGuideName(AliasTemplate),
1199-
AliasTemplate->getDeclContext()))
1200-
return;
12011216
auto [Template, AliasRhsTemplateArgs] =
12021217
getRHSTemplateDeclAndArgs(SemaRef, AliasTemplate);
12031218
if (!Template)
12041219
return;
1220+
auto SourceDeductionGuides = getSourceDeductionGuides(
1221+
Context.DeclarationNames.getCXXDeductionGuideName(AliasTemplate),
1222+
AliasTemplate->getDeclContext());
1223+
12051224
DeclarationNameInfo NameInfo(
12061225
Context.DeclarationNames.getCXXDeductionGuideName(Template), Loc);
12071226
LookupResult Guides(SemaRef, NameInfo, clang::Sema::LookupOrdinaryName);
@@ -1210,6 +1229,8 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
12101229

12111230
for (auto *G : Guides) {
12121231
if (auto *DG = dyn_cast<CXXDeductionGuideDecl>(G)) {
1232+
if (SourceDeductionGuides.contains(DG))
1233+
continue;
12131234
// The deduction guide is a non-template function decl, we just clone it.
12141235
auto *FunctionType =
12151236
SemaRef.Context.getTrivialTypeSourceInfo(DG->getType());
@@ -1252,7 +1273,7 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
12521273
continue;
12531274
}
12541275
FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(G);
1255-
if (!F)
1276+
if (!F || SourceDeductionGuides.contains(F->getTemplatedDecl()))
12561277
continue;
12571278
// The **aggregate** deduction guides are handled in a different code path
12581279
// (DeclareAggregateDeductionGuideFromInitList), which involves the tricky

clang/test/SemaCXX/cxx20-ctad-type-alias.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -234,11 +234,23 @@ int i = 0;
234234
AFoo s{i};
235235
static_assert(__is_same(decltype(s.t), int));
236236

237+
template<class T>
238+
using BFoo = AFoo<T>;
239+
240+
// template explicit deduction guide.
241+
template<class T>
242+
Foo(T) -> Foo<float>;
243+
static_assert(__is_same(decltype(AFoo(i).t), float));
244+
static_assert(__is_same(decltype(BFoo(i).t), float));
245+
237246
// explicit deduction guide.
238247
Foo(int) -> Foo<X>;
239-
AFoo s2{i};
240-
// FIXME: the type should be X because of the above explicit deduction guide.
241-
static_assert(__is_same(decltype(s2.t), int));
248+
static_assert(__is_same(decltype(AFoo(i).t), X));
249+
static_assert(__is_same(decltype(BFoo(i).t), X));
250+
251+
Foo(double) -> Foo<int>;
252+
static_assert(__is_same(decltype(AFoo(1.0).t), int));
253+
static_assert(__is_same(decltype(BFoo(1.0).t), int));
242254
} // namespace test16
243255

244256
namespace test17 {

0 commit comments

Comments
 (0)