mizvekov created this revision.
Herald added subscribers: steakhal, carlosgalvezp, martong, usaxena95, 
kadircet, arphaman.
Herald added a reviewer: shafik.
Herald added a reviewer: NoQ.
Herald added a project: All.
mizvekov requested review of this revision.
Herald added projects: clang, libc++, clang-tools-extra.
Herald added subscribers: cfe-commits, libcxx-commits.
Herald added a reviewer: libc++.

This is a change to how we represent type subsitution in the AST.
Instead of only storing the replaced type, we track the templated
entity we are substituting, plus an index.
We modify MLTAL to track the templated entity at each level.

Otherwise, it's much more expensive to go from the template parameter back
to the templated entity, and not possible to do in some cases, as when
we instantiate outer templates, parameters might still reference the
original entity.

This also allows us to very cheaply lookup the templated entity we saw in
the naming context and find the corresponding argument it was replaced
from, such as for implementing template specialization resugaring.

Depends on D130308 <https://reviews.llvm.org/D130308>

Signed-off-by: Matheus Izvekov <mizve...@gmail.com>


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D131858

Files:
  clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.cpp
  clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
  clang-tools-extra/clangd/AST.cpp
  clang/include/clang/AST/ASTContext.h
  clang/include/clang/AST/ASTNodeTraverser.h
  clang/include/clang/AST/JSONNodeDumper.h
  clang/include/clang/AST/TextNodeDumper.h
  clang/include/clang/AST/Type.h
  clang/include/clang/AST/TypeProperties.td
  clang/include/clang/Sema/Template.h
  clang/lib/AST/ASTContext.cpp
  clang/lib/AST/ASTImporter.cpp
  clang/lib/AST/ASTStructuralEquivalence.cpp
  clang/lib/AST/JSONNodeDumper.cpp
  clang/lib/AST/ODRHash.cpp
  clang/lib/AST/TextNodeDumper.cpp
  clang/lib/AST/Type.cpp
  clang/lib/AST/TypePrinter.cpp
  clang/lib/Sema/SemaConcept.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/lib/Sema/SemaTemplateDeduction.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
  clang/lib/Sema/TreeTransform.h
  clang/lib/Serialization/ASTReaderDecl.cpp
  clang/lib/Serialization/ASTWriterDecl.cpp
  clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp
  clang/test/AST/ast-dump-openmp-begin-declare-variant_reference.cpp
  clang/test/AST/ast-dump-template-decls.cpp
  clang/test/AST/deduction-guides.cpp
  clang/test/SemaTemplate/deduction-guide.cpp
  libcxx/DELETE.ME

Index: libcxx/DELETE.ME
===================================================================
--- libcxx/DELETE.ME
+++ libcxx/DELETE.ME
@@ -1,3 +1,4 @@
 D111283
 D111509
 D130308
+D127695
Index: clang/test/SemaTemplate/deduction-guide.cpp
===================================================================
--- clang/test/SemaTemplate/deduction-guide.cpp
+++ clang/test/SemaTemplate/deduction-guide.cpp
@@ -156,9 +156,8 @@
 // CHECK:               |-BuiltinType {{.*}} 'int'
 // CHECK:               |-TemplateTypeParmType {{.*}} 'T' dependent contains_unexpanded_pack depth 0 index 0 pack
 // CHECK:               | `-TemplateTypeParm {{.*}} 'T'
-// CHECK:               `-SubstTemplateTypeParmPackType {{.*}} 'U' dependent contains_unexpanded_pack
-// CHECK:                 |-TemplateTypeParmType {{.*}} 'U' dependent contains_unexpanded_pack depth 1 index 0 pack
-// CHECK:                 | `-TemplateTypeParm {{.*}} 'U'
+// CHECK:               `-SubstTemplateTypeParmPackType {{.*}} 'U' dependent contains_unexpanded_pack typename depth 1 index 0 ... U
+// CHECK:                 |-TypeAliasTemplate {{.*}} 'B'
 // CHECK:                 `-TemplateArgument pack
 // CHECK:                   |-TemplateArgument type 'type-parameter-0-1'
 // CHECK-NOT: Subst
Index: clang/test/AST/deduction-guides.cpp
===================================================================
--- clang/test/AST/deduction-guides.cpp
+++ clang/test/AST/deduction-guides.cpp
@@ -67,9 +67,8 @@
 // CHECK-NEXT: ElaboratedType {{.*}} 'typename Derived<int, 1, int>::type_alias' sugar
 // CHECK-NEXT: TypedefType {{.*}} 'PR48177::Base<int>::type_alias' sugar
 // CHECK-NEXT: TypeAlias {{.*}} 'type_alias'
-// CHECK-NEXT: SubstTemplateTypeParmType {{.*}} 'int' sugar
-// CHECK-NEXT: TemplateTypeParmType {{.*}} 'A'
-// CHECK-NEXT: TemplateTypeParm {{.*}} 'A'
+// CHECK-NEXT: SubstTemplateTypeParmType {{.*}} 'int' sugar class depth 0 index 0 A
+// CHECK-NEXT: ClassTemplateSpecialization {{.*}} 'Base'
 // CHECK-NEXT: BuiltinType {{.*}} 'int'
 
 // CHECK: CXXDeductionGuideDecl {{.*}} implicit <deduction guide for Derived> 'auto (Derived<T, S, A> &&, const typename Derived<T, S, A>::type_alias &) -> Derived<T, S, A>'
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
@@ -120,12 +120,12 @@
 // CHECK-NEXT: TemplateArgument type 'void'
 // CHECK-NEXT: BuiltinType 0x{{[^ ]*}} 'void'
 // CHECK-NEXT: FunctionProtoType 0x{{[^ ]*}} 'void (int)' cdecl
-// CHECK-NEXT: SubstTemplateTypeParmType 0x{{[^ ]*}} 'void' sugar
-// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'U' dependent depth 0 index 0
-// CHECK-NEXT: TemplateTypeParm 0x{{[^ ]*}} 'U'
+// CHECK-NEXT: SubstTemplateTypeParmType 0x{{[^ ]*}} 'void' sugar class depth 0 index 0 U
+// CHECK-NEXT: TypeAliasTemplate 0x{{[^ ]*}} 'type1'
 // CHECK-NEXT: BuiltinType 0x{{[^ ]*}} 'void'
-// CHECK-NEXT: SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar
-// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'T' dependent depth 0 index 0
+// CHECK-NEXT: SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar class depth 0 index 0 T
+// CHECK-NEXT: ClassTemplateSpecialization 0x{{[^ ]*}} 'C'
+// CHECK-NEXT: BuiltinType 0x{{[^ ]*}} 'int'
 } // namespace PR55886
 
 namespace PR56099 {
@@ -136,14 +136,14 @@
 };
 using t1 = foo<int, short>::bind<char, float>;
 // CHECK:      TemplateSpecializationType 0x{{[^ ]*}} 'Y<char, float, int, short>' sugar Y
-// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'char' sugar pack_index 0
-// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'Bs' dependent contains_unexpanded_pack depth 0 index 0 pack
-// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'float' sugar pack_index 1
-// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'Bs' dependent contains_unexpanded_pack depth 0 index 0 pack
-// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar pack_index 2
-// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'Bs' dependent contains_unexpanded_pack depth 0 index 0 pack
-// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'short' sugar pack_index 3
-// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'Bs' dependent contains_unexpanded_pack depth 0 index 0 pack
+// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'char' sugar typename depth 0 index 0 ... Bs pack_index 0
+// CHECK-NEXT: TypeAliasTemplate 0x{{[^ ]*}} 'Z'
+// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'float' sugar typename depth 0 index 0 ... Bs pack_index 1
+// CHECK-NEXT: TypeAliasTemplate 0x{{[^ ]*}} 'Z'
+// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar typename depth 0 index 0 ... Bs pack_index 2
+// CHECK-NEXT: TypeAliasTemplate 0x{{[^ ]*}} 'Z'
+// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'short' sugar typename depth 0 index 0 ... Bs pack_index 3
+// CHECK-NEXT: TypeAliasTemplate 0x{{[^ ]*}} 'Z'
 
 template <typename... T> struct D {
   template <typename... U> using B = int(int (*...p)(T, U));
@@ -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 pack_index 0
-// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'T' dependent contains_unexpanded_pack depth 0 index 0 pack
-// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar pack_index 0
-// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'U' dependent contains_unexpanded_pack depth 0 index 0 pack
+// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'float' sugar typename depth 0 index 0 ... T pack_index 0
+// CHECK-NEXT: ClassTemplateSpecialization 0x{{[^ ]*}} 'D'
+// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar typename depth 0 index 0 ... U pack_index 0
+// CHECK-NEXT: TypeAliasTemplate 0x{{[^ ]*}} 'B'
 // CHECK:      FunctionProtoType 0x{{[^ ]*}} 'int (char, short)' cdecl
-// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'char' sugar pack_index 1
-// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'T' dependent contains_unexpanded_pack depth 0 index 0 pack
-// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'short' sugar pack_index 1
-// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'U' dependent contains_unexpanded_pack depth 0 index 0 pack
+// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'char' sugar typename depth 0 index 0 ... T pack_index 1
+// CHECK-NEXT: ClassTemplateSpecialization 0x{{[^ ]*}} 'D'
+// CHECK:      SubstTemplateTypeParmType 0x{{[^ ]*}} 'short' sugar typename depth 0 index 0 ... U pack_index 1
+// CHECK-NEXT: TypeAliasTemplate 0x{{[^ ]*}} 'B'
 } // namespace PR56099
Index: clang/test/AST/ast-dump-openmp-begin-declare-variant_reference.cpp
===================================================================
--- clang/test/AST/ast-dump-openmp-begin-declare-variant_reference.cpp
+++ clang/test/AST/ast-dump-openmp-begin-declare-variant_reference.cpp
@@ -122,9 +122,8 @@
 // CHECK-NEXT: | | |   `-BuiltinType [[ADDR_8:0x[a-z0-9]*]] 'float'
 // CHECK-NEXT: | | |-CXXRecordDecl [[ADDR_9:0x[a-z0-9]*]] <col:22, col:29> col:29 implicit struct remove_reference
 // CHECK-NEXT: | | `-TypedefDecl [[ADDR_10:0x[a-z0-9]*]] <col:55, col:67> col:67 referenced type 'float':'float'
-// CHECK-NEXT: | |   `-SubstTemplateTypeParmType [[ADDR_11:0x[a-z0-9]*]] 'float' sugar
-// CHECK-NEXT: | |     |-TemplateTypeParmType [[ADDR_12:0x[a-z0-9]*]] '_Tp' dependent depth 0 index 0
-// CHECK-NEXT: | |     | `-TemplateTypeParm [[ADDR_13:0x[a-z0-9]*]] '_Tp'
+// CHECK-NEXT: | |   `-SubstTemplateTypeParmType [[ADDR_11:0x[a-z0-9]*]] 'float' sugar class depth 0 index 0 _Tp
+// CHECK-NEXT: | |     |-ClassTemplateSpecialization [[ADDR_6]] 'remove_reference'
 // CHECK-NEXT: | |     `-BuiltinType [[ADDR_8]] 'float'
 // CHECK-NEXT: | `-ClassTemplateSpecializationDecl [[ADDR_14:0x[a-z0-9]*]] <col:1, col:73> col:29 struct remove_reference definition
 // CHECK-NEXT: |   |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
