[clang] [clang] Implement transforms for DeducedTemplateName (PR #108491)
Matheus Izvekov via cfe-commits
cfe-commits at lists.llvm.org
Thu Sep 12 22:26:36 PDT 2024
https://github.com/mizvekov created https://github.com/llvm/llvm-project/pull/108491
Fixes regression introduced in #94981, reported on the pull-request.
Since this fixes a commit which was never released, there are no release notes.
>From 2d79745e93cdda66cec9781efa7e10bce5544e8f Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizvekov at gmail.com>
Date: Fri, 13 Sep 2024 02:21:36 -0300
Subject: [PATCH] [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.
---
clang/lib/Sema/SemaTemplateInstantiate.cpp | 8 +-
clang/lib/Sema/TreeTransform.h | 150 +++++++++++++--------
clang/test/AST/ast-dump-template-name.cpp | 67 ++++++++-
clang/test/SemaTemplate/cwg2398.cpp | 14 ++
4 files changed, 178 insertions(+), 61 deletions(-)
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index c42cc250bb904a..48ba7aae15268c 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1973,9 +1973,11 @@ TemplateName TemplateInstantiator::TransformTemplateName(
CXXScopeSpec &SS, TemplateName Name, SourceLocation NameLoc,
QualType ObjectType, NamedDecl *FirstQualifierInScope,
bool AllowInjectedClassName) {
- if (TemplateTemplateParmDecl *TTP
- = dyn_cast_or_null<TemplateTemplateParmDecl>(Name.getAsTemplateDecl())) {
- if (TTP->getDepth() < TemplateArgs.getNumLevels()) {
+ // FIXME: Don't lose sugar here.
+ if (auto [TD, DefArgs] = Name.getTemplateDeclAndDefaultArgs();
+ TD && DefArgs.Args.empty()) {
+ if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TD);
+ TTP && TTP->getDepth() < TemplateArgs.getNumLevels()) {
// If the corresponding template argument is NULL or non-existent, it's
// because we are performing instantiation from explicitly-specified
// template arguments in a function template, but there were some
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index ff745b3385fcd9..b149cf13edc7b0 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -4540,6 +4540,63 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
return SS.getWithLocInContext(SemaRef.Context);
}
+/// Iterator adaptor that invents template argument location information
+/// for each of the template arguments in its underlying iterator.
+template <typename Derived, typename InputIterator>
+class TemplateArgumentLocInventIterator {
+ TreeTransform<Derived> &Self;
+ InputIterator Iter;
+
+public:
+ typedef TemplateArgumentLoc value_type;
+ typedef TemplateArgumentLoc reference;
+ typedef typename std::iterator_traits<InputIterator>::difference_type
+ difference_type;
+ typedef std::input_iterator_tag iterator_category;
+
+ class pointer {
+ TemplateArgumentLoc Arg;
+
+ public:
+ explicit pointer(TemplateArgumentLoc Arg) : Arg(Arg) {}
+
+ const TemplateArgumentLoc *operator->() const { return &Arg; }
+ };
+
+ explicit TemplateArgumentLocInventIterator(TreeTransform<Derived> &Self,
+ InputIterator Iter)
+ : Self(Self), Iter(Iter) {}
+
+ TemplateArgumentLocInventIterator &operator++() {
+ ++Iter;
+ return *this;
+ }
+
+ TemplateArgumentLocInventIterator operator++(int) {
+ TemplateArgumentLocInventIterator Old(*this);
+ ++(*this);
+ return Old;
+ }
+
+ reference operator*() const {
+ TemplateArgumentLoc Result;
+ Self.InventTemplateArgumentLoc(*Iter, Result);
+ return Result;
+ }
+
+ pointer operator->() const { return pointer(**this); }
+
+ friend bool operator==(const TemplateArgumentLocInventIterator &X,
+ const TemplateArgumentLocInventIterator &Y) {
+ return X.Iter == Y.Iter;
+ }
+
+ friend bool operator!=(const TemplateArgumentLocInventIterator &X,
+ const TemplateArgumentLocInventIterator &Y) {
+ return X.Iter != Y.Iter;
+ }
+};
+
template<typename Derived>
DeclarationNameInfo
TreeTransform<Derived>
@@ -4661,6 +4718,42 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
ObjectType, AllowInjectedClassName);
}
+ if (DeducedTemplateStorage *DTN = Name.getAsDeducedTemplateName()) {
+ TemplateName Underlying = DTN->getUnderlying();
+ TemplateName TransUnderlying = getDerived().TransformTemplateName(
+ SS, Underlying, NameLoc, ObjectType, FirstQualifierInScope,
+ AllowInjectedClassName);
+ if (TransUnderlying.isNull())
+ return TemplateName();
+
+ DefaultArguments DefArgs = DTN->getDefaultArguments();
+
+ TemplateArgumentListInfo TransArgsInfo;
+ using Iterator =
+ TemplateArgumentLocInventIterator<Derived, TemplateArgument *>;
+ if (getDerived().TransformTemplateArguments(
+ Iterator(*this,
+ const_cast<TemplateArgument *>(DefArgs.Args.begin())),
+ Iterator(*this, const_cast<TemplateArgument *>(DefArgs.Args.end())),
+ TransArgsInfo))
+ return TemplateName();
+
+ SmallVector<TemplateArgument, 4> TransArgs(
+ TransArgsInfo.arguments().size());
+ for (unsigned I = 0; I < TransArgs.size(); ++I)
+ TransArgs[I] = TransArgsInfo.arguments()[I].getArgument();
+
+ return getSema().Context.getDeducedTemplateName(
+ TransUnderlying, DefaultArguments{DefArgs.StartPos, TransArgs});
+ }
+
+ // FIXME: Preserve SubstTemplateTemplateParm.
+ if (SubstTemplateTemplateParmStorage *STN =
+ Name.getAsSubstTemplateTemplateParm())
+ return getDerived().TransformTemplateName(
+ SS, STN->getReplacement(), NameLoc, ObjectType, FirstQualifierInScope,
+ AllowInjectedClassName);
+
// FIXME: Try to preserve more of the TemplateName.
if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
TemplateDecl *TransTemplate
@@ -4807,63 +4900,6 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
return true;
}
-/// Iterator adaptor that invents template argument location information
-/// for each of the template arguments in its underlying iterator.
-template<typename Derived, typename InputIterator>
-class TemplateArgumentLocInventIterator {
- TreeTransform<Derived> &Self;
- InputIterator Iter;
-
-public:
- typedef TemplateArgumentLoc value_type;
- typedef TemplateArgumentLoc reference;
- typedef typename std::iterator_traits<InputIterator>::difference_type
- difference_type;
- typedef std::input_iterator_tag iterator_category;
-
- class pointer {
- TemplateArgumentLoc Arg;
-
- public:
- explicit pointer(TemplateArgumentLoc Arg) : Arg(Arg) { }
-
- const TemplateArgumentLoc *operator->() const { return &Arg; }
- };
-
- explicit TemplateArgumentLocInventIterator(TreeTransform<Derived> &Self,
- InputIterator Iter)
- : Self(Self), Iter(Iter) { }
-
- TemplateArgumentLocInventIterator &operator++() {
- ++Iter;
- return *this;
- }
-
- TemplateArgumentLocInventIterator operator++(int) {
- TemplateArgumentLocInventIterator Old(*this);
- ++(*this);
- return Old;
- }
-
- reference operator*() const {
- TemplateArgumentLoc Result;
- Self.InventTemplateArgumentLoc(*Iter, Result);
- return Result;
- }
-
- pointer operator->() const { return pointer(**this); }
-
- friend bool operator==(const TemplateArgumentLocInventIterator &X,
- const TemplateArgumentLocInventIterator &Y) {
- return X.Iter == Y.Iter;
- }
-
- friend bool operator!=(const TemplateArgumentLocInventIterator &X,
- const TemplateArgumentLocInventIterator &Y) {
- return X.Iter != Y.Iter;
- }
-};
-
template<typename Derived>
template<typename InputIterator>
bool TreeTransform<Derived>::TransformTemplateArguments(
diff --git a/clang/test/AST/ast-dump-template-name.cpp b/clang/test/AST/ast-dump-template-name.cpp
index acacdac857954c..956191643546f0 100644
--- a/clang/test/AST/ast-dump-template-name.cpp
+++ b/clang/test/AST/ast-dump-template-name.cpp
@@ -1,4 +1,13 @@
-// RUN: %clang_cc1 -std=c++26 -ast-dump -ast-dump-filter=Test %s | FileCheck %s
+// Test without serialization:
+// RUN: %clang_cc1 -std=c++26 -triple x86_64-unknown-unknown -ast-dump -ast-dump-filter=Test %s \
+// RUN: | FileCheck -strict-whitespace %s
+//
+// Test with serialization:
+// RUN: %clang_cc1 -std=c++26 -triple x86_64-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -x c++ -std=c++26 -triple x86_64-unknown-unknown -include-pch %t \
+// RUN: -ast-dump-all -ast-dump-filter=Test /dev/null \
+// RUN: | sed -e "s/ <undeserialized declarations>//" -e "s/ imported//" \
+// RUN: | FileCheck --strict-whitespace %s
template <template <class> class TT> using N = TT<int>;
@@ -58,3 +67,59 @@ namespace subst {
// CHECK-NEXT: | |-associated ClassTemplateSpecialization {{.+}} 'B'{{$}}
// CHECK-NEXT: | `-replacement:
// CHECK-NEXT: | `-ClassTemplateDecl {{.+}} A{{$}}
+
+namespace deduced {
+ template <class> struct D;
+
+ template <class ET, template <class> class VT>
+ struct D<VT<ET>> {
+ using E = VT<char>;
+ template <class C> using F = VT<C>;
+ };
+
+ template <typename, int> class Matrix;
+
+ using TestDeduced1 = D<Matrix<double, 3>>::E;
+ using TestDeduced2 = D<Matrix<double, 3>>::F<int>;
+} // namespace deduced
+
+// CHECK: Dumping deduced::TestDeduced1:
+// CHECK-NEXT: TypeAliasDecl
+// CHECK-NEXT: `-ElaboratedType
+// CHECK-NEXT: `-TypedefType
+// CHECK-NEXT: |-TypeAlias
+// CHECK-NEXT: `-ElaboratedType
+// CHECK-NEXT: `-TemplateSpecializationType
+// CHECK-NEXT: |-name: 'deduced::Matrix:1<3>' subst index 1
+// CHECK-NEXT: | |-parameter: TemplateTemplateParmDecl {{.+}} depth 0 index 1 VT
+// CHECK-NEXT: | |-associated
+// CHECK-NEXT: | `-replacement: 'deduced::Matrix:1<3>' deduced
+// CHECK-NEXT: | |-underlying: 'deduced::Matrix'
+// CHECK-NEXT: | | `-ClassTemplateDecl {{.+}} Matrix
+// CHECK-NEXT: | `-defaults: start 1
+// CHECK-NEXT: | `-TemplateArgument integral '3'
+// CHECK-NEXT: |-TemplateArgument type 'char'
+// CHECK-NEXT: | `-BuiltinType
+// CHECK-NEXT: `-RecordType
+// CHECK-NEXT: `-ClassTemplateSpecialization
+
+// CHECK: Dumping deduced::TestDeduced2:
+// CHECK-NEXT: TypeAliasDecl
+// CHECK-NEXT: `-ElaboratedType
+// CHECK-NEXT: `-TemplateSpecializationType
+// CHECK-NEXT: |-name: 'D<Matrix<double, 3>>::F':'deduced::D<deduced::Matrix<double, 3>>::F
+// CHECK-NEXT: | |-NestedNameSpecifier
+// CHECK-NEXT: | `-TypeAliasTemplateDecl
+// CHECK-NEXT: |-TemplateArgument type 'int'
+// CHECK-NEXT: | `-BuiltinType
+// CHECK-NEXT: `-ElaboratedType
+// CHECK-NEXT: `-TemplateSpecializationType
+// CHECK-NEXT: |-name: 'Matrix:1<3>':'deduced::Matrix:1<3>' deduced
+// CHECK-NEXT: | |-underlying: 'Matrix':'deduced::Matrix' qualified
+// CHECK-NEXT: | | `-ClassTemplateDecl {{.+}} Matrix
+// CHECK-NEXT: | `-defaults: start 1
+// CHECK-NEXT: | `-TemplateArgument expr '3'
+// CHECK-NEXT: |-TemplateArgument type 'int'
+// CHECK-NEXT: | `-BuiltinType
+// CHECK-NEXT: `-RecordType
+// CHECK-NEXT: `-ClassTemplateSpecialization
diff --git a/clang/test/SemaTemplate/cwg2398.cpp b/clang/test/SemaTemplate/cwg2398.cpp
index 1d9747276fbe00..881c9dd2d697ff 100644
--- a/clang/test/SemaTemplate/cwg2398.cpp
+++ b/clang/test/SemaTemplate/cwg2398.cpp
@@ -379,3 +379,17 @@ namespace regression1 {
bar(input);
}
} // namespace regression1
+
+namespace regression2 {
+ template <class> struct D;
+ // old-note at -1 {{template is declared here}}
+
+ template <class ET, template <class> class VT>
+ struct D<VT<ET>> {
+ template <class C> using E = VT<C>;
+ };
+
+ template <typename, int> class Matrix;
+ using X = D<Matrix<double, 3>>::E<int>;
+ // old-error at -1 {{implicit instantiation of undefined template}}
+} // namespace regression2
More information about the cfe-commits
mailing list