Skip to content

Commit 2d79745

Browse files
committed
[clang] Implement transforms for DeducedTemplateName
Fixes regression introduced in #94981, reported on the pull-request. Since this fixes a commit which was never released, there are no release notes.
1 parent 981bb9d commit 2d79745

File tree

4 files changed

+178
-61
lines changed

4 files changed

+178
-61
lines changed

clang/lib/Sema/SemaTemplateInstantiate.cpp

+5-3
Original file line numberDiff line numberDiff line change
@@ -1973,9 +1973,11 @@ TemplateName TemplateInstantiator::TransformTemplateName(
19731973
CXXScopeSpec &SS, TemplateName Name, SourceLocation NameLoc,
19741974
QualType ObjectType, NamedDecl *FirstQualifierInScope,
19751975
bool AllowInjectedClassName) {
1976-
if (TemplateTemplateParmDecl *TTP
1977-
= dyn_cast_or_null<TemplateTemplateParmDecl>(Name.getAsTemplateDecl())) {
1978-
if (TTP->getDepth() < TemplateArgs.getNumLevels()) {
1976+
// FIXME: Don't lose sugar here.
1977+
if (auto [TD, DefArgs] = Name.getTemplateDeclAndDefaultArgs();
1978+
TD && DefArgs.Args.empty()) {
1979+
if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TD);
1980+
TTP && TTP->getDepth() < TemplateArgs.getNumLevels()) {
19791981
// If the corresponding template argument is NULL or non-existent, it's
19801982
// because we are performing instantiation from explicitly-specified
19811983
// template arguments in a function template, but there were some

clang/lib/Sema/TreeTransform.h

+93-57
Original file line numberDiff line numberDiff line change
@@ -4540,6 +4540,63 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
45404540
return SS.getWithLocInContext(SemaRef.Context);
45414541
}
45424542

4543+
/// Iterator adaptor that invents template argument location information
4544+
/// for each of the template arguments in its underlying iterator.
4545+
template <typename Derived, typename InputIterator>
4546+
class TemplateArgumentLocInventIterator {
4547+
TreeTransform<Derived> &Self;
4548+
InputIterator Iter;
4549+
4550+
public:
4551+
typedef TemplateArgumentLoc value_type;
4552+
typedef TemplateArgumentLoc reference;
4553+
typedef typename std::iterator_traits<InputIterator>::difference_type
4554+
difference_type;
4555+
typedef std::input_iterator_tag iterator_category;
4556+
4557+
class pointer {
4558+
TemplateArgumentLoc Arg;
4559+
4560+
public:
4561+
explicit pointer(TemplateArgumentLoc Arg) : Arg(Arg) {}
4562+
4563+
const TemplateArgumentLoc *operator->() const { return &Arg; }
4564+
};
4565+
4566+
explicit TemplateArgumentLocInventIterator(TreeTransform<Derived> &Self,
4567+
InputIterator Iter)
4568+
: Self(Self), Iter(Iter) {}
4569+
4570+
TemplateArgumentLocInventIterator &operator++() {
4571+
++Iter;
4572+
return *this;
4573+
}
4574+
4575+
TemplateArgumentLocInventIterator operator++(int) {
4576+
TemplateArgumentLocInventIterator Old(*this);
4577+
++(*this);
4578+
return Old;
4579+
}
4580+
4581+
reference operator*() const {
4582+
TemplateArgumentLoc Result;
4583+
Self.InventTemplateArgumentLoc(*Iter, Result);
4584+
return Result;
4585+
}
4586+
4587+
pointer operator->() const { return pointer(**this); }
4588+
4589+
friend bool operator==(const TemplateArgumentLocInventIterator &X,
4590+
const TemplateArgumentLocInventIterator &Y) {
4591+
return X.Iter == Y.Iter;
4592+
}
4593+
4594+
friend bool operator!=(const TemplateArgumentLocInventIterator &X,
4595+
const TemplateArgumentLocInventIterator &Y) {
4596+
return X.Iter != Y.Iter;
4597+
}
4598+
};
4599+
45434600
template<typename Derived>
45444601
DeclarationNameInfo
45454602
TreeTransform<Derived>
@@ -4661,6 +4718,42 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
46614718
ObjectType, AllowInjectedClassName);
46624719
}
46634720

