EricWF updated this revision to Diff 154005.
EricWF marked 2 inline comments as done.
EricWF added a comment.

Address main review comments.

The `TransformTraitType` is now built early, and the `DeclSpec` refers to it 
and not the list of argument types.

Additionally, the mangling formulation `u <source-name> [<template-args>]` has  
been implemented as suggested, despite being non-standard. How do we suggest 
this extension to Itanium?

I believe this patch should be good to go.


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/Parse/Parser.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/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/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,8 @@
 struct is_same_type<T, T> {
   static const bool value = true;
 };
-
+__underlying_type() x;         // expected-error {{type trait requires 1 argument; have 0 arguments}}
+__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 +27,31 @@
 static_assert(is_same_type<char, decltype(h)>::value,
               "h has the wrong type");
 
+template <class ...Args> struct TypeList {};
+
+template <class ...Args>
+struct TestParse;
+
+template <class ...> struct MyTest {};
+
+template <class ...Args>
+struct TestParse<TypeList<Args...>> {
+  using type = __underlying_type(Args...);
+};
+
+template <class... Args1, class ...Args2>
+struct TestParse<TypeList<Args1...>, TypeList<Args2...>> {
+  // expected-error@+2 2 {{type trait requires 1 argument; have 2 arguments}}
+  // expected-error@+1 {{type trait requires 1 argument; have 0 arguments}}
+  using type = __underlying_type(Args1..., Args2...);
+};
+static_assert(is_same_type<TestParse<TypeList<f>>::type, char>::value, "wrong type");
+static_assert(is_same_type<TestParse<TypeList<f>, TypeList<>>::type, char>::value, "wrong type");
+template struct TestParse<TypeList<>, TypeList<>>; // expected-note {{requested here}}
+template struct TestParse<TypeList<f, f>, TypeList<>>; // expected-note {{requested here}}
+template struct TestParse<TypeList<f>, TypeList<f>>; // expected-note {{requested here}}
+
+
 template <typename T>
 struct underlying_type {
   typedef __underlying_type(T) type; // expected-error {{only enumeration types}}
@@ -38,7 +64,7 @@
 
 using uint = unsigned;
 enum class foo : uint { bar };
- 
+
 static_assert(is_same_type<underlying_type<foo>::type, unsigned>::value,
               "foo has the wrong underlying type");
 
Index: test/CodeGenCXX/mangle.cpp
===================================================================
--- test/CodeGenCXX/mangle.cpp
+++ test/CodeGenCXX/mangle.cpp
@@ -1110,9 +1110,13 @@
 void fn(T, __underlying_type(T)) {}
 
 template void fn<E>(E, __underlying_type(E));
-// CHECK-LABEL: @_ZN6test552fnINS_1EEEEvT_U3eutS2_
+// CHECK-LABEL: @_ZN6test552fnINS_1EEEEvT_u17__underlying_typeIS2_E
+
+void fn2(E, __underlying_type(E)) {}
+// CHECK-LABEL: @_ZN6test553fn2ENS_1EEj
 }
 