@@ -139,9 +138,8 @@
 // CHECK-NEXT: |   |   `-BuiltinType [[ADDR_16:0x[a-z0-9]*]] 'short'
 // CHECK-NEXT: |   |-CXXRecordDecl [[ADDR_17:0x[a-z0-9]*]] <col:22, col:29> col:29 implicit struct remove_reference
 // CHECK-NEXT: |   `-TypedefDecl [[ADDR_18:0x[a-z0-9]*]] <col:55, col:67> col:67 referenced type 'short':'short'
-// CHECK-NEXT: |     `-SubstTemplateTypeParmType [[ADDR_19:0x[a-z0-9]*]] 'short' sugar
-// CHECK-NEXT: |       |-TemplateTypeParmType [[ADDR_12]] '_Tp' dependent depth 0 index 0
-// CHECK-NEXT: |       | `-TemplateTypeParm [[ADDR_13]] '_Tp'
+// CHECK-NEXT: |     `-SubstTemplateTypeParmType [[ADDR_19:0x[a-z0-9]*]] 'short' sugar class depth 0 index 0 _Tp
+// CHECK-NEXT: |       |-ClassTemplateSpecialization [[ADDR_14]] 'remove_reference'
 // CHECK-NEXT: |       `-BuiltinType [[ADDR_16]] 'short'
 // CHECK-NEXT: |-ClassTemplatePartialSpecializationDecl [[ADDR_20:0x[a-z0-9]*]] <col:1, col:73> col:29 struct remove_reference definition
 // CHECK-NEXT: | |-DefinitionData empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
@@ -154,10 +152,10 @@
 // CHECK-NEXT: | |-TemplateArgument type 'type-parameter-0-0 &'
 // CHECK-NEXT: | | `-LValueReferenceType [[ADDR_21:0x[a-z0-9]*]] 'type-parameter-0-0 &' dependent
 // CHECK-NEXT: | |   `-TemplateTypeParmType [[ADDR_22:0x[a-z0-9]*]] 'type-parameter-0-0' dependent depth 0 index 0
-// CHECK-NEXT: | |-TemplateTypeParmDecl [[ADDR_13]] <col:11, col:17> col:17 referenced class depth 0 index 0 _Tp
+// CHECK-NEXT: | |-TemplateTypeParmDecl [[ADDR_13:0x[a-z0-9]*]] <col:11, col:17> col:17 referenced class depth 0 index 0 _Tp
 // CHECK-NEXT: | |-CXXRecordDecl [[ADDR_23:0x[a-z0-9]*]] <col:22, col:29> col:29 implicit struct remove_reference
 // CHECK-NEXT: | `-TypedefDecl [[ADDR_24:0x[a-z0-9]*]] <col:55, col:67> col:67 type '_Tp'
-// CHECK-NEXT: |   `-TemplateTypeParmType [[ADDR_12]] '_Tp' dependent depth 0 index 0
+// CHECK-NEXT: |   `-TemplateTypeParmType [[ADDR_12:0x[a-z0-9]*]] '_Tp' dependent depth 0 index 0
 // CHECK-NEXT: |     `-TemplateTypeParm [[ADDR_13]] '_Tp'
 // CHECK-NEXT: |-ClassTemplatePartialSpecializationDecl [[ADDR_25:0x[a-z0-9]*]] <line:7:1, col:74> col:29 struct remove_reference definition
 // CHECK-NEXT: | |-DefinitionData empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
@@ -197,9 +195,8 @@
 // CHECK-NEXT: | |   |   `-ElaboratedType [[ADDR_47:0x[a-z0-9]*]] 'typename remove_reference<float &>::type' sugar
 // CHECK-NEXT: | |   |     `-TypedefType [[ADDR_48:0x[a-z0-9]*]] 'remove_reference<float &>::type' sugar
 // CHECK-NEXT: | |   |       |-Typedef [[ADDR_10]] 'type'
-// CHECK-NEXT: | |   |       `-SubstTemplateTypeParmType [[ADDR_11]] 'float' sugar
-// CHECK-NEXT: | |   |         |-TemplateTypeParmType [[ADDR_12]] '_Tp' dependent depth 0 index 0
-// CHECK-NEXT: | |   |         | `-TemplateTypeParm [[ADDR_13]] '_Tp'
+// CHECK-NEXT: | |   |       `-SubstTemplateTypeParmType [[ADDR_11]] 'float' sugar class depth 0 index 0 _Tp
+// CHECK-NEXT: | |   |         |-ClassTemplateSpecialization [[ADDR_6]] 'remove_reference'
 // CHECK-NEXT: | |   |         `-BuiltinType [[ADDR_8]] 'float'
 // CHECK-NEXT: | |   `-ReturnStmt [[ADDR_49:0x[a-z0-9]*]] <line:13:3, col:33>
 // CHECK-NEXT: | |     `-CXXStaticCastExpr [[ADDR_50:0x[a-z0-9]*]] <col:10, col:33> '_Up':'float' xvalue static_cast<_Up &&> <NoOp>
@@ -215,9 +212,8 @@
 // CHECK-NEXT: |     |   `-ElaboratedType [[ADDR_57:0x[a-z0-9]*]] 'typename remove_reference<short &>::type' sugar
 // CHECK-NEXT: |     |     `-TypedefType [[ADDR_58:0x[a-z0-9]*]] 'remove_reference<short &>::type' sugar
 // CHECK-NEXT: |     |       |-Typedef [[ADDR_18]] 'type'
-// CHECK-NEXT: |     |       `-SubstTemplateTypeParmType [[ADDR_19]] 'short' sugar
-// CHECK-NEXT: |     |         |-TemplateTypeParmType [[ADDR_12]] '_Tp' dependent depth 0 index 0
-// CHECK-NEXT: |     |         | `-TemplateTypeParm [[ADDR_13]] '_Tp'
+// CHECK-NEXT: |     |       `-SubstTemplateTypeParmType [[ADDR_19]] 'short' sugar class depth 0 index 0 _Tp
+// CHECK-NEXT: |     |         |-ClassTemplateSpecialization [[ADDR_14]] 'remove_reference'
 // CHECK-NEXT: |     |         `-BuiltinType [[ADDR_16]] 'short'
 // CHECK-NEXT: |     `-ReturnStmt [[ADDR_59:0x[a-z0-9]*]] <line:13:3, col:33>
 // CHECK-NEXT: |       `-CXXStaticCastExpr [[ADDR_60:0x[a-z0-9]*]] <col:10, col:33> '_Up':'short' xvalue static_cast<_Up &&> <NoOp>
Index: clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp
@@ -176,8 +176,10 @@
         const auto *Param = Func->getParamDecl(J);
         const auto *ParamType =
             Param->getType()->getAs<SubstTemplateTypeParmType>();
