[clang] [clang-tools-extra] Revert "[Clang] Add a builtin that deduplicate types into a pack (#106730)" (PR #154606)

Kazu Hirata via cfe-commits cfe-commits at lists.llvm.org
Wed Aug 20 13:26:53 PDT 2025


https://github.com/kazutakahirata created https://github.com/llvm/llvm-project/pull/154606

This reverts commits 85043c1c146fd5658ad4c5b5138e58994333e645 and
65de318d186c815f43b892aa20b98c50f22ab6fe.

The first commit above triggers the following warnings:

clang/lib/Sema/SemaTemplateVariadic.cpp:1069:22: error: variable
'TST' set but not used [-Werror,-Wunused-but-set-variable]

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp:4148:11:
error: enumeration value 'SubstBuiltinTemplatePack' not handled in
switch [-Werror,-Wswitch]
4148 |   switch (qual_type->getTypeClass()) {
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp:4852:11:
error: enumeration value 'SubstBuiltinTemplatePack' not handled in
switch [-Werror,-Wswitch]
4852 |   switch (qual_type->getTypeClass()) {
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp:5153:11:
error: enumeration value 'SubstBuiltinTemplatePack' not handled in
switch [-Werror,-Wswitch]
5153 |   switch (qual_type->getTypeClass()) {
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~


>From b2738f59a2c98c9e8b85447a8dc84f3ffc2c5815 Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu at google.com>
Date: Wed, 20 Aug 2025 13:03:17 -0700
Subject: [PATCH] Revert "[Clang] Add a builtin that deduplicate types into a
 pack (#106730)"

This reverts commits 85043c1c146fd5658ad4c5b5138e58994333e645 and
65de318d186c815f43b892aa20b98c50f22ab6fe.

The first commit above triggers the following warnings:

clang/lib/Sema/SemaTemplateVariadic.cpp:1069:22: error: variable
'TST' set but not used [-Werror,-Wunused-but-set-variable]

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp:4148:11:
error: enumeration value 'SubstBuiltinTemplatePack' not handled in
switch [-Werror,-Wswitch]
4148 |   switch (qual_type->getTypeClass()) {
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp:4852:11:
error: enumeration value 'SubstBuiltinTemplatePack' not handled in
switch [-Werror,-Wswitch]
4852 |   switch (qual_type->getTypeClass()) {
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp:5153:11:
error: enumeration value 'SubstBuiltinTemplatePack' not handled in
switch [-Werror,-Wswitch]
5153 |   switch (qual_type->getTypeClass()) {
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~
---
 .../clangd/unittests/FindTargetTests.cpp      |   6 -
 clang/docs/LanguageExtensions.rst             |  31 --
 clang/docs/ReleaseNotes.rst                   |  16 -
 clang/include/clang/AST/ASTContext.h          |   3 -
 clang/include/clang/AST/DeclTemplate.h        |   3 -
 clang/include/clang/AST/RecursiveASTVisitor.h |  30 +-
 clang/include/clang/AST/Type.h                |  80 +----
 clang/include/clang/AST/TypeLoc.h             |  22 +-
 clang/include/clang/AST/TypeProperties.td     |  19 +-
 clang/include/clang/Basic/BuiltinTemplates.td |   4 -
 .../clang/Basic/DiagnosticSemaKinds.td        |   7 -
 clang/include/clang/Basic/TypeNodes.td        |   4 +-
 clang/include/clang/Sema/Sema.h               |  18 +-
 clang/include/clang/Sema/SemaInternal.h       |  11 +-
 .../clang/Serialization/TypeBitCodes.def      |   1 -
 clang/lib/AST/ASTContext.cpp                  |  31 +-
 clang/lib/AST/ASTImporter.cpp                 |   8 -
 clang/lib/AST/ASTStructuralEquivalence.cpp    |   8 -
 clang/lib/AST/DeclTemplate.cpp                |  13 +-
 clang/lib/AST/ItaniumMangle.cpp               |  15 -
 clang/lib/AST/MicrosoftMangle.cpp             |   5 -
 clang/lib/AST/Type.cpp                        |  87 ++---
 clang/lib/AST/TypePrinter.cpp                 |  10 -
 clang/lib/Parse/ParseTemplate.cpp             |   2 -
 clang/lib/Sema/SemaConcept.cpp                |  13 +-
 clang/lib/Sema/SemaDeclCXX.cpp                |   3 +-
 clang/lib/Sema/SemaTemplate.cpp               |  57 ----
 clang/lib/Sema/SemaTemplateDeduction.cpp      |  18 +-
 clang/lib/Sema/SemaTemplateInstantiate.cpp    | 177 ++--------
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  52 +--
 clang/lib/Sema/SemaTemplateVariadic.cpp       | 122 +------
 clang/lib/Sema/TreeTransform.h                | 319 ++++++------------
 clang/lib/Serialization/ASTReader.cpp         |   5 -
 clang/lib/Serialization/ASTWriter.cpp         |   6 -
 .../test/Import/builtin-template/Inputs/S.cpp |  10 -
 clang/test/Import/builtin-template/test.cpp   |  12 +-
 clang/test/PCH/dedup_types.cpp                |  20 --
 clang/test/SemaCXX/pr100095.cpp               |   1 +
 .../test/SemaTemplate/dedup-types-builtin.cpp | 226 -------------
 clang/tools/libclang/CIndex.cpp               |   1 -
 40 files changed, 237 insertions(+), 1239 deletions(-)
 delete mode 100644 clang/test/PCH/dedup_types.cpp
 delete mode 100644 clang/test/SemaTemplate/dedup-types-builtin.cpp

diff --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
index f369e1b0341e8..20fd23ed4fcdc 100644
--- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
+++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
@@ -731,12 +731,6 @@ TEST_F(TargetDeclTest, BuiltinTemplates) {
     using type_pack_element = [[__type_pack_element]]<N, Pack...>;
   )cpp";
   EXPECT_DECLS("TemplateSpecializationTypeLoc", );
-
-  Code = R"cpp(
-    template <template <class...> class Templ, class... Types>
-    using dedup_types = Templ<[[__builtin_dedup_pack]]<Types...>...>;
-  )cpp";
-  EXPECT_DECLS("TemplateSpecializationTypeLoc", );
 }
 
 TEST_F(TargetDeclTest, MemberOfTemplate) {
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 1b749ead355c7..3f7b7bb270325 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1829,37 +1829,6 @@ __make_integer_seq
 
 This alias returns ``IntSeq`` instantiated with ``IntSeqT = T``and ``Ints`` being the pack ``0, ..., N - 1``.
 
-__builtin_dedup_pack
---------------------
-
-.. code-block:: c++
-
-  template <class... Ts>
-  using __builtin_dedup_pack = ...;
-
-This alias takes a template parameter pack ``Ts`` and produces a new unexpanded pack containing the unique types
-from ``Ts``, with the order of the first occurrence of each type preserved.
-It is useful in template metaprogramming to normalize type lists.
-
-The resulting pack can be expanded in contexts like template argument lists or base specifiers.
-
-**Example of Use**:
-
-.. code-block:: c++
-
-  template <typename...> struct TypeList;
-
-  // The resulting type is TypeList<int, double, char>
-  template <typename ...ExtraTypes>
-  using MyTypeList = TypeList<__builtin_dedup_pack<int, double, int, char, double, ExtraTypes...>...>;
-
-**Limitations**:
-
-* This builtin can only be used inside a template.
-* The resulting pack is currently only supported for expansion in template argument lists and base specifiers.
-* This builtin cannot be assigned to a template template parameter.
-
-
 Type Trait Primitives
 =====================
 
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index d577192d2791f..338627904e7f9 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -148,22 +148,6 @@ Non-comprehensive list of changes in this release
   correct method to check for these features is to test for the ``__PTRAUTH__``
   macro.
 
-- Added a new builtin, ``__builtin_dedup_pack``, to remove duplicate types from a parameter pack.
-  This feature is particularly useful in template metaprogramming for normalizing type lists.
-  The builtin produces a new, unexpanded parameter pack that can be used in contexts like template
-  argument lists or base specifiers.
-
-  .. code-block:: c++
-
-    template <typename...> struct TypeList;
-
-    // The resulting type is TypeList<int, double, char>
-    using MyTypeList = TypeList<__builtin_dedup_pack<int, double, int, char, double>...>;
-
-  Currently, the use of ``__builtin_dedup_pack`` is limited to template arguments and base
-  specifiers, it also must be used within a template context.
-
-
 New Compiler Flags
 ------------------
 - New option ``-fno-sanitize-annotate-debug-info-traps`` added to disable emitting trap reasons into the debug info when compiling with trapping UBSan (e.g. ``-fsanitize-trap=undefined``).
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 07f4935e06555..7c2566a09665d 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -230,8 +230,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
     SubstTemplateTypeParmTypes;
   mutable llvm::FoldingSet<SubstTemplateTypeParmPackType>
     SubstTemplateTypeParmPackTypes;
-  mutable llvm::FoldingSet<SubstBuiltinTemplatePackType>
-      SubstBuiltinTemplatePackTypes;
   mutable llvm::ContextualFoldingSet<TemplateSpecializationType, ASTContext&>
     TemplateSpecializationTypes;
   mutable llvm::FoldingSet<ParenType> ParenTypes{GeneralTypesLog2InitSize};
@@ -1897,7 +1895,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
   QualType getSubstTemplateTypeParmPackType(Decl *AssociatedDecl,
                                             unsigned Index, bool Final,
                                             const TemplateArgument &ArgPack);
-  QualType getSubstBuiltinTemplatePack(const TemplateArgument &ArgPack);
 
   QualType
   getTemplateTypeParmType(unsigned Depth, unsigned Index,
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index bba72365089f9..f298ed8b2f640 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -1796,10 +1796,7 @@ class BuiltinTemplateDecl : public TemplateDecl {
   }
 
   BuiltinTemplateKind getBuiltinTemplateKind() const { return BTK; }
-
-  bool isPackProducingBuiltinTemplate() const;
 };
-bool isPackProducingBuiltinTemplateName(TemplateName N);
 
 /// Provides information about an explicit instantiation of a variable or class
 /// template.
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 02581c8e73299..248b89200eace 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -492,8 +492,6 @@ template <typename Derived> class RecursiveASTVisitor {
   bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL,
                                           unsigned Count);
   bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL);
-  bool TraverseSubstPackTypeHelper(SubstPackType *T);
-  bool TraverseSubstPackTypeLocHelper(SubstPackTypeLoc TL);
   bool TraverseRecordHelper(RecordDecl *D);
   bool TraverseCXXRecordHelper(CXXRecordDecl *D);
   bool TraverseDeclaratorHelper(DeclaratorDecl *D);
@@ -1140,10 +1138,9 @@ DEF_TRAVERSE_TYPE(TemplateTypeParmType, {})
 DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, {
   TRY_TO(TraverseType(T->getReplacementType()));
 })
-DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType,
-                  { TRY_TO(TraverseSubstPackTypeHelper(T)); })
-DEF_TRAVERSE_TYPE(SubstBuiltinTemplatePackType,
-                  { TRY_TO(TraverseSubstPackTypeHelper(T)); })
+DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, {
+  TRY_TO(TraverseTemplateArgument(T->getArgumentPack()));
+})
 
 DEF_TRAVERSE_TYPE(AttributedType,
                   { TRY_TO(TraverseType(T->getModifiedType())); })
@@ -1484,26 +1481,9 @@ DEF_TRAVERSE_TYPELOC(TemplateTypeParmType, {})
 DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, {
   TRY_TO(TraverseType(TL.getTypePtr()->getReplacementType()));
 })
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseSubstPackTypeLocHelper(
-    SubstPackTypeLoc TL) {
+DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, {
   TRY_TO(TraverseTemplateArgument(TL.getTypePtr()->getArgumentPack()));
-  return true;
-}
-
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseSubstPackTypeHelper(
-    SubstPackType *T) {
-  TRY_TO(TraverseTemplateArgument(T->getArgumentPack()));
-  return true;
-}
-
-DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType,
-                     { TRY_TO(TraverseSubstPackTypeLocHelper(TL)); })
-
-DEF_TRAVERSE_TYPELOC(SubstBuiltinTemplatePackType,
-                     { TRY_TO(TraverseSubstPackTypeLocHelper(TL)); })
+})
 
 DEF_TRAVERSE_TYPELOC(ParenType, { TRY_TO(TraverseTypeLoc(TL.getInnerLoc())); })
 
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index adf5cb0462154..3c32f7c82a3c1 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -2210,24 +2210,20 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
     unsigned PackIndex : 15;
   };
 
-  class SubstPackTypeBitfields {
-    friend class SubstPackType;
+  class SubstTemplateTypeParmPackTypeBitfields {
     friend class SubstTemplateTypeParmPackType;
 
     LLVM_PREFERRED_TYPE(TypeBitfields)
     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.
     unsigned NumArgs : 16;
-
-    // The index of the template parameter this substitution represents.
-    // Only used by SubstTemplateTypeParmPackType. We keep it in the same
-    // class to avoid dealing with complexities of bitfields that go over
-    // the size of `unsigned`.
-    unsigned SubstTemplTypeParmPackIndex : 16;
   };
 
   class TemplateSpecializationTypeBitfields {
@@ -2344,7 +2340,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
     VectorTypeBitfields VectorTypeBits;
     TemplateTypeParmTypeBitfields TemplateTypeParmTypeBits;
     SubstTemplateTypeParmTypeBitfields SubstTemplateTypeParmTypeBits;
-    SubstPackTypeBitfields SubstPackTypeBits;
+    SubstTemplateTypeParmPackTypeBitfields SubstTemplateTypeParmPackTypeBits;
     TemplateSpecializationTypeBitfields TemplateSpecializationTypeBits;
     DependentTemplateSpecializationTypeBitfields
       DependentTemplateSpecializationTypeBits;
@@ -6996,56 +6992,6 @@ class SubstTemplateTypeParmType final
   }
 };
 
-/// Represents the result of substituting a set of types as a template argument
-/// that needs to be expanded later.
-///
-/// These types are always dependent and produced depending on the situations:
-/// - SubstTemplateTypeParmPack is an expansion that had to be delayed,
-/// - SubstBuiltinTemplatePackType is an expansion from a builtin.
-class SubstPackType : public Type, public llvm::FoldingSetNode {
-  friend class ASTContext;
-
-  /// A pointer to the set of template arguments that this
-  /// parameter pack is instantiated with.
-  const TemplateArgument *Arguments;
-
-protected:
-  SubstPackType(TypeClass Derived, QualType Canon,
-                const TemplateArgument &ArgPack);
-
-public:
-  unsigned getNumArgs() const { return SubstPackTypeBits.NumArgs; }
-
-  TemplateArgument getArgumentPack() const;
-
-  void Profile(llvm::FoldingSetNodeID &ID);
-  static void Profile(llvm::FoldingSetNodeID &ID,
-                      const TemplateArgument &ArgPack);
-
-  static bool classof(const Type *T) {
-    return T->getTypeClass() == SubstTemplateTypeParmPack ||
-           T->getTypeClass() == SubstBuiltinTemplatePack;
-  }
-};
-
-/// Represents the result of substituting a builtin template as a pack.
-class SubstBuiltinTemplatePackType : public SubstPackType {
-  friend class ASTContext;
-
-  SubstBuiltinTemplatePackType(QualType Canon, const TemplateArgument &ArgPack);
-
-public:
-  bool isSugared() const { return false; }
-  QualType desugar() const { return QualType(this, 0); }
-
-  /// Mark that we reuse the Profile. We do not introduce new fields.
-  using SubstPackType::Profile;
-
-  static bool classof(const Type *T) {
-    return T->getTypeClass() == SubstBuiltinTemplatePack;
-  }
-};
-
 /// Represents the result of substituting a set of types for a template
 /// type parameter pack.
 ///
