Skip to content

Commit dd0fba1

Browse files
authored
[clang][Sema] Use original template pattern when declaring implicit deduction guides for nested template classes (#68379)
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. Fixes #46200 Fixes #57812
1 parent f6f944e commit dd0fba1

File tree

3 files changed

+38
-1
lines changed

3 files changed

+38
-1
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,11 @@ Bug Fixes to C++ Support
513513
rather than prefer the non-templated constructor as specified in
514514
[standard.group]p3.
515515

516+
- Fix a bug where implicit deduction guides are not correctly generated for nested template
517+
classes. Fixes:
518+
(`#46200 <https://github.com/llvm/llvm-project/issues/46200>`_)
519+
(`#57812 <https://github.com/llvm/llvm-project/issues/57812>`_)
520+
516521
Bug Fixes to AST Handling
517522
^^^^^^^^^^^^^^^^^^^^^^^^^
518523
- Fixed an import failure of recursive friend class template.

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2250,6 +2250,7 @@ struct ConvertConstructorToDeductionGuideTransform {
22502250

22512251
Sema &SemaRef;
22522252
ClassTemplateDecl *Template;
2253+
ClassTemplateDecl *NestedPattern = nullptr;
22532254

22542255
DeclContext *DC = Template->getDeclContext();
22552256
CXXRecordDecl *Primary = Template->getTemplatedDecl();
@@ -2327,6 +2328,8 @@ struct ConvertConstructorToDeductionGuideTransform {
23272328
if (FTD) {
23282329
Args.addOuterTemplateArguments(SubstArgs);
23292330
Args.addOuterRetainedLevel();
2331+
if (NestedPattern)
2332+
Args.addOuterRetainedLevels(NestedPattern->getTemplateDepth());
23302333
}
23312334

23322335
FunctionProtoTypeLoc FPTL = CD->getTypeSourceInfo()->getTypeLoc()
@@ -2438,10 +2441,17 @@ struct ConvertConstructorToDeductionGuideTransform {
24382441
SmallVector<QualType, 4> ParamTypes;
24392442
const FunctionProtoType *T = TL.getTypePtr();
24402443

2444+
MultiLevelTemplateArgumentList OuterInstantiationArgs;
2445+
if (NestedPattern)
2446+
OuterInstantiationArgs = SemaRef.getTemplateInstantiationArgs(Template);
2447+
24412448
// -- The types of the function parameters are those of the constructor.
24422449
for (auto *OldParam : TL.getParams()) {
24432450
ParmVarDecl *NewParam =
24442451
transformFunctionTypeParam(OldParam, Args, MaterializedTypedefs);
2452+
if (NestedPattern && NewParam)
2453+
NewParam = transformFunctionTypeParam(NewParam, OuterInstantiationArgs,
2454+
MaterializedTypedefs);
24452455
if (!NewParam)
24462456
return QualType();
24472457
ParamTypes.push_back(NewParam->getType());
@@ -2647,13 +2657,23 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
26472657
if (BuildingDeductionGuides.isInvalid())
26482658
return;
26492659

2660+
// If the template is nested, then we need to use the original
2661+
// pattern to iterate over the constructors.
2662+
ClassTemplateDecl *Pattern = Transform.Template;
2663+
while (Pattern->getInstantiatedFromMemberTemplate()) {
2664+
if (Pattern->isMemberSpecialization())
2665+
break;
2666+
Pattern = Pattern->getInstantiatedFromMemberTemplate();
2667+
Transform.NestedPattern = Pattern;
2668+
}
2669+
26502670
// Convert declared constructors into deduction guide templates.
26512671
// FIXME: Skip constructors for which deduction must necessarily fail (those
26522672
// for which some class template parameter without a default argument never
26532673
// appears in a deduced context).
26542674
llvm::SmallPtrSet<NamedDecl *, 8> ProcessedCtors;
26552675
bool AddedAny = false;
2656-
for (NamedDecl *D : LookupConstructors(Transform.Primary)) {
2676+
for (NamedDecl *D : LookupConstructors(Pattern->getTemplatedDecl())) {
26572677
D = D->getUnderlyingDecl();
26582678
if (D->isInvalidDecl() || D->isImplicit())
26592679
continue;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
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};

0 commit comments

Comments
 (0)