-        if (!ParamType ||
-            ParamType->getReplacedParameter()->getDecl() != TPDecl)
+        if (!ParamType)
+          continue;
+        const TemplateTypeParmDecl *D = ParamType->getReplacedParameter();
+        if (D != TPDecl)
           continue;
         if (LHS.isUndef()) {
           LHS = Call.getArgSVal(J);
Index: clang/lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterDecl.cpp
+++ clang/lib/Serialization/ASTWriterDecl.cpp
@@ -1607,8 +1607,6 @@
     VarTemplateSpecializationDecl *D) {
   RegisterTemplateSpecialization(D->getSpecializedTemplate(), D);
 
-  VisitVarDecl(D);
-
   llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
   InstFrom = D->getSpecializedTemplateOrPartial();
   if (Decl *InstFromD = InstFrom.dyn_cast<VarTemplateDecl *>()) {
@@ -1629,6 +1627,9 @@
   Record.AddSourceLocation(D->getPointOfInstantiation());
   Record.push_back(D->getSpecializationKind());
   Record.push_back(D->IsCompleteDefinition);
+
+  VisitVarDecl(D);
+
   Record.push_back(D->isCanonicalDecl());
 
   if (D->isCanonicalDecl()) {
Index: clang/lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderDecl.cpp
+++ clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2390,8 +2390,6 @@
 ASTDeclReader::RedeclarableResult
 ASTDeclReader::VisitVarTemplateSpecializationDeclImpl(
     VarTemplateSpecializationDecl *D) {
-  RedeclarableResult Redecl = VisitVarDeclImpl(D);
-
   ASTContext &C = Reader.getContext();
   if (Decl *InstD = readDecl()) {
     if (auto *VTD = dyn_cast<VarTemplateDecl>(InstD)) {
@@ -2428,6 +2426,8 @@
   D->SpecializationKind = (TemplateSpecializationKind)Record.readInt();
   D->IsCompleteDefinition = Record.readInt();
 
+  RedeclarableResult Redecl = VisitVarDeclImpl(D);
+
   bool writtenAsCanonicalDecl = Record.readInt();
   if (writtenAsCanonicalDecl) {
     auto *CanonPattern = readDeclAs<VarTemplateDecl>();
Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -4854,8 +4854,8 @@
         Replacement = SemaRef.Context.getQualifiedType(
             Replacement.getUnqualifiedType(), Qs);
         T = SemaRef.Context.getSubstTemplateTypeParmType(
-            SubstTypeParam->getReplacedParameter(), Replacement,
-            SubstTypeParam->getPackIndex());
+            Replacement, SubstTypeParam->getReplacedDecl(),
+            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();
@@ -6402,6 +6402,9 @@
                                          SubstTemplateTypeParmTypeLoc TL) {
   const SubstTemplateTypeParmType *T = TL.getTypePtr();
 
+  Decl *NewReplaced =
+      getDerived().TransformDecl(TL.getNameLoc(), T->getReplacedDecl());
+
   // Substitute into the replacement type, which itself might involve something
   // that needs to be transformed. This only tends to occur with default
   // template arguments of template template parameters.
@@ -6413,7 +6416,7 @@
   // Always canonicalize the replacement type.
   Replacement = SemaRef.Context.getCanonicalType(Replacement);
   QualType Result = SemaRef.Context.getSubstTemplateTypeParmType(
-      T->getReplacedParameter(), Replacement, T->getPackIndex());
+      Replacement, NewReplaced, T->getIndex(), T->getPackIndex());
 
   // Propagate type-source information.
   SubstTemplateTypeParmTypeLoc NewTL
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4767,7 +4767,7 @@
     return nullptr;
 
   ContextRAII SavedContext(*this, FD);
-  MultiLevelTemplateArgumentList MArgs(*Args);
+  MultiLevelTemplateArgumentList MArgs(FTD, Args->asArray());
 
   return cast_or_null<FunctionDecl>(SubstDecl(FD, FD->getParent(), MArgs));
 }
@@ -5113,9 +5113,6 @@
   if (Inst.isInvalid())
     return nullptr;
 
-  MultiLevelTemplateArgumentList TemplateArgLists;
-  TemplateArgLists.addOuterTemplateArguments(&TemplateArgList);
-
   // Instantiate the first declaration of the variable template: for a partial
   // specialization of a static data member template, the first declaration may
   // or may not be the declaration in the class; if it's in the class, we want
@@ -5134,7 +5131,8 @@
   if (!IsMemberSpec)
     FromVar = FromVar->getFirstDecl();
 
-  MultiLevelTemplateArgumentList MultiLevelList(TemplateArgList);
+  MultiLevelTemplateArgumentList MultiLevelList(VarTemplate,
+                                                TemplateArgList.asArray());
   TemplateDeclInstantiator Instantiator(*this, FromVar->getDeclContext(),
                                         MultiLevelList);
 
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -64,7 +64,8 @@
   MultiLevelTemplateArgumentList Result;
 
   if (Innermost)
-    Result.addOuterTemplateArguments(Innermost);
+    Result.addOuterTemplateArguments(const_cast<NamedDecl *>(D),
+                                     Innermost->asArray());
 
   const auto *Ctx = dyn_cast<DeclContext>(D);
   if (!Ctx) {
@@ -80,8 +81,6 @@
           !isa<VarTemplatePartialSpecializationDecl>(Spec))
         return Result;
 
-      Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs());
-
       // If this variable template specialization was instantiated from a
       // specialized member that is a variable template, we're done.
       assert(Spec->getSpecializedTemplate() && "No variable template?");
@@ -90,10 +89,14 @@
                              = Spec->getSpecializedTemplateOrPartial();
       if (VarTemplatePartialSpecializationDecl *Partial =
               Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
+        Result.addOuterTemplateArguments(
+            Partial, Spec->getTemplateInstantiationArgs().asArray());
         if (Partial->isMemberSpecialization())
           return Result;
       } else {
         VarTemplateDecl *Tmpl = Specialized.get<VarTemplateDecl *>();
+        Result.addOuterTemplateArguments(
+            Tmpl, Spec->getTemplateInstantiationArgs().asArray());
         if (Tmpl->isMemberSpecialization())
           return Result;
       }
@@ -123,7 +126,9 @@
           !isa<ClassTemplatePartialSpecializationDecl>(Spec))
         break;
 
-      Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs());
+      Result.addOuterTemplateArguments(
+          const_cast<ClassTemplateSpecializationDecl *>(Spec),
+          Spec->getTemplateInstantiationArgs().asArray());
 
       // If this class template specialization was instantiated from a
       // specialized member that is a class template, we're done.
@@ -146,7 +151,8 @@
       } else if (const TemplateArgumentList *TemplateArgs
             = Function->getTemplateSpecializationArgs()) {
         // Add the template arguments for this specialization.
-        Result.addOuterTemplateArguments(TemplateArgs);
+        Result.addOuterTemplateArguments(const_cast<FunctionDecl *>(Function),
+                                         TemplateArgs->asArray());
 
         // If this function was instantiated from a specialized member that is
         // a function template, we're done.
@@ -1778,6 +1784,9 @@
 TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
                                                 TemplateTypeParmTypeLoc TL) {
   const TemplateTypeParmType *T = TL.getTypePtr();
+  TemplateTypeParmDecl *NewTTPDecl = cast_or_null<TemplateTypeParmDecl>(
+      TransformDecl(TL.getNameLoc(), T->getDecl()));
+
   if (T->getDepth() < TemplateArgs.getNumLevels()) {
     // Replace the template type parameter with its corresponding
     // template argument.
@@ -1813,6 +1822,8 @@
       return NewT;
     }
 
+    Decl *ReplacedDecl = TemplateArgs.getReplacedDecl(T->getDepth());
+
     Optional<unsigned> PackIndex;
     if (T->isParameterPack()) {
       assert(Arg.getKind() == TemplateArgument::Pack &&
@@ -1822,8 +1833,8 @@
         // We have the template argument pack, but we're not expanding the
         // enclosing pack expansion yet. Just save the template argument
         // pack for later substitution.
-        QualType Result
-          = getSema().Context.getSubstTemplateTypeParmPackType(T, Arg);
+        QualType Result = getSema().Context.getSubstTemplateTypeParmPackType(
+            ReplacedDecl, T->getIndex(), Arg);
         SubstTemplateTypeParmPackTypeLoc NewTL
           = TLB.push<SubstTemplateTypeParmPackTypeLoc>(Result);
         NewTL.setNameLoc(TL.getNameLoc());
@@ -1841,7 +1852,7 @@
 
     // TODO: only do this uniquing once, at the start of instantiation.
     QualType Result = getSema().Context.getSubstTemplateTypeParmType(
-        T, Replacement, PackIndex);
+        Replacement, ReplacedDecl, T->getIndex(), PackIndex);
     SubstTemplateTypeParmTypeLoc NewTL
       = TLB.push<SubstTemplateTypeParmTypeLoc>(Result);
     NewTL.setNameLoc(TL.getNameLoc());
@@ -1852,11 +1863,6 @@
   // the template parameter list of a member template inside the
   // template we are instantiating). Create a new template type
   // parameter with the template "level" reduced by one.
-  TemplateTypeParmDecl *NewTTPDecl = nullptr;
-  if (TemplateTypeParmDecl *OldTTPDecl = T->getDecl())
-    NewTTPDecl = cast_or_null<TemplateTypeParmDecl>(
-                                  TransformDecl(TL.getNameLoc(), OldTTPDecl));
-
   QualType Result = getSema().Context.getTemplateTypeParmType(
       T->getDepth() - TemplateArgs.getNumSubstitutedLevels(), T->getIndex(),
       T->isParameterPack(), NewTTPDecl);
@@ -1865,26 +1871,32 @@
   return Result;
 }
 
-QualType
-TemplateInstantiator::TransformSubstTemplateTypeParmPackType(
-                                                            TypeLocBuilder &TLB,
-                                         SubstTemplateTypeParmPackTypeLoc TL) {
+QualType TemplateInstantiator::TransformSubstTemplateTypeParmPackType(
+    TypeLocBuilder &TLB, SubstTemplateTypeParmPackTypeLoc TL) {
+  const SubstTemplateTypeParmPackType *T = TL.getTypePtr();
+
+  Decl *NewReplaced = TransformDecl(TL.getNameLoc(), T->getReplacedDecl());
+
   if (getSema().ArgumentPackSubstitutionIndex == -1) {
     // We aren't expanding the parameter pack, so just return ourselves.
-    SubstTemplateTypeParmPackTypeLoc NewTL
-      = TLB.push<SubstTemplateTypeParmPackTypeLoc>(TL.getType());
+    QualType Result = TL.getType();
+    if (NewReplaced != T->getReplacedDecl())
+      Result = getSema().Context.getSubstTemplateTypeParmPackType(
+          NewReplaced, T->getIndex(), T->getArgumentPack());
+    SubstTemplateTypeParmPackTypeLoc NewTL =
+        TLB.push<SubstTemplateTypeParmPackTypeLoc>(Result);
     NewTL.setNameLoc(TL.getNameLoc());
-    return TL.getType();
+    return Result;
   }
 
-  TemplateArgument Arg = TL.getTypePtr()->getArgumentPack();
-  Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
+  TemplateArgument Arg =
+      getPackSubstitutedTemplateArgument(getSema(), T->getArgumentPack());
 
   QualType Result = getSema().Context.getSubstTemplateTypeParmType(
-      TL.getTypePtr()->getReplacedParameter(), Arg.getAsType(),
+      Arg.getAsType(), NewReplaced, T->getIndex(),
       getSema().ArgumentPackSubstitutionIndex);
-  SubstTemplateTypeParmTypeLoc NewTL
-    = TLB.push<SubstTemplateTypeParmTypeLoc>(Result);
+  SubstTemplateTypeParmTypeLoc NewTL =
+      TLB.push<SubstTemplateTypeParmTypeLoc>(Result);
   NewTL.setNameLoc(TL.getNameLoc());
   return Result;
 }
Index: clang/lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateDeduction.cpp
+++ clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2633,7 +2633,7 @@
     if (PackedArgsBuilder.empty()) {
       LocalInstantiationScope Scope(S);
       TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Output);
-      MultiLevelTemplateArgumentList Args(TemplateArgs);
+      MultiLevelTemplateArgumentList Args(Template, TemplateArgs.asArray());
 
       if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
         Sema::InstantiatingTemplate Inst(S, Template->getLocation(), Template,
@@ -2805,7 +2805,7 @@
   // FIXME: This will change quite a bit once deferred concept instantiation is
   // implemented.
   MultiLevelTemplateArgumentList MLTAL;
-  MLTAL.addOuterTemplateArguments(DeducedArgs);
+  MLTAL.addOuterTemplateArguments(Template, DeducedArgs);
 
   if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints,
                                     MLTAL, Info.getLocation(),
@@ -2860,9 +2860,10 @@
   TemplateArgumentListInfo InstArgs(PartialTemplArgInfo->LAngleLoc,
                                     PartialTemplArgInfo->RAngleLoc);
 
-  if (S.SubstTemplateArguments(
-          PartialTemplArgInfo->arguments(),
-          MultiLevelTemplateArgumentList(*DeducedArgumentList), InstArgs)) {
+  if (S.SubstTemplateArguments(PartialTemplArgInfo->arguments(),
+                               MultiLevelTemplateArgumentList(
+                                   Partial, DeducedArgumentList->asArray()),
+                               InstArgs)) {
     unsigned ArgIdx = InstArgs.size(), ParamIdx = ArgIdx;
     if (ParamIdx >= Partial->getTemplateParameters()->size())
       ParamIdx = Partial->getTemplateParameters()->size() - 1;
@@ -3198,7 +3199,8 @@
   if (Proto->hasTrailingReturn()) {
     if (SubstParmTypes(Function->getLocation(), Function->parameters(),
                        Proto->getExtParameterInfosOrNull(),
-                       MultiLevelTemplateArgumentList(*ExplicitArgumentList),
+                       MultiLevelTemplateArgumentList(
+                           FunctionTemplate, ExplicitArgumentList->asArray()),
                        ParamTypes, /*params*/ nullptr, ExtParamInfos))
       return TDK_SubstitutionFailure;
   }
@@ -3224,7 +3226,8 @@
 
     ResultType =
         SubstType(Proto->getReturnType(),
-                  MultiLevelTemplateArgumentList(*ExplicitArgumentList),
+                  MultiLevelTemplateArgumentList(
+                      FunctionTemplate, ExplicitArgumentList->asArray()),
                   Function->getTypeSpecStartLoc(), Function->getDeclName());
     if (ResultType.isNull() || Trap.hasErrorOccurred())
       return TDK_SubstitutionFailure;
@@ -3242,7 +3245,8 @@
   if (!Proto->hasTrailingReturn() &&
       SubstParmTypes(Function->getLocation(), Function->parameters(),
                      Proto->getExtParameterInfosOrNull(),
-                     MultiLevelTemplateArgumentList(*ExplicitArgumentList),
+                     MultiLevelTemplateArgumentList(
+                         FunctionTemplate, ExplicitArgumentList->asArray()),
                      ParamTypes, /*params*/ nullptr, ExtParamInfos))
     return TDK_SubstitutionFailure;
 
@@ -3257,7 +3261,8 @@
     if (getLangOpts().CPlusPlus17 &&
         SubstExceptionSpec(
             Function->getLocation(), EPI.ExceptionSpec, ExceptionStorage,
-            MultiLevelTemplateArgumentList(*ExplicitArgumentList)))
+            MultiLevelTemplateArgumentList(FunctionTemplate,
+                                           ExplicitArgumentList->asArray())))
       return TDK_SubstitutionFailure;
 
     *FunctionType = BuildFunctionType(ResultType, ParamTypes,
@@ -3497,7 +3502,8 @@
   DeclContext *Owner = FunctionTemplate->getDeclContext();
   if (FunctionTemplate->getFriendObjectKind())
     Owner = FunctionTemplate->getLexicalDeclContext();
-  MultiLevelTemplateArgumentList SubstArgs(*DeducedArgumentList);
+  MultiLevelTemplateArgumentList SubstArgs(FunctionTemplate,
+                                           DeducedArgumentList->asArray());
   Specialization = cast_or_null<FunctionDecl>(
       SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner, SubstArgs));
   if (!Specialization || Specialization->isInvalidDecl())
@@ -4554,7 +4560,7 @@
                                   /*PartialTemplateArgs=*/false, Converted))
     return true;
   MultiLevelTemplateArgumentList MLTAL;
-  MLTAL.addOuterTemplateArguments(Converted);
+  MLTAL.addOuterTemplateArguments(Concept, Converted);
   if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()},
                                     MLTAL, TypeLoc.getLocalSourceRange(),
                                     Satisfaction))