+
 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) {
@@ -731,11 +734,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) {
@@ -1222,7 +1228,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
@@ -6100,11 +6100,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: {
@@ -6587,11 +6591,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,9 @@
       TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL,
       NestedNameSpecifierLoc QualifierLoc);
 
+  bool TransformTypeList(ArrayRef<TypeSourceInfo *> InArgs, bool &ArgChanged,
+                         SmallVectorImpl<TypeSourceInfo *> &Args);
+
   /// Transforms the parameters of a function type into the
   /// given vectors.
   ///
@@ -888,9 +891,9 @@
   /// By default, builds a new TypeOfType with the given underlying type.
   QualType RebuildTypeOfType(QualType Underlying);
 
-  /// Build a new unary transform type.
-  QualType RebuildUnaryTransformType(QualType BaseType,
-                                     UnaryTransformType::UTTKind UKind,
+  /// Build a new transform trait type.
+  QualType RebuildTransformTraitType(ArrayRef<QualType> ArgTypes,
+                                     TransformTraitType::TTKind TKind,
                                      SourceLocation Loc);
 
   /// Build a new C++11 decltype type.
@@ -5519,30 +5522,42 @@
   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 *, 6> NewTypeArgInfos;
+  if (getDerived().TransformTypeList(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, 6> Args;
+    Args.reserve(NewTypeArgInfos.size());
+    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);
+  assert(NewTL.getNumArgs() == NewTypeArgInfos.size());
+
   NewTL.setKWLoc(TL.getKWLoc());
   NewTL.setParensRange(TL.getParensRange());
-  NewTL.setUnderlyingTInfo(TL.getUnderlyingTInfo());
+  for (unsigned I = 0, Size = NewTypeArgInfos.size(); I < 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();
@@ -6271,90 +6286,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().TransformTypeList(TL.getTypeArgTInfoRef(), AnyChanged,
+                                     NewTypeArgInfos))
+    return QualType();
 
   QualType Result = TL.getType();
   if (getDerived().AlwaysRebuild() || AnyChanged) {
@@ -10471,20 +10405,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>::TransformTypeList(
+    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);
@@ -10515,27 +10448,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);
@@ -10552,15 +10485,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);
@@ -10582,20 +10515,29 @@
 
     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().TransformTypeList(E->getArgs(), ArgChanged, Args))
+    return ExprError();
 
   if (!getDerived().AlwaysRebuild() && !ArgChanged)
     return E;
@@ -12482,11 +12424,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
@@ -1543,18 +1543,15 @@
     }
     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: {
+    ParsedType ParsedTT = DS.getRepAsType();
+    Result = S.GetTypeFromParser(ParsedTT);
     if (Result.isNull()) {
       Result = Context.IntTy;
       declarator.setInvalidType(true);
     }
     break;
-
+  }
   case DeclSpec::TST_auto:
     Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false);
     break;
@@ -5375,16 +5372,14 @@
       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);
+      TypeSourceInfo *RepTInfo = nullptr;
+      Sema::GetTypeFromParser(DS.getRepAsType(), &RepTInfo);
+      TL.copy(RepTInfo->getTypeLoc());
     }
+
     void VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
       // By default, use the source location of the type specifier.
       TL.setBuiltinLoc(DS.getTypeSpecTypeLoc());
@@ -8068,39 +8063,130 @@
   return Context.getDecltypeType(E, getDecltypeForExpr(*this, E));
 }
 
