Skip to content

Commit 8b7263b

Browse files
authored
[clang] CTAD: use index and depth to retrieve template parameter for TemplateParamsReferencedInTemplateArgumentList (#98013)
As described in #90209 (comment), Clang may not preserve enough information during template argument deduction. This can result in a merely canonical `TemplateTypeParmType` with a null `Decl`, leading to an incomplete template parameter list for the synthesized deduction guide. This patch addresses the issue by using the index and depth information to retrieve the corresponding template parameter, rather than relying on `TTP->getDecl()`. Fixes #90209
1 parent d9c26b9 commit 8b7263b

File tree

2 files changed

+99
-22
lines changed

2 files changed

+99
-22
lines changed

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "clang/Sema/SemaInternal.h"
3838
#include "clang/Sema/Template.h"
3939
#include "clang/Sema/TemplateDeduction.h"
40+
#include "llvm/ADT/BitVector.h"
4041
#include "llvm/ADT/SmallBitVector.h"
4142
#include "llvm/ADT/SmallString.h"
4243
#include "llvm/ADT/StringExtras.h"
@@ -2751,23 +2752,48 @@ struct ConvertConstructorToDeductionGuideTransform {
27512752
}
27522753
};
27532754

2755+
unsigned getTemplateParameterDepth(NamedDecl *TemplateParam) {
2756+
if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParam))
2757+
return TTP->getDepth();
2758+
if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParam))
2759+
return TTP->getDepth();
2760+
if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(TemplateParam))
2761+
return NTTP->getDepth();
2762+
llvm_unreachable("Unhandled template parameter types");
2763+
}
2764+
2765+
unsigned getTemplateParameterIndex(NamedDecl *TemplateParam) {
2766+
if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParam))
2767+
return TTP->getIndex();
2768+
if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParam))
2769+
return TTP->getIndex();
2770+
if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(TemplateParam))
2771+
return NTTP->getIndex();
2772+
llvm_unreachable("Unhandled template parameter types");
2773+
}
2774+
27542775
// Find all template parameters that appear in the given DeducedArgs.
27552776
// Return the indices of the template parameters in the TemplateParams.
27562777
SmallVector<unsigned> TemplateParamsReferencedInTemplateArgumentList(
2757-
ArrayRef<NamedDecl *> TemplateParams,
2778+
const TemplateParameterList *TemplateParamsList,
27582779
ArrayRef<TemplateArgument> DeducedArgs) {
27592780
struct TemplateParamsReferencedFinder
27602781
: public RecursiveASTVisitor<TemplateParamsReferencedFinder> {
2761-
llvm::DenseSet<NamedDecl *> TemplateParams;
2762-
llvm::DenseSet<const NamedDecl *> ReferencedTemplateParams;
2782+
const TemplateParameterList *TemplateParamList;
2783+
llvm::BitVector ReferencedTemplateParams;
27632784

2764-
TemplateParamsReferencedFinder(ArrayRef<NamedDecl *> TemplateParams)
2765-
: TemplateParams(TemplateParams.begin(), TemplateParams.end()) {}
2785+
TemplateParamsReferencedFinder(
2786+
const TemplateParameterList *TemplateParamList)
2787+
: TemplateParamList(TemplateParamList),
2788+
ReferencedTemplateParams(TemplateParamList->size()) {}
27662789

27672790
bool VisitTemplateTypeParmType(TemplateTypeParmType *TTP) {
2768-
MarkAppeared(TTP->getDecl());
2791+
// We use the index and depth to retrieve the corresponding template
2792+
// parameter from the parameter list, which is more robost.
2793+
Mark(TTP->getDepth(), TTP->getIndex());
27692794
return true;
27702795
}
2796+
27712797
bool VisitDeclRefExpr(DeclRefExpr *DRE) {
27722798
MarkAppeared(DRE->getFoundDecl());
27732799
return true;
@@ -2780,16 +2806,22 @@ SmallVector<unsigned> TemplateParamsReferencedInTemplateArgumentList(
27802806
}
27812807

27822808
void MarkAppeared(NamedDecl *ND) {
2783-
if (TemplateParams.contains(ND))
2784-
ReferencedTemplateParams.insert(ND);
2809+
if (llvm::isa<NonTypeTemplateParmDecl, TemplateTypeParmDecl,
2810+
TemplateTemplateParmDecl>(ND))
2811+
Mark(getTemplateParameterDepth(ND), getTemplateParameterIndex(ND));
2812+
}
2813+
void Mark(unsigned Depth, unsigned Index) {
2814+
if (Index < TemplateParamList->size() &&
2815+
TemplateParamList->getParam(Index)->getTemplateDepth() == Depth)
2816+
ReferencedTemplateParams.set(Index);
27852817
}
27862818
};
2787-
TemplateParamsReferencedFinder Finder(TemplateParams);
2819+
TemplateParamsReferencedFinder Finder(TemplateParamsList);
27882820
Finder.TraverseTemplateArguments(DeducedArgs);
27892821

27902822
SmallVector<unsigned> Results;
2791-
for (unsigned Index = 0; Index < TemplateParams.size(); ++Index) {
2792-
if (Finder.ReferencedTemplateParams.contains(TemplateParams[Index]))
2823+
for (unsigned Index = 0; Index < TemplateParamsList->size(); ++Index) {
2824+
if (Finder.ReferencedTemplateParams[Index])
27932825
Results.push_back(Index);
27942826
}
27952827
return Results;
@@ -2808,16 +2840,6 @@ bool hasDeclaredDeductionGuides(DeclarationName Name, DeclContext *DC) {
28082840
return false;
28092841
}
28102842

2811-
unsigned getTemplateParameterDepth(NamedDecl *TemplateParam) {
2812-
if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParam))
2813-
return TTP->getDepth();
2814-
if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParam))
2815-
return TTP->getDepth();
2816-
if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(TemplateParam))
2817-
return NTTP->getDepth();
2818-
llvm_unreachable("Unhandled template parameter types");
2819-
}
2820-
28212843
NamedDecl *transformTemplateParameter(Sema &SemaRef, DeclContext *DC,
28222844
NamedDecl *TemplateParam,
28232845
MultiLevelTemplateArgumentList &Args,
@@ -3149,7 +3171,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
31493171
}
31503172
auto DeducedAliasTemplateParams =
31513173
TemplateParamsReferencedInTemplateArgumentList(
3152-
AliasTemplate->getTemplateParameters()->asArray(), DeducedArgs);
3174+
AliasTemplate->getTemplateParameters(), DeducedArgs);
31533175
// All template arguments null by default.
31543176
SmallVector<TemplateArgument> TemplateArgsForBuildingFPrime(
31553177
F->getTemplateParameters()->size());

