mizvekov retitled this revision from "WIP: Clang: fix AST representation of 
expanded template arguments." to "Clang: fix AST representation of expanded 
template arguments.".
mizvekov edited the summary of this revision.
mizvekov updated this revision to Diff 460206.
mizvekov requested review of this revision.
This revision is now accepted and ready to land.

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D128113/new/

https://reviews.llvm.org/D128113

Files:
  clang/include/clang/AST/ASTContext.h
  clang/include/clang/AST/Type.h
  clang/include/clang/AST/TypeProperties.td
  clang/lib/AST/ASTContext.cpp
  clang/lib/AST/ASTImporter.cpp
  clang/lib/AST/ASTStructuralEquivalence.cpp
  clang/lib/AST/JSONNodeDumper.cpp
  clang/lib/AST/TextNodeDumper.cpp
  clang/lib/AST/Type.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/lib/Sema/TreeTransform.h
  clang/test/AST/ast-dump-template-decls.cpp
  clang/test/SemaTemplate/type_pack_element.cpp
  clang/unittests/AST/ASTImporterTest.cpp

Index: clang/unittests/AST/ASTImporterTest.cpp
===================================================================
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -4793,6 +4793,44 @@
       ToD2->getDeclContext(), ToD2->getTemplateParameters()->getParam(0)));
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase, ImportSubstTemplateTypeParmType) {
+  constexpr auto Code = R"(
+    template <class A1, class... A2> struct A {
+      using B = A1(A2...);
+    };
+    template struct A<void, char, float, int, short>;
+    )";
+  Decl *FromTU = getTuDecl(Code, Lang_CXX11, "input.cpp");
+  auto *FromClass = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
+      FromTU, classTemplateSpecializationDecl());
+
+  auto testType = [&](ASTContext &Ctx, const char *Name,
+                      llvm::Optional<unsigned> PackIndex) {
+    const auto *Subst = selectFirst<SubstTemplateTypeParmType>(
+        "sttp", match(substTemplateTypeParmType(
+                          hasReplacementType(hasCanonicalType(asString(Name))))
+                          .bind("sttp"),
+                      Ctx));
+    const char *ExpectedTemplateParamName = PackIndex ? "A2" : "A1";
+    ASSERT_TRUE(Subst);
+    ASSERT_EQ(Subst->getReplacedParameter()->getIdentifier()->getName(),
+              ExpectedTemplateParamName);
+    ASSERT_EQ(Subst->getPackIndex(), PackIndex);
+  };
+  auto tests = [&](ASTContext &Ctx) {
+    testType(Ctx, "void", None);
+    testType(Ctx, "char", 3);
+    testType(Ctx, "float", 2);
+    testType(Ctx, "int", 1);
+    testType(Ctx, "short", 0);
+  };
+
+  tests(FromTU->getASTContext());
+
+  ClassTemplateSpecializationDecl *ToClass = Import(FromClass, Lang_CXX11);
+  tests(ToClass->getASTContext());
+}
+
 const AstTypeMatcher<SubstTemplateTypeParmPackType>
     substTemplateTypeParmPackType;
 
Index: clang/test/SemaTemplate/type_pack_element.cpp
===================================================================
--- clang/test/SemaTemplate/type_pack_element.cpp
+++ clang/test/SemaTemplate/type_pack_element.cpp
@@ -11,7 +11,7 @@
 // CHECK-NEXT:       |     `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:35> 'int' 0
 // CHECK-NEXT:       |-TemplateArgument type 'int'
 // CHECK-NEXT:       | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
-// CHECK-NEXT:       `-SubstTemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'int' sugar typename depth 0 index 1 ...
+// CHECK-NEXT:       `-SubstTemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'int' sugar typename depth 0 index 1 ... pack_index 0
 // CHECK-NEXT:         |-BuiltinTemplate 0x{{[0-9A-Fa-f]+}} '__type_pack_element'
 // CHECK-NEXT:         `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
 
Index: clang/test/AST/ast-dump-template-decls.cpp
===================================================================
--- clang/test/AST/ast-dump-template-decls.cpp
+++ clang/test/AST/ast-dump-template-decls.cpp
@@ -136,13 +136,13 @@
 };
 using t1 = foo<int, short>::bind<char, float>;
 // CHECK:      TemplateSpecializationType 0x{{[^ ]*}} 'Y<char, float, int, short>' sugar Y
-// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'char' sugar typename depth 0 index 0 ... Bs
+// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'char' sugar typename depth 0 index 0 ... Bs pack_index 3
 // CHECK-NEXT: TypeAliasTemplate 0x{{[^ ]*}} 'Z'
-// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'float' sugar typename depth 0 index 0 ... Bs
+// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'float' sugar typename depth 0 index 0 ... Bs pack_index 2
 // CHECK-NEXT: TypeAliasTemplate 0x{{[^ ]*}} 'Z'
-// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar typename depth 0 index 0 ... Bs
+// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar typename depth 0 index 0 ... Bs pack_index 1
 // CHECK-NEXT: TypeAliasTemplate 0x{{[^ ]*}} 'Z'
-// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'short' sugar typename depth 0 index 0 ... Bs
+// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'short' sugar typename depth 0 index 0 ... Bs pack_index 0
 // CHECK-NEXT: TypeAliasTemplate 0x{{[^ ]*}} 'Z'
 
 template <typename... T> struct D {
@@ -152,13 +152,13 @@
 // CHECK:      TemplateSpecializationType 0x{{[^ ]*}} 'B<int, short>' sugar alias B
 // CHECK:      FunctionProtoType 0x{{[^ ]*}} 'int (int (*)(float, int), int (*)(char, short))' cdecl
 // CHECK:      FunctionProtoType 0x{{[^ ]*}} 'int (float, int)' cdecl
-// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'float' sugar typename depth 0 index 0 ... T
+// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'float' sugar typename depth 0 index 0 ... T pack_index 1
 // CHECK-NEXT: ClassTemplateSpecialization 0x{{[^ ]*}} 'D'
-// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar typename depth 0 index 0 ... U
+// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar typename depth 0 index 0 ... U pack_index 1
 // CHECK-NEXT: TypeAliasTemplate 0x{{[^ ]*}} 'B'
 // CHECK:      FunctionProtoType 0x{{[^ ]*}} 'int (char, short)' cdecl
-// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'char' sugar typename depth 0 index 0 ... T
+// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'char' sugar typename depth 0 index 0 ... T pack_index 0
 // CHECK-NEXT: ClassTemplateSpecialization 0x{{[^ ]*}} 'D'
-// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'short' sugar typename depth 0 index 0 ... U
+// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'short' sugar typename depth 0 index 0 ... U pack_index 0
 // CHECK-NEXT: TypeAliasTemplate 0x{{[^ ]*}} 'B'
 } // namespace PR56099
Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -4853,7 +4853,7 @@
             Replacement.getUnqualifiedType(), Qs);
         T = SemaRef.Context.getSubstTemplateTypeParmType(
             Replacement, SubstTypeParam->getReplacedDecl(),
-            SubstTypeParam->getIndex());
+            SubstTypeParam->getIndex(), SubstTypeParam->getPackIndex());
       } else if ((AutoTy = dyn_cast<AutoType>(T)) && AutoTy->isDeduced()) {
         // 'auto' types behave the same way as template parameters.
         QualType Deduced = AutoTy->getDeducedType();
@@ -6414,7 +6414,7 @@
   // Always canonicalize the replacement type.
   Replacement = SemaRef.Context.getCanonicalType(Replacement);
   QualType Result = SemaRef.Context.getSubstTemplateTypeParmType(
-      Replacement, NewReplaced, T->getIndex());
+      Replacement, NewReplaced, T->getIndex(), T->getPackIndex());
 
   // Propagate type-source information.
   SubstTemplateTypeParmTypeLoc NewTL
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1823,6 +1823,7 @@
 
     Decl *ReplacedDecl = TemplateArgs.getReplacedDecl(T->getDepth());
 
+    Optional<unsigned> PackIndex;
     if (T->isParameterPack()) {
       assert(Arg.getKind() == TemplateArgument::Pack &&
              "Missing argument pack");
@@ -1839,6 +1840,8 @@
         return Result;
       }
 
+      // PackIndex starts from last element.
+      PackIndex = Arg.pack_size() - 1 - getSema().ArgumentPackSubstitutionIndex;
       Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
     }
 
