Skip to content

Commit 04a69a1

Browse files
authored
[clang] Fix CTAD for aggregates for nested template classes (#78387)
Use the template pattern in determining whether to synthesize the aggregate deduction guide, and update DeclareImplicitDeductionGuideFromInitList to substitute outer template arguments. Fixes #77599
1 parent 3db5c05 commit 04a69a1

File tree

4 files changed

+46
-6
lines changed

4 files changed

+46
-6
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,9 @@ Bug Fixes to C++ Support
942942
(`#57410 <https://github.com/llvm/llvm-project/issues/57410>`_) and
943943
(`#76604 <https://github.com/llvm/llvm-project/issues/57410>`_)
944944

945+
- Fixes CTAD for aggregates on nested template classes. Fixes:
946+
(`#77599 <https://github.com/llvm/llvm-project/issues/77599>`_)
947+
945948
Bug Fixes to AST Handling
946949
^^^^^^^^^^^^^^^^^^^^^^^^^
947950
- Fixed an import failure of recursive friend class template.

clang/lib/Sema/SemaInit.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10718,7 +10718,14 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
1071810718
bool HasAnyDeductionGuide = false;
1071910719

1072010720
auto SynthesizeAggrGuide = [&](InitListExpr *ListInit) {
10721-
auto *RD = cast<CXXRecordDecl>(Template->getTemplatedDecl());
10721+
auto *Pattern = Template;
10722+
while (Pattern->getInstantiatedFromMemberTemplate()) {
10723+
if (Pattern->isMemberSpecialization())
10724+
break;
10725+
Pattern = Pattern->getInstantiatedFromMemberTemplate();
10726+
}
10727+
10728+
auto *RD = cast<CXXRecordDecl>(Pattern->getTemplatedDecl());
1072210729
if (!(RD->getDefinition() && RD->isAggregate()))
1072310730
return;
1072410731
QualType Ty = Context.getRecordType(RD);

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2418,16 +2418,23 @@ struct ConvertConstructorToDeductionGuideTransform {
24182418
QualType Result = SemaRef.BuildFunctionType(DeducedType, ParamTypes, Loc,
24192419
DeductionGuideName, EPI);
24202420
TypeSourceInfo *TSI = SemaRef.Context.getTrivialTypeSourceInfo(Result, Loc);
2421+
if (NestedPattern)
2422+
TSI = SemaRef.SubstType(TSI, OuterInstantiationArgs, Loc,
2423+
DeductionGuideName);
24212424

24222425
FunctionProtoTypeLoc FPTL =
24232426
TSI->getTypeLoc().castAs<FunctionProtoTypeLoc>();
24242427

24252428
// Build the parameters, needed during deduction / substitution.
24262429
SmallVector<ParmVarDecl*, 4> Params;
24272430
for (auto T : ParamTypes) {
2428-
ParmVarDecl *NewParam = ParmVarDecl::Create(
2429-
SemaRef.Context, DC, Loc, Loc, nullptr, T,
2430-
SemaRef.Context.getTrivialTypeSourceInfo(T, Loc), SC_None, nullptr);
2431+
auto *TSI = SemaRef.Context.getTrivialTypeSourceInfo(T, Loc);
2432+
if (NestedPattern)
2433+
TSI = SemaRef.SubstType(TSI, OuterInstantiationArgs, Loc,
2434+
DeclarationName());
2435+
ParmVarDecl *NewParam =
2436+
ParmVarDecl::Create(SemaRef.Context, DC, Loc, Loc, nullptr,
2437+
TSI->getType(), TSI, SC_None, nullptr);
24312438
NewParam->setScopeInfo(0, Params.size());
24322439
FPTL.setParam(Params.size(), NewParam);
24332440
Params.push_back(NewParam);
@@ -2670,8 +2677,14 @@ FunctionTemplateDecl *Sema::DeclareImplicitDeductionGuideFromInitList(
26702677
if (BuildingDeductionGuides.isInvalid())
26712678
return nullptr;
26722679

2673-
return cast<FunctionTemplateDecl>(
2680+
ClassTemplateDecl *Pattern =
2681+
Transform.NestedPattern ? Transform.NestedPattern : Transform.Template;
2682+
ContextRAII SavedContext(*this, Pattern->getTemplatedDecl());
2683+
2684+
auto *DG = cast<FunctionTemplateDecl>(
26742685
Transform.buildSimpleDeductionGuide(ParamTypes));
2686+
SavedContext.pop();
2687+
return DG;
26752688
}
26762689

26772690
void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,

clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// RUN: %clang_cc1 -std=c++20 -verify %s
2-
// expected-no-diagnostics
32

43
template<class T> struct S {
54
template<class U> struct N {
@@ -58,3 +57,21 @@ template<class X> struct requires_clause {
5857
requires_clause<int>::B req(1, 2);
5958
using RC = decltype(req);
6059
using RC = requires_clause<int>::B<int>;
60+
61+
template<typename X> struct nested_init_list {
62+
template<C<X> Y>
63+
struct B { // #INIT_LIST_INNER
64+
X x;
65+
Y y;
66+
};
67+
};
68+
69+
nested_init_list<int>::B nil {1, 2};
70+
using NIL = decltype(nil);
71+
using NIL = nested_init_list<int>::B<int>;
72+
73+
// expected-error@+1 {{no viable constructor or deduction guide for deduction of template arguments of 'B'}}
74+
nested_init_list<int>::B nil_invalid {1, ""};
75+
// expected-note@#INIT_LIST_INNER {{candidate template ignored: substitution failure [with Y = const char *]: constraints not satisfied for class template 'B' [with Y = const char *]}}
76+
// expected-note@#INIT_LIST_INNER {{candidate function template not viable: requires 1 argument, but 2 were provided}}
77+
// expected-note@#INIT_LIST_INNER {{candidate function template not viable: requires 0 arguments, but 2 were provided}}

0 commit comments

Comments
 (0)