-QualType Sema::BuildUnaryTransformType(QualType BaseType,
-                                       UnaryTransformType::UTTKind UKind,
-                                       SourceLocation Loc) {
-  switch (UKind) {
-  case UnaryTransformType::EnumUnderlyingType:
-    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();
-        }
+static bool CheckTransformTraitArity(Sema &S, TransformTraitType::TTKind Kind,
+                               unsigned NumArgs, SourceLocation Loc, SourceRange R) {
+  unsigned Arity;
+  bool IsVariadic = false;
+  switch (Kind) {
+  case TransformTraitType::EnumUnderlyingType:
+    Arity = 1;
+    break;
+  }
+
+  struct DiagInfo {
+    unsigned ReqNumArgs;
+    unsigned SelectOne;
+  };
+  auto DiagSelect = [&]() -> Optional<DiagInfo> {
+    if (NumArgs == 0)
+      return DiagInfo{Arity, 0};
+    if (Arity && !IsVariadic && Arity != NumArgs)
+      return DiagInfo{Arity, 0};
+    if (Arity && IsVariadic && NumArgs < Arity)
+      return DiagInfo{Arity, 1};
+    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 << R;
+    return true;
+  }
+  return false;
+}
+
+TypeResult Sema::ActOnTransformTraitType(ArrayRef<ParsedType> ParsedArgs,
+                                         TransformTraitType::TTKind Kind,
+                                         SourceLocation KWLoc,
+                                         SourceRange ParenRange) {
+  SmallVector<TypeSourceInfo *, 2> ArgTInfos;
+  SmallVector<QualType, 2> ArgTypes;
+  ArgTInfos.reserve(ParsedArgs.size());
+  ArgTypes.reserve(ParsedArgs.size());
+
+  for (auto &PT : ParsedArgs) {
+    TypeSourceInfo *ArgTypeInfo = nullptr;
+    QualType NewArg = GetTypeFromParser(PT, &ArgTypeInfo);
+    assert(ArgTypeInfo && "No type source info?");
+    ArgTypes.push_back(NewArg);
+    ArgTInfos.push_back(ArgTypeInfo);
+  }
+  QualType Result = BuildTransformTraitType(ArgTypes, Kind, KWLoc);
+  if (Result.isNull())
+    return TypeResult(/*IsInvalid*/true);
 
-        EnumDecl *ED = BaseType->getAs<EnumType>()->getDecl();
-        assert(ED && "EnumType has no EnumDecl");
+  // Create source information for this type.
+  TypeSourceInfo *ResultTInfo = Context.CreateTypeSourceInfo(Result);
+  TypeLoc ResultTL = ResultTInfo->getTypeLoc();
 
-        DiagnoseUseOfDecl(ED, Loc);
+  auto TTT = ResultTL.castAs<TransformTraitTypeLoc>();
+  TTT.setKWLoc(KWLoc);
+  TTT.setParensRange(ParenRange);
+  if (TTT.getNumArgs() > 0) {
+    assert(TTT.getNumArgs() == ArgTInfos.size());
+    TTT.setArgTInfo(ArgTInfos);
+  }
 
-        Underlying = ED->getIntegerType();
-        assert(!Underlying.isNull());
-      }
-      return Context.getUnaryTransformType(BaseType, Underlying,
-                                        UnaryTransformType::EnumUnderlyingType);
+  return CreateParsedType(Result, ResultTInfo);
+}
+
+QualType Sema::ComputeTransformTraitResultType(ArrayRef<QualType> ArgTypes,
+                                               TransformTraitType::TTKind TKind,
+                                               SourceLocation Loc) {
+  auto Error = []() { return QualType(); };
+  bool DelayChecking = llvm::any_of(ArgTypes, [](QualType Ty) {
+    return Ty->isDependentType() ||
+           Ty->containsUnexpandedParameterPack();
+  });
+
+  // Delay all checking while any of the arguments are instantiation dependent.
+  if (DelayChecking)
+    return Context.DependentTy;
+
+  if (CheckTransformTraitArity(*this, TKind, ArgTypes.size(), Loc, SourceRange(Loc)))
+    return Error();
+
+  switch (TKind) {
+  case TransformTraitType::EnumUnderlyingType: {
+    assert(ArgTypes.size() == 1);
+    if (ArgTypes[0]->isDependentType())
+      return Context.DependentTy;
+
+    QualType BaseType = ArgTypes[0];
+    if (!BaseType->isEnumeralType()) {
+      Diag(Loc, diag::err_only_enums_have_underlying_types);
+      return Error();
     }
+    // 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 Error();
+    }
+
+    EnumDecl *ED = BaseType->getAs<EnumType>()->getDecl();
+    assert(ED && "EnumType has no EnumDecl");
+
+    DiagnoseUseOfDecl(ED, Loc);
+    assert(!ED->getIntegerType().isNull());
+    return ED->getIntegerType();
   }
-  llvm_unreachable("unknown unary transform type");
+  }
+
+  llvm_unreachable("unknown transform type");
+}
+
+QualType Sema::BuildTransformTraitType(ArrayRef<QualType> ArgTypes,
+                                       TransformTraitType::TTKind TKind,
+                                       SourceLocation Loc) {
+  QualType ResultType = ComputeTransformTraitResultType(ArgTypes, TKind, Loc);
+  if (ResultType.isNull())
+    return QualType();
+  return Context.getTransformTraitType(ArgTypes, ResultType, TKind);
 }
 
 QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) {
Index: lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- lib/Sema/SemaTemplateDeduction.cpp
+++ lib/Sema/SemaTemplateDeduction.cpp
@@ -1951,7 +1951,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:
@@ -5369,13 +5369,14 @@
                                  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) {
+      for (auto Ty : TT->getArgs())
+        MarkUsedTemplateParameters(Ctx, Ty, 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
@@ -5382,8 +5382,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
@@ -3940,7 +3940,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
@@ -370,8 +370,13 @@
       if (Expr *E = DS.getRepAsExpr())
         return E->getType()->isFunctionType();
       return false;
-     
-    case TST_underlyingType:
+
+    case TST_underlyingType: {
+      QualType QT = DS.getRepAsType().get();
+      assert(!QT.isNull());
+      return QT->isFunctionType();
+    }
+
     case TST_typename:
     case TST_typeofType: {
       QualType QT = DS.getRepAsType().get();
Index: lib/Parse/ParseDeclCXX.cpp
===================================================================
--- lib/Parse/ParseDeclCXX.cpp
+++ lib/Parse/ParseDeclCXX.cpp
@@ -1020,35 +1020,66 @@
   PP.AnnotateCachedTokens(Tok);
 }
 
-void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) {
-  assert(Tok.is(tok::kw___underlying_type) &&
-         "Not an underlying type specifier");
 
-  SourceLocation StartLoc = ConsumeToken();
-  BalancedDelimiterTracker T(*this, tok::l_paren);
-  if (T.expectAndConsume(diag::err_expected_lparen_after,
-                       "__underlying_type", tok::r_paren)) {
+void Parser::ParseTransformTraitTypeSpecifier(DeclSpec &DS) {
+  auto Error = [&]() {
+    DS.SetTypeSpecError();
     return;
-  }
+  };
+  auto KindInfo =
+      [&]() -> std::pair<TransformTraitType::TTKind, DeclSpec::TST> {
+    using EnumKind = TransformTraitType::TTKind;
+    switch (Tok.getKind()) {
+    case tok::kw___underlying_type:
+      return {EnumKind::EnumUnderlyingType, clang::TST_underlyingType};
+    default:
+      llvm_unreachable("Not a transformation trait type specifier");
+    }
+  }();
 
-  TypeResult Result = ParseTypeName();
-  if (Result.isInvalid()) {
-    SkipUntil(tok::r_paren, StopAtSemi);
-    return;
+  SourceLocation StartLoc = ConsumeToken();
+  BalancedDelimiterTracker Parens(*this, tok::l_paren);
+  if (Parens.expectAndConsume())
+    return Error();
+
+  SmallVector<ParsedType, 2> Args;
+  if (Tok.isNot(tok::r_paren)) {
+    do {
+      // Parse the next type.
+      TypeResult Ty = ParseTypeName();
+      if (Ty.isInvalid()) {
+        Parens.skipToEnd();
+        return Error();
+      }
+
+      // Parse the ellipsis, if present.
+      if (Tok.is(tok::ellipsis)) {
+        Ty = Actions.ActOnPackExpansion(Ty.get(), ConsumeToken());
+        if (Ty.isInvalid()) {
+          Parens.skipToEnd();
+          return Error();
+        }
+      }
+
+      // Add this type to the list of arguments.
+      Args.push_back(Ty.get());
+    } while (TryConsumeToken(tok::comma));
   }
+  if (Parens.consumeClose())
+    return Error();
 
-  // Match the ')'
-  T.consumeClose();
-  if (T.getCloseLocation().isInvalid())
-    return;
+  TypeResult TyRes = Actions.ActOnTransformTraitType(
+      Args, KindInfo.first, StartLoc, Parens.getRange());
+  if (TyRes.isInvalid())
+    return Error();
 
+  // TST
   const char *PrevSpec = nullptr;
   unsigned DiagID;
-  if (DS.SetTypeSpecType(DeclSpec::TST_underlyingType, StartLoc, PrevSpec,
-                         DiagID, Result.get(),
+  if (DS.SetTypeSpecType(KindInfo.second, StartLoc, PrevSpec, DiagID, TyRes.get(),
                          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
@@ -3770,7 +3770,7 @@
       continue;
 
     case tok::kw___underlying_type:
-      ParseUnderlyingTypeSpecifier(DS);
+      ParseTransformTraitTypeSpecifier(DS);
       continue;
 
     case tok::kw__Atomic:
Index: lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- lib/CodeGen/CodeGenFunction.cpp
+++ lib/CodeGen/CodeGenFunction.cpp
@@ -2118,7 +2118,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
@@ -2639,8 +2639,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();
@@ -2834,7 +2834,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
@@ -811,7 +811,7 @@
 const AstTypeMatcher<TypedefType> typedefType;
 const AstTypeMatcher<EnumType> enumType;
 const AstTypeMatcher<TemplateSpecializationType> templateSpecializationType;
-const AstTypeMatcher<UnaryTransformType> unaryTransformType;
+const AstTypeMatcher<TransformTraitType> transformTraitType;
 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
@@ -203,7 +203,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:
@@ -931,32 +931,32 @@
 
 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;
+  OS << T->getName() << "(";
+
+  for (unsigned I = 0; I != T->getNumArgs(); ++I) {
+    print(T->getArg(I), OS, StringRef());
+    if ((I + 1) != T->getNumArgs())
+      OS << ", ";
   }
 
-  printBefore(T->getBaseType(), OS);
+  OS << ')';
+  spaceBeforePlaceHolder(OS);
 }
 
-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
@@ -470,13 +470,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
@@ -977,10 +977,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)
 
@@ -3083,20 +3107,41 @@
   E->Profile(ID, Context, true);
 }
 
-UnaryTransformType::UnaryTransformType(QualType BaseType,
-                                       QualType UnderlyingType,
-                                       UTTKind UKind,
+TransformTraitType::TransformTraitType(const ASTContext &Ctx,
+                                       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),
+      TransformedType(TransformedTy) {
+  TransformTraitTypeBits.TTKind = TKind;
+  TransformTraitTypeBits.NumArgs = ArgTys.size();
+  ArgStorage = (QualType *)Ctx.Allocate(sizeof(QualType) * ArgTys.size(),
+                                        alignof(QualType));
+  assert(!TransformedTy.isNull());
+  this->setDependent(TransformedTy->isDependentType());
+  this->setVariablyModified(TransformedTy->isVariablyModifiedType());
+
+  for (unsigned I = 0, NumArgs = ArgTys.size(); I < NumArgs; ++I) {
+    QualType T = ArgTys[I];
+    new ((void *)(ArgStorage + I)) QualType(T);
+    if (T->isInstantiationDependentType())
+      this->setInstantiationDependent(true);
+    if (T->containsUnexpandedParameterPack())
+      this->setContainsUnexpandedParameterPack(true);
+  }
+}
+
+StringRef TransformTraitType::getName(TTKind Kind) {
+  switch (Kind) {
+  case TransformTraitType::EnumUnderlyingType:
+    return "__underlying_type";
+  }
+  llvm_unreachable("unhandled case");
+}
 
-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(C, ArgTys, C.DependentTy, TKind, QualType()) {}
 
 TagType::TagType(TypeClass TC, const TagDecl *D, QualType can)
     : Type(TC, can, D->isDependentType(),
@@ -3717,7 +3762,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
@@ -2650,13 +2650,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.
@@ -3267,20 +3267,37 @@
   Out << 'E';
 }
 
-void CXXNameMangler::mangleType(const UnaryTransformType *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;
-    }
+void CXXNameMangler::mangleType(const TransformTraitType *T) {
+  // TransformTraitType's uses a non-standard mangling with the intent to
+  // suggest it as a Itanium ABI extension.
+  //
+  // <type-traits-type> ::=
+  //     u <source-name> [<template-args>] # vendor extended type
+
+  // If this type isn't dependent, simply mangle it as the transformed type
+  // since they are equivalent. Otherwise, we need to record the dependent type.
+  if (!T->isDependentType()) {
+    mangleType(T->getTransformedType());
+    return;
   }
 
-  mangleType(T->getBaseType());
+  Out << "u";
+
+  // mangle the source name.
+  StringRef Ident =
+      TransformTraitType::GetTransformTraitIdentifier(T->getTTKind());
+  Out << Ident.size() << Ident;
+
+  assert(T->getNumArgs() && "Empty argument list for transformation trait?");
+
+  Out << "I";
+
+  // mangle each argument type.
+  for (auto Ty : T->getArgs())
+    mangleType(Ty);
+
+  // Disambiguate the end of the argument list.
+  Out << "E";
 }
 
 void CXXNameMangler::mangleType(const AutoType *T) {
Index: lib/AST/ASTStructuralEquivalence.cpp
===================================================================
--- lib/AST/ASTStructuralEquivalence.cpp
+++ lib/AST/ASTStructuralEquivalence.cpp
@@ -508,13 +508,22 @@
       return false;
     break;
 
-  case Type::UnaryTransform:
-    if (!IsStructurallyEquivalent(
-            Context, cast<UnaryTransformType>(T1)->getUnderlyingType(),
-            cast<UnaryTransformType>(T2)->getUnderlyingType()))
+  case Type::TransformTrait: {
+    const TransformTraitType *TT1 = cast<TransformTraitType>(T1);
+    const TransformTraitType *TT2 = cast<TransformTraitType>(T2);
+    if (TT1->getTTKind() != TT2->getTTKind())
+      return false;
+    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
@@ -129,7 +129,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
@@ -807,15 +807,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, 6> 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 {};
 
-  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());
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -3047,7 +3047,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:
@@ -4686,38 +4686,44 @@
   return QualType(dt, 0);
 }
 
-/// getUnaryTransformationType - 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()) {
+/// We don't unique these, since the memory savings are minimal and these are
+/// rare.
+QualType
+ASTContext::getTransformTraitType(ArrayRef<QualType> ArgTypes,
+                                  QualType TransformedType,
+                                  TransformTraitType::TTKind Kind) const {
+  assert(!TransformedType.isNull());
+  TransformTraitType *ut = nullptr;
+
+  bool IsDependent = TransformedType->isDependentType();
+
+  if (IsDependent) {
+    SmallVector<QualType, 6> 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(
+        *this, ArgTypes, DependentTy, 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(*this, 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
@@ -1142,8 +1142,8 @@
       /// A AutoType record.
       TYPE_AUTO                  = 38,
 
-      /// A UnaryTransformType record.
-      TYPE_UNARY_TRANSFORM       = 39,
+      /// A TransformTraitType record.
+      TYPE_TRANSFORM_TRAIT       = 39,
 
       /// An AtomicType record.
       TYPE_ATOMIC                = 40,
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -1647,8 +1647,18 @@
   /// 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,
+
+  TypeResult ActOnTransformTraitType(ArrayRef<ParsedType> ArgTypes,
+                                     TransformTraitType::TTKind Kind,
+                                     SourceLocation KWLoc,
+                                     SourceRange ParenRange);
+
+  QualType ComputeTransformTraitResultType(ArrayRef<QualType> ArgTypes,
+                                           TransformTraitType::TTKind Kind,
+                                           SourceLocation Loc);
+
+  QualType BuildTransformTraitType(ArrayRef<QualType> ArgTypes,
+                                   TransformTraitType::TTKind Kind,
                                    SourceLocation Loc);
 
   //===--------------------------------------------------------------------===//
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -2505,7 +2505,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/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -892,11 +892,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}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
@@ -5288,15 +5288,29 @@
 extern const AstTypeMatcher<TemplateSpecializationType>
     templateSpecializationType;
 
+/// Matches types nodes representing type-trait transformations.
+///
+/// Given:
+/// \code
+///   typedef __underlying_type(T) type;
+/// \endcode
+/// transformTraitType()
+///   matches "__underlying_type(T)"
+extern const AstTypeMatcher<TransformTraitType> transformTraitType;
+
 /// Matches types nodes representing unary type transformations.
 ///
 /// Given:
 /// \code
 ///   typedef __underlying_type(T) type;
 /// \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;
+}
 
 /// 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());
+  }
+
+  TypeSourceInfo *getArgInfo(unsigned I) {
+    assert(I < getNumArgs());
+    return getArgLocArray()[I];
   }
 
-  void setUnderlyingTInfo(TypeSourceInfo *TInfo) {
-    getLocalData()->UnderlyingTInfo = TInfo;
+  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,14 @@
   }
 
   void initializeLocal(ASTContext &Context, SourceLocation Loc);
+
+  unsigned getExtraLocalDataSize() const {
+    return this->getNumArgs() * sizeof(TypeSourceInfo *);
+  }
+
+  unsigned getExtraLocalDataAlignment() const {
+    return alignof(TypeSourceInfo *);
+  }
 };
 
 class DeducedTypeLoc
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -1622,6 +1622,18 @@
     unsigned Keyword : 2;
   };
 
+  class TransformTraitTypeBitfields {
+    friend class TransformTraitType;
+
+    unsigned : NumTypeBits;
+
+    /// The transformation trait kind
+    unsigned TTKind : 1;
+
+    /// The number of type arguments
+    unsigned NumArgs : 31 - NumTypeBits;
+  };
+
   union {
     TypeBitfields TypeBits;
     ArrayTypeBitfields ArrayTypeBits;
@@ -1633,6 +1645,7 @@
     ReferenceTypeBitfields ReferenceTypeBits;
     TypeWithKeywordBitfields TypeWithKeywordBits;
     VectorTypeBitfields VectorTypeBits;
+    TransformTraitTypeBitfields TransformTraitTypeBits;
   };
 
 private:
@@ -3995,61 +4008,72 @@
 };
 
 /// 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;
+  QualType *ArgStorage;
 
   /// 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,
+  TransformTraitType(const ASTContext &Ctx, 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 TransformTraitTypeBits.NumArgs; }
+  ArrayRef<QualType> getArgs() const {
+    return llvm::makeArrayRef(ArgStorage, getNumArgs());
+  }
 
-  UTTKind getUTTKind() const { return UKind; }
+  QualType getTransformedType() const { return TransformedType; }
+  QualType getArg(unsigned N) const {
+    assert(N < getNumArgs() && "invalid index");
+    return ArgStorage[N];
+  }
+
+  static StringRef getName(TTKind K);
+  StringRef getName() const { return getName(getTTKind()); }
+
+  TTKind getTTKind() const {
+    return static_cast<TTKind>(TransformTraitTypeBits.TTKind);
+  }
 
   static bool classof(const Type *T) {
-    return T->getTypeClass() == UnaryTransform;
+    return T->getTypeClass() == TransformTrait;
   }
 };
 
 /// 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
@@ -190,8 +190,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;
@@ -1487,9 +1487,10 @@
   /// C++11 decltype.
   QualType getDecltypeType(Expr *e, QualType UnderlyingType) const;
 
-  /// Unary type transforms
-  QualType getUnaryTransformType(QualType BaseType, QualType UnderlyingType,
-                                 UnaryTransformType::UTTKind UKind) const;
+  /// Type trait transformations
+  QualType getTransformTraitType(ArrayRef<QualType> ArgTypes,
+                                 QualType TransformedType,
+                                 TransformTraitType::TTKind TKind) const;
 
   /// 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

Reply via email to