EricWF created this revision.
EricWF added reviewers: rsmith, aaron.ballman, majnemer.
Herald added a subscriber: klimek.

This patch refactors `UnaryTransformType` into `TransformTraitType` which 
accepts an arbitrary number of input arguments, which is needed to support 
upcoming traits such as `__raw_invocation_type`


https://reviews.llvm.org/D45131

Files:
  include/clang/AST/ASTContext.h
  include/clang/AST/CanonicalType.h
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/AST/Type.h
  include/clang/AST/TypeLoc.h
  include/clang/AST/TypeNodes.def
  include/clang/ASTMatchers/ASTMatchers.h
  include/clang/Basic/DiagnosticCommonKinds.td
  include/clang/Basic/DiagnosticParseKinds.td
  include/clang/Basic/Specifiers.h
  include/clang/Parse/Parser.h
  include/clang/Sema/DeclSpec.h
  include/clang/Sema/Sema.h
  include/clang/Serialization/ASTBitCodes.h
  lib/AST/ASTContext.cpp
  lib/AST/ASTDumper.cpp
  lib/AST/ASTImporter.cpp
  lib/AST/ASTStructuralEquivalence.cpp
  lib/AST/ItaniumMangle.cpp
  lib/AST/MicrosoftMangle.cpp
  lib/AST/Type.cpp
  lib/AST/TypeLoc.cpp
  lib/AST/TypePrinter.cpp
  lib/ASTMatchers/ASTMatchersInternal.cpp
  lib/CodeGen/CGDebugInfo.cpp
  lib/CodeGen/CodeGenFunction.cpp
  lib/Lex/PPMacroExpansion.cpp
  lib/Parse/ParseDecl.cpp
  lib/Parse/ParseDeclCXX.cpp
  lib/Sema/DeclSpec.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaTemplate.cpp
  lib/Sema/SemaTemplateDeduction.cpp
  lib/Sema/SemaTemplateVariadic.cpp
  lib/Sema/SemaType.cpp
  lib/Sema/TreeTransform.h
  lib/Serialization/ASTReader.cpp
  lib/Serialization/ASTWriter.cpp
  test/CodeGenCXX/mangle.cpp
  test/SemaCXX/underlying_type.cpp

Index: test/SemaCXX/underlying_type.cpp
===================================================================
--- test/SemaCXX/underlying_type.cpp
+++ test/SemaCXX/underlying_type.cpp
@@ -10,7 +10,10 @@
 struct is_same_type<T, T> {
   static const bool value = true;
 };
-
+// expected-error@+1 {{C++ requires a type}}
+__underlying_type() x;         // expected-error {{type trait requires 1 argument; have 0 arguments}}
+// expected-error@+1 {{C++ requires a type}}
+__underlying_type(int, int) y; // expected-error {{type trait requires 1 argument; have 2 arguments}}
 __underlying_type(int) a; // expected-error {{only enumeration types}}
 __underlying_type(struct b) c; // expected-error {{only enumeration types}}
 
@@ -26,6 +29,17 @@
 static_assert(is_same_type<char, decltype(h)>::value,
               "h has the wrong type");
 
+template <class... Args>
+struct TestParse {
+  // expected-error@+2 {{type trait requires 1 argument; have 0 arguments}}
+  // expected-error@+1 {{type trait requires 1 argument; have 2 arguments}}
+  using type = __underlying_type(Args...);
+};
+static_assert(is_same_type<TestParse<f>::type, char>::value, "wrong type");
+template struct TestParse<>; // expected-note {{requested here}}
+template struct TestParse<f, f>; // expected-note {{requested here}}
+
+
 template <typename T>
 struct underlying_type {
   typedef __underlying_type(T) type; // expected-error {{only enumeration types}}
Index: test/CodeGenCXX/mangle.cpp
===================================================================
--- test/CodeGenCXX/mangle.cpp
+++ test/CodeGenCXX/mangle.cpp
@@ -1113,6 +1113,7 @@
 // CHECK-LABEL: @_ZN6test552fnINS_1EEEEvT_U3eutS2_
 }
 
+
 namespace test56 {
   struct A { A *operator->(); int n; } a;
   template<int N> void f(decltype(a->n + N)) {}
Index: lib/Serialization/ASTWriter.cpp
===================================================================
--- lib/Serialization/ASTWriter.cpp
+++ lib/Serialization/ASTWriter.cpp
@@ -358,11 +358,14 @@
   Code = TYPE_DECLTYPE;
 }
 
-void ASTTypeWriter::VisitUnaryTransformType(const UnaryTransformType *T) {
-  Record.AddTypeRef(T->getBaseType());
-  Record.AddTypeRef(T->getUnderlyingType());
-  Record.push_back(T->getUTTKind());
-  Code = TYPE_UNARY_TRANSFORM;
+void ASTTypeWriter::VisitTransformTraitType(const TransformTraitType *T) {
+  auto ArgTys = T->getArgs();
+  Record.push_back(ArgTys.size());
+  for (auto Ty : ArgTys)
+    Record.AddTypeRef(Ty);
+  Record.AddTypeRef(T->getTransformedType());
+  Record.push_back(T->getTTKind());
+  Code = TYPE_TRANSFORM_TRAIT;
 }
 
 void ASTTypeWriter::VisitAutoType(const AutoType *T) {
@@ -730,11 +733,14 @@
   Record.AddSourceLocation(TL.getNameLoc());
 }
 
-void TypeLocWriter::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
+void TypeLocWriter::VisitTransformTraitTypeLoc(TransformTraitTypeLoc TL) {
   Record.AddSourceLocation(TL.getKWLoc());
   Record.AddSourceLocation(TL.getLParenLoc());
   Record.AddSourceLocation(TL.getRParenLoc());
-  Record.AddTypeSourceInfo(TL.getUnderlyingTInfo());
+  ArrayRef<TypeSourceInfo *> ArgTInfo = TL.getArgTInfo();
+  Record.push_back(ArgTInfo.size());
+  for (auto *TSI : ArgTInfo)
+    Record.AddTypeSourceInfo(TSI);
 }
 
 void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) {
@@ -1221,7 +1227,7 @@
   RECORD(TYPE_ATTRIBUTED);
   RECORD(TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK);
   RECORD(TYPE_AUTO);
-  RECORD(TYPE_UNARY_TRANSFORM);
+  RECORD(TYPE_TRANSFORM_TRAIT);
   RECORD(TYPE_ATOMIC);
   RECORD(TYPE_DECAYED);
   RECORD(TYPE_ADJUSTED);
Index: lib/Serialization/ASTReader.cpp
===================================================================
--- lib/Serialization/ASTReader.cpp
+++ lib/Serialization/ASTReader.cpp
@@ -6092,11 +6092,15 @@
     return Context.getDecltypeType(ReadExpr(*Loc.F), UnderlyingType);
   }
 
-  case TYPE_UNARY_TRANSFORM: {
-    QualType BaseType = readType(*Loc.F, Record, Idx);
-    QualType UnderlyingType = readType(*Loc.F, Record, Idx);
-    UnaryTransformType::UTTKind UKind = (UnaryTransformType::UTTKind)Record[2];
-    return Context.getUnaryTransformType(BaseType, UnderlyingType, UKind);
+  case TYPE_TRANSFORM_TRAIT: {
+    SmallVector<QualType, 2> ArgTypes;
+    unsigned NumArgs = (unsigned)Record[Idx++];
+    for (unsigned I = 0; I < NumArgs; ++I)
+      ArgTypes.push_back(readType(*Loc.F, Record, Idx));
+    QualType TransformedType = readType(*Loc.F, Record, Idx);
+    TransformTraitType::TTKind TKind =
+        (TransformTraitType::TTKind)Record[Idx++];
+    return Context.getTransformTraitType(ArgTypes, TransformedType, TKind);
   }
 
   case TYPE_AUTO: {
@@ -6578,11 +6582,15 @@
   TL.setNameLoc(ReadSourceLocation());
 }
 
-void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
+void TypeLocReader::VisitTransformTraitTypeLoc(TransformTraitTypeLoc TL) {
   TL.setKWLoc(ReadSourceLocation());
   TL.setLParenLoc(ReadSourceLocation());
   TL.setRParenLoc(ReadSourceLocation());
-  TL.setUnderlyingTInfo(GetTypeSourceInfo());
+  unsigned Size = Record[Idx++];
+  SmallVector<TypeSourceInfo *, 2> ArgTInfo;
+  for (unsigned I = 0; I < Size; ++I)
+    ArgTInfo.push_back(GetTypeSourceInfo());
+  TL.setArgTInfo(ArgTInfo);
 }
 
 void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) {
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -622,6 +622,10 @@
       TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL,
       NestedNameSpecifierLoc QualifierLoc);
 
+  bool TransformTypeSourceListAndExpandPacks(
+      ArrayRef<TypeSourceInfo *> InArgs, bool &ArgChanged,
+      SmallVectorImpl<TypeSourceInfo *> &Args);
+
   /// \brief Transforms the parameters of a function type into the
   /// given vectors.
   ///
@@ -888,9 +892,9 @@
   /// By default, builds a new TypeOfType with the given underlying type.
   QualType RebuildTypeOfType(QualType Underlying);
 
-  /// \brief Build a new unary transform type.
-  QualType RebuildUnaryTransformType(QualType BaseType,
-                                     UnaryTransformType::UTTKind UKind,
+  /// \brief Build a new transform trait type.
+  QualType RebuildTransformTraitType(ArrayRef<QualType> ArgTypes,
+                                     TransformTraitType::TTKind TKind,
                                      SourceLocation Loc);
 
   /// \brief Build a new C++11 decltype type.
@@ -5520,30 +5524,38 @@
   return Result;
 }
 