@@ -5798,9 +5804,8 @@
   case Type::SubstTemplateTypeParmPack: {
     const SubstTemplateTypeParmPackType *Subst
       = cast<SubstTemplateTypeParmPackType>(T);
-    MarkUsedTemplateParameters(Ctx,
-                               QualType(Subst->getReplacedParameter(), 0),
-                               OnlyDeduced, Depth, Used);
+    if (Subst->getReplacedParameter()->getDepth() == Depth)
+      Used[Subst->getIndex()] = true;
     MarkUsedTemplateParameters(Ctx, Subst->getArgumentPack(),
                                OnlyDeduced, Depth, Used);
     break;
Index: clang/lib/Sema/SemaTemplate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -3760,7 +3760,8 @@
 
     // Only substitute for the innermost template argument list.
     MultiLevelTemplateArgumentList TemplateArgLists;
-    TemplateArgLists.addOuterTemplateArguments(&StackTemplateArgs);
+    TemplateArgLists.addOuterTemplateArguments(Template,
+                                               StackTemplateArgs.asArray());
     TemplateArgLists.addOuterRetainedLevels(
         AliasTemplate->getTemplateParameters()->getDepth());
 
@@ -3882,7 +3883,7 @@
       InstantiatingTemplate Inst(*this, TemplateLoc, Decl);
       if (!Inst.isInvalid()) {
         MultiLevelTemplateArgumentList TemplateArgLists;
-        TemplateArgLists.addOuterTemplateArguments(Converted);
+        TemplateArgLists.addOuterTemplateArguments(Template, Converted);
         InstantiateAttrsForDecl(TemplateArgLists,
                                 ClassTemplate->getTemplatedDecl(), Decl);
       }
@@ -4751,7 +4752,7 @@
       TemplateSpecializationType::anyDependentTemplateArguments(*TemplateArgs,
                                                                 Converted);
   MultiLevelTemplateArgumentList MLTAL;
-  MLTAL.addOuterTemplateArguments(Converted);
+  MLTAL.addOuterTemplateArguments(NamedConcept, Converted);
   LocalInstantiationScope Scope(*this);
   if (!AreArgsDependent &&
       CheckConstraintSatisfaction(
@@ -5161,8 +5162,8 @@
     TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
 
     // Only substitute for the innermost template argument list.
-    MultiLevelTemplateArgumentList TemplateArgLists;
-    TemplateArgLists.addOuterTemplateArguments(&TemplateArgs);
+    MultiLevelTemplateArgumentList TemplateArgLists(Template,
+                                                    TemplateArgs.asArray());
     for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
       TemplateArgLists.addOuterTemplateArguments(None);
 
@@ -5217,8 +5218,8 @@
   TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
 
   // Only substitute for the innermost template argument list.
-  MultiLevelTemplateArgumentList TemplateArgLists;
-  TemplateArgLists.addOuterTemplateArguments(&TemplateArgs);
+  MultiLevelTemplateArgumentList TemplateArgLists(Template,
+                                                  TemplateArgs.asArray());
   for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
     TemplateArgLists.addOuterTemplateArguments(None);
 
@@ -5270,8 +5271,8 @@
   TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
 
   // Only substitute for the innermost template argument list.
-  MultiLevelTemplateArgumentList TemplateArgLists;
-  TemplateArgLists.addOuterTemplateArguments(&TemplateArgs);
+  MultiLevelTemplateArgumentList TemplateArgLists(Template,
+                                                  TemplateArgs.asArray());
   for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
     TemplateArgLists.addOuterTemplateArguments(None);
 
@@ -5455,18 +5456,15 @@
       TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
                                         Converted);
 
+      MultiLevelTemplateArgumentList MLTAL(Template, TemplateArgs.asArray());
       // If the parameter is a pack expansion, expand this slice of the pack.
       if (auto *PET = NTTPType->getAs<PackExpansionType>()) {
         Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this,
                                                            ArgumentPackIndex);
-        NTTPType = SubstType(PET->getPattern(),
-                             MultiLevelTemplateArgumentList(TemplateArgs),
-                             NTTP->getLocation(),
+        NTTPType = SubstType(PET->getPattern(), MLTAL, NTTP->getLocation(),
                              NTTP->getDeclName());
       } else {
-        NTTPType = SubstType(NTTPType,
-                             MultiLevelTemplateArgumentList(TemplateArgs),
-                             NTTP->getLocation(),
+        NTTPType = SubstType(NTTPType, MLTAL, NTTP->getLocation(),
                              NTTP->getDeclName());
       }
 
@@ -5609,15 +5607,15 @@
   {
     // Set up a template instantiation context.
     LocalInstantiationScope Scope(*this);
-    InstantiatingTemplate Inst(*this, TemplateLoc, Template,
-                               TempParm, Converted,
-                               SourceRange(TemplateLoc, RAngleLoc));
+    InstantiatingTemplate Inst(*this, TemplateLoc, Template, TempParm,
+                               Converted, SourceRange(TemplateLoc, RAngleLoc));
     if (Inst.isInvalid())
       return true;
 
     TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
-    Params = SubstTemplateParams(Params, CurContext,
-                                 MultiLevelTemplateArgumentList(TemplateArgs));
+    Params = SubstTemplateParams(
+        Params, CurContext,
+        MultiLevelTemplateArgumentList(Template, TemplateArgs.asArray()));
     if (!Params)
       return true;
   }
@@ -5976,7 +5974,7 @@
     // FIXME: This will be changed a bit once deferred concept instantiation is
     // implemented.
     MultiLevelTemplateArgumentList MLTAL;
-    MLTAL.addOuterTemplateArguments(Converted);
+    MLTAL.addOuterTemplateArguments(Template, Converted);
     if (EnsureTemplateArgumentListConstraints(
             Template, MLTAL,
             SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) {
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -8907,13 +8907,13 @@
         Context.getReferenceQualifiedType(E).getCanonicalType();
     llvm::SmallVector<TemplateArgument, 1> Args;
     Args.push_back(TemplateArgument(MatchedType));
+
+    auto *Param = cast<TemplateTypeParmDecl>(TPL->getParam(0));
+
     TemplateArgumentList TAL(TemplateArgumentList::OnStack, Args);
-    MultiLevelTemplateArgumentList MLTAL(TAL);
-    for (unsigned I = 0; I < TPL->getDepth(); ++I)
-      MLTAL.addOuterRetainedLevel();
-    Expr *IDC =
-        cast<TemplateTypeParmDecl>(TPL->getParam(0))->getTypeConstraint()
-            ->getImmediatelyDeclaredConstraint();
+    MultiLevelTemplateArgumentList MLTAL(Param, TAL.asArray());
+    MLTAL.addOuterRetainedLevels(TPL->getDepth());
+    Expr *IDC = Param->getTypeConstraint()->getImmediatelyDeclaredConstraint();
     ExprResult Constraint = SubstExpr(IDC, MLTAL);
     if (Constraint.isInvalid()) {
       Status = concepts::ExprRequirement::SS_ExprSubstitutionFailure;
Index: clang/lib/Sema/SemaConcept.cpp
===================================================================
--- clang/lib/Sema/SemaConcept.cpp
+++ clang/lib/Sema/SemaConcept.cpp
@@ -327,8 +327,9 @@
   // has no access to the MultiLevelTemplateArgumentList, so this has to happen
   // here.
   llvm::SmallVector<TemplateArgument, 4> FlattenedArgs;
-  for (ArrayRef<TemplateArgument> List : TemplateArgsLists)
-    FlattenedArgs.insert(FlattenedArgs.end(), List.begin(), List.end());
+  for (auto List : TemplateArgsLists)
+    FlattenedArgs.insert(FlattenedArgs.end(), List.Args.begin(),
+                         List.Args.end());
 
   llvm::FoldingSetNodeID ID;
   ConstraintSatisfaction::Profile(ID, Context, Template, FlattenedArgs);
@@ -435,7 +436,7 @@
   MultiLevelTemplateArgumentList MLTAL;
   // FIXME: This will be replaced with some logic to get all the template
   // arguments when we switch to deferred template instantiation.
-  MLTAL.addOuterTemplateArguments(TemplateArgs);
+  MLTAL.addOuterTemplateArguments(Decl, TemplateArgs);
 
   // If this is not an explicit specialization - we need to get the instantiated
   // version of the template arguments and add them to scope for the
@@ -447,7 +448,7 @@
     if (Inst.isInvalid())
       return true;
     MultiLevelTemplateArgumentList MLTAL(
-        *Decl->getTemplateSpecializationArgs());
+        Decl, Decl->getTemplateSpecializationArgs()->asArray());
     if (addInstantiatedParametersToScope(
             Decl, Decl->getPrimaryTemplate()->getTemplatedDecl(), Scope, MLTAL))
       return true;
@@ -749,7 +750,7 @@
   AtomicConstraint &Atomic = *N.getAtomicConstraint();
   TemplateArgumentListInfo SubstArgs;
   MultiLevelTemplateArgumentList MLTAL;
-  MLTAL.addOuterTemplateArguments(TemplateArgs);
+  MLTAL.addOuterTemplateArguments(Concept, TemplateArgs);
   if (!Atomic.ParameterMapping) {
     llvm::SmallBitVector OccurringIndices(TemplateParams->size());
     S.MarkUsedTemplateParameters(Atomic.ConstraintExpr, /*OnlyDeduced=*/false,
Index: clang/lib/AST/TypePrinter.cpp
===================================================================
--- clang/lib/AST/TypePrinter.cpp
+++ clang/lib/AST/TypePrinter.cpp
@@ -1470,14 +1470,27 @@
                                         const SubstTemplateTypeParmPackType *T,
                                         raw_ostream &OS) {
   IncludeStrongLifetimeRAII Strong(Policy);
-  printTemplateTypeParmBefore(T->getReplacedParameter(), OS);
+  if (const TemplateTypeParmDecl *D = T->getReplacedParameter()) {
+    if (D && D->isImplicit()) {
+      if (auto *TC = D->getTypeConstraint()) {
+        TC->print(OS, Policy);
+        OS << ' ';
+      }
+      OS << "auto";
+    } else if (IdentifierInfo *Id = D->getIdentifier())
+      OS << (Policy.CleanUglifiedParameters ? Id->deuglifiedName()
+                                            : Id->getName());
+    else
+      OS << "type-parameter-" << D->getDepth() << '-' << D->getIndex();
+
+    spaceBeforePlaceHolder(OS);
+  }
 }
 
 void TypePrinter::printSubstTemplateTypeParmPackAfter(
                                         const SubstTemplateTypeParmPackType *T,
                                         raw_ostream &OS) {
   IncludeStrongLifetimeRAII Strong(Policy);
-  printTemplateTypeParmAfter(T->getReplacedParameter(), OS);
 }
 
 void TypePrinter::printTemplateId(const TemplateSpecializationType *T,
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(T->getReplacedParameter(),
-                                            replacementType, T->getPackIndex());
+    return Ctx.getSubstTemplateTypeParmType(replacementType,
+                                            T->getReplacedDecl(), T->getIndex(),
+                                            T->getPackIndex());
   }
 
   // FIXME: Non-trivial to implement, but important for C++
@@ -3649,14 +3650,105 @@
   return isCanonicalUnqualified() ? nullptr : getDecl()->getIdentifier();
 }
 
+static const TemplateParameterList *
+getReplacedTemplateParameterList(const Decl *D) {
+  switch (D->getKind()) {
+  case Decl::Kind::ClassTemplate:
+    return cast<ClassTemplateDecl>(D)->getTemplateParameters();
+  case Decl::Kind::ClassTemplateSpecialization: {
+    const auto *CTSD = cast<ClassTemplateSpecializationDecl>(D);
+    auto P = CTSD->getSpecializedTemplateOrPartial();
+    if (const auto *CTPSD =
+            P.dyn_cast<ClassTemplatePartialSpecializationDecl *>())
+      return CTPSD->getTemplateParameters();
+    return cast<ClassTemplateDecl *>(P)->getTemplateParameters();
+  }
+  case Decl::Kind::ClassTemplatePartialSpecialization:
+    return cast<ClassTemplatePartialSpecializationDecl>(D)
+        ->getTemplateParameters();
+  case Decl::Kind::TypeAliasTemplate:
+    return cast<TypeAliasTemplateDecl>(D)->getTemplateParameters();
+  case Decl::Kind::BuiltinTemplate:
+    return cast<BuiltinTemplateDecl>(D)->getTemplateParameters();
+  case Decl::Kind::CXXConversion:
+  case Decl::Kind::CXXConstructor:
+  case Decl::Kind::CXXDestructor:
+  case Decl::Kind::CXXMethod:
+  case Decl::Kind::Function:
+    return cast<FunctionDecl>(D)
+        ->getTemplateSpecializationInfo()
+        ->getTemplate()
+        ->getTemplateParameters();
+  case Decl::Kind::FunctionTemplate:
+    return cast<FunctionTemplateDecl>(D)->getTemplateParameters();
+  case Decl::Kind::VarTemplate:
+    return cast<VarTemplateDecl>(D)->getTemplateParameters();
+  case Decl::Kind::VarTemplateSpecialization: {
+    const auto *VTSD = cast<VarTemplateSpecializationDecl>(D);
+    auto P = VTSD->getSpecializedTemplateOrPartial();
+    if (const auto *VTPSD =
+            P.dyn_cast<VarTemplatePartialSpecializationDecl *>())
+      return VTPSD->getTemplateParameters();
+    return cast<VarTemplateDecl *>(P)->getTemplateParameters();
+  }
+  case Decl::Kind::VarTemplatePartialSpecialization:
+    return cast<VarTemplatePartialSpecializationDecl>(D)
+        ->getTemplateParameters();
+  case Decl::Kind::TemplateTemplateParm:
+    return cast<TemplateTemplateParmDecl>(D)->getTemplateParameters();
+  case Decl::Kind::Concept:
+    return cast<ConceptDecl>(D)->getTemplateParameters();
+  default:
+    D->dumpColor();
+    llvm_unreachable("Unhandled Replaced Kind");
+  }
+}
+
+static const TemplateTypeParmDecl *getReplacedParameter(const Decl *D,
+                                                        unsigned Index) {
+  if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(D))
+    return TTP;
+  return cast<TemplateTypeParmDecl>(
+      getReplacedTemplateParameterList(D)->getParam(Index));
+}
+
+SubstTemplateTypeParmType::SubstTemplateTypeParmType(
+    QualType Replacement, Decl *ReplacedDecl, unsigned Index,
+    Optional<unsigned> PackIndex)
+    : Type(SubstTemplateTypeParm, Replacement.getCanonicalType(),
+           Replacement->getDependence()),
+      Replacement(Replacement), ReplacedDecl(ReplacedDecl) {
+  SubstTemplateTypeParmTypeBits.Index = Index;
+  SubstTemplateTypeParmTypeBits.PackIndex = PackIndex ? *PackIndex + 1 : 0;
+  assert(ReplacedDecl != nullptr);
+  assert(getReplacedParameter() != nullptr);
+}
+
+const TemplateTypeParmDecl *
+SubstTemplateTypeParmType::getReplacedParameter() const {
+  return ::getReplacedParameter(getReplacedDecl(), getIndex());
+}
+
 SubstTemplateTypeParmPackType::SubstTemplateTypeParmPackType(
-    const TemplateTypeParmType *Param, QualType Canon,
+    QualType Canon, Decl *ReplacedDecl, unsigned Index,
     const TemplateArgument &ArgPack)
     : Type(SubstTemplateTypeParmPack, Canon,
            TypeDependence::DependentInstantiation |
                TypeDependence::UnexpandedPack),
-      Replaced(Param), Arguments(ArgPack.pack_begin()) {
+      Arguments(ArgPack.pack_begin()), ReplacedDecl(ReplacedDecl) {
+  SubstTemplateTypeParmPackTypeBits.Index = Index;
   SubstTemplateTypeParmPackTypeBits.NumArgs = ArgPack.pack_size();
+  assert(ReplacedDecl != nullptr);
+  assert(getReplacedParameter() != nullptr);
+}
+
+const TemplateTypeParmDecl *
+SubstTemplateTypeParmPackType::getReplacedParameter() const {
+  return ::getReplacedParameter(getReplacedDecl(), getIndex());
+}
+
+IdentifierInfo *SubstTemplateTypeParmPackType::getIdentifier() const {
+  return getReplacedParameter()->getIdentifier();
 }
 
 TemplateArgument SubstTemplateTypeParmPackType::getArgumentPack() const {
@@ -3664,13 +3756,15 @@
 }
 
 void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID) {
-  Profile(ID, getReplacedParameter(), getArgumentPack());
+  Profile(ID, getReplacedDecl(), getIndex(), getArgumentPack());
 }
 
 void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID,
-                                           const TemplateTypeParmType *Replaced,
+                                            const Decl *ReplacedDecl,
+                                            unsigned Index,
                                             const TemplateArgument &ArgPack) {
-  ID.AddPointer(Replaced);
+  ID.AddPointer(ReplacedDecl);
+  ID.AddInteger(Index);
   ID.AddInteger(ArgPack.pack_size());
   for (const auto &P : ArgPack.pack_elements())
     ID.AddPointer(P.getAsType().getAsOpaquePtr());
Index: clang/lib/AST/TextNodeDumper.cpp
===================================================================
--- clang/lib/AST/TextNodeDumper.cpp
+++ clang/lib/AST/TextNodeDumper.cpp
@@ -1570,10 +1570,18 @@
 
 void TextNodeDumper::VisitSubstTemplateTypeParmType(
     const SubstTemplateTypeParmType *T) {
+  dumpDeclRef(T->getReplacedDecl());
+  VisitTemplateTypeParmDecl(T->getReplacedParameter());
   if (auto PackIndex = T->getPackIndex())
     OS << " pack_index " << *PackIndex;
 }
 
+void TextNodeDumper::VisitSubstTemplateTypeParmPackType(
+    const SubstTemplateTypeParmPackType *T) {
+  dumpDeclRef(T->getReplacedDecl());
+  VisitTemplateTypeParmDecl(T->getReplacedParameter());
+}
+
 void TextNodeDumper::VisitAutoType(const AutoType *T) {
   if (T->isDecltypeAuto())
     OS << " decltype(auto)";
Index: clang/lib/AST/ODRHash.cpp
===================================================================
--- clang/lib/AST/ODRHash.cpp
+++ clang/lib/AST/ODRHash.cpp
@@ -671,7 +671,7 @@
     }
   }
 
-  void AddDecl(Decl *D) {
+  void AddDecl(const Decl *D) {
     Hash.AddBoolean(D);
     if (D) {
       Hash.AddDecl(D);
@@ -995,13 +995,13 @@
 
   void
   VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) {
-    AddType(T->getReplacedParameter());
+    AddDecl(T->getReplacedDecl());
     Hash.AddTemplateArgument(T->getArgumentPack());
     VisitType(T);
   }
 
   void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) {
-    AddType(T->getReplacedParameter());
+    AddDecl(T->getReplacedDecl());
     AddQualType(T->getReplacementType());
     VisitType(T);
   }
Index: clang/lib/AST/JSONNodeDumper.cpp
===================================================================
--- clang/lib/AST/JSONNodeDumper.cpp
+++ clang/lib/AST/JSONNodeDumper.cpp
@@ -682,10 +682,16 @@
 
 void JSONNodeDumper::VisitSubstTemplateTypeParmType(
     const SubstTemplateTypeParmType *STTPT) {
+  JOS.attribute("index", STTPT->getIndex());
   if (auto PackIndex = STTPT->getPackIndex())
     JOS.attribute("pack_index", *PackIndex);
 }
 
+void JSONNodeDumper::VisitSubstTemplateTypeParmPackType(
+    const SubstTemplateTypeParmPackType *T) {
+  JOS.attribute("index", T->getIndex());
+}
+
 void JSONNodeDumper::VisitAutoType(const AutoType *AT) {
   JOS.attribute("undeduced", !AT->isDeduced());
   switch (AT->getKeyword()) {
Index: clang/lib/AST/ASTStructuralEquivalence.cpp
===================================================================
--- clang/lib/AST/ASTStructuralEquivalence.cpp
+++ clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -1055,13 +1055,13 @@
   case Type::SubstTemplateTypeParm: {
     const auto *Subst1 = cast<SubstTemplateTypeParmType>(T1);
     const auto *Subst2 = cast<SubstTemplateTypeParmType>(T2);
-    if (!IsStructurallyEquivalent(Context,
-                                  QualType(Subst1->getReplacedParameter(), 0),
-                                  QualType(Subst2->getReplacedParameter(), 0)))
-      return false;
     if (!IsStructurallyEquivalent(Context, Subst1->getReplacementType(),
                                   Subst2->getReplacementType()))
       return false;
+    if (Subst1->getReplacedDecl() != Subst2->getReplacedDecl())
+      return false;
+    if (Subst1->getIndex() != Subst2->getIndex())
+      return false;
     if (Subst1->getPackIndex() != Subst2->getPackIndex())
       return false;
     break;
@@ -1070,9 +1070,9 @@
   case Type::SubstTemplateTypeParmPack: {
     const auto *Subst1 = cast<SubstTemplateTypeParmPackType>(T1);
     const auto *Subst2 = cast<SubstTemplateTypeParmPackType>(T2);
-    if (!IsStructurallyEquivalent(Context,
-                                  QualType(Subst1->getReplacedParameter(), 0),
-                                  QualType(Subst2->getReplacedParameter(), 0)))
+    if (Subst1->getReplacedDecl() != Subst2->getReplacedDecl())
+      return false;
+    if (Subst1->getIndex() != Subst2->getIndex())
       return false;
     if (!IsStructurallyEquivalent(Context, Subst1->getArgumentPack(),
                                   Subst2->getArgumentPack()))
Index: clang/lib/AST/ASTImporter.cpp
===================================================================
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -1520,8 +1520,7 @@
 
 ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmType(
     const SubstTemplateTypeParmType *T) {
-  Expected<const TemplateTypeParmType *> ReplacedOrErr =
-      import(T->getReplacedParameter());
+  Expected<Decl *> ReplacedOrErr = import(T->getReplacedDecl());
   if (!ReplacedOrErr)
     return ReplacedOrErr.takeError();
 
@@ -1530,14 +1529,13 @@
     return ToReplacementTypeOrErr.takeError();
 
   return Importer.getToContext().getSubstTemplateTypeParmType(
-      *ReplacedOrErr, ToReplacementTypeOrErr->getCanonicalType(),
+      *ToReplacementTypeOrErr, *ReplacedOrErr, T->getIndex(),
       T->getPackIndex());
 }
 
 ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmPackType(
     const SubstTemplateTypeParmPackType *T) {
-  Expected<const TemplateTypeParmType *> ReplacedOrErr =
-      import(T->getReplacedParameter());
+  Expected<Decl *> ReplacedOrErr = import(T->getReplacedDecl());
   if (!ReplacedOrErr)
     return ReplacedOrErr.takeError();
 
@@ -1546,7 +1544,7 @@
     return ToArgumentPack.takeError();
 
   return Importer.getToContext().getSubstTemplateTypeParmPackType(
-      *ReplacedOrErr, *ToArgumentPack);
+      *ReplacedOrErr, T->getIndex(), *ToArgumentPack);
 }
 
 ExpectedType ASTNodeImporter::VisitTemplateSpecializationType(
@@ -3747,6 +3745,10 @@
     }
   }
 
+  // If it is a template, import all related things.
+  if (Error Err = ImportTemplateInformation(D, ToFunction))
+    return std::move(Err);
+
   if (D->doesThisDeclarationHaveABody()) {
     Error Err = ImportFunctionDeclBody(D, ToFunction);
 
@@ -3768,10 +3770,6 @@
 
   // FIXME: Other bits to merge?
 
-  // If it is a template, import all related things.
-  if (Error Err = ImportTemplateInformation(D, ToFunction))
-    return std::move(Err);
-
   addDeclToContexts(D, ToFunction);
 
   if (auto *FromCXXMethod = dyn_cast<CXXMethodDecl>(D))
@@ -5991,6 +5989,30 @@
 
   D2->setTemplateSpecializationKind(D->getTemplateSpecializationKind());
 
+  if (auto P = D->getInstantiatedFrom()) {
+    if (auto *CTD = P.dyn_cast<ClassTemplateDecl *>()) {
+      if (auto CTDorErr = import(CTD))
+        D2->setInstantiationOf(*CTDorErr);
+    } else {
+      auto *CTPSD = cast<ClassTemplatePartialSpecializationDecl *>(P);
+      auto CTPSDOrErr = import(CTPSD);
+      if (!CTPSDOrErr)
+        return CTPSDOrErr.takeError();
+      const TemplateArgumentList &DArgs = D->getTemplateInstantiationArgs();
+      SmallVector<TemplateArgument, 2> D2ArgsVec(DArgs.size());
+      for (unsigned I = 0; I < DArgs.size(); ++I) {
+        const TemplateArgument &DArg = DArgs[I];
+        if (auto ArgOrErr = import(DArg))
+          D2ArgsVec[I] = *ArgOrErr;
+        else
+          return ArgOrErr.takeError();
+      }
+      D2->setInstantiationOf(
+          *CTPSDOrErr,
+          TemplateArgumentList::CreateCopy(Importer.getToContext(), D2ArgsVec));
+    }
+  }
+
   if (D->isCompleteDefinition())
     if (Error Err = ImportDefinition(D, D2))
       return std::move(Err);
@@ -6154,15 +6176,6 @@
       }
     }
   } else {
-    // Import the type.
-    QualType T;
-    if (Error Err = importInto(T, D->getType()))
-      return std::move(Err);
-
-    auto TInfoOrErr = import(D->getTypeSourceInfo());
-    if (!TInfoOrErr)
-      return TInfoOrErr.takeError();
-
     TemplateArgumentListInfo ToTAInfo;
     if (const ASTTemplateArgumentListInfo *Args = D->getTemplateArgsInfo()) {
       if (Error Err = ImportTemplateArgumentListInfo(*Args, ToTAInfo))
@@ -6187,7 +6200,7 @@
       PartVarSpecDecl *ToPartial;
       if (GetImportedOrCreateDecl(ToPartial, D, Importer.getToContext(), DC,
                                   *BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr,
-                                  VarTemplate, T, *TInfoOrErr,
+                                  VarTemplate, QualType(), nullptr,
                                   D->getStorageClass(), TemplateArgs, ArgInfos))
         return ToPartial;
 
@@ -6208,11 +6221,21 @@
     } else { // Full specialization
       if (GetImportedOrCreateDecl(D2, D, Importer.getToContext(), DC,
                                   *BeginLocOrErr, *IdLocOrErr, VarTemplate,
-                                  T, *TInfoOrErr,
-                                  D->getStorageClass(), TemplateArgs))
+                                  QualType(), nullptr, D->getStorageClass(),
+                                  TemplateArgs))
         return D2;
     }
 
+    QualType T;
+    if (Error Err = importInto(T, D->getType()))
+      return std::move(Err);
+    D2->setType(T);
+
+    auto TInfoOrErr = import(D->getTypeSourceInfo());
+    if (!TInfoOrErr)
+      return TInfoOrErr.takeError();
+    D2->setTypeSourceInfo(*TInfoOrErr);
+
     if (D->getPointOfInstantiation().isValid()) {
       if (ExpectedSLoc POIOrErr = import(D->getPointOfInstantiation()))
         D2->setPointOfInstantiation(*POIOrErr);
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -4747,21 +4747,19 @@
 
 /// Retrieve a substitution-result type.
 QualType
-ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm,
-                                         QualType Replacement,
+ASTContext::getSubstTemplateTypeParmType(QualType Replacement,
+                                         Decl *ReplacedDecl, unsigned Index,
                                          Optional<unsigned> PackIndex) const {
-  assert(Replacement.isCanonical()
-         && "replacement types must always be canonical");
-
   llvm::FoldingSetNodeID ID;
-  SubstTemplateTypeParmType::Profile(ID, Parm, Replacement, PackIndex);
+  SubstTemplateTypeParmType::Profile(ID, Replacement, ReplacedDecl, Index,
+                                     PackIndex);
   void *InsertPos = nullptr;
-  SubstTemplateTypeParmType *SubstParm
-    = SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
+  SubstTemplateTypeParmType *SubstParm =
+      SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
 
   if (!SubstParm) {
     SubstParm = new (*this, TypeAlignment)
-        SubstTemplateTypeParmType(Parm, Replacement, PackIndex);
+        SubstTemplateTypeParmType(Replacement, ReplacedDecl, Index, PackIndex);
     Types.push_back(SubstParm);
     SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos);
   }
@@ -4770,34 +4768,32 @@
 }
 
 /// Retrieve a
-QualType ASTContext::getSubstTemplateTypeParmPackType(
-                                          const TemplateTypeParmType *Parm,
-                                              const TemplateArgument &ArgPack) {
+QualType
+ASTContext::getSubstTemplateTypeParmPackType(Decl *ReplacedDecl, unsigned Index,
+                                             const TemplateArgument &ArgPack) {
 #ifndef NDEBUG
   for (const auto &P : ArgPack.pack_elements()) {
-    assert(P.getKind() == TemplateArgument::Type &&"Pack contains a non-type");
+    assert(P.getKind() == TemplateArgument::Type && "Pack contains a non-type");
     assert(P.getAsType().isCanonical() && "Pack contains non-canonical type");
   }
 #endif
 
   llvm::FoldingSetNodeID ID;
-  SubstTemplateTypeParmPackType::Profile(ID, Parm, ArgPack);
+  SubstTemplateTypeParmPackType::Profile(ID, ReplacedDecl, Index, ArgPack);
   void *InsertPos = nullptr;
-  if (SubstTemplateTypeParmPackType *SubstParm
-        = SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos))
+  if (SubstTemplateTypeParmPackType *SubstParm =
+          SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos))
     return QualType(SubstParm, 0);
 
   QualType Canon;
-  if (!Parm->isCanonicalUnqualified()) {
-    Canon = getCanonicalType(QualType(Parm, 0));
-    Canon = getSubstTemplateTypeParmPackType(cast<TemplateTypeParmType>(Canon),
-                                             ArgPack);
+  if (!ReplacedDecl->isCanonicalDecl()) {
+    Canon = getSubstTemplateTypeParmPackType(ReplacedDecl->getCanonicalDecl(),
+                                             Index, ArgPack);
     SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos);
   }
 
-  auto *SubstParm
-    = new (*this, TypeAlignment) SubstTemplateTypeParmPackType(Parm, Canon,
-                                                               ArgPack);
+  auto *SubstParm = new (*this, TypeAlignment)
+      SubstTemplateTypeParmPackType(Canon, ReplacedDecl, Index, ArgPack);
   Types.push_back(SubstParm);
   SubstTemplateTypeParmPackTypes.InsertNode(SubstParm, InsertPos);
   return QualType(SubstParm, 0);
@@ -12777,16 +12773,15 @@
   case Type::SubstTemplateTypeParm: {
     const auto *SX = cast<SubstTemplateTypeParmType>(X),
                *SY = cast<SubstTemplateTypeParmType>(Y);
+    unsigned Index = SX->getIndex();
     auto PackIndex = SX->getPackIndex();
-    if (PackIndex != SY->getPackIndex())
+    if (Index != SY->getIndex() || PackIndex != SY->getPackIndex())
       return QualType();
-
-    const TemplateTypeParmType *PX = SX->getReplacedParameter();
-    if (PX != SY->getReplacedParameter())
+    Decl *CD = ::getCommonDecl(SX->getReplacedDecl(), SY->getReplacedDecl());
+    if (!CD)
       return QualType();
-
-    return Ctx.getSubstTemplateTypeParmType(
-        PX, Ctx.getQualifiedType(Underlying), PackIndex);
+    return Ctx.getSubstTemplateTypeParmType(Ctx.getQualifiedType(Underlying),
+                                            CD, Index, PackIndex);
   }
   case Type::ObjCTypeParam:
     // FIXME: Try to merge these.
Index: clang/include/clang/Sema/Template.h
===================================================================
--- clang/include/clang/Sema/Template.h
+++ clang/include/clang/Sema/Template.h
@@ -74,13 +74,20 @@
   /// template argument list (17) at depth 1.
   class MultiLevelTemplateArgumentList {
     /// The template argument list at a certain template depth
+
     using ArgList = ArrayRef<TemplateArgument>;
-    using ArgListsIterator = SmallVector<ArgList, 4>::iterator;
-    using ConstArgListsIterator = SmallVector<ArgList, 4>::const_iterator;
+    struct ArgumentListLevel {
+      Decl *ReplacedDecl;
+      ArgList Args;
+    };
+    using ContainerType = SmallVector<ArgumentListLevel, 4>;
+
+    using ArgListsIterator = ContainerType::iterator;
+    using ConstArgListsIterator = ContainerType::const_iterator;
 
     /// The template argument lists, stored from the innermost template
     /// argument list (first) to the outermost template argument list (last).
-    SmallVector<ArgList, 4> TemplateArgumentLists;
+    ContainerType TemplateArgumentLists;
 
     /// The number of outer levels of template arguments that are not
     /// being substituted.
@@ -94,9 +101,8 @@
     MultiLevelTemplateArgumentList() = default;
 
     /// Construct a single-level template argument list.
-    explicit
-    MultiLevelTemplateArgumentList(const TemplateArgumentList &TemplateArgs) {
-      addOuterTemplateArguments(&TemplateArgs);
+    explicit MultiLevelTemplateArgumentList(Decl *D, ArgList Args) {
+      addOuterTemplateArguments(D, Args);
     }
 
     void setKind(TemplateSubstitutionKind K) { Kind = K; }
@@ -126,7 +132,7 @@
     // Determine the number of substituted args at 'Depth'.
     unsigned getNumSubsitutedArgs(unsigned Depth) const {
       assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels());
-      return TemplateArgumentLists[getNumLevels() - Depth - 1].size();
+      return TemplateArgumentLists[getNumLevels() - Depth - 1].Args.size();
     }
 
     unsigned getNumRetainedOuterLevels() const {
@@ -146,8 +152,14 @@
     /// Retrieve the template argument at a given depth and index.
     const TemplateArgument &operator()(unsigned Depth, unsigned Index) const {
       assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels());
-      assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].size());
-      return TemplateArgumentLists[getNumLevels() - Depth - 1][Index];
+      assert(Index <
+             TemplateArgumentLists[getNumLevels() - Depth - 1].Args.size());
+      return TemplateArgumentLists[getNumLevels() - Depth - 1].Args[Index];
+    }
+
+    Decl *getReplacedDecl(unsigned Depth) const {
+      assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels());
+      return TemplateArgumentLists[getNumLevels() - Depth - 1].ReplacedDecl;
     }
 
     /// Determine whether there is a non-NULL template argument at the
@@ -160,15 +172,16 @@
       if (Depth < NumRetainedOuterLevels)
         return false;
 
-      if (Index >= TemplateArgumentLists[getNumLevels() - Depth - 1].size())
+      if (Index >=
+          TemplateArgumentLists[getNumLevels() - Depth - 1].Args.size())
         return false;
 
       return !(*this)(Depth, Index).isNull();
     }
 
     bool isAnyArgInstantiationDependent() const {
-      for (ArgList List : TemplateArgumentLists)
-        for (const TemplateArgument &TA : List)
+      for (ArgumentListLevel ListLevel : TemplateArgumentLists)
+        for (const TemplateArgument &TA : ListLevel.Args)
           if (TA.isInstantiationDependent())
             return true;
       return false;
@@ -178,25 +191,34 @@
     void setArgument(unsigned Depth, unsigned Index,
                      TemplateArgument Arg) {
       assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels());
-      assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].size());
-      const_cast<TemplateArgument&>(
-                TemplateArgumentLists[getNumLevels() - Depth - 1][Index])
-        = Arg;
+      assert(Index <
+             TemplateArgumentLists[getNumLevels() - Depth - 1].Args.size());
+      const_cast<TemplateArgument &>(
+          TemplateArgumentLists[getNumLevels() - Depth - 1].Args[Index]) = Arg;
     }
 