@@ -1849,7 +1852,7 @@
 
     // TODO: only do this uniquing once, at the start of instantiation.
     QualType Result = getSema().Context.getSubstTemplateTypeParmType(
-        Replacement, ReplacedDecl, T->getIndex());
+        Replacement, ReplacedDecl, T->getIndex(), PackIndex);
     SubstTemplateTypeParmTypeLoc NewTL
       = TLB.push<SubstTemplateTypeParmTypeLoc>(Result);
     NewTL.setNameLoc(TL.getNameLoc());
@@ -1890,11 +1893,14 @@
     return Result;
   }
 
-  TemplateArgument Arg =
-      getPackSubstitutedTemplateArgument(getSema(), T->getArgumentPack());
+  TemplateArgument Pack = T->getArgumentPack();
+  TemplateArgument Arg = getPackSubstitutedTemplateArgument(getSema(), Pack);
 
+  // PackIndex starts from last element.
   QualType Result = getSema().Context.getSubstTemplateTypeParmType(
-      Arg.getAsType(), NewReplaced, T->getIndex());
+      Arg.getAsType(), NewReplaced, T->getIndex(),
+      Pack.pack_size() - 1 - getSema().ArgumentPackSubstitutionIndex);
+
   SubstTemplateTypeParmTypeLoc NewTL =
       TLB.push<SubstTemplateTypeParmTypeLoc>(Result);
   NewTL.setNameLoc(TL.getNameLoc());
Index: clang/lib/Sema/SemaTemplate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -3506,9 +3506,10 @@
   TemplateParameterList *TPL = BTD->getTemplateParameters();
 
   // Wrap the type in substitution sugar.
-  auto getSubstType = [&](unsigned IndexReplaced, QualType Replacement) {
-    return SemaRef.Context.getSubstTemplateTypeParmType(Replacement, BTD,
-                                                        IndexReplaced);
+  auto getSubstType = [&](QualType Replacement, unsigned IndexReplaced,
+                          Optional<unsigned> PackIndexReplaced) {
+    return SemaRef.Context.getSubstTemplateTypeParmType(
+        Replacement, BTD, IndexReplaced, PackIndexReplaced);
   };
 
   switch (BTD->getBuiltinTemplateKind()) {
@@ -3533,7 +3534,7 @@
     TemplateArgumentListInfo SyntheticTemplateArgs;
     // The type argument, wrapped in substitution sugar, gets reused as the
     // first template argument in the synthetic template argument list.
-    QualType SyntheticType = getSubstType(1, OrigType);
+    QualType SyntheticType = getSubstType(OrigType, 1, None);
     SyntheticTemplateArgs.addArgument(
         TemplateArgumentLoc(TemplateArgument(SyntheticType),
                             SemaRef.Context.getTrivialTypeSourceInfo(
@@ -3588,8 +3589,9 @@
     }
 
     // We simply return the type at index `Index`.
-    auto Nth = std::next(Ts.pack_begin(), Index.getExtValue());
-    return getSubstType(1, Nth->getAsType());
+    int64_t N = Index.getExtValue();
+    return getSubstType(Ts.getPackAsArray()[N].getAsType(), 1,
+                        Ts.pack_size() - 1 - N);
   }
   llvm_unreachable("unexpected BuiltinTemplateDecl!");
 }
Index: clang/lib/AST/Type.cpp
===================================================================
--- clang/lib/AST/Type.cpp
+++ clang/lib/AST/Type.cpp
@@ -1166,8 +1166,9 @@
           == T->getReplacementType().getAsOpaquePtr())
       return QualType(T, 0);
 
-    return Ctx.getSubstTemplateTypeParmType(
-        replacementType, T->getReplacedDecl(), T->getIndex());
+    return Ctx.getSubstTemplateTypeParmType(replacementType,
+                                            T->getReplacedDecl(), T->getIndex(),
+                                            T->getPackIndex());
   }
 
   // FIXME: Non-trivial to implement, but important for C++
@@ -3721,9 +3722,9 @@
       getReplacedTemplateParameterList(D)->getParam(Index));
 }
 