-template<typename Derived>
-QualType TreeTransform<Derived>::TransformUnaryTransformType(
-                                                            TypeLocBuilder &TLB,
-                                                     UnaryTransformTypeLoc TL) {
+template <typename Derived>
+QualType
+TreeTransform<Derived>::TransformTransformTraitType(TypeLocBuilder &TLB,
+                                                    TransformTraitTypeLoc TL) {
+  bool AnyChanged = false;
+  SmallVector<TypeSourceInfo *, 4> NewTypeArgInfos;
+  if (getDerived().TransformTypeSourceListAndExpandPacks(
+          TL.getArgTInfo(), AnyChanged, NewTypeArgInfos))
+    return QualType();
+
   QualType Result = TL.getType();
-  if (Result->isDependentType()) {
-    const UnaryTransformType *T = TL.getTypePtr();
-    QualType NewBase =
-      getDerived().TransformType(TL.getUnderlyingTInfo())->getType();
-    Result = getDerived().RebuildUnaryTransformType(NewBase,
-                                                    T->getUTTKind(),
+  if (getDerived().AlwaysRebuild() || AnyChanged) {
+    const TransformTraitType *T = TL.getTypePtr();
+    SmallVector<QualType, 2> Args;
+    for (auto *TyInfo : NewTypeArgInfos)
+      Args.push_back(TyInfo->getType());
+    Result = getDerived().RebuildTransformTraitType(Args, T->getTTKind(),
                                                     TL.getKWLoc());
     if (Result.isNull())
       return QualType();
   }
 
-  UnaryTransformTypeLoc NewTL = TLB.push<UnaryTransformTypeLoc>(Result);
+  TransformTraitTypeLoc NewTL = TLB.push<TransformTraitTypeLoc>(Result);
   NewTL.setKWLoc(TL.getKWLoc());
   NewTL.setParensRange(TL.getParensRange());
-  NewTL.setUnderlyingTInfo(TL.getUnderlyingTInfo());
+  for (unsigned I = 0; I < TL.getArgTInfo().size(); ++I)
+    NewTL.setArgInfo(I, NewTypeArgInfos[I]);
+
   return Result;
 }
 
-template<typename Derived>
+template <typename Derived>
 QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB,
                                                    AutoTypeLoc TL) {
   const AutoType *T = TL.getTypePtr();
@@ -6272,90 +6284,9 @@
 
   // Transform type arguments.
   SmallVector<TypeSourceInfo *, 4> NewTypeArgInfos;
-  for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) {
-    TypeSourceInfo *TypeArgInfo = TL.getTypeArgTInfo(i);
-    TypeLoc TypeArgLoc = TypeArgInfo->getTypeLoc();
-    QualType TypeArg = TypeArgInfo->getType();
-    if (auto PackExpansionLoc = TypeArgLoc.getAs<PackExpansionTypeLoc>()) {
-      AnyChanged = true;
-
-      // We have a pack expansion. Instantiate it.
-      const auto *PackExpansion = PackExpansionLoc.getType()
-                                    ->castAs<PackExpansionType>();
-      SmallVector<UnexpandedParameterPack, 2> Unexpanded;
-      SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(),
-                                              Unexpanded);
-      assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
-
-      // Determine whether the set of unexpanded parameter packs can
-      // and should be expanded.
-      TypeLoc PatternLoc = PackExpansionLoc.getPatternLoc();
-      bool Expand = false;
-      bool RetainExpansion = false;
-      Optional<unsigned> NumExpansions = PackExpansion->getNumExpansions();
-      if (getDerived().TryExpandParameterPacks(
-            PackExpansionLoc.getEllipsisLoc(), PatternLoc.getSourceRange(),
-            Unexpanded, Expand, RetainExpansion, NumExpansions))
-        return QualType();
-
-      if (!Expand) {
-        // We can't expand this pack expansion into separate arguments yet;
-        // just substitute into the pattern and create a new pack expansion
-        // type.
-        Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
-
-        TypeLocBuilder TypeArgBuilder;
-        TypeArgBuilder.reserve(PatternLoc.getFullDataSize());
-        QualType NewPatternType = getDerived().TransformType(TypeArgBuilder, 
-                                                             PatternLoc);
-        if (NewPatternType.isNull())
-          return QualType();
-
-        QualType NewExpansionType = SemaRef.Context.getPackExpansionType(
-                                      NewPatternType, NumExpansions);
-        auto NewExpansionLoc = TLB.push<PackExpansionTypeLoc>(NewExpansionType);
-        NewExpansionLoc.setEllipsisLoc(PackExpansionLoc.getEllipsisLoc());
-        NewTypeArgInfos.push_back(
-          TypeArgBuilder.getTypeSourceInfo(SemaRef.Context, NewExpansionType));
-        continue;
-      }
-
-      // Substitute into the pack expansion pattern for each slice of the
-      // pack.
-      for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) {
-        Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), ArgIdx);
-
-        TypeLocBuilder TypeArgBuilder;
-        TypeArgBuilder.reserve(PatternLoc.getFullDataSize());
-
-        QualType NewTypeArg = getDerived().TransformType(TypeArgBuilder,
-                                                         PatternLoc);
-        if (NewTypeArg.isNull())
-          return QualType();
-
-        NewTypeArgInfos.push_back(
-          TypeArgBuilder.getTypeSourceInfo(SemaRef.Context, NewTypeArg));
-      }
-
-      continue;
-    }
-
-    TypeLocBuilder TypeArgBuilder;
-    TypeArgBuilder.reserve(TypeArgLoc.getFullDataSize());
-    QualType NewTypeArg = getDerived().TransformType(TypeArgBuilder, TypeArgLoc);
-    if (NewTypeArg.isNull())
-      return QualType();
-
-    // If nothing changed, just keep the old TypeSourceInfo.
-    if (NewTypeArg == TypeArg) {
-      NewTypeArgInfos.push_back(TypeArgInfo);
-      continue;
-    }
-
-    NewTypeArgInfos.push_back(
-      TypeArgBuilder.getTypeSourceInfo(SemaRef.Context, NewTypeArg));
-    AnyChanged = true;
-  }
+  if (getDerived().TransformTypeSourceListAndExpandPacks(
+          TL.getTypeArgTInfoRef(), AnyChanged, NewTypeArgInfos))
+    return QualType();
 
   QualType Result = TL.getType();
   if (getDerived().AlwaysRebuild() || AnyChanged) {
@@ -10466,20 +10397,19 @@
                                             Old->requiresADL(), &TransArgs);
 }
 
-template<typename Derived>
-ExprResult
-TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
-  bool ArgChanged = false;
-  SmallVector<TypeSourceInfo *, 4> Args;
-  for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) {
-    TypeSourceInfo *From = E->getArg(I);
+template <typename Derived>
+bool TreeTransform<Derived>::TransformTypeSourceListAndExpandPacks(
+    ArrayRef<TypeSourceInfo *> InArgs, bool &ArgChanged,
+    SmallVectorImpl<TypeSourceInfo *> &Args) {
+  for (unsigned I = 0, N = InArgs.size(); I != N; ++I) {
+    TypeSourceInfo *From = InArgs[I];
     TypeLoc FromTL = From->getTypeLoc();
     if (!FromTL.getAs<PackExpansionTypeLoc>()) {
       TypeLocBuilder TLB;
       TLB.reserve(FromTL.getFullDataSize());
       QualType To = getDerived().TransformType(TLB, FromTL);
       if (To.isNull())
-        return ExprError();
+        return true;
 
       if (To == From->getType())
         Args.push_back(From);
@@ -10510,27 +10440,27 @@
                                              Unexpanded,
                                              Expand, RetainExpansion,
                                              NumExpansions))
-      return ExprError();
+      return true;
 
     if (!Expand) {
       // The transform has determined that we should perform a simple
       // transformation on the pack expansion, producing another pack
       // expansion.
-      Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
+      Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1);
 
       TypeLocBuilder TLB;
       TLB.reserve(From->getTypeLoc().getFullDataSize());
 
       QualType To = getDerived().TransformType(TLB, PatternTL);
       if (To.isNull())
-        return ExprError();
+        return true;
 
       To = getDerived().RebuildPackExpansionType(To,
                                                  PatternTL.getSourceRange(),
                                                  ExpansionTL.getEllipsisLoc(),
                                                  NumExpansions);
       if (To.isNull())
-        return ExprError();
+        return true;
 
       PackExpansionTypeLoc ToExpansionTL
         = TLB.push<PackExpansionTypeLoc>(To);
@@ -10547,15 +10477,15 @@
       TLB.reserve(PatternTL.getFullDataSize());
       QualType To = getDerived().TransformType(TLB, PatternTL);
       if (To.isNull())
-        return ExprError();
+        return true;
 
       if (To->containsUnexpandedParameterPack()) {
         To = getDerived().RebuildPackExpansionType(To,
                                                    PatternTL.getSourceRange(),
                                                    ExpansionTL.getEllipsisLoc(),
                                                    NumExpansions);
         if (To.isNull())
-          return ExprError();
+          return true;
 
         PackExpansionTypeLoc ToExpansionTL
           = TLB.push<PackExpansionTypeLoc>(To);
@@ -10577,20 +10507,30 @@
 
     QualType To = getDerived().TransformType(TLB, PatternTL);
     if (To.isNull())
-      return ExprError();
+      return true;
 
     To = getDerived().RebuildPackExpansionType(To,
                                                PatternTL.getSourceRange(),
                                                ExpansionTL.getEllipsisLoc(),
                                                NumExpansions);
     if (To.isNull())
-      return ExprError();
+      return true;
 
     PackExpansionTypeLoc ToExpansionTL
       = TLB.push<PackExpansionTypeLoc>(To);
     ToExpansionTL.setEllipsisLoc(ExpansionTL.getEllipsisLoc());
     Args.push_back(TLB.getTypeSourceInfo(SemaRef.Context, To));
   }
+  return false;
+}
+
+template <typename Derived>
+ExprResult TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
+  bool ArgChanged = false;
+  SmallVector<TypeSourceInfo *, 4> Args;
+  if (getDerived().TransformTypeSourceListAndExpandPacks(E->getArgs(),
+                                                         ArgChanged, Args))
+    return ExprError();
 
   if (!getDerived().AlwaysRebuild() && !ArgChanged)
     return E;
@@ -12477,11 +12417,11 @@
   return SemaRef.BuildDecltypeType(E, Loc);
 }
 
-template<typename Derived>
-QualType TreeTransform<Derived>::RebuildUnaryTransformType(QualType BaseType,
-                                            UnaryTransformType::UTTKind UKind,
-                                            SourceLocation Loc) {
-  return SemaRef.BuildUnaryTransformType(BaseType, UKind, Loc);
+template <typename Derived>
+QualType TreeTransform<Derived>::RebuildTransformTraitType(
+    ArrayRef<QualType> ArgTypes, TransformTraitType::TTKind TKind,
+    SourceLocation Loc) {
+  return SemaRef.BuildTransformTraitType(ArgTypes, TKind, Loc);
 }
 
 template<typename Derived>
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp
+++ lib/Sema/SemaType.cpp
@@ -1491,18 +1491,31 @@
     }
     break;
   }