4721+
if (DeducedTemplateStorage *DTN = Name.getAsDeducedTemplateName()) {
4722+
TemplateName Underlying = DTN->getUnderlying();
4723+
TemplateName TransUnderlying = getDerived().TransformTemplateName(
4724+
SS, Underlying, NameLoc, ObjectType, FirstQualifierInScope,
4725+
AllowInjectedClassName);
4726+
if (TransUnderlying.isNull())
4727+
return TemplateName();
4728+
4729+
DefaultArguments DefArgs = DTN->getDefaultArguments();
4730+
4731+
TemplateArgumentListInfo TransArgsInfo;
4732+
using Iterator =
4733+
TemplateArgumentLocInventIterator<Derived, TemplateArgument *>;
4734+
if (getDerived().TransformTemplateArguments(
4735+
Iterator(*this,
4736+
const_cast<TemplateArgument *>(DefArgs.Args.begin())),
4737+
Iterator(*this, const_cast<TemplateArgument *>(DefArgs.Args.end())),
4738+
TransArgsInfo))
4739+
return TemplateName();
4740+
4741+
SmallVector<TemplateArgument, 4> TransArgs(
4742+
TransArgsInfo.arguments().size());
4743+
for (unsigned I = 0; I < TransArgs.size(); ++I)
4744+
TransArgs[I] = TransArgsInfo.arguments()[I].getArgument();
4745+
4746+
return getSema().Context.getDeducedTemplateName(
4747+
TransUnderlying, DefaultArguments{DefArgs.StartPos, TransArgs});
4748+
}
4749+
4750+
// FIXME: Preserve SubstTemplateTemplateParm.
4751+
if (SubstTemplateTemplateParmStorage *STN =
4752+
Name.getAsSubstTemplateTemplateParm())
4753+
return getDerived().TransformTemplateName(
4754+
SS, STN->getReplacement(), NameLoc, ObjectType, FirstQualifierInScope,
4755+
AllowInjectedClassName);
4756+
46644757
// FIXME: Try to preserve more of the TemplateName.
46654758
if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
46664759
TemplateDecl *TransTemplate
@@ -4807,63 +4900,6 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
48074900
return true;
48084901
}
48094902