-    /// Add a new outermost level to the multi-level template argument
+    /// Add a new outmost level to the multi-level template argument
     /// list.
-    void addOuterTemplateArguments(const TemplateArgumentList *TemplateArgs) {
-      addOuterTemplateArguments(ArgList(TemplateArgs->data(),
-                                        TemplateArgs->size()));
+    void addOuterTemplateArguments(Decl *ReplacedDecl, ArgList Args) {
+      assert(!NumRetainedOuterLevels &&
+             "substituted args outside retained args?");
+      assert(getKind() == TemplateSubstitutionKind::Specialization);
+      assert(ReplacedDecl != nullptr || Args.size() == 0);
+      TemplateArgumentLists.push_back(
+          {ReplacedDecl ? ReplacedDecl->getCanonicalDecl() : nullptr, Args});
     }
 
-    /// Add a new outmost level to the multi-level template argument
-    /// list.
     void addOuterTemplateArguments(ArgList Args) {
       assert(!NumRetainedOuterLevels &&
              "substituted args outside retained args?");
-      TemplateArgumentLists.push_back(Args);
+      assert(getKind() == TemplateSubstitutionKind::Rewrite);
+      TemplateArgumentLists.push_back({nullptr, Args});
+    }
+
+    void addOuterTemplateArguments(llvm::NoneType) {
+      assert(!NumRetainedOuterLevels &&
+             "substituted args outside retained args?");
+      TemplateArgumentLists.push_back({});
     }
 
     /// Replaces the current 'innermost' level with the provided argument list.
@@ -204,7 +226,7 @@
     /// list from the AST, but then add the deduced innermost list.
     void replaceInnermostTemplateArguments(ArgList Args) {
       assert(TemplateArgumentLists.size() > 0 && "Replacing in an empty list?");
-      TemplateArgumentLists[0] = Args;
+      TemplateArgumentLists[0].Args = Args;
     }
 
     /// Add an outermost level that we are not substituting. We have no
@@ -219,11 +241,11 @@
 
     /// Retrieve the innermost template argument list.
     const ArgList &getInnermost() const {
-      return TemplateArgumentLists.front();
+      return TemplateArgumentLists.front().Args;
     }
     /// Retrieve the outermost template argument list.
     const ArgList &getOutermost() const {
-      return TemplateArgumentLists.back();
+      return TemplateArgumentLists.back().Args;
     }
     ArgListsIterator begin() { return TemplateArgumentLists.begin(); }
     ConstArgListsIterator begin() const {
Index: clang/include/clang/AST/TypeProperties.td
===================================================================
--- clang/include/clang/AST/TypeProperties.td
+++ clang/include/clang/AST/TypeProperties.td
@@ -728,21 +728,22 @@
 }
 
 let Class = SubstTemplateTypeParmType in {
-  def : Property<"replacedParameter", QualType> {
-    let Read = [{ QualType(node->getReplacedParameter(), 0) }];
-  }
   def : Property<"replacementType", QualType> {
     let Read = [{ node->getReplacementType() }];
   }
+  def : Property<"replacedDecl", DeclRef> {
+    let Read = [{ node->getReplacedDecl() }];
+  }
+  def : Property<"Index", UInt32> {
+    let Read = [{ node->getIndex() }];
+  }
   def : Property<"PackIndex", Optional<UInt32>> {
     let Read = [{ node->getPackIndex() }];
   }
 
   def : Creator<[{
-    // The call to getCanonicalType here existed in ASTReader.cpp, too.
     return ctx.getSubstTemplateTypeParmType(
-        cast<TemplateTypeParmType>(replacedParameter),
-        ctx.getCanonicalType(replacementType), PackIndex);
+        replacementType, replacedDecl, Index, PackIndex);
   }]>;
 }
 
