[clang] bc60cf2 - [clang] adds unary type transformations as compiler built-ins

Christopher Di Bella via cfe-commits cfe-commits at lists.llvm.org
Sun Aug 14 10:33:53 PDT 2022


Author: Christopher Di Bella
Date: 2022-08-14T17:12:15Z
New Revision: bc60cf2368de90918719dc7e3d7c63a72cc007ad

URL: https://github.com/llvm/llvm-project/commit/bc60cf2368de90918719dc7e3d7c63a72cc007ad
DIFF: https://github.com/llvm/llvm-project/commit/bc60cf2368de90918719dc7e3d7c63a72cc007ad.diff

LOG: [clang] adds unary type transformations as compiler built-ins

Adds

* `__add_lvalue_reference`
* `__add_pointer`
* `__add_rvalue_reference`
* `__decay`
* `__make_signed`
* `__make_unsigned`
* `__remove_all_extents`
* `__remove_extent`
* `__remove_const`
* `__remove_volatile`
* `__remove_cv`
* `__remove_pointer`
* `__remove_reference`
* `__remove_cvref`

These are all compiler built-in equivalents of the unary type traits
found in [[meta.trans]][1]. The compiler already has all of the
information it needs to answer these transformations, so we can skip
needing to make partial specialisations in standard library
implementations (we already do this for a lot of the query traits). This
will hopefully improve compile times, as we won't need use as much
memory in such a base part of the standard library.

[1]: http://wg21.link/meta.trans

Co-authored-by: zoecarver

Reviewed By: aaron.ballman, rsmith

Differential Revision: https://reviews.llvm.org/D116203

Added: 
    clang/include/clang/Basic/TransformTypeTraits.def
    clang/test/SemaCXX/libstdcxx_transform_type_traits_hack.cpp
    clang/test/SemaCXX/remove_pointer.mm

Modified: 
    clang/include/clang/AST/Type.h
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Basic/Specifiers.h
    clang/include/clang/Basic/TokenKinds.def
    clang/include/clang/Parse/Parser.h
    clang/include/clang/Sema/DeclSpec.h
    clang/include/clang/Sema/Sema.h
    clang/include/clang/module.modulemap
    clang/lib/AST/ASTContext.cpp
    clang/lib/AST/ItaniumMangle.cpp
    clang/lib/AST/JSONNodeDumper.cpp
    clang/lib/AST/TextNodeDumper.cpp
    clang/lib/AST/TypePrinter.cpp
    clang/lib/Format/FormatToken.cpp
    clang/lib/Format/FormatToken.h
    clang/lib/Format/TokenAnnotator.cpp
    clang/lib/Lex/PPMacroExpansion.cpp
    clang/lib/Parse/ParseDecl.cpp
    clang/lib/Parse/ParseDeclCXX.cpp
    clang/lib/Parse/ParseExpr.cpp
    clang/lib/Parse/ParseExprCXX.cpp
    clang/lib/Parse/ParseStmt.cpp
    clang/lib/Parse/ParseTentative.cpp
    clang/lib/Sema/DeclSpec.cpp
    clang/lib/Sema/SemaDecl.cpp
    clang/lib/Sema/SemaTemplateVariadic.cpp
    clang/lib/Sema/SemaType.cpp
    clang/test/CodeGenCXX/mangle.cpp
    clang/test/SemaCXX/type-traits.cpp
    clang/utils/ClangVisualizers/clang.natvis

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index ad9835e839a65..f46224ff3d703 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -797,6 +797,9 @@ class QualType {
     return Value.getPointer().isNull();
   }
 
+  // Determines if a type can form `T&`.
+  bool isReferenceable() const;
+
   /// Determine whether this particular QualType instance has the
   /// "const" qualifier set, without looking through typedefs that may have
   /// added "const" at a 