-  case DeclSpec::TST_underlyingType:
-    Result = S.GetTypeFromParser(DS.getRepAsType());
-    assert(!Result.isNull() && "Didn't get a type for __underlying_type?");
-    Result = S.BuildUnaryTransformType(Result,
-                                       UnaryTransformType::EnumUnderlyingType,
-                                       DS.getTypeSpecTypeLoc());
+  case DeclSpec::TST_underlyingType: {
+    ArrayRef<ParsedType> ParsedArgs = DS.getRepAsTypeList();
+    SmallVector<QualType, 2> Args;
+    Args.reserve(ParsedArgs.size());
+    for (auto PT : ParsedArgs) {
+      QualType NewArg = S.GetTypeFromParser(PT);
+      assert(!NewArg.isNull());
+      Args.push_back(NewArg);
+    }
+    TransformTraitType::TTKind TKind;
+    switch (DS.getTypeSpecType()) {
+    case DeclSpec::TST_underlyingType:
+      TKind = TransformTraitType::EnumUnderlyingType;
+      break;
+    default:
+      llvm_unreachable("unhandled case");
+    }
+
+    Result = S.BuildTransformTraitType(Args, TKind, DS.getTypeSpecTypeLoc());
     if (Result.isNull()) {
       Result = Context.IntTy;
       declarator.setInvalidType(true);
     }
     break;
-
+  }
   case DeclSpec::TST_auto:
     Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false);
     break;
@@ -5323,15 +5336,18 @@
       Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
       TL.setUnderlyingTInfo(TInfo);
     }
-    void VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
-      // FIXME: This holds only because we only have one unary transform.
+    void VisitTransformTraitTypeLoc(TransformTraitTypeLoc TL) {
       assert(DS.getTypeSpecType() == DeclSpec::TST_underlyingType);
       TL.setKWLoc(DS.getTypeSpecTypeLoc());
       TL.setParensRange(DS.getTypeofParensRange());
-      assert(DS.getRepAsType());
-      TypeSourceInfo *TInfo = nullptr;
-      Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
-      TL.setUnderlyingTInfo(TInfo);
+      ArrayRef<ParsedType> ParsedArgs = DS.getRepAsTypeList();
+      SmallVector<TypeSourceInfo *, 2> ArgInfo;
+      for (auto PT : ParsedArgs) {
+        TypeSourceInfo *TInfo = nullptr;
+        Sema::GetTypeFromParser(PT, &TInfo);
+        ArgInfo.push_back(TInfo);
+      }
+      TL.setArgTInfo(ArgInfo);
     }
     void VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
       // By default, use the source location of the type specifier.
@@ -7982,39 +7998,78 @@
   return Context.getDecltypeType(E, getDecltypeForExpr(*this, E));
 }
 
