Skip to content

Commit b3ea9b3

Browse files
authored
Reland "[clang] Fix CTAD for aggregates for nested template classes" (#78670)
Reland of #78387 Use the template pattern in determining whether to synthesize the aggregate deduction guide, and update DeclareImplicitDeductionGuideFromInitList to substitute outer template arguments. The tests in the original patch made an assumption about the size of a pointer type, and this led to them failing on targets with 32-bit pointers. The tests have been updated to not depend on the size of any type. This only requires updates to the test file, no functionality has otherwise changed between this and the original patch.
1 parent 0223230 commit b3ea9b3

File tree

4 files changed

+58
-9
lines changed

4 files changed

+58
-9
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,9 @@ Bug Fixes to C++ Support
10011001
- Clang now allows parenthesized initialization of arrays in `operator new[]`.
10021002
Fixes: (`#68198 <https://github.com/llvm/llvm-project/issues/68198>`_)
10031003

1004+
- Fixes CTAD for aggregates on nested template classes. Fixes:
1005+
(`#77599 <https://github.com/llvm/llvm-project/issues/77599>`_)
1006+
10041007
- Fix crash when importing the same module with an dynamic initializer twice
10051008
in different visibility.
10061009
Fixes (`#67893 <https://github.com/llvm/llvm-project/issues/67893>`_)

clang/lib/Sema/SemaInit.cpp

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

1075310753
auto SynthesizeAggrGuide = [&](InitListExpr *ListInit) {
10754-
auto *RD = cast<CXXRecordDecl>(Template->getTemplatedDecl());
10754+
auto *Pattern = Template;
10755+
while (Pattern->getInstantiatedFromMemberTemplate()) {
10756+
if (Pattern->isMemberSpecialization())
10757+
break;
10758+
Pattern = Pattern->getInstantiatedFromMemberTemplate();
10759+
}
10760+
10761+
auto *RD = cast<CXXRecordDecl>(Pattern->getTemplatedDecl());
1075510762
if (!(RD->getDefinition() && RD->isAggregate()))
1075610763
return;
1075710764
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: 30 additions & 4 deletions
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 {
@@ -36,11 +35,14 @@ using NonTypeParam = decltype(ntp);
3635
using NonTypeParam = non_type_param<int>::B<int>;
3736

3837
template<typename A, typename T>
39-
concept C = (sizeof(T) == sizeof(A));
38+
concept True = true;
39+
40+
template<typename T>
41+
concept False = false;
4042

4143
template<class X> struct concepts {
4244
template<class Y> struct B {
43-
template<class K = X, C<K> Z> B(Y, Z);
45+
template<class K = X, True<K> Z> B(Y, Z);
4446
};
4547
};
4648

@@ -50,11 +52,35 @@ using Concepts = concepts<int>::B<int>;
5052

5153
template<class X> struct requires_clause {
5254
template<class Y> struct B {
53-
template<class Z> requires (sizeof(Z) == sizeof(X))
55+
template<class Z> requires true
5456
B(Y, Z);
5557
};
5658
};
5759

5860
requires_clause<int>::B req(1, 2);
5961
using RC = decltype(req);
6062
using RC = requires_clause<int>::B<int>;
63+
64+
template<typename X> struct nested_init_list {
65+
template<True<X> Y>
66+
struct B {
67+
X x;
68+
Y y;
69+
};
70+
71+
template<False F>
72+
struct concept_fail { // #INIT_LIST_INNER_INVALID
73+
X x;
74+
F f;
75+
};
76+
};
77+
78+
nested_init_list<int>::B nil {1, 2};
79+
using NIL = decltype(nil);
80+
using NIL = nested_init_list<int>::B<int>;
81+
82+
// expected-error@+1 {{no viable constructor or deduction guide for deduction of template arguments of 'concept_fail'}}
83+
nested_init_list<int>::concept_fail nil_invalid{1, ""};
84+
// expected-note@#INIT_LIST_INNER_INVALID {{candidate template ignored: substitution failure [with F = const char *]: constraints not satisfied for class template 'concept_fail' [with F = const char *]}}
85+
// expected-note@#INIT_LIST_INNER_INVALID {{candidate function template not viable: requires 1 argument, but 2 were provided}}
86+
// expected-note@#INIT_LIST_INNER_INVALID {{candidate function template not viable: requires 0 arguments, but 2 were provided}}

0 commit comments

Comments
 (0)