4810-
/// Iterator adaptor that invents template argument location information
4811-
/// for each of the template arguments in its underlying iterator.
4812-
template<typename Derived, typename InputIterator>
4813-
class TemplateArgumentLocInventIterator {
4814-
TreeTransform<Derived> &Self;
4815-
InputIterator Iter;
4816-
4817-
public:
4818-
typedef TemplateArgumentLoc value_type;
4819-
typedef TemplateArgumentLoc reference;
4820-
typedef typename std::iterator_traits<InputIterator>::difference_type
4821-
difference_type;
4822-
typedef std::input_iterator_tag iterator_category;
4823-
4824-
class pointer {
4825-
TemplateArgumentLoc Arg;
4826-
4827-
public:
4828-
explicit pointer(TemplateArgumentLoc Arg) : Arg(Arg) { }
4829-
4830-
const TemplateArgumentLoc *operator->() const { return &Arg; }
4831-
};
4832-
4833-
explicit TemplateArgumentLocInventIterator(TreeTransform<Derived> &Self,
4834-
InputIterator Iter)
4835-
: Self(Self), Iter(Iter) { }
4836-
4837-
TemplateArgumentLocInventIterator &operator++() {
4838-
++Iter;
4839-
return *this;
4840-
}
4841-
4842-
TemplateArgumentLocInventIterator operator++(int) {
4843-
TemplateArgumentLocInventIterator Old(*this);
4844-
++(*this);
4845-
return Old;
4846-
}
4847-
4848-
reference operator*() const {
4849-
TemplateArgumentLoc Result;
4850-
Self.InventTemplateArgumentLoc(*Iter, Result);
4851-
return Result;
4852-
}
4853-
4854-
pointer operator->() const { return pointer(**this); }
4855-
4856-
friend bool operator==(const TemplateArgumentLocInventIterator &X,
4857-
const TemplateArgumentLocInventIterator &Y) {
4858-
return X.Iter == Y.Iter;
4859-
}
4860-
4861-
friend bool operator!=(const TemplateArgumentLocInventIterator &X,
4862-
const TemplateArgumentLocInventIterator &Y) {
4863-
return X.Iter != Y.Iter;
4864-
}
4865-
};
4866-
48674903
template<typename Derived>
48684904
template<typename InputIterator>
48694905
bool TreeTransform<Derived>::TransformTemplateArguments(

clang/test/AST/ast-dump-template-name.cpp

+66-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
1-
// RUN: %clang_cc1 -std=c++26 -ast-dump -ast-dump-filter=Test %s | FileCheck %s
1+
// Test without serialization:
2+
// RUN: %clang_cc1 -std=c++26 -triple x86_64-unknown-unknown -ast-dump -ast-dump-filter=Test %s \
3+
// RUN: | FileCheck -strict-whitespace %s
4+
//
5+
// Test with serialization:
6+
// RUN: %clang_cc1 -std=c++26 -triple x86_64-unknown-unknown -emit-pch -o %t %s
7+
// RUN: %clang_cc1 -x c++ -std=c++26 -triple x86_64-unknown-unknown -include-pch %t \
8+
// RUN: -ast-dump-all -ast-dump-filter=Test /dev/null \
9+
// RUN: | sed -e "s/ <undeserialized declarations>//" -e "s/ imported//" \
10+
// RUN: | FileCheck --strict-whitespace %s
211

312
template <template <class> class TT> using N = TT<int>;
413

@@ -58,3 +67,59 @@ namespace subst {
5867
// CHECK-NEXT: | |-associated ClassTemplateSpecialization {{.+}} 'B'{{$}}
5968
// CHECK-NEXT: | `-replacement:
6069
// CHECK-NEXT: | `-ClassTemplateDecl {{.+}} A{{$}}
70+
71+
namespace deduced {
72+
template <class> struct D;
73+
74+
template <class ET, template <class> class VT>
75+
struct D<VT<ET>> {
76+
using E = VT<char>;
77+
template <class C> using F = VT<C>;
78+
};
79+
80+
template <typename, int> class Matrix;
81+
82+
using TestDeduced1 = D<Matrix<double, 3>>::E;
83+
using TestDeduced2 = D<Matrix<double, 3>>::F<int>;
84+
} // namespace deduced
85+
86+
// CHECK: Dumping deduced::TestDeduced1:
87+
// CHECK-NEXT: TypeAliasDecl
88+
// CHECK-NEXT: `-ElaboratedType
89+
// CHECK-NEXT: `-TypedefType
90+
// CHECK-NEXT: |-TypeAlias
91+
// CHECK-NEXT: `-ElaboratedType
92+
// CHECK-NEXT: `-TemplateSpecializationType
93+
// CHECK-NEXT: |-name: 'deduced::Matrix:1<3>' subst index 1
94+
// CHECK-NEXT: | |-parameter: TemplateTemplateParmDecl {{.+}} depth 0 index 1 VT
95+
// CHECK-NEXT: | |-associated
96+
// CHECK-NEXT: | `-replacement: 'deduced::Matrix:1<3>' deduced
97+
// CHECK-NEXT: | |-underlying: 'deduced::Matrix'
98+
// CHECK-NEXT: | | `-ClassTemplateDecl {{.+}} Matrix
99+
// CHECK-NEXT: | `-defaults: start 1
100+
// CHECK-NEXT: | `-TemplateArgument integral '3'
101+
// CHECK-NEXT: |-TemplateArgument type 'char'
102+
// CHECK-NEXT: | `-BuiltinType
103+
// CHECK-NEXT: `-RecordType
104+
// CHECK-NEXT: `-ClassTemplateSpecialization
105+
106+
// CHECK: Dumping deduced::TestDeduced2:
107+
// CHECK-NEXT: TypeAliasDecl
108+
// CHECK-NEXT: `-ElaboratedType
109+
// CHECK-NEXT: `-TemplateSpecializationType
110+
// CHECK-NEXT: |-name: 'D<Matrix<double, 3>>::F':'deduced::D<deduced::Matrix<double, 3>>::F
111+
// CHECK-NEXT: | |-NestedNameSpecifier
112+
// CHECK-NEXT: | `-TypeAliasTemplateDecl
113+
// CHECK-NEXT: |-TemplateArgument type 'int'
114+
// CHECK-NEXT: | `-BuiltinType
115+
// CHECK-NEXT: `-ElaboratedType
116+
// CHECK-NEXT: `-TemplateSpecializationType
117+
// CHECK-NEXT: |-name: 'Matrix:1<3>':'deduced::Matrix:1<3>' deduced
118+
// CHECK-NEXT: | |-underlying: 'Matrix':'deduced::Matrix' qualified
119+
// CHECK-NEXT: | | `-ClassTemplateDecl {{.+}} Matrix
120+
// CHECK-NEXT: | `-defaults: start 1
121+
// CHECK-NEXT: | `-TemplateArgument expr '3'
122+
// CHECK-NEXT: |-TemplateArgument type 'int'
123+
// CHECK-NEXT: | `-BuiltinType
124+
// CHECK-NEXT: `-RecordType
125+
// CHECK-NEXT: `-ClassTemplateSpecialization

clang/test/SemaTemplate/cwg2398.cpp

+14
Original file line numberDiff line numberDiff line change
@@ -379,3 +379,17 @@ namespace regression1 {
379379
bar(input);
380380
}
381381
} // namespace regression1
382+
383+
namespace regression2 {
384+
template <class> struct D;
385+
// old-note@-1 {{template is declared here}}
386+
387+
template <class ET, template <class> class VT>
388+
struct D<VT<ET>> {
389+
template <class C> using E = VT<C>;
390+
};
391+
392+
template <typename, int> class Matrix;
393+
using X = D<Matrix<double, 3>>::E<int>;
394+
// old-error@-1 {{implicit instantiation of undefined template}}
395+
} // namespace regression2

0 commit comments

Comments
 (0)