diff erent level.
@@ -4637,7 +4640,8 @@ class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode {
 class UnaryTransformType : public Type {
 public:
   enum UTTKind {
-    EnumUnderlyingType
+#define TRANSFORM_TYPE_TRAIT_DEF(Enum, _) Enum,
+#include "clang/Basic/TransformTypeTraits.def"
   };
 
 private:
@@ -6584,6 +6588,19 @@ inline const Type *QualType::getTypePtrOrNull() const {
   return (isNull() ? nullptr : getCommonPtr()->BaseType);
 }
 
+inline bool QualType::isReferenceable() const {
+  // C++ [defns.referenceable]
+  //   type that is either an object type, a function type that does not have
+  //   cv-qualifiers or a ref-qualifier, or a reference type.
+  const Type &Self = **this;
+  if (Self.isObjectType() || Self.isReferenceType())
+    return true;
+  if (const auto *F = Self.getAs<FunctionProtoType>())
+    return F->getMethodQuals().empty() && F->getRefQualifier() == RQ_None;
+
+  return false;
+}
+
 inline SplitQualType QualType::split() const {
   if (!hasLocalNonFastQualifiers())
     return SplitQualType(getTypePtrUnsafe(),

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index e4e7d7b7338a4..cff85d5e33cdb 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8674,6 +8674,10 @@ def err_typecheck_expect_flt_or_vector : Error<
   "a vector of such types is required">;
 def err_cast_selector_expr : Error<
   "cannot type cast @selector expression">;
+def err_make_signed_integral_only : Error<
+  "'%select{make_unsigned|make_signed}0' is only compatible with "
+  "non-%select{bool|_BitInt(1)}1 integers and enum types, but was given "
+  "%2%select{| whose underlying type is %4}3">;
 def ext_typecheck_cond_incompatible_pointers : ExtWarn<
   "pointer type mismatch%
diff { ($ and $)|}0,1">,
   InGroup<DiagGroup<"pointer-type-mismatch">>;

diff  --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h
index 7657ae36d21bb..8a08a430d012a 100644
--- a/clang/include/clang/Basic/Specifiers.h
+++ b/clang/include/clang/Basic/Specifiers.h
@@ -53,41 +53,42 @@ namespace clang {
     TST_unspecified,
     TST_void,
     TST_char,
-    TST_wchar,        // C++ wchar_t
-    TST_char8,        // C++20 char8_t (proposed)
-    TST_char16,       // C++11 char16_t
-    TST_char32,       // C++11 char32_t
+    TST_wchar,  // C++ wchar_t
+    TST_char8,  // C++20 char8_t (proposed)
+    TST_char16, // C++11 char16_t
+    TST_char32, // C++11 char32_t
     TST_int,
     TST_int128,
-    TST_bitint,       // Bit-precise integer types.
-    TST_half,         // OpenCL half, ARM NEON __fp16
-    TST_Float16,      // C11 extension ISO/IEC TS 18661-3
-    TST_Accum,        // ISO/IEC JTC1 SC22 WG14 N1169 Extension
+    TST_bitint,  // Bit-precise integer types.
+    TST_half,    // OpenCL half, ARM NEON __fp16
+    TST_Float16, // C11 extension ISO/IEC TS 18661-3
+    TST_Accum,   // ISO/IEC JTC1 SC22 WG14 N1169 Extension
     TST_Fract,
     TST_BFloat16,
     TST_float,
     TST_double,
     TST_float128,
     TST_ibm128,
-    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
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) TST_##Trait,
+#include "clang/Basic/TransformTypeTraits.def"
+    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
@@ -96,8 +97,8 @@ namespace clang {
   /// Structure that packs information about the type specifiers that
   /// were written in a particular type specifier sequence.
   struct WrittenBuiltinSpecs {
-    static_assert(TST_error < 1 << 6, "Type bitfield not wide enough for TST");
-    /*DeclSpec::TST*/ unsigned Type  : 6;
+    static_assert(TST_error < 1 << 7, "Type bitfield not wide enough for TST");
+    /*DeclSpec::TST*/ unsigned Type : 7;
     /*DeclSpec::TSS*/ unsigned Sign  : 2;
     /*TypeSpecifierWidth*/ unsigned Width : 2;
     unsigned ModeAttr : 1;

diff  --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 565e5a37be3d8..7f421add92aa1 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -501,7 +501,9 @@ TYPE_TRAIT_1(__is_trivially_copyable, IsTriviallyCopyable, KEYCXX)
 TYPE_TRAIT_1(__is_union, IsUnion, KEYCXX)
 TYPE_TRAIT_1(__has_unique_object_representations,
              HasUniqueObjectRepresentations, KEYCXX)
-KEYWORD(__underlying_type           , KEYCXX)
+
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) KEYWORD(__##Trait, KEYCXX)
+#include "clang/Basic/TransformTypeTraits.def"
 
 // Clang-only C++ Type Traits
 TYPE_TRAIT_1(__is_trivially_relocatable, IsTriviallyRelocatable, KEYCXX)

diff  --git a/clang/include/clang/Basic/TransformTypeTraits.def b/clang/include/clang/Basic/TransformTypeTraits.def
new file mode 100644
index 0000000000000..9389effc6d835
--- /dev/null
+++ b/clang/include/clang/Basic/TransformTypeTraits.def
@@ -0,0 +1,29 @@
+//==--- TransformTypeTraits.def - type trait transformations --------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines transform type traits' names.
+//
+//===----------------------------------------------------------------------===//
+
+TRANSFORM_TYPE_TRAIT_DEF(AddLvalueReference, add_lvalue_reference)
+TRANSFORM_TYPE_TRAIT_DEF(AddPointer, add_pointer)
+TRANSFORM_TYPE_TRAIT_DEF(AddRvalueReference, add_rvalue_reference)
+TRANSFORM_TYPE_TRAIT_DEF(Decay, decay)
+TRANSFORM_TYPE_TRAIT_DEF(MakeSigned, make_signed)
+TRANSFORM_TYPE_TRAIT_DEF(MakeUnsigned, make_unsigned)
+TRANSFORM_TYPE_TRAIT_DEF(RemoveAllExtents, remove_all_extents)
+TRANSFORM_TYPE_TRAIT_DEF(RemoveConst, remove_const)
+TRANSFORM_TYPE_TRAIT_DEF(RemoveCV, remove_cv)
+TRANSFORM_TYPE_TRAIT_DEF(RemoveCVRef, remove_cvref)
+TRANSFORM_TYPE_TRAIT_DEF(RemoveExtent, remove_extent)
+TRANSFORM_TYPE_TRAIT_DEF(RemovePointer, remove_pointer)
+TRANSFORM_TYPE_TRAIT_DEF(RemoveReference, remove_reference)
+TRANSFORM_TYPE_TRAIT_DEF(RemoveRestrict, remove_restrict)
+TRANSFORM_TYPE_TRAIT_DEF(RemoveVolatile, remove_volatile)
+TRANSFORM_TYPE_TRAIT_DEF(EnumUnderlyingType, underlying_type)
+#undef TRANSFORM_TYPE_TRAIT_DEF

diff  --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 41bfc9f48eccf..0b6da06de9bee 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -2906,7 +2906,6 @@ class Parser : public CodeCompletionHandler {
   void AnnotateExistingDecltypeSpecifier(const DeclSpec &DS,
                                          SourceLocation StartLoc,
                                          SourceLocation EndLoc);
-  void ParseUnderlyingTypeSpecifier(DeclSpec &DS);
   void ParseAtomicSpecifier(DeclSpec &DS);
 
   ExprResult ParseAlignArgument(SourceLocation Start,
@@ -3004,6 +3003,8 @@ class Parser : public CodeCompletionHandler {
          SourceLocation &EllipsisLoc);
   void ParseBracketDeclarator(Declarator &D);
   void ParseMisplacedBracketDeclarator(Declarator &D);
+  bool MaybeParseTypeTransformTypeSpecifier(DeclSpec &DS);
+  DeclSpec::TST TypeTransformTokToDeclSpec();
 
   //===--------------------------------------------------------------------===//
   // C++ 7: Declarations [dcl.dcl]

diff  --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h
index be94dabb622a6..8115574852686 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -32,6 +32,7 @@
 #include "clang/Lex/Token.h"
 #include "clang/Sema/Ownership.h"
 #include "clang/Sema/ParsedAttr.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -290,7 +291,9 @@ class DeclSpec {
   static const TST TST_typeofExpr = clang::TST_typeofExpr;
   static const TST TST_decltype = clang::TST_decltype;
   static const TST TST_decltype_auto = clang::TST_decltype_auto;
-  static const TST TST_underlyingType = clang::TST_underlyingType;
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait)                                     \
+  static const TST TST_##Trait = clang::TST_##Trait;
+#include "clang/Basic/TransformTypeTraits.def"
   static const TST TST_auto = clang::TST_auto;
   static const TST TST_auto_type = clang::TST_auto_type;
   static const TST TST_unknown_anytype = clang::TST_unknown_anytype;
@@ -333,7 +336,7 @@ class DeclSpec {
   /*TypeSpecifierWidth*/ unsigned TypeSpecWidth : 2;
   /*TSC*/unsigned TypeSpecComplex : 2;
   /*TSS*/unsigned TypeSpecSign : 2;
-  /*TST*/unsigned TypeSpecType : 6;
+  /*TST*/unsigned TypeSpecType : 7;
   unsigned TypeAltiVecVector : 1;
   unsigned TypeAltiVecPixel : 1;
   unsigned TypeAltiVecBool : 1;
@@ -400,8 +403,8 @@ class DeclSpec {
   ObjCDeclSpec *ObjCQualifiers;
 
   static bool isTypeRep(TST T) {
-    return (T == TST_typename || T == TST_typeofType ||
-            T == TST_underlyingType || T == TST_atomic);
+    return T == TST_atomic || T == TST_typename || T == TST_typeofType ||
+           isTransformTypeTrait(T);
   }
   static bool isExprRep(TST T) {
     return (T == TST_typeofExpr || T == TST_decltype || T == TST_bitint);
@@ -418,6 +421,14 @@ class DeclSpec {
             T == TST_interface || T == TST_union ||
             T == TST_class);
   }
+  static bool isTransformTypeTrait(TST T) {
+    ArrayRef<TST> Traits = {
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) TST_##Trait,
+#include "clang/Basic/TransformTypeTraits.def"
+    };
+
+    return T >= Traits.front() && T <= Traits.back();
+  }
 
   DeclSpec(AttributeFactory &attrFactory)
       : StorageClassSpec(SCS_unspecified),
@@ -522,7 +533,7 @@ class DeclSpec {
   }
 
   SourceRange getTypeofParensRange() const { return TypeofParensRange; }
-  void setTypeofParensRange(SourceRange range) { TypeofParensRange = range; }
+  void setTypeArgumentRange(SourceRange range) { TypeofParensRange = range; }
 
   bool hasAutoTypeSpec() const {
     return (TypeSpecType == TST_auto || TypeSpecType == TST_auto_type ||

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 6908eaf8ff954..75b6c72d902d7 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2506,8 +2506,23 @@ class Sema final {
   /// If AsUnevaluated is false, E is treated as though it were an evaluated
   /// context, such as when building a type for decltype(auto).
   QualType BuildDecltypeType(Expr *E, bool AsUnevaluated = true);
-  QualType BuildUnaryTransformType(QualType BaseType,
-                                   UnaryTransformType::UTTKind UKind,
+
+  using UTTKind = UnaryTransformType::UTTKind;
+  QualType BuildUnaryTransformType(QualType BaseType, UTTKind UKind,
+                                   SourceLocation Loc);
+  QualType BuiltinEnumUnderlyingType(QualType BaseType, SourceLocation Loc);
+  QualType BuiltinAddPointer(QualType BaseType, SourceLocation Loc);
+  QualType BuiltinRemovePointer(QualType BaseType, SourceLocation Loc);
+  QualType BuiltinDecay(QualType BaseType, SourceLocation Loc);
+  QualType BuiltinAddReference(QualType BaseType, UTTKind UKind,
+                               SourceLocation Loc);
+  QualType BuiltinRemoveExtent(QualType BaseType, UTTKind UKind,
+                               SourceLocation Loc);
+  QualType BuiltinRemoveReference(QualType BaseType, UTTKind UKind,
+                                  SourceLocation Loc);
+  QualType BuiltinChangeCVRQualifiers(QualType BaseType, UTTKind UKind,
+                                      SourceLocation Loc);
+  QualType BuiltinChangeSignedness(QualType BaseType, UTTKind UKind,
                                    SourceLocation Loc);
 
   //===--------------------------------------------------------------------===//

diff  --git a/clang/include/clang/module.modulemap b/clang/include/clang/module.modulemap
index 01bce77718b35..ef055b599c0ae 100644
--- a/clang/include/clang/module.modulemap
+++ b/clang/include/clang/module.modulemap
@@ -71,6 +71,7 @@ module Clang_Basic {
   textual header "Basic/RISCVVTypes.def"
   textual header "Basic/Sanitizers.def"
   textual header "Basic/TargetCXXABI.def"
+  textual header "Basic/TransformTypeTraits.def"
 
   module * { export * }
 }

diff  --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 2c2f4661a95ef..45ec85fefa9d5 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -10782,7 +10782,8 @@ unsigned ASTContext::getIntWidth(QualType T) const {
 }
 
 QualType ASTContext::getCorrespondingUnsignedType(QualType T) const {
-  assert((T->hasSignedIntegerRepresentation() || T->isSignedFixedPointType()) &&
+  assert((T->hasIntegerRepresentation() || T->isEnumeralType() ||
+          T->isFixedPointType()) &&
          "Unexpected type");
 
   // Turn <4 x signed int> -> <4 x unsigned int>
@@ -10800,8 +10801,11 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const {
     T = ETy->getDecl()->getIntegerType();
 
   switch (T->castAs<BuiltinType>()->getKind()) {
+  case BuiltinType::Char_U:
+    // Plain `char` is mapped to `unsigned char` even if it's already unsigned
   case BuiltinType::Char_S:
   case BuiltinType::SChar:
+  case BuiltinType::Char8:
     return UnsignedCharTy;
   case BuiltinType::Short:
     return UnsignedShortTy;
@@ -10815,7 +10819,7 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const {
     return UnsignedInt128Ty;
   // wchar_t is special. It is either signed or not, but when it's signed,
   // there's no matching "unsigned wchar_t". Therefore we return the unsigned
-  // version of it's underlying type instead.
+  // version of its underlying type instead.
   case BuiltinType::WChar_S:
     return getUnsignedWCharType();
 
@@ -10844,13 +10848,16 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const {
   case BuiltinType::SatLongFract:
     return SatUnsignedLongFractTy;
   default:
-    llvm_unreachable("Unexpected signed integer or fixed point type");
+    assert((T->hasUnsignedIntegerRepresentation() ||
+            T->isUnsignedFixedPointType()) &&
+           "Unexpected signed integer or fixed point type");
+    return T;
   }
 }
 
 QualType ASTContext::getCorrespondingSignedType(QualType T) const {
-  assert((T->hasUnsignedIntegerRepresentation() ||
-          T->isUnsignedFixedPointType()) &&
+  assert((T->hasIntegerRepresentation() || T->isEnumeralType() ||
+          T->isFixedPointType()) &&
          "Unexpected type");
 
   // Turn <4 x unsigned int> -> <4 x signed int>
@@ -10868,8 +10875,11 @@ QualType ASTContext::getCorrespondingSignedType(QualType T) const {
     T = ETy->getDecl()->getIntegerType();
 
   switch (T->castAs<BuiltinType>()->getKind()) {
+  case BuiltinType::Char_S:
+    // Plain `char` is mapped to `signed char` even if it's already signed
   case BuiltinType::Char_U:
   case BuiltinType::UChar:
+  case BuiltinType::Char8:
     return SignedCharTy;
   case BuiltinType::UShort:
     return ShortTy;
@@ -10883,7 +10893,7 @@ QualType ASTContext::getCorrespondingSignedType(QualType T) const {
     return Int128Ty;
   // wchar_t is special. It is either unsigned or not, but when it's unsigned,
   // there's no matching "signed wchar_t". Therefore we return the signed
-  // version of it's underlying type instead.
+  // version of its underlying type instead.
   case BuiltinType::WChar_U:
     return getSignedWCharType();
 
@@ -10912,7 +10922,10 @@ QualType ASTContext::getCorrespondingSignedType(QualType T) const {
   case BuiltinType::SatULongFract:
     return SatLongFractTy;
   default:
-    llvm_unreachable("Unexpected unsigned integer or fixed point type");
+    assert(
+        (T->hasSignedIntegerRepresentation() || T->isSignedFixedPointType()) &&
+        "Unexpected signed integer or fixed point type");
+    return T;
   }
 }
 

diff  --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index fc5a5909ad669..46229a0843ef1 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -3980,16 +3980,22 @@ 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';
+    Out << "u";
 
+    StringRef BuiltinName;
     switch (T->getUTTKind()) {
-      case UnaryTransformType::EnumUnderlyingType:
-        Out << "3eut";
-        break;
+#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait)                                  \
+  case UnaryTransformType::Enum:                                               \
+    BuiltinName = "__" #Trait;                                                 \
+    break;
+#include "clang/Basic/TransformTypeTraits.def"
     }
+    Out << BuiltinName.size() << BuiltinName;
   }
 
+  Out << "I";
   mangleType(T->getBaseType());
+  Out << "E";
 }
 
 void CXXNameMangler::mangleType(const AutoType *T) {

diff  --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
index 74ef4c3330280..ae9c85e7542b3 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -1,4 +1,5 @@
 #include "clang/AST/JSONNodeDumper.h"
+#include "clang/AST/Type.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/Specifiers.h"
 #include "clang/Lex/Lexer.h"
@@ -662,9 +663,11 @@ void JSONNodeDumper::VisitUnresolvedUsingType(const UnresolvedUsingType *UUT) {
 
 void JSONNodeDumper::VisitUnaryTransformType(const UnaryTransformType *UTT) {
   switch (UTT->getUTTKind()) {
-  case UnaryTransformType::EnumUnderlyingType:
-    JOS.attribute("transformKind", "underlying_type");
+#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait)                                  \
+  case UnaryTransformType::Enum:                                               \
+    JOS.attribute("transformKind", #Trait);                                    \
     break;
+#include "clang/Basic/TransformTypeTraits.def"
   }
 }
 

diff  --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index c3da5a4cf942b..f9f149bc883f6 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1551,9 +1551,11 @@ void TextNodeDumper::VisitTypedefType(const TypedefType *T) {
 
 void TextNodeDumper::VisitUnaryTransformType(const UnaryTransformType *T) {
   switch (T->getUTTKind()) {
-  case UnaryTransformType::EnumUnderlyingType:
-    OS << " underlying_type";
+#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait)                                  \
+  case UnaryTransformType::Enum:                                               \
+    OS << " " #Trait;                                                          \
     break;
+#include "clang/Basic/TransformTypeTraits.def"
   }
 }
 

diff  --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 3cb200140b9fa..a7da9fd7e9e34 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -22,6 +22,7 @@
 #include "clang/AST/PrettyPrinter.h"
 #include "clang/AST/TemplateBase.h"
 #include "clang/AST/TemplateName.h"
+#include "clang/AST/TextNodeDumper.h"
 #include "clang/AST/Type.h"
 #include "clang/Basic/AddressSpaces.h"
 #include "clang/Basic/ExceptionSpecificationType.h"
@@ -32,6 +33,7 @@
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/Specifiers.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Twine.h"
@@ -1140,29 +1142,19 @@ void TypePrinter::printUnaryTransformBefore(const UnaryTransformType *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;
-  }
-
-  printBefore(T->getBaseType(), OS);
+  static llvm::DenseMap<int, const char *> Transformation = {{
+#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait)                                  \
+  {UnaryTransformType::Enum, "__" #Trait},
+#include "clang/Basic/TransformTypeTraits.def"
+  }};
+  OS << Transformation[T->getUTTKind()] << '(';
+  print(T->getBaseType(), OS, StringRef());
+  OS << ')';
+  spaceBeforePlaceHolder(OS);
 }
 
 void TypePrinter::printUnaryTransformAfter(const UnaryTransformType *T,
-                                           raw_ostream &OS) {
-  IncludeStrongLifetimeRAII Strong(Policy);
-
-  switch (T->getUTTKind()) {
-    case UnaryTransformType::EnumUnderlyingType:
-      return;
-  }
-
-  printAfter(T->getBaseType(), OS);
-}
+                                           raw_ostream &OS) {}
 
 void TypePrinter::printAutoBefore(const AutoType *T, raw_ostream &OS) {
   // If the type has been deduced, do not print 'auto'.

diff  --git a/clang/lib/Format/FormatToken.cpp b/clang/lib/Format/FormatToken.cpp
index 832af463206c8..f9f0d712bc165 100644
--- a/clang/lib/Format/FormatToken.cpp
+++ b/clang/lib/Format/FormatToken.cpp
@@ -56,7 +56,8 @@ bool FormatToken::isSimpleTypeSpecifier() const {
   case tok::kw___ibm128:
   case tok::kw_wchar_t:
   case tok::kw_bool:
-  case tok::kw___underlying_type:
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
   case tok::annot_typename:
   case tok::kw_char8_t:
   case tok::kw_char16_t:

diff  --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h
index 7d963cf6af7f7..1ce64f7946664 100644
--- a/clang/lib/Format/FormatToken.h
+++ b/clang/lib/Format/FormatToken.h
@@ -677,7 +677,8 @@ struct FormatToken {
     case tok::kw_static_assert:
     case tok::kw__Atomic:
     case tok::kw___attribute:
-    case tok::kw___underlying_type:
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
     case tok::kw_requires:
       return true;
     default:

diff  --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index b0a1c691c771a..eb0ee91da1f12 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -317,8 +317,10 @@ class AnnotatingParser {
       if (PrevNonComment->is(tok::kw___attribute)) {
         OpeningParen.setType(TT_AttributeParen);
       } else if (PrevNonComment->isOneOf(TT_TypenameMacro, tok::kw_decltype,
-                                         tok::kw_typeof, tok::kw__Atomic,
-                                         tok::kw___underlying_type)) {
+                                         tok::kw_typeof,
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) tok::kw___##Trait,
+#include "clang/Basic/TransformTypeTraits.def"
+                                         tok::kw__Atomic)) {
         OpeningParen.setType(TT_TypeDeclarationParen);
         // decltype() and typeof() usually contain expressions.
         if (PrevNonComment->isOneOf(tok::kw_decltype, tok::kw_typeof))

diff  --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp
index f3be2107f985f..78ab8bae2f610 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -1663,7 +1663,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
               .Case("__array_rank", true)
               .Case("__array_extent", true)
               .Case("__reference_binds_to_temporary", true)
-              .Case("__underlying_type", true)
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) .Case("__" #Trait, true)
+#include "clang/Basic/TransformTypeTraits.def"
               .Default(false);
         } else {
           return llvm::StringSwitch<bool>(II->getName())

diff  --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 39ba93ee33859..70dd5e257242e 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -3471,7 +3471,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
       // typedef-name
     case tok::kw___super:
     case tok::kw_decltype:
-    case tok::identifier: {
+    case tok::identifier:
+    ParseIdentifier: {
       // This identifier can only be a typedef name if we haven't already seen
       // a type-specifier.  Without this check we misparse:
       //  typedef int X; struct Y { short X; };  as 'short int'.
@@ -3664,7 +3665,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
             }
           }
           ConsumedEnd = Tok.getLocation();
-          DS.setTypeofParensRange(Tracker.getRange());
+          DS.setTypeArgumentRange(Tracker.getRange());
           // Even if something went wrong above, continue as if we've seen
           // `decltype(auto)`.
           isInvalid = DS.SetTypeSpecType(TST_decltype_auto, Loc, PrevSpec,
@@ -4206,8 +4207,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
       HandlePragmaMSPointersToMembers();
       continue;
 
-    case tok::kw___underlying_type:
-      ParseUnderlyingTypeSpecifier(DS);
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
+      // HACK: libstdc++ already uses '__remove_cv' as an alias template so we
+      // work around this by expecting all transform type traits to be suffixed
+      // with '('. They're an identifier otherwise.
+      if (!MaybeParseTypeTransformTypeSpecifier(DS))
+        goto ParseIdentifier;
       continue;
 
     case tok::kw__Atomic:
@@ -7445,7 +7451,7 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
   ExprResult Operand = Actions.CorrectDelayedTyposInExpr(
       ParseExprAfterUnaryExprOrTypeTrait(OpTok, isCastExpr, CastTy, CastRange));
   if (hasParens)
-    DS.setTypeofParensRange(CastRange);
+    DS.setTypeArgumentRange(CastRange);
 
   if (CastRange.getEnd().isInvalid())
     // FIXME: Not accurate, the range gets one token more than it should.
@@ -7515,7 +7521,7 @@ void Parser::ParseAtomicSpecifier(DeclSpec &DS) {
   if (T.getCloseLocation().isInvalid())
     return;
 
-  DS.setTypeofParensRange(T.getRange());
+  DS.setTypeArgumentRange(T.getRange());
   DS.SetRangeEnd(T.getCloseLocation());
 
   const char *PrevSpec = nullptr;

diff  --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 8dfa91eae3b2e..4510ff8470fa1 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -18,6 +18,7 @@
 #include "clang/Basic/CharInfo.h"
 #include "clang/Basic/OperatorKinds.h"
 #include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TokenKinds.h"
 #include "clang/Parse/ParseDiagnostic.h"
 #include "clang/Parse/Parser.h"
 #include "clang/Parse/RAIIObjectsForParser.h"
@@ -1021,7 +1022,7 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
     EndLoc = Tok.getAnnotationEndLoc();
     // Unfortunately, we don't know the LParen source location as the annotated
     // token doesn't have it.
-    DS.setTypeofParensRange(SourceRange(SourceLocation(), EndLoc));
+    DS.setTypeArgumentRange(SourceRange(SourceLocation(), EndLoc));
     ConsumeAnnotationToken();
     if (Result.isInvalid()) {
       DS.SetTypeSpecError();
@@ -1085,7 +1086,7 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
 
     // Match the ')'
     T.consumeClose();
-    DS.setTypeofParensRange(T.getRange());
+    DS.setTypeArgumentRange(T.getRange());
     if (T.getCloseLocation().isInvalid()) {
       DS.SetTypeSpecError();
       // FIXME: this should return the location of the last token
@@ -1142,35 +1143,48 @@ void Parser::AnnotateExistingDecltypeSpecifier(const DeclSpec &DS,
   PP.AnnotateCachedTokens(Tok);
 }
 
-void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) {
-  assert(Tok.is(tok::kw___underlying_type) &&
-         "Not an underlying type specifier");
+DeclSpec::TST Parser::TypeTransformTokToDeclSpec() {
+  switch (Tok.getKind()) {
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait)                                     \
+  case tok::kw___##Trait:                                                      \
+    return DeclSpec::TST_##Trait;
+#include "clang/Basic/TransformTypeTraits.def"
+  default:
+    llvm_unreachable("passed in an unhandled type transformation built-in");
+  }
+}
 
+bool Parser::MaybeParseTypeTransformTypeSpecifier(DeclSpec &DS) {
+  if (!NextToken().is(tok::l_paren)) {
+    Tok.setKind(tok::identifier);
+    return false;
+  }
+  DeclSpec::TST TypeTransformTST = TypeTransformTokToDeclSpec();
   SourceLocation StartLoc = ConsumeToken();
+
   BalancedDelimiterTracker T(*this, tok::l_paren);
-  if (T.expectAndConsume(diag::err_expected_lparen_after, "__underlying_type",
-                         tok::r_paren)) {
-    return;
-  }
+  if (T.expectAndConsume(diag::err_expected_lparen_after, Tok.getName(),
+                         tok::r_paren))
+    return true;
 
   TypeResult Result = ParseTypeName();
   if (Result.isInvalid()) {
     SkipUntil(tok::r_paren, StopAtSemi);
-    return;
+    return true;
   }
 
-  // Match the ')'
   T.consumeClose();
   if (T.getCloseLocation().isInvalid())
-    return;
+    return true;
 
   const char *PrevSpec = nullptr;
   unsigned DiagID;
-  if (DS.SetTypeSpecType(DeclSpec::TST_underlyingType, StartLoc, PrevSpec,
-                         DiagID, Result.get(),
+  if (DS.SetTypeSpecType(TypeTransformTST, StartLoc, PrevSpec, DiagID,
+                         Result.get(),
                          Actions.getASTContext().getPrintingPolicy()))
     Diag(StartLoc, DiagID) << PrevSpec;
-  DS.setTypeofParensRange(T.getRange());
+  DS.setTypeArgumentRange(T.getRange());
+  return true;
 }
 
 /// ParseBaseTypeSpecifier - Parse a C++ base-type-specifier which is either a
@@ -1525,28 +1539,58 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
   if (TagType == DeclSpec::TST_struct && Tok.isNot(tok::identifier) &&
       !Tok.isAnnotation() && Tok.getIdentifierInfo() &&
       Tok.isOneOf(
-          tok::kw___is_abstract, tok::kw___is_aggregate,
-          tok::kw___is_arithmetic, tok::kw___is_array, tok::kw___is_assignable,
-          tok::kw___is_base_of, tok::kw___is_class, tok::kw___is_complete_type,
-          tok::kw___is_compound, tok::kw___is_const, tok::kw___is_constructible,
-          tok::kw___is_convertible, tok::kw___is_convertible_to,
-          tok::kw___is_destructible, tok::kw___is_empty, tok::kw___is_enum,
-          tok::kw___is_floating_point, tok::kw___is_final,
-          tok::kw___is_function, tok::kw___is_fundamental,
-          tok::kw___is_integral, tok::kw___is_interface_class,
-          tok::kw___is_literal, tok::kw___is_lvalue_expr,
-          tok::kw___is_lvalue_reference, tok::kw___is_member_function_pointer,
-          tok::kw___is_member_object_pointer, tok::kw___is_member_pointer,
-          tok::kw___is_nothrow_assignable, tok::kw___is_nothrow_constructible,
-          tok::kw___is_nothrow_destructible, tok::kw___is_object,
-          tok::kw___is_pod, tok::kw___is_pointer, tok::kw___is_polymorphic,
-          tok::kw___is_reference, tok::kw___is_rvalue_expr,
-          tok::kw___is_rvalue_reference, tok::kw___is_same, tok::kw___is_scalar,
-          tok::kw___is_sealed, tok::kw___is_signed,
-          tok::kw___is_standard_layout, tok::kw___is_trivial,
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) tok::kw___##Trait,
+#include "clang/Basic/TransformTypeTraits.def"
+          tok::kw___is_abstract,
+          tok::kw___is_aggregate,
+          tok::kw___is_arithmetic,
+          tok::kw___is_array,
+          tok::kw___is_assignable,
+          tok::kw___is_base_of,
+          tok::kw___is_class,
+          tok::kw___is_complete_type,
+          tok::kw___is_compound,
+          tok::kw___is_const,
+          tok::kw___is_constructible,
+          tok::kw___is_convertible,
+          tok::kw___is_convertible_to,
+          tok::kw___is_destructible,
+          tok::kw___is_empty,
+          tok::kw___is_enum,
+          tok::kw___is_floating_point,
+          tok::kw___is_final,
+          tok::kw___is_function,
+          tok::kw___is_fundamental,
+          tok::kw___is_integral,
+          tok::kw___is_interface_class,
+          tok::kw___is_literal,
+          tok::kw___is_lvalue_expr,
+          tok::kw___is_lvalue_reference,
+          tok::kw___is_member_function_pointer,
+          tok::kw___is_member_object_pointer,
+          tok::kw___is_member_pointer,
+          tok::kw___is_nothrow_assignable,
+          tok::kw___is_nothrow_constructible,
+          tok::kw___is_nothrow_destructible,
+          tok::kw___is_object,
+          tok::kw___is_pod,
+          tok::kw___is_pointer,
+          tok::kw___is_polymorphic,
+          tok::kw___is_reference,
+          tok::kw___is_rvalue_expr,
+          tok::kw___is_rvalue_reference,
+          tok::kw___is_same,
+          tok::kw___is_scalar,
+          tok::kw___is_sealed,
+          tok::kw___is_signed,
+          tok::kw___is_standard_layout,
+          tok::kw___is_trivial,
           tok::kw___is_trivially_assignable,
-          tok::kw___is_trivially_constructible, tok::kw___is_trivially_copyable,
-          tok::kw___is_union, tok::kw___is_unsigned, tok::kw___is_void,
+          tok::kw___is_trivially_constructible,
+          tok::kw___is_trivially_copyable,
+          tok::kw___is_union,
+          tok::kw___is_unsigned,
+          tok::kw___is_void,
           tok::kw___is_volatile))
     // GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the
     // name of struct templates, but some are keywords in GCC >= 4.3

diff  --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 354908a5d250a..588f4cf6aa8c6 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -1038,9 +1038,10 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
     return ParseCastExpression(ParseKind, isAddressOfOperand, isTypeCast,
                                isVectorLiteral, NotPrimaryExpression);
 
-  case tok::identifier: {      // primary-expression: identifier
-                               // unqualified-id: identifier
-                               // constant: enumeration-constant
+  case tok::identifier:
+  ParseIdentifier: {    // primary-expression: identifier
+                        // unqualified-id: identifier
+                        // constant: enumeration-constant
     // Turn a potentially qualified name into a annot_typename or
     // annot_cxxscope if it would be valid.  This handles things like x::y, etc.
     if (getLangOpts().CPlusPlus) {
@@ -1113,6 +1114,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
           REVERTIBLE_TYPE_TRAIT(__is_unsigned);
           REVERTIBLE_TYPE_TRAIT(__is_void);
           REVERTIBLE_TYPE_TRAIT(__is_volatile);
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait)                                     \
+  REVERTIBLE_TYPE_TRAIT(RTT_JOIN(__, Trait));
+#include "clang/Basic/TransformTypeTraits.def"
 #undef REVERTIBLE_TYPE_TRAIT
 #undef RTT_JOIN
         }
@@ -1739,6 +1743,17 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
                                    PreferredType.get(Tok.getLocation()));
     return ExprError();
   }
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
+    // HACK: libstdc++ uses some of the transform-type-traits as alias
+    // templates, so we need to work around this.
+    if (!NextToken().is(tok::l_paren)) {
+      Tok.setKind(tok::identifier);
+      Diag(Tok, diag::ext_keyword_as_ident)
+          << Tok.getIdentifierInfo()->getName() << 0;
+      goto ParseIdentifier;
+    }
+    goto ExpectedExpression;
   case tok::l_square:
     if (getLangOpts().CPlusPlus11) {
       if (getLangOpts().ObjC) {
@@ -1766,6 +1781,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
     }
     [[fallthrough]];
   default:
+  ExpectedExpression:
     NotCastExpr = true;
     return ExprError();
   }

diff  --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 2f30075f7c3cd..b2e9aa1f6a146 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -14,6 +14,7 @@
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/Basic/PrettyStackTrace.h"
+#include "clang/Basic/TokenKinds.h"
 #include "clang/Lex/LiteralSupport.h"
 #include "clang/Parse/ParseDiagnostic.h"
 #include "clang/Parse/Parser.h"
@@ -21,6 +22,7 @@
 #include "clang/Sema/DeclSpec.h"
 #include "clang/Sema/ParsedTemplate.h"
 #include "clang/Sema/Scope.h"
+#include "llvm/Support/Compiler.h"
 #include "llvm/Support/ErrorHandling.h"
 #include <numeric>
 
@@ -2819,6 +2821,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType,
   //   identifier
   //   template-id (when it hasn't already been annotated)
   if (Tok.is(tok::identifier)) {
+  ParseIdentifier:
     // Consume the identifier.
     IdentifierInfo *Id = Tok.getIdentifierInfo();
     SourceLocation IdLoc = ConsumeToken();
@@ -3053,9 +3056,20 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType,
     return false;
   }
 
-  Diag(Tok, diag::err_expected_unqualified_id)
-    << getLangOpts().CPlusPlus;
-  return true;
+  switch (Tok.getKind()) {
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
+    if (!NextToken().is(tok::l_paren)) {
+      Tok.setKind(tok::identifier);
+      Diag(Tok, diag::ext_keyword_as_ident)
+          << Tok.getIdentifierInfo()->getName() << 0;
+      goto ParseIdentifier;
+    }
+    LLVM_FALLTHROUGH;
+  default:
+    Diag(Tok, diag::err_expected_unqualified_id) << getLangOpts().CPlusPlus;
+    return true;
+  }
 }
 
 /// ParseCXXNewExpression - Parse a C++ new-expression. New is used to allocate

diff  --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 530e0de9eb9ff..fc515f192a727 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -14,6 +14,7 @@
 #include "clang/AST/PrettyDeclStackTrace.h"
 #include "clang/Basic/Attributes.h"
 #include "clang/Basic/PrettyStackTrace.h"
+#include "clang/Basic/TokenKinds.h"
 #include "clang/Parse/LoopHint.h"
 #include "clang/Parse/Parser.h"
 #include "clang/Parse/RAIIObjectsForParser.h"
@@ -188,7 +189,8 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
     Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement);
     return StmtError();
 
-  case tok::identifier: {
+  case tok::identifier:
+  ParseIdentifier: {
     Token Next = NextToken();
     if (Next.is(tok::colon)) { // C99 6.8.1: labeled-statement
       // Both C++11 and GNU attributes preceding the label appertain to the
@@ -261,7 +263,19 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
       return StmtError();
     }
 
-    return ParseExprStatement(StmtCtx);
+    switch (Tok.getKind()) {
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
+      if (NextToken().is(tok::less)) {
+        Tok.setKind(tok::identifier);
+        Diag(Tok, diag::ext_keyword_as_ident)
+            << Tok.getIdentifierInfo()->getName() << 0;
+        goto ParseIdentifier;
+      }
+      LLVM_FALLTHROUGH;
+    default:
+      return ParseExprStatement(StmtCtx);
+    }
   }
 
   case tok::kw___attribute: {

diff  --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index 8f4558430fad1..9cd405a40efa1 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -161,7 +161,9 @@ Parser::TPResult Parser::TryConsumeDeclarationSpecifier() {
     [[fallthrough]];
   case tok::kw_typeof:
   case tok::kw___attribute:
-  case tok::kw___underlying_type: {
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
+  {
     ConsumeToken();
     if (Tok.isNot(tok::l_paren))
       return TPResult::Error;
@@ -1682,8 +1684,8 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
     return TPResult::True;
   }
 
-  // C++0x type traits support
-  case tok::kw___underlying_type:
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
     return TPResult::True;
 
   // C11 _Atomic
@@ -1721,7 +1723,8 @@ bool Parser::isCXXDeclarationSpecifierAType() {
   case tok::annot_template_id:
   case tok::annot_typename:
   case tok::kw_typeof:
-  case tok::kw___underlying_type:
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
     return true;
 
     // elaborated-type-specifier

diff  --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp
index d4dc790c008a2..af31105d13434 100644
--- a/clang/lib/Sema/DeclSpec.cpp
+++ b/clang/lib/Sema/DeclSpec.cpp
@@ -18,6 +18,7 @@
 #include "clang/AST/TypeLoc.h"
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Specifiers.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Sema/ParsedTemplate.h"
 #include "clang/Sema/Sema.h"
@@ -389,7 +390,8 @@ bool Declarator::isDeclarationOfFunction() const {
         return E->getType()->isFunctionType();
       return false;
 
-    case TST_underlyingType:
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case TST_##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
     case TST_typename:
     case TST_typeofType: {
       QualType QT = DS.getRepAsType().get();
@@ -576,7 +578,10 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T,
   case DeclSpec::TST_auto_type:   return "__auto_type";
   case DeclSpec::TST_decltype:    return "(decltype)";
   case DeclSpec::TST_decltype_auto: return "decltype(auto)";
-  case DeclSpec::TST_underlyingType: return "__underlying_type";
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait)                                     \
+  case DeclSpec::TST_##Trait:                                                  \
+    return "__" #Trait;
+#include "clang/Basic/TransformTypeTraits.def"
   case DeclSpec::TST_unknown_anytype: return "__unknown_anytype";
   case DeclSpec::TST_atomic: return "_Atomic";
   case DeclSpec::TST_BFloat16: return "__bf16";

diff  --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 94009d33fa94e..e689a05efacd7 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -145,7 +145,8 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const {
   case tok::kw___ibm128:
   case tok::kw_wchar_t:
   case tok::kw_bool:
-  case tok::kw___underlying_type:
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
   case tok::kw___auto_type:
     return true;
 
@@ -5923,7 +5924,8 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
   switch (DS.getTypeSpecType()) {
   case DeclSpec::TST_typename:
   case DeclSpec::TST_typeofType:
-  case DeclSpec::TST_underlyingType:
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case DeclSpec::TST_##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
   case DeclSpec::TST_atomic: {
     // Grab the type from the parser.
     TypeSourceInfo *TSI = nullptr;

diff  --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index 790792f77b24f..285bf67398f16 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -858,7 +858,8 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
   switch (DS.getTypeSpecType()) {
   case TST_typename:
   case TST_typeofType:
-  case TST_underlyingType:
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case TST_##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
   case TST_atomic: {
     QualType T = DS.getRepAsType().get();
     if (!T.isNull() && T->containsUnexpandedParameterPack())

diff  --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 14b2d2e74f3f2..5bd0dac503621 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -19,9 +19,11 @@
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
 #include "clang/AST/TypeLoc.h"
 #include "clang/AST/TypeLocVisitor.h"
 #include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/Specifiers.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Lex/Preprocessor.h"
@@ -33,6 +35,7 @@
 #include "clang/Sema/SemaInternal.h"
 #include "clang/Sema/Template.h"
 #include "clang/Sema/TemplateInstCallback.h"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringSwitch.h"
@@ -1247,6 +1250,18 @@ getImageAccess(const ParsedAttributesView &Attrs) {
   return OpenCLAccessAttr::Keyword_read_only;
 }
 
+static UnaryTransformType::UTTKind
+TSTToUnaryTransformType(DeclSpec::TST SwitchTST) {
+  switch (SwitchTST) {
+#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait)                                  \
+  case TST_##Trait:                                                            \
+    return UnaryTransformType::Enum;
+#include "clang/Basic/TransformTypeTraits.def"
+  default:
+    llvm_unreachable("attempted to parse a non-unary transform builtin");
+  }
+}
+
 /// Convert the specified declspec to the appropriate type
 /// object.
 /// \param state Specifies the declarator containing the declaration specifier
@@ -1628,12 +1643,13 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
     }
     break;
   }
-  case DeclSpec::TST_underlyingType:
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case DeclSpec::TST_##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
     Result = S.GetTypeFromParser(DS.getRepAsType());
-    assert(!Result.isNull() && "Didn't get a type for __underlying_type?");
-    Result = S.BuildUnaryTransformType(Result,
-                                       UnaryTransformType::EnumUnderlyingType,
-                                       DS.getTypeSpecTypeLoc());
+    assert(!Result.isNull() && "Didn't get a type for the transformation?");
+    Result = S.BuildUnaryTransformType(
+        Result, TSTToUnaryTransformType(DS.getTypeSpecType()),
+        DS.getTypeSpecTypeLoc());
     if (Result.isNull()) {
       Result = Context.IntTy;
       declarator.setInvalidType(true);
@@ -6067,8 +6083,7 @@ namespace {
       TL.setRParenLoc(DS.getTypeofParensRange().getEnd());
     }
     void VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
-      // FIXME: This holds only because we only have one unary transform.
-      assert(DS.getTypeSpecType() == DeclSpec::TST_underlyingType);
+      assert(DS.isTransformTypeTrait(DS.getTypeSpecType()));
       TL.setKWLoc(DS.getTypeSpecTypeLoc());
       TL.setParensRange(DS.getTypeofParensRange());
       assert(DS.getRepAsType());
@@ -9205,39 +9220,259 @@ QualType Sema::BuildDecltypeType(Expr *E, bool AsUnevaluated) {
   return Context.getDecltypeType(E, getDecltypeForExpr(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 QualType GetEnumUnderlyingType(Sema &S, QualType BaseType,
+                                      SourceLocation Loc) {
+  assert(BaseType->isEnumeralType());
+  EnumDecl *ED = BaseType->castAs<EnumType>()->getDecl();
+  assert(ED && "EnumType has no EnumDecl");
 
-        EnumDecl *ED = BaseType->castAs<EnumType>()->getDecl();
-        assert(ED && "EnumType has no EnumDecl");
+  S.DiagnoseUseOfDecl(ED, Loc);
 
-        DiagnoseUseOfDecl(ED, Loc);
+  QualType Underlying = ED->getIntegerType();
+  assert(!Underlying.isNull());
 
-        Underlying = ED->getIntegerType();
-        assert(!Underlying.isNull());
-      }
-      return Context.getUnaryTransformType(BaseType, Underlying,
-                                        UnaryTransformType::EnumUnderlyingType);
+  return Underlying;
+}
+
+QualType Sema::BuiltinEnumUnderlyingType(QualType BaseType,
+                                         SourceLocation Loc) {
+  if (!BaseType->isEnumeralType()) {
+    Diag(Loc, diag::err_only_enums_have_underlying_types);
+    return QualType();
+  }
+
+  // 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();
+  }
+
+  return GetEnumUnderlyingType(*this, BaseType, Loc);
+}
+
+QualType Sema::BuiltinAddPointer(QualType BaseType, SourceLocation Loc) {
+  QualType Pointer = BaseType.isReferenceable() || BaseType->isVoidType()
+                         ? BuildPointerType(BaseType.getNonReferenceType(), Loc,
+                                            DeclarationName())
+                         : BaseType;
+
+  return Pointer.isNull() ? QualType() : Pointer;
+}
+
+QualType Sema::BuiltinRemovePointer(QualType BaseType, SourceLocation Loc) {
+  // We don't want block pointers or ObjectiveC's id type.
+  if (!BaseType->isAnyPointerType() || BaseType->isObjCIdType())
+    return BaseType;
+
+  return BaseType->getPointeeType();
+}
+
+QualType Sema::BuiltinDecay(QualType BaseType, SourceLocation Loc) {
+  QualType Underlying = BaseType.getNonReferenceType();
+  if (Underlying->isArrayType())
+    return Context.getDecayedType(Underlying);
+
+  if (Underlying->isFunctionType())
+    return BuiltinAddPointer(BaseType, Loc);
+
+  SplitQualType Split = Underlying.getSplitUnqualifiedType();
+  // std::decay is supposed to produce 'std::remove_cv', but since 'restrict' is
+  // in the same group of qualifiers as 'const' and 'volatile', we're extending
+  // '__decay(T)' so that it removes all qualifiers.
+  Split.Quals.removeCVRQualifiers();
+  return Context.getQualifiedType(Split);
+}
+
+QualType Sema::BuiltinAddReference(QualType BaseType, UTTKind UKind,
+                                   SourceLocation Loc) {
+  assert(LangOpts.CPlusPlus);
+  QualType Reference =
+      BaseType.isReferenceable()
+          ? BuildReferenceType(BaseType,
+                               UKind == UnaryTransformType::AddLvalueReference,
+                               Loc, DeclarationName())
+          : BaseType;
+  return Reference.isNull() ? QualType() : Reference;
+}
+
+QualType Sema::BuiltinRemoveExtent(QualType BaseType, UTTKind UKind,
+                                   SourceLocation Loc) {
+  if (UKind == UnaryTransformType::RemoveAllExtents)
+    return Context.getBaseElementType(BaseType);
+
+  if (const auto *AT = Context.getAsArrayType(BaseType))
+    return AT->getElementType();
+
+  return BaseType;
+}
+
+QualType Sema::BuiltinRemoveReference(QualType BaseType, UTTKind UKind,
+                                      SourceLocation Loc) {
+  assert(LangOpts.CPlusPlus);
+  QualType T = BaseType.getNonReferenceType();
+  if (UKind == UTTKind::RemoveCVRef &&
+      (T.isConstQualified() || T.isVolatileQualified())) {
+    Qualifiers Quals;
+    QualType Unqual = Context.getUnqualifiedArrayType(T, Quals);
+    Quals.removeConst();
+    Quals.removeVolatile();
+    T = Context.getQualifiedType(Unqual, Quals);
+  }
+  return T;
+}
+
+QualType Sema::BuiltinChangeCVRQualifiers(QualType BaseType, UTTKind UKind,
+                                          SourceLocation Loc) {
+  if ((BaseType->isReferenceType() && UKind != UTTKind::RemoveRestrict) ||
+      BaseType->isFunctionType())
+    return BaseType;
+
+  Qualifiers Quals;
+  QualType Unqual = Context.getUnqualifiedArrayType(BaseType, Quals);
+
+  if (UKind == UTTKind::RemoveConst || UKind == UTTKind::RemoveCV)
+    Quals.removeConst();
+  if (UKind == UTTKind::RemoveVolatile || UKind == UTTKind::RemoveCV)
+    Quals.removeVolatile();
+  if (UKind == UTTKind::RemoveRestrict)
+    Quals.removeRestrict();
+
+  return Context.getQualifiedType(Unqual, Quals);
+}
+
+static QualType ChangeIntegralSignedness(Sema &S, QualType BaseType,
+                                         bool IsMakeSigned,
+                                         SourceLocation Loc) {
+  if (BaseType->isEnumeralType()) {
+    QualType Underlying = GetEnumUnderlyingType(S, BaseType, Loc);
+    if (auto *BitInt = dyn_cast<BitIntType>(Underlying)) {
+      unsigned int Bits = BitInt->getNumBits();
+      if (Bits > 1)
+        return S.Context.getBitIntType(!IsMakeSigned, Bits);
+
+      S.Diag(Loc, diag::err_make_signed_integral_only)
+          << IsMakeSigned << /*_BitInt(1)*/ true << BaseType << 1 << Underlying;
+      return QualType();
     }
+    if (Underlying->isBooleanType()) {
+      S.Diag(Loc, diag::err_make_signed_integral_only)
+          << IsMakeSigned << /*_BitInt(1)*/ false << BaseType << 1
+          << Underlying;
+      return QualType();
+    }
+  }
+
+  bool Int128Unsupported = !S.Context.getTargetInfo().hasInt128Type();
+  std::array<CanQualType *, 6> AllSignedIntegers = {
+      &S.Context.SignedCharTy, &S.Context.ShortTy,    &S.Context.IntTy,
+      &S.Context.LongTy,       &S.Context.LongLongTy, &S.Context.Int128Ty};
+  ArrayRef<CanQualType *> AvailableSignedIntegers(
+      AllSignedIntegers.begin(), AllSignedIntegers.end() - Int128Unsupported);
+  std::array<CanQualType *, 6> AllUnsignedIntegers = {
+      &S.Context.UnsignedCharTy,     &S.Context.UnsignedShortTy,
+      &S.Context.UnsignedIntTy,      &S.Context.UnsignedLongTy,
+      &S.Context.UnsignedLongLongTy, &S.Context.UnsignedInt128Ty};
+  ArrayRef<CanQualType *> AvailableUnsignedIntegers(AllUnsignedIntegers.begin(),
+                                                    AllUnsignedIntegers.end() -
+                                                        Int128Unsupported);
+  ArrayRef<CanQualType *> *Consider =
+      IsMakeSigned ? &AvailableSignedIntegers : &AvailableUnsignedIntegers;
+
+  uint64_t BaseSize = S.Context.getTypeSize(BaseType);
+  auto *Result =
+      llvm::find_if(*Consider, [&S, BaseSize](const CanQual<Type> *T) {
+        return BaseSize == S.Context.getTypeSize(T->getTypePtr());
+      });
+
+  assert(Result != Consider->end());
+  return QualType((*Result)->getTypePtr(), 0);
+}
+
+QualType Sema::BuiltinChangeSignedness(QualType BaseType, UTTKind UKind,
+                                       SourceLocation Loc) {
+  bool IsMakeSigned = UKind == UnaryTransformType::MakeSigned;
+  if ((!BaseType->isIntegerType() && !BaseType->isEnumeralType()) ||
+      BaseType->isBooleanType() ||
+      (BaseType->isBitIntType() &&
+       BaseType->getAs<BitIntType>()->getNumBits() < 2)) {
+    Diag(Loc, diag::err_make_signed_integral_only)
+        << IsMakeSigned << BaseType->isBitIntType() << BaseType << 0;
+    return QualType();
+  }
+
+  bool IsNonIntIntegral =
+      BaseType->isChar16Type() || BaseType->isChar32Type() ||
+      BaseType->isWideCharType() || BaseType->isEnumeralType();
+
+  QualType Underlying =
+      IsNonIntIntegral
+          ? ChangeIntegralSignedness(*this, BaseType, IsMakeSigned, Loc)
+      : IsMakeSigned ? Context.getCorrespondingSignedType(BaseType)
+                     : Context.getCorrespondingUnsignedType(BaseType);
+  if (Underlying.isNull())
+    return Underlying;
+  return Context.getQualifiedType(Underlying, BaseType.getQualifiers());
+}
+
+QualType Sema::BuildUnaryTransformType(QualType BaseType, UTTKind UKind,
+                                       SourceLocation Loc) {
+  if (BaseType->isDependentType())
+    return Context.getUnaryTransformType(BaseType, BaseType, UKind);
+  QualType Result;
+  switch (UKind) {
+  case UnaryTransformType::EnumUnderlyingType: {
+    Result = BuiltinEnumUnderlyingType(BaseType, Loc);
+    break;
+  }
+  case UnaryTransformType::AddPointer: {
+    Result = BuiltinAddPointer(BaseType, Loc);
+    break;
+  }
+  case UnaryTransformType::RemovePointer: {
+    Result = BuiltinRemovePointer(BaseType, Loc);
+    break;
+  }
+  case UnaryTransformType::Decay: {
+    Result = BuiltinDecay(BaseType, Loc);
+    break;
+  }
+  case UnaryTransformType::AddLvalueReference:
+  case UnaryTransformType::AddRvalueReference: {
+    Result = BuiltinAddReference(BaseType, UKind, Loc);
+    break;
   }
-  llvm_unreachable("unknown unary transform type");
+  case UnaryTransformType::RemoveAllExtents:
+  case UnaryTransformType::RemoveExtent: {
+    Result = BuiltinRemoveExtent(BaseType, UKind, Loc);
+    break;
+  }
+  case UnaryTransformType::RemoveCVRef:
+  case UnaryTransformType::RemoveReference: {
+    Result = BuiltinRemoveReference(BaseType, UKind, Loc);
+    break;
+  }
+  case UnaryTransformType::RemoveConst:
+  case UnaryTransformType::RemoveCV:
+  case UnaryTransformType::RemoveRestrict:
+  case UnaryTransformType::RemoveVolatile: {
+    Result = BuiltinChangeCVRQualifiers(BaseType, UKind, Loc);
+    break;
+  }
+  case UnaryTransformType::MakeSigned:
+  case UnaryTransformType::MakeUnsigned: {
+    Result = BuiltinChangeSignedness(BaseType, UKind, Loc);
+    break;
+  }
+  default:
+    llvm_unreachable("unknown unary transform type");
+  }
+
+  return !Result.isNull()
+             ? Context.getUnaryTransformType(BaseType, Result, UKind)
+             : Result;
 }
 
 QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) {

diff  --git a/clang/test/CodeGenCXX/mangle.cpp b/clang/test/CodeGenCXX/mangle.cpp
index eb87118c56e62..708b492a2ebed 100644
--- a/clang/test/CodeGenCXX/mangle.cpp
+++ b/clang/test/CodeGenCXX/mangle.cpp
@@ -51,7 +51,7 @@ namespace N { int f(int, int) { static int b; return b; } }
 namespace N { int h(); void g() { static int a = h(); } }
 
 // CHECK-LABEL: define{{.*}} void @_Z1fno
-void f(__int128_t, __uint128_t) { } 
+void f(__int128_t, __uint128_t) {}
 
 template <typename T> struct S1 {};
 
@@ -101,13 +101,13 @@ namespace NS {
 void g1() {
   // CHECK: @_Z3ft1IidEvT0_T_
   ft1<int, double>(1, 0);
-  
+
   // CHECK: @_Z3ft2IcEvT_PFvS0_ES2_
   ft2<char>(1, 0, 0);
-  
+
   // CHECK: @_Z3ft3IiEvP2S4IT_2S1IS1_EE
   ft3<int>(0);
-  
+
   // CHECK: @_ZN2NS3ft1IiEEvT_
   NS::ft1<int>(1);
 }
@@ -119,14 +119,14 @@ template<int I> void ft4(S5<I>) { }
 void g2() {
   // CHECK: @_Z3ft4ILi10EEv2S5IXT_EE
   ft4(S5<10>());
-  
+
   // CHECK: @_Z3ft4ILi20EEv2S5IXT_EE
   ft4(S5<20>());
 }
 
 extern "C++" {
   // CHECK: @_Z1hv
- void h() { } 
+void h() {}
 }
 
 // PR5019
@@ -208,7 +208,7 @@ void extern_f(void) { }
 
 struct S7 {
   S7();
-  
+
   struct S { S(); };
   struct {
     S s;
@@ -276,7 +276,7 @@ struct Ops {
   Ops& operator-(const Ops&);
   Ops& operator&(const Ops&);
   Ops& operator*(const Ops&);
-  
+
   void *v;
 };
 
@@ -493,7 +493,7 @@ namespace test11 {
   struct A {
     void f(...);
   };
-  
+
   // CHECK: @_ZN6test111A1fEz
   void A::f(...) { }
 }
@@ -832,9 +832,9 @@ namespace test34 {
 
 namespace test35 {
   // Dependent operator names of unknown arity.
-  struct A { 
-    template<typename U> A operator+(U) const;
-  };
+struct A {
+  template <typename U> A operator+(U) const;
+};
 
   template<typename T>
   void f1(decltype(sizeof(&T::template operator+<int>))) {}
@@ -1107,11 +1107,74 @@ namespace test55 {
 enum E { R };
 
 template <typename T>
-void fn(T, __underlying_type(T)) {}
-
-template void fn<E>(E, __underlying_type(E));
-// CHECK-LABEL: @_ZN6test552fnINS_1EEEEvT_U3eutS2_
-}
+void f1(T, __underlying_type(T)) {}
+template void f1<E>(E, __underlying_type(E));
+// CHECK-LABEL: @_ZN6test552f1INS_1EEEEvT_u17__underlying_typeIS2_E
+
+template <typename T> void f2(T, __add_lvalue_reference(T)) {}
+template void f2<int>(int, __add_lvalue_reference(int));
+// CHECK-LABEL: @_ZN6test552f2IiEEvT_u22__add_lvalue_referenceIS1_E
+
+template <typename T> void f3(T, __add_pointer(T)) {}
+template void f3<int>(int, __add_pointer(int));
+// CHECK-LABEL: @_ZN6test552f3IiEEvT_u13__add_pointerIS1_E
+
+template <typename T> void f4(T, __add_rvalue_reference(T)) {}
+template void f4<int>(int, __add_rvalue_reference(int));
+// CHECK-LABEL: @_ZN6test552f4IiEEvT_u22__add_rvalue_referenceIS1_E
+
+template <typename T> void f5(T, __decay(T)) {}
+template void f5<int>(int, __decay(int));
+// CHECK-LABEL: @_ZN6test552f5IiEEvT_u7__decayIS1_E
+
+template <typename T> void f6(T, __make_signed(T)) {}
+template void f6<int>(int, __make_signed(int));
+// CHECK-LABEL: @_ZN6test552f6IiEEvT_u13__make_signedIS1_E
+
+template <typename T> void f7(T, __make_unsigned(T)) {}
+template void f7<int>(int, __make_unsigned(int));
+// CHECK-LABEL: @_ZN6test552f7IiEEvT_u15__make_unsignedIS1_E
+
+template <typename T> void f8(T, __remove_const(T)) {}
+template void f8<int>(int, __remove_const(int));
+// CHECK-LABEL: @_ZN6test552f8IiEEvT_u14__remove_constIS1_E
+
+template <typename T> void f9(T, __remove_cv(T)) {}
+template void f9<int>(int, __remove_cv(int));
+// CHECK-LABEL: @_ZN6test552f9IiEEvT_u11__remove_cvIS1_E
+
+template <typename T> void f10(T, __remove_cvref(T)) {}
+template void f10<int>(int, __remove_cvref(int));
+// CHECK-LABEL: @_ZN6test553f10IiEEvT_u14__remove_cvrefIS1_E
+
+template <typename T> void f11(T, __remove_volatile(T)) {}
+template void f11<int>(int, __remove_volatile(int));
+// CHECK-LABEL: @_ZN6test553f11IiEEvT_u17__remove_volatileIS1_E
+
+template <typename T> void f12(T, __remove_extent(T)) {}
+template void f12<int>(int, __remove_extent(int));
+// CHECK-LABEL: @_ZN6test553f12IiEEvT_u15__remove_extentIS1_E
+
+template <typename T> void f13(T, __remove_all_extents(T)) {}
+template void f13<int>(int, __remove_all_extents(int));
+// CHECK-LABEL: @_ZN6test553f13IiEEvT_u20__remove_all_extentsIS1_E
+
+template <typename T> void f14(T, __remove_pointer(T)) {}
+template void f14<int>(int, __remove_pointer(int));
+// CHECK-LABEL: @_ZN6test553f14IiEEvT_u16__remove_pointerIS1_E
+
+template <typename T> void f15(T, __remove_reference(T)) {}
+template void f15<int>(int, __remove_reference(int));
+// CHECK-LABEL: @_ZN6test553f15IiEEvT_u18__remove_referenceIS1_E
+
+template <typename T> void f16(T, __remove_volatile(T)) {}
+template void f16<int>(int, __remove_volatile(int));
+// CHECK-LABEL: @_ZN6test553f16IiEEvT_u17__remove_volatileIS1_E
+
+template <typename T> void f17(T, __remove_restrict(T)) {}
+template void f17<int>(int, __remove_restrict(int));
+// CHECK-LABEL: @_ZN6test553f17IiEEvT_u17__remove_restrictIS1_E
+} // namespace test55
 
 namespace test56 {
   struct A { A *operator->(); int n; } a;

diff  --git a/clang/test/SemaCXX/libstdcxx_transform_type_traits_hack.cpp b/clang/test/SemaCXX/libstdcxx_transform_type_traits_hack.cpp
new file mode 100644
index 0000000000000..5032c3ad00e4d
--- /dev/null
+++ b/clang/test/SemaCXX/libstdcxx_transform_type_traits_hack.cpp
@@ -0,0 +1,84 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++11 -fms-extensions -Wno-microsoft %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++14 -fms-extensions -Wno-microsoft %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++1z -fms-extensions -Wno-microsoft %s
+
+// libstdc++ uses __remove_cv as an alias, so we make our transform type traits alias-revertible
+template <class T, class U>
+struct Same {
+  static constexpr auto value = __is_same(T, U);
+};
+
+template <class T>
+using __remove_const = int; // expected-warning{{keyword '__remove_const' will be made available as an identifier here}}
+template <class T>
+using A = Same<__remove_const<T>, __remove_const<T>>;
+
+template <class T>
+using __remove_restrict = int; // expected-warning{{keyword '__remove_restrict' will be made available as an identifier here}}
+template <class T>
+using B = Same<__remove_restrict<T>, __remove_restrict<T>>;
+
+template <class T>
+using __remove_volatile = int; // expected-warning{{keyword '__remove_volatile' will be made available as an identifier here}}
+template <class T>
+using C = Same<__remove_volatile<T>, __remove_volatile<T>>;
+
+template <class T>
+using __remove_cv = int; // expected-warning{{keyword '__remove_cv' will be made available as an identifier here}}
+template <class T>
+using D = Same<__remove_cv<T>, __remove_cv<T>>;
+
+template <class T>
+using __add_pointer = int; // expected-warning{{keyword '__add_pointer' will be made available as an identifier here}}
+template <class T>
+using E = Same<__add_pointer<T>, __add_pointer<T>>;
+
+template <class T>
+using __remove_pointer = int; // expected-warning{{keyword '__remove_pointer' will be made available as an identifier here}}
+template <class T>
+using F = Same<__remove_pointer<T>, __remove_pointer<T>>;
+
+template <class T>
+using __add_lvalue_reference = int; // expected-warning{{keyword '__add_lvalue_reference' will be made available as an identifier here}}
+template <class T>
+using G = Same<__add_lvalue_reference<T>, __add_lvalue_reference<T>>;
+
+template <class T>
+using __add_rvalue_reference = int; // expected-warning{{keyword '__add_rvalue_reference' will be made available as an identifier here}}
+template <class T>
+using H = Same<__add_rvalue_reference<T>, __add_rvalue_reference<T>>;
+
+template <class T>
+using __remove_reference = int; // expected-warning{{keyword '__remove_reference' will be made available as an identifier here}}
+template <class T>
+using I = Same<__remove_reference<T>, __remove_reference<T>>;
+
+template <class T>
+using __remove_cvref = int; // expected-warning{{keyword '__remove_cvref' will be made available as an identifier here}}
+template <class T>
+using J = Same<__remove_cvref<T>, __remove_cvref<T>>;
+
+template <class T>
+using __decay = int; // expected-warning{{keyword '__decay' will be made available as an identifier here}}
+template <class T>
+using K = Same<__decay<T>, __decay<T>>;
+
+template <class T>
+using __make_signed = int; // expected-warning{{keyword '__make_signed' will be made available as an identifier here}}
+template <class T>
+using L = Same<__make_signed<T>, __make_signed<T>>;
+
+template <class T>
+using __make_unsigned = int; // expected-warning{{keyword '__make_unsigned' will be made available as an identifier here}}
+template <class T>
+using M = Same<__make_unsigned<T>, __make_unsigned<T>>;
+
+template <class T>
+using __remove_extent = int; // expected-warning{{keyword '__remove_extent' will be made available as an identifier here}}
+template <class T>
+using N = Same<__remove_extent<T>, __remove_extent<T>>;
+
+template <class T>
+using __remove_all_extents = int; // expected-warning{{keyword '__remove_all_extents' will be made available as an identifier here}}
+template <class T>
+using O = Same<__remove_all_extents<T>, __remove_all_extents<T>>;

diff  --git a/clang/test/SemaCXX/remove_pointer.mm b/clang/test/SemaCXX/remove_pointer.mm
new file mode 100644
index 0000000000000..d1cf1fa9f4efc
--- /dev/null
+++ b/clang/test/SemaCXX/remove_pointer.mm
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// expected-no-diagnostics
+
+ at class X;
+
+static_assert(__is_same(__remove_pointer(X *), X), "");
+static_assert(__is_same(__remove_pointer(id), id), "");

diff  --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index 0ef1205d44853..f54ae0eb2c578 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++11 -Wno-deprecated-builtins -fms-extensions -Wno-microsoft %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++14 -Wno-deprecated-builtins -fms-extensions -Wno-microsoft %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++1z -Wno-deprecated-builtins -fms-extensions -Wno-microsoft %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++11 -fblocks -Wno-deprecated-builtins -fms-extensions -Wno-microsoft %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++14 -fblocks -Wno-deprecated-builtins -fms-extensions -Wno-microsoft %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++1z -fblocks -Wno-deprecated-builtins -fms-extensions -Wno-microsoft %s
 
 #define T(b) (b) ? 1 : -1
 #define F(b) (b) ? -1 : 1
@@ -14,6 +14,9 @@ typedef NonPOD NonPODArMB[10][2];
 enum Enum { EV };
 enum SignedEnum : signed int { };
 enum UnsignedEnum : unsigned int { };
+enum class EnumClass { EV };
+enum class SignedEnumClass : signed int {};
+enum class UnsignedEnumClass : unsigned int {};
 struct POD { Enum e; int i; float f; NonPOD* p; };
 struct Empty {};
 struct IncompleteStruct;
@@ -2915,3 +2918,694 @@ static_assert(__is_trivially_relocatable(TrivialAbiNontrivialMoveCtor), "");
 static_assert(__is_trivially_relocatable(TrivialAbiNontrivialMoveCtor[]), "");
 
 } // namespace is_trivially_relocatable
+
+struct S {};
+template <class T> using remove_const_t = __remove_const(T);
+
+void check_remove_const() {
+  static_assert(__is_same(remove_const_t<void>, void), "");
+  static_assert(__is_same(remove_const_t<const void>, void), "");
+  static_assert(__is_same(remove_const_t<int>, int), "");
+  static_assert(__is_same(remove_const_t<const int>, int), "");
+  static_assert(__is_same(remove_const_t<volatile int>, volatile int), "");
+  static_assert(__is_same(remove_const_t<const volatile int>, volatile int), "");
+  static_assert(__is_same(remove_const_t<int *>, int *), "");
+  static_assert(__is_same(remove_const_t<int *const>, int *), "");
+  static_assert(__is_same(remove_const_t<int const *const>, int const *), "");
+  static_assert(__is_same(remove_const_t<int const *const __restrict>, int const *__restrict), "");
+  static_assert(__is_same(remove_const_t<int &>, int &), "");
+  static_assert(__is_same(remove_const_t<int const &>, int const &), "");
+  static_assert(__is_same(remove_const_t<int &&>, int &&), "");
+  static_assert(__is_same(remove_const_t<int const &&>, int const &&), "");
+  static_assert(__is_same(remove_const_t<int()>, int()), "");
+  static_assert(__is_same(remove_const_t<int (*const)()>, int (*)()), "");
+  static_assert(__is_same(remove_const_t<int (&)()>, int (&)()), "");
+
+  static_assert(__is_same(remove_const_t<S>, S), "");
+  static_assert(__is_same(remove_const_t<const S>, S), "");
+  static_assert(__is_same(remove_const_t<volatile S>, volatile S), "");
+  static_assert(__is_same(remove_const_t<S *__restrict>, S *__restrict), "");
+  static_assert(__is_same(remove_const_t<const volatile S>, volatile S), "");
+  static_assert(__is_same(remove_const_t<S *const volatile __restrict>, S *volatile __restrict), "");
+  static_assert(__is_same(remove_const_t<int S::*const>, int S::*), "");
+  static_assert(__is_same(remove_const_t<int (S::*const)()>, int(S::*)()), "");
+}
+
+template <class T> using remove_restrict_t = __remove_restrict(T);
+
+void check_remove_restrict() {
+  static_assert(__is_same(remove_restrict_t<void>, void), "");
+  static_assert(__is_same(remove_restrict_t<int>, int), "");
+  static_assert(__is_same(remove_restrict_t<const int>, const int), "");
+  static_assert(__is_same(remove_restrict_t<volatile int>, volatile int), "");
+  static_assert(__is_same(remove_restrict_t<int *__restrict>, int *), "");
+  static_assert(__is_same(remove_restrict_t<int *const volatile __restrict>, int *const volatile), "");
+  static_assert(__is_same(remove_restrict_t<int *>, int *), "");
+  static_assert(__is_same(remove_restrict_t<int *__restrict>, int *), "");
+  static_assert(__is_same(remove_restrict_t<int &>, int &), "");
+  static_assert(__is_same(remove_restrict_t<int &__restrict>, int &), "");
+  static_assert(__is_same(remove_restrict_t<int &&>, int &&), "");
+  static_assert(__is_same(remove_restrict_t<int &&__restrict>, int &&), "");
+  static_assert(__is_same(remove_restrict_t<int()>, int()), "");
+  static_assert(__is_same(remove_restrict_t<int (*const volatile)()>, int (*const volatile)()), "");
+  static_assert(__is_same(remove_restrict_t<int (&)()>, int (&)()), "");
+
+  static_assert(__is_same(remove_restrict_t<S>, S), "");
+  static_assert(__is_same(remove_restrict_t<const S>, const S), "");
+  static_assert(__is_same(remove_restrict_t<volatile S>, volatile S), "");
+  static_assert(__is_same(remove_restrict_t<S *__restrict>, S *), "");
+  static_assert(__is_same(remove_restrict_t<S *const volatile __restrict>, S *const volatile), "");
+  static_assert(__is_same(remove_restrict_t<int S::*__restrict>, int S::*), "");
+  static_assert(__is_same(remove_restrict_t<int (S::*const volatile)()>, int(S::*const volatile)()), "");
+}
+
+template <class T> using remove_volatile_t = __remove_volatile(T);
+
+void check_remove_volatile() {
+  static_assert(__is_same(remove_volatile_t<void>, void), "");
+  static_assert(__is_same(remove_volatile_t<volatile void>, void), "");
+  static_assert(__is_same(remove_volatile_t<int>, int), "");
+  static_assert(__is_same(remove_volatile_t<const int>, const int), "");
+  static_assert(__is_same(remove_volatile_t<volatile int>, int), "");
+  static_assert(__is_same(remove_volatile_t<int *__restrict>, int *__restrict), "");
+  static_assert(__is_same(remove_volatile_t<const volatile int>, const int), "");
+  static_assert(__is_same(remove_volatile_t<int *const volatile __restrict>, int *const __restrict), "");
+  static_assert(__is_same(remove_volatile_t<int *>, int *), "");
+  static_assert(__is_same(remove_volatile_t<int *volatile>, int *), "");
+  static_assert(__is_same(remove_volatile_t<int volatile *volatile>, int volatile *), "");
+  static_assert(__is_same(remove_volatile_t<int &>, int &), "");
+  static_assert(__is_same(remove_volatile_t<int volatile &>, int volatile &), "");
+  static_assert(__is_same(remove_volatile_t<int &&>, int &&), "");
+  static_assert(__is_same(remove_volatile_t<int volatile &&>, int volatile &&), "");
+  static_assert(__is_same(remove_volatile_t<int()>, int()), "");
+  static_assert(__is_same(remove_volatile_t<int (*volatile)()>, int (*)()), "");
+  static_assert(__is_same(remove_volatile_t<int (&)()>, int (&)()), "");
+
+  static_assert(__is_same(remove_volatile_t<S>, S), "");
+  static_assert(__is_same(remove_volatile_t<const S>, const S), "");
+  static_assert(__is_same(remove_volatile_t<volatile S>, S), "");
+  static_assert(__is_same(remove_volatile_t<const volatile S>, const S), "");
+  static_assert(__is_same(remove_volatile_t<int S::*volatile>, int S::*), "");
+  static_assert(__is_same(remove_volatile_t<int (S::*volatile)()>, int(S::*)()), "");
+}
+
+template <class T> using remove_cv_t = __remove_cv(T);
+
+void check_remove_cv() {
+  static_assert(__is_same(remove_cv_t<void>, void), "");
+  static_assert(__is_same(remove_cv_t<const volatile void>, void), "");
+  static_assert(__is_same(remove_cv_t<int>, int), "");
+  static_assert(__is_same(remove_cv_t<const int>, int), "");
+  static_assert(__is_same(remove_cv_t<volatile int>, int), "");
+  static_assert(__is_same(remove_cv_t<const volatile int>, int), "");
+  static_assert(__is_same(remove_cv_t<int *>, int *), "");
+  static_assert(__is_same(remove_cv_t<int *const volatile>, int *), "");
+  static_assert(__is_same(remove_cv_t<int const *const volatile>, int const *), "");
+  static_assert(__is_same(remove_cv_t<int const *const volatile __restrict>, int const *__restrict), "");
+  static_assert(__is_same(remove_cv_t<int const *const volatile _Nonnull>, int const *_Nonnull), "");
+  static_assert(__is_same(remove_cv_t<int &>, int &), "");
+  static_assert(__is_same(remove_cv_t<int const volatile &>, int const volatile &), "");
+  static_assert(__is_same(remove_cv_t<int &&>, int &&), "");
+  static_assert(__is_same(remove_cv_t<int const volatile &&>, int const volatile &&), "");
+  static_assert(__is_same(remove_cv_t<int()>, int()), "");
+  static_assert(__is_same(remove_cv_t<int (*const volatile)()>, int (*)()), "");
+  static_assert(__is_same(remove_cv_t<int (&)()>, int (&)()), "");
+
+  static_assert(__is_same(remove_cv_t<S>, S), "");
+  static_assert(__is_same(remove_cv_t<const S>, S), "");
+  static_assert(__is_same(remove_cv_t<volatile S>, S), "");
+  static_assert(__is_same(remove_cv_t<const volatile S>, S), "");
+  static_assert(__is_same(remove_cv_t<int S::*const volatile>, int S::*), "");
+  static_assert(__is_same(remove_cv_t<int (S::*const volatile)()>, int(S::*)()), "");
+}
+
+template <class T> using add_pointer_t = __add_pointer(T);
+
+void add_pointer() {
+  static_assert(__is_same(add_pointer_t<void>, void *), "");
+  static_assert(__is_same(add_pointer_t<const void>, const void *), "");
+  static_assert(__is_same(add_pointer_t<volatile void>, volatile void *), "");
+  static_assert(__is_same(add_pointer_t<const volatile void>, const volatile void *), "");
+  static_assert(__is_same(add_pointer_t<int>, int *), "");
+  static_assert(__is_same(add_pointer_t<const int>, const int *), "");
+  static_assert(__is_same(add_pointer_t<volatile int>, volatile int *), "");
+  static_assert(__is_same(add_pointer_t<const volatile int>, const volatile int *), "");
+  static_assert(__is_same(add_pointer_t<int *>, int **), "");
+  static_assert(__is_same(add_pointer_t<int &>, int *), "");
+  static_assert(__is_same(add_pointer_t<int &&>, int *), "");
+  static_assert(__is_same(add_pointer_t<int()>, int (*)()), "");
+  static_assert(__is_same(add_pointer_t<int (*)()>, int (**)()), "");
+  static_assert(__is_same(add_pointer_t<int (&)()>, int (*)()), "");
+
+  static_assert(__is_same(add_pointer_t<S>, S *), "");
+  static_assert(__is_same(add_pointer_t<const S>, const S *), "");
+  static_assert(__is_same(add_pointer_t<volatile S>, volatile S *), "");
+  static_assert(__is_same(add_pointer_t<const volatile S>, const volatile S *), "");
+  static_assert(__is_same(add_pointer_t<int S::*>, int S::**), "");
+  static_assert(__is_same(add_pointer_t<int (S::*)()>, int(S::**)()), "");
+
+  static_assert(__is_same(add_pointer_t<int __attribute__((address_space(1)))>, int __attribute__((address_space(1))) *), "");
+  static_assert(__is_same(add_pointer_t<S __attribute__((address_space(2)))>, S __attribute__((address_space(2))) *), "");
+}
+
+template <class T> using remove_pointer_t = __remove_pointer(T);
+
+void remove_pointer() {
+  static_assert(__is_same(remove_pointer_t<void>, void), "");
+  static_assert(__is_same(remove_pointer_t<const void>, const void), "");
+  static_assert(__is_same(remove_pointer_t<volatile void>, volatile void), "");
+  static_assert(__is_same(remove_pointer_t<const volatile void>, const volatile void), "");
+  static_assert(__is_same(remove_pointer_t<int>, int), "");
+  static_assert(__is_same(remove_pointer_t<const int>, const int), "");
+  static_assert(__is_same(remove_pointer_t<volatile int>, volatile int), "");
+  static_assert(__is_same(remove_pointer_t<const volatile int>, const volatile int), "");
+  static_assert(__is_same(remove_pointer_t<int *>, int), "");
+  static_assert(__is_same(remove_pointer_t<const int *>, const int), "");
+  static_assert(__is_same(remove_pointer_t<volatile int *>, volatile int), "");
+  static_assert(__is_same(remove_pointer_t<const volatile int *>, const volatile int), "");
+  static_assert(__is_same(remove_pointer_t<int *const>, int), "");
+  static_assert(__is_same(remove_pointer_t<int *volatile>, int), "");
+  static_assert(__is_same(remove_pointer_t<int *const volatile>, int), "");
+  static_assert(__is_same(remove_pointer_t<int &>, int &), "");
+  static_assert(__is_same(remove_pointer_t<int &&>, int &&), "");
+  static_assert(__is_same(remove_pointer_t<int()>, int()), "");
+  static_assert(__is_same(remove_pointer_t<int (*)()>, int()), "");
+  static_assert(__is_same(remove_pointer_t<int (&)()>, int (&)()), "");
+
+  static_assert(__is_same(remove_pointer_t<S>, S), "");
+  static_assert(__is_same(remove_pointer_t<const S>, const S), "");
+  static_assert(__is_same(remove_pointer_t<volatile S>, volatile S), "");
+  static_assert(__is_same(remove_pointer_t<const volatile S>, const volatile S), "");
+  static_assert(__is_same(remove_pointer_t<int S::*>, int S::*), "");
+  static_assert(__is_same(remove_pointer_t<int (S::*)()>, int(S::*)()), "");
+
+  static_assert(__is_same(remove_pointer_t<int __attribute__((address_space(1))) *>, int __attribute__((address_space(1)))), "");
+  static_assert(__is_same(remove_pointer_t<S __attribute__((address_space(2))) *>, S  __attribute__((address_space(2)))), "");
+
+  static_assert(__is_same(remove_pointer_t<int (^)(char)>, int (^)(char)), "");
+}
+
+template <class T> using add_lvalue_reference_t = __add_lvalue_reference(T);
+
+void add_lvalue_reference() {
+  static_assert(__is_same(add_lvalue_reference_t<void>, void), "");
+  static_assert(__is_same(add_lvalue_reference_t<const void>, const void), "");
+  static_assert(__is_same(add_lvalue_reference_t<volatile void>, volatile void), "");
+  static_assert(__is_same(add_lvalue_reference_t<const volatile void>, const volatile void), "");
+  static_assert(__is_same(add_lvalue_reference_t<int>, int &), "");
+  static_assert(__is_same(add_lvalue_reference_t<const int>, const int &), "");
+  static_assert(__is_same(add_lvalue_reference_t<volatile int>, volatile int &), "");
+  static_assert(__is_same(add_lvalue_reference_t<const volatile int>, const volatile int &), "");
+  static_assert(__is_same(add_lvalue_reference_t<int *>, int *&), "");
+  static_assert(__is_same(add_lvalue_reference_t<int &>, int &), "");
+  static_assert(__is_same(add_lvalue_reference_t<int &&>, int &), ""); // reference collapsing
+  static_assert(__is_same(add_lvalue_reference_t<int()>, int (&)()), "");
+  static_assert(__is_same(add_lvalue_reference_t<int (*)()>, int (*&)()), "");
+  static_assert(__is_same(add_lvalue_reference_t<int (&)()>, int (&)()), "");
+
+  static_assert(__is_same(add_lvalue_reference_t<S>, S &), "");
+  static_assert(__is_same(add_lvalue_reference_t<const S>, const S &), "");
+  static_assert(__is_same(add_lvalue_reference_t<volatile S>, volatile S &), "");
+  static_assert(__is_same(add_lvalue_reference_t<const volatile S>, const volatile S &), "");
+  static_assert(__is_same(add_lvalue_reference_t<int S::*>, int S::*&), "");
+  static_assert(__is_same(add_lvalue_reference_t<int (S::*)()>, int(S::*&)()), "");
+}
+
+template <class T> using add_rvalue_reference_t = __add_rvalue_reference(T);
+
+void add_rvalue_reference() {
+  static_assert(__is_same(add_rvalue_reference_t<void>, void), "");
+  static_assert(__is_same(add_rvalue_reference_t<const void>, const void), "");
+  static_assert(__is_same(add_rvalue_reference_t<volatile void>, volatile void), "");
+  static_assert(__is_same(add_rvalue_reference_t<const volatile void>, const volatile void), "");
+  static_assert(__is_same(add_rvalue_reference_t<int>, int &&), "");
+  static_assert(__is_same(add_rvalue_reference_t<const int>, const int &&), "");
+  static_assert(__is_same(add_rvalue_reference_t<volatile int>, volatile int &&), "");
+  static_assert(__is_same(add_rvalue_reference_t<const volatile int>, const volatile int &&), "");
+  static_assert(__is_same(add_rvalue_reference_t<int *>, int *&&), "");
+  static_assert(__is_same(add_rvalue_reference_t<int &>, int &), ""); // reference collapsing
+  static_assert(__is_same(add_rvalue_reference_t<int &&>, int &&), "");
+  static_assert(__is_same(add_rvalue_reference_t<int()>, int(&&)()), "");
+  static_assert(__is_same(add_rvalue_reference_t<int (*)()>, int (*&&)()), "");
+  static_assert(__is_same(add_rvalue_reference_t<int (&)()>, int (&)()), ""); // reference collapsing
+
+  static_assert(__is_same(add_rvalue_reference_t<S>, S &&), "");
+  static_assert(__is_same(add_rvalue_reference_t<const S>, const S &&), "");
+  static_assert(__is_same(add_rvalue_reference_t<volatile S>, volatile S &&), "");
+  static_assert(__is_same(add_rvalue_reference_t<const volatile S>, const volatile S &&), "");
+  static_assert(__is_same(add_rvalue_reference_t<int S::*>, int S::*&&), "");
+  static_assert(__is_same(add_rvalue_reference_t<int (S::*)()>, int(S::* &&)()), "");
+}
+
+template <class T> using remove_reference_t = __remove_reference(T);
+
+void check_remove_reference() {
+  static_assert(__is_same(remove_reference_t<void>, void), "");
+  static_assert(__is_same(remove_reference_t<const volatile void>, const volatile void), "");
+  static_assert(__is_same(remove_reference_t<int>, int), "");
+  static_assert(__is_same(remove_reference_t<const int>, const int), "");
+  static_assert(__is_same(remove_reference_t<volatile int>, volatile int), "");
+  static_assert(__is_same(remove_reference_t<const volatile int>, const volatile int), "");
+  static_assert(__is_same(remove_reference_t<int *>, int *), "");
+  static_assert(__is_same(remove_reference_t<int *const volatile>, int *const volatile), "");
+  static_assert(__is_same(remove_reference_t<int const *const volatile>, int const *const volatile), "");
+  static_assert(__is_same(remove_reference_t<int &>, int), "");
+  static_assert(__is_same(remove_reference_t<int const volatile &>, int const volatile), "");
+  static_assert(__is_same(remove_reference_t<int &&>, int), "");
+  static_assert(__is_same(remove_reference_t<int const volatile &&>, int const volatile), "");
+  static_assert(__is_same(remove_reference_t<int()>, int()), "");
+  static_assert(__is_same(remove_reference_t<int (*const volatile)()>, int (*const volatile)()), "");
+  static_assert(__is_same(remove_reference_t<int (&)()>, int()), "");
+
+  static_assert(__is_same(remove_reference_t<S>, S), "");
+  static_assert(__is_same(remove_reference_t<S &>, S), "");
+  static_assert(__is_same(remove_reference_t<S &&>, S), "");
+  static_assert(__is_same(remove_reference_t<const S>, const S), "");
+  static_assert(__is_same(remove_reference_t<const S &>, const S), "");
+  static_assert(__is_same(remove_reference_t<const S &&>, const S), "");
+  static_assert(__is_same(remove_reference_t<volatile S>, volatile S), "");
+  static_assert(__is_same(remove_reference_t<volatile S &>, volatile S), "");
+  static_assert(__is_same(remove_reference_t<volatile S &&>, volatile S), "");
+  static_assert(__is_same(remove_reference_t<const volatile S>, const volatile S), "");
+  static_assert(__is_same(remove_reference_t<const volatile S &>, const volatile S), "");
+  static_assert(__is_same(remove_reference_t<const volatile S &&>, const volatile S), "");
+  static_assert(__is_same(remove_reference_t<int S::*const volatile &>, int S::*const volatile), "");
+  static_assert(__is_same(remove_reference_t<int (S::*const volatile &)()>, int(S::*const volatile)()), "");
+  static_assert(__is_same(remove_reference_t<int (S::*const volatile &&)() &>, int(S::*const volatile)() &), "");
+}
+
+template <class T> using remove_cvref_t = __remove_cvref(T);
+
+void check_remove_cvref() {
+  static_assert(__is_same(remove_cvref_t<void>, void), "");
+  static_assert(__is_same(remove_cvref_t<const volatile void>, void), "");
+  static_assert(__is_same(remove_cvref_t<int>, int), "");
+  static_assert(__is_same(remove_cvref_t<const int>, int), "");
+  static_assert(__is_same(remove_cvref_t<volatile int>, int), "");
+  static_assert(__is_same(remove_cvref_t<const volatile int>, int), "");
+  static_assert(__is_same(remove_cvref_t<int *>, int *), "");
+  static_assert(__is_same(remove_cvref_t<int *const volatile>, int *), "");
+  static_assert(__is_same(remove_cvref_t<int const *const volatile>, int const *), "");
+  static_assert(__is_same(remove_cvref_t<int const *const volatile __restrict>, int const *__restrict), "");
+  static_assert(__is_same(remove_cvref_t<int const *const volatile _Nonnull>, int const *_Nonnull), "");
+  static_assert(__is_same(remove_cvref_t<int &>, int), "");
+  static_assert(__is_same(remove_cvref_t<int const volatile &>, int), "");
+  static_assert(__is_same(remove_cvref_t<int &&>, int), "");
+  static_assert(__is_same(remove_cvref_t<int const volatile &&>, int), "");
+  static_assert(__is_same(remove_cvref_t<int()>, int()), "");
+  static_assert(__is_same(remove_cvref_t<int (*const volatile)()>, int (*)()), "");
+  static_assert(__is_same(remove_cvref_t<int (&)()>, int()), "");
+
+  static_assert(__is_same(remove_cvref_t<S>, S), "");
+  static_assert(__is_same(remove_cvref_t<S &>, S), "");
+  static_assert(__is_same(remove_cvref_t<S &&>, S), "");
+  static_assert(__is_same(remove_cvref_t<const S>, S), "");
+  static_assert(__is_same(remove_cvref_t<const S &>, S), "");
+  static_assert(__is_same(remove_cvref_t<const S &&>, S), "");
+  static_assert(__is_same(remove_cvref_t<volatile S>, S), "");
+  static_assert(__is_same(remove_cvref_t<volatile S &>, S), "");
+  static_assert(__is_same(remove_cvref_t<volatile S &&>, S), "");
+  static_assert(__is_same(remove_cvref_t<const volatile S>, S), "");
+  static_assert(__is_same(remove_cvref_t<const volatile S &>, S), "");
+  static_assert(__is_same(remove_cvref_t<const volatile S &&>, S), "");
+  static_assert(__is_same(remove_cvref_t<int S::*const volatile>, int S::*), "");
+  static_assert(__is_same(remove_cvref_t<int (S::*const volatile)()>, int(S::*)()), "");
+  static_assert(__is_same(remove_cvref_t<int (S::*const volatile)() &>, int(S::*)() &), "");
+  static_assert(__is_same(remove_cvref_t<int (S::*const volatile)() &&>, int(S::*)() &&), "");
+}
+
+template <class T> using decay_t = __decay(T);
+template <class T> struct dne;
+
+void check_decay() {
+  static_assert(__is_same(decay_t<void>, void), "");
+  static_assert(__is_same(decay_t<const volatile void>, void), "");
+  static_assert(__is_same(decay_t<int>, int), "");
+  static_assert(__is_same(decay_t<const int>, int), "");
+  static_assert(__is_same(decay_t<volatile int>, int), "");
+  static_assert(__is_same(decay_t<const volatile int>, int), "");
+  static_assert(__is_same(decay_t<int *>, int *), "");
+  static_assert(__is_same(decay_t<int *const volatile>, int *), "");
+  static_assert(__is_same(decay_t<int *const volatile __restrict>, int *), "");
+  static_assert(__is_same(decay_t<int const *const volatile>, int const *), "");
+  static_assert(__is_same(decay_t<int const *const volatile _Nonnull>, int const *), "");
+  static_assert(__is_same(decay_t<int &>, int), "");
+  static_assert(__is_same(decay_t<int const volatile &>, int), "");
+  static_assert(__is_same(decay_t<int &&>, int), "");
+  static_assert(__is_same(decay_t<int const volatile &&>, int), "");
+  static_assert(__is_same(decay_t<int()>, int (*)()), "");
+  static_assert(__is_same(decay_t<int (*)()>, int (*)()), "");
+  static_assert(__is_same(decay_t<int (*const)()>, int (*)()), "");
+  static_assert(__is_same(decay_t<int (*volatile)()>, int (*)()), "");
+  static_assert(__is_same(decay_t<int (*const volatile)()>, int (*)()), "");
+  static_assert(__is_same(decay_t<int (&)()>, int (*)()), "");
+  static_assert(__is_same(decay_t<IntAr>, int *), "");
+  static_assert(__is_same(decay_t<IntArNB>, int *), "");
+
+  static_assert(__is_same(decay_t<S>, S), "");
+  static_assert(__is_same(decay_t<S &>, S), "");
+  static_assert(__is_same(decay_t<S &&>, S), "");
+  static_assert(__is_same(decay_t<const S>, S), "");
+  static_assert(__is_same(decay_t<const S &>, S), "");
+  static_assert(__is_same(decay_t<const S &&>, S), "");
+  static_assert(__is_same(decay_t<volatile S>, S), "");
+  static_assert(__is_same(decay_t<volatile S &>, S), "");
+  static_assert(__is_same(decay_t<volatile S &&>, S), "");
+  static_assert(__is_same(decay_t<const volatile S>, S), "");
+  static_assert(__is_same(decay_t<const volatile S &>, S), "");
+  static_assert(__is_same(decay_t<const volatile S &&>, S), "");
+  static_assert(__is_same(decay_t<int S::*const volatile>, int S::*), "");
+  static_assert(__is_same(decay_t<int (S::*const volatile)()>, int(S::*)()), "");
+  static_assert(__is_same(decay_t<int S::*const volatile &>, int S::*), "");
+  static_assert(__is_same(decay_t<int (S::*const volatile &)()>, int(S::*)()), "");
+  static_assert(__is_same(decay_t<int S::*const volatile &&>, int S::*), "");
+}
+
+template <class T> struct CheckAbominableFunction {};
+template <class M>
+struct CheckAbominableFunction<M S::*> {
+  static void checks() {
+    static_assert(__is_same(add_lvalue_reference_t<M>, M), "");
+    static_assert(__is_same(add_pointer_t<M>, M), "");
+    static_assert(__is_same(add_rvalue_reference_t<M>, M), "");
+    static_assert(__is_same(decay_t<M>, M), "");
+    static_assert(__is_same(remove_const_t<M>, M), "");
+    static_assert(__is_same(remove_volatile_t<M>, M), "");
+    static_assert(__is_same(remove_cv_t<M>, M), "");
+    static_assert(__is_same(remove_cvref_t<M>, M), "");
+    static_assert(__is_same(remove_pointer_t<M>, M), "");
+    static_assert(__is_same(remove_reference_t<M>, M), "");
+  }
+};
+
+void check_abominable_function() {
+  { CheckAbominableFunction<int (S::*)() &> x; }
+  { CheckAbominableFunction<int (S::*)() &&> x; }
+  { CheckAbominableFunction<int (S::*)() const> x; }
+  { CheckAbominableFunction<int (S::*)() const &> x; }
+  { CheckAbominableFunction<int (S::*)() const &&> x; }
+  { CheckAbominableFunction<int (S::*)() volatile> x; }
+  { CheckAbominableFunction<int (S::*)() volatile &> x; }
+  { CheckAbominableFunction<int (S::*)() volatile &&> x; }
+  { CheckAbominableFunction<int (S::*)() const volatile> x; }
+  { CheckAbominableFunction<int (S::*)() const volatile &> x; }
+  { CheckAbominableFunction<int (S::*)() const volatile &&> x; }
+}
+
+template <class T> using make_signed_t = __make_signed(T);
+template <class T, class Expected>
+void check_make_signed() {
+  static_assert(__is_same(make_signed_t<T>, Expected), "");
+  static_assert(__is_same(make_signed_t<const T>, const Expected), "");
+  static_assert(__is_same(make_signed_t<volatile T>, volatile Expected), "");
+  static_assert(__is_same(make_signed_t<const volatile T>, const volatile Expected), "");
+}
+
+#if defined(__ILP32__) || defined(__LLP64__)
+  using Int64 = long long;
+  using UInt64 = unsigned long long;
+#elif defined(__LP64__) || defined(__ILP64__) || defined(__SILP64__)
+  using Int64 = long;
+  using UInt64 = unsigned long;
+#else
+#error Programming model currently unsupported; please add a new entry.
+#endif
+
+enum UnscopedBool : bool {}; // deliberately char
+enum class ScopedBool : bool {}; // deliberately char
+enum UnscopedChar : char {}; // deliberately char
+enum class ScopedChar : char {}; // deliberately char
+enum UnscopedUChar : unsigned char {};
+enum class ScopedUChar : unsigned char {};
+enum UnscopedLongLong : long long {};
+enum UnscopedULongLong : unsigned long long {};
+enum class ScopedLongLong : long long {};
+enum class ScopedULongLong : unsigned long long {};
+enum class UnscopedInt128 : __int128 {};
+enum class ScopedInt128 : __int128 {};
+enum class UnscopedUInt128 : unsigned __int128 {};
+enum class ScopedUInt128 : unsigned __int128 {};
+enum UnscopedBit : unsigned _BitInt(1) {};
+enum ScopedBit : unsigned _BitInt(1) {};
+enum UnscopedIrregular : _BitInt(21) {};
+enum UnscopedUIrregular : unsigned _BitInt(21) {};
+enum class ScopedIrregular : _BitInt(21) {};
+enum class ScopedUIrregular : unsigned _BitInt(21) {};
+
+void make_signed() {
+  check_make_signed<char, signed char>();
+  check_make_signed<signed char, signed char>();
+  check_make_signed<unsigned char, signed char>();
+  check_make_signed<short, short>();
+  check_make_signed<unsigned short, short>();
+  check_make_signed<int, int>();
+  check_make_signed<unsigned int, int>();
+  check_make_signed<long, long>();
+  check_make_signed<unsigned long, long>();
+  check_make_signed<long long, long long>();
+  check_make_signed<unsigned long long, long long>();
+  check_make_signed<__int128, __int128>();
+  check_make_signed<__uint128_t, __int128>();
+  check_make_signed<_BitInt(65), _BitInt(65)>();
+  check_make_signed<unsigned _BitInt(65), _BitInt(65)>();
+
+  check_make_signed<wchar_t, int>();
+#if __cplusplus >= 202002L
+  check_make_signed<char8_t, signed char>();
+#endif
+#if __cplusplus >= 201103L
+  check_make_signed<char16_t, short>();
+  check_make_signed<char32_t, int>();
+#endif
+
+  check_make_signed<UnscopedChar, signed char>();
+  check_make_signed<ScopedChar, signed char>();
+  check_make_signed<UnscopedUChar, signed char>();
+  check_make_signed<ScopedUChar, signed char>();
+
+  check_make_signed<UnscopedLongLong, Int64>();
+  check_make_signed<UnscopedULongLong, Int64>();
+  check_make_signed<ScopedLongLong, Int64>();
+  check_make_signed<ScopedULongLong, Int64>();
+
+  check_make_signed<UnscopedInt128, __int128>();
+  check_make_signed<ScopedInt128, __int128>();
+  check_make_signed<UnscopedUInt128, __int128>();
+  check_make_signed<ScopedUInt128, __int128>();
+
+  check_make_signed<UnscopedIrregular, _BitInt(21)>();
+  check_make_signed<UnscopedUIrregular, _BitInt(21)>();
+  check_make_signed<ScopedIrregular, _BitInt(21)>();
+  check_make_signed<ScopedUIrregular, _BitInt(21)>();
+
+  { using ExpectedError = __make_signed(bool); }
+  // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'bool'}}
+  { using ExpectedError = __make_signed(UnscopedBool); }
+  // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'UnscopedBool' whose underlying type is 'bool'}}
+  { using ExpectedError = __make_signed(ScopedBool); }
+  // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'ScopedBool' whose underlying type is 'bool'}}
+  { using ExpectedError = __make_signed(unsigned _BitInt(1)); }
+  // expected-error@*:*{{'make_signed' is only compatible with non-_BitInt(1) integers and enum types, but was given 'unsigned _BitInt(1)'}}
+  { using ExpectedError = __make_signed(UnscopedBit); }
+  // expected-error@*:*{{'make_signed' is only compatible with non-_BitInt(1) integers and enum types, but was given 'UnscopedBit' whose underlying type is 'unsigned _BitInt(1)'}}
+  { using ExpectedError = __make_signed(ScopedBit); }
+  // expected-error@*:*{{'make_signed' is only compatible with non-_BitInt(1) integers and enum types, but was given 'ScopedBit' whose underlying type is 'unsigned _BitInt(1)'}}
+  { using ExpectedError = __make_signed(int[]); }
+  // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'int[]'}}
+  { using ExpectedError = __make_signed(int[5]); }
+  // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'int[5]'}}
+  { using ExpectedError = __make_signed(void); }
+  // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'void'}}
+  { using ExpectedError = __make_signed(int *); }
+  // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'int *'}}
+  { using ExpectedError = __make_signed(int &); }
+  // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'int &'}}
+  { using ExpectedError = __make_signed(int &&); }
+  // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'int &&'}}
+  { using ExpectedError = __make_signed(float); }
+  // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'float'}}
+  { using ExpectedError = __make_signed(double); }
+  // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'double'}}
+  { using ExpectedError = __make_signed(long double); }
+  // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'long double'}}
+  { using ExpectedError = __make_signed(S); }
+  // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'S'}}
+  { using ExpectedError = __make_signed(S *); }
+  // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'S *'}}
+  { using ExpectedError = __make_signed(int S::*); }
+  // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'int S::*'}}
+  { using ExpectedError = __make_signed(int(S::*)()); }
+  // expected-error@*:*{{'make_signed' is only compatible with non-bool integers and enum types, but was given 'int (S::*)()'}}
+}
+
+template <class T>
+using make_unsigned_t = __make_unsigned(T);
+
+template <class T, class Expected>
+void check_make_unsigned() {
+  static_assert(__is_same(make_unsigned_t<T>, Expected), "");
+  static_assert(__is_same(make_unsigned_t<const T>, const Expected), "");
+  static_assert(__is_same(make_unsigned_t<volatile T>, volatile Expected), "");
+  static_assert(__is_same(make_unsigned_t<const volatile T>, const volatile Expected), "");
+}
+
+void make_unsigned() {
+  check_make_unsigned<char, unsigned char>();
+  check_make_unsigned<signed char, unsigned char>();
+  check_make_unsigned<unsigned char, unsigned char>();
+  check_make_unsigned<short, unsigned short>();
+  check_make_unsigned<unsigned short, unsigned short>();
+  check_make_unsigned<int, unsigned int>();
+  check_make_unsigned<unsigned int, unsigned int>();
+  check_make_unsigned<long, unsigned long>();
+  check_make_unsigned<unsigned long, unsigned long>();
+  check_make_unsigned<long long, unsigned long long>();
+  check_make_unsigned<unsigned long long, unsigned long long>();
+  check_make_unsigned<__int128, __uint128_t>();
+  check_make_unsigned<__uint128_t, __uint128_t>();
+  check_make_unsigned<_BitInt(65), unsigned _BitInt(65)>();
+  check_make_unsigned<unsigned _BitInt(65), unsigned _BitInt(65)>();
+
+  check_make_unsigned<wchar_t, unsigned int>();
+#if __cplusplus >= 202002L
+  check_make_unsigned<char8_t, unsigned char>();
+#endif
+#if __cplusplus >= 201103L
+  check_make_unsigned<char16_t, unsigned short>();
+  check_make_unsigned<char32_t, unsigned int>();
+#endif
+
+  check_make_unsigned<UnscopedChar, unsigned char>();
+  check_make_unsigned<ScopedChar, unsigned char>();
+  check_make_unsigned<UnscopedUChar, unsigned char>();
+  check_make_unsigned<ScopedUChar, unsigned char>();
+
+  check_make_unsigned<UnscopedLongLong, UInt64>();
+  check_make_unsigned<UnscopedULongLong, UInt64>();
+  check_make_unsigned<ScopedLongLong, UInt64>();
+  check_make_unsigned<ScopedULongLong, UInt64>();
+
+  check_make_unsigned<UnscopedInt128, unsigned __int128>();
+  check_make_unsigned<ScopedInt128, unsigned __int128>();
+  check_make_unsigned<UnscopedUInt128, unsigned __int128>();
+  check_make_unsigned<ScopedUInt128, unsigned __int128>();
+
+  check_make_unsigned<UnscopedIrregular, unsigned _BitInt(21)>();
+  check_make_unsigned<UnscopedUIrregular, unsigned _BitInt(21)>();
+  check_make_unsigned<ScopedIrregular, unsigned _BitInt(21)>();
+  check_make_unsigned<ScopedUIrregular, unsigned _BitInt(21)>();
+
+  { using ExpectedError = __make_unsigned(bool); }
+  // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'bool'}}
+  { using ExpectedError = __make_unsigned(UnscopedBool); }
+  // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'UnscopedBool' whose underlying type is 'bool'}}
+  { using ExpectedError = __make_unsigned(ScopedBool); }
+  // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'ScopedBool' whose underlying type is 'bool'}}
+  { using ExpectedError = __make_unsigned(unsigned _BitInt(1)); }
+  // expected-error@*:*{{'make_unsigned' is only compatible with non-_BitInt(1) integers and enum types, but was given 'unsigned _BitInt(1)'}}
+  { using ExpectedError = __make_unsigned(UnscopedBit); }
+  // expected-error@*:*{{'make_unsigned' is only compatible with non-_BitInt(1) integers and enum types, but was given 'UnscopedBit'}}
+  { using ExpectedError = __make_unsigned(ScopedBit); }
+  // expected-error@*:*{{'make_unsigned' is only compatible with non-_BitInt(1) integers and enum types, but was given 'ScopedBit'}}
+  { using ExpectedError = __make_unsigned(int[]); }
+  // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'int[]'}}
+  { using ExpectedError = __make_unsigned(int[5]); }
+  // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'int[5]'}}
+  { using ExpectedError = __make_unsigned(void); }
+  // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'void'}}
+  { using ExpectedError = __make_unsigned(int *); }
+  // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'int *'}}
+  { using ExpectedError = __make_unsigned(int &); }
+  // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'int &'}}
+  { using ExpectedError = __make_unsigned(int &&); }
+  // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'int &&'}}
+  { using ExpectedError = __make_unsigned(float); }
+  // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'float'}}
+  { using ExpectedError = __make_unsigned(double); }
+  // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'double'}}
+  { using ExpectedError = __make_unsigned(long double); }
+  // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'long double'}}
+  { using ExpectedError = __make_unsigned(S); }
+  // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'S'}}
+  { using ExpectedError = __make_unsigned(S *); }
+  // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'S *'}}
+  { using ExpectedError = __make_unsigned(int S::*); }
+  // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'int S::*'}}
+  { using ExpectedError = __make_unsigned(int(S::*)()); }
+  // expected-error@*:*{{'make_unsigned' is only compatible with non-bool integers and enum types, but was given 'int (S::*)()'}}
+}
+
+template <class T> using remove_extent_t = __remove_extent(T);
+
+void remove_extent() {
+  static_assert(__is_same(remove_extent_t<void>, void), "");
+  static_assert(__is_same(remove_extent_t<int>, int), "");
+  static_assert(__is_same(remove_extent_t<int[]>, int), "");
+  static_assert(__is_same(remove_extent_t<int[1]>, int), "");
+  static_assert(__is_same(remove_extent_t<int[1][2]>, int[2]), "");
+  static_assert(__is_same(remove_extent_t<int[][2]>, int[2]), "");
+  static_assert(__is_same(remove_extent_t<const int[]>, const int), "");
+  static_assert(__is_same(remove_extent_t<const int[1]>, const int), "");
+  static_assert(__is_same(remove_extent_t<const int[1][2]>, const int[2]), "");
+  static_assert(__is_same(remove_extent_t<const int[][2]>, const int[2]), "");
+  static_assert(__is_same(remove_extent_t<volatile int[]>, volatile int), "");
+  static_assert(__is_same(remove_extent_t<volatile int[1]>, volatile int), "");
+  static_assert(__is_same(remove_extent_t<volatile int[1][2]>, volatile int[2]), "");
+  static_assert(__is_same(remove_extent_t<volatile int[][2]>, volatile int[2]), "");
+  static_assert(__is_same(remove_extent_t<const volatile int[]>, const volatile int), "");
+  static_assert(__is_same(remove_extent_t<const volatile int[1]>, const volatile int), "");
+  static_assert(__is_same(remove_extent_t<const volatile int[1][2]>, const volatile int[2]), "");
+  static_assert(__is_same(remove_extent_t<const volatile int[][2]>, const volatile int[2]), "");
+  static_assert(__is_same(remove_extent_t<int *>, int *), "");
+  static_assert(__is_same(remove_extent_t<int &>, int &), "");
+  static_assert(__is_same(remove_extent_t<int &&>, int &&), "");
+  static_assert(__is_same(remove_extent_t<int()>, int()), "");
+  static_assert(__is_same(remove_extent_t<int (*)()>, int (*)()), "");
+  static_assert(__is_same(remove_extent_t<int (&)()>, int (&)()), "");
+
+  static_assert(__is_same(remove_extent_t<S>, S), "");
+  static_assert(__is_same(remove_extent_t<int S::*>, int S::*), "");
+  static_assert(__is_same(remove_extent_t<int (S::*)()>, int(S::*)()), "");
+
+  using SomeArray = int[1][2];
+  static_assert(__is_same(remove_extent_t<const SomeArray>, const int[2]), "");
+}
+
+template <class T> using remove_all_extents_t = __remove_all_extents(T);
+
+void remove_all_extents() {
+  static_assert(__is_same(remove_all_extents_t<void>, void), "");
+  static_assert(__is_same(remove_all_extents_t<int>, int), "");
+  static_assert(__is_same(remove_all_extents_t<const int>, const int), "");
+  static_assert(__is_same(remove_all_extents_t<volatile int>, volatile int), "");
+  static_assert(__is_same(remove_all_extents_t<const volatile int>, const volatile int), "");
+  static_assert(__is_same(remove_all_extents_t<int[]>, int), "");
+  static_assert(__is_same(remove_all_extents_t<int[1]>, int), "");
+  static_assert(__is_same(remove_all_extents_t<int[1][2]>, int), "");
+  static_assert(__is_same(remove_all_extents_t<int[][2]>, int), "");
+  static_assert(__is_same(remove_all_extents_t<const int[]>, const int), "");
+  static_assert(__is_same(remove_all_extents_t<const int[1]>, const int), "");
+  static_assert(__is_same(remove_all_extents_t<const int[1][2]>, const int), "");
+  static_assert(__is_same(remove_all_extents_t<const int[][2]>, const int), "");
+  static_assert(__is_same(remove_all_extents_t<volatile int[]>, volatile int), "");
+  static_assert(__is_same(remove_all_extents_t<volatile int[1]>, volatile int), "");
+  static_assert(__is_same(remove_all_extents_t<volatile int[1][2]>, volatile int), "");
+  static_assert(__is_same(remove_all_extents_t<volatile int[][2]>, volatile int), "");
+  static_assert(__is_same(remove_all_extents_t<const volatile int[]>, const volatile int), "");
+  static_assert(__is_same(remove_all_extents_t<const volatile int[1]>, const volatile int), "");
+  static_assert(__is_same(remove_all_extents_t<const volatile int[1][2]>, const volatile int), "");
+  static_assert(__is_same(remove_all_extents_t<const volatile int[][2]>, const volatile int), "");
+  static_assert(__is_same(remove_all_extents_t<int *>, int *), "");
+  static_assert(__is_same(remove_all_extents_t<int &>, int &), "");
+  static_assert(__is_same(remove_all_extents_t<int &&>, int &&), "");
+  static_assert(__is_same(remove_all_extents_t<int()>, int()), "");
+  static_assert(__is_same(remove_all_extents_t<int (*)()>, int (*)()), "");
+  static_assert(__is_same(remove_all_extents_t<int (&)()>, int (&)()), "");
+
+  static_assert(__is_same(remove_all_extents_t<S>, S), "");
+  static_assert(__is_same(remove_all_extents_t<int S::*>, int S::*), "");
+  static_assert(__is_same(remove_all_extents_t<int (S::*)()>, int(S::*)()), "");
+
+  using SomeArray = int[1][2];
+  static_assert(__is_same(remove_all_extents_t<const SomeArray>, const int), "");
+}

diff  --git a/clang/utils/ClangVisualizers/clang.natvis b/clang/utils/ClangVisualizers/clang.natvis
index 36dea11b0118f..3e6148cd5e05c 100644
--- a/clang/utils/ClangVisualizers/clang.natvis
+++ b/clang/utils/ClangVisualizers/clang.natvis
@@ -2,7 +2,7 @@
 <!--
 Visual Studio Native Debugging Visualizers for LLVM
 
-For Visual Studio 2013 only, put this file into 
+For Visual Studio 2013 only, put this file into
 "%USERPROFILE%\Documents\Visual Studio 2013\Visualizers" or create a symbolic link so it updates automatically.
 
 For later versions of Visual Studio, no setup is required-->
@@ -11,8 +11,8 @@ For later versions of Visual Studio, no setup is required-->
   <Type Name="clang::Type">
     <!-- To visualize clang::Types, we need to look at TypeBits.TC to determine the actual
          type subclass and manually dispatch accordingly (Visual Studio can't identify the real type
-         because clang::Type has no virtual members hence no RTTI). 
-         
+         because clang::Type has no virtual members hence no RTTI).
+
          Views:
            "cmn": Visualization that is common to all clang::Type subclasses
            "poly": Visualization that is specific to the actual clang::Type subclass. The subtype-specific
@@ -160,7 +160,7 @@ For later versions of Visual Studio, no setup is required-->
   <Type Name="clang::AttributedType">
     <DisplayString>{ModifiedType} Attribute={(clang::AttributedType::Kind)AttributedTypeBits.AttrKind}</DisplayString>
   </Type>
-  
+
   <!-- Unfortunately, Visual Studio has trouble seeing the PointerBitMask member PointerIntUnion, so I hardwire it to 2 bits-->
   <Type Name="clang::DeclContext">
     <DisplayString>{(clang::Decl::Kind)DeclContextBits.DeclKind,en}Decl</DisplayString>
@@ -201,7 +201,7 @@ For later versions of Visual Studio, no setup is required-->
     <DisplayString IncludeView="DefaultArg">{{InheritedInitializer}}</DisplayString>
     <DisplayString IncludeView="Initializer" Condition="DefaultArgument.ValueOrInherited.Val.Value&~3LL">= {this,view(DefaultArg)na}</DisplayString>
     <DisplayString IncludeView="Initializer"></DisplayString>
-    <DisplayString>{*this,view(TorC)} {*this,view(MaybeEllipses)}{Name,view(cpp)} {this,view(Initializer)na}</DisplayString> 
+    <DisplayString>{*this,view(TorC)} {*this,view(MaybeEllipses)}{Name,view(cpp)} {this,view(Initializer)na}</DisplayString>
   </Type>
   <Type Name="clang::TemplateDecl">
     <DisplayString IncludeView="cpp">{*TemplatedDecl,view(cpp)}</DisplayString>
@@ -694,7 +694,7 @@ For later versions of Visual Studio, no setup is required-->
     <DisplayString Condition="(Ptr & PtrMask) == StoredCXXConstructorName">C++ Constructor {{{(clang::detail::CXXSpecialNameExtra *)(Ptr & ~PtrMask),view(cpp)na}}}</DisplayString>
     <DisplayString Condition="(Ptr & PtrMask) == StoredCXXDestructorName">C++ Destructor {{*(clang::detail::CXXSpecialNameExtra *)(Ptr & ~PtrMask)}}</DisplayString>
     <DisplayString Condition="(Ptr & PtrMask) == StoredCXXConversionFunctionName">C++ Conversion function {{*(clang::detail::CXXSpecialNameExtra *)(Ptr & ~PtrMask)}}</DisplayString>
-    <DisplayString Condition="(Ptr & PtrMask) == StoredCXXOperatorName">C++ Operator {{*(clang::detail::CXXOperatorIdName *)(Ptr & ~PtrMask)}}</DisplayString>    
+    <DisplayString Condition="(Ptr & PtrMask) == StoredCXXOperatorName">C++ Operator {{*(clang::detail::CXXOperatorIdName *)(Ptr & ~PtrMask)}}</DisplayString>
     <DisplayString Condition="(Ptr & PtrMask) == StoredDeclarationNameExtra"
                    IncludeView="cpp">{*(clang::detail::DeclarationNameExtra *)(Ptr & ~PtrMask),view(cpp)}</DisplayString>
     <DisplayString Condition="(Ptr & PtrMask) == StoredDeclarationNameExtra">{{Extra ({*(clang::detail::DeclarationNameExtra *)(Ptr & ~PtrMask)})}}</DisplayString>
@@ -706,7 +706,7 @@ For later versions of Visual Studio, no setup is required-->
       <Item Condition="(Ptr & PtrMask) == StoredCXXConstructorName" Name="[C++ Constructor]">*(clang::detail::CXXSpecialNameExtra *)(Ptr & ~PtrMask),na</Item>
       <Item Condition="(Ptr & PtrMask) == StoredCXXDestructorName" Name="[C++ Destructor]">*(clang::detail::CXXSpecialNameExtra *)(Ptr & ~PtrMask),na</Item>
       <Item Condition="(Ptr & PtrMask) == StoredCXXConversionFunctionName" Name="[C++ Conversion function]">*(clang::detail::CXXSpecialNameExtra *)(Ptr & ~PtrMask),na</Item>
-      <Item Condition="(Ptr & PtrMask) == StoredCXXOperatorName" Name="[C++ Operator]">*(clang::detail::CXXOperatorIdName *)(Ptr & ~PtrMask),na</Item>      
+      <Item Condition="(Ptr & PtrMask) == StoredCXXOperatorName" Name="[C++ Operator]">*(clang::detail::CXXOperatorIdName *)(Ptr & ~PtrMask),na</Item>
       <Item Condition="(Ptr & PtrMask) == StoredDeclarationNameExtra" Name="[Extra]">(clang::detail::DeclarationNameExtra *)(Ptr & ~PtrMask),na</Item>
     </Expand>
   </Type>
@@ -718,7 +718,7 @@ For later versions of Visual Studio, no setup is required-->
       {(CXXDeductionGuideNameExtra *)this,nand}
     </DisplayString>
     <DisplayString Condition="ExtraKindOrNumArgs == CXXLiteralOperatorName">C++ Literal operator</DisplayString>
-    <DisplayString Condition="ExtraKindOrNumArgs == CXXUsingDirective">C++ Using directive</DisplayString>  
+    <DisplayString Condition="ExtraKindOrNumArgs == CXXUsingDirective">C++ Using directive</DisplayString>
     <DisplayString>{(clang::detail::DeclarationNameExtra::ExtraKind)ExtraKindOrNumArgs,en}{"  ",sb}{*this,view(cpp)}</DisplayString>
     <Expand>
       <ExpandedItem Condition="ExtraKindOrNumArgs == CXXDeductionGuideName">(CXXDeductionGuideNameExtra *)this</ExpandedItem>
@@ -809,7 +809,7 @@ For later versions of Visual Studio, no setup is required-->
     <DisplayString>[{this,view(default)na}{this,view(capture0)na}]</DisplayString>
   </Type>
   <Type Name="clang::DeclSpec">
-    <DisplayString IncludeView="extra" Condition="TypeSpecType == TST_typename || TypeSpecType == TST_typeofType || TypeSpecType == TST_underlyingType || TypeSpecType == TST_atomic">
+    <DisplayString IncludeView="extra" Condition="TypeSpecType == TST_typename || TypeSpecType == TST_typeofType || TypeSpecType == TST_underlying_type || TypeSpecType == TST_atomic">
       , [{TypeRep}]
     </DisplayString>
     <DisplayString IncludeView="extra" Condition="TypeSpecType == TST_typeofExpr || TypeSpecType == TST_decltype">
@@ -823,7 +823,7 @@ For later versions of Visual Studio, no setup is required-->
     <Expand>
       <Item Name="StorageClassSpec">(clang::DeclSpec::SCS)StorageClassSpec</Item>
       <Item Name="TypeSpecType">(clang::TypeSpecifierType)TypeSpecType</Item>
-      <Item Name="TypeRep" Condition="TypeSpecType == TST_typename || TypeSpecType == TST_typeofType || TypeSpecType == TST_underlyingType || TypeSpecType == TST_atomic">
+      <Item Name="TypeRep" Condition="TypeSpecType == TST_typename || TypeSpecType == TST_typeofType || TypeSpecType == TST_underlying_type || TypeSpecType == TST_atomic">
         TypeRep
       </Item>
       <Item Name="ExprRep" Condition="TypeSpecType == TST_typeofExpr || TypeSpecType == TST_decltype">


        


More information about the cfe-commits mailing list