-QualType Sema::BuildUnaryTransformType(QualType BaseType,
-                                       UnaryTransformType::UTTKind UKind,
+static bool diagnoseTransformTraitArity(Sema &S,
+                                        TransformTraitType::TTKind Kind,
+                                        SourceLocation Loc, unsigned NumArgs) {
+  unsigned MinArity, MaxArity;
+  switch (Kind) {
+  case TransformTraitType::EnumUnderlyingType:
+    MinArity = MaxArity = 1;
+    break;
+  }
+  struct DiagInfo {
+    unsigned ReqNumArgs;
+    unsigned SelectOne;
+  };
+  auto DiagSelect = [&]() -> Optional<DiagInfo> {
+    if (MinArity && MinArity == MaxArity && MinArity != NumArgs)
+      return DiagInfo{MinArity, 0};
+    if (MinArity && NumArgs < MinArity)
+      return DiagInfo{MinArity, 1};
+    if (MaxArity && NumArgs > MaxArity)
+      return DiagInfo{MinArity, 2};
+    return {};
+  }();
+
+  if (DiagSelect.hasValue()) {
+    auto &Info = DiagSelect.getValue();
+    S.Diag(Loc, diag::err_type_trait_arity)
+        << Info.ReqNumArgs << Info.SelectOne << (Info.ReqNumArgs != 1)
+        << (int)NumArgs << SourceRange(Loc);
+    return true;
+  }
+  return false;
+}
+
+QualType Sema::BuildTransformTraitType(ArrayRef<QualType> ArgTypes,
+                                       TransformTraitType::TTKind TKind,
                                        SourceLocation Loc) {
-  switch (UKind) {
-  case UnaryTransformType::EnumUnderlyingType:
+  if (diagnoseTransformTraitArity(*this, TKind, Loc, ArgTypes.size()))
+    return QualType();
+  switch (TKind) {
+  case TransformTraitType::EnumUnderlyingType: {
+    assert(ArgTypes.size() == 1 &&
+           "underlying_type takes only a single argument");
+    QualType BaseType = ArgTypes[0];
     if (!BaseType->isDependentType() && !BaseType->isEnumeralType()) {
       Diag(Loc, diag::err_only_enums_have_underlying_types);
       return QualType();
-    } else {
-      QualType Underlying = BaseType;
-      if (!BaseType->isDependentType()) {
-        // The enum could be incomplete if we're parsing its definition or
-        // recovering from an error.
-        NamedDecl *FwdDecl = nullptr;
-        if (BaseType->isIncompleteType(&FwdDecl)) {
-          Diag(Loc, diag::err_underlying_type_of_incomplete_enum) << BaseType;
-          Diag(FwdDecl->getLocation(), diag::note_forward_declaration) << FwdDecl;
-          return QualType();
-        }
+    }
+    QualType Underlying = BaseType;
+    if (!BaseType->isDependentType()) {
+      // The enum could be incomplete if we're parsing its definition or
+      // recovering from an error.
+      NamedDecl *FwdDecl = nullptr;
+      if (BaseType->isIncompleteType(&FwdDecl)) {
+        Diag(Loc, diag::err_underlying_type_of_incomplete_enum) << BaseType;
+        Diag(FwdDecl->getLocation(), diag::note_forward_declaration) << FwdDecl;
+        return QualType();
+      }
 
-        EnumDecl *ED = BaseType->getAs<EnumType>()->getDecl();
-        assert(ED && "EnumType has no EnumDecl");
+      EnumDecl *ED = BaseType->getAs<EnumType>()->getDecl();
+      assert(ED && "EnumType has no EnumDecl");
 
-        DiagnoseUseOfDecl(ED, Loc);
+      DiagnoseUseOfDecl(ED, Loc);
 
-        Underlying = ED->getIntegerType();
-        assert(!Underlying.isNull());
-      }
-      return Context.getUnaryTransformType(BaseType, Underlying,
-                                        UnaryTransformType::EnumUnderlyingType);
+      Underlying = ED->getIntegerType();
+      assert(!Underlying.isNull());
     }
+    return Context.getTransformTraitType(
+        BaseType, Underlying, TransformTraitType::EnumUnderlyingType);
   }
-  llvm_unreachable("unknown unary transform type");
+  }
+
+  llvm_unreachable("unknown transform type");
 }
 
 QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) {
Index: lib/Sema/SemaTemplateVariadic.cpp
===================================================================
--- lib/Sema/SemaTemplateVariadic.cpp
+++ lib/Sema/SemaTemplateVariadic.cpp
@@ -803,14 +803,23 @@
   switch (DS.getTypeSpecType()) {
   case TST_typename:
   case TST_typeofType:
-  case TST_underlyingType:
   case TST_atomic: {
     QualType T = DS.getRepAsType().get();
     if (!T.isNull() && T->containsUnexpandedParameterPack())
       return true;
     break;
   }
-      
+
+  case TST_underlyingType: {
+    ArrayRef<ParsedType> Args = DS.getRepAsTypeList();
+    for (auto PT : Args) {
+      QualType T = PT.get();
+      if (!T.isNull() && T->containsUnexpandedParameterPack())
+        return true;
+    }
+    break;
+  }
+
   case TST_typeofExpr:
   case TST_decltype:
     if (DS.getRepAsExpr() && 
Index: lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- lib/Sema/SemaTemplateDeduction.cpp
+++ lib/Sema/SemaTemplateDeduction.cpp
@@ -1945,7 +1945,7 @@
     case Type::DependentName:
     case Type::UnresolvedUsing:
     case Type::Decltype:
-    case Type::UnaryTransform:
+    case Type::TransformTrait:
     case Type::Auto:
     case Type::DeducedTemplateSpecialization:
     case Type::DependentTemplateSpecialization:
@@ -5357,13 +5357,18 @@
                                  OnlyDeduced, Depth, Used);
     break;
 
-  case Type::UnaryTransform:
-    if (!OnlyDeduced)
-      MarkUsedTemplateParameters(Ctx,
-                                 cast<UnaryTransformType>(T)->getUnderlyingType(),
-                                 OnlyDeduced, Depth, Used);
+  case Type::TransformTrait: {
+    const TransformTraitType *TT = cast<TransformTraitType>(T);
+    if (!OnlyDeduced) {
+      // FIXME(EricWF): Do we mark the input args as used unconditionally?
+      for (auto Ty : TT->getArgs()) {
+        MarkUsedTemplateParameters(Ctx, Ty, OnlyDeduced, Depth, Used);
+      }
+      MarkUsedTemplateParameters(Ctx, TT->getTransformedType(), OnlyDeduced,
+                                 Depth, Used);
+    }
     break;
-
+  }
   case Type::PackExpansion:
     MarkUsedTemplateParameters(Ctx,
                                cast<PackExpansionType>(T)->getPattern(),
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -982,14 +982,14 @@
   // Check that we have valid decl-specifiers specified.
   auto CheckValidDeclSpecifiers = [this, &D] {
     // C++ [temp.param]
-    // p1 
-    //   template-parameter:
-    //     ...
-    //     parameter-declaration
-    // p2 
+    // p1
+    //   template-parameter:
+    //     ...
+    //     parameter-declaration
+    // p2
     //   ... A storage class shall not be specified in a template-parameter
     //   declaration.
-    // [dcl.typedef]p1: 
+    // [dcl.typedef]p1:
     //   The typedef specifier [...] shall not be used in the decl-specifier-seq
     //   of a parameter-declaration
     const DeclSpec &DS = D.getDeclSpec();
@@ -5291,8 +5291,8 @@
   return false;
 }
 
-bool UnnamedLocalNoLinkageFinder::VisitUnaryTransformType(
-                                                    const UnaryTransformType*) {
+bool UnnamedLocalNoLinkageFinder::VisitTransformTraitType(
+    const TransformTraitType *) {
   return false;
 }
 
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -3901,7 +3901,7 @@
       break;
     case Type::Paren:
     case Type::TypeOf:
-    case Type::UnaryTransform:
+    case Type::TransformTrait:
     case Type::Attributed:
     case Type::SubstTemplateTypeParm:
     case Type::PackExpansion:
Index: lib/Sema/DeclSpec.cpp
===================================================================
--- lib/Sema/DeclSpec.cpp
+++ lib/Sema/DeclSpec.cpp
@@ -367,6 +367,8 @@
       return false;
      
     case TST_underlyingType:
+      return false;
+
     case TST_typename:
     case TST_typeofType: {
       QualType QT = DS.getRepAsType().get();
@@ -689,6 +691,24 @@
   return false;
 }
 
+bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec,
+                               unsigned &DiagID, ArrayRef<ParsedType> Rep,
+                               const PrintingPolicy &Policy) {
+  assert(isTypeListRep(T) && "T does not store a type");
+
+  if (TypeSpecType != TST_unspecified) {
+    PrevSpec = DeclSpec::getSpecifierName((TST)TypeSpecType, Policy);
+    DiagID = diag::err_invalid_decl_spec_combination;
+    return true;
+  }
+  TypeSpecType = T;
+  TypeListRep = SmallVector<ParsedType, 2>(Rep.begin(), Rep.end());
+  TSTLoc = Loc;
+  TSTNameLoc = Loc;
+  TypeSpecOwned = false;
+  return false;
+}
+
 bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
                                const char *&PrevSpec,
                                unsigned &DiagID,
Index: lib/Parse/ParseDeclCXX.cpp
===================================================================
--- lib/Parse/ParseDeclCXX.cpp
+++ lib/Parse/ParseDeclCXX.cpp
@@ -1020,35 +1020,86 @@
   PP.AnnotateCachedTokens(Tok);
 }
 
-void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) {
-  assert(Tok.is(tok::kw___underlying_type) &&
-         "Not an underlying type specifier");
+struct TransformTraitInfo {
+  unsigned MinArity, MaxArity;
+  DeclSpec::TST TypeSpecType;
+};
+
+static TransformTraitInfo GetTraitInfo(tok::TokenKind Kind) {
+  switch (Kind) {
+  case tok::kw___underlying_type:
+    return {1, 1, DeclSpec::TST_underlyingType};
+  default:
+    llvm_unreachable("Not a transformation trait type specifier");
+  }
+}
+
+void Parser::ParseTransformTraitTypeSpecifier(DeclSpec &DS) {
+  TransformTraitInfo Info = GetTraitInfo(Tok.getKind());
 
   SourceLocation StartLoc = ConsumeToken();
-  BalancedDelimiterTracker T(*this, tok::l_paren);
-  if (T.expectAndConsume(diag::err_expected_lparen_after,
-                       "__underlying_type", tok::r_paren)) {
+  BalancedDelimiterTracker Parens(*this, tok::l_paren);
+  if (Parens.expectAndConsume())
     return;
-  }
 
-  TypeResult Result = ParseTypeName();
-  if (Result.isInvalid()) {
-    SkipUntil(tok::r_paren, StopAtSemi);
-    return;
+  SmallVector<ParsedType, 2> Args;
+  if (Tok.isNot(tok::r_paren)) {
+    do {
+      // Parse the next type.
+      TypeResult Ty = ParseTypeName();
+      if (Ty.isInvalid()) {
+        Parens.skipToEnd();
+        return;
+      }
+
+      // Parse the ellipsis, if present.
+      if (Tok.is(tok::ellipsis)) {
+        Ty = Actions.ActOnPackExpansion(Ty.get(), ConsumeToken());
+        if (Ty.isInvalid()) {
+          Parens.skipToEnd();
+          return;
+        }
+      }
+
+      // Add this type to the list of arguments.
+      Args.push_back(Ty.get());
+    } while (TryConsumeToken(tok::comma));
   }
+  if (Parens.consumeClose())
+    return;
 
-  // Match the ')'
-  T.consumeClose();
-  if (T.getCloseLocation().isInvalid())
+  SourceLocation EndLoc = Parens.getCloseLocation();
+
+  struct DiagInfo {
+    unsigned ReqNumArgs;
+    unsigned SelectOne;
+  };
+  auto DiagSelect = [&]() -> Optional<DiagInfo> {
+    if (Info.MinArity && Info.MinArity == Info.MaxArity &&
+        Info.MinArity != Args.size())
+      return DiagInfo{Info.MinArity, 0};
+    if (Info.MinArity && Args.size() < Info.MinArity)
+      return DiagInfo{Info.MinArity, 1};
+    if (Info.MaxArity && Args.size() > Info.MaxArity)
+      return DiagInfo{Info.MaxArity, 2};
+    return {};
+  }();
+
+  if (DiagSelect.hasValue()) {
+    auto &Info = DiagSelect.getValue();
+    Diag(EndLoc, diag::err_type_trait_arity)
+        << Info.ReqNumArgs << Info.SelectOne << (Info.ReqNumArgs != 1)
+        << (int)Args.size() << SourceRange(StartLoc);
     return;
+  }
 
+  // TST
   const char *PrevSpec = nullptr;
   unsigned DiagID;
-  if (DS.SetTypeSpecType(DeclSpec::TST_underlyingType, StartLoc, PrevSpec,
-                         DiagID, Result.get(),
+  if (DS.SetTypeSpecType(Info.TypeSpecType, StartLoc, PrevSpec, DiagID, Args,
                          Actions.getASTContext().getPrintingPolicy()))
     Diag(StartLoc, DiagID) << PrevSpec;
-  DS.setTypeofParensRange(T.getRange());
+    DS.setTypeofParensRange(Parens.getRange());
 }
 
 /// ParseBaseTypeSpecifier - Parse a C++ base-type-specifier which is either a
Index: lib/Parse/ParseDecl.cpp
===================================================================
--- lib/Parse/ParseDecl.cpp
+++ lib/Parse/ParseDecl.cpp
@@ -3722,7 +3722,7 @@
       continue;
 
     case tok::kw___underlying_type:
-      ParseUnderlyingTypeSpecifier(DS);
+      ParseTransformTraitTypeSpecifier(DS);
       continue;
 
     case tok::kw__Atomic:
Index: lib/Lex/PPMacroExpansion.cpp
===================================================================
--- lib/Lex/PPMacroExpansion.cpp
+++ lib/Lex/PPMacroExpansion.cpp
@@ -1243,7 +1243,6 @@
       //.Case("cxx_runtime_arrays", LangOpts.CPlusPlusTSArrays)
       //.Case("cxx_concepts", LangOpts.CPlusPlusTSConcepts)
       // FIXME: Should this be __has_feature or __has_extension?
-      //.Case("raw_invocation_type", LangOpts.CPlusPlus)
       // Type traits
       // N.B. Additional type traits should not be added to the following list.
       // Instead, they should be detected by has_extension.
Index: lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- lib/CodeGen/CodeGenFunction.cpp
+++ lib/CodeGen/CodeGenFunction.cpp
@@ -2093,7 +2093,7 @@
 
     case Type::Paren:
     case Type::TypeOf:
-    case Type::UnaryTransform:
+    case Type::TransformTrait:
     case Type::Attributed:
     case Type::SubstTemplateTypeParm:
     case Type::PackExpansion:
Index: lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- lib/CodeGen/CGDebugInfo.cpp
+++ lib/CodeGen/CGDebugInfo.cpp
@@ -2585,8 +2585,8 @@
     case Type::Decltype:
       T = cast<DecltypeType>(T)->getUnderlyingType();
       break;
-    case Type::UnaryTransform:
-      T = cast<UnaryTransformType>(T)->getUnderlyingType();
+    case Type::TransformTrait:
+      T = cast<TransformTraitType>(T)->getTransformedType();
       break;
     case Type::Attributed:
       T = cast<AttributedType>(T)->getEquivalentType();
@@ -2780,7 +2780,7 @@
   case Type::TypeOfExpr:
   case Type::TypeOf:
   case Type::Decltype:
-  case Type::UnaryTransform:
+  case Type::TransformTrait:
   case Type::PackExpansion:
     break;
   }
Index: lib/ASTMatchers/ASTMatchersInternal.cpp
===================================================================
--- lib/ASTMatchers/ASTMatchersInternal.cpp
+++ lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -809,7 +809,7 @@
 const AstTypeMatcher<TypedefType> typedefType;
 const AstTypeMatcher<EnumType> enumType;
 const AstTypeMatcher<TemplateSpecializationType> templateSpecializationType;
-const AstTypeMatcher<UnaryTransformType> unaryTransformType;
+const AstTypeMatcher<TransformTraitType> transformTraingType;
 const AstTypeMatcher<RecordType> recordType;
 const AstTypeMatcher<TagType> tagType;
 const AstTypeMatcher<ElaboratedType> elaboratedType;
Index: lib/AST/TypePrinter.cpp
===================================================================
--- lib/AST/TypePrinter.cpp
+++ lib/AST/TypePrinter.cpp
@@ -184,7 +184,7 @@
     case Type::TypeOfExpr:
     case Type::TypeOf:
     case Type::Decltype:
-    case Type::UnaryTransform:
+    case Type::TransformTrait:
     case Type::Record:
     case Type::Enum:
     case Type::Elaborated:
@@ -879,33 +879,38 @@
   OS << ')';
   spaceBeforePlaceHolder(OS);
 }
-void TypePrinter::printDecltypeAfter(const DecltypeType *T, raw_ostream &OS) { } 
+void TypePrinter::printDecltypeAfter(const DecltypeType *T, raw_ostream &OS) {}
 
-void TypePrinter::printUnaryTransformBefore(const UnaryTransformType *T,
+void TypePrinter::printTransformTraitBefore(const TransformTraitType *T,
                                             raw_ostream &OS) {
   IncludeStrongLifetimeRAII Strong(Policy);
 
-  switch (T->getUTTKind()) {
-    case UnaryTransformType::EnumUnderlyingType:
-      OS << "__underlying_type(";
-      print(T->getBaseType(), OS, StringRef());
-      OS << ')';
-      spaceBeforePlaceHolder(OS);
-      return;
+  switch (T->getTTKind()) {
+  case TransformTraitType::EnumUnderlyingType:
+    OS << "__underlying_type(";
+    break;
   }
-
-  printBefore(T->getBaseType(), OS);
+  for (unsigned I = 0; I != T->getNumArgs(); ++I) {
+    print(T->getArg(I), OS, StringRef());
+    if ((I + 1) != T->getNumArgs())
+      OS << ", ";
+    }
+    OS << ')';
+    spaceBeforePlaceHolder(OS);
+    return;
+  llvm_unreachable("transformation trait not handled");
 }
-void TypePrinter::printUnaryTransformAfter(const UnaryTransformType *T,
+
+void TypePrinter::printTransformTraitAfter(const TransformTraitType *T,
                                            raw_ostream &OS) {
   IncludeStrongLifetimeRAII Strong(Policy);
 
-  switch (T->getUTTKind()) {
-    case UnaryTransformType::EnumUnderlyingType:
-      return;
+  switch (T->getTTKind()) {
+  case TransformTraitType::EnumUnderlyingType:
+    return;
   }
 
-  printAfter(T->getBaseType(), OS);
+  llvm_unreachable("transformation trait not handled");
 }
 
 void TypePrinter::printAutoBefore(const AutoType *T, raw_ostream &OS) { 
Index: lib/AST/TypeLoc.cpp
===================================================================
--- lib/AST/TypeLoc.cpp
+++ lib/AST/TypeLoc.cpp
@@ -444,13 +444,15 @@
       getUnderlyingType(), Loc);
 }
 
-void UnaryTransformTypeLoc::initializeLocal(ASTContext &Context,
-                                       SourceLocation Loc) {
-    setKWLoc(Loc);
-    setRParenLoc(Loc);
-    setLParenLoc(Loc);
-    this->setUnderlyingTInfo(
-        Context.getTrivialTypeSourceInfo(getTypePtr()->getBaseType(), Loc));
+void TransformTraitTypeLoc::initializeLocal(ASTContext &Context,
+                                            SourceLocation Loc) {
+  setKWLoc(Loc);
+  setRParenLoc(Loc);
+  setLParenLoc(Loc);
+  for (unsigned I = 0; I < getTypePtr()->getNumArgs(); ++I) {
+    this->setArgInfo(
+        I, Context.getTrivialTypeSourceInfo(getTypePtr()->getArg(I), Loc));
+  }
 }
 
 void ElaboratedTypeLoc::initializeLocal(ASTContext &Context, 
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp
+++ lib/AST/Type.cpp
@@ -967,10 +967,34 @@
   TRIVIAL_TYPE_CLASS(TypeOfExpr)
   TRIVIAL_TYPE_CLASS(TypeOf)
   TRIVIAL_TYPE_CLASS(Decltype)
-  TRIVIAL_TYPE_CLASS(UnaryTransform)
   TRIVIAL_TYPE_CLASS(Record)
   TRIVIAL_TYPE_CLASS(Enum)
 
+  QualType VisitTransformTraitType(const TransformTraitType *T) {
+    // Transform type arguments.
+    bool typeArgChanged = false;
+    SmallVector<QualType, 4> typeArgs;
+    for (auto typeArg : T->getArgs()) {
+      QualType newTypeArg = recurse(typeArg);
+      if (newTypeArg.isNull())
+        return {};
+
+      if (newTypeArg.getAsOpaquePtr() != typeArg.getAsOpaquePtr())
+        typeArgChanged = true;
+
+      typeArgs.push_back(newTypeArg);
+    }
+    QualType TransformedType = recurse(T->getTransformedType());
+    if (TransformedType.isNull())
+      return {};
+    if (TransformedType.getAsOpaquePtr() ==
+            T->getTransformedType().getAsOpaquePtr() &&
+        !typeArgChanged)
+      return QualType(T, 0);
+
+    return Ctx.getTransformTraitType(typeArgs, TransformedType, T->getTTKind());
+  }
+
   // FIXME: Non-trivial to implement, but important for C++
   TRIVIAL_TYPE_CLASS(Elaborated)
 
@@ -3042,20 +3066,27 @@
   E->Profile(ID, Context, true);
 }
 
-UnaryTransformType::UnaryTransformType(QualType BaseType,
-                                       QualType UnderlyingType,
-                                       UTTKind UKind,
+TransformTraitType::TransformTraitType(ArrayRef<QualType> ArgTys,
+                                       QualType TransformedTy, TTKind TKind,
                                        QualType CanonicalType)
-    : Type(UnaryTransform, CanonicalType, BaseType->isDependentType(),
-           BaseType->isInstantiationDependentType(),
-           BaseType->isVariablyModifiedType(),
-           BaseType->containsUnexpandedParameterPack()),
-      BaseType(BaseType), UnderlyingType(UnderlyingType), UKind(UKind) {}
+    : Type(TransformTrait, CanonicalType, false, false, false, false),
+      ArgTypes(ArgTys.begin(), ArgTys.end()), TransformedType(TransformedTy) {
+  TransformTraitTypeBits.TTKind = TKind;
+  for (QualType T : ArgTypes) {
+    if (T->isDependentType())
+      this->setDependent(true);
+    if (T->isInstantiationDependentType())
+      this->setInstantiationDependent(true);
+    if (T->isVariablyModifiedType())
+      this->setVariablyModified(true);
+    if (T->containsUnexpandedParameterPack())
+      this->setContainsUnexpandedParameterPack(true);
+  }
+}
 
-DependentUnaryTransformType::DependentUnaryTransformType(const ASTContext &C,
-                                                         QualType BaseType,
-                                                         UTTKind UKind)
-     : UnaryTransformType(BaseType, C.DependentTy, UKind, QualType()) {}
+DependentTransformTraitType::DependentTransformTraitType(
+    const ASTContext &C, ArrayRef<QualType> ArgTys, TTKind TKind)
+    : TransformTraitType(ArgTys, C.DependentTy, TKind, QualType()) {}
 
 TagType::TagType(TypeClass TC, const TagDecl *D, QualType can)
     : Type(TC, can, D->isDependentType(),
@@ -3676,7 +3707,7 @@
   case Type::TypeOfExpr:
   case Type::TypeOf:
   case Type::Decltype:
-  case Type::UnaryTransform:
+  case Type::TransformTrait:
   case Type::TemplateTypeParm:
   case Type::SubstTemplateTypeParmPack:
   case Type::DependentName:
Index: lib/AST/MicrosoftMangle.cpp
===================================================================
--- lib/AST/MicrosoftMangle.cpp
+++ lib/AST/MicrosoftMangle.cpp
@@ -2617,13 +2617,12 @@
     << Range;
 }
 
-void MicrosoftCXXNameMangler::mangleType(const UnaryTransformType *T,
+void MicrosoftCXXNameMangler::mangleType(const TransformTraitType *T,
                                          Qualifiers, SourceRange Range) {
   DiagnosticsEngine &Diags = Context.getDiags();
-  unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
-    "cannot mangle this unary transform type yet");
-  Diags.Report(Range.getBegin(), DiagID)
-    << Range;
+  unsigned DiagID = Diags.getCustomDiagID(
+      DiagnosticsEngine::Error, "cannot mangle this transform type yet");
+  Diags.Report(Range.getBegin(), DiagID) << Range;
 }
 
 void MicrosoftCXXNameMangler::mangleType(const AutoType *T, Qualifiers,
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -1964,7 +1964,7 @@
   case Type::TypeOf:
   case Type::Decltype:
   case Type::TemplateTypeParm:
-  case Type::UnaryTransform:
+  case Type::TransformTrait:
   case Type::SubstTemplateTypeParm:
   unresolvedType:
     // Some callers want a prefix before the mangled type.
@@ -3234,20 +3234,21 @@
   Out << 'E';
 }
 
-void CXXNameMangler::mangleType(const UnaryTransformType *T) {
+void CXXNameMangler::mangleType(const TransformTraitType *T) {
   // If this is dependent, we need to record that. If not, we simply
   // mangle it as the underlying type since they are equivalent.
   if (T->isDependentType()) {
     Out << 'U';
-    
-    switch (T->getUTTKind()) {
-      case UnaryTransformType::EnumUnderlyingType:
-        Out << "3eut";
-        break;
+
+    switch (T->getTTKind()) {
+    case TransformTraitType::EnumUnderlyingType:
+      Out << "3eut";
+      break;
     }
   }
 
-  mangleType(T->getBaseType());
+  for (auto Ty : T->getArgs())
+    mangleType(Ty);
 }
 
 void CXXNameMangler::mangleType(const AutoType *T) {
Index: lib/AST/ASTStructuralEquivalence.cpp
===================================================================
--- lib/AST/ASTStructuralEquivalence.cpp
+++ lib/AST/ASTStructuralEquivalence.cpp
@@ -498,13 +498,20 @@
       return false;
     break;
 
-  case Type::UnaryTransform:
-    if (!IsStructurallyEquivalent(
-            Context, cast<UnaryTransformType>(T1)->getUnderlyingType(),
-            cast<UnaryTransformType>(T1)->getUnderlyingType()))
+  case Type::TransformTrait: {
+    const TransformTraitType *TT1 = cast<TransformTraitType>(T1);
+    const TransformTraitType *TT2 = cast<TransformTraitType>(T2);
+    if (TT1->getNumArgs() != TT2->getNumArgs())
+      return false;
+    for (unsigned I = 0; I < TT1->getNumArgs(); ++I) {
+      if (!IsStructurallyEquivalent(Context, TT1->getArg(I), TT2->getArg(I)))
+        return false;
+    }
+    if (!IsStructurallyEquivalent(Context, TT1->getTransformedType(),
+                                  TT2->getTransformedType()))
       return false;
     break;
-
+  }
   case Type::Decltype:
     if (!IsStructurallyEquivalent(Context,
                                   cast<DecltypeType>(T1)->getUnderlyingExpr(),
Index: lib/AST/ASTImporter.cpp
===================================================================
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -64,7 +64,7 @@
     // FIXME: DependentTypeOfExprType
     QualType VisitTypeOfType(const TypeOfType *T);
     QualType VisitDecltypeType(const DecltypeType *T);
-    QualType VisitUnaryTransformType(const UnaryTransformType *T);
+    QualType VisitTransformTraitType(const TransformTraitType *T);
     QualType VisitAutoType(const AutoType *T);
     QualType VisitInjectedClassNameType(const InjectedClassNameType *T);
     // FIXME: DependentDecltypeType
@@ -712,15 +712,21 @@
   return Importer.getToContext().getDecltypeType(ToExpr, UnderlyingType);
 }
 
-QualType ASTNodeImporter::VisitUnaryTransformType(const UnaryTransformType *T) {
-  QualType ToBaseType = Importer.Import(T->getBaseType());
-  QualType ToUnderlyingType = Importer.Import(T->getUnderlyingType());
-  if (ToBaseType.isNull() || ToUnderlyingType.isNull())
+
+QualType ASTNodeImporter::VisitTransformTraitType(const TransformTraitType *T) {
+  SmallVector<QualType, 2> ToArgTypes;
+  for (auto Ty : T->getArgs()) {
+    QualType ToTy = Importer.Import(Ty);
+    if (ToTy.isNull())
+      return QualType();
+    ToArgTypes.push_back(ToTy);
+  }
+  QualType ToTransformedType = Importer.Import(T->getTransformedType());
+  if (ToTransformedType.isNull())
     return QualType();
 
-  return Importer.getToContext().getUnaryTransformType(ToBaseType,
-                                                       ToUnderlyingType,
-                                                       T->getUTTKind());
+  return Importer.getToContext().getTransformTraitType(
+      ToArgTypes, ToTransformedType, T->getTTKind());
 }
 
 QualType ASTNodeImporter::VisitAutoType(const AutoType *T) {
Index: lib/AST/ASTDumper.cpp
===================================================================
--- lib/AST/ASTDumper.cpp
+++ lib/AST/ASTDumper.cpp
@@ -362,13 +362,14 @@
     void VisitDecltypeType(const DecltypeType *T) {
       dumpStmt(T->getUnderlyingExpr());
     }
-    void VisitUnaryTransformType(const UnaryTransformType *T) {
-      switch (T->getUTTKind()) {
-      case UnaryTransformType::EnumUnderlyingType:
+    void VisitTransformTraitType(const TransformTraitType *T) {
+      switch (T->getTTKind()) {
+      case TransformTraitType::EnumUnderlyingType:
         OS << " underlying_type";
         break;
       }
-      dumpTypeAsChild(T->getBaseType());
+      for (auto Ty : T->getArgs())
+        dumpTypeAsChild(Ty);
     }
     void VisitTagType(const TagType *T) {
       dumpDeclRef(T->getDecl());
@@ -2213,14 +2214,14 @@
 }
 
 void ASTDumper::VisitUnaryOperator(const UnaryOperator *Node) {
-  VisitExpr(Node);
-  OS << " " << (Node->isPostfix() ? "postfix" : "prefix")
-     << " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
-  if (!Node->canOverflow())
-    OS << " cannot overflow";
-}
-
-void ASTDumper::VisitUnaryExprOrTypeTraitExpr(
+  VisitExpr(Node);
+  OS << " " << (Node->isPostfix() ? "postfix" : "prefix") << " '"
+     << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
+  if (!Node->canOverflow())
+    OS << " cannot overflow";
+}
+
+void ASTDumper::VisitUnaryExprOrTypeTraitExpr(
     const UnaryExprOrTypeTraitExpr *Node) {
   VisitExpr(Node);
   switch(Node->getKind()) {
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -2984,7 +2984,7 @@
   case Type::TypeOfExpr:
   case Type::TypeOf:
   case Type::Decltype:
-  case Type::UnaryTransform:
+  case Type::TransformTrait:
   case Type::DependentName:
   case Type::InjectedClassName:
   case Type::TemplateSpecialization:
@@ -4639,38 +4639,46 @@
   return QualType(dt, 0);
 }
 
-/// getUnaryTransformationType - We don't unique these, since the memory
+/// getTransformTraitType - We don't unique these, since the memory
 /// savings are minimal and these are rare.
-QualType ASTContext::getUnaryTransformType(QualType BaseType,
-                                           QualType UnderlyingType,
-                                           UnaryTransformType::UTTKind Kind)
-    const {
-  UnaryTransformType *ut = nullptr;
-
-  if (BaseType->isDependentType()) {
+QualType
+ASTContext::getTransformTraitType(ArrayRef<QualType> ArgTypes,
+                                  QualType TransformedType,
+                                  TransformTraitType::TTKind Kind) const {
+  TransformTraitType *ut = nullptr;
+
+  bool IsDependent =
+      llvm::any_of(ArgTypes, [](QualType T) { return T->isDependentType(); });
+
+  if (IsDependent) {
+    assert(TransformedType->isDependentType() &&
+           "non-dependent transformed type with dependent argument types");
+    SmallVector<QualType, 2> CanonArgs;
+    CanonArgs.reserve(ArgTypes.size());
+    for (auto Ty : ArgTypes)
+      CanonArgs.push_back(getCanonicalType(Ty));
     // Look in the folding set for an existing type.
     llvm::FoldingSetNodeID ID;
-    DependentUnaryTransformType::Profile(ID, getCanonicalType(BaseType), Kind);
+    DependentTransformTraitType::Profile(ID, CanonArgs, Kind);
 
     void *InsertPos = nullptr;
-    DependentUnaryTransformType *Canon
-      = DependentUnaryTransformTypes.FindNodeOrInsertPos(ID, InsertPos);
+    DependentTransformTraitType *Canon =
+        DependentTransformTraitTypes.FindNodeOrInsertPos(ID, InsertPos);
 
     if (!Canon) {
-      // Build a new, canonical __underlying_type(type) type.
+      // Build a new, canonical transformation trait type.
       Canon = new (*this, TypeAlignment)
-             DependentUnaryTransformType(*this, getCanonicalType(BaseType),
-                                         Kind);
-      DependentUnaryTransformTypes.InsertNode(Canon, InsertPos);
+          DependentTransformTraitType(*this, CanonArgs, Kind);
+      DependentTransformTraitTypes.InsertNode(Canon, InsertPos);
     }
-    ut = new (*this, TypeAlignment) UnaryTransformType (BaseType,
-                                                        QualType(), Kind,
-                                                        QualType(Canon, 0));
+    ut = new (*this, TypeAlignment)
+        TransformTraitType(ArgTypes, QualType(), Kind, QualType(Canon, 0));
   } else {
-    QualType CanonType = getCanonicalType(UnderlyingType);
-    ut = new (*this, TypeAlignment) UnaryTransformType (BaseType,
-                                                        UnderlyingType, Kind,
-                                                        CanonType);
+    assert(!TransformedType->isDependentType() &&
+           "dependent transformed type with non-dependent argument types");
+    QualType CanonType = getCanonicalType(TransformedType);
+    ut = new (*this, TypeAlignment)
+        TransformTraitType(ArgTypes, TransformedType, Kind, CanonType);
   }
   Types.push_back(ut);
   return QualType(ut, 0);
Index: include/clang/Serialization/ASTBitCodes.h
===================================================================
--- include/clang/Serialization/ASTBitCodes.h
+++ include/clang/Serialization/ASTBitCodes.h
@@ -957,133 +957,133 @@
     /// AST. Note that DeclCode values share this code space.
     enum TypeCode {
       /// \brief An ExtQualType record.
-      TYPE_EXT_QUAL                 = 1,
+      TYPE_EXT_QUAL = 1,
 
       /// \brief A ComplexType record.
-      TYPE_COMPLEX                  = 3,
+      TYPE_COMPLEX = 3,
 
       /// \brief A PointerType record.
-      TYPE_POINTER                  = 4,
+      TYPE_POINTER = 4,
 
       /// \brief A BlockPointerType record.
-      TYPE_BLOCK_POINTER            = 5,
+      TYPE_BLOCK_POINTER = 5,
 
       /// \brief An LValueReferenceType record.
-      TYPE_LVALUE_REFERENCE         = 6,
+      TYPE_LVALUE_REFERENCE = 6,
 
       /// \brief An RValueReferenceType record.
-      TYPE_RVALUE_REFERENCE         = 7,
+      TYPE_RVALUE_REFERENCE = 7,
 
       /// \brief A MemberPointerType record.
-      TYPE_MEMBER_POINTER           = 8,
+      TYPE_MEMBER_POINTER = 8,
 
       /// \brief A ConstantArrayType record.
-      TYPE_CONSTANT_ARRAY           = 9,
+      TYPE_CONSTANT_ARRAY = 9,
 
       /// \brief An IncompleteArrayType record.
-      TYPE_INCOMPLETE_ARRAY         = 10,
+      TYPE_INCOMPLETE_ARRAY = 10,
 
       /// \brief A VariableArrayType record.
-      TYPE_VARIABLE_ARRAY           = 11,
+      TYPE_VARIABLE_ARRAY = 11,
 
       /// \brief A VectorType record.
-      TYPE_VECTOR                   = 12,
+      TYPE_VECTOR = 12,
 
       /// \brief An ExtVectorType record.
-      TYPE_EXT_VECTOR               = 13,
+      TYPE_EXT_VECTOR = 13,
 
       /// \brief A FunctionNoProtoType record.
-      TYPE_FUNCTION_NO_PROTO        = 14,
+      TYPE_FUNCTION_NO_PROTO = 14,
 
       /// \brief A FunctionProtoType record.
-      TYPE_FUNCTION_PROTO           = 15,
+      TYPE_FUNCTION_PROTO = 15,
 
       /// \brief A TypedefType record.
-      TYPE_TYPEDEF                  = 16,
+      TYPE_TYPEDEF = 16,
 
       /// \brief A TypeOfExprType record.
-      TYPE_TYPEOF_EXPR              = 17,
+      TYPE_TYPEOF_EXPR = 17,
 
       /// \brief A TypeOfType record.
-      TYPE_TYPEOF                   = 18,
+      TYPE_TYPEOF = 18,
 
       /// \brief A RecordType record.
-      TYPE_RECORD                   = 19,
+      TYPE_RECORD = 19,
 
       /// \brief An EnumType record.
-      TYPE_ENUM                     = 20,
+      TYPE_ENUM = 20,
 
       /// \brief An ObjCInterfaceType record.
-      TYPE_OBJC_INTERFACE           = 21,
+      TYPE_OBJC_INTERFACE = 21,
 
       /// \brief An ObjCObjectPointerType record.
-      TYPE_OBJC_OBJECT_POINTER      = 22,
+      TYPE_OBJC_OBJECT_POINTER = 22,
 
       /// \brief a DecltypeType record.
-      TYPE_DECLTYPE                 = 23,
+      TYPE_DECLTYPE = 23,
 
       /// \brief An ElaboratedType record.
-      TYPE_ELABORATED               = 24,
+      TYPE_ELABORATED = 24,
 
       /// \brief A SubstTemplateTypeParmType record.
       TYPE_SUBST_TEMPLATE_TYPE_PARM = 25,
 
       /// \brief An UnresolvedUsingType record.
-      TYPE_UNRESOLVED_USING         = 26,
+      TYPE_UNRESOLVED_USING = 26,
 
       /// \brief An InjectedClassNameType record.
-      TYPE_INJECTED_CLASS_NAME      = 27,
+      TYPE_INJECTED_CLASS_NAME = 27,
 
       /// \brief An ObjCObjectType record.
-      TYPE_OBJC_OBJECT              = 28,
+      TYPE_OBJC_OBJECT = 28,
 
       /// \brief An TemplateTypeParmType record.
-      TYPE_TEMPLATE_TYPE_PARM       = 29,
+      TYPE_TEMPLATE_TYPE_PARM = 29,
 
       /// \brief An TemplateSpecializationType record.
-      TYPE_TEMPLATE_SPECIALIZATION  = 30,
+      TYPE_TEMPLATE_SPECIALIZATION = 30,
 
       /// \brief A DependentNameType record.
-      TYPE_DEPENDENT_NAME           = 31,
+      TYPE_DEPENDENT_NAME = 31,
 
       /// \brief A DependentTemplateSpecializationType record.
       TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION = 32,
 
       /// \brief A DependentSizedArrayType record.
-      TYPE_DEPENDENT_SIZED_ARRAY    = 33,
+      TYPE_DEPENDENT_SIZED_ARRAY = 33,
 
       /// \brief A ParenType record.
-      TYPE_PAREN                    = 34,
+      TYPE_PAREN = 34,
 
       /// \brief A PackExpansionType record.
-      TYPE_PACK_EXPANSION           = 35,
+      TYPE_PACK_EXPANSION = 35,
 
       /// \brief An AttributedType record.
-      TYPE_ATTRIBUTED               = 36,
+      TYPE_ATTRIBUTED = 36,
 
       /// \brief A SubstTemplateTypeParmPackType record.
       TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK = 37,
 
       /// \brief A AutoType record.
-      TYPE_AUTO                  = 38,
+      TYPE_AUTO = 38,
 
-      /// \brief A UnaryTransformType record.
-      TYPE_UNARY_TRANSFORM       = 39,
+      /// \brief A TransformTraitType record.
+      TYPE_TRANSFORM_TRAIT = 39,
 
       /// \brief An AtomicType record.
-      TYPE_ATOMIC                = 40,
+      TYPE_ATOMIC = 40,
 
       /// \brief A DecayedType record.
-      TYPE_DECAYED               = 41,
+      TYPE_DECAYED = 41,
 
       /// \brief An AdjustedType record.
-      TYPE_ADJUSTED              = 42,
+      TYPE_ADJUSTED = 42,
 
       /// \brief A PipeType record.
-      TYPE_PIPE                  = 43,
+      TYPE_PIPE = 43,
 
       /// \brief An ObjCTypeParamType record.
-      TYPE_OBJC_TYPE_PARAM       = 44,
+      TYPE_OBJC_TYPE_PARAM = 44,
 
       /// \brief A DeducedTemplateSpecializationType record.
       TYPE_DEDUCED_TEMPLATE_SPECIALIZATION = 45,
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -1643,8 +1643,9 @@
   /// context, such as when building a type for decltype(auto).
   QualType BuildDecltypeType(Expr *E, SourceLocation Loc,
                              bool AsUnevaluated = true);
-  QualType BuildUnaryTransformType(QualType BaseType,
-                                   UnaryTransformType::UTTKind UKind,
+
+  QualType BuildTransformTraitType(ArrayRef<QualType> ArgTypes,
+                                   TransformTraitType::TTKind Kind,
                                    SourceLocation Loc);
 
   //===--------------------------------------------------------------------===//
Index: include/clang/Sema/DeclSpec.h
===================================================================
--- include/clang/Sema/DeclSpec.h
+++ include/clang/Sema/DeclSpec.h
@@ -368,6 +368,8 @@
     Expr *ExprRep;
   };
 
+  SmallVector<ParsedType, 0> TypeListRep;
+
   // attributes.
   ParsedAttributes Attrs;
 
@@ -400,12 +402,14 @@
   ObjCDeclSpec *ObjCQualifiers;
 
   static bool isTypeRep(TST T) {
-    return (T == TST_typename || T == TST_typeofType ||
-            T == TST_underlyingType || T == TST_atomic);
+    return (T == TST_typename || T == TST_typeofType || T == TST_atomic);
   }
   static bool isExprRep(TST T) {
     return (T == TST_typeofExpr || T == TST_decltype);
   }
+  static bool isTypeListRep(TST T) {
+    return (T == TST_underlyingType);
+  }
 
   DeclSpec(const DeclSpec &) = delete;
   void operator=(const DeclSpec &) = delete;
@@ -481,6 +485,7 @@
   bool isTypeAltiVecBool() const { return TypeAltiVecBool; }
   bool isTypeSpecOwned() const { return TypeSpecOwned; }
   bool isTypeRep() const { return isTypeRep((TST) TypeSpecType); }
+  bool isTypeListRep() const { return isTypeListRep((TST)TypeSpecType); }
   bool isTypeSpecPipe() const { return TypeSpecPipe; }
 
   ParsedType getRepAsType() const {
@@ -495,6 +500,12 @@
     assert(isExprRep((TST) TypeSpecType) && "DeclSpec does not store an expr");
     return ExprRep;
   }
+  ArrayRef<ParsedType> getRepAsTypeList() const {
+    assert(isTypeListRep((TST)TypeSpecType) &&
+           "DeclSpec does not store a type list");
+
+    return TypeListRep;
+  }
   CXXScopeSpec &getTypeSpecScope() { return TypeScope; }
   const CXXScopeSpec &getTypeSpecScope() const { return TypeScope; }
 
@@ -644,10 +655,12 @@
                        SourceLocation TagNameLoc, const char *&PrevSpec,
                        unsigned &DiagID, Decl *Rep, bool Owned,
                        const PrintingPolicy &Policy);
-
   bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec,
                        unsigned &DiagID, Expr *Rep,
                        const PrintingPolicy &policy);
+  bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec,
+                       unsigned &DiagID, ArrayRef<ParsedType> Rep,
+                       const PrintingPolicy &policy);
   bool SetTypeAltiVecVector(bool isAltiVecVector, SourceLocation Loc,
                        const char *&PrevSpec, unsigned &DiagID,
                        const PrintingPolicy &Policy);
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -2407,7 +2407,7 @@
   void AnnotateExistingDecltypeSpecifier(const DeclSpec &DS,
                                          SourceLocation StartLoc,
                                          SourceLocation EndLoc);
-  void ParseUnderlyingTypeSpecifier(DeclSpec &DS);
+  void ParseTransformTraitTypeSpecifier(DeclSpec &DS);
   void ParseAtomicSpecifier(DeclSpec &DS);
 
   ExprResult ParseAlignArgument(SourceLocation Start,
Index: include/clang/Basic/Specifiers.h
===================================================================
--- include/clang/Basic/Specifiers.h
+++ include/clang/Basic/Specifiers.h
@@ -46,35 +46,35 @@
     TST_unspecified,
     TST_void,
     TST_char,
-    TST_wchar,        // C++ wchar_t
-    TST_char16,       // C++11 char16_t
-    TST_char32,       // C++11 char32_t
+    TST_wchar,  // C++ wchar_t
+    TST_char16, // C++11 char16_t
+    TST_char32, // C++11 char32_t
     TST_int,
     TST_int128,
-    TST_half,         // OpenCL half, ARM NEON __fp16
-    TST_Float16,      // C11 extension ISO/IEC TS 18661-3
+    TST_half,    // OpenCL half, ARM NEON __fp16
+    TST_Float16, // C11 extension ISO/IEC TS 18661-3
     TST_float,
     TST_double,
     TST_float128,
-    TST_bool,         // _Bool
-    TST_decimal32,    // _Decimal32
-    TST_decimal64,    // _Decimal64
-    TST_decimal128,   // _Decimal128
+    TST_bool,       // _Bool
+    TST_decimal32,  // _Decimal32
+    TST_decimal64,  // _Decimal64
+    TST_decimal128, // _Decimal128
     TST_enum,
     TST_union,
     TST_struct,
-    TST_class,        // C++ class type
-    TST_interface,    // C++ (Microsoft-specific) __interface type
-    TST_typename,     // Typedef, C++ class-name or enum name, etc.
+    TST_class,     // C++ class type
+    TST_interface, // C++ (Microsoft-specific) __interface type
+    TST_typename,  // Typedef, C++ class-name or enum name, etc.
     TST_typeofType,
     TST_typeofExpr,
-    TST_decltype,         // C++11 decltype
-    TST_underlyingType,   // __underlying_type for C++11
-    TST_auto,             // C++11 auto
-    TST_decltype_auto,    // C++1y decltype(auto)
-    TST_auto_type,        // __auto_type extension
-    TST_unknown_anytype,  // __unknown_anytype extension
-    TST_atomic,           // C11 _Atomic
+    TST_decltype,          // C++11 decltype
+    TST_underlyingType,    // __underlying_type for C++11
+    TST_auto,              // C++11 auto
+    TST_decltype_auto,     // C++1y decltype(auto)
+    TST_auto_type,         // __auto_type extension
+    TST_unknown_anytype,   // __unknown_anytype extension
+    TST_atomic,            // C11 _Atomic
 #define GENERIC_IMAGE_TYPE(ImgType, Id) TST_##ImgType##_t, // OpenCL image types
 #include "clang/Basic/OpenCLImageTypes.def"
     TST_error // erroneous type
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -882,11 +882,6 @@
 def err_type_safety_unknown_flag : Error<
   "invalid comparison flag %0; use 'layout_compatible' or 'must_be_null'">;
 
-// Type traits
-def err_type_trait_arity : Error<
-  "type trait requires %0%select{| or more}1 argument%select{|s}2; have "
-  "%3 argument%s3">;
-
 // Language specific pragmas
 // - Generic warnings
 def warn_pragma_expected_lparen : Warning<
Index: include/clang/Basic/DiagnosticCommonKinds.td
===================================================================
--- include/clang/Basic/DiagnosticCommonKinds.td
+++ include/clang/Basic/DiagnosticCommonKinds.td
@@ -108,6 +108,10 @@
   "%0 attribute cannot be applied to types">;
 def err_enum_template : Error<"enumeration cannot be a template">;
 
+// Type traits
+def err_type_trait_arity : Error<
+  "type trait requires %0%select{| or more| or fewer}1 argument%select{|s}2; have "
+  "%3 argument%s3">;
 }
 
 let CategoryName = "Nullability Issue" in {
Index: include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -5259,7 +5259,11 @@
 /// \endcode
 /// unaryTransformType()
 ///   matches "__underlying_type(T)"
-extern const AstTypeMatcher<UnaryTransformType> unaryTransformType;
+AST_MATCHER(Type, unaryTransformType) {
+  if (const auto *T = Node.getAs<TransformTraitType>())
+    return T->getNumArgs() == 1;
+  return false;
+}
 
 /// \brief Matches record types (e.g. structs, classes).
 ///
Index: include/clang/AST/TypeNodes.def
===================================================================
--- include/clang/AST/TypeNodes.def
+++ include/clang/AST/TypeNodes.def
@@ -87,7 +87,8 @@
 NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TypeOfExpr, Type)
 NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TypeOf, Type)
 NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Decltype, Type)
-NON_CANONICAL_UNLESS_DEPENDENT_TYPE(UnaryTransform, Type)
+NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TransformTrait, Type)
+
 ABSTRACT_TYPE(Tag, Type)
 TYPE(Record, TagType)
 TYPE(Enum, TagType)
Index: include/clang/AST/TypeLoc.h
===================================================================
--- include/clang/AST/TypeLoc.h
+++ include/clang/AST/TypeLoc.h
@@ -1029,6 +1029,10 @@
     getTypeArgLocArray()[i] = TInfo;
   }
 
+  ArrayRef<TypeSourceInfo *> getTypeArgTInfoRef() const {
+    return llvm::makeArrayRef(getTypeArgLocArray(), getNumTypeArgs());
+  }
+
   SourceLocation getProtocolLAngleLoc() const {
     return this->getLocalData()->ProtocolLAngleLoc;
   }
@@ -1919,17 +1923,20 @@
   Expr *getUnderlyingExpr() const { return getTypePtr()->getUnderlyingExpr(); }
 };
 
-struct UnaryTransformTypeLocInfo {
+struct TransformTraitTypeLocInfo {
   // FIXME: While there's only one unary transform right now, future ones may
   // need different representations
   SourceLocation KWLoc, LParenLoc, RParenLoc;
-  TypeSourceInfo *UnderlyingTInfo;
 };
 
-class UnaryTransformTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
-                                                    UnaryTransformTypeLoc,
-                                                    UnaryTransformType,
-                                                    UnaryTransformTypeLocInfo> {
+class TransformTraitTypeLoc
+    : public ConcreteTypeLoc<UnqualTypeLoc, TransformTraitTypeLoc,
+                             TransformTraitType, TransformTraitTypeLocInfo> {
+  // TypeSourceInfo*'s are stored after Info, one for each type argument.
+  TypeSourceInfo **getArgLocArray() const {
+    return (TypeSourceInfo **)this->getExtraLocalData();
+  }
+
 public:
   SourceLocation getKWLoc() const { return getLocalData()->KWLoc; }
   void setKWLoc(SourceLocation Loc) { getLocalData()->KWLoc = Loc; }
@@ -1940,12 +1947,26 @@
   SourceLocation getRParenLoc() const { return getLocalData()->RParenLoc; }
   void setRParenLoc(SourceLocation Loc) { getLocalData()->RParenLoc = Loc; }
 
-  TypeSourceInfo* getUnderlyingTInfo() const {
-    return getLocalData()->UnderlyingTInfo;
+  unsigned getNumArgs() const { return this->getTypePtr()->getNumArgs(); }
+
+  ArrayRef<TypeSourceInfo *> getArgTInfo() const {
+    return llvm::makeArrayRef(getArgLocArray(), getNumArgs());
   }
 
-  void setUnderlyingTInfo(TypeSourceInfo *TInfo) {
-    getLocalData()->UnderlyingTInfo = TInfo;
+  TypeSourceInfo *getArgInfo(unsigned I) {
+    assert(I < getNumArgs());
+    return getArgLocArray()[I];
+  }
+
+  void setArgInfo(unsigned I, TypeSourceInfo *Info) {
+    assert(I < getNumArgs());
+    getArgLocArray()[I] = Info;
+  }
+
+  void setArgTInfo(ArrayRef<TypeSourceInfo *> ArgInfo) {
+    assert(ArgInfo.size() == getNumArgs());
+    for (unsigned I = 0; I < ArgInfo.size(); ++I)
+      setArgInfo(I, ArgInfo[I]);
   }
 
   SourceRange getLocalSourceRange() const {
@@ -1962,6 +1983,16 @@
   }
 
   void initializeLocal(ASTContext &Context, SourceLocation Loc);
+
+  unsigned getExtraLocalDataSize() const {
+    return this->getNumArgs() * sizeof(TypeSourceInfo *);
+  }
+
+  unsigned getExtraLocalDataAlignment() const {
+    static_assert(alignof(TransformTraitTypeLoc) >= alignof(TypeSourceInfo *),
+                  "not enough alignment for tail-allocated data");
+    return alignof(TypeSourceInfo *);
+  }
 };
 
 class DeducedTypeLoc
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -1614,6 +1614,15 @@
     unsigned Keyword : 2;
   };
 
+  class TransformTraitTypeBitfields {
+    friend class TransformTraitType;
+
+    unsigned : NumTypeBits;
+
+    /// The transformation trait kind
+    unsigned TTKind : 1;
+  };
+
   union {
     TypeBitfields TypeBits;
     ArrayTypeBitfields ArrayTypeBits;
@@ -1625,6 +1634,7 @@
     ReferenceTypeBitfields ReferenceTypeBits;
     TypeWithKeywordBitfields TypeWithKeywordBits;
     VectorTypeBitfields VectorTypeBits;
+    TransformTraitTypeBitfields TransformTraitTypeBits;
   };
 
 private:
@@ -3971,61 +3981,67 @@
 };
 
 /// A unary type transform, which is a type constructed from another.
-class UnaryTransformType : public Type {
+class TransformTraitType : public Type {
 public:
-  enum UTTKind {
-    EnumUnderlyingType
-  };
+  enum TTKind { EnumUnderlyingType };
 
 private:
   /// The untransformed type.
-  QualType BaseType;
+  SmallVector<QualType, 2> ArgTypes;
 
   /// The transformed type if not dependent, otherwise the same as BaseType.
-  QualType UnderlyingType;
-
-  UTTKind UKind;
+  QualType TransformedType;
 
 protected:
   friend class ASTContext;
 
-  UnaryTransformType(QualType BaseTy, QualType UnderlyingTy, UTTKind UKind,
-                     QualType CanonicalTy);
+  TransformTraitType(ArrayRef<QualType> ArgTy, QualType TransformedTy,
+                     TTKind TKind, QualType CanonicalTy);
 
 public:
   bool isSugared() const { return !isDependentType(); }
-  QualType desugar() const { return UnderlyingType; }
+  QualType desugar() const { return TransformedType; }
 
-  QualType getUnderlyingType() const { return UnderlyingType; }
-  QualType getBaseType() const { return BaseType; }
+  unsigned getNumArgs() const { return ArgTypes.size(); }
+  ArrayRef<QualType> getArgs() const { return ArgTypes; }
 
-  UTTKind getUTTKind() const { return UKind; }
+  QualType getTransformedType() const { return TransformedType; }
+  QualType getArg(unsigned N) const {
+    assert(N < ArgTypes.size() && "invalid index");
+    return ArgTypes[N];
+  }
+
+  TTKind getTTKind() const {
+    return static_cast<TTKind>(TransformTraitTypeBits.TTKind);
+  }
 
   static bool classof(const Type *T) {
-    return T->getTypeClass() == UnaryTransform;
+    return T->getTypeClass() == TransformTrait;
   }
 };
 
 /// \brief Internal representation of canonical, dependent
 /// __underlying_type(type) types.
 ///
 /// This class is used internally by the ASTContext to manage
 /// canonical, dependent types, only. Clients will only see instances
-/// of this class via UnaryTransformType nodes.
-class DependentUnaryTransformType : public UnaryTransformType,
+/// of this class via TransformTraitType nodes.
+class DependentTransformTraitType : public TransformTraitType,
                                     public llvm::FoldingSetNode {
 public:
-  DependentUnaryTransformType(const ASTContext &C, QualType BaseType,
-                              UTTKind UKind);
+  DependentTransformTraitType(const ASTContext &C, ArrayRef<QualType> ArgTypes,
+                              TTKind TKind);
 
   void Profile(llvm::FoldingSetNodeID &ID) {
-    Profile(ID, getBaseType(), getUTTKind());
+    Profile(ID, getArgs(), getTTKind());
   }
 
-  static void Profile(llvm::FoldingSetNodeID &ID, QualType BaseType,
-                      UTTKind UKind) {
-    ID.AddPointer(BaseType.getAsOpaquePtr());
-    ID.AddInteger((unsigned)UKind);
+  static void Profile(llvm::FoldingSetNodeID &ID, ArrayRef<QualType> ArgTypes,
+                      TTKind TKind) {
+    ID.AddInteger((unsigned)ArgTypes.size());
+    for (auto Ty : ArgTypes)
+      ID.AddPointer(Ty.getAsOpaquePtr());
+    ID.AddInteger((unsigned)TKind);
   }
 };
 
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -1032,9 +1032,11 @@
 DEF_TRAVERSE_TYPE(DecltypeType,
                   { TRY_TO(TraverseStmt(T->getUnderlyingExpr())); })
 
-DEF_TRAVERSE_TYPE(UnaryTransformType, {
-  TRY_TO(TraverseType(T->getBaseType()));
-  TRY_TO(TraverseType(T->getUnderlyingType()));
+DEF_TRAVERSE_TYPE(TransformTraitType, {
+  for (auto Ty : T->getArgs()) {
+    TRY_TO(TraverseType(Ty));
+  }
+  TRY_TO(TraverseType(T->getTransformedType()));
 })
 
 DEF_TRAVERSE_TYPE(AutoType, { TRY_TO(TraverseType(T->getDeducedType())); })
@@ -1267,8 +1269,10 @@
   TRY_TO(TraverseStmt(TL.getTypePtr()->getUnderlyingExpr()));
 })
 
-DEF_TRAVERSE_TYPELOC(UnaryTransformType, {
-  TRY_TO(TraverseTypeLoc(TL.getUnderlyingTInfo()->getTypeLoc()));
+DEF_TRAVERSE_TYPELOC(TransformTraitType, {
+  for (auto *TyInfo : TL.getArgTInfo()) {
+    TRY_TO(TraverseTypeLoc(TyInfo->getTypeLoc()));
+  }
 })
 
 DEF_TRAVERSE_TYPELOC(AutoType, {
Index: include/clang/AST/CanonicalType.h
===================================================================
--- include/clang/AST/CanonicalType.h
+++ include/clang/AST/CanonicalType.h
@@ -538,11 +538,15 @@
 };
 
 template <>
-struct CanProxyAdaptor<UnaryTransformType>
-    : public CanProxyBase<UnaryTransformType> {
-  LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getBaseType)
-  LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType)
-  LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(UnaryTransformType::UTTKind, getUTTKind)
+struct CanProxyAdaptor<TransformTraitType>
+    : public CanProxyBase<TransformTraitType> {
+  LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getTransformedType)
+
+  CanQualType getArg(unsigned i) const {
+    return CanQualType::CreateUnsafe(this->getTypePtr()->getArg(i));
+  }
+
+  LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TransformTraitType::TTKind, getTTKind)
 };
 
 template<>
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h
+++ include/clang/AST/ASTContext.h
@@ -189,8 +189,8 @@
   llvm::FoldingSet<PackExpansionType> PackExpansionTypes;
   mutable llvm::FoldingSet<ObjCObjectTypeImpl> ObjCObjectTypes;
   mutable llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes;
-  mutable llvm::FoldingSet<DependentUnaryTransformType>
-    DependentUnaryTransformTypes;
+  mutable llvm::FoldingSet<DependentTransformTraitType>
+      DependentTransformTraitTypes;
   mutable llvm::FoldingSet<AutoType> AutoTypes;
   mutable llvm::FoldingSet<DeducedTemplateSpecializationType>
     DeducedTemplateSpecializationTypes;
@@ -1476,9 +1476,10 @@
   /// \brief C++11 decltype.
   QualType getDecltypeType(Expr *e, QualType UnderlyingType) const;
 
-  /// \brief Unary type transforms
-  QualType getUnaryTransformType(QualType BaseType, QualType UnderlyingType,
-                                 UnaryTransformType::UTTKind UKind) const;
+  /// \brief type trait transformations
+  QualType getTransformTraitType(ArrayRef<QualType> ArgTypes,
+                                 QualType TransformedType,
+                                 TransformTraitType::TTKind TKind) const;
 
   /// \brief C++11 deduced auto type.
   QualType getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D45131: [... Eric Fiselier via Phabricator via cfe-commits

Reply via email to