clang/test/AST/ast-dump-ctad-alias.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,58 @@ BFoo b2(1.0, 2.0);
9999
// CHECK-NEXT: | | |-ParmVarDecl {{.*}} 'type-parameter-0-0'
100100
// CHECK-NEXT: | | `-ParmVarDecl {{.*}} 'type-parameter-0-0'
101101
// CHECK-NEXT: | `-CXXDeductionGuideDecl {{.*}} implicit used <deduction guide for BFoo> 'auto (double, double) -> Foo<double, double>' implicit_instantiation
102+
103+
namespace GH90209 {
104+
// Case 1: type template parameter
105+
template <class Ts>
106+
struct List1 {
107+
List1(int);
108+
};
109+
110+
template <class T1>
111+
struct TemplatedClass1 {
112+
TemplatedClass1(T1);
113+
};
114+
115+
template <class T1>
116+
TemplatedClass1(T1) -> TemplatedClass1<List1<T1>>;
117+
118+
template <class T2>
119+
using ATemplatedClass1 = TemplatedClass1<List1<T2>>;
120+
121+
ATemplatedClass1 test1(1);
122+
// Verify that we have a correct template parameter list for the deduction guide.
123+
//
124+
// CHECK: FunctionTemplateDecl {{.*}} <deduction guide for ATemplatedClass1>
125+
// CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} class depth 0 index 0 T2
126+
// CHECK-NEXT: |-TypeTraitExpr {{.*}} 'bool' __is_deducible
127+
128+
// Case 2: template template parameter
129+
template<typename K> struct Foo{};
130+
131+
template <template<typename> typename Ts>
132+
struct List2 {
133+
List2(int);
134+
};
135+
136+
template <typename T1>
137+
struct TemplatedClass2 {
138+
TemplatedClass2(T1);
139+
};
140+
141+
template <template<typename> typename T1>
142+
TemplatedClass2(T1<int>) -> TemplatedClass2<List2<T1>>;
143+
144+
template <template<typename> typename T2>
145+
using ATemplatedClass2 = TemplatedClass2<List2<T2>>;
146+
147+
List2<Foo> list(1);
148+
ATemplatedClass2 test2(list);
149+
// Verify that we have a correct template parameter list for the deduction guide.
150+
//
151+
// CHECK: FunctionTemplateDecl {{.*}} <deduction guide for ATemplatedClass2>
152+
// CHECK-NEXT: |-TemplateTemplateParmDecl {{.*}} depth 0 index 0 T2
153+
// CHECK-NEXT: | `-TemplateTypeParmDecl {{.*}} typename depth 0 index 0
154+
// CHECK-NEXT: |-TypeTraitExpr {{.*}} 'bool' __is_deducible
155+
156+
} // namespace GH90209

0 commit comments

Comments
 (0)