Skip to content

Commit f418319

Browse files
authored
Reland "[clang][Sema] Use original template pattern when declaring implicit deduction guides for nested template classes" (llvm#69676)
Reland of dd0fba1 When a nested template is instantiated, the template pattern of the inner class is not copied into the outer class ClassTemplateSpecializationDecl. The specialization contains a ClassTemplateDecl with an empty record that points to the original template pattern instead. As a result, when looking up the constructors of the inner class, no results are returned. This patch finds the original template pattern and uses that for the lookup instead. Based on CWG2471 we must also substitute the known outer template arguments when creating deduction guides for the inner class. Changes from the last iteration: 1. The outer retained levels from the outer template are always added to the `MultiLevelTemplateArgumentList` for rewriting `FunctionTemplateDecl` arguments, even if there is no FTD and the arguments are empty. 2. When building implicit deduction guides, the template pattern underlying decl is pushed as the current context. This resolves the issue where `FindInstantiatedDecl` is unable to find the inner template class. 3. Tests are updated to cover the failing case, and to assert that the type is correct after argument deduction in the implicit case.
1 parent 4950467 commit f418319

File tree

4 files changed

+50
-1
lines changed

4 files changed

+50
-1
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,11 @@ Bug Fixes to C++ Support
617617
declaration definition. Fixes:
618618
(`#61763 <https://github.com/llvm/llvm-project/issues/61763>`_)
619619

620+
- Fix a bug where implicit deduction guides are not correctly generated for nested template
621+
classes. Fixes:
622+
(`#46200 <https://github.com/llvm/llvm-project/issues/46200>`_)
623+
(`#57812 <https://github.com/llvm/llvm-project/issues/57812>`_)
624+
620625
Bug Fixes to AST Handling
621626
^^^^^^^^^^^^^^^^^^^^^^^^^
622627
- Fixed an import failure of recursive friend class template.

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2253,6 +2253,7 @@ struct ConvertConstructorToDeductionGuideTransform {
22532253

22542254
Sema &SemaRef;
22552255
ClassTemplateDecl *Template;
2256+
ClassTemplateDecl *NestedPattern = nullptr;
22562257

22572258
DeclContext *DC = Template->getDeclContext();
22582259
CXXRecordDecl *Primary = Template->getTemplatedDecl();
@@ -2332,6 +2333,9 @@ struct ConvertConstructorToDeductionGuideTransform {
23322333
Args.addOuterRetainedLevel();
23332334
}
23342335

2336+
if (NestedPattern)
2337+
Args.addOuterRetainedLevels(NestedPattern->getTemplateDepth());
2338+
23352339
FunctionProtoTypeLoc FPTL = CD->getTypeSourceInfo()->getTypeLoc()
23362340
.getAsAdjusted<FunctionProtoTypeLoc>();
23372341
assert(FPTL && "no prototype for constructor declaration");
@@ -2441,10 +2445,17 @@ struct ConvertConstructorToDeductionGuideTransform {
24412445
SmallVector<QualType, 4> ParamTypes;
24422446
const FunctionProtoType *T = TL.getTypePtr();
24432447

2448+
MultiLevelTemplateArgumentList OuterInstantiationArgs;
2449+
if (NestedPattern)
2450+
OuterInstantiationArgs = SemaRef.getTemplateInstantiationArgs(Template);
2451+
24442452
// -- The types of the function parameters are those of the constructor.
24452453
for (auto *OldParam : TL.getParams()) {
24462454
ParmVarDecl *NewParam =
24472455
transformFunctionTypeParam(OldParam, Args, MaterializedTypedefs);
2456+
if (NestedPattern && NewParam)
2457+
NewParam = transformFunctionTypeParam(NewParam, OuterInstantiationArgs,
2458+
MaterializedTypedefs);
24482459
if (!NewParam)
24492460
return QualType();
24502461
ParamTypes.push_back(NewParam->getType());
@@ -2650,13 +2661,24 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
26502661
if (BuildingDeductionGuides.isInvalid())
26512662
return;
26522663

2664+
// If the template is nested, then we need to use the original
2665+
// pattern to iterate over the constructors.
2666+
ClassTemplateDecl *Pattern = Transform.Template;
2667+
while (Pattern->getInstantiatedFromMemberTemplate()) {
2668+
if (Pattern->isMemberSpecialization())
2669+
break;
2670+
Pattern = Pattern->getInstantiatedFromMemberTemplate();
2671+
Transform.NestedPattern = Pattern;
2672+
}
2673+
26532674
// Convert declared constructors into deduction guide templates.
26542675
// FIXME: Skip constructors for which deduction must necessarily fail (those
26552676
// for which some class template parameter without a default argument never
26562677
// appears in a deduced context).
2678+
ContextRAII SavedContext(*this, Pattern->getTemplatedDecl());
26572679
llvm::SmallPtrSet<NamedDecl *, 8> ProcessedCtors;
26582680
bool AddedAny = false;
2659-
for (NamedDecl *D : LookupConstructors(Transform.Primary)) {
2681+
for (NamedDecl *D : LookupConstructors(Pattern->getTemplatedDecl())) {
26602682
D = D->getUnderlyingDecl();
26612683
if (D->isInvalidDecl() || D->isImplicit())
26622684
continue;
@@ -2702,6 +2724,8 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
27022724
Transform.buildSimpleDeductionGuide(Transform.DeducedType))
27032725
->getTemplatedDecl())
27042726
->setDeductionCandidateKind(DeductionCandidate::Copy);
2727+
2728+
SavedContext.pop();
27052729
}
27062730

27072731
/// Diagnose the presence of a default template argument on a

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@
44
template<typename T> struct A {
55
template<typename U> struct B {
66
B(...);
7+
B(const B &) = default;
78
};
89
template<typename U> B(U) -> B<U>;
910
};
1011
A<void>::B b = 123;
12+
A<void>::B copy = b;
1113

1214
using T = decltype(b);
1315
using T = A<void>::B<int>;
16+
17+
using Copy = decltype(copy);
18+
using Copy = A<void>::B<int>;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: %clang_cc1 -std=c++17 -verify %s
2+
// expected-no-diagnostics
3+
4+
template<class T> struct S {
5+
template<class U> struct N {
6+
N(T) {}
7+
N(T, U) {}
8+
template<class V> N(V, U) {}
9+
};
10+
};
11+
12+
S<int>::N x{"a", 1};
13+
14+
using T = decltype(x);
15+
using T = S<int>::N<int>;

0 commit comments

Comments
 (0)