[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