-SubstTemplateTypeParmType::SubstTemplateTypeParmType(QualType Replacement,
-                                                     Decl *ReplacedDecl,
-                                                     unsigned Index)
+SubstTemplateTypeParmType::SubstTemplateTypeParmType(
+    QualType Replacement, Decl *ReplacedDecl, unsigned Index,
+    Optional<unsigned> PackIndex)
     : Type(SubstTemplateTypeParm, Replacement.getCanonicalType(),
            Replacement->getDependence()),
       ReplacedDecl(ReplacedDecl) {
@@ -3733,6 +3734,7 @@
     *getTrailingObjects<QualType>() = Replacement;
 
   SubstTemplateTypeParmTypeBits.Index = Index;
+  SubstTemplateTypeParmTypeBits.PackIndex = PackIndex ? *PackIndex + 1 : 0;
   assert(ReplacedDecl != nullptr);
   assert(getReplacedParameter() != nullptr);
 }
Index: clang/lib/AST/TextNodeDumper.cpp
===================================================================
--- clang/lib/AST/TextNodeDumper.cpp
+++ clang/lib/AST/TextNodeDumper.cpp
@@ -1578,6 +1578,8 @@
     const SubstTemplateTypeParmType *T) {
   dumpDeclRef(T->getReplacedDecl());
   VisitTemplateTypeParmDecl(T->getReplacedParameter());
+  if (auto PackIndex = T->getPackIndex())
+    OS << " pack_index " << *PackIndex;
 }
 
 void TextNodeDumper::VisitSubstTemplateTypeParmPackType(
Index: clang/lib/AST/JSONNodeDumper.cpp
===================================================================
--- clang/lib/AST/JSONNodeDumper.cpp
+++ clang/lib/AST/JSONNodeDumper.cpp
@@ -694,6 +694,8 @@
 void JSONNodeDumper::VisitSubstTemplateTypeParmType(
     const SubstTemplateTypeParmType *STTPT) {
   JOS.attribute("index", STTPT->getIndex());
+  if (auto PackIndex = STTPT->getPackIndex())
+    JOS.attribute("pack_index", *PackIndex);
 }
 
 void JSONNodeDumper::VisitSubstTemplateTypeParmPackType(
Index: clang/lib/AST/ASTStructuralEquivalence.cpp
===================================================================
--- clang/lib/AST/ASTStructuralEquivalence.cpp
+++ clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -1069,6 +1069,8 @@
       return false;
     if (Subst1->getIndex() != Subst2->getIndex())
       return false;
+    if (Subst1->getPackIndex() != Subst2->getPackIndex())
+      return false;
     break;
   }
 
Index: clang/lib/AST/ASTImporter.cpp
===================================================================
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -1533,7 +1533,8 @@
     return ToReplacementTypeOrErr.takeError();
 
   return Importer.getToContext().getSubstTemplateTypeParmType(
-      *ToReplacementTypeOrErr, *ReplacedOrErr, T->getIndex());
+      *ToReplacementTypeOrErr, *ReplacedOrErr, T->getIndex(),
+      T->getPackIndex());
 }
 
 ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmPackType(
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -4775,11 +4775,13 @@
 }
 
 /// Retrieve a substitution-result type.
-QualType ASTContext::getSubstTemplateTypeParmType(QualType Replacement,
-                                                  Decl *ReplacedDecl,
-                                                  unsigned Index) const {
+QualType
+ASTContext::getSubstTemplateTypeParmType(QualType Replacement,
+                                         Decl *ReplacedDecl, unsigned Index,
+                                         Optional<unsigned> PackIndex) const {
   llvm::FoldingSetNodeID ID;
-  SubstTemplateTypeParmType::Profile(ID, Replacement, ReplacedDecl, Index);
+  SubstTemplateTypeParmType::Profile(ID, Replacement, ReplacedDecl, Index,
+                                     PackIndex);
   void *InsertPos = nullptr;
   SubstTemplateTypeParmType *SubstParm =
       SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
@@ -4788,8 +4790,8 @@
     void *Mem = Allocate(SubstTemplateTypeParmType::totalSizeToAlloc<QualType>(
                              !Replacement.isCanonical()),
                          TypeAlignment);
-    SubstParm =
-        new (Mem) SubstTemplateTypeParmType(Replacement, ReplacedDecl, Index);
+    SubstParm = new (Mem)
+        SubstTemplateTypeParmType(Replacement, ReplacedDecl, Index, PackIndex);
     Types.push_back(SubstParm);
     SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos);
   }
@@ -12870,11 +12872,14 @@
     unsigned Index = SX->getIndex();
     if (Index != SY->getIndex())
       return QualType();