@@ -761,8 +762,11 @@
 }
 
 let Class = SubstTemplateTypeParmPackType in {
-  def : Property<"replacedParameter", QualType> {
-    let Read = [{ QualType(node->getReplacedParameter(), 0) }];
+  def : Property<"replacedDecl", DeclRef> {
+    let Read = [{ node->getReplacedDecl() }];
+  }
+  def : Property<"Index", UInt32> {
+    let Read = [{ node->getIndex() }];
   }
   def : Property<"replacementPack", TemplateArgument> {
     let Read = [{ node->getArgumentPack() }];
@@ -770,8 +774,7 @@
 
   def : Creator<[{
     return ctx.getSubstTemplateTypeParmPackType(
-                         cast<TemplateTypeParmType>(replacedParameter),
-                        replacementPack);
+                        replacedDecl, Index, replacementPack);
   }]>;
 }
 
Index: clang/include/clang/AST/Type.h
===================================================================
--- clang/include/clang/AST/Type.h
+++ clang/include/clang/AST/Type.h
@@ -1790,16 +1790,37 @@
     unsigned NumArgs;
   };
 
+  class UsingBitfields {
+    friend class UsingType;
+
+    unsigned : NumTypeBits;
+
+    /// True if this UsingType has underlying type different from decl.
+    unsigned hasDifferentUnderlyingType : 1;
+  };
+
+  class TypedefBitfields {
+    friend class TypedefType;
+
+    unsigned : NumTypeBits;
+
+    /// True if this typedef has underlying type different from decl.
+    unsigned hasDifferentUnderlyingType : 1;
+  };
+
   class SubstTemplateTypeParmTypeBitfields {
     friend class SubstTemplateTypeParmType;
 
     unsigned : NumTypeBits;
 
+    // The index of the template parameter this substitution represents.
+    unsigned Index : 16;
+
     /// Represents the index within a pack if this represents a substitution
     /// from a pack expansion.
     /// Positive non-zero number represents the index + 1.
     /// Zero means this is not substituted from an expansion.
-    unsigned PackIndex;
+    unsigned PackIndex : 16;
   };
 
   class SubstTemplateTypeParmPackTypeBitfields {
@@ -1807,14 +1828,14 @@
 
     unsigned : NumTypeBits;
 
+    // The index of the template parameter this substitution represents.
+    unsigned Index : 16;
+
     /// The number of template arguments in \c Arguments, which is
     /// expected to be able to hold at least 1024 according to [implimits].
     /// However as this limit is somewhat easy to hit with template
     /// metaprogramming we'd prefer to keep it as large as possible.
-    /// At the moment it has been left as a non-bitfield since this type
-    /// safely fits in 64 bits as an unsigned, so there is no reason to
-    /// introduce the performance impact of a bitfield.
-    unsigned NumArgs;
+    unsigned NumArgs : 16;
   };
 
   class TemplateSpecializationTypeBitfields {
@@ -4984,26 +5005,25 @@
   friend class ASTContext;
 
   // The original type parameter.
-  const TemplateTypeParmType *Replaced;
+  QualType Replacement;
 
-  SubstTemplateTypeParmType(const TemplateTypeParmType *Param, QualType Canon,
-                            Optional<unsigned> PackIndex)
-      : Type(SubstTemplateTypeParm, Canon, Canon->getDependence()),
-        Replaced(Param) {
-    SubstTemplateTypeParmTypeBits.PackIndex = PackIndex ? *PackIndex + 1 : 0;
-  }
+  // The templated entity which owned the substituted type parameter.
+  Decl *ReplacedDecl;
 
-public:
-  /// Gets the template parameter that was substituted for.
-  const TemplateTypeParmType *getReplacedParameter() const {
-    return Replaced;
-  }
+  SubstTemplateTypeParmType(QualType Replacement, Decl *ReplacedDecl,
+                            unsigned Index, Optional<unsigned> PackIndex);
 
+public:
   /// Gets the type that was substituted for the template
   /// parameter.
-  QualType getReplacementType() const {
-    return getCanonicalTypeInternal();
-  }
+  QualType getReplacementType() const { return Replacement; }
+
+  /// Gets the template specialization that was substituted.
+  Decl *getReplacedDecl() const { return ReplacedDecl; }
+
+  const TemplateTypeParmDecl *getReplacedParameter() const;
+
+  unsigned getIndex() const { return SubstTemplateTypeParmTypeBits.Index; }
 
   Optional<unsigned> getPackIndex() const {
     if (SubstTemplateTypeParmTypeBits.PackIndex == 0)
@@ -5015,14 +5035,16 @@
   QualType desugar() const { return getReplacementType(); }
 
   void Profile(llvm::FoldingSetNodeID &ID) {
-    Profile(ID, getReplacedParameter(), getReplacementType(), getPackIndex());
+    Profile(ID, getReplacementType(), getReplacedDecl(), getIndex(),
+            getPackIndex());
   }
 
-  static void Profile(llvm::FoldingSetNodeID &ID,
-                      const TemplateTypeParmType *Replaced,
-                      QualType Replacement, Optional<unsigned> PackIndex) {
-    ID.AddPointer(Replaced);
+  static void Profile(llvm::FoldingSetNodeID &ID, QualType Replacement,
+                      const Decl *ReplacedDecl, unsigned Index,
+                      Optional<unsigned> PackIndex) {
+    ID.AddPointer(ReplacedDecl);
     ID.AddPointer(Replacement.getAsOpaquePtr());
+    ID.AddInteger(Index);
     ID.AddInteger(PackIndex ? *PackIndex - 1 : 0);
   }
 
@@ -5046,24 +5068,26 @@
 class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode {
   friend class ASTContext;
 
-  /// The original type parameter.
-  const TemplateTypeParmType *Replaced;
-
   /// A pointer to the set of template arguments that this
   /// parameter pack is instantiated with.
   const TemplateArgument *Arguments;
 
-  SubstTemplateTypeParmPackType(const TemplateTypeParmType *Param,
-                                QualType Canon,
+  // The template specialization which owned the substituted type parameter.
+  Decl *ReplacedDecl;
+
+  SubstTemplateTypeParmPackType(QualType Canon, Decl *ReplacedDecl,
+                                unsigned Index,
                                 const TemplateArgument &ArgPack);
 
 public:
-  IdentifierInfo *getIdentifier() const { return Replaced->getIdentifier(); }
+  IdentifierInfo *getIdentifier() const;
 
-  /// Gets the template parameter that was substituted for.
-  const TemplateTypeParmType *getReplacedParameter() const {
-    return Replaced;
-  }
+  /// Gets the template specialization that was substituted.
+  Decl *getReplacedDecl() const { return ReplacedDecl; }
+
+  const TemplateTypeParmDecl *getReplacedParameter() const;
+
+  unsigned getIndex() const { return SubstTemplateTypeParmPackTypeBits.Index; }
 
   unsigned getNumArgs() const {
     return SubstTemplateTypeParmPackTypeBits.NumArgs;
@@ -5075,9 +5099,8 @@
   TemplateArgument getArgumentPack() const;
 
   void Profile(llvm::FoldingSetNodeID &ID);
-  static void Profile(llvm::FoldingSetNodeID &ID,
-                      const TemplateTypeParmType *Replaced,
-                      const TemplateArgument &ArgPack);
+  static void Profile(llvm::FoldingSetNodeID &ID, const Decl *ReplacedDecl,
+                      unsigned Index, const TemplateArgument &ArgPack);
 
   static bool classof(const Type *T) {
     return T->getTypeClass() == SubstTemplateTypeParmPack;
Index: clang/include/clang/AST/TextNodeDumper.h
===================================================================
--- clang/include/clang/AST/TextNodeDumper.h
+++ clang/include/clang/AST/TextNodeDumper.h
@@ -318,6 +318,8 @@
   void VisitTagType(const TagType *T);
   void VisitTemplateTypeParmType(const TemplateTypeParmType *T);
   void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T);
+  void
+  VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T);
   void VisitAutoType(const AutoType *T);
   void VisitDeducedTemplateSpecializationType(
       const DeducedTemplateSpecializationType *T);
Index: clang/include/clang/AST/JSONNodeDumper.h
===================================================================
--- clang/include/clang/AST/JSONNodeDumper.h
+++ clang/include/clang/AST/JSONNodeDumper.h
@@ -221,6 +221,8 @@
   void VisitTagType(const TagType *TT);
   void VisitTemplateTypeParmType(const TemplateTypeParmType *TTPT);
   void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *STTPT);
+  void
+  VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T);
   void VisitAutoType(const AutoType *AT);
   void VisitTemplateSpecializationType(const TemplateSpecializationType *TST);
   void VisitInjectedClassNameType(const InjectedClassNameType *ICNT);
Index: clang/include/clang/AST/ASTNodeTraverser.h
===================================================================
--- clang/include/clang/AST/ASTNodeTraverser.h
+++ clang/include/clang/AST/ASTNodeTraverser.h
@@ -389,12 +389,9 @@
   void VisitBTFTagAttributedType(const BTFTagAttributedType *T) {
     Visit(T->getWrappedType());
   }
-  void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) {
-    Visit(T->getReplacedParameter());
-  }
+  void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *) {}
   void
   VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) {
-    Visit(T->getReplacedParameter());
     Visit(T->getArgumentPack());
   }
   void VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