@@ -7058,7 +7004,7 @@ class SubstBuiltinTemplatePackType : public SubstPackType {
 /// that pack expansion (e.g., when all template parameters have corresponding
 /// arguments), this type will be replaced with the \c SubstTemplateTypeParmType
 /// at the current pack substitution index.
-class SubstTemplateTypeParmPackType : public SubstPackType {
+class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode {
   friend class ASTContext;
 
   /// A pointer to the set of template arguments that this
@@ -7084,17 +7030,21 @@ class SubstTemplateTypeParmPackType : public SubstPackType {
 
   /// Returns the index of the replaced parameter in the associated declaration.
   /// This should match the result of `getReplacedParameter()->getIndex()`.
-  unsigned getIndex() const {
-    return SubstPackTypeBits.SubstTemplTypeParmPackIndex;
-  }
+  unsigned getIndex() const { return SubstTemplateTypeParmPackTypeBits.Index; }
 
   // This substitution will be Final, which means the substitution will be fully
   // sugared: it doesn't need to be resugared later.
   bool getFinal() const;
 
+  unsigned getNumArgs() const {
+    return SubstTemplateTypeParmPackTypeBits.NumArgs;
+  }
+
   bool isSugared() const { return false; }
   QualType desugar() const { return QualType(this, 0); }
 
+  TemplateArgument getArgumentPack() const;
+
   void Profile(llvm::FoldingSetNodeID &ID);
   static void Profile(llvm::FoldingSetNodeID &ID, const Decl *AssociatedDecl,
                       unsigned Index, bool Final,
@@ -7329,7 +7279,9 @@ class TemplateSpecializationType : public TypeWithKeyword,
             TemplateSpecializationTypeBits.NumArgs};
   }
 
-  bool isSugared() const;
+  bool isSugared() const {
+    return !isDependentType() || isCurrentInstantiation() || isTypeAlias();
+  }
 
   QualType desugar() const {
     return isTypeAlias() ? getAliasedType() : getCanonicalTypeInternal();
diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h
index 00835f1490eda..6389bdea6d122 100644
--- a/clang/include/clang/AST/TypeLoc.h
+++ b/clang/include/clang/AST/TypeLoc.h
@@ -989,22 +989,12 @@ class SubstTemplateTypeParmTypeLoc :
                                      SubstTemplateTypeParmType> {
 };
 
-/// Abstract type representing delayed type pack expansions.
-class SubstPackTypeLoc
-    : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, SubstPackTypeLoc,
-                                       SubstPackType> {};
-
-/// Wrapper for substituted template type parameters.
-class SubstTemplateTypeParmPackTypeLoc
-    : public InheritingConcreteTypeLoc<SubstPackTypeLoc,
-                                       SubstTemplateTypeParmPackTypeLoc,
-                                       SubstTemplateTypeParmPackType> {};
-
-/// Wrapper for substituted template type parameters.
-class SubstBuiltinTemplatePackTypeLoc
-    : public InheritingConcreteTypeLoc<SubstPackTypeLoc,
-                                       SubstBuiltinTemplatePackTypeLoc,
-                                       SubstBuiltinTemplatePackType> {};
+  /// Wrapper for substituted template type parameters.
+class SubstTemplateTypeParmPackTypeLoc :
+    public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
+                                     SubstTemplateTypeParmPackTypeLoc,
+                                     SubstTemplateTypeParmPackType> {
+};
 
 struct AttributedLocInfo {
   const Attr *TypeAttr;
diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td
index 185a968217f97..388f6dda4a6f0 100644
--- a/clang/include/clang/AST/TypeProperties.td
+++ b/clang/include/clang/AST/TypeProperties.td
@@ -820,12 +820,6 @@ let Class = PackExpansionType in {
   }]>;
 }
 
-let Class = SubstPackType in {
-  def : Property<"replacementPack", TemplateArgument> {
-    let Read = [{ node->getArgumentPack() }];
-  }
-}
-
 let Class = SubstTemplateTypeParmPackType in {
   def : Property<"associatedDecl", DeclRef> {
     let Read = [{ node->getAssociatedDecl() }];
@@ -833,7 +827,12 @@ let Class = SubstTemplateTypeParmPackType in {
   def : Property<"Index", UInt32> {
     let Read = [{ node->getIndex() }];
   }
-  def : Property<"Final", Bool> { let Read = [{ node->getFinal() }]; }
+  def : Property<"Final", Bool> {
+    let Read = [{ node->getFinal() }];
+  }
+  def : Property<"replacementPack", TemplateArgument> {
+    let Read = [{ node->getArgumentPack() }];
+  }
 
   def : Creator<[{
     return ctx.getSubstTemplateTypeParmPackType(
@@ -841,12 +840,6 @@ let Class = SubstTemplateTypeParmPackType in {
   }]>;
 }
 
-let Class = SubstBuiltinTemplatePackType in {
-  def : Creator<[{
-    return ctx.getSubstBuiltinTemplatePack(replacementPack);
-  }]>;
-}
-
 let Class = BuiltinType in {
   def : Property<"kind", BuiltinTypeKind> {
     let Read = [{ node->getKind() }];
diff --git a/clang/include/clang/Basic/BuiltinTemplates.td b/clang/include/clang/Basic/BuiltinTemplates.td
index 504405acbdc78..5b9672b395955 100644
--- a/clang/include/clang/Basic/BuiltinTemplates.td
+++ b/clang/include/clang/Basic/BuiltinTemplates.td
@@ -62,7 +62,3 @@ def __builtin_common_type : CPlusPlusBuiltinTemplate<
 //           typename ...Operands>
 def __hlsl_spirv_type : HLSLBuiltinTemplate<
 [Uint32T, Uint32T, Uint32T, Class<"Operands", /*is_variadic=*/1>]>;
-
-// template <class ...Args>
-def __builtin_dedup_pack
-    : CPlusPlusBuiltinTemplate<[Class<"Args", /*is_variadic=*/1>]>;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f40cac865ade0..24723573cc861 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6074,13 +6074,6 @@ def warn_cxx23_pack_indexing : Warning<
 def err_pack_outside_template : Error<
   "pack declaration outside of template">;
 
-def err_builtin_pack_outside_template
-    : Error<"%0 cannot be used outside of template">;
-
-def err_unsupported_builtin_template_pack_expansion
-    : Error<"expansions of %0 are not supported here. Only expansions in "
-            "template arguments and class bases are supported">;
-
 def err_fold_expression_packs_both_sides : Error<
   "binary fold expression has unexpanded parameter packs in both operands">;
 def err_fold_expression_empty : Error<
diff --git a/clang/include/clang/Basic/TypeNodes.td b/clang/include/clang/Basic/TypeNodes.td
index c8d45dec78816..e4960ec660b90 100644
--- a/clang/include/clang/Basic/TypeNodes.td
+++ b/clang/include/clang/Basic/TypeNodes.td
@@ -97,9 +97,7 @@ def HLSLAttributedResourceType : TypeNode<Type>;
 def HLSLInlineSpirvType : TypeNode<Type>;
 def TemplateTypeParmType : TypeNode<Type>, AlwaysDependent, LeafType;
 def SubstTemplateTypeParmType : TypeNode<Type>, NeverCanonical;
-def SubstPackType : TypeNode<Type, 1>;
-def SubstTemplateTypeParmPackType : TypeNode<SubstPackType>, AlwaysDependent;
-def SubstBuiltinTemplatePackType : TypeNode<SubstPackType>, AlwaysDependent;
+def SubstTemplateTypeParmPackType : TypeNode<Type>, AlwaysDependent;
 def TemplateSpecializationType : TypeNode<Type>, NeverCanonicalUnlessDependent;
 def DeducedType : TypeNode<Type, 1>;
 def AutoType : TypeNode<DeducedType>;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 12112eb1ad225..89d3f61380db1 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -228,9 +228,7 @@ void threadSafetyCleanup(BeforeSet *Cache);
 
 // FIXME: No way to easily map from TemplateTypeParmTypes to
 // TemplateTypeParmDecls, so we have this horrible PointerUnion.
-typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType *, NamedDecl *,
-                                     const TemplateSpecializationType *,
-                                     const SubstBuiltinTemplatePackType *>,
+typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType *, NamedDecl *>,
                   SourceLocation>
     UnexpandedParameterPack;
 
@@ -13499,6 +13497,8 @@ class Sema final : public SemaBase {
     ~ArgPackSubstIndexRAII() { Self.ArgPackSubstIndex = OldSubstIndex; }
   };
 
+  friend class ArgumentPackSubstitutionRAII;
+
   void pushCodeSynthesisContext(CodeSynthesisContext Ctx);
   void popCodeSynthesisContext();
 
@@ -14428,15 +14428,6 @@ class Sema final : public SemaBase {
   static void collectUnexpandedParameterPacks(
       Expr *E, SmallVectorImpl<UnexpandedParameterPack> &Unexpanded);
 
-  /// Invoked when parsing a template argument.
-  ///
-  /// \param Arg the template argument, which may already be invalid.
-  ///
-  /// If it is followed by ellipsis, this function is called before
-  /// `ActOnPackExpansion`.
-  ParsedTemplateArgument
-  ActOnTemplateTemplateArgument(const ParsedTemplateArgument &Arg);
-
   /// Invoked when parsing a template argument followed by an
   /// ellipsis, which creates a pack expansion.
   ///
@@ -14524,8 +14515,7 @@ class Sema final : public SemaBase {
   bool CheckParameterPacksForExpansion(
       SourceLocation EllipsisLoc, SourceRange PatternRange,
       ArrayRef<UnexpandedParameterPack> Unexpanded,
-      const MultiLevelTemplateArgumentList &TemplateArgs,
-      bool FailOnPackProducingTemplates, bool &ShouldExpand,
+      const MultiLevelTemplateArgumentList &TemplateArgs, bool &ShouldExpand,
       bool &RetainExpansion, UnsignedOrNone &NumExpansions);
 
   /// Determine the number of arguments in the given pack expansion
diff --git a/clang/include/clang/Sema/SemaInternal.h b/clang/include/clang/Sema/SemaInternal.h
index 8f6041b5f00e4..f7c67c15379f1 100644
--- a/clang/include/clang/Sema/SemaInternal.h
+++ b/clang/include/clang/Sema/SemaInternal.h
@@ -71,17 +71,12 @@ inline std::pair<unsigned, unsigned> getDepthAndIndex(const NamedDecl *ND) {
 }
 
 /// Retrieve the depth and index of an unexpanded parameter pack.
-/// Returns nullopt when the unexpanded packs do not correspond to template
-/// parameters, e.g. __builtin_dedup_types.
-inline std::optional<std::pair<unsigned, unsigned>>
+inline std::pair<unsigned, unsigned>
 getDepthAndIndex(UnexpandedParameterPack UPP) {
   if (const auto *TTP = dyn_cast<const TemplateTypeParmType *>(UPP.first))
     return std::make_pair(TTP->getDepth(), TTP->getIndex());
-  if (isa<NamedDecl *>(UPP.first))
-    return getDepthAndIndex(cast<NamedDecl *>(UPP.first));
-  assert((isa<const TemplateSpecializationType *,
-              const SubstBuiltinTemplatePackType *>(UPP.first)));
-  return std::nullopt;
+
+  return getDepthAndIndex(cast<NamedDecl *>(UPP.first));
 }
 
 class TypoCorrectionConsumer : public VisibleDeclConsumer {
diff --git a/clang/include/clang/Serialization/TypeBitCodes.def b/clang/include/clang/Serialization/TypeBitCodes.def
index bea15254922c1..8af32db4c0b39 100644
--- a/clang/include/clang/Serialization/TypeBitCodes.def
+++ b/clang/include/clang/Serialization/TypeBitCodes.def
@@ -69,6 +69,5 @@ TYPE_BIT_CODE(ArrayParameter, ARRAY_PARAMETER, 58)
 TYPE_BIT_CODE(HLSLAttributedResource, HLSLRESOURCE_ATTRIBUTED, 59)
 TYPE_BIT_CODE(HLSLInlineSpirv, HLSL_INLINE_SPIRV, 60)
 TYPE_BIT_CODE(PredefinedSugar, PREDEFINED_SUGAR, 61)
-TYPE_BIT_CODE(SubstBuiltinTemplatePack, SUBST_BUILTIN_TEMPLATE_PACK, 62)
 
 #undef TYPE_BIT_CODE
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index bbb957067c4c8..fe0b247c36831 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -4306,7 +4306,6 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
   case Type::DependentTemplateSpecialization:
   case Type::TemplateTypeParm:
   case Type::SubstTemplateTypeParmPack:
-  case Type::SubstBuiltinTemplatePack:
   case Type::Auto:
   case Type::DeducedTemplateSpecialization:
   case Type::PackExpansion:
@@ -5849,6 +5848,7 @@ QualType ASTContext::getSubstTemplateTypeParmType(QualType Replacement,
   return QualType(SubstParm, 0);
 }
 
+/// Retrieve a
 QualType
 ASTContext::getSubstTemplateTypeParmPackType(Decl *AssociatedDecl,
                                              unsigned Index, bool Final,
@@ -5887,34 +5887,6 @@ ASTContext::getSubstTemplateTypeParmPackType(Decl *AssociatedDecl,
   return QualType(SubstParm, 0);
 }
 
-QualType
-ASTContext::getSubstBuiltinTemplatePack(const TemplateArgument &ArgPack) {
-  assert(llvm::all_of(ArgPack.pack_elements(),
-                      [](const auto &P) {
-                        return P.getKind() == TemplateArgument::Type;
-                      }) &&
-         "Pack contains a non-type");
-
-  llvm::FoldingSetNodeID ID;
-  SubstBuiltinTemplatePackType::Profile(ID, ArgPack);
-
-  void *InsertPos = nullptr;
-  if (auto *T =
-          SubstBuiltinTemplatePackTypes.FindNodeOrInsertPos(ID, InsertPos))
-    return QualType(T, 0);
-
-  QualType Canon;
-  TemplateArgument CanonArgPack = getCanonicalTemplateArgument(ArgPack);
-  if (!CanonArgPack.structurallyEquals(ArgPack))
-    Canon = getSubstBuiltinTemplatePack(CanonArgPack);
-
-  auto *PackType = new (*this, alignof(SubstBuiltinTemplatePackType))
-      SubstBuiltinTemplatePackType(Canon, ArgPack);
-  Types.push_back(PackType);
-  SubstBuiltinTemplatePackTypes.InsertNode(PackType, InsertPos);
-  return QualType(PackType, 0);
-}
-
 /// Retrieve the template type parameter type for a template
 /// parameter or parameter pack with the given depth, index, and (optionally)
 /// name.
@@ -14072,7 +14044,6 @@ static QualType getCommonNonSugarTypeNode(const ASTContext &Ctx, const Type *X,
     SUGAR_FREE_TYPE(BitInt)
     SUGAR_FREE_TYPE(ObjCInterface)
     SUGAR_FREE_TYPE(SubstTemplateTypeParmPack)
-    SUGAR_FREE_TYPE(SubstBuiltinTemplatePack)
     SUGAR_FREE_TYPE(UnresolvedUsing)
     SUGAR_FREE_TYPE(HLSLAttributedResource)
     SUGAR_FREE_TYPE(HLSLInlineSpirv)
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 6299efaf6bbfc..315ead9ef0105 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -1842,14 +1842,6 @@ ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmPackType(
       *ReplacedOrErr, T->getIndex(), T->getFinal(), *ToArgumentPack);
 }
 
-ExpectedType ASTNodeImporter::VisitSubstBuiltinTemplatePackType(
-    const SubstBuiltinTemplatePackType *T) {
-  Expected<TemplateArgument> ToArgumentPack = import(T->getArgumentPack());
-  if (!ToArgumentPack)
-    return ToArgumentPack.takeError();
-  return Importer.getToContext().getSubstBuiltinTemplatePack(*ToArgumentPack);
-}
-
 ExpectedType ASTNodeImporter::VisitTemplateSpecializationType(
                                        const TemplateSpecializationType *T) {
   auto ToTemplateOrErr = import(T->getTemplateName());
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp
index 6d83de384ee10..096bc6c8ca5b3 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -1337,14 +1337,6 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
     break;
   }
 
-  case Type::SubstBuiltinTemplatePack: {
-    const auto *Subst1 = cast<SubstBuiltinTemplatePackType>(T1);
-    const auto *Subst2 = cast<SubstBuiltinTemplatePackType>(T2);
-    if (!IsStructurallyEquivalent(Context, Subst1->getArgumentPack(),
-                                  Subst2->getArgumentPack()))
-      return false;
-    break;
-  }
   case Type::SubstTemplateTypeParmPack: {
     const auto *Subst1 = cast<SubstTemplateTypeParmPackType>(T1);
     const auto *Subst2 = cast<SubstTemplateTypeParmPackType>(T2);
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index b91b4670c63a3..8a6fb3391c13f 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -307,9 +307,8 @@ bool TemplateDecl::hasAssociatedConstraints() const {
 bool TemplateDecl::isTypeAlias() const {
   switch (getKind()) {
   case TemplateDecl::TypeAliasTemplate:
-    return true;
   case TemplateDecl::BuiltinTemplate:
-    return !cast<BuiltinTemplateDecl>(this)->isPackProducingBuiltinTemplate();
+    return true;
   default:
     return false;
   };
@@ -1599,16 +1598,6 @@ BuiltinTemplateDecl::BuiltinTemplateDecl(const ASTContext &C, DeclContext *DC,
                    createBuiltinTemplateParameterList(C, DC, BTK)),
       BTK(BTK) {}
 
-bool BuiltinTemplateDecl::isPackProducingBuiltinTemplate() const {
-  return getBuiltinTemplateKind() == clang::BTK__builtin_dedup_pack;
-}
-
-bool clang::isPackProducingBuiltinTemplateName(TemplateName N) {
-  auto *T = dyn_cast_or_null<BuiltinTemplateDecl>(
-      N.getAsTemplateDecl(/*IgnoreDeduced=*/true));
-  return T && T->isPackProducingBuiltinTemplate();
-}
-
 TemplateParamObjectDecl *TemplateParamObjectDecl::Create(const ASTContext &C,
                                                          QualType T,
                                                          const APValue &V) {
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 112678fb2714a..a7380a19e3607 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -2444,13 +2444,6 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
   case Type::CountAttributed:
     llvm_unreachable("type is illegal as a nested name specifier");
 
-  case Type::SubstBuiltinTemplatePack:
-    // FIXME: not clear how to mangle this!
-    // template <class T...> class A {
-    //   template <class U...> void foo(__builtin_dedup_pack<T...>(*)(U) x...);
-    // };
-    Out << "_SUBSTBUILTINPACK_";
-    break;
   case Type::SubstTemplateTypeParmPack:
     // FIXME: not clear how to mangle this!
     // template <class T...> class A {
@@ -3898,14 +3891,6 @@ void CXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T) {
   Out << "_SUBSTPACK_";
 }
 
-void CXXNameMangler::mangleType(const SubstBuiltinTemplatePackType *T) {
-  // FIXME: not clear how to mangle this!
-  // template <class T...> class A {
-  //   template <class U...> void foo(__builtin_dedup_pack<T...>(*)(U) x...);
-  // };
-  Out << "_SUBSTBUILTINPACK_";
-}
-
 // <type> ::= P <type>   # pointer-to
 void CXXNameMangler::mangleType(const PointerType *T) {
   Out << 'P';
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index fc79ab1de24ff..241c7c35fcc83 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -3383,11 +3383,6 @@ void MicrosoftCXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T,
   Error(Range.getBegin(), "substituted parameter pack") << Range;
 }
 
-void MicrosoftCXXNameMangler::mangleType(const SubstBuiltinTemplatePackType *T,
-                                         Qualifiers, SourceRange Range) {
-  Error(Range.getBegin(), "substituted builtin template pack") << Range;
-}
-
 // <type> ::= <pointer-type>
 // <pointer-type> ::= E? <pointer-cvr-qualifiers> <cvr-qualifiers> <type>
 //                       # the E is required for 64-bit non-static pointers
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index a70bc5424009c..5fbf1999ed725 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -4558,45 +4558,17 @@ void SubstTemplateTypeParmType::Profile(llvm::FoldingSetNodeID &ID,
   ID.AddBoolean(Final);
 }
 
-SubstPackType::SubstPackType(TypeClass Derived, QualType Canon,
-                             const TemplateArgument &ArgPack)
-    : Type(Derived, Canon,
-           TypeDependence::DependentInstantiation |
-               TypeDependence::UnexpandedPack),
-      Arguments(ArgPack.pack_begin()) {
-  assert(llvm::all_of(
-             ArgPack.pack_elements(),
-             [](auto &P) { return P.getKind() == TemplateArgument::Type; }) &&
-         "non-type argument to SubstPackType?");
-  SubstPackTypeBits.NumArgs = ArgPack.pack_size();
-}
-
-TemplateArgument SubstPackType::getArgumentPack() const {
-  return TemplateArgument(llvm::ArrayRef(Arguments, getNumArgs()));
-}
-
-void SubstPackType::Profile(llvm::FoldingSetNodeID &ID) {
-  Profile(ID, getArgumentPack());
-}
-
-void SubstPackType::Profile(llvm::FoldingSetNodeID &ID,
-                            const TemplateArgument &ArgPack) {
-  ID.AddInteger(ArgPack.pack_size());
-  for (const auto &P : ArgPack.pack_elements())
-    ID.AddPointer(P.getAsType().getAsOpaquePtr());
-}
-
 SubstTemplateTypeParmPackType::SubstTemplateTypeParmPackType(
     QualType Canon, Decl *AssociatedDecl, unsigned Index, bool Final,
     const TemplateArgument &ArgPack)
-    : SubstPackType(SubstTemplateTypeParmPack, Canon, ArgPack),
+    : Type(SubstTemplateTypeParmPack, Canon,
+           TypeDependence::DependentInstantiation |
+               TypeDependence::UnexpandedPack),
+      Arguments(ArgPack.pack_begin()),
       AssociatedDeclAndFinal(AssociatedDecl, Final) {
+  SubstTemplateTypeParmPackTypeBits.Index = Index;
+  SubstTemplateTypeParmPackTypeBits.NumArgs = ArgPack.pack_size();
   assert(AssociatedDecl != nullptr);
-
-  SubstPackTypeBits.SubstTemplTypeParmPackIndex = Index;
-  assert(getNumArgs() == ArgPack.pack_size() &&
-         "Parent bitfields in SubstPackType were overwritten."
-         "Check NumSubstPackTypeBits.");
 }
 
 Decl *SubstTemplateTypeParmPackType::getAssociatedDecl() const {
@@ -4616,6 +4588,10 @@ IdentifierInfo *SubstTemplateTypeParmPackType::getIdentifier() const {
   return getReplacedParameter()->getIdentifier();
 }
 
+TemplateArgument SubstTemplateTypeParmPackType::getArgumentPack() const {
+  return TemplateArgument(llvm::ArrayRef(Arguments, getNumArgs()));
+}
+
 void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID) {
   Profile(ID, getAssociatedDecl(), getIndex(), getFinal(), getArgumentPack());
 }
@@ -4627,13 +4603,11 @@ void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID,
   ID.AddPointer(AssociatedDecl);
   ID.AddInteger(Index);
   ID.AddBoolean(Final);
-  SubstPackType::Profile(ID, ArgPack);
+  ID.AddInteger(ArgPack.pack_size());
+  for (const auto &P : ArgPack.pack_elements())
+    ID.AddPointer(P.getAsType().getAsOpaquePtr());
 }
 
-SubstBuiltinTemplatePackType::SubstBuiltinTemplatePackType(
-    QualType Canon, const TemplateArgument &ArgPack)
-    : SubstPackType(SubstBuiltinTemplatePack, Canon, ArgPack) {}
-
 bool TemplateSpecializationType::anyDependentTemplateArguments(
     const TemplateArgumentListInfo &Args,
     ArrayRef<TemplateArgument> Converted) {
@@ -4657,28 +4631,18 @@ bool TemplateSpecializationType::anyInstantiationDependentTemplateArguments(
   return false;
 }
 
-static TypeDependence
-getTemplateSpecializationTypeDependence(QualType Underlying, TemplateName T) {
-  TypeDependence D = Underlying.isNull()
-                         ? TypeDependence::DependentInstantiation
-                         : toSemanticDependence(Underlying->getDependence());
-  D |= toTypeDependence(T.getDependence()) & TypeDependence::UnexpandedPack;
-  if (isPackProducingBuiltinTemplateName(T)) {
-    if (Underlying.isNull()) // Dependent, will produce a pack on substitution.
-      D |= TypeDependence::UnexpandedPack;
-    else
-      D |= (Underlying->getDependence() & TypeDependence::UnexpandedPack);
-  }
-  return D;
-}
-
 TemplateSpecializationType::TemplateSpecializationType(
     ElaboratedTypeKeyword Keyword, TemplateName T, bool IsAlias,
     ArrayRef<TemplateArgument> Args, QualType Underlying)
-    : TypeWithKeyword(Keyword, TemplateSpecialization,
-                      Underlying.isNull() ? QualType(this, 0)
-                                          : Underlying.getCanonicalType(),
-                      getTemplateSpecializationTypeDependence(Underlying, T)),
+    : TypeWithKeyword(
+          Keyword, TemplateSpecialization,
+          Underlying.isNull() ? QualType(this, 0)
+                              : Underlying.getCanonicalType(),
+          (Underlying.isNull()
+               ? TypeDependence::DependentInstantiation
+               : toSemanticDependence(Underlying->getDependence())) |
+              (toTypeDependence(T.getDependence()) &
+               TypeDependence::UnexpandedPack)),
       Template(T) {
   TemplateSpecializationTypeBits.NumArgs = Args.size();
   TemplateSpecializationTypeBits.TypeAlias = IsAlias;
@@ -4724,12 +4688,6 @@ QualType TemplateSpecializationType::getAliasedType() const {
   return *reinterpret_cast<const QualType *>(template_arguments().end());
 }
 
-bool clang::TemplateSpecializationType::isSugared() const {
-  return !isDependentType() || isCurrentInstantiation() || isTypeAlias() ||
-         (isPackProducingBuiltinTemplateName(Template) &&
-          isa<SubstBuiltinTemplatePackType>(*getCanonicalTypeInternal()));
-}
-
 void TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
                                          const ASTContext &Ctx) {
   Profile(ID, Template, template_arguments(),
@@ -5145,7 +5103,6 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
   case Type::UnaryTransform:
   case Type::TemplateTypeParm:
   case Type::SubstTemplateTypeParmPack:
-  case Type::SubstBuiltinTemplatePack:
   case Type::DependentName:
   case Type::DependentTemplateSpecialization:
   case Type::Auto:
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 52ff0d5b5771b..85242b69f0679 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -232,7 +232,6 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
     case Type::Enum:
     case Type::TemplateTypeParm:
     case Type::SubstTemplateTypeParmPack:
-    case Type::SubstBuiltinTemplatePack:
     case Type::DeducedTemplateSpecialization:
     case Type::TemplateSpecialization:
     case Type::InjectedClassName:
@@ -1732,15 +1731,6 @@ void TypePrinter::printSubstTemplateTypeParmAfter(
   printAfter(T->getReplacementType(), OS);
 }
 
-void TypePrinter::printSubstBuiltinTemplatePackBefore(
-    const SubstBuiltinTemplatePackType *T, raw_ostream &OS) {
-  IncludeStrongLifetimeRAII Strong(Policy);
-  OS << "type-pack";
-}
-
-void TypePrinter::printSubstBuiltinTemplatePackAfter(
-    const SubstBuiltinTemplatePackType *T, raw_ostream &OS) {}
-
 void TypePrinter::printSubstTemplateTypeParmPackBefore(
                                         const SubstTemplateTypeParmPackType *T,
                                         raw_ostream &OS) {
diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index 74aff0b804057..0c1cd8c2d75c8 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -1310,8 +1310,6 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
     }
   }
 
-  Result = Actions.ActOnTemplateTemplateArgument(Result);
-
   // If this is a pack expansion, build it as such.
   if (EllipsisLoc.isValid() && !Result.isInvalid())
     Result = Actions.ActOnPackExpansion(Result, EllipsisLoc);
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index f114173a42c21..da85959c005fe 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -307,8 +307,7 @@ static UnsignedOrNone EvaluateFoldExpandedConstraintSize(
   UnsignedOrNone NumExpansions = FE->getNumExpansions();
   if (S.CheckParameterPacksForExpansion(
           FE->getEllipsisLoc(), Pattern->getSourceRange(), Unexpanded, MLTAL,
-          /*FailOnPackProducingTemplates=*/true, Expand, RetainExpansion,
-          NumExpansions) ||
+          Expand, RetainExpansion, NumExpansions) ||
       !Expand || RetainExpansion)
     return std::nullopt;
 
@@ -1697,13 +1696,11 @@ bool FoldExpandedConstraint::AreCompatibleForSubsumption(
   Sema::collectUnexpandedParameterPacks(const_cast<Expr *>(B.Pattern), BPacks);
 
   for (const UnexpandedParameterPack &APack : APacks) {
-    auto ADI = getDepthAndIndex(APack);
-    if (!ADI)
-      continue;
-    auto It = llvm::find_if(BPacks, [&](const UnexpandedParameterPack &BPack) {
-      return getDepthAndIndex(BPack) == ADI;
+    std::pair<unsigned, unsigned> DepthAndIndex = getDepthAndIndex(APack);
+    auto it = llvm::find_if(BPacks, [&](const UnexpandedParameterPack &BPack) {
+      return getDepthAndIndex(BPack) == DepthAndIndex;
     });
-    if (It != BPacks.end())
+    if (it != BPacks.end())
       return true;
   }
   return false;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index bb57968830a65..aa7de722c3e94 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -18012,8 +18012,7 @@ DeclResult Sema::ActOnTemplatedFriendTag(
   collectUnexpandedParameterPacks(QualifierLoc, Unexpanded);
   unsigned FriendDeclDepth = TempParamLists.front()->getDepth();
   for (UnexpandedParameterPack &U : Unexpanded) {
-    if (std::optional<std::pair<unsigned, unsigned>> DI = getDepthAndIndex(U);
-        DI && DI->first >= FriendDeclDepth) {
+    if (getDepthAndIndex(U).first >= FriendDeclDepth) {
       auto *ND = dyn_cast<NamedDecl *>(U.first);
       if (!ND)
         ND = cast<const TemplateTypeParmType *>(U.first)->getDecl();
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 764625d24fe48..0edc850ae1b13 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -19,7 +19,6 @@
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/TemplateName.h"
 #include "clang/AST/Type.h"
-#include "clang/AST/TypeOrdering.h"
 #include "clang/AST/TypeVisitor.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/DiagnosticSema.h"
@@ -317,12 +316,6 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
     }
   }
 
-  if (isPackProducingBuiltinTemplateName(Template) &&
-      S->getTemplateParamParent() == nullptr)
-    Diag(Name.getBeginLoc(), diag::err_builtin_pack_outside_template) << TName;
-  // Recover by returning the template, even though we would never be able to
-  // substitute it.
-
   TemplateResult = TemplateTy::make(Template);
   return TemplateKind;
 }
@@ -3484,28 +3477,6 @@ static QualType checkBuiltinTemplateIdType(
 
     return Context.getHLSLInlineSpirvType(Opcode, Size, Alignment, Operands);
   }
-  case BTK__builtin_dedup_pack: {
-    assert(Converted.size() == 1 && "__builtin_dedup_pack should be given "
-                                    "a parameter pack");
-    TemplateArgument Ts = Converted[0];
-    // Delay the computation until we can compute the final result. We choose
-    // not to remove the duplicates upfront before substitution to keep the code
-    // simple.
-    if (Ts.isDependent())
-      return QualType();
-    assert(Ts.getKind() == clang::TemplateArgument::Pack);
-    llvm::SmallVector<TemplateArgument> OutArgs;
-    llvm::SmallDenseSet<QualType> Seen;
-    // Synthesize a new template argument list, removing duplicates.
-    for (auto T : Ts.getPackAsArray()) {
-      assert(T.getKind() == clang::TemplateArgument::Type);
-      if (!Seen.insert(T.getAsType().getCanonicalType()).second)
-        continue;
-      OutArgs.push_back(T);
-    }
-    return Context.getSubstBuiltinTemplatePack(
-        TemplateArgument::CreatePackCopy(Context, OutArgs));
-  }
   }
   llvm_unreachable("unexpected BuiltinTemplateDecl!");
 }
@@ -5868,29 +5839,6 @@ bool Sema::CheckTemplateArgumentList(
       }
     }
 
-    // Check for builtins producing template packs in this context, we do not
-    // support them yet.
-    if (const NonTypeTemplateParmDecl *NTTP =
-            dyn_cast<NonTypeTemplateParmDecl>(*Param);
-        NTTP && NTTP->isPackExpansion()) {
-      auto TL = NTTP->getTypeSourceInfo()
-                    ->getTypeLoc()
-                    .castAs<PackExpansionTypeLoc>();
-      llvm::SmallVector<UnexpandedParameterPack> Unexpanded;
-      collectUnexpandedParameterPacks(TL.getPatternLoc(), Unexpanded);
-      for (const auto &UPP : Unexpanded) {
-        auto *TST = UPP.first.dyn_cast<const TemplateSpecializationType *>();
-        if (!TST)
-          continue;
-        assert(isPackProducingBuiltinTemplateName(TST->getTemplateName()));
-        // Expanding a built-in pack in this context is not yet supported.
-        Diag(TL.getEllipsisLoc(),
-             diag::err_unsupported_builtin_template_pack_expansion)
-            << TST->getTemplateName();
-        return true;
-      }
-    }
-
     if (ArgIdx < NumArgs) {
       TemplateArgumentLoc &ArgLoc = NewArgs[ArgIdx];
       bool NonPackParameter =
@@ -6348,11 +6296,6 @@ bool UnnamedLocalNoLinkageFinder::VisitSubstTemplateTypeParmPackType(
   return false;
 }
 
-bool UnnamedLocalNoLinkageFinder::VisitSubstBuiltinTemplatePackType(
-    const SubstBuiltinTemplatePackType *) {
-  return false;
-}
-
 bool UnnamedLocalNoLinkageFinder::VisitTemplateSpecializationType(
                                             const TemplateSpecializationType*) {
   return false;
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 93983bf6d1607..477f8c7541939 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -710,9 +710,6 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams,
   // If the parameter is an alias template, there is nothing to deduce.
   if (const auto *TD = TNP.getAsTemplateDecl(); TD && TD->isTypeAlias())
     return TemplateDeductionResult::Success;
-  // Pack-producing templates can only be matched after substitution.
-  if (isPackProducingBuiltinTemplateName(TNP))
-    return TemplateDeductionResult::Success;
 
   // Check whether the template argument is a dependent template-id.
   if (isa<TemplateSpecializationType>(A.getCanonicalType())) {
@@ -931,11 +928,7 @@ class PackDeductionScope {
       S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
       for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
         unsigned Depth, Index;
-        if (auto DI = getDepthAndIndex(Unexpanded[I]))
-          std::tie(Depth, Index) = *DI;
-        else
-          continue;
-
+        std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
         if (Depth == Info.getDeducedDepth())
           AddPack(Index);
       }
@@ -943,6 +936,7 @@ class PackDeductionScope {
 
     // Look for unexpanded packs in the pattern.
     Collect(Pattern);
+    assert(!Packs.empty() && "Pack expansion without unexpanded packs?");
 
     unsigned NumNamedPacks = Packs.size();
 
@@ -1864,7 +1858,6 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
 
     case Type::TemplateTypeParm:
     case Type::SubstTemplateTypeParmPack:
-    case Type::SubstBuiltinTemplatePack:
       llvm_unreachable("Type nodes handled above");
 
     case Type::Auto:
@@ -6974,12 +6967,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
       = cast<SubstTemplateTypeParmPackType>(T);
     if (Subst->getReplacedParameter()->getDepth() == Depth)
       Used[Subst->getIndex()] = true;
-    MarkUsedTemplateParameters(Ctx, Subst->getArgumentPack(), OnlyDeduced,
-                               Depth, Used);
-    break;
-  }
-  case Type::SubstBuiltinTemplatePack: {
-    MarkUsedTemplateParameters(Ctx, cast<SubstPackType>(T)->getArgumentPack(),
+    MarkUsedTemplateParameters(Ctx, Subst->getArgumentPack(),
                                OnlyDeduced, Depth, Used);
     break;
   }
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index fe1c5faba9e40..5e8dfd19fd6fa 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1459,7 +1459,6 @@ namespace {
     bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
                                  SourceRange PatternRange,
                                  ArrayRef<UnexpandedParameterPack> Unexpanded,
-                                 bool FailOnPackProducingTemplates,
                                  bool &ShouldExpand, bool &RetainExpansion,
                                  UnsignedOrNone &NumExpansions) {
       if (SemaRef.CurrentInstantiationScope &&
@@ -1473,9 +1472,8 @@ namespace {
       }
 
       return getSema().CheckParameterPacksForExpansion(
-          EllipsisLoc, PatternRange, Unexpanded, TemplateArgs,
-          FailOnPackProducingTemplates, ShouldExpand, RetainExpansion,
-          NumExpansions);
+          EllipsisLoc, PatternRange, Unexpanded, TemplateArgs, ShouldExpand,
+          RetainExpansion, NumExpansions);
     }
 
     void ExpandingFunctionParameterPack(ParmVarDecl *Pack) {
@@ -1517,21 +1515,6 @@ namespace {
       }
     }
 
-    MultiLevelTemplateArgumentList ForgetSubstitution() {
-      MultiLevelTemplateArgumentList New;
-      New.addOuterRetainedLevels(this->TemplateArgs.getNumLevels());
-
-      MultiLevelTemplateArgumentList Old =
-          const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
-      const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs) =
-          std::move(New);
-      return Old;
-    }
-    void RememberSubstitution(MultiLevelTemplateArgumentList Old) {
-      const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs) =
-          std::move(Old);
-    }
-
     TemplateArgument
     getTemplateArgumentPackPatternForRewrite(const TemplateArgument &TA) {
       if (TA.getKind() != TemplateArgument::Pack)
@@ -1714,26 +1697,6 @@ namespace {
       return inherited::TransformTemplateArgument(Input, Output, Uneval);
     }
 
-    using TreeTransform::TransformTemplateSpecializationType;
-    QualType
-    TransformTemplateSpecializationType(TypeLocBuilder &TLB,
-                                        TemplateSpecializationTypeLoc TL) {
-      auto *T = TL.getTypePtr();
-      if (!getSema().ArgPackSubstIndex || !T->isSugared() ||
-          !isPackProducingBuiltinTemplateName(T->getTemplateName()))
-        return TreeTransform::TransformTemplateSpecializationType(TLB, TL);
-      // Look through sugar to get to the SubstBuiltinTemplatePackType that we
-      // need to substitute into.
-
-      // `TransformType` code below will handle picking the element from a pack
-      // with the index `ArgPackSubstIndex`.
-      // FIXME: add ability to represent sugarred type for N-th element of a
-      // builtin pack and produce the sugar here.
-      QualType R = TransformType(T->desugar());
-      TLB.pushTrivial(getSema().getASTContext(), R, TL.getBeginLoc());
-      return R;
-    }
-
     UnsignedOrNone ComputeSizeOfPackExprWithoutSubstitution(
         ArrayRef<TemplateArgument> PackArgs) {
       // Don't do this when rewriting template parameters for CTAD:
@@ -1783,9 +1746,6 @@ namespace {
     TransformSubstTemplateTypeParmPackType(TypeLocBuilder &TLB,
                                            SubstTemplateTypeParmPackTypeLoc TL,
                                            bool SuppressObjCLifetime);
-    QualType
-    TransformSubstBuiltinTemplatePackType(TypeLocBuilder &TLB,
-                                          SubstBuiltinTemplatePackTypeLoc TL);
 
     CXXRecordDecl::LambdaDependencyKind
     ComputeLambdaDependency(LambdaScopeInfo *LSI) {
@@ -2023,7 +1983,6 @@ bool TemplateInstantiator::maybeInstantiateFunctionParameterToScope(
   UnsignedOrNone NumExpansions = OrigNumExpansions;
   if (TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
                               Pattern.getSourceRange(), Unexpanded,
-                              /*FailOnPackProducingTemplates=*/true,
                               ShouldExpand, RetainExpansion, NumExpansions))
     return true;
 
@@ -2760,17 +2719,6 @@ QualType TemplateInstantiator::TransformSubstTemplateTypeParmPackType(
       getPackIndex(Pack), Arg, TL.getNameLoc());
 }
 
-QualType TemplateInstantiator::TransformSubstBuiltinTemplatePackType(
-    TypeLocBuilder &TLB, SubstBuiltinTemplatePackTypeLoc TL) {
-  if (!getSema().ArgPackSubstIndex)
-    return TreeTransform::TransformSubstBuiltinTemplatePackType(TLB, TL);
-  auto &Sema = getSema();
-  TemplateArgument Result = getPackSubstitutedTemplateArgument(
-      Sema, TL.getTypePtr()->getArgumentPack());
-  TLB.pushTrivial(Sema.getASTContext(), Result.getAsType(), TL.getBeginLoc());
-  return Result.getAsType();
-}
-
 static concepts::Requirement::SubstitutionDiagnostic *
 createSubstDiag(Sema &S, TemplateDeductionInfo &Info,
                 Sema::EntityPrinter Printer) {
@@ -3498,72 +3446,6 @@ bool Sema::SubstDefaultArgument(
   return false;
 }
 
-// See TreeTransform::PreparePackForExpansion for the relevant comment.
-// This function implements the same concept for base specifiers.
-static bool
-PreparePackForExpansion(Sema &S, const CXXBaseSpecifier &Base,
-                        const MultiLevelTemplateArgumentList &TemplateArgs,
-                        TypeSourceInfo *&Out, UnexpandedInfo &Info) {
-  SourceRange BaseSourceRange = Base.getSourceRange();
-  SourceLocation BaseEllipsisLoc = Base.getEllipsisLoc();
-  Info.Ellipsis = Base.getEllipsisLoc();
-  auto ComputeInfo = [&S, &TemplateArgs, BaseSourceRange, BaseEllipsisLoc](
-                         TypeSourceInfo *BaseTypeInfo,
-                         bool IsLateExpansionAttempt, UnexpandedInfo &Info) {
-    // This is a pack expansion. See whether we should expand it now, or
-    // wait until later.
-    SmallVector<UnexpandedParameterPack, 2> Unexpanded;
-    S.collectUnexpandedParameterPacks(BaseTypeInfo->getTypeLoc(), Unexpanded);
-    if (IsLateExpansionAttempt) {
-      // Request expansion only when there is an opportunity to expand a pack
-      // that required a substituion first.
-      bool SawPackTypes =
-          llvm::any_of(Unexpanded, [](UnexpandedParameterPack P) {
-            return P.first.dyn_cast<const SubstBuiltinTemplatePackType *>();
-          });
-      if (!SawPackTypes) {
-        Info.Expand = false;
-        return false;
-      }
-    }
-
-    // Determine whether the set of unexpanded parameter packs can and should be
-    // expanded.
-    Info.Expand = false;
-    Info.RetainExpansion = false;
-    Info.NumExpansions = std::nullopt;
-    return S.CheckParameterPacksForExpansion(
-        BaseEllipsisLoc, BaseSourceRange, Unexpanded, TemplateArgs,
-        /*FailOnPackProducingTemplates=*/false, Info.Expand,
-        Info.RetainExpansion, Info.NumExpansions);
-  };
-
-  if (ComputeInfo(Base.getTypeSourceInfo(), false, Info))
-    return true;
-
-  if (Info.Expand) {
-    Out = Base.getTypeSourceInfo();
-    return false;
-  }
-
-  // The resulting base specifier will (still) be a pack expansion.
-  {
-    Sema::ArgPackSubstIndexRAII SubstIndex(S, std::nullopt);
-    Out = S.SubstType(Base.getTypeSourceInfo(), TemplateArgs,
-                      BaseSourceRange.getBegin(), DeclarationName());
-  }
-  if (!Out->getType()->containsUnexpandedParameterPack())
-    return false;
-
-  // Some packs will learn their length after substitution.
-  // We may need to request their expansion.
-  if (ComputeInfo(Out, /*IsLateExpansionAttempt=*/true, Info))
-    return true;
-  if (Info.Expand)
-    Info.ExpandUnderForgetSubstitions = true;
-  return false;
-}
-
 bool
 Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
                           CXXRecordDecl *Pattern,
@@ -3581,37 +3463,47 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
     }
 
     SourceLocation EllipsisLoc;
-    TypeSourceInfo *BaseTypeLoc = nullptr;
+    TypeSourceInfo *BaseTypeLoc;
     if (Base.isPackExpansion()) {
-      UnexpandedInfo Info;
-      if (PreparePackForExpansion(*this, Base, TemplateArgs, BaseTypeLoc,
-                                  Info)) {
+      // This is a pack expansion. See whether we should expand it now, or
+      // wait until later.
+      SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+      collectUnexpandedParameterPacks(Base.getTypeSourceInfo()->getTypeLoc(),
+                                      Unexpanded);
+      bool ShouldExpand = false;
+      bool RetainExpansion = false;
+      UnsignedOrNone NumExpansions = std::nullopt;
+      if (CheckParameterPacksForExpansion(Base.getEllipsisLoc(),
+                                          Base.getSourceRange(),
+                                          Unexpanded,
+                                          TemplateArgs, ShouldExpand,
+                                          RetainExpansion,
+                                          NumExpansions)) {
         Invalid = true;
         continue;
       }
 
       // If we should expand this pack expansion now, do so.
-      MultiLevelTemplateArgumentList EmptyList;
-      const MultiLevelTemplateArgumentList *ArgsForSubst = &TemplateArgs;
-      if (Info.ExpandUnderForgetSubstitions)
-        ArgsForSubst = &EmptyList;
-
-      if (Info.Expand) {
-        for (unsigned I = 0; I != *Info.NumExpansions; ++I) {
+      if (ShouldExpand) {
+        for (unsigned I = 0; I != *NumExpansions; ++I) {
           Sema::ArgPackSubstIndexRAII SubstIndex(*this, I);
 
-          TypeSourceInfo *Expanded =
-              SubstType(BaseTypeLoc, *ArgsForSubst,
-                        Base.getSourceRange().getBegin(), DeclarationName());
-          if (!Expanded) {
+          TypeSourceInfo *BaseTypeLoc = SubstType(Base.getTypeSourceInfo(),
+                                                  TemplateArgs,
+                                              Base.getSourceRange().getBegin(),
+                                                  DeclarationName());
+          if (!BaseTypeLoc) {
             Invalid = true;
             continue;
           }
 
-          if (CXXBaseSpecifier *InstantiatedBase = CheckBaseSpecifier(
-                  Instantiation, Base.getSourceRange(), Base.isVirtual(),
-                  Base.getAccessSpecifierAsWritten(), Expanded,
-                  SourceLocation()))
+          if (CXXBaseSpecifier *InstantiatedBase
+                = CheckBaseSpecifier(Instantiation,
+                                     Base.getSourceRange(),
+                                     Base.isVirtual(),
+                                     Base.getAccessSpecifierAsWritten(),
+                                     BaseTypeLoc,
+                                     SourceLocation()))
             InstantiatedBases.push_back(InstantiatedBase);
           else
             Invalid = true;
@@ -3623,9 +3515,10 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
       // The resulting base specifier will (still) be a pack expansion.
       EllipsisLoc = Base.getEllipsisLoc();
       Sema::ArgPackSubstIndexRAII SubstIndex(*this, std::nullopt);
-      BaseTypeLoc =
-          SubstType(BaseTypeLoc, *ArgsForSubst,
-                    Base.getSourceRange().getBegin(), DeclarationName());
+      BaseTypeLoc = SubstType(Base.getTypeSourceInfo(),
+                              TemplateArgs,
+                              Base.getSourceRange().getBegin(),
+                              DeclarationName());
     } else {
       BaseTypeLoc = SubstType(Base.getTypeSourceInfo(),
                               TemplateArgs,
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 681ee796440f3..6b423ce06523a 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -133,9 +133,8 @@ static void instantiateDependentAlignedAttr(
   // FIXME: Use the actual location of the ellipsis.
   SourceLocation EllipsisLoc = Aligned->getLocation();
   if (S.CheckParameterPacksForExpansion(EllipsisLoc, Aligned->getRange(),
-                                        Unexpanded, TemplateArgs,
-                                        /*FailOnPackProducingTemplates=*/true,
-                                        Expand, RetainExpansion, NumExpansions))
+                                        Unexpanded, TemplateArgs, Expand,
+                                        RetainExpansion, NumExpansions))
     return;
 
   if (!Expand) {
@@ -1915,8 +1914,7 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
         UnsignedOrNone NumExpansions = std::nullopt;
         if (SemaRef.CheckParameterPacksForExpansion(
                 D->getEllipsisLoc(), D->getSourceRange(), Unexpanded,
-                TemplateArgs, /*FailOnPackProducingTemplates=*/true,
-                ShouldExpand, RetainExpansion, NumExpansions))
+                TemplateArgs, ShouldExpand, RetainExpansion, NumExpansions))
           return nullptr;
 
         assert(!RetainExpansion &&
@@ -3466,11 +3464,10 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
               cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
                   ->getEllipsisLoc(),
               SourceRange(TC->getConceptNameLoc(),
-                          TC->hasExplicitTemplateArgs()
-                              ? TC->getTemplateArgsAsWritten()->getRAngleLoc()
-                              : TC->getConceptNameInfo().getEndLoc()),
-              Unexpanded, TemplateArgs, /*FailOnPackProducingTemplates=*/true,
-              Expand, RetainExpansion, NumExpanded))
+                          TC->hasExplicitTemplateArgs() ?
+                          TC->getTemplateArgsAsWritten()->getRAngleLoc() :
+                          TC->getConceptNameInfo().getEndLoc()),
+              Unexpanded, TemplateArgs, Expand, RetainExpansion, NumExpanded))
         return nullptr;
     }
   }
@@ -3558,10 +3555,12 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
     UnsignedOrNone OrigNumExpansions =
         Expansion.getTypePtr()->getNumExpansions();
     UnsignedOrNone NumExpansions = OrigNumExpansions;
-    if (SemaRef.CheckParameterPacksForExpansion(
-            Expansion.getEllipsisLoc(), Pattern.getSourceRange(), Unexpanded,
-            TemplateArgs, /*FailOnPackProducingTemplates=*/true, Expand,
-            RetainExpansion, NumExpansions))
+    if (SemaRef.CheckParameterPacksForExpansion(Expansion.getEllipsisLoc(),
+                                                Pattern.getSourceRange(),
+                                                Unexpanded,
+                                                TemplateArgs,
+                                                Expand, RetainExpansion,
+                                                NumExpansions))
       return nullptr;
 
     if (Expand) {
@@ -3727,10 +3726,12 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
     bool Expand = true;
     bool RetainExpansion = false;
     UnsignedOrNone NumExpansions = std::nullopt;
-    if (SemaRef.CheckParameterPacksForExpansion(
-            D->getLocation(), TempParams->getSourceRange(), Unexpanded,
-            TemplateArgs, /*FailOnPackProducingTemplates=*/true, Expand,
-            RetainExpansion, NumExpansions))
+    if (SemaRef.CheckParameterPacksForExpansion(D->getLocation(),
+                                                TempParams->getSourceRange(),
+                                                Unexpanded,
+                                                TemplateArgs,
+                                                Expand, RetainExpansion,
+                                                NumExpansions))
       return nullptr;
 
     if (Expand) {
@@ -4002,9 +4003,8 @@ Decl *TemplateDeclInstantiator::instantiateUnresolvedUsingDecl(
     bool RetainExpansion = false;
     UnsignedOrNone NumExpansions = std::nullopt;
     if (SemaRef.CheckParameterPacksForExpansion(
-            D->getEllipsisLoc(), D->getSourceRange(), Unexpanded, TemplateArgs,
-            /*FailOnPackProducingTemplates=*/true, Expand, RetainExpansion,
-            NumExpansions))
+          D->getEllipsisLoc(), D->getSourceRange(), Unexpanded, TemplateArgs,
+            Expand, RetainExpansion, NumExpansions))
       return nullptr;
 
     // This declaration cannot appear within a function template signature,
@@ -6401,10 +6401,12 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
       bool ShouldExpand = false;
       bool RetainExpansion = false;
       UnsignedOrNone NumExpansions = std::nullopt;
-      if (CheckParameterPacksForExpansion(
-              Init->getEllipsisLoc(), BaseTL.getSourceRange(), Unexpanded,
-              TemplateArgs, /*FailOnPackProducingTemplates=*/true, ShouldExpand,
-              RetainExpansion, NumExpansions)) {
+      if (CheckParameterPacksForExpansion(Init->getEllipsisLoc(),
+                                          BaseTL.getSourceRange(),
+                                          Unexpanded,
+                                          TemplateArgs, ShouldExpand,
+                                          RetainExpansion,
+                                          NumExpansions)) {
         AnyErrors = true;
         New->setInvalidDecl();
         continue;
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index 0f72d6a13ae06..377f2ed3552d3 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -65,41 +65,6 @@ class CollectUnexpandedParameterPacksVisitor
         Unexpanded.push_back({T, Loc});
     }
 
-    bool addUnexpanded(const SubstBuiltinTemplatePackType *T,
-                       SourceLocation Loc = SourceLocation()) {
-      Unexpanded.push_back({T, Loc});
-      return true;
-    }
-
-    bool addUnexpanded(const TemplateSpecializationType *T,
-                       SourceLocation Loc = SourceLocation()) {
-      assert(T->isCanonicalUnqualified() &&
-             isPackProducingBuiltinTemplateName(T->getTemplateName()));
-      Unexpanded.push_back({T, Loc});
-      return true;
-    }
-
-    /// Returns true iff it handled the traversal. On false, the callers must
-    /// traverse themselves.
-    bool
-    TryTraverseSpecializationProducingPacks(const TemplateSpecializationType *T,
-                                            SourceLocation Loc) {
-      if (!isPackProducingBuiltinTemplateName(T->getTemplateName()))
-        return false;
-      // Canonical types are inputs to the initial substitution. Report them and
-      // do not recurse any further.
-      if (T->isCanonicalUnqualified()) {
-        addUnexpanded(T, Loc);
-        return true;
-      }
-      // For sugared types, do not use the default traversal as it would be
-      // looking at (now irrelevant) template arguments. Instead, look at the
-      // result of substitution, it usually contains SubstPackType that needs to
-      // be expanded further.
-      DynamicRecursiveASTVisitor::TraverseType(T->desugar());
-      return true;
-    }
-
   public:
     explicit CollectUnexpandedParameterPacksVisitor(
         SmallVectorImpl<UnexpandedParameterPack> &Unexpanded)
@@ -158,23 +123,6 @@ class CollectUnexpandedParameterPacksVisitor
       return DynamicRecursiveASTVisitor::TraverseTemplateName(Template);
     }
 
-    bool
-    TraverseTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc T,
-                                          bool TraverseQualifier) override {
-      if (TryTraverseSpecializationProducingPacks(T.getTypePtr(),
-                                                  T.getBeginLoc()))
-        return true;
-      return DynamicRecursiveASTVisitor::TraverseTemplateSpecializationTypeLoc(
-          T, TraverseQualifier);
-    }
-
-    bool TraverseTemplateSpecializationType(TemplateSpecializationType *T,
-                                            bool TraverseQualfier) override {
-      if (TryTraverseSpecializationProducingPacks(T, SourceLocation()))
-        return true;
-      return DynamicRecursiveASTVisitor::TraverseTemplateSpecializationType(T);
-    }
-
     /// Suppress traversal into Objective-C container literal
     /// elements that are pack expansions.
     bool TraverseObjCDictionaryLiteral(ObjCDictionaryLiteral *E) override {
@@ -377,14 +325,6 @@ class CollectUnexpandedParameterPacksVisitor
       return DynamicRecursiveASTVisitor::TraverseUnresolvedLookupExpr(E);
     }
 
-    bool TraverseSubstBuiltinTemplatePackType(SubstBuiltinTemplatePackType *T,
-                                              bool TraverseQualifier) override {
-      addUnexpanded(T);
-      // Do not call into base implementation to supress traversal of the
-      // substituted types.
-      return true;
-    }
-
 #ifndef NDEBUG
     bool TraverseFunctionParmPackExpr(FunctionParmPackExpr *) override {
       ContainsIntermediatePacks = true;
@@ -705,23 +645,6 @@ void Sema::collectUnexpandedParameterPacks(
   CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseStmt(E);
 }
 
-ParsedTemplateArgument
-Sema::ActOnTemplateTemplateArgument(const ParsedTemplateArgument &Arg) {
-  if (Arg.isInvalid())
-    return Arg;
-
-  // We do not allow to reference builtin templates that produce multiple
-  // values, they would not have a well-defined semantics outside template
-  // arguments.
-  auto *T = dyn_cast_or_null<BuiltinTemplateDecl>(
-      Arg.getAsTemplate().get().getAsTemplateDecl());
-  if (T && T->isPackProducingBuiltinTemplate())
-    diagnoseMissingTemplateArguments(Arg.getAsTemplate().get(),
-                                     Arg.getNameLoc());
-
-  return Arg;
-}
-
 ParsedTemplateArgument
 Sema::ActOnPackExpansion(const ParsedTemplateArgument &Arg,
                          SourceLocation EllipsisLoc) {
@@ -808,7 +731,7 @@ QualType Sema::CheckPackExpansion(QualType Pattern, SourceRange PatternRange,
   if (!Pattern->containsUnexpandedParameterPack() &&
       !Pattern->getContainedDeducedType()) {
     Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
-        << PatternRange;
+      << PatternRange;
     return QualType();
   }
 
@@ -842,8 +765,7 @@ ExprResult Sema::CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
 bool Sema::CheckParameterPacksForExpansion(
     SourceLocation EllipsisLoc, SourceRange PatternRange,
     ArrayRef<UnexpandedParameterPack> Unexpanded,
-    const MultiLevelTemplateArgumentList &TemplateArgs,
-    bool FailOnPackProducingTemplates, bool &ShouldExpand,
+    const MultiLevelTemplateArgumentList &TemplateArgs, bool &ShouldExpand,
     bool &RetainExpansion, UnsignedOrNone &NumExpansions) {
   ShouldExpand = true;
   RetainExpansion = false;
@@ -859,31 +781,12 @@ bool Sema::CheckParameterPacksForExpansion(
     IdentifierInfo *Name;
     bool IsVarDeclPack = false;
     FunctionParmPackExpr *BindingPack = nullptr;
-    std::optional<unsigned> NumPrecomputedArguments;
 
-    if (auto *TTP = ParmPack.first.dyn_cast<const TemplateTypeParmType *>()) {
+    if (const TemplateTypeParmType *TTP =
+            ParmPack.first.dyn_cast<const TemplateTypeParmType *>()) {
       Depth = TTP->getDepth();
       Index = TTP->getIndex();
       Name = TTP->getIdentifier();
-    } else if (auto *TST =
-                   ParmPack.first
-                       .dyn_cast<const TemplateSpecializationType *>()) {
-      assert(isPackProducingBuiltinTemplateName(TST->getTemplateName()));
-      // Delay expansion, substitution is required to know the size.
-      ShouldExpand = false;
-      if (!FailOnPackProducingTemplates)
-        continue;
-
-      // It is not yet supported in certain contexts.
-      return Diag(PatternRange.getBegin().isValid() ? PatternRange.getBegin()
-                                                    : EllipsisLoc,
-                  diag::err_unsupported_builtin_template_pack_expansion)
-             << TST->getTemplateName();
-    } else if (auto *S =
-                   ParmPack.first
-                       .dyn_cast<const SubstBuiltinTemplatePackType *>()) {
-      Name = nullptr;
-      NumPrecomputedArguments = S->getNumArgs();
     } else {
       NamedDecl *ND = cast<NamedDecl *>(ParmPack.first);
       if (isa<VarDecl>(ND))
@@ -923,8 +826,6 @@ bool Sema::CheckParameterPacksForExpansion(
       }
     } else if (BindingPack) {
       NewPackSize = BindingPack->getNumExpansions();
-    } else if (NumPrecomputedArguments) {
-      NewPackSize = *NumPrecomputedArguments;
     } else {
       // If we don't have a template argument at this depth/index, then we
       // cannot expand the pack expansion. Make a note of this, but we still
@@ -1066,21 +967,6 @@ UnsignedOrNone Sema::getNumArgumentsInExpansionFromUnexpanded(
             Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) {
       Depth = TTP->getDepth();
       Index = TTP->getIndex();
-    } else if (auto *TST =
-                   Unexpanded[I]
-                       .first.dyn_cast<const TemplateSpecializationType *>()) {
-      // This is a dependent pack, we are not ready to expand it yet.
-      assert(isPackProducingBuiltinTemplateName(TST->getTemplateName()));
-      (void)TST;
-      return std::nullopt;
-    } else if (auto *PST =
-                   Unexpanded[I]
-                       .first
-                       .dyn_cast<const SubstBuiltinTemplatePackType *>()) {
-      assert((!Result || *Result == PST->getNumArgs()) &&
-             "inconsistent pack sizes");
-      Result = PST->getNumArgs();
-      continue;
     } else {
       NamedDecl *ND = cast<NamedDecl *>(Unexpanded[I].first);
       if (isa<VarDecl>(ND)) {
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 1d14ead778446..13cc6f1b24792 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -45,7 +45,6 @@
 #include "clang/Sema/SemaOpenMP.h"
 #include "clang/Sema/SemaPseudoObject.h"
 #include "clang/Sema/SemaSYCL.h"
-#include "clang/Sema/Template.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/Support/ErrorHandling.h"
 #include <algorithm>
@@ -56,17 +55,6 @@ using namespace llvm::omp;
 namespace clang {
 using namespace sema;
 
-// This helper class is used to facilitate pack expansion during tree transform.
-struct UnexpandedInfo {
-  SourceLocation Ellipsis;
-  UnsignedOrNone OrigNumExpansions = std::nullopt;
-
-  bool Expand = false;
-  bool RetainExpansion = false;
-  UnsignedOrNone NumExpansions = std::nullopt;
-  bool ExpandUnderForgetSubstitions = false;
-};
-
 /// A semantic tree transformation that allows one to transform one
 /// abstract syntax tree into another.
 ///
@@ -304,7 +292,6 @@ class TreeTransform {
   bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
                                SourceRange PatternRange,
                                ArrayRef<UnexpandedParameterPack> Unexpanded,
-                               bool FailOnPackProducingTemplates,
                                bool &ShouldExpand, bool &RetainExpansion,
                                UnsignedOrNone &NumExpansions) {
     ShouldExpand = false;
@@ -327,27 +314,6 @@ class TreeTransform {
   /// This routine is meant to be overridden by the template instantiator.
   void RememberPartiallySubstitutedPack(TemplateArgument Arg) { }
 
-  /// "Forget" the template substitution to allow transforming the AST without
-  /// any template instantiations. This is used to expand template packs when
-  /// their size is not known in advance (e.g. for builtins that produce type
-  /// packs).
-  MultiLevelTemplateArgumentList ForgetSubstitution() { return {}; }
-  void RememberSubstitution(MultiLevelTemplateArgumentList) {}
-
-private:
-  struct ForgetSubstitutionRAII {
-    Derived &Self;
-    MultiLevelTemplateArgumentList Old;
-
-  public:
-    ForgetSubstitutionRAII(Derived &Self) : Self(Self) {
-      Old = Self.ForgetSubstitution();
-    }
-
-    ~ForgetSubstitutionRAII() { Self.RememberSubstitution(std::move(Old)); }
-  };
-
-public:
   /// Note to the derived class when a function parameter pack is
   /// being expanded.
   void ExpandingFunctionParameterPack(ParmVarDecl *Pack) { }
@@ -694,19 +660,6 @@ class TreeTransform {
                                   TemplateArgumentListInfo &Outputs,
                                   bool Uneval = false);
 
-  /// Checks if the argument pack from \p In will need to be expanded and does
-  /// the necessary prework.
-  /// Whether the expansion is needed is captured in Info.Expand.
-  ///
-  /// - When the expansion is required, \p Out will be a template pattern that
-  ///   would need to be expanded.
-  /// - When the expansion must not happen, \p Out will be a pack that must be
-  ///   returned to the outputs directly.
-  ///
-  /// \return true iff the error occurred
-  bool PreparePackForExpansion(TemplateArgumentLoc In, bool Uneval,
-                               TemplateArgumentLoc &Out, UnexpandedInfo &Info);
-
   /// Fakes up a TemplateArgumentLoc for a given TemplateArgument.
   void InventTemplateArgumentLoc(const TemplateArgument &Arg,
                                  TemplateArgumentLoc &ArgLoc);
@@ -4508,10 +4461,11 @@ bool TreeTransform<Derived>::TransformExprs(Expr *const *Inputs,
       bool RetainExpansion = false;
       UnsignedOrNone OrigNumExpansions = Expansion->getNumExpansions();
       UnsignedOrNone NumExpansions = OrigNumExpansions;
-      if (getDerived().TryExpandParameterPacks(
-              Expansion->getEllipsisLoc(), Pattern->getSourceRange(),
-              Unexpanded, /*FailOnPackProducingTemplates=*/true, Expand,
-              RetainExpansion, NumExpansions))
+      if (getDerived().TryExpandParameterPacks(Expansion->getEllipsisLoc(),
+                                               Pattern->getSourceRange(),
+                                               Unexpanded,
+                                               Expand, RetainExpansion,
+                                               NumExpansions))
         return true;
 
       if (!Expand) {
@@ -5127,30 +5081,60 @@ bool TreeTransform<Derived>::TransformTemplateArguments(
     }
 
     if (In.getArgument().isPackExpansion()) {
-      UnexpandedInfo Info;
-      TemplateArgumentLoc Prepared;
-      if (PreparePackForExpansion(In, Uneval, Prepared, Info))
+      // We have a pack expansion, for which we will be substituting into
+      // the pattern.
+      SourceLocation Ellipsis;
+      UnsignedOrNone OrigNumExpansions = std::nullopt;
+      TemplateArgumentLoc Pattern
+        = getSema().getTemplateArgumentPackExpansionPattern(
+              In, Ellipsis, OrigNumExpansions);
+
+      SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+      getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded);
+      assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
+
+      // Determine whether the set of unexpanded parameter packs can and should
+      // be expanded.
+      bool Expand = true;
+      bool RetainExpansion = false;
+      UnsignedOrNone NumExpansions = OrigNumExpansions;
+      if (getDerived().TryExpandParameterPacks(Ellipsis,
+                                               Pattern.getSourceRange(),
+                                               Unexpanded,
+                                               Expand,
+                                               RetainExpansion,
+                                               NumExpansions))
         return true;
-      if (!Info.Expand) {
-        Outputs.addArgument(Prepared);
+
+      if (!Expand) {
+        // The transform has determined that we should perform a simple
+        // transformation on the pack expansion, producing another pack
+        // expansion.
+        TemplateArgumentLoc OutPattern;
+        Sema::ArgPackSubstIndexRAII SubstIndex(getSema(), std::nullopt);
+        if (getDerived().TransformTemplateArgument(Pattern, OutPattern, Uneval))
+          return true;
+
+        Out = getDerived().RebuildPackExpansion(OutPattern, Ellipsis,
+                                                NumExpansions);
+        if (Out.getArgument().isNull())
+          return true;
+
+        Outputs.addArgument(Out);
         continue;
       }
 
       // The transform has determined that we should perform an elementwise
       // expansion of the pattern. Do so.
-      std::optional<ForgetSubstitutionRAII> ForgetSubst;
-      if (Info.ExpandUnderForgetSubstitions)
-        ForgetSubst.emplace(getDerived());
-      for (unsigned I = 0; I != *Info.NumExpansions; ++I) {
+      for (unsigned I = 0; I != *NumExpansions; ++I) {
         Sema::ArgPackSubstIndexRAII SubstIndex(getSema(), I);
 
-        TemplateArgumentLoc Out;
-        if (getDerived().TransformTemplateArgument(Prepared, Out, Uneval))
+        if (getDerived().TransformTemplateArgument(Pattern, Out, Uneval))
           return true;
 
         if (Out.getArgument().containsUnexpandedParameterPack()) {
-          Out = getDerived().RebuildPackExpansion(Out, Info.Ellipsis,
-                                                  Info.OrigNumExpansions);
+          Out = getDerived().RebuildPackExpansion(Out, Ellipsis,
+                                                  OrigNumExpansions);
           if (Out.getArgument().isNull())
             return true;
         }
@@ -5160,15 +5144,14 @@ bool TreeTransform<Derived>::TransformTemplateArguments(
 
       // If we're supposed to retain a pack expansion, do so by temporarily
       // forgetting the partially-substituted parameter pack.
-      if (Info.RetainExpansion) {
+      if (RetainExpansion) {
         ForgetPartiallySubstitutedPackRAII Forget(getDerived());
 
-        TemplateArgumentLoc Out;
-        if (getDerived().TransformTemplateArgument(Prepared, Out, Uneval))
+        if (getDerived().TransformTemplateArgument(Pattern, Out, Uneval))
           return true;
 
-        Out = getDerived().RebuildPackExpansion(Out, Info.Ellipsis,
-                                                Info.OrigNumExpansions);
+        Out = getDerived().RebuildPackExpansion(Out, Ellipsis,
+                                                OrigNumExpansions);
         if (Out.getArgument().isNull())
           return true;
 
@@ -5189,114 +5172,6 @@ bool TreeTransform<Derived>::TransformTemplateArguments(
 
 }
 
-// FIXME: Find ways to reduce code duplication for pack expansions.
-template <typename Derived>
-bool TreeTransform<Derived>::PreparePackForExpansion(TemplateArgumentLoc In,
-                                                     bool Uneval,
-                                                     TemplateArgumentLoc &Out,
-                                                     UnexpandedInfo &Info) {
-  auto ComputeInfo = [this](TemplateArgumentLoc Arg,
-                            bool IsLateExpansionAttempt, UnexpandedInfo &Info,
-                            TemplateArgumentLoc &Pattern) {
-    assert(Arg.getArgument().isPackExpansion());
-    // We have a pack expansion, for which we will be substituting into the
-    // pattern.
-    Pattern = getSema().getTemplateArgumentPackExpansionPattern(
-        Arg, Info.Ellipsis, Info.OrigNumExpansions);
-    SmallVector<UnexpandedParameterPack, 2> Unexpanded;
-    getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded);
-    if (IsLateExpansionAttempt) {
-      // Request expansion only when there is an opportunity to expand a pack
-      // that required a substituion first.
-      bool SawPackTypes =
-          llvm::any_of(Unexpanded, [](UnexpandedParameterPack P) {
-            return P.first.dyn_cast<const SubstBuiltinTemplatePackType *>();
-          });
-      if (!SawPackTypes) {
-        Info.Expand = false;
-        return false;
-      }
-    }
-    assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
-
-    // Determine whether the set of unexpanded parameter packs can and
-    // should be expanded.
-    Info.Expand = true;
-    Info.RetainExpansion = false;
-    Info.NumExpansions = Info.OrigNumExpansions;
-    return getDerived().TryExpandParameterPacks(
-        Info.Ellipsis, Pattern.getSourceRange(), Unexpanded,
-        /*FailOnPackProducingTemplates=*/false, Info.Expand,
-        Info.RetainExpansion, Info.NumExpansions);
-  };
-
-  TemplateArgumentLoc Pattern;
-  if (ComputeInfo(In, false, Info, Pattern))
-    return true;
-
-  if (Info.Expand) {
-    Out = Pattern;
-    return false;
-  }
-
-  // The transform has determined that we should perform a simple
-  // transformation on the pack expansion, producing another pack
-  // expansion.
-  TemplateArgumentLoc OutPattern;
-  std::optional<Sema::ArgPackSubstIndexRAII> SubstIndex(
-      std::in_place, getSema(), std::nullopt);
-  if (getDerived().TransformTemplateArgument(Pattern, OutPattern, Uneval))
-    return true;
-
-  Out = getDerived().RebuildPackExpansion(OutPattern, Info.Ellipsis,
-                                          Info.NumExpansions);
-  if (Out.getArgument().isNull())
-    return true;
-  SubstIndex.reset();
-
-  if (!OutPattern.getArgument().containsUnexpandedParameterPack())
-    return false;
-
-  // Some packs will learn their length after substitution, e.g.
-  // __builtin_dedup_pack<T,int> has size 1 or 2, depending on the substitution
-  // value of `T`.
-  //
-  // We only expand after we know sizes of all packs, check if this is the case
-  // or not. However, we avoid a full template substitution and only do
-  // expanstions after this point.
-
-  // E.g. when substituting template arguments of tuple with {T -> int} in the
-  // following example:
-  //   template <class T>
-  //   struct TupleWithInt {
-  //     using type = std::tuple<__builtin_dedup_pack<T, int>...>;
-  //   };
-  //   TupleWithInt<int>::type y;
-  // At this point we will see the `__builtin_dedup_pack<int, int>` with a known
-  // lenght and run `ComputeInfo()` to provide the necessary information to our
-  // caller.
-  //
-  // Note that we may still have situations where builtin is not going to be
-  // expanded. For example:
-  //   template <class T>
-  //   struct Foo {
-  //     template <class U> using tuple_with_t =
-  //     std::tuple<__builtin_dedup_pack<T, U, int>...>; using type =
-  //     tuple_with_t<short>;
-  //   }
-  // Because the substitution into `type` happens in dependent context, `type`
-  // will be `tuple<builtin_dedup_pack<T, short, int>...>` after substitution
-  // and the caller will not be able to expand it.
-  ForgetSubstitutionRAII ForgetSubst(getDerived());
-  if (ComputeInfo(Out, true, Info, OutPattern))
-    return true;
-  if (!Info.Expand)
-    return false;
-  Out = OutPattern;
-  Info.ExpandUnderForgetSubstitions = true;
-  return false;
-}
-
 //===----------------------------------------------------------------------===//
 // Type transformation
 //===----------------------------------------------------------------------===//
@@ -6307,10 +6182,12 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(
         if (Unexpanded.size() > 0) {
           OrigNumExpansions = ExpansionTL.getTypePtr()->getNumExpansions();
           NumExpansions = OrigNumExpansions;
-          if (getDerived().TryExpandParameterPacks(
-                  ExpansionTL.getEllipsisLoc(), Pattern.getSourceRange(),
-                  Unexpanded, /*FailOnPackProducingTemplates=*/true,
-                  ShouldExpand, RetainExpansion, NumExpansions)) {
+          if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
+                                                   Pattern.getSourceRange(),
+                                                   Unexpanded,
+                                                   ShouldExpand,
+                                                   RetainExpansion,
+                                                   NumExpansions)) {
             return true;
           }
         } else {
@@ -6416,10 +6293,11 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(
       // Determine whether we should expand the parameter packs.
       bool ShouldExpand = false;
       bool RetainExpansion = false;
-      if (getDerived().TryExpandParameterPacks(
-              Loc, SourceRange(), Unexpanded,
-              /*FailOnPackProducingTemplates=*/true, ShouldExpand,
-              RetainExpansion, NumExpansions)) {
+      if (getDerived().TryExpandParameterPacks(Loc, SourceRange(),
+                                               Unexpanded,
+                                               ShouldExpand,
+                                               RetainExpansion,
+                                               NumExpansions)) {
         return true;
       }
 
@@ -6716,9 +6594,8 @@ bool TreeTransform<Derived>::TransformExceptionSpec(
       // FIXME: Track the location of the ellipsis (and track source location
       // information for the types in the exception specification in general).
       if (getDerived().TryExpandParameterPacks(
-              Loc, SourceRange(), Unexpanded,
-              /*FailOnPackProducingTemplates=*/true, Expand, RetainExpansion,
-              NumExpansions))
+              Loc, SourceRange(), Unexpanded, Expand,
+              RetainExpansion, NumExpansions))
         return true;
 
       if (!Expand) {
@@ -7030,10 +6907,9 @@ TreeTransform<Derived>::TransformPackIndexingType(TypeLocBuilder &TLB,
     bool ShouldExpand = true;
     bool RetainExpansion = false;
     UnsignedOrNone NumExpansions = std::nullopt;
-    if (getDerived().TryExpandParameterPacks(
-            TL.getEllipsisLoc(), SourceRange(), Unexpanded,
-            /*FailOnPackProducingTemplates=*/true, ShouldExpand,
-            RetainExpansion, NumExpansions))
+    if (getDerived().TryExpandParameterPacks(TL.getEllipsisLoc(), SourceRange(),
+                                             Unexpanded, ShouldExpand,
+                                             RetainExpansion, NumExpansions))
       return QualType();
     if (!ShouldExpand) {
       Sema::ArgPackSubstIndexRAII SubstIndex(getSema(), std::nullopt);
@@ -7255,11 +7131,6 @@ QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmType(
   return Result;
 
 }
-template <typename Derived>
-QualType TreeTransform<Derived>::TransformSubstBuiltinTemplatePackType(
-    TypeLocBuilder &TLB, SubstBuiltinTemplatePackTypeLoc TL) {
-  return TransformTypeSpecType(TLB, TL);
-}
 
 template<typename Derived>
 QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmPackType(
@@ -7986,9 +7857,8 @@ TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB,
       bool RetainExpansion = false;
       UnsignedOrNone NumExpansions = PackExpansion->getNumExpansions();
       if (getDerived().TryExpandParameterPacks(
-              PackExpansionLoc.getEllipsisLoc(), PatternLoc.getSourceRange(),
-              Unexpanded, /*FailOnPackProducingTemplates=*/true, Expand,
-              RetainExpansion, NumExpansions))
+            PackExpansionLoc.getEllipsisLoc(), PatternLoc.getSourceRange(),
+            Unexpanded, Expand, RetainExpansion, NumExpansions))
         return QualType();
 
       if (!Expand) {
@@ -14971,10 +14841,11 @@ TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
     UnsignedOrNone OrigNumExpansions =
         ExpansionTL.getTypePtr()->getNumExpansions();
     UnsignedOrNone NumExpansions = OrigNumExpansions;
-    if (getDerived().TryExpandParameterPacks(
-            ExpansionTL.getEllipsisLoc(), PatternTL.getSourceRange(),
-            Unexpanded, /*FailOnPackProducingTemplates=*/true, Expand,
-            RetainExpansion, NumExpansions))
+    if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
+                                             PatternTL.getSourceRange(),
+                                             Unexpanded,
+                                             Expand, RetainExpansion,
+                                             NumExpansions))
       return ExprError();
 
     if (!Expand) {
@@ -15548,8 +15419,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
           ExpansionTL.getTypePtr()->getNumExpansions();
       UnsignedOrNone NumExpansions = OrigNumExpansions;
       if (getDerived().TryExpandParameterPacks(
-              ExpansionTL.getEllipsisLoc(), OldVD->getInit()->getSourceRange(),
-              Unexpanded, /*FailOnPackProducingTemplates=*/true, Expand,
+              ExpansionTL.getEllipsisLoc(),
+              OldVD->getInit()->getSourceRange(), Unexpanded, Expand,
               RetainExpansion, NumExpansions))
         return ExprError();
       assert(!RetainExpansion && "Should not need to retain expansion after a "
@@ -15709,10 +15580,11 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
       bool ShouldExpand = false;
       bool RetainExpansion = false;
       UnsignedOrNone NumExpansions = std::nullopt;
-      if (getDerived().TryExpandParameterPacks(
-              C->getEllipsisLoc(), C->getLocation(), Unexpanded,
-              /*FailOnPackProducingTemplates=*/true, ShouldExpand,
-              RetainExpansion, NumExpansions)) {
+      if (getDerived().TryExpandParameterPacks(C->getEllipsisLoc(),
+                                               C->getLocation(),
+                                               Unexpanded,
+                                               ShouldExpand, RetainExpansion,
+                                               NumExpansions)) {
         Invalid = true;
         continue;
       }
@@ -16226,10 +16098,10 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
     bool ShouldExpand = false;
     bool RetainExpansion = false;
     UnsignedOrNone NumExpansions = std::nullopt;
-    if (getDerived().TryExpandParameterPacks(
-            E->getOperatorLoc(), E->getPackLoc(), Unexpanded,
-            /*FailOnPackProducingTemplates=*/true, ShouldExpand,
-            RetainExpansion, NumExpansions))
+    if (getDerived().TryExpandParameterPacks(E->getOperatorLoc(), E->getPackLoc(),
+                                             Unexpanded,
+                                             ShouldExpand, RetainExpansion,
+                                             NumExpansions))
       return ExprError();
 
     // If we need to expand the pack, build a template argument from it and
@@ -16346,8 +16218,7 @@ TreeTransform<Derived>::TransformPackIndexingExpr(PackIndexingExpr *E) {
                    NumExpansions = std::nullopt;
     if (getDerived().TryExpandParameterPacks(
             E->getEllipsisLoc(), Pattern->getSourceRange(), Unexpanded,
-            /*FailOnPackProducingTemplates=*/true, ShouldExpand,
-            RetainExpansion, NumExpansions))
+            ShouldExpand, RetainExpansion, NumExpansions))
       return true;
     if (!ShouldExpand) {
       Sema::ArgPackSubstIndexRAII SubstIndex(getSema(), std::nullopt);
@@ -16453,10 +16324,11 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
   bool RetainExpansion = false;
   UnsignedOrNone OrigNumExpansions = E->getNumExpansions(),
                  NumExpansions = OrigNumExpansions;
-  if (getDerived().TryExpandParameterPacks(
-          E->getEllipsisLoc(), Pattern->getSourceRange(), Unexpanded,
-          /*FailOnPackProducingTemplates=*/true, Expand, RetainExpansion,
-          NumExpansions))
+  if (getDerived().TryExpandParameterPacks(E->getEllipsisLoc(),
+                                           Pattern->getSourceRange(),
+                                           Unexpanded,
+                                           Expand, RetainExpansion,
+                                           NumExpansions))
     return true;
 
   if (!Expand) {
@@ -16690,10 +16562,9 @@ TreeTransform<Derived>::TransformObjCDictionaryLiteral(
       UnsignedOrNone NumExpansions = OrigNumExpansions;
       SourceRange PatternRange(OrigElement.Key->getBeginLoc(),
                                OrigElement.Value->getEndLoc());
-      if (getDerived().TryExpandParameterPacks(
-              OrigElement.EllipsisLoc, PatternRange, Unexpanded,
-              /*FailOnPackProducingTemplates=*/true, Expand, RetainExpansion,
-              NumExpansions))
+      if (getDerived().TryExpandParameterPacks(OrigElement.EllipsisLoc,
+                                               PatternRange, Unexpanded, Expand,
+                                               RetainExpansion, NumExpansions))
         return ExprError();
 
       if (!Expand) {
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index b3111c3091a44..b38f4944bda76 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -7500,11 +7500,6 @@ void TypeLocReader::VisitSubstTemplateTypeParmPackTypeLoc(
   TL.setNameLoc(readSourceLocation());
 }
 
-void TypeLocReader::VisitSubstBuiltinTemplatePackTypeLoc(
-    SubstBuiltinTemplatePackTypeLoc TL) {
-  TL.setNameLoc(readSourceLocation());
-}
-
 void TypeLocReader::VisitTemplateSpecializationTypeLoc(
                                            TemplateSpecializationTypeLoc TL) {
   SourceLocation ElaboratedKeywordLoc = readSourceLocation();
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 87e462f179ce6..a7327397aa6d7 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -627,11 +627,6 @@ void TypeLocWriter::VisitSubstTemplateTypeParmPackTypeLoc(
   addSourceLocation(TL.getNameLoc());
 }
 
-void TypeLocWriter::VisitSubstBuiltinTemplatePackTypeLoc(
-    SubstBuiltinTemplatePackTypeLoc TL) {
-  addSourceLocation(TL.getNameLoc());
-}
-
 void TypeLocWriter::VisitTemplateSpecializationTypeLoc(
                                            TemplateSpecializationTypeLoc TL) {
   addSourceLocation(TL.getElaboratedKeywordLoc());
@@ -1065,7 +1060,6 @@ void ASTWriter::WriteBlockInfoBlock() {
   RECORD(TYPE_PACK_EXPANSION);
   RECORD(TYPE_ATTRIBUTED);
   RECORD(TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK);
-  RECORD(TYPE_SUBST_BUILTIN_TEMPLATE_PACK);
   RECORD(TYPE_AUTO);
   RECORD(TYPE_UNARY_TRANSFORM);
   RECORD(TYPE_ATOMIC);
diff --git a/clang/test/Import/builtin-template/Inputs/S.cpp b/clang/test/Import/builtin-template/Inputs/S.cpp
index 85c71f61b0220..d5c9a9ae0309d 100644
--- a/clang/test/Import/builtin-template/Inputs/S.cpp
+++ b/clang/test/Import/builtin-template/Inputs/S.cpp
@@ -14,13 +14,3 @@ using TypePackElement = __type_pack_element<i, T...>;
 
 template <int i>
 struct X;
-
-using X0 = X<0>;
-template <int I>
-using SameAsX = X<I>;
-
-template <template <class...> class Templ, class...Types>
-using TypePackDedup = Templ<__builtin_dedup_pack<Types...>...>;
-
-template <class ...Ts>
-struct TypeList {};
diff --git a/clang/test/Import/builtin-template/test.cpp b/clang/test/Import/builtin-template/test.cpp
index a9afbd1b316bf..590efad0c71dc 100644
--- a/clang/test/Import/builtin-template/test.cpp
+++ b/clang/test/Import/builtin-template/test.cpp
@@ -1,11 +1,9 @@
 // RUN: clang-import-test -dump-ast -import %S/Inputs/S.cpp -expression %s -Xcc -DSEQ | FileCheck --check-prefix=CHECK-SEQ %s
 // RUN: clang-import-test -dump-ast -import %S/Inputs/S.cpp -expression %s -Xcc -DPACK | FileCheck --check-prefix=CHECK-PACK %s
-// RUN: clang-import-test -dump-ast -import %S/Inputs/S.cpp -expression %s -Xcc -DDEDUP | FileCheck --check-prefix=CHECK-DEDUP %s
-// RUN: clang-import-test -dump-ast -import %S/Inputs/S.cpp -expression %s -Xcc -DPACK -Xcc -DSEQ -Xcc -DDEDUP | FileCheck --check-prefixes=CHECK-SEQ,CHECK-PACK,CHECK-DEDUP %s
+// RUN: clang-import-test -dump-ast -import %S/Inputs/S.cpp -expression %s -Xcc -DPACK -Xcc -DSEQ | FileCheck --check-prefixes=CHECK-SEQ,CHECK-PACK %s
 
 // CHECK-SEQ:  BuiltinTemplateDecl {{.+}} <<invalid sloc>> <invalid sloc> implicit __make_integer_seq{{$}}
 // CHECK-PACK: BuiltinTemplateDecl {{.+}} <<invalid sloc>> <invalid sloc> implicit __type_pack_element{{$}}
-// CHECK-DEDUP: BuiltinTemplateDecl {{.+}} <<invalid sloc>> <invalid sloc> implicit __builtin_dedup_pack{{$}}
 
 void expr() {
 #ifdef SEQ
@@ -22,12 +20,4 @@ void expr() {
   static_assert(__is_same(TypePackElement<0, X<0>, X<1>>, X<0>), "");
   static_assert(__is_same(TypePackElement<1, X<0>, X<1>>, X<1>), "");
 #endif
-
-#ifdef DEDUP
-  static_assert(__is_same(TypePackDedup<TypeList>, TypeList<>), "");
-  static_assert(__is_same(TypePackDedup<TypeList, int, double, int>, TypeList<int, double>), "");
-  static_assert(!__is_same(TypePackDedup<TypeList, int, double, int>, TypeList<double, int>), "");
-  static_assert(__is_same(TypePackDedup<TypeList, X<0>, X<1>, X<1>, X<2>, X<0>>, TypeList<X<0>, X<1>, X<2>>), "");
-  static_assert(__is_same(TypePackDedup<TypeList, X0, SameAsX<1>, X<1>, X<0>>, TypeList<X<0>,X<1>>), "");
-#endif
 }
diff --git a/clang/test/PCH/dedup_types.cpp b/clang/test/PCH/dedup_types.cpp
deleted file mode 100644
index d4b19b4411169..0000000000000
--- a/clang/test/PCH/dedup_types.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %clang_cc1 -std=c++14 -x c++-header %s -emit-pch -o %t.pch
-// RUN: %clang_cc1 -std=c++14 -x c++ /dev/null -include-pch %t.pch
-
-// RUN: %clang_cc1 -std=c++14 -x c++-header %s -emit-pch -fpch-instantiate-templates -o %t.pch
-// RUN: %clang_cc1 -std=c++14 -x c++ /dev/null -include-pch %t.pch
-
-template <template <class...> class Templ, class...Types>
-using TypePackDedup = Templ<__builtin_dedup_pack<Types...>...>;
-
-template <class ...Ts>
-struct TypeList {};
-
-template <int i>
-struct X {};
-
-void fn1() {
-  TypeList<int, double> l1 = TypePackDedup<TypeList, int, double, int>{};
-  TypeList<> l2 = TypePackDedup<TypeList>{};
-  TypeList<X<0>, X<1>> x1 = TypePackDedup<TypeList, X<0>, X<1>, X<0>, X<1>>{};
-}
diff --git a/clang/test/SemaCXX/pr100095.cpp b/clang/test/SemaCXX/pr100095.cpp
index 9b8c09cb82977..15913fec9d5ae 100644
--- a/clang/test/SemaCXX/pr100095.cpp
+++ b/clang/test/SemaCXX/pr100095.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -std=c++11 %s
+// XFAIL: asserts
 
 template <class> struct Pair;
 template <class...> struct Tuple {
diff --git a/clang/test/SemaTemplate/dedup-types-builtin.cpp b/clang/test/SemaTemplate/dedup-types-builtin.cpp
deleted file mode 100644
index 860754da4d628..0000000000000
--- a/clang/test/SemaTemplate/dedup-types-builtin.cpp
+++ /dev/null
@@ -1,226 +0,0 @@
-// RUN: %clang_cc1 %s -verify
-template <typename...> struct TypeList;
-
-// === Check results of the builtin.
-template <class>
-struct TemplateWrapper {
-  static_assert(__is_same( // expected-error {{static assertion contains an unexpanded parameter pack}}
-    TypeList<__builtin_dedup_pack<int, int*, int, double, float>>,
-    TypeList<int, int*, double, float>));
-};
-
-template <template<typename ...> typename Templ, typename ...Types>
-struct Dependent {
-  using empty_list = Templ<__builtin_dedup_pack<>...>;
-  using same = Templ<__builtin_dedup_pack<Types...>...>;
-  using twice = Templ<__builtin_dedup_pack<Types..., Types...>...>;
-  using dep_only_types = TypeList<__builtin_dedup_pack<Types...>...>;
-  using dep_only_template = Templ<__builtin_dedup_pack<int, double, int>...>;
-};
-
-// Check the reverse condition to make sure we see an error and not accidentally produced dependent expression.
-static_assert(!__is_same(Dependent<TypeList>::empty_list, TypeList<>)); // expected-error {{static assertion failed}}
-static_assert(!__is_same(Dependent<TypeList>::same, TypeList<>)); // expected-error {{static assertion failed}}
-static_assert(!__is_same(Dependent<TypeList>::twice, TypeList<>)); // expected-error {{static assertion failed}}
-static_assert(!__is_same(Dependent<TypeList>::dep_only_types, TypeList<>)); // expected-error {{static assertion failed}}
-static_assert(!__is_same(Dependent<TypeList>::dep_only_template, TypeList<int, double>)); // expected-error {{static assertion failed}}
-static_assert(!__is_same(Dependent<TypeList, int*, double*, int*>::empty_list, TypeList<>)); // expected-error {{static assertion failed}}
-static_assert(!__is_same(Dependent<TypeList, int*, double*, int*>::same, TypeList<int*, double*>)); // expected-error {{static assertion failed}}
-static_assert(!__is_same(Dependent<TypeList, int*, double*, int*>::twice, TypeList<int*, double*>)); // expected-error {{static assertion failed}}
-static_assert(!__is_same(Dependent<TypeList, int*, double*, int*>::dep_only_types, TypeList<int*, double*>)); // expected-error {{static assertion failed}}
-static_assert(!__is_same(Dependent<TypeList, int*, double*, int*>::dep_only_template, TypeList<int, double>)); // expected-error {{static assertion failed}}
-
-
-template <class ...T>
-using Twice = TypeList<T..., T...>;
-
-template <class>
-struct TwiceTemplateWrapper {
-  static_assert(!__is_same(Twice<__builtin_dedup_pack<int, double, int>...>, TypeList<int, double, int, double>)); // expected-error {{static assertion failed}}
-
-};
-template struct TwiceTemplateWrapper<int>; // expected-note {{in instantiation of template class 'TwiceTemplateWrapper<int>' requested here}}
-
-template <int...> struct IntList;
-// Wrong kinds of template arguments.
-template <class> struct IntListTemplateWrapper {
-  IntList<__builtin_dedup_pack<int>...>* wrong_template; // expected-error {{template argument for non-type template parameter must be an expression}}
-                                                         // expected-note at -4 {{template parameter is declared here}}
-  TypeList<__builtin_dedup_pack<1, 2, 3>...>* wrong_template_args; // expected-error  {{template argument for template type parameter must be a type}}
-                                                                    // expected-note@* {{template parameter from hidden source}}
-  __builtin_dedup_pack<> not_enough_args; // expected-error {{data member type contains an unexpanded parameter pack}}
-                                          // expected-note@* {{template declaration from hidden source}}
-  __builtin_dedup_pack missing_template_args; // expected-error {{use of template '__builtin_dedup_pack' requires template arguments}}
-};
-
-// Make sure various canonical / non-canonical type representations do not affect results
-// of the deduplication and the qualifiers do end up creating different types when C++ requires it.
-using Int = int;
-using CInt = const Int;
-using IntArray = Int[10];
-using CIntArray = Int[10];
-using IntPtr = int*;
-using CIntPtr = const int*;
-
-template <class>
-struct Foo {
-  static_assert(
-    !__is_same( // expected-error {{static assertion failed}}
-                // expected-note@* {{in instantiation of template class 'Foo<int>'}}
-      TypeList<__builtin_dedup_pack<
-        Int, int,
-        const int, const Int, CInt, const CInt,
-        IntArray, Int[10], int[10],
-        const IntArray, const int[10], CIntArray, const CIntArray,
-        IntPtr, int*,
-        const IntPtr, int* const,
-        CIntPtr, const int*,
-        const IntPtr*, int*const*,
-        CIntPtr*, const int**,
-        const CIntPtr*, const int* const*
-      >...>,
-      TypeList<int, const int, int[10], const int [10], int*, int* const, const int*, int*const *, const int**, const int*const*>),
-    "");
-};
-
-template struct Foo<int>;
-
-// === Show an error when packs are used in non-template contexts.
-static_assert(!__is_same(TypeList<__builtin_dedup_pack<int>...>, TypeList<int>)); // expected-error {{outside}}
-// Non-dependent uses in template are fine, though.
-template <class T>
-struct NonDepInTemplate {
-  static_assert(!__is_same(TypeList<__builtin_dedup_pack<int>...>, TypeList<int>)); // expected-error {{static assertion failed}}
-};
-template struct NonDepInTemplate<int>; // expected-note {{requested here}}
-
-template <template<class...> class T = __builtin_dedup_pack> // expected-error {{use of template '__builtin_dedup_pack' requires template arguments}}
-                                                             // expected-note@* {{template declaration from hidden source}}
-struct UseAsTemplate;
-template <template<class...> class>
-struct AcceptsTemplateArg;
-template <class>
-struct UseAsTemplateWrapper {
-  AcceptsTemplateArg<__builtin_dedup_pack>* a; // expected-error {{use of template '__builtin_dedup_pack' requires template arguments}}
-                                               // expected-note@* {{template declaration from hidden source}}
-};
-
-// === Check how expansions in various contexts behave.
-// The following cases are not supported yet, should produce an error.
-template <class... T>
-struct DedupBases : __builtin_dedup_pack<T...>... {};
-struct Base1 {
-   int a1;
-};
-struct Base2 {
-   int a2;
-};
-static_assert(DedupBases<Base1, Base1, Base2, Base1, Base2, Base2>{1, 2}.a1 != 1); // expected-error {{static assertion failed}} \
-                                                                                   // expected-note {{}}
-static_assert(DedupBases<Base1, Base1, Base2, Base1, Base2, Base2>{1, 2}.a2 != 2); // expected-error {{static assertion failed}} \
-                                                                                   // expected-note {{}}
-
-template <class ...T>
-constexpr int dedup_params(__builtin_dedup_pack<T...>... as) {
- return (as + ...);
-}
-static_assert(dedup_params<int, int, short, int, short, short>(1, 2)); // expected-error {{no matching function}} \
-                                                                       // expected-note at -3 {{expansions of '__builtin_dedup_pack' are not supported here}}
-
-template <class ...T>
-constexpr int dedup_params_into_type_list(TypeList<__builtin_dedup_pack<T...>...> *, T... as) {
- return (as + ...);
-}
-static_assert(dedup_params_into_type_list(static_cast<TypeList<int,short,long>*>(nullptr), 1, short(1), 1, 1l, 1l) != 5); // expected-error {{static assertion failed}} \
-                                                                                                                          // expected-note {{expression evaluates}}
-
-template <class T, __builtin_dedup_pack<T, int>...> // expected-error 2{{expansions of '__builtin_dedup_pack' are not supported here}}
-struct InTemplateParams {};
-InTemplateParams<int> itp1;
-InTemplateParams<int, 1, 2, 3, 4, 5> itp2;
-
-template <class T>
-struct DeepTemplateParams {
-  template <__builtin_dedup_pack<T, int>...> // expected-error {{expansions of '__builtin_dedup_pack' are not supported here}}
-  struct Templ {};
-};
-DeepTemplateParams<int>::Templ<> dtp1; // expected-note {{requested here}} \
-                                       // expected-error {{no template named 'Templ'}}
-
-
-template <class ...T>
-struct MemInitializers : T... {
-  MemInitializers() : __builtin_dedup_pack<T...>()... {} // expected-error 2{{expansions of '__builtin_dedup_pack' are not supported here.}}
-};
-MemInitializers<> mi1; // expected-note {{in instantiation of member function}}
-MemInitializers<Base1, Base2> mi2; // expected-note {{in instantiation of member function}}
-
-template <class ...T>
-constexpr int dedup_in_expressions() {
- // counts the number of unique Ts.
- return ((1 + __builtin_dedup_pack<T...>()) + ...); // expected-error {{expansions of '__builtin_dedup_pack' are not supported here.}} \
-                                                    // expected-note at +3 {{in instantiation of function template specialization}}
-}
-static_assert(dedup_in_expressions<int, int, short, double, int, short, double, int>() == 3); // expected-error {{not an integral constant expression}}
-
-template <class ...T>
-void in_exception_spec() throw(__builtin_dedup_pack<T...>...); // expected-error{{C++17 does not allow dynamic exception specifications}} \
-                                                               // expected-note {{use 'noexcept}} \
-                                                               // expected-error{{expansions of '__builtin_dedup_pack' are not supported here.}}
-
-void test_in_exception_spec() {
-  in_exception_spec<int, double, int>(); // expected-note {{instantiation of exception specification}}
-}
-
-template <class ...T>
-constexpr bool in_type_trait = __is_trivially_constructible(int, __builtin_dedup_pack<T...>...);  // expected-error{{expansions of '__builtin_dedup_pack' are not supported here.}}
-
-static_assert(in_type_trait<int, int, int>); // expected-note{{in instantiation of variable template specialization}}
-
-template <class ...T>
-struct InFriends {
-  friend __builtin_dedup_pack<T>...; // expected-warning {{variadic 'friend' declarations are a C++2c extension}} \
-                                     // expected-error  2 {{expansions of '__builtin_dedup_pack' are not supported here.}} \
-                                     // expected-note@* 2 {{in instantiation of template class}}
-
-};
-struct Friend1 {};
-struct Friend2 {};
-InFriends<> if1;
-InFriends<Friend1, Friend2> if2;
-
-template <class ...T>
-struct InUsingDecl {
-  using __builtin_dedup_pack<T...>::func...; // expected-error  2 {{expansions of '__builtin_dedup_pack' are not supported here.}}
-};
-struct WithFunc1 { void func(); };
-struct WithFunc2 { void func(int); };
-InUsingDecl<> iu1; // expected-note {{in instantiation of template class}}
-InUsingDecl<WithFunc1, WithFunc2> iu2; // expected-note {{in instantiation of template class}}
-
-// Note: produces parsing errors and does not construct pack indexing.
-// Keep this commented out until the parser supports this.
-//
-// template <class ...T>
-// struct InPackIndexing {
-//
-//   using type = __builtin_dedup_pack<T...>...[0];
-// };
-// static_assert(__is_same(InPackIndexing<int, int>, int));
-
-template <class ...T>
-struct LambdaInitCaptures {
-  static constexpr int test() {
-    [...foos=__builtin_dedup_pack<T...>()]{}; // expected-warning {{initialized lambda pack captures are a C++20 extension}} \
-                                              // expected-error 2{{expansions of '__builtin_dedup_pack' are not supported here.}}
-    return 3;
-  }
-};
-static_assert(LambdaInitCaptures<>::test() == 3); // expected-note {{in instantiation of member function}}
-static_assert(LambdaInitCaptures<int, int, int>::test() == 3); // expected-note {{in instantiation of member function}}
-
-template <class ...T>
-struct alignas(__builtin_dedup_pack<T...>...) AlignAs {}; // expected-error 2{{expansions of '__builtin_dedup_pack' are not supported here.}}
-AlignAs<> aa1; // expected-note {{in instantiation of template class}}
-AlignAs<int, double> aa2; // expected-note {{in instantiation of template class}}
-
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index e1aa9bb0721f8..eb6be2b337519 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -1900,7 +1900,6 @@ DEFAULT_TYPELOC_IMPL(Record, TagType)
 DEFAULT_TYPELOC_IMPL(Enum, TagType)
 DEFAULT_TYPELOC_IMPL(SubstTemplateTypeParm, Type)
 DEFAULT_TYPELOC_IMPL(SubstTemplateTypeParmPack, Type)
-DEFAULT_TYPELOC_IMPL(SubstBuiltinTemplatePack, Type)
 DEFAULT_TYPELOC_IMPL(Auto, Type)
 DEFAULT_TYPELOC_IMPL(BitInt, Type)
 DEFAULT_TYPELOC_IMPL(DependentBitInt, Type)



More information about the cfe-commits mailing list