+    auto PackIndex = SX->getPackIndex();
+    if (Index != SY->getPackIndex())
+      return QualType();
     Decl *CD = ::getCommonDecl(SX->getReplacedDecl(), SY->getReplacedDecl());
     if (!CD)
       return QualType();
     return Ctx.getSubstTemplateTypeParmType(Ctx.getQualifiedType(Underlying),
-                                            CD, Index);
+                                            CD, Index, PackIndex);
   }
   case Type::ObjCTypeParam:
     // FIXME: Try to merge these.
Index: clang/include/clang/AST/TypeProperties.td
===================================================================
--- clang/include/clang/AST/TypeProperties.td
+++ clang/include/clang/AST/TypeProperties.td
@@ -733,11 +733,14 @@
   def : Property<"Index", UInt32> {
     let Read = [{ node->getIndex() }];
   }
+  def : Property<"PackIndex", Optional<UInt32>> {
+    let Read = [{ node->getPackIndex() }];
+  }
 
   // The call to getCanonicalType here existed in ASTReader.cpp, too.
   def : Creator<[{
     return ctx.getSubstTemplateTypeParmType(
-        replacementType, replacedDecl, Index);
+        replacementType, replacedDecl, Index, PackIndex);
   }]>;
 }
 
Index: clang/include/clang/AST/Type.h
===================================================================
--- clang/include/clang/AST/Type.h
+++ clang/include/clang/AST/Type.h
@@ -1819,7 +1819,14 @@
     unsigned HasNonCanonicalUnderlyingType : 1;
 
     // The index of the template parameter this substitution represents.
-    unsigned Index : 16;
+    unsigned Index : 15;
+
+    /// Represents the index within a pack if this represents a substitution
+    /// from a pack expansion. This index starts at the end of the pack and
+    /// increments towards the beginning.
+    /// Positive non-zero number represents the index + 1.
+    /// Zero means this is not substituted from an expansion.
+    unsigned PackIndex : 16;
   };
 
   class SubstTemplateTypeParmPackTypeBitfields {
@@ -5033,7 +5040,7 @@
   Decl *ReplacedDecl;
 
   SubstTemplateTypeParmType(QualType Replacement, Decl *ReplacedDecl,
-                            unsigned Index);
+                            unsigned Index, Optional<unsigned> PackIndex);
 
 public:
   /// Gets the type that was substituted for the template
@@ -5051,18 +5058,27 @@
 
   unsigned getIndex() const { return SubstTemplateTypeParmTypeBits.Index; }
 
+  Optional<unsigned> getPackIndex() const {
+    if (SubstTemplateTypeParmTypeBits.PackIndex == 0)
+      return None;
+    return SubstTemplateTypeParmTypeBits.PackIndex - 1;
+  }
+
   bool isSugared() const { return true; }
   QualType desugar() const { return getReplacementType(); }
 
   void Profile(llvm::FoldingSetNodeID &ID) {
-    Profile(ID, getReplacementType(), getReplacedDecl(), getIndex());
+    Profile(ID, getReplacementType(), getReplacedDecl(), getIndex(),
+            getPackIndex());
   }
 
   static void Profile(llvm::FoldingSetNodeID &ID, QualType Replacement,
-                      const Decl *ReplacedDecl, unsigned Index) {
+                      const Decl *ReplacedDecl, unsigned Index,
+                      Optional<unsigned> PackIndex) {
     ID.AddPointer(ReplacedDecl);
     Replacement.Profile(ID);
     ID.AddInteger(Index);
+    ID.AddInteger(PackIndex ? *PackIndex - 1 : 0);
   }
 
   static bool classof(const Type *T) {
Index: clang/include/clang/AST/ASTContext.h
===================================================================
--- clang/include/clang/AST/ASTContext.h
+++ clang/include/clang/AST/ASTContext.h
@@ -1618,8 +1618,8 @@
                                    QualType Wrapped);
 
   QualType getSubstTemplateTypeParmType(QualType Replacement,
-                                        Decl *ReplacedDecl,
-                                        unsigned Index) const;
+                                        Decl *ReplacedDecl, unsigned Index,
+                                        Optional<unsigned> PackIndex) const;
   QualType getSubstTemplateTypeParmPackType(Decl *ReplacedDecl, unsigned Index,
                                             const TemplateArgument &ArgPack);
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to