Index: clang/include/clang/AST/ASTContext.h
===================================================================
--- clang/include/clang/AST/ASTContext.h
+++ clang/include/clang/AST/ASTContext.h
@@ -1614,11 +1614,10 @@
   QualType getBTFTagAttributedType(const BTFTypeTagAttr *BTFAttr,
                                    QualType Wrapped);
 
-  QualType getSubstTemplateTypeParmType(const TemplateTypeParmType *Replaced,
-                                        QualType Replacement,
+  QualType getSubstTemplateTypeParmType(QualType Replacement,
+                                        Decl *ReplacedDecl, unsigned Index,
                                         Optional<unsigned> PackIndex) const;
-  QualType getSubstTemplateTypeParmPackType(
-                                          const TemplateTypeParmType *Replaced,
+  QualType getSubstTemplateTypeParmPackType(Decl *ReplacedDecl, unsigned Index,
                                             const TemplateArgument &ArgPack);
 
   QualType
Index: clang-tools-extra/clangd/AST.cpp
===================================================================
--- clang-tools-extra/clangd/AST.cpp
+++ clang-tools-extra/clangd/AST.cpp
@@ -727,8 +727,8 @@
   if (const auto *SubstType = dyn_cast<SubstTemplateTypeParmType>(PlainType)) {
     const auto *ReplacedParameter = SubstType->getReplacedParameter();
     if (ReplacedParameter->isParameterPack()) {
-      return dyn_cast<TemplateTypeParmType>(
-          ReplacedParameter->getCanonicalTypeUnqualified()->getTypePtr());
+      return ReplacedParameter->getTypeForDecl()
+          ->castAs<TemplateTypeParmType>();
     }
   }
   return nullptr;
Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
===================================================================
--- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -191,12 +191,12 @@
           getSubstitutedType(VarType, Context)) {
     if (const SubstTemplateTypeParmType *InitializerTmplType =
             getSubstitutedType(InitializerType, Context)) {
-      return VarTmplType->getReplacedParameter()
-                 ->desugar()
-                 .getCanonicalType() !=
-             InitializerTmplType->getReplacedParameter()
-                 ->desugar()
-                 .getCanonicalType();
+      const TemplateTypeParmDecl *VarTTP = VarTmplType->getReplacedParameter();
+      const TemplateTypeParmDecl *InitTTP =
+          InitializerTmplType->getReplacedParameter();
+      return (VarTTP->getDepth() != InitTTP->getDepth() ||
+              VarTTP->getIndex() != InitTTP->getIndex() ||
+              VarTTP->isParameterPack() != InitTTP->isParameterPack());
     }
   }
   return false;
Index: clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.cpp
+++ clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.cpp
@@ -52,7 +52,7 @@
     diag(BadThrow->getSubExpr()->getBeginLoc(),
          "type %0 is a template instantiation of %1", DiagnosticIDs::Note)
         << BadThrow->getSubExpr()->getType()
-        << Template->getReplacedParameter()->getDecl();
+        << Template->getReplacedParameter();
 
   if (const auto *TypeDecl = Result.Nodes.getNodeAs<NamedDecl>("decl"))
     diag(TypeDecl->getBeginLoc(), "type defined here", DiagnosticIDs::Note);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to