[clang] [Clang][NFC] Move the type trait logic to a separate file. (PR #141245)

via cfe-commits cfe-commits at lists.llvm.org
Fri May 23 08:53:16 PDT 2025


https://github.com/cor3ntin updated https://github.com/llvm/llvm-project/pull/141245

>From 02186cea131a735c29e08541c0d1f6a4bce6b6f0 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Fri, 23 May 2025 17:43:49 +0200
Subject: [PATCH 1/2] [Clang][NFC] Move the type trait logic to a separate
 file.

Just to try to keep the size of SemaExprCXX.cpp in check.

As discussed in #141238
---
 clang/lib/Sema/CMakeLists.txt     |    1 +
 clang/lib/Sema/SemaDeclCXX.cpp    |  273 ----
 clang/lib/Sema/SemaExprCXX.cpp    | 1621 ------------------------
 clang/lib/Sema/SemaTypeTraits.cpp | 1919 +++++++++++++++++++++++++++++
 4 files changed, 1920 insertions(+), 1894 deletions(-)
 create mode 100644 clang/lib/Sema/SemaTypeTraits.cpp

diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index 4b87004e4b8ea..51e0ee10b080b 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -96,6 +96,7 @@ add_clang_library(clangSema
   SemaTemplateInstantiateDecl.cpp
   SemaTemplateVariadic.cpp
   SemaType.cpp
+  SemaTypeTraits.cpp
   SemaWasm.cpp
   SemaX86.cpp
   TypeLocBuilder.cpp
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index fe92191b6a687..ead53a995dff1 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -7368,279 +7368,6 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
   CheckMismatchedTypeAwareAllocators(OO_Array_New, OO_Array_Delete);
 }
 
-static CXXMethodDecl *LookupSpecialMemberFromXValue(Sema &SemaRef,
-                                                    const CXXRecordDecl *RD,
-                                                    bool Assign) {
-  RD = RD->getDefinition();
-  SourceLocation LookupLoc = RD->getLocation();
-
-  CanQualType CanTy = SemaRef.getASTContext().getCanonicalType(
-      SemaRef.getASTContext().getTagDeclType(RD));
-  DeclarationName Name;
-  Expr *Arg = nullptr;
-  unsigned NumArgs;
-
-  QualType ArgType = CanTy;
-  ExprValueKind VK = clang::VK_XValue;
-
-  if (Assign)
-    Name =
-        SemaRef.getASTContext().DeclarationNames.getCXXOperatorName(OO_Equal);
-  else
-    Name =
-        SemaRef.getASTContext().DeclarationNames.getCXXConstructorName(CanTy);
-
-  OpaqueValueExpr FakeArg(LookupLoc, ArgType, VK);
-  NumArgs = 1;
-  Arg = &FakeArg;
-
-  // Create the object argument
-  QualType ThisTy = CanTy;
-  Expr::Classification Classification =
-      OpaqueValueExpr(LookupLoc, ThisTy, VK_LValue)
-          .Classify(SemaRef.getASTContext());
-
-  // Now we perform lookup on the name we computed earlier and do overload
-  // resolution. Lookup is only performed directly into the class since there
-  // will always be a (possibly implicit) declaration to shadow any others.
-  OverloadCandidateSet OCS(LookupLoc, OverloadCandidateSet::CSK_Normal);
-  DeclContext::lookup_result R = RD->lookup(Name);
-
-  if (R.empty())
-    return nullptr;
-
-  // Copy the candidates as our processing of them may load new declarations
-  // from an external source and invalidate lookup_result.
-  SmallVector<NamedDecl *, 8> Candidates(R.begin(), R.end());
-
-  for (NamedDecl *CandDecl : Candidates) {
-    if (CandDecl->isInvalidDecl())
-      continue;
-
-    DeclAccessPair Cand = DeclAccessPair::make(CandDecl, clang::AS_none);
-    auto CtorInfo = getConstructorInfo(Cand);
-    if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(Cand->getUnderlyingDecl())) {
-      if (Assign)
-        SemaRef.AddMethodCandidate(M, Cand, const_cast<CXXRecordDecl *>(RD),
-                                   ThisTy, Classification,
-                                   llvm::ArrayRef(&Arg, NumArgs), OCS, true);
-      else {
-        assert(CtorInfo);
-        SemaRef.AddOverloadCandidate(CtorInfo.Constructor, CtorInfo.FoundDecl,
-                                     llvm::ArrayRef(&Arg, NumArgs), OCS,
-                                     /*SuppressUserConversions*/ true);
-      }
-    } else if (FunctionTemplateDecl *Tmpl =
-                   dyn_cast<FunctionTemplateDecl>(Cand->getUnderlyingDecl())) {
-      if (Assign)
-        SemaRef.AddMethodTemplateCandidate(
-            Tmpl, Cand, const_cast<CXXRecordDecl *>(RD), nullptr, ThisTy,
-            Classification, llvm::ArrayRef(&Arg, NumArgs), OCS, true);
-      else {
-        assert(CtorInfo);
-        SemaRef.AddTemplateOverloadCandidate(
-            CtorInfo.ConstructorTmpl, CtorInfo.FoundDecl, nullptr,
-            llvm::ArrayRef(&Arg, NumArgs), OCS, true);
-      }
-    }
-  }
-
-  OverloadCandidateSet::iterator Best;
-  switch (OCS.BestViableFunction(SemaRef, LookupLoc, Best)) {
-  case OR_Success:
-    return cast<CXXMethodDecl>(Best->Function);
-  default:
-    return nullptr;
-  }
-}
-
-static bool hasSuitableConstructorForRelocation(Sema &SemaRef,
-                                                const CXXRecordDecl *D,
-                                                bool AllowUserDefined) {
-  assert(D->hasDefinition() && !D->isInvalidDecl());
-
-  if (D->hasSimpleMoveConstructor() || D->hasSimpleCopyConstructor())
-    return true;
-
-  CXXMethodDecl *Decl =
-      LookupSpecialMemberFromXValue(SemaRef, D, /*Assign=*/false);
-  return Decl && Decl->isUserProvided() == AllowUserDefined;
-}
-
-static bool hasSuitableMoveAssignmentOperatorForRelocation(
-    Sema &SemaRef, const CXXRecordDecl *D, bool AllowUserDefined) {
-  assert(D->hasDefinition() && !D->isInvalidDecl());
-
-  if (D->hasSimpleMoveAssignment() || D->hasSimpleCopyAssignment())
-    return true;
-
-  CXXMethodDecl *Decl =
-      LookupSpecialMemberFromXValue(SemaRef, D, /*Assign=*/true);
-  if (!Decl)
-    return false;
-
-  return Decl && Decl->isUserProvided() == AllowUserDefined;
-}
-
-// [C++26][class.prop]
-// A class C is default-movable if
-// - overload resolution for direct-initializing an object of type C
-// from an xvalue of type C selects a constructor that is a direct member of C
-// and is neither user-provided nor deleted,
-// - overload resolution for assigning to an lvalue of type C from an xvalue of
-// type C selects an assignment operator function that is a direct member of C
-// and is neither user-provided nor deleted, and C has a destructor that is
-// neither user-provided nor deleted.
-static bool IsDefaultMovable(Sema &SemaRef, const CXXRecordDecl *D) {
-  if (!hasSuitableConstructorForRelocation(SemaRef, D,
-                                           /*AllowUserDefined=*/false))
-    return false;
-
-  if (!hasSuitableMoveAssignmentOperatorForRelocation(
-          SemaRef, D, /*AllowUserDefined=*/false))
-    return false;
-
-  CXXDestructorDecl *Dtr = D->getDestructor();
-
-  if (!Dtr)
-    return true;
-
-  if (Dtr->isUserProvided() && (!Dtr->isDefaulted() || Dtr->isDeleted()))
-    return false;
-
-  return !Dtr->isDeleted();
-}
-
-// [C++26][class.prop]
-// A class is eligible for trivial relocation unless it...
-static bool IsEligibleForTrivialRelocation(Sema &SemaRef,
-                                           const CXXRecordDecl *D) {
-
-  for (const CXXBaseSpecifier &B : D->bases()) {
-    const auto *BaseDecl = B.getType()->getAsCXXRecordDecl();
-    if (!BaseDecl)
-      continue;
-    // ... has any virtual base classes
-    // ... has a base class that is not a trivially relocatable class
-    if (B.isVirtual() || (!BaseDecl->isDependentType() &&
-                          !SemaRef.IsCXXTriviallyRelocatableType(B.getType())))
-      return false;
-  }
-
-  for (const FieldDecl *Field : D->fields()) {
-    if (Field->getType()->isDependentType())
-      continue;
-    if (Field->getType()->isReferenceType())
-      continue;
-    // ... has a non-static data member of an object type that is not
-    // of a trivially relocatable type
-    if (!SemaRef.IsCXXTriviallyRelocatableType(Field->getType()))
-      return false;
-  }
-  return !D->hasDeletedDestructor();
-}
-
-// [C++26][class.prop]
-// A class C is eligible for replacement unless
-static bool IsEligibleForReplacement(Sema &SemaRef, const CXXRecordDecl *D) {
-
-  for (const CXXBaseSpecifier &B : D->bases()) {
-    const auto *BaseDecl = B.getType()->getAsCXXRecordDecl();
-    if (!BaseDecl)
-      continue;
-    // it has a base class that is not a replaceable class
-    if (!BaseDecl->isDependentType() &&
-        !SemaRef.IsCXXReplaceableType(B.getType()))
-      return false;
-  }
-
-  for (const FieldDecl *Field : D->fields()) {
-    if (Field->getType()->isDependentType())
-      continue;
-
-    // it has a non-static data member that is not of a replaceable type,
-    if (!SemaRef.IsCXXReplaceableType(Field->getType()))
-      return false;
-  }
-  return !D->hasDeletedDestructor();
-}
-
-ASTContext::CXXRecordDeclRelocationInfo
-Sema::CheckCXX2CRelocatableAndReplaceable(const CXXRecordDecl *D) {
-  ASTContext::CXXRecordDeclRelocationInfo Info{false, false};
-
-  if (!getLangOpts().CPlusPlus || D->isInvalidDecl())
-    return Info;
-
-  assert(D->hasDefinition());
-
-  // This is part of "eligible for replacement", however we defer it
-  // to avoid extraneous computations.
-  auto HasSuitableSMP = [&] {
-    return hasSuitableConstructorForRelocation(*this, D,
-                                               /*AllowUserDefined=*/true) &&
-           hasSuitableMoveAssignmentOperatorForRelocation(
-               *this, D, /*AllowUserDefined=*/true);
-  };
-
-  auto IsUnion = [&, Is = std::optional<bool>{}]() mutable {
-    if (!Is.has_value())
-      Is = D->isUnion() && !D->hasUserDeclaredCopyConstructor() &&
-           !D->hasUserDeclaredCopyAssignment() &&
-           !D->hasUserDeclaredMoveOperation() &&
-           !D->hasUserDeclaredDestructor();
-    return *Is;
-  };
-
-  auto IsDefaultMovable = [&, Is = std::optional<bool>{}]() mutable {
-    if (!Is.has_value())
-      Is = ::IsDefaultMovable(*this, D);
-    return *Is;
-  };
-
-  Info.IsRelocatable = [&] {
-    if (D->isDependentType())
-      return false;
-
-    // if it is eligible for trivial relocation
-    if (!IsEligibleForTrivialRelocation(*this, D))
-      return false;
-
-    // has the trivially_relocatable_if_eligible class-property-specifier,
-    if (D->hasAttr<TriviallyRelocatableAttr>())
-      return true;
-
-    // is a union with no user-declared special member functions, or
-    if (IsUnion())
-      return true;
-
-    // is default-movable.
-    return IsDefaultMovable();
-  }();
-
-  Info.IsReplaceable = [&] {
-    if (D->isDependentType())
-      return false;
-
-    // A class C is a replaceable class if it is eligible for replacement
-    if (!IsEligibleForReplacement(*this, D))
-      return false;
-
-    // has the replaceable_if_eligible class-property-specifier
-    if (D->hasAttr<ReplaceableAttr>())
-      return HasSuitableSMP();
-
-    // is a union with no user-declared special member functions, or
-    if (IsUnion())
-      return HasSuitableSMP();
-
-    // is default-movable.
-    return IsDefaultMovable();
-  }();
-
-  return Info;
-}
-
 /// Look up the special member function that would be called by a special
 /// member function for a subobject of class type.
 ///
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index b53877c40668d..63cf324ddb1f9 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -30,7 +30,6 @@
 #include "clang/Basic/PartialDiagnostic.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Basic/TokenKinds.h"
-#include "clang/Basic/TypeTraits.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Sema/DeclSpec.h"
 #include "clang/Sema/EnterExpressionEvaluationContext.h"
@@ -49,7 +48,6 @@
 #include "clang/Sema/TemplateDeduction.h"
 #include "llvm/ADT/APInt.h"
 #include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/STLForwardCompat.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/TypeSize.h"
@@ -5294,1625 +5292,6 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
   return From;
 }
 
-/// Checks that type T is not a VLA.
-///
-/// @returns @c true if @p T is VLA and a diagnostic was emitted,
-/// @c false otherwise.
-static bool DiagnoseVLAInCXXTypeTrait(Sema &S, const TypeSourceInfo *T,
-                                      clang::tok::TokenKind TypeTraitID) {
-  if (!T->getType()->isVariableArrayType())
-    return false;
-
-  S.Diag(T->getTypeLoc().getBeginLoc(), diag::err_vla_unsupported)
-      << 1 << TypeTraitID;
-  return true;
-}
-
-/// Checks that type T is not an atomic type (_Atomic).
-///
-/// @returns @c true if @p T is VLA and a diagnostic was emitted,
-/// @c false otherwise.
-static bool DiagnoseAtomicInCXXTypeTrait(Sema &S, const TypeSourceInfo *T,
-                                         clang::tok::TokenKind TypeTraitID) {
-  if (!T->getType()->isAtomicType())
-    return false;
-
-  S.Diag(T->getTypeLoc().getBeginLoc(), diag::err_atomic_unsupported)
-      << TypeTraitID;
-  return true;
-}
-
-/// Check the completeness of a type in a unary type trait.
-///
-/// If the particular type trait requires a complete type, tries to complete
-/// it. If completing the type fails, a diagnostic is emitted and false
-/// returned. If completing the type succeeds or no completion was required,
-/// returns true.
-static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
-                                                SourceLocation Loc,
-                                                QualType ArgTy) {
-  // C++0x [meta.unary.prop]p3:
-  //   For all of the class templates X declared in this Clause, instantiating
-  //   that template with a template argument that is a class template
-  //   specialization may result in the implicit instantiation of the template
-  //   argument if and only if the semantics of X require that the argument
-  //   must be a complete type.
-  // We apply this rule to all the type trait expressions used to implement
-  // these class templates. We also try to follow any GCC documented behavior
-  // in these expressions to ensure portability of standard libraries.
-  switch (UTT) {
-  default: llvm_unreachable("not a UTT");
-    // is_complete_type somewhat obviously cannot require a complete type.
-  case UTT_IsCompleteType:
-    // Fall-through
-
-    // These traits are modeled on the type predicates in C++0x
-    // [meta.unary.cat] and [meta.unary.comp]. They are not specified as
-    // requiring a complete type, as whether or not they return true cannot be
-    // impacted by the completeness of the type.
-  case UTT_IsVoid:
-  case UTT_IsIntegral:
-  case UTT_IsFloatingPoint:
-  case UTT_IsArray:
-  case UTT_IsBoundedArray:
-  case UTT_IsPointer:
-  case UTT_IsLvalueReference:
-  case UTT_IsRvalueReference:
-  case UTT_IsMemberFunctionPointer:
-  case UTT_IsMemberObjectPointer:
-  case UTT_IsEnum:
-  case UTT_IsScopedEnum:
-  case UTT_IsUnion:
-  case UTT_IsClass:
-  case UTT_IsFunction:
-  case UTT_IsReference:
-  case UTT_IsArithmetic:
-  case UTT_IsFundamental:
-  case UTT_IsObject:
-  case UTT_IsScalar:
-  case UTT_IsCompound:
-  case UTT_IsMemberPointer:
-  case UTT_IsTypedResourceElementCompatible:
-    // Fall-through
-
-    // These traits are modeled on type predicates in C++0x [meta.unary.prop]
-    // which requires some of its traits to have the complete type. However,
-    // the completeness of the type cannot impact these traits' semantics, and
-    // so they don't require it. This matches the comments on these traits in
-    // Table 49.
-  case UTT_IsConst:
-  case UTT_IsVolatile:
-  case UTT_IsSigned:
-  case UTT_IsUnboundedArray:
-  case UTT_IsUnsigned:
-
-  // This type trait always returns false, checking the type is moot.
-  case UTT_IsInterfaceClass:
-    return true;
-
-  // We diagnose incomplete class types later.
-  case UTT_StructuredBindingSize:
-    return true;
-
-  // C++14 [meta.unary.prop]:
-  //   If T is a non-union class type, T shall be a complete type.
-  case UTT_IsEmpty:
-  case UTT_IsPolymorphic:
-  case UTT_IsAbstract:
-    if (const auto *RD = ArgTy->getAsCXXRecordDecl())
-      if (!RD->isUnion())
-        return !S.RequireCompleteType(
-            Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
-    return true;
-
-  // C++14 [meta.unary.prop]:
-  //   If T is a class type, T shall be a complete type.
-  case UTT_IsFinal:
-  case UTT_IsSealed:
-    if (ArgTy->getAsCXXRecordDecl())
-      return !S.RequireCompleteType(
-          Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
-    return true;
-
-  // LWG3823: T shall be an array type, a complete type, or cv void.
-  case UTT_IsAggregate:
-  case UTT_IsImplicitLifetime:
-    if (ArgTy->isArrayType() || ArgTy->isVoidType())
-      return true;
-
-    return !S.RequireCompleteType(
-        Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
-
-  // has_unique_object_representations<T>
-  // remove_all_extents_t<T> shall be a complete type or cv void (LWG4113).
-  case UTT_HasUniqueObjectRepresentations:
-    ArgTy = QualType(ArgTy->getBaseElementTypeUnsafe(), 0);
-    if (ArgTy->isVoidType())
-      return true;
-    return !S.RequireCompleteType(
-        Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
-
-  // C++1z [meta.unary.prop]:
-  //   remove_all_extents_t<T> shall be a complete type or cv void.
-  case UTT_IsTrivial:
-  case UTT_IsTriviallyCopyable:
-  case UTT_IsStandardLayout:
-  case UTT_IsPOD:
-  case UTT_IsLiteral:
-  case UTT_IsBitwiseCloneable:
-  // By analogy, is_trivially_relocatable and is_trivially_equality_comparable
-  // impose the same constraints.
-  case UTT_IsTriviallyRelocatable:
-  case UTT_IsTriviallyEqualityComparable:
-  case UTT_IsCppTriviallyRelocatable:
-  case UTT_IsReplaceable:
-  case UTT_CanPassInRegs:
-  // Per the GCC type traits documentation, T shall be a complete type, cv void,
-  // or an array of unknown bound. But GCC actually imposes the same constraints
-  // as above.
-  case UTT_HasNothrowAssign:
-  case UTT_HasNothrowMoveAssign:
-  case UTT_HasNothrowConstructor:
-  case UTT_HasNothrowCopy:
-  case UTT_HasTrivialAssign:
-  case UTT_HasTrivialMoveAssign:
-  case UTT_HasTrivialDefaultConstructor:
-  case UTT_HasTrivialMoveConstructor:
-  case UTT_HasTrivialCopy:
-  case UTT_HasTrivialDestructor:
-  case UTT_HasVirtualDestructor:
-    ArgTy = QualType(ArgTy->getBaseElementTypeUnsafe(), 0);
-    [[fallthrough]];
-  // C++1z [meta.unary.prop]:
-  //   T shall be a complete type, cv void, or an array of unknown bound.
-  case UTT_IsDestructible:
-  case UTT_IsNothrowDestructible:
-  case UTT_IsTriviallyDestructible:
-  case UTT_IsIntangibleType:
-    if (ArgTy->isIncompleteArrayType() || ArgTy->isVoidType())
-      return true;
-
-    return !S.RequireCompleteType(
-        Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
-  }
-}
-
-static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op,
-                               Sema &Self, SourceLocation KeyLoc, ASTContext &C,
-                               bool (CXXRecordDecl::*HasTrivial)() const,
-                               bool (CXXRecordDecl::*HasNonTrivial)() const,
-                               bool (CXXMethodDecl::*IsDesiredOp)() const)
-{
-  CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
-  if ((RD->*HasTrivial)() && !(RD->*HasNonTrivial)())
-    return true;
-
-  DeclarationName Name = C.DeclarationNames.getCXXOperatorName(Op);
-  DeclarationNameInfo NameInfo(Name, KeyLoc);
-  LookupResult Res(Self, NameInfo, Sema::LookupOrdinaryName);
-  if (Self.LookupQualifiedName(Res, RD)) {
-    bool FoundOperator = false;
-    Res.suppressDiagnostics();
-    for (LookupResult::iterator Op = Res.begin(), OpEnd = Res.end();
-         Op != OpEnd; ++Op) {
-      if (isa<FunctionTemplateDecl>(*Op))
-        continue;
-
-      CXXMethodDecl *Operator = cast<CXXMethodDecl>(*Op);
-      if((Operator->*IsDesiredOp)()) {
-        FoundOperator = true;
-        auto *CPT = Operator->getType()->castAs<FunctionProtoType>();
-        CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
-        if (!CPT || !CPT->isNothrow())
-          return false;
-      }
-    }
-    return FoundOperator;
-  }
-  return false;
-}
-
-static bool HasNonDeletedDefaultedEqualityComparison(Sema &S,
-                                                     const CXXRecordDecl *Decl,
-                                                     SourceLocation KeyLoc) {
-  if (Decl->isUnion())
-    return false;
-  if (Decl->isLambda())
-    return Decl->isCapturelessLambda();
-
-  {
-    EnterExpressionEvaluationContext UnevaluatedContext(
-        S, Sema::ExpressionEvaluationContext::Unevaluated);
-    Sema::SFINAETrap SFINAE(S, /*ForValidityCheck=*/true);
-    Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
-
-    // const ClassT& obj;
-    OpaqueValueExpr Operand(
-        KeyLoc,
-        Decl->getTypeForDecl()->getCanonicalTypeUnqualified().withConst(),
-        ExprValueKind::VK_LValue);
-    UnresolvedSet<16> Functions;
-    // obj == obj;
-    S.LookupBinOp(S.TUScope, {}, BinaryOperatorKind::BO_EQ, Functions);
-
-    auto Result = S.CreateOverloadedBinOp(KeyLoc, BinaryOperatorKind::BO_EQ,
-                                          Functions, &Operand, &Operand);
-    if (Result.isInvalid() || SFINAE.hasErrorOccurred())
-      return false;
-
-    const auto *CallExpr = dyn_cast<CXXOperatorCallExpr>(Result.get());
-    if (!CallExpr)
-      return false;
-    const auto *Callee = CallExpr->getDirectCallee();
-    auto ParamT = Callee->getParamDecl(0)->getType();
-    if (!Callee->isDefaulted())
-      return false;
-    if (!ParamT->isReferenceType() && !Decl->isTriviallyCopyable())
-      return false;
-    if (ParamT.getNonReferenceType()->getUnqualifiedDesugaredType() !=
-        Decl->getTypeForDecl())
-      return false;
-  }
-
-  return llvm::all_of(Decl->bases(),
-                      [&](const CXXBaseSpecifier &BS) {
-                        if (const auto *RD = BS.getType()->getAsCXXRecordDecl())
-                          return HasNonDeletedDefaultedEqualityComparison(
-                              S, RD, KeyLoc);
-                        return true;
-                      }) &&
-         llvm::all_of(Decl->fields(), [&](const FieldDecl *FD) {
-           auto Type = FD->getType();
-           if (Type->isArrayType())
-             Type = Type->getBaseElementTypeUnsafe()
-                        ->getCanonicalTypeUnqualified();
-
-           if (Type->isReferenceType() || Type->isEnumeralType())
-             return false;
-           if (const auto *RD = Type->getAsCXXRecordDecl())
-             return HasNonDeletedDefaultedEqualityComparison(S, RD, KeyLoc);
-           return true;
-         });
-}
-
-static bool isTriviallyEqualityComparableType(Sema &S, QualType Type, SourceLocation KeyLoc) {
-  QualType CanonicalType = Type.getCanonicalType();
-  if (CanonicalType->isIncompleteType() || CanonicalType->isDependentType() ||
-      CanonicalType->isEnumeralType() || CanonicalType->isArrayType())
-    return false;
-
-  if (const auto *RD = CanonicalType->getAsCXXRecordDecl()) {
-    if (!HasNonDeletedDefaultedEqualityComparison(S, RD, KeyLoc))
-      return false;
-  }
-
-  return S.getASTContext().hasUniqueObjectRepresentations(
-      CanonicalType, /*CheckIfTriviallyCopyable=*/false);
-}
-
-static bool IsCXXTriviallyRelocatableType(Sema &S, const CXXRecordDecl *RD) {
-  if (std::optional<ASTContext::CXXRecordDeclRelocationInfo> Info =
-          S.getASTContext().getRelocationInfoForCXXRecord(RD))
-    return Info->IsRelocatable;
-  ASTContext::CXXRecordDeclRelocationInfo Info =
-      S.CheckCXX2CRelocatableAndReplaceable(RD);
-  S.getASTContext().setRelocationInfoForCXXRecord(RD, Info);
-  return Info.IsRelocatable;
-}
-
-bool Sema::IsCXXTriviallyRelocatableType(QualType Type) {
-
-  QualType BaseElementType = getASTContext().getBaseElementType(Type);
-
-  if (Type->isVariableArrayType())
-    return false;
-
-  if (BaseElementType.hasNonTrivialObjCLifetime())
-    return false;
-
-  if (BaseElementType.hasAddressDiscriminatedPointerAuth())
-    return false;
-
-  if (BaseElementType->isIncompleteType())
-    return false;
-
-  if (BaseElementType->isScalarType() || BaseElementType->isVectorType())
-    return true;
-
-  if (const auto *RD = BaseElementType->getAsCXXRecordDecl())
-    return ::IsCXXTriviallyRelocatableType(*this, RD);
-
-  return false;
-}
-
-static bool IsCXXReplaceableType(Sema &S, const CXXRecordDecl *RD) {
-  if (std::optional<ASTContext::CXXRecordDeclRelocationInfo> Info =
-          S.getASTContext().getRelocationInfoForCXXRecord(RD))
-    return Info->IsReplaceable;
-  ASTContext::CXXRecordDeclRelocationInfo Info =
-      S.CheckCXX2CRelocatableAndReplaceable(RD);
-  S.getASTContext().setRelocationInfoForCXXRecord(RD, Info);
-  return Info.IsReplaceable;
-}
-
-bool Sema::IsCXXReplaceableType(QualType Type) {
-  if (Type.isConstQualified() || Type.isVolatileQualified())
-    return false;
-
-  if (Type->isVariableArrayType())
-    return false;
-
-  QualType BaseElementType =
-      getASTContext().getBaseElementType(Type.getUnqualifiedType());
-  if (BaseElementType->isIncompleteType())
-    return false;
-  if (BaseElementType->isScalarType())
-    return true;
-  if (const auto *RD = BaseElementType->getAsCXXRecordDecl())
-    return ::IsCXXReplaceableType(*this, RD);
-  return false;
-}
-
-static bool IsTriviallyRelocatableType(Sema &SemaRef, QualType T) {
-  QualType BaseElementType = SemaRef.getASTContext().getBaseElementType(T);
-
-  if (BaseElementType->isIncompleteType())
-    return false;
-  if (!BaseElementType->isObjectType())
-    return false;
-
-  if (T.hasAddressDiscriminatedPointerAuth())
-    return false;
-
-  if (const auto *RD = BaseElementType->getAsCXXRecordDecl();
-      RD && !RD->isPolymorphic() && IsCXXTriviallyRelocatableType(SemaRef, RD))
-    return true;
-
-  if (const auto *RD = BaseElementType->getAsRecordDecl())
-    return RD->canPassInRegisters();
-
-  if (BaseElementType.isTriviallyCopyableType(SemaRef.getASTContext()))
-    return true;
-
-  switch (T.isNonTrivialToPrimitiveDestructiveMove()) {
-  case QualType::PCK_Trivial:
-    return !T.isDestructedType();
-  case QualType::PCK_ARCStrong:
-    return true;
-  default:
-    return false;
-  }
-}
-
-static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
-                                   SourceLocation KeyLoc,
-                                   TypeSourceInfo *TInfo) {
-  QualType T = TInfo->getType();
-  assert(!T->isDependentType() && "Cannot evaluate traits of dependent type");
-
-  ASTContext &C = Self.Context;
-  switch(UTT) {
-  default: llvm_unreachable("not a UTT");
-    // Type trait expressions corresponding to the primary type category
-    // predicates in C++0x [meta.unary.cat].
-  case UTT_IsVoid:
-    return T->isVoidType();
-  case UTT_IsIntegral:
-    return T->isIntegralType(C);
-  case UTT_IsFloatingPoint:
-    return T->isFloatingType();
-  case UTT_IsArray:
-    // Zero-sized arrays aren't considered arrays in partial specializations,
-    // so __is_array shouldn't consider them arrays either.
-    if (const auto *CAT = C.getAsConstantArrayType(T))
-      return CAT->getSize() != 0;
-    return T->isArrayType();
-  case UTT_IsBoundedArray:
-    if (DiagnoseVLAInCXXTypeTrait(Self, TInfo, tok::kw___is_bounded_array))
-      return false;
-    // Zero-sized arrays aren't considered arrays in partial specializations,
-    // so __is_bounded_array shouldn't consider them arrays either.
-    if (const auto *CAT = C.getAsConstantArrayType(T))
-      return CAT->getSize() != 0;
-    return T->isArrayType() && !T->isIncompleteArrayType();
-  case UTT_IsUnboundedArray:
-    if (DiagnoseVLAInCXXTypeTrait(Self, TInfo, tok::kw___is_unbounded_array))
-      return false;
-    return T->isIncompleteArrayType();
-  case UTT_IsPointer:
-    return T->isAnyPointerType();
-  case UTT_IsLvalueReference:
-    return T->isLValueReferenceType();
-  case UTT_IsRvalueReference:
-    return T->isRValueReferenceType();
-  case UTT_IsMemberFunctionPointer:
-    return T->isMemberFunctionPointerType();
-  case UTT_IsMemberObjectPointer:
-    return T->isMemberDataPointerType();
-  case UTT_IsEnum:
-    return T->isEnumeralType();
-  case UTT_IsScopedEnum:
-    return T->isScopedEnumeralType();
-  case UTT_IsUnion:
-    return T->isUnionType();
-  case UTT_IsClass:
-    return T->isClassType() || T->isStructureType() || T->isInterfaceType();
-  case UTT_IsFunction:
-    return T->isFunctionType();
-
-    // Type trait expressions which correspond to the convenient composition
-    // predicates in C++0x [meta.unary.comp].
-  case UTT_IsReference:
-    return T->isReferenceType();
-  case UTT_IsArithmetic:
-    return T->isArithmeticType() && !T->isEnumeralType();
-  case UTT_IsFundamental:
-    return T->isFundamentalType();
-  case UTT_IsObject:
-    return T->isObjectType();
-  case UTT_IsScalar:
-    // Note: semantic analysis depends on Objective-C lifetime types to be
-    // considered scalar types. However, such types do not actually behave
-    // like scalar types at run time (since they may require retain/release
-    // operations), so we report them as non-scalar.
-    if (T->isObjCLifetimeType()) {
-      switch (T.getObjCLifetime()) {
-      case Qualifiers::OCL_None:
-      case Qualifiers::OCL_ExplicitNone:
-        return true;
-
-      case Qualifiers::OCL_Strong:
-      case Qualifiers::OCL_Weak:
-      case Qualifiers::OCL_Autoreleasing:
-        return false;
-      }
-    }
-
-    return T->isScalarType();
-  case UTT_IsCompound:
-    return T->isCompoundType();
-  case UTT_IsMemberPointer:
-    return T->isMemberPointerType();
-
-    // Type trait expressions which correspond to the type property predicates
-    // in C++0x [meta.unary.prop].
-  case UTT_IsConst:
-    return T.isConstQualified();
-  case UTT_IsVolatile:
-    return T.isVolatileQualified();
-  case UTT_IsTrivial:
-    return T.isTrivialType(C);
-  case UTT_IsTriviallyCopyable:
-    return T.isTriviallyCopyableType(C);
-  case UTT_IsStandardLayout:
-    return T->isStandardLayoutType();
-  case UTT_IsPOD:
-    return T.isPODType(C);
-  case UTT_IsLiteral:
-    return T->isLiteralType(C);
-  case UTT_IsEmpty:
-    if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
-      return !RD->isUnion() && RD->isEmpty();
-    return false;
-  case UTT_IsPolymorphic:
-    if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
-      return !RD->isUnion() && RD->isPolymorphic();
-    return false;
-  case UTT_IsAbstract:
-    if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
-      return !RD->isUnion() && RD->isAbstract();
-    return false;
-  case UTT_IsAggregate:
-    // Report vector extensions and complex types as aggregates because they
-    // support aggregate initialization. GCC mirrors this behavior for vectors
-    // but not _Complex.
-    return T->isAggregateType() || T->isVectorType() || T->isExtVectorType() ||
-           T->isAnyComplexType();
-  // __is_interface_class only returns true when CL is invoked in /CLR mode and
-  // even then only when it is used with the 'interface struct ...' syntax
-  // Clang doesn't support /CLR which makes this type trait moot.
-  case UTT_IsInterfaceClass:
-    return false;
-  case UTT_IsFinal:
-  case UTT_IsSealed:
-    if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
-      return RD->hasAttr<FinalAttr>();
-    return false;
-  case UTT_IsSigned:
-    // Enum types should always return false.
-    // Floating points should always return true.
-    return T->isFloatingType() ||
-           (T->isSignedIntegerType() && !T->isEnumeralType());
-  case UTT_IsUnsigned:
-    // Enum types should always return false.
-    return T->isUnsignedIntegerType() && !T->isEnumeralType();
-
-    // Type trait expressions which query classes regarding their construction,
-    // destruction, and copying. Rather than being based directly on the
-    // related type predicates in the standard, they are specified by both
-    // GCC[1] and the Embarcadero C++ compiler[2], and Clang implements those
-    // specifications.
-    //
-    //   1: http://gcc.gnu/.org/onlinedocs/gcc/Type-Traits.html
-    //   2: http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index
-    //
-    // Note that these builtins do not behave as documented in g++: if a class
-    // has both a trivial and a non-trivial special member of a particular kind,
-    // they return false! For now, we emulate this behavior.
-    // FIXME: This appears to be a g++ bug: more complex cases reveal that it
-    // does not correctly compute triviality in the presence of multiple special
-    // members of the same kind. Revisit this once the g++ bug is fixed.
-  case UTT_HasTrivialDefaultConstructor:
-    // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
-    //   If __is_pod (type) is true then the trait is true, else if type is
-    //   a cv class or union type (or array thereof) with a trivial default
-    //   constructor ([class.ctor]) then the trait is true, else it is false.
-    if (T.isPODType(C))
-      return true;
-    if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
-      return RD->hasTrivialDefaultConstructor() &&
-             !RD->hasNonTrivialDefaultConstructor();
-    return false;
-  case UTT_HasTrivialMoveConstructor:
-    //  This trait is implemented by MSVC 2012 and needed to parse the
-    //  standard library headers. Specifically this is used as the logic
-    //  behind std::is_trivially_move_constructible (20.9.4.3).
-    if (T.isPODType(C))
-      return true;
-    if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
-      return RD->hasTrivialMoveConstructor() && !RD->hasNonTrivialMoveConstructor();
-    return false;
-  case UTT_HasTrivialCopy:
-    // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
-    //   If __is_pod (type) is true or type is a reference type then
-    //   the trait is true, else if type is a cv class or union type
-    //   with a trivial copy constructor ([class.copy]) then the trait
-    //   is true, else it is false.
-    if (T.isPODType(C) || T->isReferenceType())
-      return true;
-    if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
-      return RD->hasTrivialCopyConstructor() &&
-             !RD->hasNonTrivialCopyConstructor();
-    return false;
-  case UTT_HasTrivialMoveAssign:
-    //  This trait is implemented by MSVC 2012 and needed to parse the
-    //  standard library headers. Specifically it is used as the logic
-    //  behind std::is_trivially_move_assignable (20.9.4.3)
-    if (T.isPODType(C))
-      return true;
-    if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
-      return RD->hasTrivialMoveAssignment() && !RD->hasNonTrivialMoveAssignment();
-    return false;
-  case UTT_HasTrivialAssign:
-    // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
-    //   If type is const qualified or is a reference type then the
-    //   trait is false. Otherwise if __is_pod (type) is true then the
-    //   trait is true, else if type is a cv class or union type with
-    //   a trivial copy assignment ([class.copy]) then the trait is
-    //   true, else it is false.
-    // Note: the const and reference restrictions are interesting,
-    // given that const and reference members don't prevent a class
-    // from having a trivial copy assignment operator (but do cause
-    // errors if the copy assignment operator is actually used, q.v.
-    // [class.copy]p12).
-
-    if (T.isConstQualified())
-      return false;
-    if (T.isPODType(C))
-      return true;
-    if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
-      return RD->hasTrivialCopyAssignment() &&
-             !RD->hasNonTrivialCopyAssignment();
-    return false;
-  case UTT_IsDestructible:
-  case UTT_IsTriviallyDestructible:
-  case UTT_IsNothrowDestructible:
-    // C++14 [meta.unary.prop]:
-    //   For reference types, is_destructible<T>::value is true.
-    if (T->isReferenceType())
-      return true;
-
-    // Objective-C++ ARC: autorelease types don't require destruction.
-    if (T->isObjCLifetimeType() &&
-        T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing)
-      return true;
-
-    // C++14 [meta.unary.prop]:
-    //   For incomplete types and function types, is_destructible<T>::value is
-    //   false.
-    if (T->isIncompleteType() || T->isFunctionType())
-      return false;
-
-    // A type that requires destruction (via a non-trivial destructor or ARC
-    // lifetime semantics) is not trivially-destructible.
-    if (UTT == UTT_IsTriviallyDestructible && T.isDestructedType())
-      return false;
-
-    // C++14 [meta.unary.prop]:
-    //   For object types and given U equal to remove_all_extents_t<T>, if the
-    //   expression std::declval<U&>().~U() is well-formed when treated as an
-    //   unevaluated operand (Clause 5), then is_destructible<T>::value is true
-    if (auto *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) {
-      CXXDestructorDecl *Destructor = Self.LookupDestructor(RD);
-      if (!Destructor)
-        return false;
-      //  C++14 [dcl.fct.def.delete]p2:
-      //    A program that refers to a deleted function implicitly or
-      //    explicitly, other than to declare it, is ill-formed.
-      if (Destructor->isDeleted())
-        return false;
-      if (C.getLangOpts().AccessControl && Destructor->getAccess() != AS_public)
-        return false;
-      if (UTT == UTT_IsNothrowDestructible) {
-        auto *CPT = Destructor->getType()->castAs<FunctionProtoType>();
-        CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
-        if (!CPT || !CPT->isNothrow())
-          return false;
-      }
-    }
-    return true;
-
-  case UTT_HasTrivialDestructor:
-    // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html
-    //   If __is_pod (type) is true or type is a reference type
-    //   then the trait is true, else if type is a cv class or union
-    //   type (or array thereof) with a trivial destructor
-    //   ([class.dtor]) then the trait is true, else it is
-    //   false.
-    if (T.isPODType(C) || T->isReferenceType())
-      return true;
-
-    // Objective-C++ ARC: autorelease types don't require destruction.
-    if (T->isObjCLifetimeType() &&
-        T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing)
-      return true;
-
-    if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
-      return RD->hasTrivialDestructor();
-    return false;
-  // TODO: Propagate nothrowness for implicitly declared special members.
-  case UTT_HasNothrowAssign:
-    // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
-    //   If type is const qualified or is a reference type then the
-    //   trait is false. Otherwise if __has_trivial_assign (type)
-    //   is true then the trait is true, else if type is a cv class
-    //   or union type with copy assignment operators that are known
-    //   not to throw an exception then the trait is true, else it is
-    //   false.
-    if (C.getBaseElementType(T).isConstQualified())
-      return false;
-    if (T->isReferenceType())
-      return false;
-    if (T.isPODType(C) || T->isObjCLifetimeType())
-      return true;
-
-    if (const RecordType *RT = T->getAs<RecordType>())
-      return HasNoThrowOperator(RT, OO_Equal, Self, KeyLoc, C,
-                                &CXXRecordDecl::hasTrivialCopyAssignment,
-                                &CXXRecordDecl::hasNonTrivialCopyAssignment,
-                                &CXXMethodDecl::isCopyAssignmentOperator);
-    return false;
-  case UTT_HasNothrowMoveAssign:
-    //  This trait is implemented by MSVC 2012 and needed to parse the
-    //  standard library headers. Specifically this is used as the logic
-    //  behind std::is_nothrow_move_assignable (20.9.4.3).
-    if (T.isPODType(C))
-      return true;
-
-    if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>())
-      return HasNoThrowOperator(RT, OO_Equal, Self, KeyLoc, C,
-                                &CXXRecordDecl::hasTrivialMoveAssignment,
-                                &CXXRecordDecl::hasNonTrivialMoveAssignment,
-                                &CXXMethodDecl::isMoveAssignmentOperator);
-    return false;
-  case UTT_HasNothrowCopy:
-    // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
-    //   If __has_trivial_copy (type) is true then the trait is true, else
-    //   if type is a cv class or union type with copy constructors that are
-    //   known not to throw an exception then the trait is true, else it is
-    //   false.
-    if (T.isPODType(C) || T->isReferenceType() || T->isObjCLifetimeType())
-      return true;
-    if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) {
-      if (RD->hasTrivialCopyConstructor() &&
-          !RD->hasNonTrivialCopyConstructor())
-        return true;
-
-      bool FoundConstructor = false;
-      unsigned FoundTQs;
-      for (const auto *ND : Self.LookupConstructors(RD)) {
-        // A template constructor is never a copy constructor.
-        // FIXME: However, it may actually be selected at the actual overload
-        // resolution point.
-        if (isa<FunctionTemplateDecl>(ND->getUnderlyingDecl()))
-          continue;
-        // UsingDecl itself is not a constructor
-        if (isa<UsingDecl>(ND))
-          continue;
-        auto *Constructor = cast<CXXConstructorDecl>(ND->getUnderlyingDecl());
-        if (Constructor->isCopyConstructor(FoundTQs)) {
-          FoundConstructor = true;
-          auto *CPT = Constructor->getType()->castAs<FunctionProtoType>();
-          CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
-          if (!CPT)
-            return false;
-          // TODO: check whether evaluating default arguments can throw.
-          // For now, we'll be conservative and assume that they can throw.
-          if (!CPT->isNothrow() || CPT->getNumParams() > 1)
-            return false;
-        }
-      }
-
-      return FoundConstructor;
-    }
-    return false;
-  case UTT_HasNothrowConstructor:
-    // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html
-    //   If __has_trivial_constructor (type) is true then the trait is
-    //   true, else if type is a cv class or union type (or array
-    //   thereof) with a default constructor that is known not to
-    //   throw an exception then the trait is true, else it is false.
-    if (T.isPODType(C) || T->isObjCLifetimeType())
-      return true;
-    if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) {
-      if (RD->hasTrivialDefaultConstructor() &&
-          !RD->hasNonTrivialDefaultConstructor())
-        return true;
-
-      bool FoundConstructor = false;
-      for (const auto *ND : Self.LookupConstructors(RD)) {
-        // FIXME: In C++0x, a constructor template can be a default constructor.
-        if (isa<FunctionTemplateDecl>(ND->getUnderlyingDecl()))
-          continue;
-        // UsingDecl itself is not a constructor
-        if (isa<UsingDecl>(ND))
-          continue;
-        auto *Constructor = cast<CXXConstructorDecl>(ND->getUnderlyingDecl());
-        if (Constructor->isDefaultConstructor()) {
-          FoundConstructor = true;
-          auto *CPT = Constructor->getType()->castAs<FunctionProtoType>();
-          CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
-          if (!CPT)
-            return false;
-          // FIXME: check whether evaluating default arguments can throw.
-          // For now, we'll be conservative and assume that they can throw.
-          if (!CPT->isNothrow() || CPT->getNumParams() > 0)
-            return false;
-        }
-      }
-      return FoundConstructor;
-    }
-    return false;
-  case UTT_HasVirtualDestructor:
-    // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
-    //   If type is a class type with a virtual destructor ([class.dtor])
-    //   then the trait is true, else it is false.
-    if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
-      if (CXXDestructorDecl *Destructor = Self.LookupDestructor(RD))
-        return Destructor->isVirtual();
-    return false;
-
-    // These type trait expressions are modeled on the specifications for the
-    // Embarcadero C++0x type trait functions:
-    //   http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index
-  case UTT_IsCompleteType:
-    // http://docwiki.embarcadero.com/RADStudio/XE/en/Is_complete_type_(typename_T_):
-    //   Returns True if and only if T is a complete type at the point of the
-    //   function call.
-    return !T->isIncompleteType();
-  case UTT_HasUniqueObjectRepresentations:
-    return C.hasUniqueObjectRepresentations(T);
-  case UTT_IsTriviallyRelocatable:
-    return IsTriviallyRelocatableType(Self, T);
-  case UTT_IsBitwiseCloneable:
-    return T.isBitwiseCloneableType(C);
-  case UTT_IsCppTriviallyRelocatable:
-    return Self.IsCXXTriviallyRelocatableType(T);
-  case UTT_IsReplaceable:
-    return Self.IsCXXReplaceableType(T);
-  case UTT_CanPassInRegs:
-    if (CXXRecordDecl *RD = T->getAsCXXRecordDecl(); RD && !T.hasQualifiers())
-      return RD->canPassInRegisters();
-    Self.Diag(KeyLoc, diag::err_builtin_pass_in_regs_non_class) << T;
-    return false;
-  case UTT_IsTriviallyEqualityComparable:
-    return isTriviallyEqualityComparableType(Self, T, KeyLoc);
-  case UTT_IsImplicitLifetime: {
-    DiagnoseVLAInCXXTypeTrait(Self, TInfo,
-                              tok::kw___builtin_is_implicit_lifetime);
-    DiagnoseAtomicInCXXTypeTrait(Self, TInfo,
-                                 tok::kw___builtin_is_implicit_lifetime);
-
-    // [basic.types.general] p9
-    // Scalar types, implicit-lifetime class types ([class.prop]),
-    // array types, and cv-qualified versions of these types
-    // are collectively called implicit-lifetime types.
-    QualType UnqualT = T->getCanonicalTypeUnqualified();
-    if (UnqualT->isScalarType())
-      return true;
-    if (UnqualT->isArrayType() || UnqualT->isVectorType())
-      return true;
-    const CXXRecordDecl *RD = UnqualT->getAsCXXRecordDecl();
-    if (!RD)
-      return false;
-
-    // [class.prop] p9
-    // A class S is an implicit-lifetime class if
-    //   - it is an aggregate whose destructor is not user-provided or
-    //   - it has at least one trivial eligible constructor and a trivial,
-    //     non-deleted destructor.
-    const CXXDestructorDecl *Dtor = RD->getDestructor();
-    if (UnqualT->isAggregateType())
-      if (Dtor && !Dtor->isUserProvided())
-        return true;
-    if (RD->hasTrivialDestructor() && (!Dtor || !Dtor->isDeleted()))
-      if (RD->hasTrivialDefaultConstructor() ||
-          RD->hasTrivialCopyConstructor() || RD->hasTrivialMoveConstructor())
-        return true;
-    return false;
-  }
-  case UTT_IsIntangibleType:
-    assert(Self.getLangOpts().HLSL && "intangible types are HLSL-only feature");
-    if (!T->isVoidType() && !T->isIncompleteArrayType())
-      if (Self.RequireCompleteType(TInfo->getTypeLoc().getBeginLoc(), T,
-                                   diag::err_incomplete_type))
-        return false;
-    if (DiagnoseVLAInCXXTypeTrait(Self, TInfo,
-                                  tok::kw___builtin_hlsl_is_intangible))
-      return false;
-    return T->isHLSLIntangibleType();
-
-  case UTT_IsTypedResourceElementCompatible:
-    assert(Self.getLangOpts().HLSL &&
-           "typed resource element compatible types are an HLSL-only feature");
-    if (T->isIncompleteType())
-      return false;
-
-    return Self.HLSL().IsTypedResourceElementCompatible(T);
-  }
-}
-
-static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceInfo *Lhs,
-                                    const TypeSourceInfo *Rhs, SourceLocation KeyLoc);
-
-static ExprResult CheckConvertibilityForTypeTraits(
-    Sema &Self, const TypeSourceInfo *Lhs, const TypeSourceInfo *Rhs,
-    SourceLocation KeyLoc, llvm::BumpPtrAllocator &OpaqueExprAllocator) {
-
-  QualType LhsT = Lhs->getType();
-  QualType RhsT = Rhs->getType();
-
-  // C++0x [meta.rel]p4:
-  //   Given the following function prototype:
-  //
-  //     template <class T>
-  //       typename add_rvalue_reference<T>::type create();
-  //
-  //   the predicate condition for a template specialization
-  //   is_convertible<From, To> shall be satisfied if and only if
-  //   the return expression in the following code would be
-  //   well-formed, including any implicit conversions to the return
-  //   type of the function:
-  //
-  //     To test() {
-  //       return create<From>();
-  //     }
-  //
-  //   Access checking is performed as if in a context unrelated to To and
-  //   From. Only the validity of the immediate context of the expression
-  //   of the return-statement (including conversions to the return type)
-  //   is considered.
-  //
-  // We model the initialization as a copy-initialization of a temporary
-  // of the appropriate type, which for this expression is identical to the
-  // return statement (since NRVO doesn't apply).
-
-  // Functions aren't allowed to return function or array types.
-  if (RhsT->isFunctionType() || RhsT->isArrayType())
-    return ExprError();
-
-  // A function definition requires a complete, non-abstract return type.
-  if (!Self.isCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT) ||
-      Self.isAbstractType(Rhs->getTypeLoc().getBeginLoc(), RhsT))
-    return ExprError();
-
-  // Compute the result of add_rvalue_reference.
-  if (LhsT->isObjectType() || LhsT->isFunctionType())
-    LhsT = Self.Context.getRValueReferenceType(LhsT);
-
-  // Build a fake source and destination for initialization.
-  InitializedEntity To(InitializedEntity::InitializeTemporary(RhsT));
-  Expr *From = new (OpaqueExprAllocator.Allocate<OpaqueValueExpr>())
-      OpaqueValueExpr(KeyLoc, LhsT.getNonLValueExprType(Self.Context),
-                      Expr::getValueKindForType(LhsT));
-  InitializationKind Kind =
-      InitializationKind::CreateCopy(KeyLoc, SourceLocation());
-
-  // Perform the initialization in an unevaluated context within a SFINAE
-  // trap at translation unit scope.
-  EnterExpressionEvaluationContext Unevaluated(
-      Self, Sema::ExpressionEvaluationContext::Unevaluated);
-  Sema::SFINAETrap SFINAE(Self, /*ForValidityCheck=*/true);
-  Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl());
-  InitializationSequence Init(Self, To, Kind, From);
-  if (Init.Failed())
-    return ExprError();
-
-  ExprResult Result = Init.Perform(Self, To, Kind, From);
-  if (Result.isInvalid() || SFINAE.hasErrorOccurred())
-    return ExprError();
-
-  return Result;
-}
-
-static APValue EvaluateSizeTTypeTrait(Sema &S, TypeTrait Kind,
-                                      SourceLocation KWLoc,
-                                      ArrayRef<TypeSourceInfo *> Args,
-                                      SourceLocation RParenLoc,
-                                      bool IsDependent) {
-  if (IsDependent)
-    return APValue();
-
-  switch (Kind) {
-  case TypeTrait::UTT_StructuredBindingSize: {
-    QualType T = Args[0]->getType();
-    SourceRange ArgRange = Args[0]->getTypeLoc().getSourceRange();
-    UnsignedOrNone Size =
-        S.GetDecompositionElementCount(T, ArgRange.getBegin());
-    if (!Size) {
-      S.Diag(KWLoc, diag::err_arg_is_not_destructurable) << T << ArgRange;
-      return APValue();
-    }
-    return APValue(
-        S.getASTContext().MakeIntValue(*Size, S.getASTContext().getSizeType()));
-    break;
-  }
-  default:
-    llvm_unreachable("Not a SizeT type trait");
-  }
-}
-
-static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind,
-                                     SourceLocation KWLoc,
-                                     ArrayRef<TypeSourceInfo *> Args,
-                                     SourceLocation RParenLoc,
-                                     bool IsDependent) {
-  if (IsDependent)
-    return false;
-
-  if (Kind <= UTT_Last)
-    return EvaluateUnaryTypeTrait(S, Kind, KWLoc, Args[0]);
-
-  // Evaluate ReferenceBindsToTemporary and ReferenceConstructsFromTemporary
-  // alongside the IsConstructible traits to avoid duplication.
-  if (Kind <= BTT_Last && Kind != BTT_ReferenceBindsToTemporary &&
-      Kind != BTT_ReferenceConstructsFromTemporary &&
-      Kind != BTT_ReferenceConvertsFromTemporary)
-    return EvaluateBinaryTypeTrait(S, Kind, Args[0],
-                                   Args[1], RParenLoc);
-
-  switch (Kind) {
-  case clang::BTT_ReferenceBindsToTemporary:
-  case clang::BTT_ReferenceConstructsFromTemporary:
-  case clang::BTT_ReferenceConvertsFromTemporary:
-  case clang::TT_IsConstructible:
-  case clang::TT_IsNothrowConstructible:
-  case clang::TT_IsTriviallyConstructible: {
-    // C++11 [meta.unary.prop]:
-    //   is_trivially_constructible is defined as:
-    //
-    //     is_constructible<T, Args...>::value is true and the variable
-    //     definition for is_constructible, as defined below, is known to call
-    //     no operation that is not trivial.
-    //
-    //   The predicate condition for a template specialization
-    //   is_constructible<T, Args...> shall be satisfied if and only if the
-    //   following variable definition would be well-formed for some invented
-    //   variable t:
-    //
-    //     T t(create<Args>()...);
-    assert(!Args.empty());
-
-    // Precondition: T and all types in the parameter pack Args shall be
-    // complete types, (possibly cv-qualified) void, or arrays of
-    // unknown bound.
-    for (const auto *TSI : Args) {
-      QualType ArgTy = TSI->getType();
-      if (ArgTy->isVoidType() || ArgTy->isIncompleteArrayType())
-        continue;
-
-      if (S.RequireCompleteType(KWLoc, ArgTy,
-          diag::err_incomplete_type_used_in_type_trait_expr))
-        return false;
-    }
-
-    // Make sure the first argument is not incomplete nor a function type.
-    QualType T = Args[0]->getType();
-    if (T->isIncompleteType() || T->isFunctionType())
-      return false;
-
-    // Make sure the first argument is not an abstract type.
-    CXXRecordDecl *RD = T->getAsCXXRecordDecl();
-    if (RD && RD->isAbstract())
-      return false;
-
-    llvm::BumpPtrAllocator OpaqueExprAllocator;
-    SmallVector<Expr *, 2> ArgExprs;
-    ArgExprs.reserve(Args.size() - 1);
-    for (unsigned I = 1, N = Args.size(); I != N; ++I) {
-      QualType ArgTy = Args[I]->getType();
-      if (ArgTy->isObjectType() || ArgTy->isFunctionType())
-        ArgTy = S.Context.getRValueReferenceType(ArgTy);
-      ArgExprs.push_back(
-          new (OpaqueExprAllocator.Allocate<OpaqueValueExpr>())
-              OpaqueValueExpr(Args[I]->getTypeLoc().getBeginLoc(),
-                              ArgTy.getNonLValueExprType(S.Context),
-                              Expr::getValueKindForType(ArgTy)));
-    }
-
-    // Perform the initialization in an unevaluated context within a SFINAE
-    // trap at translation unit scope.
-    EnterExpressionEvaluationContext Unevaluated(
-        S, Sema::ExpressionEvaluationContext::Unevaluated);
-    Sema::SFINAETrap SFINAE(S, /*ForValidityCheck=*/true);
-    Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
-    InitializedEntity To(
-        InitializedEntity::InitializeTemporary(S.Context, Args[0]));
-    InitializationKind InitKind(
-        Kind == clang::BTT_ReferenceConvertsFromTemporary
-            ? InitializationKind::CreateCopy(KWLoc, KWLoc)
-            : InitializationKind::CreateDirect(KWLoc, KWLoc, RParenLoc));
-    InitializationSequence Init(S, To, InitKind, ArgExprs);
-    if (Init.Failed())
-      return false;
-
-    ExprResult Result = Init.Perform(S, To, InitKind, ArgExprs);
-    if (Result.isInvalid() || SFINAE.hasErrorOccurred())
-      return false;
-
-    if (Kind == clang::TT_IsConstructible)
-      return true;
-
-    if (Kind == clang::BTT_ReferenceBindsToTemporary ||
-        Kind == clang::BTT_ReferenceConstructsFromTemporary ||
-        Kind == clang::BTT_ReferenceConvertsFromTemporary) {
-      if (!T->isReferenceType())
-        return false;
-
-      if (!Init.isDirectReferenceBinding())
-        return true;
-
-      if (Kind == clang::BTT_ReferenceBindsToTemporary)
-        return false;
-
-      QualType U = Args[1]->getType();
-      if (U->isReferenceType())
-        return false;
-
-      TypeSourceInfo *TPtr = S.Context.CreateTypeSourceInfo(
-          S.Context.getPointerType(T.getNonReferenceType()));
-      TypeSourceInfo *UPtr = S.Context.CreateTypeSourceInfo(
-          S.Context.getPointerType(U.getNonReferenceType()));
-      return !CheckConvertibilityForTypeTraits(S, UPtr, TPtr, RParenLoc,
-                                               OpaqueExprAllocator)
-                  .isInvalid();
-    }
-
-    if (Kind == clang::TT_IsNothrowConstructible)
-      return S.canThrow(Result.get()) == CT_Cannot;
-
-    if (Kind == clang::TT_IsTriviallyConstructible) {
-      // Under Objective-C ARC and Weak, if the destination has non-trivial
-      // Objective-C lifetime, this is a non-trivial construction.
-      if (T.getNonReferenceType().hasNonTrivialObjCLifetime())
-        return false;
-
-      // The initialization succeeded; now make sure there are no non-trivial
-      // calls.
-      return !Result.get()->hasNonTrivialCall(S.Context);
-    }
-
-    llvm_unreachable("unhandled type trait");
-    return false;
-  }
-    default: llvm_unreachable("not a TT");
-  }
-
-  return false;
-}
-
-namespace {
-void DiagnoseBuiltinDeprecation(Sema& S, TypeTrait Kind,
-                                SourceLocation KWLoc) {
-  TypeTrait Replacement;
-  switch (Kind) {
-    case UTT_HasNothrowAssign:
-    case UTT_HasNothrowMoveAssign:
-      Replacement = BTT_IsNothrowAssignable;
-      break;
-    case UTT_HasNothrowCopy:
-    case UTT_HasNothrowConstructor:
-      Replacement = TT_IsNothrowConstructible;
-      break;
-    case UTT_HasTrivialAssign:
-    case UTT_HasTrivialMoveAssign:
-      Replacement = BTT_IsTriviallyAssignable;
-      break;
-    case UTT_HasTrivialCopy:
-      Replacement = UTT_IsTriviallyCopyable;
-      break;
-    case UTT_HasTrivialDefaultConstructor:
-    case UTT_HasTrivialMoveConstructor:
-      Replacement = TT_IsTriviallyConstructible;
-      break;
-    case UTT_HasTrivialDestructor:
-      Replacement = UTT_IsTriviallyDestructible;
-      break;
-    case UTT_IsTriviallyRelocatable:
-      Replacement = clang::UTT_IsCppTriviallyRelocatable;
-      break;
-    default:
-      return;
-  }
-  S.Diag(KWLoc, diag::warn_deprecated_builtin)
-    << getTraitSpelling(Kind) << getTraitSpelling(Replacement);
-}
-}
-
-bool Sema::CheckTypeTraitArity(unsigned Arity, SourceLocation Loc, size_t N) {
-  if (Arity && N != Arity) {
-    Diag(Loc, diag::err_type_trait_arity)
-        << Arity << 0 << (Arity > 1) << (int)N << SourceRange(Loc);
-    return false;
-  }
-
-  if (!Arity && N == 0) {
-    Diag(Loc, diag::err_type_trait_arity)
-        << 1 << 1 << 1 << (int)N << SourceRange(Loc);
-    return false;
-  }
-  return true;
-}
-
-enum class TypeTraitReturnType {
-  Bool,
-  SizeT,
-};
-
-static TypeTraitReturnType GetReturnType(TypeTrait Kind) {
-  if (Kind == TypeTrait::UTT_StructuredBindingSize)
-    return TypeTraitReturnType::SizeT;
-  return TypeTraitReturnType::Bool;
-}
-
-ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
-                                ArrayRef<TypeSourceInfo *> Args,
-                                SourceLocation RParenLoc) {
-  if (!CheckTypeTraitArity(getTypeTraitArity(Kind), KWLoc, Args.size()))
-    return ExprError();
-
-  if (Kind <= UTT_Last && !CheckUnaryTypeTraitTypeCompleteness(
-                               *this, Kind, KWLoc, Args[0]->getType()))
-    return ExprError();
-
-  DiagnoseBuiltinDeprecation(*this, Kind, KWLoc);
-
-  bool Dependent = false;
-  for (unsigned I = 0, N = Args.size(); I != N; ++I) {
-    if (Args[I]->getType()->isDependentType()) {
-      Dependent = true;
-      break;
-    }
-  }
-
-  switch (GetReturnType(Kind)) {
-  case TypeTraitReturnType::Bool: {
-    bool Result = EvaluateBooleanTypeTrait(*this, Kind, KWLoc, Args, RParenLoc,
-                                           Dependent);
-    return TypeTraitExpr::Create(Context, Context.getLogicalOperationType(),
-                                 KWLoc, Kind, Args, RParenLoc, Result);
-  }
-  case TypeTraitReturnType::SizeT: {
-    APValue Result =
-        EvaluateSizeTTypeTrait(*this, Kind, KWLoc, Args, RParenLoc, Dependent);
-    return TypeTraitExpr::Create(Context, Context.getSizeType(), KWLoc, Kind,
-                                 Args, RParenLoc, Result);
-  }
-  }
-  llvm_unreachable("unhandled type trait return type");
-}
-
-ExprResult Sema::ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
-                                ArrayRef<ParsedType> Args,
-                                SourceLocation RParenLoc) {
-  SmallVector<TypeSourceInfo *, 4> ConvertedArgs;
-  ConvertedArgs.reserve(Args.size());
-
-  for (unsigned I = 0, N = Args.size(); I != N; ++I) {
-    TypeSourceInfo *TInfo;
-    QualType T = GetTypeFromParser(Args[I], &TInfo);
-    if (!TInfo)
-      TInfo = Context.getTrivialTypeSourceInfo(T, KWLoc);
-
-    ConvertedArgs.push_back(TInfo);
-  }
-
-  return BuildTypeTrait(Kind, KWLoc, ConvertedArgs, RParenLoc);
-}
-
-static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceInfo *Lhs,
-                                    const TypeSourceInfo *Rhs, SourceLocation KeyLoc) {
-  QualType LhsT = Lhs->getType();
-  QualType RhsT = Rhs->getType();
-
-  assert(!LhsT->isDependentType() && !RhsT->isDependentType() &&
-         "Cannot evaluate traits of dependent types");
-
-  switch(BTT) {
-  case BTT_IsBaseOf: {
-    // C++0x [meta.rel]p2
-    // Base is a base class of Derived without regard to cv-qualifiers or
-    // Base and Derived are not unions and name the same class type without
-    // regard to cv-qualifiers.
-
-    const RecordType *lhsRecord = LhsT->getAs<RecordType>();
-    const RecordType *rhsRecord = RhsT->getAs<RecordType>();
-    if (!rhsRecord || !lhsRecord) {
-      const ObjCObjectType *LHSObjTy = LhsT->getAs<ObjCObjectType>();
-      const ObjCObjectType *RHSObjTy = RhsT->getAs<ObjCObjectType>();
-      if (!LHSObjTy || !RHSObjTy)
-        return false;
-
-      ObjCInterfaceDecl *BaseInterface = LHSObjTy->getInterface();
-      ObjCInterfaceDecl *DerivedInterface = RHSObjTy->getInterface();
-      if (!BaseInterface || !DerivedInterface)
-        return false;
-
-      if (Self.RequireCompleteType(
-              Rhs->getTypeLoc().getBeginLoc(), RhsT,
-              diag::err_incomplete_type_used_in_type_trait_expr))
-        return false;
-
-      return BaseInterface->isSuperClassOf(DerivedInterface);
-    }
-
-    assert(Self.Context.hasSameUnqualifiedType(LhsT, RhsT)
-             == (lhsRecord == rhsRecord));
-
-    // Unions are never base classes, and never have base classes.
-    // It doesn't matter if they are complete or not. See PR#41843
-    if (lhsRecord && lhsRecord->getDecl()->isUnion())
-      return false;
-    if (rhsRecord && rhsRecord->getDecl()->isUnion())
-      return false;
-
-    if (lhsRecord == rhsRecord)
-      return true;
-
-    // C++0x [meta.rel]p2:
-    //   If Base and Derived are class types and are different types
-    //   (ignoring possible cv-qualifiers) then Derived shall be a
-    //   complete type.
-    if (Self.RequireCompleteType(
-            Rhs->getTypeLoc().getBeginLoc(), RhsT,
-            diag::err_incomplete_type_used_in_type_trait_expr))
-      return false;
-
-    return cast<CXXRecordDecl>(rhsRecord->getDecl())
-      ->isDerivedFrom(cast<CXXRecordDecl>(lhsRecord->getDecl()));
-  }
-  case BTT_IsVirtualBaseOf: {
-    const RecordType *BaseRecord = LhsT->getAs<RecordType>();
-    const RecordType *DerivedRecord = RhsT->getAs<RecordType>();
-
-    if (!BaseRecord || !DerivedRecord) {
-      DiagnoseVLAInCXXTypeTrait(Self, Lhs,
-                                tok::kw___builtin_is_virtual_base_of);
-      DiagnoseVLAInCXXTypeTrait(Self, Rhs,
-                                tok::kw___builtin_is_virtual_base_of);
-      return false;
-    }
-
-    if (BaseRecord->isUnionType() || DerivedRecord->isUnionType())
-      return false;
-
-    if (!BaseRecord->isStructureOrClassType() ||
-        !DerivedRecord->isStructureOrClassType())
-      return false;
-
-    if (Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT,
-                                 diag::err_incomplete_type))
-      return false;
-
-    return cast<CXXRecordDecl>(DerivedRecord->getDecl())
-        ->isVirtuallyDerivedFrom(cast<CXXRecordDecl>(BaseRecord->getDecl()));
-  }
-  case BTT_IsSame:
-    return Self.Context.hasSameType(LhsT, RhsT);
-  case BTT_TypeCompatible: {
-    // GCC ignores cv-qualifiers on arrays for this builtin.
-    Qualifiers LhsQuals, RhsQuals;
-    QualType Lhs = Self.getASTContext().getUnqualifiedArrayType(LhsT, LhsQuals);
-    QualType Rhs = Self.getASTContext().getUnqualifiedArrayType(RhsT, RhsQuals);
-    return Self.Context.typesAreCompatible(Lhs, Rhs);
-  }
-  case BTT_IsConvertible:
-  case BTT_IsConvertibleTo:
-  case BTT_IsNothrowConvertible: {
-    if (RhsT->isVoidType())
-      return LhsT->isVoidType();
-    llvm::BumpPtrAllocator OpaqueExprAllocator;
-    ExprResult Result = CheckConvertibilityForTypeTraits(Self, Lhs, Rhs, KeyLoc,
-                                                         OpaqueExprAllocator);
-    if (Result.isInvalid())
-      return false;
-
-    if (BTT != BTT_IsNothrowConvertible)
-      return true;
-
-    return Self.canThrow(Result.get()) == CT_Cannot;
-  }
-
-  case BTT_IsAssignable:
-  case BTT_IsNothrowAssignable:
-  case BTT_IsTriviallyAssignable: {
-    // C++11 [meta.unary.prop]p3:
-    //   is_trivially_assignable is defined as:
-    //     is_assignable<T, U>::value is true and the assignment, as defined by
-    //     is_assignable, is known to call no operation that is not trivial
-    //
-    //   is_assignable is defined as:
-    //     The expression declval<T>() = declval<U>() is well-formed when
-    //     treated as an unevaluated operand (Clause 5).
-    //
-    //   For both, T and U shall be complete types, (possibly cv-qualified)
-    //   void, or arrays of unknown bound.
-    if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType() &&
-        Self.RequireCompleteType(
-            Lhs->getTypeLoc().getBeginLoc(), LhsT,
-            diag::err_incomplete_type_used_in_type_trait_expr))
-      return false;
-    if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType() &&
-        Self.RequireCompleteType(
-            Rhs->getTypeLoc().getBeginLoc(), RhsT,
-            diag::err_incomplete_type_used_in_type_trait_expr))
-      return false;
-
-    // cv void is never assignable.
-    if (LhsT->isVoidType() || RhsT->isVoidType())
-      return false;
-
-    // Build expressions that emulate the effect of declval<T>() and
-    // declval<U>().
-    if (LhsT->isObjectType() || LhsT->isFunctionType())
-      LhsT = Self.Context.getRValueReferenceType(LhsT);
-    if (RhsT->isObjectType() || RhsT->isFunctionType())
-      RhsT = Self.Context.getRValueReferenceType(RhsT);
-    OpaqueValueExpr Lhs(KeyLoc, LhsT.getNonLValueExprType(Self.Context),
-                        Expr::getValueKindForType(LhsT));
-    OpaqueValueExpr Rhs(KeyLoc, RhsT.getNonLValueExprType(Self.Context),
-                        Expr::getValueKindForType(RhsT));
-
-    // Attempt the assignment in an unevaluated context within a SFINAE
-    // trap at translation unit scope.
-    EnterExpressionEvaluationContext Unevaluated(
-        Self, Sema::ExpressionEvaluationContext::Unevaluated);
-    Sema::SFINAETrap SFINAE(Self, /*ForValidityCheck=*/true);
-    Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl());
-    ExprResult Result = Self.BuildBinOp(/*S=*/nullptr, KeyLoc, BO_Assign, &Lhs,
-                                        &Rhs);
-    if (Result.isInvalid())
-      return false;
-
-    // Treat the assignment as unused for the purpose of -Wdeprecated-volatile.
-    Self.CheckUnusedVolatileAssignment(Result.get());
-
-    if (SFINAE.hasErrorOccurred())
-      return false;
-
-    if (BTT == BTT_IsAssignable)
-      return true;
-
-    if (BTT == BTT_IsNothrowAssignable)
-      return Self.canThrow(Result.get()) == CT_Cannot;
-
-    if (BTT == BTT_IsTriviallyAssignable) {
-      // Under Objective-C ARC and Weak, if the destination has non-trivial
-      // Objective-C lifetime, this is a non-trivial assignment.
-      if (LhsT.getNonReferenceType().hasNonTrivialObjCLifetime())
-        return false;
-
-      return !Result.get()->hasNonTrivialCall(Self.Context);
-    }
-
-    llvm_unreachable("unhandled type trait");
-    return false;
-  }
-  case BTT_IsLayoutCompatible: {
-    if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType())
-      Self.RequireCompleteType(Lhs->getTypeLoc().getBeginLoc(), LhsT,
-                               diag::err_incomplete_type);
-    if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType())
-      Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT,
-                               diag::err_incomplete_type);
-
-    DiagnoseVLAInCXXTypeTrait(Self, Lhs, tok::kw___is_layout_compatible);
-    DiagnoseVLAInCXXTypeTrait(Self, Rhs, tok::kw___is_layout_compatible);
-
-    return Self.IsLayoutCompatible(LhsT, RhsT);
-  }
-  case BTT_IsPointerInterconvertibleBaseOf: {
-    if (LhsT->isStructureOrClassType() && RhsT->isStructureOrClassType() &&
-        !Self.getASTContext().hasSameUnqualifiedType(LhsT, RhsT)) {
-      Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT,
-                               diag::err_incomplete_type);
-    }
-
-    DiagnoseVLAInCXXTypeTrait(Self, Lhs,
-                              tok::kw___is_pointer_interconvertible_base_of);
-    DiagnoseVLAInCXXTypeTrait(Self, Rhs,
-                              tok::kw___is_pointer_interconvertible_base_of);
-
-    return Self.IsPointerInterconvertibleBaseOf(Lhs, Rhs);
-  }
-  case BTT_IsDeducible: {
-    const auto *TSTToBeDeduced = cast<DeducedTemplateSpecializationType>(LhsT);
-    sema::TemplateDeductionInfo Info(KeyLoc);
-    return Self.DeduceTemplateArgumentsFromType(
-               TSTToBeDeduced->getTemplateName().getAsTemplateDecl(), RhsT,
-               Info) == TemplateDeductionResult::Success;
-  }
-  case BTT_IsScalarizedLayoutCompatible: {
-    if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType() &&
-        Self.RequireCompleteType(Lhs->getTypeLoc().getBeginLoc(), LhsT,
-                                 diag::err_incomplete_type))
-      return true;
-    if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType() &&
-        Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT,
-                                 diag::err_incomplete_type))
-      return true;
-
-    DiagnoseVLAInCXXTypeTrait(
-        Self, Lhs, tok::kw___builtin_hlsl_is_scalarized_layout_compatible);
-    DiagnoseVLAInCXXTypeTrait(
-        Self, Rhs, tok::kw___builtin_hlsl_is_scalarized_layout_compatible);
-
-    return Self.HLSL().IsScalarizedLayoutCompatible(LhsT, RhsT);
-  }
-  default:
-    llvm_unreachable("not a BTT");
-  }
-  llvm_unreachable("Unknown type trait or not implemented");
-}
-
-ExprResult Sema::ActOnArrayTypeTrait(ArrayTypeTrait ATT,
-                                     SourceLocation KWLoc,
-                                     ParsedType Ty,
-                                     Expr* DimExpr,
-                                     SourceLocation RParen) {
-  TypeSourceInfo *TSInfo;
-  QualType T = GetTypeFromParser(Ty, &TSInfo);
-  if (!TSInfo)
-    TSInfo = Context.getTrivialTypeSourceInfo(T);
-
-  return BuildArrayTypeTrait(ATT, KWLoc, TSInfo, DimExpr, RParen);
-}
-
-static uint64_t EvaluateArrayTypeTrait(Sema &Self, ArrayTypeTrait ATT,
-                                           QualType T, Expr *DimExpr,
-                                           SourceLocation KeyLoc) {
-  assert(!T->isDependentType() && "Cannot evaluate traits of dependent type");
-
-  switch(ATT) {
-  case ATT_ArrayRank:
-    if (T->isArrayType()) {
-      unsigned Dim = 0;
-      while (const ArrayType *AT = Self.Context.getAsArrayType(T)) {
-        ++Dim;
-        T = AT->getElementType();
-      }
-      return Dim;
-    }
-    return 0;
-
-  case ATT_ArrayExtent: {
-    llvm::APSInt Value;
-    uint64_t Dim;
-    if (Self.VerifyIntegerConstantExpression(
-                DimExpr, &Value, diag::err_dimension_expr_not_constant_integer)
-            .isInvalid())
-      return 0;
-    if (Value.isSigned() && Value.isNegative()) {
-      Self.Diag(KeyLoc, diag::err_dimension_expr_not_constant_integer)
-        << DimExpr->getSourceRange();
-      return 0;
-    }
-    Dim = Value.getLimitedValue();
-
-    if (T->isArrayType()) {
-      unsigned D = 0;
-      bool Matched = false;
-      while (const ArrayType *AT = Self.Context.getAsArrayType(T)) {
-        if (Dim == D) {
-          Matched = true;
-          break;
-        }
-        ++D;
-        T = AT->getElementType();
-      }
-
-      if (Matched && T->isArrayType()) {
-        if (const ConstantArrayType *CAT = Self.Context.getAsConstantArrayType(T))
-          return CAT->getLimitedSize();
-      }
-    }
-    return 0;
-  }
-  }
-  llvm_unreachable("Unknown type trait or not implemented");
-}
-
-ExprResult Sema::BuildArrayTypeTrait(ArrayTypeTrait ATT,
-                                     SourceLocation KWLoc,
-                                     TypeSourceInfo *TSInfo,
-                                     Expr* DimExpr,
-                                     SourceLocation RParen) {
-  QualType T = TSInfo->getType();
-
-  // FIXME: This should likely be tracked as an APInt to remove any host
-  // assumptions about the width of size_t on the target.
-  uint64_t Value = 0;
-  if (!T->isDependentType())
-    Value = EvaluateArrayTypeTrait(*this, ATT, T, DimExpr, KWLoc);
-
-  // While the specification for these traits from the Embarcadero C++
-  // compiler's documentation says the return type is 'unsigned int', Clang
-  // returns 'size_t'. On Windows, the primary platform for the Embarcadero
-  // compiler, there is no difference. On several other platforms this is an
-  // important distinction.
-  return new (Context) ArrayTypeTraitExpr(KWLoc, ATT, TSInfo, Value, DimExpr,
-                                          RParen, Context.getSizeType());
-}
-
-ExprResult Sema::ActOnExpressionTrait(ExpressionTrait ET,
-                                      SourceLocation KWLoc,
-                                      Expr *Queried,
-                                      SourceLocation RParen) {
-  // If error parsing the expression, ignore.
-  if (!Queried)
-    return ExprError();
-
-  ExprResult Result = BuildExpressionTrait(ET, KWLoc, Queried, RParen);
-
-  return Result;
-}
-
-static bool EvaluateExpressionTrait(ExpressionTrait ET, Expr *E) {
-  switch (ET) {
-  case ET_IsLValueExpr: return E->isLValue();
-  case ET_IsRValueExpr:
-    return E->isPRValue();
-  }
-  llvm_unreachable("Expression trait not covered by switch");
-}
-
-ExprResult Sema::BuildExpressionTrait(ExpressionTrait ET,
-                                      SourceLocation KWLoc,
-                                      Expr *Queried,
-                                      SourceLocation RParen) {
-  if (Queried->isTypeDependent()) {
-    // Delay type-checking for type-dependent expressions.
-  } else if (Queried->hasPlaceholderType()) {
-    ExprResult PE = CheckPlaceholderExpr(Queried);
-    if (PE.isInvalid()) return ExprError();
-    return BuildExpressionTrait(ET, KWLoc, PE.get(), RParen);
-  }
-
-  bool Value = EvaluateExpressionTrait(ET, Queried);
-
-  return new (Context)
-      ExpressionTraitExpr(KWLoc, ET, Queried, Value, RParen, Context.BoolTy);
-}
 
 QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS,
                                             ExprValueKind &VK,
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp
new file mode 100644
index 0000000000000..763d37071b134
--- /dev/null
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -0,0 +1,1919 @@
+//===----- SemaTypeTraits.cpp - Semantic Analysis for C++ Type Traits -----===//
+//
+// 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 implements semantic analysis for C++ type traits.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/DeclCXX.h"
+#include "clang/Basic/DiagnosticParse.h"
+#include "clang/Basic/DiagnosticSema.h"
+#include "clang/Sema/EnterExpressionEvaluationContext.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Overload.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaHLSL.h"
+
+using namespace clang;
+
+static CXXMethodDecl *LookupSpecialMemberFromXValue(Sema &SemaRef,
+                                                    const CXXRecordDecl *RD,
+                                                    bool Assign) {
+  RD = RD->getDefinition();
+  SourceLocation LookupLoc = RD->getLocation();
+
+  CanQualType CanTy = SemaRef.getASTContext().getCanonicalType(
+      SemaRef.getASTContext().getTagDeclType(RD));
+  DeclarationName Name;
+  Expr *Arg = nullptr;
+  unsigned NumArgs;
+
+  QualType ArgType = CanTy;
+  ExprValueKind VK = clang::VK_XValue;
+
+  if (Assign)
+    Name =
+        SemaRef.getASTContext().DeclarationNames.getCXXOperatorName(OO_Equal);
+  else
+    Name =
+        SemaRef.getASTContext().DeclarationNames.getCXXConstructorName(CanTy);
+
+  OpaqueValueExpr FakeArg(LookupLoc, ArgType, VK);
+  NumArgs = 1;
+  Arg = &FakeArg;
+
+  // Create the object argument
+  QualType ThisTy = CanTy;
+  Expr::Classification Classification =
+      OpaqueValueExpr(LookupLoc, ThisTy, VK_LValue)
+          .Classify(SemaRef.getASTContext());
+
+  // Now we perform lookup on the name we computed earlier and do overload
+  // resolution. Lookup is only performed directly into the class since there
+  // will always be a (possibly implicit) declaration to shadow any others.
+  OverloadCandidateSet OCS(LookupLoc, OverloadCandidateSet::CSK_Normal);
+  DeclContext::lookup_result R = RD->lookup(Name);
+
+  if (R.empty())
+    return nullptr;
+
+  // Copy the candidates as our processing of them may load new declarations
+  // from an external source and invalidate lookup_result.
+  SmallVector<NamedDecl *, 8> Candidates(R.begin(), R.end());
+
+  for (NamedDecl *CandDecl : Candidates) {
+    if (CandDecl->isInvalidDecl())
+      continue;
+
+    DeclAccessPair Cand = DeclAccessPair::make(CandDecl, clang::AS_none);
+    auto CtorInfo = getConstructorInfo(Cand);
+    if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(Cand->getUnderlyingDecl())) {
+      if (Assign)
+        SemaRef.AddMethodCandidate(M, Cand, const_cast<CXXRecordDecl *>(RD),
+                                   ThisTy, Classification,
+                                   llvm::ArrayRef(&Arg, NumArgs), OCS, true);
+      else {
+        assert(CtorInfo);
+        SemaRef.AddOverloadCandidate(CtorInfo.Constructor, CtorInfo.FoundDecl,
+                                     llvm::ArrayRef(&Arg, NumArgs), OCS,
+                                     /*SuppressUserConversions*/ true);
+      }
+    } else if (FunctionTemplateDecl *Tmpl =
+                   dyn_cast<FunctionTemplateDecl>(Cand->getUnderlyingDecl())) {
+      if (Assign)
+        SemaRef.AddMethodTemplateCandidate(
+            Tmpl, Cand, const_cast<CXXRecordDecl *>(RD), nullptr, ThisTy,
+            Classification, llvm::ArrayRef(&Arg, NumArgs), OCS, true);
+      else {
+        assert(CtorInfo);
+        SemaRef.AddTemplateOverloadCandidate(
+            CtorInfo.ConstructorTmpl, CtorInfo.FoundDecl, nullptr,
+            llvm::ArrayRef(&Arg, NumArgs), OCS, true);
+      }
+    }
+  }
+
+  OverloadCandidateSet::iterator Best;
+  switch (OCS.BestViableFunction(SemaRef, LookupLoc, Best)) {
+  case OR_Success:
+    return cast<CXXMethodDecl>(Best->Function);
+  default:
+    return nullptr;
+  }
+}
+
+static bool hasSuitableConstructorForRelocation(Sema &SemaRef,
+                                                const CXXRecordDecl *D,
+                                                bool AllowUserDefined) {
+  assert(D->hasDefinition() && !D->isInvalidDecl());
+
+  if (D->hasSimpleMoveConstructor() || D->hasSimpleCopyConstructor())
+    return true;
+
+  CXXMethodDecl *Decl =
+      LookupSpecialMemberFromXValue(SemaRef, D, /*Assign=*/false);
+  return Decl && Decl->isUserProvided() == AllowUserDefined;
+}
+
+static bool hasSuitableMoveAssignmentOperatorForRelocation(
+    Sema &SemaRef, const CXXRecordDecl *D, bool AllowUserDefined) {
+  assert(D->hasDefinition() && !D->isInvalidDecl());
+
+  if (D->hasSimpleMoveAssignment() || D->hasSimpleCopyAssignment())
+    return true;
+
+  CXXMethodDecl *Decl =
+      LookupSpecialMemberFromXValue(SemaRef, D, /*Assign=*/true);
+  if (!Decl)
+    return false;
+
+  return Decl && Decl->isUserProvided() == AllowUserDefined;
+}
+
+// [C++26][class.prop]
+// A class C is default-movable if
+// - overload resolution for direct-initializing an object of type C
+// from an xvalue of type C selects a constructor that is a direct member of C
+// and is neither user-provided nor deleted,
+// - overload resolution for assigning to an lvalue of type C from an xvalue of
+// type C selects an assignment operator function that is a direct member of C
+// and is neither user-provided nor deleted, and C has a destructor that is
+// neither user-provided nor deleted.
+static bool IsDefaultMovable(Sema &SemaRef, const CXXRecordDecl *D) {
+  if (!hasSuitableConstructorForRelocation(SemaRef, D,
+                                           /*AllowUserDefined=*/false))
+    return false;
+
+  if (!hasSuitableMoveAssignmentOperatorForRelocation(
+          SemaRef, D, /*AllowUserDefined=*/false))
+    return false;
+
+  CXXDestructorDecl *Dtr = D->getDestructor();
+
+  if (!Dtr)
+    return true;
+
+  if (Dtr->isUserProvided() && (!Dtr->isDefaulted() || Dtr->isDeleted()))
+    return false;
+
+  return !Dtr->isDeleted();
+}
+
+// [C++26][class.prop]
+// A class is eligible for trivial relocation unless it...
+static bool IsEligibleForTrivialRelocation(Sema &SemaRef,
+                                           const CXXRecordDecl *D) {
+
+  for (const CXXBaseSpecifier &B : D->bases()) {
+    const auto *BaseDecl = B.getType()->getAsCXXRecordDecl();
+    if (!BaseDecl)
+      continue;
+    // ... has any virtual base classes
+    // ... has a base class that is not a trivially relocatable class
+    if (B.isVirtual() || (!BaseDecl->isDependentType() &&
+                          !SemaRef.IsCXXTriviallyRelocatableType(B.getType())))
+      return false;
+  }
+
+  for (const FieldDecl *Field : D->fields()) {
+    if (Field->getType()->isDependentType())
+      continue;
+    if (Field->getType()->isReferenceType())
+      continue;
+    // ... has a non-static data member of an object type that is not
+    // of a trivially relocatable type
+    if (!SemaRef.IsCXXTriviallyRelocatableType(Field->getType()))
+      return false;
+  }
+  return !D->hasDeletedDestructor();
+}
+
+// [C++26][class.prop]
+// A class C is eligible for replacement unless
+static bool IsEligibleForReplacement(Sema &SemaRef, const CXXRecordDecl *D) {
+
+  for (const CXXBaseSpecifier &B : D->bases()) {
+    const auto *BaseDecl = B.getType()->getAsCXXRecordDecl();
+    if (!BaseDecl)
+      continue;
+    // it has a base class that is not a replaceable class
+    if (!BaseDecl->isDependentType() &&
+        !SemaRef.IsCXXReplaceableType(B.getType()))
+      return false;
+  }
+
+  for (const FieldDecl *Field : D->fields()) {
+    if (Field->getType()->isDependentType())
+      continue;
+
+    // it has a non-static data member that is not of a replaceable type,
+    if (!SemaRef.IsCXXReplaceableType(Field->getType()))
+      return false;
+  }
+  return !D->hasDeletedDestructor();
+}
+
+ASTContext::CXXRecordDeclRelocationInfo
+Sema::CheckCXX2CRelocatableAndReplaceable(const CXXRecordDecl *D) {
+  ASTContext::CXXRecordDeclRelocationInfo Info{false, false};
+
+  if (!getLangOpts().CPlusPlus || D->isInvalidDecl())
+    return Info;
+
+  assert(D->hasDefinition());
+
+  // This is part of "eligible for replacement", however we defer it
+  // to avoid extraneous computations.
+  auto HasSuitableSMP = [&] {
+    return hasSuitableConstructorForRelocation(*this, D,
+                                               /*AllowUserDefined=*/true) &&
+           hasSuitableMoveAssignmentOperatorForRelocation(
+               *this, D, /*AllowUserDefined=*/true);
+  };
+
+  auto IsUnion = [&, Is = std::optional<bool>{}]() mutable {
+    if (!Is.has_value())
+      Is = D->isUnion() && !D->hasUserDeclaredCopyConstructor() &&
+           !D->hasUserDeclaredCopyAssignment() &&
+           !D->hasUserDeclaredMoveOperation() &&
+           !D->hasUserDeclaredDestructor();
+    return *Is;
+  };
+
+  auto IsDefaultMovable = [&, Is = std::optional<bool>{}]() mutable {
+    if (!Is.has_value())
+      Is = ::IsDefaultMovable(*this, D);
+    return *Is;
+  };
+
+  Info.IsRelocatable = [&] {
+    if (D->isDependentType())
+      return false;
+
+    // if it is eligible for trivial relocation
+    if (!IsEligibleForTrivialRelocation(*this, D))
+      return false;
+
+    // has the trivially_relocatable_if_eligible class-property-specifier,
+    if (D->hasAttr<TriviallyRelocatableAttr>())
+      return true;
+
+    // is a union with no user-declared special member functions, or
+    if (IsUnion())
+      return true;
+
+    // is default-movable.
+    return IsDefaultMovable();
+  }();
+
+  Info.IsReplaceable = [&] {
+    if (D->isDependentType())
+      return false;
+
+    // A class C is a replaceable class if it is eligible for replacement
+    if (!IsEligibleForReplacement(*this, D))
+      return false;
+
+    // has the replaceable_if_eligible class-property-specifier
+    if (D->hasAttr<ReplaceableAttr>())
+      return HasSuitableSMP();
+
+    // is a union with no user-declared special member functions, or
+    if (IsUnion())
+      return HasSuitableSMP();
+
+    // is default-movable.
+    return IsDefaultMovable();
+  }();
+
+  return Info;
+}
+
+static bool IsCXXTriviallyRelocatableType(Sema &S, const CXXRecordDecl *RD) {
+  if (std::optional<ASTContext::CXXRecordDeclRelocationInfo> Info =
+          S.getASTContext().getRelocationInfoForCXXRecord(RD))
+    return Info->IsRelocatable;
+  ASTContext::CXXRecordDeclRelocationInfo Info =
+      S.CheckCXX2CRelocatableAndReplaceable(RD);
+  S.getASTContext().setRelocationInfoForCXXRecord(RD, Info);
+  return Info.IsRelocatable;
+}
+
+bool Sema::IsCXXTriviallyRelocatableType(QualType Type) {
+
+  QualType BaseElementType = getASTContext().getBaseElementType(Type);
+
+  if (Type->isVariableArrayType())
+    return false;
+
+  if (BaseElementType.hasNonTrivialObjCLifetime())
+    return false;
+
+  if (BaseElementType.hasAddressDiscriminatedPointerAuth())
+    return false;
+
+  if (BaseElementType->isIncompleteType())
+    return false;
+
+  if (BaseElementType->isScalarType() || BaseElementType->isVectorType())
+    return true;
+
+  if (const auto *RD = BaseElementType->getAsCXXRecordDecl())
+    return ::IsCXXTriviallyRelocatableType(*this, RD);
+
+  return false;
+}
+
+static bool IsCXXReplaceableType(Sema &S, const CXXRecordDecl *RD) {
+  if (std::optional<ASTContext::CXXRecordDeclRelocationInfo> Info =
+          S.getASTContext().getRelocationInfoForCXXRecord(RD))
+    return Info->IsReplaceable;
+  ASTContext::CXXRecordDeclRelocationInfo Info =
+      S.CheckCXX2CRelocatableAndReplaceable(RD);
+  S.getASTContext().setRelocationInfoForCXXRecord(RD, Info);
+  return Info.IsReplaceable;
+}
+
+bool Sema::IsCXXReplaceableType(QualType Type) {
+  if (Type.isConstQualified() || Type.isVolatileQualified())
+    return false;
+
+  if (Type->isVariableArrayType())
+    return false;
+
+  QualType BaseElementType =
+      getASTContext().getBaseElementType(Type.getUnqualifiedType());
+  if (BaseElementType->isIncompleteType())
+    return false;
+  if (BaseElementType->isScalarType())
+    return true;
+  if (const auto *RD = BaseElementType->getAsCXXRecordDecl())
+    return ::IsCXXReplaceableType(*this, RD);
+  return false;
+}
+
+
+/// Checks that type T is not a VLA.
+///
+/// @returns @c true if @p T is VLA and a diagnostic was emitted,
+/// @c false otherwise.
+static bool DiagnoseVLAInCXXTypeTrait(Sema &S, const TypeSourceInfo *T,
+                                      clang::tok::TokenKind TypeTraitID) {
+  if (!T->getType()->isVariableArrayType())
+    return false;
+
+  S.Diag(T->getTypeLoc().getBeginLoc(), diag::err_vla_unsupported)
+      << 1 << TypeTraitID;
+  return true;
+}
+
+/// Checks that type T is not an atomic type (_Atomic).
+///
+/// @returns @c true if @p T is VLA and a diagnostic was emitted,
+/// @c false otherwise.
+static bool DiagnoseAtomicInCXXTypeTrait(Sema &S, const TypeSourceInfo *T,
+                                         clang::tok::TokenKind TypeTraitID) {
+  if (!T->getType()->isAtomicType())
+    return false;
+
+  S.Diag(T->getTypeLoc().getBeginLoc(), diag::err_atomic_unsupported)
+      << TypeTraitID;
+  return true;
+}
+
+/// Check the completeness of a type in a unary type trait.
+///
+/// If the particular type trait requires a complete type, tries to complete
+/// it. If completing the type fails, a diagnostic is emitted and false
+/// returned. If completing the type succeeds or no completion was required,
+/// returns true.
+static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
+                                                SourceLocation Loc,
+                                                QualType ArgTy) {
+  // C++0x [meta.unary.prop]p3:
+  //   For all of the class templates X declared in this Clause, instantiating
+  //   that template with a template argument that is a class template
+  //   specialization may result in the implicit instantiation of the template
+  //   argument if and only if the semantics of X require that the argument
+  //   must be a complete type.
+  // We apply this rule to all the type trait expressions used to implement
+  // these class templates. We also try to follow any GCC documented behavior
+  // in these expressions to ensure portability of standard libraries.
+  switch (UTT) {
+  default: llvm_unreachable("not a UTT");
+    // is_complete_type somewhat obviously cannot require a complete type.
+  case UTT_IsCompleteType:
+                           // Fall-through
+
+           // These traits are modeled on the type predicates in C++0x
+           // [meta.unary.cat] and [meta.unary.comp]. They are not specified as
+           // requiring a complete type, as whether or not they return true cannot be
+           // impacted by the completeness of the type.
+  case UTT_IsVoid:
+  case UTT_IsIntegral:
+  case UTT_IsFloatingPoint:
+  case UTT_IsArray:
+  case UTT_IsBoundedArray:
+  case UTT_IsPointer:
+  case UTT_IsLvalueReference:
+  case UTT_IsRvalueReference:
+  case UTT_IsMemberFunctionPointer:
+  case UTT_IsMemberObjectPointer:
+  case UTT_IsEnum:
+  case UTT_IsScopedEnum:
+  case UTT_IsUnion:
+  case UTT_IsClass:
+  case UTT_IsFunction:
+  case UTT_IsReference:
+  case UTT_IsArithmetic:
+  case UTT_IsFundamental:
+  case UTT_IsObject:
+  case UTT_IsScalar:
+  case UTT_IsCompound:
+  case UTT_IsMemberPointer:
+  case UTT_IsTypedResourceElementCompatible:
+                                             // Fall-through
+
+           // These traits are modeled on type predicates in C++0x [meta.unary.prop]
+           // which requires some of its traits to have the complete type. However,
+           // the completeness of the type cannot impact these traits' semantics, and
+           // so they don't require it. This matches the comments on these traits in
+           // Table 49.
+  case UTT_IsConst:
+  case UTT_IsVolatile:
+  case UTT_IsSigned:
+  case UTT_IsUnboundedArray:
+  case UTT_IsUnsigned:
+
+           // This type trait always returns false, checking the type is moot.
+  case UTT_IsInterfaceClass:
+    return true;
+
+           // We diagnose incomplete class types later.
+  case UTT_StructuredBindingSize:
+    return true;
+
+           // C++14 [meta.unary.prop]:
+           //   If T is a non-union class type, T shall be a complete type.
+  case UTT_IsEmpty:
+  case UTT_IsPolymorphic:
+  case UTT_IsAbstract:
+    if (const auto *RD = ArgTy->getAsCXXRecordDecl())
+      if (!RD->isUnion())
+        return !S.RequireCompleteType(
+            Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
+    return true;
+
+           // C++14 [meta.unary.prop]:
+           //   If T is a class type, T shall be a complete type.
+  case UTT_IsFinal:
+  case UTT_IsSealed:
+    if (ArgTy->getAsCXXRecordDecl())
+      return !S.RequireCompleteType(
+          Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
+    return true;
+
+           // LWG3823: T shall be an array type, a complete type, or cv void.
+  case UTT_IsAggregate:
+  case UTT_IsImplicitLifetime:
+    if (ArgTy->isArrayType() || ArgTy->isVoidType())
+      return true;
+
+    return !S.RequireCompleteType(
+        Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
+
+           // has_unique_object_representations<T>
+           // remove_all_extents_t<T> shall be a complete type or cv void (LWG4113).
+  case UTT_HasUniqueObjectRepresentations:
+    ArgTy = QualType(ArgTy->getBaseElementTypeUnsafe(), 0);
+    if (ArgTy->isVoidType())
+      return true;
+    return !S.RequireCompleteType(
+        Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
+
+           // C++1z [meta.unary.prop]:
+           //   remove_all_extents_t<T> shall be a complete type or cv void.
+  case UTT_IsTrivial:
+  case UTT_IsTriviallyCopyable:
+  case UTT_IsStandardLayout:
+  case UTT_IsPOD:
+  case UTT_IsLiteral:
+  case UTT_IsBitwiseCloneable:
+  // By analogy, is_trivially_relocatable and is_trivially_equality_comparable
+  // impose the same constraints.
+  case UTT_IsTriviallyRelocatable:
+  case UTT_IsTriviallyEqualityComparable:
+  case UTT_IsCppTriviallyRelocatable:
+  case UTT_IsReplaceable:
+  case UTT_CanPassInRegs:
+  // Per the GCC type traits documentation, T shall be a complete type, cv void,
+  // or an array of unknown bound. But GCC actually imposes the same constraints
+  // as above.
+  case UTT_HasNothrowAssign:
+  case UTT_HasNothrowMoveAssign:
+  case UTT_HasNothrowConstructor:
+  case UTT_HasNothrowCopy:
+  case UTT_HasTrivialAssign:
+  case UTT_HasTrivialMoveAssign:
+  case UTT_HasTrivialDefaultConstructor:
+  case UTT_HasTrivialMoveConstructor:
+  case UTT_HasTrivialCopy:
+  case UTT_HasTrivialDestructor:
+  case UTT_HasVirtualDestructor:
+    ArgTy = QualType(ArgTy->getBaseElementTypeUnsafe(), 0);
+    [[fallthrough]];
+  // C++1z [meta.unary.prop]:
+  //   T shall be a complete type, cv void, or an array of unknown bound.
+  case UTT_IsDestructible:
+  case UTT_IsNothrowDestructible:
+  case UTT_IsTriviallyDestructible:
+  case UTT_IsIntangibleType:
+    if (ArgTy->isIncompleteArrayType() || ArgTy->isVoidType())
+      return true;
+
+    return !S.RequireCompleteType(
+        Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
+  }
+}
+
+static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op,
+                               Sema &Self, SourceLocation KeyLoc, ASTContext &C,
+                               bool (CXXRecordDecl::*HasTrivial)() const,
+                               bool (CXXRecordDecl::*HasNonTrivial)() const,
+                               bool (CXXMethodDecl::*IsDesiredOp)() const)
+{
+  CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+  if ((RD->*HasTrivial)() && !(RD->*HasNonTrivial)())
+    return true;
+
+  DeclarationName Name = C.DeclarationNames.getCXXOperatorName(Op);
+  DeclarationNameInfo NameInfo(Name, KeyLoc);
+  LookupResult Res(Self, NameInfo, Sema::LookupOrdinaryName);
+  if (Self.LookupQualifiedName(Res, RD)) {
+    bool FoundOperator = false;
+    Res.suppressDiagnostics();
+    for (LookupResult::iterator Op = Res.begin(), OpEnd = Res.end();
+         Op != OpEnd; ++Op) {
+      if (isa<FunctionTemplateDecl>(*Op))
+        continue;
+
+      CXXMethodDecl *Operator = cast<CXXMethodDecl>(*Op);
+      if((Operator->*IsDesiredOp)()) {
+        FoundOperator = true;
+        auto *CPT = Operator->getType()->castAs<FunctionProtoType>();
+        CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
+        if (!CPT || !CPT->isNothrow())
+          return false;
+      }
+    }
+    return FoundOperator;
+  }
+  return false;
+}
+
+static bool HasNonDeletedDefaultedEqualityComparison(Sema &S,
+                                                     const CXXRecordDecl *Decl,
+                                                     SourceLocation KeyLoc) {
+  if (Decl->isUnion())
+    return false;
+  if (Decl->isLambda())
+    return Decl->isCapturelessLambda();
+
+  {
+    EnterExpressionEvaluationContext UnevaluatedContext(
+        S, Sema::ExpressionEvaluationContext::Unevaluated);
+    Sema::SFINAETrap SFINAE(S, /*ForValidityCheck=*/true);
+    Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
+
+           // const ClassT& obj;
+    OpaqueValueExpr Operand(
+        KeyLoc,
+        Decl->getTypeForDecl()->getCanonicalTypeUnqualified().withConst(),
+        ExprValueKind::VK_LValue);
+    UnresolvedSet<16> Functions;
+    // obj == obj;
+    S.LookupBinOp(S.TUScope, {}, BinaryOperatorKind::BO_EQ, Functions);
+
+    auto Result = S.CreateOverloadedBinOp(KeyLoc, BinaryOperatorKind::BO_EQ,
+                                          Functions, &Operand, &Operand);
+    if (Result.isInvalid() || SFINAE.hasErrorOccurred())
+      return false;
+
+    const auto *CallExpr = dyn_cast<CXXOperatorCallExpr>(Result.get());
+    if (!CallExpr)
+      return false;
+    const auto *Callee = CallExpr->getDirectCallee();
+    auto ParamT = Callee->getParamDecl(0)->getType();
+    if (!Callee->isDefaulted())
+      return false;
+    if (!ParamT->isReferenceType() && !Decl->isTriviallyCopyable())
+      return false;
+    if (ParamT.getNonReferenceType()->getUnqualifiedDesugaredType() !=
+        Decl->getTypeForDecl())
+      return false;
+  }
+
+  return llvm::all_of(Decl->bases(),
+                      [&](const CXXBaseSpecifier &BS) {
+                        if (const auto *RD = BS.getType()->getAsCXXRecordDecl())
+                          return HasNonDeletedDefaultedEqualityComparison(
+                              S, RD, KeyLoc);
+                        return true;
+                      }) &&
+         llvm::all_of(Decl->fields(), [&](const FieldDecl *FD) {
+           auto Type = FD->getType();
+           if (Type->isArrayType())
+             Type = Type->getBaseElementTypeUnsafe()
+                        ->getCanonicalTypeUnqualified();
+
+           if (Type->isReferenceType() || Type->isEnumeralType())
+             return false;
+           if (const auto *RD = Type->getAsCXXRecordDecl())
+             return HasNonDeletedDefaultedEqualityComparison(S, RD, KeyLoc);
+           return true;
+         });
+}
+
+static bool isTriviallyEqualityComparableType(Sema &S, QualType Type, SourceLocation KeyLoc) {
+  QualType CanonicalType = Type.getCanonicalType();
+  if (CanonicalType->isIncompleteType() || CanonicalType->isDependentType() ||
+      CanonicalType->isEnumeralType() || CanonicalType->isArrayType())
+    return false;
+
+  if (const auto *RD = CanonicalType->getAsCXXRecordDecl()) {
+    if (!HasNonDeletedDefaultedEqualityComparison(S, RD, KeyLoc))
+      return false;
+  }
+
+  return S.getASTContext().hasUniqueObjectRepresentations(
+      CanonicalType, /*CheckIfTriviallyCopyable=*/false);
+}
+
+static bool IsTriviallyRelocatableType(Sema &SemaRef, QualType T) {
+  QualType BaseElementType = SemaRef.getASTContext().getBaseElementType(T);
+
+  if (BaseElementType->isIncompleteType())
+    return false;
+  if (!BaseElementType->isObjectType())
+    return false;
+
+  if (T.hasAddressDiscriminatedPointerAuth())
+    return false;
+
+  if (const auto *RD = BaseElementType->getAsCXXRecordDecl();
+      RD && !RD->isPolymorphic() && IsCXXTriviallyRelocatableType(SemaRef, RD))
+    return true;
+
+  if (const auto *RD = BaseElementType->getAsRecordDecl())
+    return RD->canPassInRegisters();
+
+  if (BaseElementType.isTriviallyCopyableType(SemaRef.getASTContext()))
+    return true;
+
+  switch (T.isNonTrivialToPrimitiveDestructiveMove()) {
+  case QualType::PCK_Trivial:
+    return !T.isDestructedType();
+  case QualType::PCK_ARCStrong:
+    return true;
+  default:
+    return false;
+  }
+}
+
+static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
+                                   SourceLocation KeyLoc,
+                                   TypeSourceInfo *TInfo) {
+  QualType T = TInfo->getType();
+  assert(!T->isDependentType() && "Cannot evaluate traits of dependent type");
+
+  ASTContext &C = Self.Context;
+  switch(UTT) {
+  default: llvm_unreachable("not a UTT");
+    // Type trait expressions corresponding to the primary type category
+    // predicates in C++0x [meta.unary.cat].
+  case UTT_IsVoid:
+    return T->isVoidType();
+  case UTT_IsIntegral:
+    return T->isIntegralType(C);
+  case UTT_IsFloatingPoint:
+    return T->isFloatingType();
+  case UTT_IsArray:
+    // Zero-sized arrays aren't considered arrays in partial specializations,
+    // so __is_array shouldn't consider them arrays either.
+    if (const auto *CAT = C.getAsConstantArrayType(T))
+      return CAT->getSize() != 0;
+    return T->isArrayType();
+  case UTT_IsBoundedArray:
+    if (DiagnoseVLAInCXXTypeTrait(Self, TInfo, tok::kw___is_bounded_array))
+      return false;
+    // Zero-sized arrays aren't considered arrays in partial specializations,
+    // so __is_bounded_array shouldn't consider them arrays either.
+    if (const auto *CAT = C.getAsConstantArrayType(T))
+      return CAT->getSize() != 0;
+    return T->isArrayType() && !T->isIncompleteArrayType();
+  case UTT_IsUnboundedArray:
+    if (DiagnoseVLAInCXXTypeTrait(Self, TInfo, tok::kw___is_unbounded_array))
+      return false;
+    return T->isIncompleteArrayType();
+  case UTT_IsPointer:
+    return T->isAnyPointerType();
+  case UTT_IsLvalueReference:
+    return T->isLValueReferenceType();
+  case UTT_IsRvalueReference:
+    return T->isRValueReferenceType();
+  case UTT_IsMemberFunctionPointer:
+    return T->isMemberFunctionPointerType();
+  case UTT_IsMemberObjectPointer:
+    return T->isMemberDataPointerType();
+  case UTT_IsEnum:
+    return T->isEnumeralType();
+  case UTT_IsScopedEnum:
+    return T->isScopedEnumeralType();
+  case UTT_IsUnion:
+    return T->isUnionType();
+  case UTT_IsClass:
+    return T->isClassType() || T->isStructureType() || T->isInterfaceType();
+  case UTT_IsFunction:
+    return T->isFunctionType();
+
+           // Type trait expressions which correspond to the convenient composition
+           // predicates in C++0x [meta.unary.comp].
+  case UTT_IsReference:
+    return T->isReferenceType();
+  case UTT_IsArithmetic:
+    return T->isArithmeticType() && !T->isEnumeralType();
+  case UTT_IsFundamental:
+    return T->isFundamentalType();
+  case UTT_IsObject:
+    return T->isObjectType();
+  case UTT_IsScalar:
+    // Note: semantic analysis depends on Objective-C lifetime types to be
+    // considered scalar types. However, such types do not actually behave
+    // like scalar types at run time (since they may require retain/release
+    // operations), so we report them as non-scalar.
+    if (T->isObjCLifetimeType()) {
+      switch (T.getObjCLifetime()) {
+      case Qualifiers::OCL_None:
+      case Qualifiers::OCL_ExplicitNone:
+        return true;
+
+      case Qualifiers::OCL_Strong:
+      case Qualifiers::OCL_Weak:
+      case Qualifiers::OCL_Autoreleasing:
+        return false;
+      }
+    }
+
+    return T->isScalarType();
+  case UTT_IsCompound:
+    return T->isCompoundType();
+  case UTT_IsMemberPointer:
+    return T->isMemberPointerType();
+
+           // Type trait expressions which correspond to the type property predicates
+           // in C++0x [meta.unary.prop].
+  case UTT_IsConst:
+    return T.isConstQualified();
+  case UTT_IsVolatile:
+    return T.isVolatileQualified();
+  case UTT_IsTrivial:
+    return T.isTrivialType(C);
+  case UTT_IsTriviallyCopyable:
+    return T.isTriviallyCopyableType(C);
+  case UTT_IsStandardLayout:
+    return T->isStandardLayoutType();
+  case UTT_IsPOD:
+    return T.isPODType(C);
+  case UTT_IsLiteral:
+    return T->isLiteralType(C);
+  case UTT_IsEmpty:
+    if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+      return !RD->isUnion() && RD->isEmpty();
+    return false;
+  case UTT_IsPolymorphic:
+    if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+      return !RD->isUnion() && RD->isPolymorphic();
+    return false;
+  case UTT_IsAbstract:
+    if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+      return !RD->isUnion() && RD->isAbstract();
+    return false;
+  case UTT_IsAggregate:
+    // Report vector extensions and complex types as aggregates because they
+    // support aggregate initialization. GCC mirrors this behavior for vectors
+    // but not _Complex.
+    return T->isAggregateType() || T->isVectorType() || T->isExtVectorType() ||
+           T->isAnyComplexType();
+  // __is_interface_class only returns true when CL is invoked in /CLR mode and
+  // even then only when it is used with the 'interface struct ...' syntax
+  // Clang doesn't support /CLR which makes this type trait moot.
+  case UTT_IsInterfaceClass:
+    return false;
+  case UTT_IsFinal:
+  case UTT_IsSealed:
+    if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+      return RD->hasAttr<FinalAttr>();
+    return false;
+  case UTT_IsSigned:
+    // Enum types should always return false.
+    // Floating points should always return true.
+    return T->isFloatingType() ||
+           (T->isSignedIntegerType() && !T->isEnumeralType());
+  case UTT_IsUnsigned:
+    // Enum types should always return false.
+    return T->isUnsignedIntegerType() && !T->isEnumeralType();
+
+           // Type trait expressions which query classes regarding their construction,
+           // destruction, and copying. Rather than being based directly on the
+           // related type predicates in the standard, they are specified by both
+           // GCC[1] and the Embarcadero C++ compiler[2], and Clang implements those
+           // specifications.
+           //
+           //   1: http://gcc.gnu/.org/onlinedocs/gcc/Type-Traits.html
+           //   2: http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index
+           //
+           // Note that these builtins do not behave as documented in g++: if a class
+           // has both a trivial and a non-trivial special member of a particular kind,
+           // they return false! For now, we emulate this behavior.
+           // FIXME: This appears to be a g++ bug: more complex cases reveal that it
+           // does not correctly compute triviality in the presence of multiple special
+           // members of the same kind. Revisit this once the g++ bug is fixed.
+  case UTT_HasTrivialDefaultConstructor:
+    // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
+    //   If __is_pod (type) is true then the trait is true, else if type is
+    //   a cv class or union type (or array thereof) with a trivial default
+    //   constructor ([class.ctor]) then the trait is true, else it is false.
+    if (T.isPODType(C))
+      return true;
+    if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
+      return RD->hasTrivialDefaultConstructor() &&
+             !RD->hasNonTrivialDefaultConstructor();
+    return false;
+  case UTT_HasTrivialMoveConstructor:
+    //  This trait is implemented by MSVC 2012 and needed to parse the
+    //  standard library headers. Specifically this is used as the logic
+    //  behind std::is_trivially_move_constructible (20.9.4.3).
+    if (T.isPODType(C))
+      return true;
+    if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
+      return RD->hasTrivialMoveConstructor() && !RD->hasNonTrivialMoveConstructor();
+    return false;
+  case UTT_HasTrivialCopy:
+    // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
+    //   If __is_pod (type) is true or type is a reference type then
+    //   the trait is true, else if type is a cv class or union type
+    //   with a trivial copy constructor ([class.copy]) then the trait
+    //   is true, else it is false.
+    if (T.isPODType(C) || T->isReferenceType())
+      return true;
+    if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+      return RD->hasTrivialCopyConstructor() &&
+             !RD->hasNonTrivialCopyConstructor();
+    return false;
+  case UTT_HasTrivialMoveAssign:
+    //  This trait is implemented by MSVC 2012 and needed to parse the
+    //  standard library headers. Specifically it is used as the logic
+    //  behind std::is_trivially_move_assignable (20.9.4.3)
+    if (T.isPODType(C))
+      return true;
+    if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
+      return RD->hasTrivialMoveAssignment() && !RD->hasNonTrivialMoveAssignment();
+    return false;
+  case UTT_HasTrivialAssign:
+    // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
+    //   If type is const qualified or is a reference type then the
+    //   trait is false. Otherwise if __is_pod (type) is true then the
+    //   trait is true, else if type is a cv class or union type with
+    //   a trivial copy assignment ([class.copy]) then the trait is
+    //   true, else it is false.
+    // Note: the const and reference restrictions are interesting,
+    // given that const and reference members don't prevent a class
+    // from having a trivial copy assignment operator (but do cause
+    // errors if the copy assignment operator is actually used, q.v.
+    // [class.copy]p12).
+
+    if (T.isConstQualified())
+      return false;
+    if (T.isPODType(C))
+      return true;
+    if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+      return RD->hasTrivialCopyAssignment() &&
+             !RD->hasNonTrivialCopyAssignment();
+    return false;
+  case UTT_IsDestructible:
+  case UTT_IsTriviallyDestructible:
+  case UTT_IsNothrowDestructible:
+    // C++14 [meta.unary.prop]:
+    //   For reference types, is_destructible<T>::value is true.
+    if (T->isReferenceType())
+      return true;
+
+           // Objective-C++ ARC: autorelease types don't require destruction.
+    if (T->isObjCLifetimeType() &&
+        T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing)
+      return true;
+
+           // C++14 [meta.unary.prop]:
+           //   For incomplete types and function types, is_destructible<T>::value is
+           //   false.
+    if (T->isIncompleteType() || T->isFunctionType())
+      return false;
+
+           // A type that requires destruction (via a non-trivial destructor or ARC
+           // lifetime semantics) is not trivially-destructible.
+    if (UTT == UTT_IsTriviallyDestructible && T.isDestructedType())
+      return false;
+
+           // C++14 [meta.unary.prop]:
+           //   For object types and given U equal to remove_all_extents_t<T>, if the
+           //   expression std::declval<U&>().~U() is well-formed when treated as an
+           //   unevaluated operand (Clause 5), then is_destructible<T>::value is true
+    if (auto *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) {
+      CXXDestructorDecl *Destructor = Self.LookupDestructor(RD);
+      if (!Destructor)
+        return false;
+      //  C++14 [dcl.fct.def.delete]p2:
+      //    A program that refers to a deleted function implicitly or
+      //    explicitly, other than to declare it, is ill-formed.
+      if (Destructor->isDeleted())
+        return false;
+      if (C.getLangOpts().AccessControl && Destructor->getAccess() != AS_public)
+        return false;
+      if (UTT == UTT_IsNothrowDestructible) {
+        auto *CPT = Destructor->getType()->castAs<FunctionProtoType>();
+        CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
+        if (!CPT || !CPT->isNothrow())
+          return false;
+      }
+    }
+    return true;
+
+  case UTT_HasTrivialDestructor:
+    // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html
+    //   If __is_pod (type) is true or type is a reference type
+    //   then the trait is true, else if type is a cv class or union
+    //   type (or array thereof) with a trivial destructor
+    //   ([class.dtor]) then the trait is true, else it is
+    //   false.
+    if (T.isPODType(C) || T->isReferenceType())
+      return true;
+
+           // Objective-C++ ARC: autorelease types don't require destruction.
+    if (T->isObjCLifetimeType() &&
+        T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing)
+      return true;
+
+    if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
+      return RD->hasTrivialDestructor();
+    return false;
+  // TODO: Propagate nothrowness for implicitly declared special members.
+  case UTT_HasNothrowAssign:
+    // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
+    //   If type is const qualified or is a reference type then the
+    //   trait is false. Otherwise if __has_trivial_assign (type)
+    //   is true then the trait is true, else if type is a cv class
+    //   or union type with copy assignment operators that are known
+    //   not to throw an exception then the trait is true, else it is
+    //   false.
+    if (C.getBaseElementType(T).isConstQualified())
+      return false;
+    if (T->isReferenceType())
+      return false;
+    if (T.isPODType(C) || T->isObjCLifetimeType())
+      return true;
+
+    if (const RecordType *RT = T->getAs<RecordType>())
+      return HasNoThrowOperator(RT, OO_Equal, Self, KeyLoc, C,
+                                &CXXRecordDecl::hasTrivialCopyAssignment,
+                                &CXXRecordDecl::hasNonTrivialCopyAssignment,
+                                &CXXMethodDecl::isCopyAssignmentOperator);
+    return false;
+  case UTT_HasNothrowMoveAssign:
+    //  This trait is implemented by MSVC 2012 and needed to parse the
+    //  standard library headers. Specifically this is used as the logic
+    //  behind std::is_nothrow_move_assignable (20.9.4.3).
+    if (T.isPODType(C))
+      return true;
+
+    if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>())
+      return HasNoThrowOperator(RT, OO_Equal, Self, KeyLoc, C,
+                                &CXXRecordDecl::hasTrivialMoveAssignment,
+                                &CXXRecordDecl::hasNonTrivialMoveAssignment,
+                                &CXXMethodDecl::isMoveAssignmentOperator);
+    return false;
+  case UTT_HasNothrowCopy:
+    // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
+    //   If __has_trivial_copy (type) is true then the trait is true, else
+    //   if type is a cv class or union type with copy constructors that are
+    //   known not to throw an exception then the trait is true, else it is
+    //   false.
+    if (T.isPODType(C) || T->isReferenceType() || T->isObjCLifetimeType())
+      return true;
+    if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) {
+      if (RD->hasTrivialCopyConstructor() &&
+          !RD->hasNonTrivialCopyConstructor())
+        return true;
+
+      bool FoundConstructor = false;
+      unsigned FoundTQs;
+      for (const auto *ND : Self.LookupConstructors(RD)) {
+        // A template constructor is never a copy constructor.
+        // FIXME: However, it may actually be selected at the actual overload
+        // resolution point.
+        if (isa<FunctionTemplateDecl>(ND->getUnderlyingDecl()))
+          continue;
+        // UsingDecl itself is not a constructor
+        if (isa<UsingDecl>(ND))
+          continue;
+        auto *Constructor = cast<CXXConstructorDecl>(ND->getUnderlyingDecl());
+        if (Constructor->isCopyConstructor(FoundTQs)) {
+          FoundConstructor = true;
+          auto *CPT = Constructor->getType()->castAs<FunctionProtoType>();
+          CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
+          if (!CPT)
+            return false;
+          // TODO: check whether evaluating default arguments can throw.
+          // For now, we'll be conservative and assume that they can throw.
+          if (!CPT->isNothrow() || CPT->getNumParams() > 1)
+            return false;
+        }
+      }
+
+      return FoundConstructor;
+    }
+    return false;
+  case UTT_HasNothrowConstructor:
+    // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html
+    //   If __has_trivial_constructor (type) is true then the trait is
+    //   true, else if type is a cv class or union type (or array
+    //   thereof) with a default constructor that is known not to
+    //   throw an exception then the trait is true, else it is false.
+    if (T.isPODType(C) || T->isObjCLifetimeType())
+      return true;
+    if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) {
+      if (RD->hasTrivialDefaultConstructor() &&
+          !RD->hasNonTrivialDefaultConstructor())
+        return true;
+
+      bool FoundConstructor = false;
+      for (const auto *ND : Self.LookupConstructors(RD)) {
+        // FIXME: In C++0x, a constructor template can be a default constructor.
+        if (isa<FunctionTemplateDecl>(ND->getUnderlyingDecl()))
+          continue;
+        // UsingDecl itself is not a constructor
+        if (isa<UsingDecl>(ND))
+          continue;
+        auto *Constructor = cast<CXXConstructorDecl>(ND->getUnderlyingDecl());
+        if (Constructor->isDefaultConstructor()) {
+          FoundConstructor = true;
+          auto *CPT = Constructor->getType()->castAs<FunctionProtoType>();
+          CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
+          if (!CPT)
+            return false;
+          // FIXME: check whether evaluating default arguments can throw.
+          // For now, we'll be conservative and assume that they can throw.
+          if (!CPT->isNothrow() || CPT->getNumParams() > 0)
+            return false;
+        }
+      }
+      return FoundConstructor;
+    }
+    return false;
+  case UTT_HasVirtualDestructor:
+    // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
+    //   If type is a class type with a virtual destructor ([class.dtor])
+    //   then the trait is true, else it is false.
+    if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+      if (CXXDestructorDecl *Destructor = Self.LookupDestructor(RD))
+        return Destructor->isVirtual();
+    return false;
+
+           // These type trait expressions are modeled on the specifications for the
+           // Embarcadero C++0x type trait functions:
+           //   http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index
+  case UTT_IsCompleteType:
+    // http://docwiki.embarcadero.com/RADStudio/XE/en/Is_complete_type_(typename_T_):
+    //   Returns True if and only if T is a complete type at the point of the
+    //   function call.
+    return !T->isIncompleteType();
+  case UTT_HasUniqueObjectRepresentations:
+    return C.hasUniqueObjectRepresentations(T);
+  case UTT_IsTriviallyRelocatable:
+    return IsTriviallyRelocatableType(Self, T);
+  case UTT_IsBitwiseCloneable:
+    return T.isBitwiseCloneableType(C);
+  case UTT_IsCppTriviallyRelocatable:
+    return Self.IsCXXTriviallyRelocatableType(T);
+  case UTT_IsReplaceable:
+    return Self.IsCXXReplaceableType(T);
+  case UTT_CanPassInRegs:
+    if (CXXRecordDecl *RD = T->getAsCXXRecordDecl(); RD && !T.hasQualifiers())
+      return RD->canPassInRegisters();
+    Self.Diag(KeyLoc, diag::err_builtin_pass_in_regs_non_class) << T;
+    return false;
+  case UTT_IsTriviallyEqualityComparable:
+    return isTriviallyEqualityComparableType(Self, T, KeyLoc);
+  case UTT_IsImplicitLifetime: {
+    DiagnoseVLAInCXXTypeTrait(Self, TInfo,
+                              tok::kw___builtin_is_implicit_lifetime);
+    DiagnoseAtomicInCXXTypeTrait(Self, TInfo,
+                                 tok::kw___builtin_is_implicit_lifetime);
+
+           // [basic.types.general] p9
+           // Scalar types, implicit-lifetime class types ([class.prop]),
+           // array types, and cv-qualified versions of these types
+           // are collectively called implicit-lifetime types.
+    QualType UnqualT = T->getCanonicalTypeUnqualified();
+    if (UnqualT->isScalarType())
+      return true;
+    if (UnqualT->isArrayType() || UnqualT->isVectorType())
+      return true;
+    const CXXRecordDecl *RD = UnqualT->getAsCXXRecordDecl();
+    if (!RD)
+      return false;
+
+           // [class.prop] p9
+           // A class S is an implicit-lifetime class if
+           //   - it is an aggregate whose destructor is not user-provided or
+           //   - it has at least one trivial eligible constructor and a trivial,
+           //     non-deleted destructor.
+    const CXXDestructorDecl *Dtor = RD->getDestructor();
+    if (UnqualT->isAggregateType())
+      if (Dtor && !Dtor->isUserProvided())
+        return true;
+    if (RD->hasTrivialDestructor() && (!Dtor || !Dtor->isDeleted()))
+      if (RD->hasTrivialDefaultConstructor() ||
+          RD->hasTrivialCopyConstructor() || RD->hasTrivialMoveConstructor())
+        return true;
+    return false;
+  }
+  case UTT_IsIntangibleType:
+    assert(Self.getLangOpts().HLSL && "intangible types are HLSL-only feature");
+    if (!T->isVoidType() && !T->isIncompleteArrayType())
+      if (Self.RequireCompleteType(TInfo->getTypeLoc().getBeginLoc(), T,
+                                   diag::err_incomplete_type))
+        return false;
+    if (DiagnoseVLAInCXXTypeTrait(Self, TInfo,
+                                  tok::kw___builtin_hlsl_is_intangible))
+      return false;
+    return T->isHLSLIntangibleType();
+
+  case UTT_IsTypedResourceElementCompatible:
+    assert(Self.getLangOpts().HLSL &&
+           "typed resource element compatible types are an HLSL-only feature");
+    if (T->isIncompleteType())
+      return false;
+
+    return Self.HLSL().IsTypedResourceElementCompatible(T);
+  }
+}
+
+
+
+static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceInfo *Lhs,
+                                    const TypeSourceInfo *Rhs, SourceLocation KeyLoc);
+
+static ExprResult CheckConvertibilityForTypeTraits(
+    Sema &Self, const TypeSourceInfo *Lhs, const TypeSourceInfo *Rhs,
+    SourceLocation KeyLoc, llvm::BumpPtrAllocator &OpaqueExprAllocator) {
+
+  QualType LhsT = Lhs->getType();
+  QualType RhsT = Rhs->getType();
+
+         // C++0x [meta.rel]p4:
+         //   Given the following function prototype:
+         //
+         //     template <class T>
+         //       typename add_rvalue_reference<T>::type create();
+         //
+         //   the predicate condition for a template specialization
+         //   is_convertible<From, To> shall be satisfied if and only if
+         //   the return expression in the following code would be
+         //   well-formed, including any implicit conversions to the return
+         //   type of the function:
+         //
+         //     To test() {
+         //       return create<From>();
+         //     }
+         //
+         //   Access checking is performed as if in a context unrelated to To and
+         //   From. Only the validity of the immediate context of the expression
+         //   of the return-statement (including conversions to the return type)
+         //   is considered.
+         //
+         // We model the initialization as a copy-initialization of a temporary
+         // of the appropriate type, which for this expression is identical to the
+         // return statement (since NRVO doesn't apply).
+
+         // Functions aren't allowed to return function or array types.
+  if (RhsT->isFunctionType() || RhsT->isArrayType())
+    return ExprError();
+
+         // A function definition requires a complete, non-abstract return type.
+  if (!Self.isCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT) ||
+      Self.isAbstractType(Rhs->getTypeLoc().getBeginLoc(), RhsT))
+    return ExprError();
+
+         // Compute the result of add_rvalue_reference.
+  if (LhsT->isObjectType() || LhsT->isFunctionType())
+    LhsT = Self.Context.getRValueReferenceType(LhsT);
+
+         // Build a fake source and destination for initialization.
+  InitializedEntity To(InitializedEntity::InitializeTemporary(RhsT));
+  Expr *From = new (OpaqueExprAllocator.Allocate<OpaqueValueExpr>())
+      OpaqueValueExpr(KeyLoc, LhsT.getNonLValueExprType(Self.Context),
+                      Expr::getValueKindForType(LhsT));
+  InitializationKind Kind =
+      InitializationKind::CreateCopy(KeyLoc, SourceLocation());
+
+         // Perform the initialization in an unevaluated context within a SFINAE
+         // trap at translation unit scope.
+  EnterExpressionEvaluationContext Unevaluated(
+      Self, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::SFINAETrap SFINAE(Self, /*ForValidityCheck=*/true);
+  Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl());
+  InitializationSequence Init(Self, To, Kind, From);
+  if (Init.Failed())
+    return ExprError();
+
+  ExprResult Result = Init.Perform(Self, To, Kind, From);
+  if (Result.isInvalid() || SFINAE.hasErrorOccurred())
+    return ExprError();
+
+  return Result;
+}
+
+static APValue EvaluateSizeTTypeTrait(Sema &S, TypeTrait Kind,
+                                      SourceLocation KWLoc,
+                                      ArrayRef<TypeSourceInfo *> Args,
+                                      SourceLocation RParenLoc,
+                                      bool IsDependent) {
+  if (IsDependent)
+    return APValue();
+
+  switch (Kind) {
+  case TypeTrait::UTT_StructuredBindingSize: {
+    QualType T = Args[0]->getType();
+    SourceRange ArgRange = Args[0]->getTypeLoc().getSourceRange();
+    UnsignedOrNone Size =
+        S.GetDecompositionElementCount(T, ArgRange.getBegin());
+    if (!Size) {
+      S.Diag(KWLoc, diag::err_arg_is_not_destructurable) << T << ArgRange;
+      return APValue();
+    }
+    return APValue(
+        S.getASTContext().MakeIntValue(*Size, S.getASTContext().getSizeType()));
+    break;
+  }
+  default:
+    llvm_unreachable("Not a SizeT type trait");
+  }
+}
+
+static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind,
+                                     SourceLocation KWLoc,
+                                     ArrayRef<TypeSourceInfo *> Args,
+                                     SourceLocation RParenLoc,
+                                     bool IsDependent) {
+  if (IsDependent)
+    return false;
+
+  if (Kind <= UTT_Last)
+    return EvaluateUnaryTypeTrait(S, Kind, KWLoc, Args[0]);
+
+         // Evaluate ReferenceBindsToTemporary and ReferenceConstructsFromTemporary
+         // alongside the IsConstructible traits to avoid duplication.
+  if (Kind <= BTT_Last && Kind != BTT_ReferenceBindsToTemporary &&
+      Kind != BTT_ReferenceConstructsFromTemporary &&
+      Kind != BTT_ReferenceConvertsFromTemporary)
+    return EvaluateBinaryTypeTrait(S, Kind, Args[0],
+                                   Args[1], RParenLoc);
+
+  switch (Kind) {
+  case clang::BTT_ReferenceBindsToTemporary:
+  case clang::BTT_ReferenceConstructsFromTemporary:
+  case clang::BTT_ReferenceConvertsFromTemporary:
+  case clang::TT_IsConstructible:
+  case clang::TT_IsNothrowConstructible:
+  case clang::TT_IsTriviallyConstructible: {
+    // C++11 [meta.unary.prop]:
+    //   is_trivially_constructible is defined as:
+    //
+    //     is_constructible<T, Args...>::value is true and the variable
+    //     definition for is_constructible, as defined below, is known to call
+    //     no operation that is not trivial.
+    //
+    //   The predicate condition for a template specialization
+    //   is_constructible<T, Args...> shall be satisfied if and only if the
+    //   following variable definition would be well-formed for some invented
+    //   variable t:
+    //
+    //     T t(create<Args>()...);
+    assert(!Args.empty());
+
+           // Precondition: T and all types in the parameter pack Args shall be
+           // complete types, (possibly cv-qualified) void, or arrays of
+           // unknown bound.
+    for (const auto *TSI : Args) {
+      QualType ArgTy = TSI->getType();
+      if (ArgTy->isVoidType() || ArgTy->isIncompleteArrayType())
+        continue;
+
+      if (S.RequireCompleteType(KWLoc, ArgTy,
+                                diag::err_incomplete_type_used_in_type_trait_expr))
+        return false;
+    }
+
+           // Make sure the first argument is not incomplete nor a function type.
+    QualType T = Args[0]->getType();
+    if (T->isIncompleteType() || T->isFunctionType())
+      return false;
+
+           // Make sure the first argument is not an abstract type.
+    CXXRecordDecl *RD = T->getAsCXXRecordDecl();
+    if (RD && RD->isAbstract())
+      return false;
+
+    llvm::BumpPtrAllocator OpaqueExprAllocator;
+    SmallVector<Expr *, 2> ArgExprs;
+    ArgExprs.reserve(Args.size() - 1);
+    for (unsigned I = 1, N = Args.size(); I != N; ++I) {
+      QualType ArgTy = Args[I]->getType();
+      if (ArgTy->isObjectType() || ArgTy->isFunctionType())
+        ArgTy = S.Context.getRValueReferenceType(ArgTy);
+      ArgExprs.push_back(
+          new (OpaqueExprAllocator.Allocate<OpaqueValueExpr>())
+          OpaqueValueExpr(Args[I]->getTypeLoc().getBeginLoc(),
+                          ArgTy.getNonLValueExprType(S.Context),
+                          Expr::getValueKindForType(ArgTy)));
+    }
+
+           // Perform the initialization in an unevaluated context within a SFINAE
+           // trap at translation unit scope.
+    EnterExpressionEvaluationContext Unevaluated(
+        S, Sema::ExpressionEvaluationContext::Unevaluated);
+    Sema::SFINAETrap SFINAE(S, /*ForValidityCheck=*/true);
+    Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
+    InitializedEntity To(
+        InitializedEntity::InitializeTemporary(S.Context, Args[0]));
+    InitializationKind InitKind(
+        Kind == clang::BTT_ReferenceConvertsFromTemporary
+            ? InitializationKind::CreateCopy(KWLoc, KWLoc)
+            : InitializationKind::CreateDirect(KWLoc, KWLoc, RParenLoc));
+    InitializationSequence Init(S, To, InitKind, ArgExprs);
+    if (Init.Failed())
+      return false;
+
+    ExprResult Result = Init.Perform(S, To, InitKind, ArgExprs);
+    if (Result.isInvalid() || SFINAE.hasErrorOccurred())
+      return false;
+
+    if (Kind == clang::TT_IsConstructible)
+      return true;
+
+    if (Kind == clang::BTT_ReferenceBindsToTemporary ||
+        Kind == clang::BTT_ReferenceConstructsFromTemporary ||
+        Kind == clang::BTT_ReferenceConvertsFromTemporary) {
+      if (!T->isReferenceType())
+        return false;
+
+      if (!Init.isDirectReferenceBinding())
+        return true;
+
+      if (Kind == clang::BTT_ReferenceBindsToTemporary)
+        return false;
+
+      QualType U = Args[1]->getType();
+      if (U->isReferenceType())
+        return false;
+
+      TypeSourceInfo *TPtr = S.Context.CreateTypeSourceInfo(
+          S.Context.getPointerType(T.getNonReferenceType()));
+      TypeSourceInfo *UPtr = S.Context.CreateTypeSourceInfo(
+          S.Context.getPointerType(U.getNonReferenceType()));
+      return !CheckConvertibilityForTypeTraits(S, UPtr, TPtr, RParenLoc,
+                                               OpaqueExprAllocator)
+                  .isInvalid();
+    }
+
+    if (Kind == clang::TT_IsNothrowConstructible)
+      return S.canThrow(Result.get()) == CT_Cannot;
+
+    if (Kind == clang::TT_IsTriviallyConstructible) {
+      // Under Objective-C ARC and Weak, if the destination has non-trivial
+      // Objective-C lifetime, this is a non-trivial construction.
+      if (T.getNonReferenceType().hasNonTrivialObjCLifetime())
+        return false;
+
+             // The initialization succeeded; now make sure there are no non-trivial
+             // calls.
+      return !Result.get()->hasNonTrivialCall(S.Context);
+    }
+
+    llvm_unreachable("unhandled type trait");
+    return false;
+  }
+  default: llvm_unreachable("not a TT");
+  }
+
+  return false;
+}
+
+namespace {
+void DiagnoseBuiltinDeprecation(Sema& S, TypeTrait Kind,
+                                SourceLocation KWLoc) {
+  TypeTrait Replacement;
+  switch (Kind) {
+  case UTT_HasNothrowAssign:
+  case UTT_HasNothrowMoveAssign:
+    Replacement = BTT_IsNothrowAssignable;
+    break;
+  case UTT_HasNothrowCopy:
+  case UTT_HasNothrowConstructor:
+    Replacement = TT_IsNothrowConstructible;
+    break;
+  case UTT_HasTrivialAssign:
+  case UTT_HasTrivialMoveAssign:
+    Replacement = BTT_IsTriviallyAssignable;
+    break;
+  case UTT_HasTrivialCopy:
+    Replacement = UTT_IsTriviallyCopyable;
+    break;
+  case UTT_HasTrivialDefaultConstructor:
+  case UTT_HasTrivialMoveConstructor:
+    Replacement = TT_IsTriviallyConstructible;
+    break;
+  case UTT_HasTrivialDestructor:
+    Replacement = UTT_IsTriviallyDestructible;
+    break;
+  case UTT_IsTriviallyRelocatable:
+    Replacement = clang::UTT_IsCppTriviallyRelocatable;
+    break;
+  default:
+    return;
+  }
+  S.Diag(KWLoc, diag::warn_deprecated_builtin)
+      << getTraitSpelling(Kind) << getTraitSpelling(Replacement);
+}
+} // namespace
+
+bool Sema::CheckTypeTraitArity(unsigned Arity, SourceLocation Loc, size_t N) {
+  if (Arity && N != Arity) {
+    Diag(Loc, diag::err_type_trait_arity)
+    << Arity << 0 << (Arity > 1) << (int)N << SourceRange(Loc);
+    return false;
+  }
+
+  if (!Arity && N == 0) {
+    Diag(Loc, diag::err_type_trait_arity)
+    << 1 << 1 << 1 << (int)N << SourceRange(Loc);
+    return false;
+  }
+  return true;
+}
+
+enum class TypeTraitReturnType {
+  Bool,
+  SizeT,
+};
+
+static TypeTraitReturnType GetReturnType(TypeTrait Kind) {
+  if (Kind == TypeTrait::UTT_StructuredBindingSize)
+    return TypeTraitReturnType::SizeT;
+  return TypeTraitReturnType::Bool;
+}
+
+ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
+                                ArrayRef<TypeSourceInfo *> Args,
+                                SourceLocation RParenLoc) {
+  if (!CheckTypeTraitArity(getTypeTraitArity(Kind), KWLoc, Args.size()))
+    return ExprError();
+
+  if (Kind <= UTT_Last && !CheckUnaryTypeTraitTypeCompleteness(
+                              *this, Kind, KWLoc, Args[0]->getType()))
+    return ExprError();
+
+  DiagnoseBuiltinDeprecation(*this, Kind, KWLoc);
+
+  bool Dependent = false;
+  for (unsigned I = 0, N = Args.size(); I != N; ++I) {
+    if (Args[I]->getType()->isDependentType()) {
+      Dependent = true;
+      break;
+    }
+  }
+
+  switch (GetReturnType(Kind)) {
+  case TypeTraitReturnType::Bool: {
+    bool Result = EvaluateBooleanTypeTrait(*this, Kind, KWLoc, Args, RParenLoc,
+                                           Dependent);
+    return TypeTraitExpr::Create(Context, Context.getLogicalOperationType(),
+                                 KWLoc, Kind, Args, RParenLoc, Result);
+  }
+  case TypeTraitReturnType::SizeT: {
+    APValue Result =
+        EvaluateSizeTTypeTrait(*this, Kind, KWLoc, Args, RParenLoc, Dependent);
+    return TypeTraitExpr::Create(Context, Context.getSizeType(), KWLoc, Kind,
+                                 Args, RParenLoc, Result);
+  }
+  }
+  llvm_unreachable("unhandled type trait return type");
+}
+
+ExprResult Sema::ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
+                                ArrayRef<ParsedType> Args,
+                                SourceLocation RParenLoc) {
+  SmallVector<TypeSourceInfo *, 4> ConvertedArgs;
+  ConvertedArgs.reserve(Args.size());
+
+  for (unsigned I = 0, N = Args.size(); I != N; ++I) {
+    TypeSourceInfo *TInfo;
+    QualType T = GetTypeFromParser(Args[I], &TInfo);
+    if (!TInfo)
+      TInfo = Context.getTrivialTypeSourceInfo(T, KWLoc);
+
+    ConvertedArgs.push_back(TInfo);
+  }
+
+  return BuildTypeTrait(Kind, KWLoc, ConvertedArgs, RParenLoc);
+}
+
+static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceInfo *Lhs,
+                                    const TypeSourceInfo *Rhs, SourceLocation KeyLoc) {
+  QualType LhsT = Lhs->getType();
+  QualType RhsT = Rhs->getType();
+
+  assert(!LhsT->isDependentType() && !RhsT->isDependentType() &&
+         "Cannot evaluate traits of dependent types");
+
+  switch(BTT) {
+  case BTT_IsBaseOf: {
+    // C++0x [meta.rel]p2
+    // Base is a base class of Derived without regard to cv-qualifiers or
+    // Base and Derived are not unions and name the same class type without
+    // regard to cv-qualifiers.
+
+    const RecordType *lhsRecord = LhsT->getAs<RecordType>();
+    const RecordType *rhsRecord = RhsT->getAs<RecordType>();
+    if (!rhsRecord || !lhsRecord) {
+      const ObjCObjectType *LHSObjTy = LhsT->getAs<ObjCObjectType>();
+      const ObjCObjectType *RHSObjTy = RhsT->getAs<ObjCObjectType>();
+      if (!LHSObjTy || !RHSObjTy)
+        return false;
+
+      ObjCInterfaceDecl *BaseInterface = LHSObjTy->getInterface();
+      ObjCInterfaceDecl *DerivedInterface = RHSObjTy->getInterface();
+      if (!BaseInterface || !DerivedInterface)
+        return false;
+
+      if (Self.RequireCompleteType(
+              Rhs->getTypeLoc().getBeginLoc(), RhsT,
+              diag::err_incomplete_type_used_in_type_trait_expr))
+        return false;
+
+      return BaseInterface->isSuperClassOf(DerivedInterface);
+    }
+
+    assert(Self.Context.hasSameUnqualifiedType(LhsT, RhsT)
+           == (lhsRecord == rhsRecord));
+
+           // Unions are never base classes, and never have base classes.
+           // It doesn't matter if they are complete or not. See PR#41843
+    if (lhsRecord && lhsRecord->getDecl()->isUnion())
+      return false;
+    if (rhsRecord && rhsRecord->getDecl()->isUnion())
+      return false;
+
+    if (lhsRecord == rhsRecord)
+      return true;
+
+           // C++0x [meta.rel]p2:
+           //   If Base and Derived are class types and are different types
+           //   (ignoring possible cv-qualifiers) then Derived shall be a
+           //   complete type.
+    if (Self.RequireCompleteType(
+            Rhs->getTypeLoc().getBeginLoc(), RhsT,
+            diag::err_incomplete_type_used_in_type_trait_expr))
+      return false;
+
+    return cast<CXXRecordDecl>(rhsRecord->getDecl())
+        ->isDerivedFrom(cast<CXXRecordDecl>(lhsRecord->getDecl()));
+  }
+  case BTT_IsVirtualBaseOf: {
+    const RecordType *BaseRecord = LhsT->getAs<RecordType>();
+    const RecordType *DerivedRecord = RhsT->getAs<RecordType>();
+
+    if (!BaseRecord || !DerivedRecord) {
+      DiagnoseVLAInCXXTypeTrait(Self, Lhs,
+                                tok::kw___builtin_is_virtual_base_of);
+      DiagnoseVLAInCXXTypeTrait(Self, Rhs,
+                                tok::kw___builtin_is_virtual_base_of);
+      return false;
+    }
+
+    if (BaseRecord->isUnionType() || DerivedRecord->isUnionType())
+      return false;
+
+    if (!BaseRecord->isStructureOrClassType() ||
+        !DerivedRecord->isStructureOrClassType())
+      return false;
+
+    if (Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT,
+                                 diag::err_incomplete_type))
+      return false;
+
+    return cast<CXXRecordDecl>(DerivedRecord->getDecl())
+        ->isVirtuallyDerivedFrom(cast<CXXRecordDecl>(BaseRecord->getDecl()));
+  }
+  case BTT_IsSame:
+    return Self.Context.hasSameType(LhsT, RhsT);
+  case BTT_TypeCompatible: {
+    // GCC ignores cv-qualifiers on arrays for this builtin.
+    Qualifiers LhsQuals, RhsQuals;
+    QualType Lhs = Self.getASTContext().getUnqualifiedArrayType(LhsT, LhsQuals);
+    QualType Rhs = Self.getASTContext().getUnqualifiedArrayType(RhsT, RhsQuals);
+    return Self.Context.typesAreCompatible(Lhs, Rhs);
+  }
+  case BTT_IsConvertible:
+  case BTT_IsConvertibleTo:
+  case BTT_IsNothrowConvertible: {
+    if (RhsT->isVoidType())
+      return LhsT->isVoidType();
+    llvm::BumpPtrAllocator OpaqueExprAllocator;
+    ExprResult Result = CheckConvertibilityForTypeTraits(Self, Lhs, Rhs, KeyLoc,
+                                                         OpaqueExprAllocator);
+    if (Result.isInvalid())
+      return false;
+
+    if (BTT != BTT_IsNothrowConvertible)
+      return true;
+
+    return Self.canThrow(Result.get()) == CT_Cannot;
+  }
+
+  case BTT_IsAssignable:
+  case BTT_IsNothrowAssignable:
+  case BTT_IsTriviallyAssignable: {
+    // C++11 [meta.unary.prop]p3:
+    //   is_trivially_assignable is defined as:
+    //     is_assignable<T, U>::value is true and the assignment, as defined by
+    //     is_assignable, is known to call no operation that is not trivial
+    //
+    //   is_assignable is defined as:
+    //     The expression declval<T>() = declval<U>() is well-formed when
+    //     treated as an unevaluated operand (Clause 5).
+    //
+    //   For both, T and U shall be complete types, (possibly cv-qualified)
+    //   void, or arrays of unknown bound.
+    if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType() &&
+        Self.RequireCompleteType(
+            Lhs->getTypeLoc().getBeginLoc(), LhsT,
+            diag::err_incomplete_type_used_in_type_trait_expr))
+      return false;
+    if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType() &&
+        Self.RequireCompleteType(
+            Rhs->getTypeLoc().getBeginLoc(), RhsT,
+            diag::err_incomplete_type_used_in_type_trait_expr))
+      return false;
+
+           // cv void is never assignable.
+    if (LhsT->isVoidType() || RhsT->isVoidType())
+      return false;
+
+           // Build expressions that emulate the effect of declval<T>() and
+           // declval<U>().
+    if (LhsT->isObjectType() || LhsT->isFunctionType())
+      LhsT = Self.Context.getRValueReferenceType(LhsT);
+    if (RhsT->isObjectType() || RhsT->isFunctionType())
+      RhsT = Self.Context.getRValueReferenceType(RhsT);
+    OpaqueValueExpr Lhs(KeyLoc, LhsT.getNonLValueExprType(Self.Context),
+                        Expr::getValueKindForType(LhsT));
+    OpaqueValueExpr Rhs(KeyLoc, RhsT.getNonLValueExprType(Self.Context),
+                        Expr::getValueKindForType(RhsT));
+
+           // Attempt the assignment in an unevaluated context within a SFINAE
+           // trap at translation unit scope.
+    EnterExpressionEvaluationContext Unevaluated(
+        Self, Sema::ExpressionEvaluationContext::Unevaluated);
+    Sema::SFINAETrap SFINAE(Self, /*ForValidityCheck=*/true);
+    Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl());
+    ExprResult Result = Self.BuildBinOp(/*S=*/nullptr, KeyLoc, BO_Assign, &Lhs,
+                                        &Rhs);
+    if (Result.isInvalid())
+      return false;
+
+           // Treat the assignment as unused for the purpose of -Wdeprecated-volatile.
+    Self.CheckUnusedVolatileAssignment(Result.get());
+
+    if (SFINAE.hasErrorOccurred())
+      return false;
+
+    if (BTT == BTT_IsAssignable)
+      return true;
+
+    if (BTT == BTT_IsNothrowAssignable)
+      return Self.canThrow(Result.get()) == CT_Cannot;
+
+    if (BTT == BTT_IsTriviallyAssignable) {
+      // Under Objective-C ARC and Weak, if the destination has non-trivial
+      // Objective-C lifetime, this is a non-trivial assignment.
+      if (LhsT.getNonReferenceType().hasNonTrivialObjCLifetime())
+        return false;
+
+      return !Result.get()->hasNonTrivialCall(Self.Context);
+    }
+
+    llvm_unreachable("unhandled type trait");
+    return false;
+  }
+  case BTT_IsLayoutCompatible: {
+    if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType())
+      Self.RequireCompleteType(Lhs->getTypeLoc().getBeginLoc(), LhsT,
+                               diag::err_incomplete_type);
+    if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType())
+      Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT,
+                               diag::err_incomplete_type);
+
+    DiagnoseVLAInCXXTypeTrait(Self, Lhs, tok::kw___is_layout_compatible);
+    DiagnoseVLAInCXXTypeTrait(Self, Rhs, tok::kw___is_layout_compatible);
+
+    return Self.IsLayoutCompatible(LhsT, RhsT);
+  }
+  case BTT_IsPointerInterconvertibleBaseOf: {
+    if (LhsT->isStructureOrClassType() && RhsT->isStructureOrClassType() &&
+        !Self.getASTContext().hasSameUnqualifiedType(LhsT, RhsT)) {
+      Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT,
+                               diag::err_incomplete_type);
+    }
+
+    DiagnoseVLAInCXXTypeTrait(Self, Lhs,
+                              tok::kw___is_pointer_interconvertible_base_of);
+    DiagnoseVLAInCXXTypeTrait(Self, Rhs,
+                              tok::kw___is_pointer_interconvertible_base_of);
+
+    return Self.IsPointerInterconvertibleBaseOf(Lhs, Rhs);
+  }
+  case BTT_IsDeducible: {
+    const auto *TSTToBeDeduced = cast<DeducedTemplateSpecializationType>(LhsT);
+    sema::TemplateDeductionInfo Info(KeyLoc);
+    return Self.DeduceTemplateArgumentsFromType(
+               TSTToBeDeduced->getTemplateName().getAsTemplateDecl(), RhsT,
+               Info) == TemplateDeductionResult::Success;
+  }
+  case BTT_IsScalarizedLayoutCompatible: {
+    if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType() &&
+        Self.RequireCompleteType(Lhs->getTypeLoc().getBeginLoc(), LhsT,
+                                 diag::err_incomplete_type))
+      return true;
+    if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType() &&
+        Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT,
+                                 diag::err_incomplete_type))
+      return true;
+
+    DiagnoseVLAInCXXTypeTrait(
+        Self, Lhs, tok::kw___builtin_hlsl_is_scalarized_layout_compatible);
+    DiagnoseVLAInCXXTypeTrait(
+        Self, Rhs, tok::kw___builtin_hlsl_is_scalarized_layout_compatible);
+
+    return Self.HLSL().IsScalarizedLayoutCompatible(LhsT, RhsT);
+  }
+  default:
+    llvm_unreachable("not a BTT");
+  }
+  llvm_unreachable("Unknown type trait or not implemented");
+}
+
+ExprResult Sema::ActOnArrayTypeTrait(ArrayTypeTrait ATT,
+                                     SourceLocation KWLoc,
+                                     ParsedType Ty,
+                                     Expr* DimExpr,
+                                     SourceLocation RParen) {
+  TypeSourceInfo *TSInfo;
+  QualType T = GetTypeFromParser(Ty, &TSInfo);
+  if (!TSInfo)
+    TSInfo = Context.getTrivialTypeSourceInfo(T);
+
+  return BuildArrayTypeTrait(ATT, KWLoc, TSInfo, DimExpr, RParen);
+}
+
+static uint64_t EvaluateArrayTypeTrait(Sema &Self, ArrayTypeTrait ATT,
+                                       QualType T, Expr *DimExpr,
+                                       SourceLocation KeyLoc) {
+  assert(!T->isDependentType() && "Cannot evaluate traits of dependent type");
+
+  switch(ATT) {
+  case ATT_ArrayRank:
+    if (T->isArrayType()) {
+      unsigned Dim = 0;
+      while (const ArrayType *AT = Self.Context.getAsArrayType(T)) {
+        ++Dim;
+        T = AT->getElementType();
+      }
+      return Dim;
+    }
+    return 0;
+
+  case ATT_ArrayExtent: {
+    llvm::APSInt Value;
+    uint64_t Dim;
+    if (Self.VerifyIntegerConstantExpression(
+                DimExpr, &Value, diag::err_dimension_expr_not_constant_integer)
+            .isInvalid())
+      return 0;
+    if (Value.isSigned() && Value.isNegative()) {
+      Self.Diag(KeyLoc, diag::err_dimension_expr_not_constant_integer)
+      << DimExpr->getSourceRange();
+      return 0;
+    }
+    Dim = Value.getLimitedValue();
+
+    if (T->isArrayType()) {
+      unsigned D = 0;
+      bool Matched = false;
+      while (const ArrayType *AT = Self.Context.getAsArrayType(T)) {
+        if (Dim == D) {
+          Matched = true;
+          break;
+        }
+        ++D;
+        T = AT->getElementType();
+      }
+
+      if (Matched && T->isArrayType()) {
+        if (const ConstantArrayType *CAT = Self.Context.getAsConstantArrayType(T))
+          return CAT->getLimitedSize();
+      }
+    }
+    return 0;
+  }
+  }
+  llvm_unreachable("Unknown type trait or not implemented");
+}
+
+ExprResult Sema::BuildArrayTypeTrait(ArrayTypeTrait ATT,
+                                     SourceLocation KWLoc,
+                                     TypeSourceInfo *TSInfo,
+                                     Expr* DimExpr,
+                                     SourceLocation RParen) {
+  QualType T = TSInfo->getType();
+
+         // FIXME: This should likely be tracked as an APInt to remove any host
+         // assumptions about the width of size_t on the target.
+  uint64_t Value = 0;
+  if (!T->isDependentType())
+    Value = EvaluateArrayTypeTrait(*this, ATT, T, DimExpr, KWLoc);
+
+         // While the specification for these traits from the Embarcadero C++
+         // compiler's documentation says the return type is 'unsigned int', Clang
+         // returns 'size_t'. On Windows, the primary platform for the Embarcadero
+         // compiler, there is no difference. On several other platforms this is an
+         // important distinction.
+  return new (Context) ArrayTypeTraitExpr(KWLoc, ATT, TSInfo, Value, DimExpr,
+                                          RParen, Context.getSizeType());
+}
+
+ExprResult Sema::ActOnExpressionTrait(ExpressionTrait ET,
+                                      SourceLocation KWLoc,
+                                      Expr *Queried,
+                                      SourceLocation RParen) {
+  // If error parsing the expression, ignore.
+  if (!Queried)
+    return ExprError();
+
+  ExprResult Result = BuildExpressionTrait(ET, KWLoc, Queried, RParen);
+
+  return Result;
+}
+
+static bool EvaluateExpressionTrait(ExpressionTrait ET, Expr *E) {
+  switch (ET) {
+  case ET_IsLValueExpr: return E->isLValue();
+  case ET_IsRValueExpr:
+    return E->isPRValue();
+  }
+  llvm_unreachable("Expression trait not covered by switch");
+}
+
+ExprResult Sema::BuildExpressionTrait(ExpressionTrait ET,
+                                      SourceLocation KWLoc,
+                                      Expr *Queried,
+                                      SourceLocation RParen) {
+  if (Queried->isTypeDependent()) {
+    // Delay type-checking for type-dependent expressions.
+  } else if (Queried->hasPlaceholderType()) {
+    ExprResult PE = CheckPlaceholderExpr(Queried);
+    if (PE.isInvalid()) return ExprError();
+    return BuildExpressionTrait(ET, KWLoc, PE.get(), RParen);
+  }
+
+  bool Value = EvaluateExpressionTrait(ET, Queried);
+
+  return new (Context)
+      ExpressionTraitExpr(KWLoc, ET, Queried, Value, RParen, Context.BoolTy);
+}

>From 64a90d29451d172d1e70481fef839800238af757 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Fri, 23 May 2025 17:53:02 +0200
Subject: [PATCH 2/2] Run clang-format to fix miss-aligned comments

---
 clang/lib/Sema/SemaExprCXX.cpp    |   1 -
 clang/lib/Sema/SemaTypeTraits.cpp | 360 +++++++++++++++---------------
 2 files changed, 180 insertions(+), 181 deletions(-)

diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 63cf324ddb1f9..d8338e08dd0f7 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -5292,7 +5292,6 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
   return From;
 }
 
-
 QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS,
                                             ExprValueKind &VK,
                                             SourceLocation Loc,
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp
index 763d37071b134..bac71c07d9907 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -358,7 +358,6 @@ bool Sema::IsCXXReplaceableType(QualType Type) {
   return false;
 }
 
-
 /// Checks that type T is not a VLA.
 ///
 /// @returns @c true if @p T is VLA and a diagnostic was emitted,
@@ -406,15 +405,16 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
   // these class templates. We also try to follow any GCC documented behavior
   // in these expressions to ensure portability of standard libraries.
   switch (UTT) {
-  default: llvm_unreachable("not a UTT");
+  default:
+    llvm_unreachable("not a UTT");
     // is_complete_type somewhat obviously cannot require a complete type.
   case UTT_IsCompleteType:
-                           // Fall-through
+    // Fall-through
 
-           // These traits are modeled on the type predicates in C++0x
-           // [meta.unary.cat] and [meta.unary.comp]. They are not specified as
-           // requiring a complete type, as whether or not they return true cannot be
-           // impacted by the completeness of the type.
+    // These traits are modeled on the type predicates in C++0x
+    // [meta.unary.cat] and [meta.unary.comp]. They are not specified as
+    // requiring a complete type, as whether or not they return true cannot be
+    // impacted by the completeness of the type.
   case UTT_IsVoid:
   case UTT_IsIntegral:
   case UTT_IsFloatingPoint:
@@ -438,29 +438,29 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
   case UTT_IsCompound:
   case UTT_IsMemberPointer:
   case UTT_IsTypedResourceElementCompatible:
-                                             // Fall-through
+    // Fall-through
 
-           // These traits are modeled on type predicates in C++0x [meta.unary.prop]
-           // which requires some of its traits to have the complete type. However,
-           // the completeness of the type cannot impact these traits' semantics, and
-           // so they don't require it. This matches the comments on these traits in
-           // Table 49.
+    // These traits are modeled on type predicates in C++0x [meta.unary.prop]
+    // which requires some of its traits to have the complete type. However,
+    // the completeness of the type cannot impact these traits' semantics, and
+    // so they don't require it. This matches the comments on these traits in
+    // Table 49.
   case UTT_IsConst:
   case UTT_IsVolatile:
   case UTT_IsSigned:
   case UTT_IsUnboundedArray:
   case UTT_IsUnsigned:
 
-           // This type trait always returns false, checking the type is moot.
+    // This type trait always returns false, checking the type is moot.
   case UTT_IsInterfaceClass:
     return true;
 
-           // We diagnose incomplete class types later.
+    // We diagnose incomplete class types later.
   case UTT_StructuredBindingSize:
     return true;
 
-           // C++14 [meta.unary.prop]:
-           //   If T is a non-union class type, T shall be a complete type.
+    // C++14 [meta.unary.prop]:
+    //   If T is a non-union class type, T shall be a complete type.
   case UTT_IsEmpty:
   case UTT_IsPolymorphic:
   case UTT_IsAbstract:
@@ -470,8 +470,8 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
             Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
     return true;
 
-           // C++14 [meta.unary.prop]:
-           //   If T is a class type, T shall be a complete type.
+    // C++14 [meta.unary.prop]:
+    //   If T is a class type, T shall be a complete type.
   case UTT_IsFinal:
   case UTT_IsSealed:
     if (ArgTy->getAsCXXRecordDecl())
@@ -479,7 +479,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
           Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
     return true;
 
-           // LWG3823: T shall be an array type, a complete type, or cv void.
+    // LWG3823: T shall be an array type, a complete type, or cv void.
   case UTT_IsAggregate:
   case UTT_IsImplicitLifetime:
     if (ArgTy->isArrayType() || ArgTy->isVoidType())
@@ -488,8 +488,8 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
     return !S.RequireCompleteType(
         Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
 
-           // has_unique_object_representations<T>
-           // remove_all_extents_t<T> shall be a complete type or cv void (LWG4113).
+    // has_unique_object_representations<T>
+    // remove_all_extents_t<T> shall be a complete type or cv void (LWG4113).
   case UTT_HasUniqueObjectRepresentations:
     ArgTy = QualType(ArgTy->getBaseElementTypeUnsafe(), 0);
     if (ArgTy->isVoidType())
@@ -497,8 +497,8 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
     return !S.RequireCompleteType(
         Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
 
-           // C++1z [meta.unary.prop]:
-           //   remove_all_extents_t<T> shall be a complete type or cv void.
+    // C++1z [meta.unary.prop]:
+    //   remove_all_extents_t<T> shall be a complete type or cv void.
   case UTT_IsTrivial:
   case UTT_IsTriviallyCopyable:
   case UTT_IsStandardLayout:
@@ -546,8 +546,7 @@ static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op,
                                Sema &Self, SourceLocation KeyLoc, ASTContext &C,
                                bool (CXXRecordDecl::*HasTrivial)() const,
                                bool (CXXRecordDecl::*HasNonTrivial)() const,
-                               bool (CXXMethodDecl::*IsDesiredOp)() const)
-{
+                               bool (CXXMethodDecl::*IsDesiredOp)() const) {
   CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
   if ((RD->*HasTrivial)() && !(RD->*HasNonTrivial)())
     return true;
@@ -564,7 +563,7 @@ static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op,
         continue;
 
       CXXMethodDecl *Operator = cast<CXXMethodDecl>(*Op);
-      if((Operator->*IsDesiredOp)()) {
+      if ((Operator->*IsDesiredOp)()) {
         FoundOperator = true;
         auto *CPT = Operator->getType()->castAs<FunctionProtoType>();
         CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
@@ -591,7 +590,7 @@ static bool HasNonDeletedDefaultedEqualityComparison(Sema &S,
     Sema::SFINAETrap SFINAE(S, /*ForValidityCheck=*/true);
     Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
 
-           // const ClassT& obj;
+    // const ClassT& obj;
     OpaqueValueExpr Operand(
         KeyLoc,
         Decl->getTypeForDecl()->getCanonicalTypeUnqualified().withConst(),
@@ -640,7 +639,8 @@ static bool HasNonDeletedDefaultedEqualityComparison(Sema &S,
          });
 }
 
-static bool isTriviallyEqualityComparableType(Sema &S, QualType Type, SourceLocation KeyLoc) {
+static bool isTriviallyEqualityComparableType(Sema &S, QualType Type,
+                                              SourceLocation KeyLoc) {
   QualType CanonicalType = Type.getCanonicalType();
   if (CanonicalType->isIncompleteType() || CanonicalType->isDependentType() ||
       CanonicalType->isEnumeralType() || CanonicalType->isArrayType())
@@ -693,8 +693,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
   assert(!T->isDependentType() && "Cannot evaluate traits of dependent type");
 
   ASTContext &C = Self.Context;
-  switch(UTT) {
-  default: llvm_unreachable("not a UTT");
+  switch (UTT) {
+  default:
+    llvm_unreachable("not a UTT");
     // Type trait expressions corresponding to the primary type category
     // predicates in C++0x [meta.unary.cat].
   case UTT_IsVoid:
@@ -742,8 +743,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
   case UTT_IsFunction:
     return T->isFunctionType();
 
-           // Type trait expressions which correspond to the convenient composition
-           // predicates in C++0x [meta.unary.comp].
+    // Type trait expressions which correspond to the convenient composition
+    // predicates in C++0x [meta.unary.comp].
   case UTT_IsReference:
     return T->isReferenceType();
   case UTT_IsArithmetic:
@@ -776,8 +777,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
   case UTT_IsMemberPointer:
     return T->isMemberPointerType();
 
-           // Type trait expressions which correspond to the type property predicates
-           // in C++0x [meta.unary.prop].
+    // Type trait expressions which correspond to the type property predicates
+    // in C++0x [meta.unary.prop].
   case UTT_IsConst:
     return T.isConstQualified();
   case UTT_IsVolatile:
@@ -829,21 +830,22 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
     // Enum types should always return false.
     return T->isUnsignedIntegerType() && !T->isEnumeralType();
 
-           // Type trait expressions which query classes regarding their construction,
-           // destruction, and copying. Rather than being based directly on the
-           // related type predicates in the standard, they are specified by both
-           // GCC[1] and the Embarcadero C++ compiler[2], and Clang implements those
-           // specifications.
-           //
-           //   1: http://gcc.gnu/.org/onlinedocs/gcc/Type-Traits.html
-           //   2: http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index
-           //
-           // Note that these builtins do not behave as documented in g++: if a class
-           // has both a trivial and a non-trivial special member of a particular kind,
-           // they return false! For now, we emulate this behavior.
-           // FIXME: This appears to be a g++ bug: more complex cases reveal that it
-           // does not correctly compute triviality in the presence of multiple special
-           // members of the same kind. Revisit this once the g++ bug is fixed.
+    // Type trait expressions which query classes regarding their construction,
+    // destruction, and copying. Rather than being based directly on the
+    // related type predicates in the standard, they are specified by both
+    // GCC[1] and the Embarcadero C++ compiler[2], and Clang implements those
+    // specifications.
+    //
+    //   1: http://gcc.gnu/.org/onlinedocs/gcc/Type-Traits.html
+    //   2:
+    //   http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index
+    //
+    // Note that these builtins do not behave as documented in g++: if a class
+    // has both a trivial and a non-trivial special member of a particular kind,
+    // they return false! For now, we emulate this behavior.
+    // FIXME: This appears to be a g++ bug: more complex cases reveal that it
+    // does not correctly compute triviality in the presence of multiple special
+    // members of the same kind. Revisit this once the g++ bug is fixed.
   case UTT_HasTrivialDefaultConstructor:
     // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
     //   If __is_pod (type) is true then the trait is true, else if type is
@@ -862,7 +864,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
     if (T.isPODType(C))
       return true;
     if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
-      return RD->hasTrivialMoveConstructor() && !RD->hasNonTrivialMoveConstructor();
+      return RD->hasTrivialMoveConstructor() &&
+             !RD->hasNonTrivialMoveConstructor();
     return false;
   case UTT_HasTrivialCopy:
     // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
@@ -883,7 +886,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
     if (T.isPODType(C))
       return true;
     if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
-      return RD->hasTrivialMoveAssignment() && !RD->hasNonTrivialMoveAssignment();
+      return RD->hasTrivialMoveAssignment() &&
+             !RD->hasNonTrivialMoveAssignment();
     return false;
   case UTT_HasTrivialAssign:
     // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
@@ -914,26 +918,26 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
     if (T->isReferenceType())
       return true;
 
-           // Objective-C++ ARC: autorelease types don't require destruction.
+    // Objective-C++ ARC: autorelease types don't require destruction.
     if (T->isObjCLifetimeType() &&
         T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing)
       return true;
 
-           // C++14 [meta.unary.prop]:
-           //   For incomplete types and function types, is_destructible<T>::value is
-           //   false.
+    // C++14 [meta.unary.prop]:
+    //   For incomplete types and function types, is_destructible<T>::value is
+    //   false.
     if (T->isIncompleteType() || T->isFunctionType())
       return false;
 
-           // A type that requires destruction (via a non-trivial destructor or ARC
-           // lifetime semantics) is not trivially-destructible.
+    // A type that requires destruction (via a non-trivial destructor or ARC
+    // lifetime semantics) is not trivially-destructible.
     if (UTT == UTT_IsTriviallyDestructible && T.isDestructedType())
       return false;
 
-           // C++14 [meta.unary.prop]:
-           //   For object types and given U equal to remove_all_extents_t<T>, if the
-           //   expression std::declval<U&>().~U() is well-formed when treated as an
-           //   unevaluated operand (Clause 5), then is_destructible<T>::value is true
+    // C++14 [meta.unary.prop]:
+    //   For object types and given U equal to remove_all_extents_t<T>, if the
+    //   expression std::declval<U&>().~U() is well-formed when treated as an
+    //   unevaluated operand (Clause 5), then is_destructible<T>::value is true
     if (auto *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) {
       CXXDestructorDecl *Destructor = Self.LookupDestructor(RD);
       if (!Destructor)
@@ -964,7 +968,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
     if (T.isPODType(C) || T->isReferenceType())
       return true;
 
-           // Objective-C++ ARC: autorelease types don't require destruction.
+    // Objective-C++ ARC: autorelease types don't require destruction.
     if (T->isObjCLifetimeType() &&
         T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing)
       return true;
@@ -1094,9 +1098,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
         return Destructor->isVirtual();
     return false;
 
-           // These type trait expressions are modeled on the specifications for the
-           // Embarcadero C++0x type trait functions:
-           //   http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index
+    // These type trait expressions are modeled on the specifications for the
+    // Embarcadero C++0x type trait functions:
+    //   http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index
   case UTT_IsCompleteType:
     // http://docwiki.embarcadero.com/RADStudio/XE/en/Is_complete_type_(typename_T_):
     //   Returns True if and only if T is a complete type at the point of the
@@ -1125,10 +1129,10 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
     DiagnoseAtomicInCXXTypeTrait(Self, TInfo,
                                  tok::kw___builtin_is_implicit_lifetime);
 
-           // [basic.types.general] p9
-           // Scalar types, implicit-lifetime class types ([class.prop]),
-           // array types, and cv-qualified versions of these types
-           // are collectively called implicit-lifetime types.
+    // [basic.types.general] p9
+    // Scalar types, implicit-lifetime class types ([class.prop]),
+    // array types, and cv-qualified versions of these types
+    // are collectively called implicit-lifetime types.
     QualType UnqualT = T->getCanonicalTypeUnqualified();
     if (UnqualT->isScalarType())
       return true;
@@ -1138,11 +1142,11 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
     if (!RD)
       return false;
 
-           // [class.prop] p9
-           // A class S is an implicit-lifetime class if
-           //   - it is an aggregate whose destructor is not user-provided or
-           //   - it has at least one trivial eligible constructor and a trivial,
-           //     non-deleted destructor.
+    // [class.prop] p9
+    // A class S is an implicit-lifetime class if
+    //   - it is an aggregate whose destructor is not user-provided or
+    //   - it has at least one trivial eligible constructor and a trivial,
+    //     non-deleted destructor.
     const CXXDestructorDecl *Dtor = RD->getDestructor();
     if (UnqualT->isAggregateType())
       if (Dtor && !Dtor->isUserProvided())
@@ -1174,10 +1178,10 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
   }
 }
 
-
-
-static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceInfo *Lhs,
-                                    const TypeSourceInfo *Rhs, SourceLocation KeyLoc);
+static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT,
+                                    const TypeSourceInfo *Lhs,
+                                    const TypeSourceInfo *Rhs,
+                                    SourceLocation KeyLoc);
 
 static ExprResult CheckConvertibilityForTypeTraits(
     Sema &Self, const TypeSourceInfo *Lhs, const TypeSourceInfo *Rhs,
@@ -1186,45 +1190,45 @@ static ExprResult CheckConvertibilityForTypeTraits(
   QualType LhsT = Lhs->getType();
   QualType RhsT = Rhs->getType();
 
-         // C++0x [meta.rel]p4:
-         //   Given the following function prototype:
-         //
-         //     template <class T>
-         //       typename add_rvalue_reference<T>::type create();
-         //
-         //   the predicate condition for a template specialization
-         //   is_convertible<From, To> shall be satisfied if and only if
-         //   the return expression in the following code would be
-         //   well-formed, including any implicit conversions to the return
-         //   type of the function:
-         //
-         //     To test() {
-         //       return create<From>();
-         //     }
-         //
-         //   Access checking is performed as if in a context unrelated to To and
-         //   From. Only the validity of the immediate context of the expression
-         //   of the return-statement (including conversions to the return type)
-         //   is considered.
-         //
-         // We model the initialization as a copy-initialization of a temporary
-         // of the appropriate type, which for this expression is identical to the
-         // return statement (since NRVO doesn't apply).
-
-         // Functions aren't allowed to return function or array types.
+  // C++0x [meta.rel]p4:
+  //   Given the following function prototype:
+  //
+  //     template <class T>
+  //       typename add_rvalue_reference<T>::type create();
+  //
+  //   the predicate condition for a template specialization
+  //   is_convertible<From, To> shall be satisfied if and only if
+  //   the return expression in the following code would be
+  //   well-formed, including any implicit conversions to the return
+  //   type of the function:
+  //
+  //     To test() {
+  //       return create<From>();
+  //     }
+  //
+  //   Access checking is performed as if in a context unrelated to To and
+  //   From. Only the validity of the immediate context of the expression
+  //   of the return-statement (including conversions to the return type)
+  //   is considered.
+  //
+  // We model the initialization as a copy-initialization of a temporary
+  // of the appropriate type, which for this expression is identical to the
+  // return statement (since NRVO doesn't apply).
+
+  // Functions aren't allowed to return function or array types.
   if (RhsT->isFunctionType() || RhsT->isArrayType())
     return ExprError();
 
-         // A function definition requires a complete, non-abstract return type.
+  // A function definition requires a complete, non-abstract return type.
   if (!Self.isCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT) ||
       Self.isAbstractType(Rhs->getTypeLoc().getBeginLoc(), RhsT))
     return ExprError();
 
-         // Compute the result of add_rvalue_reference.
+  // Compute the result of add_rvalue_reference.
   if (LhsT->isObjectType() || LhsT->isFunctionType())
     LhsT = Self.Context.getRValueReferenceType(LhsT);
 
-         // Build a fake source and destination for initialization.
+  // Build a fake source and destination for initialization.
   InitializedEntity To(InitializedEntity::InitializeTemporary(RhsT));
   Expr *From = new (OpaqueExprAllocator.Allocate<OpaqueValueExpr>())
       OpaqueValueExpr(KeyLoc, LhsT.getNonLValueExprType(Self.Context),
@@ -1232,8 +1236,8 @@ static ExprResult CheckConvertibilityForTypeTraits(
   InitializationKind Kind =
       InitializationKind::CreateCopy(KeyLoc, SourceLocation());
 
-         // Perform the initialization in an unevaluated context within a SFINAE
-         // trap at translation unit scope.
+  // Perform the initialization in an unevaluated context within a SFINAE
+  // trap at translation unit scope.
   EnterExpressionEvaluationContext Unevaluated(
       Self, Sema::ExpressionEvaluationContext::Unevaluated);
   Sema::SFINAETrap SFINAE(Self, /*ForValidityCheck=*/true);
@@ -1287,13 +1291,12 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind,
   if (Kind <= UTT_Last)
     return EvaluateUnaryTypeTrait(S, Kind, KWLoc, Args[0]);
 
-         // Evaluate ReferenceBindsToTemporary and ReferenceConstructsFromTemporary
-         // alongside the IsConstructible traits to avoid duplication.
+  // Evaluate ReferenceBindsToTemporary and ReferenceConstructsFromTemporary
+  // alongside the IsConstructible traits to avoid duplication.
   if (Kind <= BTT_Last && Kind != BTT_ReferenceBindsToTemporary &&
       Kind != BTT_ReferenceConstructsFromTemporary &&
       Kind != BTT_ReferenceConvertsFromTemporary)
-    return EvaluateBinaryTypeTrait(S, Kind, Args[0],
-                                   Args[1], RParenLoc);
+    return EvaluateBinaryTypeTrait(S, Kind, Args[0], Args[1], RParenLoc);
 
   switch (Kind) {
   case clang::BTT_ReferenceBindsToTemporary:
@@ -1317,25 +1320,25 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind,
     //     T t(create<Args>()...);
     assert(!Args.empty());
 
-           // Precondition: T and all types in the parameter pack Args shall be
-           // complete types, (possibly cv-qualified) void, or arrays of
-           // unknown bound.
+    // Precondition: T and all types in the parameter pack Args shall be
+    // complete types, (possibly cv-qualified) void, or arrays of
+    // unknown bound.
     for (const auto *TSI : Args) {
       QualType ArgTy = TSI->getType();
       if (ArgTy->isVoidType() || ArgTy->isIncompleteArrayType())
         continue;
 
-      if (S.RequireCompleteType(KWLoc, ArgTy,
-                                diag::err_incomplete_type_used_in_type_trait_expr))
+      if (S.RequireCompleteType(
+              KWLoc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr))
         return false;
     }
 
-           // Make sure the first argument is not incomplete nor a function type.
+    // Make sure the first argument is not incomplete nor a function type.
     QualType T = Args[0]->getType();
     if (T->isIncompleteType() || T->isFunctionType())
       return false;
 
-           // Make sure the first argument is not an abstract type.
+    // Make sure the first argument is not an abstract type.
     CXXRecordDecl *RD = T->getAsCXXRecordDecl();
     if (RD && RD->isAbstract())
       return false;
@@ -1349,13 +1352,13 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind,
         ArgTy = S.Context.getRValueReferenceType(ArgTy);
       ArgExprs.push_back(
           new (OpaqueExprAllocator.Allocate<OpaqueValueExpr>())
-          OpaqueValueExpr(Args[I]->getTypeLoc().getBeginLoc(),
-                          ArgTy.getNonLValueExprType(S.Context),
-                          Expr::getValueKindForType(ArgTy)));
+              OpaqueValueExpr(Args[I]->getTypeLoc().getBeginLoc(),
+                              ArgTy.getNonLValueExprType(S.Context),
+                              Expr::getValueKindForType(ArgTy)));
     }
 
-           // Perform the initialization in an unevaluated context within a SFINAE
-           // trap at translation unit scope.
+    // Perform the initialization in an unevaluated context within a SFINAE
+    // trap at translation unit scope.
     EnterExpressionEvaluationContext Unevaluated(
         S, Sema::ExpressionEvaluationContext::Unevaluated);
     Sema::SFINAETrap SFINAE(S, /*ForValidityCheck=*/true);
@@ -1411,23 +1414,23 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind,
       if (T.getNonReferenceType().hasNonTrivialObjCLifetime())
         return false;
 
-             // The initialization succeeded; now make sure there are no non-trivial
-             // calls.
+      // The initialization succeeded; now make sure there are no non-trivial
+      // calls.
       return !Result.get()->hasNonTrivialCall(S.Context);
     }
 
     llvm_unreachable("unhandled type trait");
     return false;
   }
-  default: llvm_unreachable("not a TT");
+  default:
+    llvm_unreachable("not a TT");
   }
 
   return false;
 }
 
 namespace {
-void DiagnoseBuiltinDeprecation(Sema& S, TypeTrait Kind,
-                                SourceLocation KWLoc) {
+void DiagnoseBuiltinDeprecation(Sema &S, TypeTrait Kind, SourceLocation KWLoc) {
   TypeTrait Replacement;
   switch (Kind) {
   case UTT_HasNothrowAssign:
@@ -1466,13 +1469,13 @@ void DiagnoseBuiltinDeprecation(Sema& S, TypeTrait Kind,
 bool Sema::CheckTypeTraitArity(unsigned Arity, SourceLocation Loc, size_t N) {
   if (Arity && N != Arity) {
     Diag(Loc, diag::err_type_trait_arity)
-    << Arity << 0 << (Arity > 1) << (int)N << SourceRange(Loc);
+        << Arity << 0 << (Arity > 1) << (int)N << SourceRange(Loc);
     return false;
   }
 
   if (!Arity && N == 0) {
     Diag(Loc, diag::err_type_trait_arity)
-    << 1 << 1 << 1 << (int)N << SourceRange(Loc);
+        << 1 << 1 << 1 << (int)N << SourceRange(Loc);
     return false;
   }
   return true;
@@ -1544,15 +1547,17 @@ ExprResult Sema::ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
   return BuildTypeTrait(Kind, KWLoc, ConvertedArgs, RParenLoc);
 }
 
-static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceInfo *Lhs,
-                                    const TypeSourceInfo *Rhs, SourceLocation KeyLoc) {
+static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT,
+                                    const TypeSourceInfo *Lhs,
+                                    const TypeSourceInfo *Rhs,
+                                    SourceLocation KeyLoc) {
   QualType LhsT = Lhs->getType();
   QualType RhsT = Rhs->getType();
 
   assert(!LhsT->isDependentType() && !RhsT->isDependentType() &&
          "Cannot evaluate traits of dependent types");
 
-  switch(BTT) {
+  switch (BTT) {
   case BTT_IsBaseOf: {
     // C++0x [meta.rel]p2
     // Base is a base class of Derived without regard to cv-qualifiers or
@@ -1580,11 +1585,11 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI
       return BaseInterface->isSuperClassOf(DerivedInterface);
     }
 
-    assert(Self.Context.hasSameUnqualifiedType(LhsT, RhsT)
-           == (lhsRecord == rhsRecord));
+    assert(Self.Context.hasSameUnqualifiedType(LhsT, RhsT) ==
+           (lhsRecord == rhsRecord));
 
-           // Unions are never base classes, and never have base classes.
-           // It doesn't matter if they are complete or not. See PR#41843
+    // Unions are never base classes, and never have base classes.
+    // It doesn't matter if they are complete or not. See PR#41843
     if (lhsRecord && lhsRecord->getDecl()->isUnion())
       return false;
     if (rhsRecord && rhsRecord->getDecl()->isUnion())
@@ -1593,10 +1598,10 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI
     if (lhsRecord == rhsRecord)
       return true;
 
-           // C++0x [meta.rel]p2:
-           //   If Base and Derived are class types and are different types
-           //   (ignoring possible cv-qualifiers) then Derived shall be a
-           //   complete type.
+    // C++0x [meta.rel]p2:
+    //   If Base and Derived are class types and are different types
+    //   (ignoring possible cv-qualifiers) then Derived shall be a
+    //   complete type.
     if (Self.RequireCompleteType(
             Rhs->getTypeLoc().getBeginLoc(), RhsT,
             diag::err_incomplete_type_used_in_type_trait_expr))
@@ -1682,12 +1687,12 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI
             diag::err_incomplete_type_used_in_type_trait_expr))
       return false;
 
-           // cv void is never assignable.
+    // cv void is never assignable.
     if (LhsT->isVoidType() || RhsT->isVoidType())
       return false;
 
-           // Build expressions that emulate the effect of declval<T>() and
-           // declval<U>().
+    // Build expressions that emulate the effect of declval<T>() and
+    // declval<U>().
     if (LhsT->isObjectType() || LhsT->isFunctionType())
       LhsT = Self.Context.getRValueReferenceType(LhsT);
     if (RhsT->isObjectType() || RhsT->isFunctionType())
@@ -1697,18 +1702,18 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI
     OpaqueValueExpr Rhs(KeyLoc, RhsT.getNonLValueExprType(Self.Context),
                         Expr::getValueKindForType(RhsT));
 
-           // Attempt the assignment in an unevaluated context within a SFINAE
-           // trap at translation unit scope.
+    // Attempt the assignment in an unevaluated context within a SFINAE
+    // trap at translation unit scope.
     EnterExpressionEvaluationContext Unevaluated(
         Self, Sema::ExpressionEvaluationContext::Unevaluated);
     Sema::SFINAETrap SFINAE(Self, /*ForValidityCheck=*/true);
     Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl());
-    ExprResult Result = Self.BuildBinOp(/*S=*/nullptr, KeyLoc, BO_Assign, &Lhs,
-                                        &Rhs);
+    ExprResult Result =
+        Self.BuildBinOp(/*S=*/nullptr, KeyLoc, BO_Assign, &Lhs, &Rhs);
     if (Result.isInvalid())
       return false;
 
-           // Treat the assignment as unused for the purpose of -Wdeprecated-volatile.
+    // Treat the assignment as unused for the purpose of -Wdeprecated-volatile.
     Self.CheckUnusedVolatileAssignment(Result.get());
 
     if (SFINAE.hasErrorOccurred())
@@ -1789,10 +1794,8 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI
   llvm_unreachable("Unknown type trait or not implemented");
 }
 
-ExprResult Sema::ActOnArrayTypeTrait(ArrayTypeTrait ATT,
-                                     SourceLocation KWLoc,
-                                     ParsedType Ty,
-                                     Expr* DimExpr,
+ExprResult Sema::ActOnArrayTypeTrait(ArrayTypeTrait ATT, SourceLocation KWLoc,
+                                     ParsedType Ty, Expr *DimExpr,
                                      SourceLocation RParen) {
   TypeSourceInfo *TSInfo;
   QualType T = GetTypeFromParser(Ty, &TSInfo);
@@ -1807,7 +1810,7 @@ static uint64_t EvaluateArrayTypeTrait(Sema &Self, ArrayTypeTrait ATT,
                                        SourceLocation KeyLoc) {
   assert(!T->isDependentType() && "Cannot evaluate traits of dependent type");
 
-  switch(ATT) {
+  switch (ATT) {
   case ATT_ArrayRank:
     if (T->isArrayType()) {
       unsigned Dim = 0;
@@ -1828,7 +1831,7 @@ static uint64_t EvaluateArrayTypeTrait(Sema &Self, ArrayTypeTrait ATT,
       return 0;
     if (Value.isSigned() && Value.isNegative()) {
       Self.Diag(KeyLoc, diag::err_dimension_expr_not_constant_integer)
-      << DimExpr->getSourceRange();
+          << DimExpr->getSourceRange();
       return 0;
     }
     Dim = Value.getLimitedValue();
@@ -1846,7 +1849,8 @@ static uint64_t EvaluateArrayTypeTrait(Sema &Self, ArrayTypeTrait ATT,
       }
 
       if (Matched && T->isArrayType()) {
-        if (const ConstantArrayType *CAT = Self.Context.getAsConstantArrayType(T))
+        if (const ConstantArrayType *CAT =
+                Self.Context.getAsConstantArrayType(T))
           return CAT->getLimitedSize();
       }
     }
@@ -1856,32 +1860,28 @@ static uint64_t EvaluateArrayTypeTrait(Sema &Self, ArrayTypeTrait ATT,
   llvm_unreachable("Unknown type trait or not implemented");
 }
 
-ExprResult Sema::BuildArrayTypeTrait(ArrayTypeTrait ATT,
-                                     SourceLocation KWLoc,
-                                     TypeSourceInfo *TSInfo,
-                                     Expr* DimExpr,
+ExprResult Sema::BuildArrayTypeTrait(ArrayTypeTrait ATT, SourceLocation KWLoc,
+                                     TypeSourceInfo *TSInfo, Expr *DimExpr,
                                      SourceLocation RParen) {
   QualType T = TSInfo->getType();
 
-         // FIXME: This should likely be tracked as an APInt to remove any host
-         // assumptions about the width of size_t on the target.
+  // FIXME: This should likely be tracked as an APInt to remove any host
+  // assumptions about the width of size_t on the target.
   uint64_t Value = 0;
   if (!T->isDependentType())
     Value = EvaluateArrayTypeTrait(*this, ATT, T, DimExpr, KWLoc);
 
-         // While the specification for these traits from the Embarcadero C++
-         // compiler's documentation says the return type is 'unsigned int', Clang
-         // returns 'size_t'. On Windows, the primary platform for the Embarcadero
-         // compiler, there is no difference. On several other platforms this is an
-         // important distinction.
+  // While the specification for these traits from the Embarcadero C++
+  // compiler's documentation says the return type is 'unsigned int', Clang
+  // returns 'size_t'. On Windows, the primary platform for the Embarcadero
+  // compiler, there is no difference. On several other platforms this is an
+  // important distinction.
   return new (Context) ArrayTypeTraitExpr(KWLoc, ATT, TSInfo, Value, DimExpr,
                                           RParen, Context.getSizeType());
 }
 
-ExprResult Sema::ActOnExpressionTrait(ExpressionTrait ET,
-                                      SourceLocation KWLoc,
-                                      Expr *Queried,
-                                      SourceLocation RParen) {
+ExprResult Sema::ActOnExpressionTrait(ExpressionTrait ET, SourceLocation KWLoc,
+                                      Expr *Queried, SourceLocation RParen) {
   // If error parsing the expression, ignore.
   if (!Queried)
     return ExprError();
@@ -1893,22 +1893,22 @@ ExprResult Sema::ActOnExpressionTrait(ExpressionTrait ET,
 
 static bool EvaluateExpressionTrait(ExpressionTrait ET, Expr *E) {
   switch (ET) {
-  case ET_IsLValueExpr: return E->isLValue();
+  case ET_IsLValueExpr:
+    return E->isLValue();
   case ET_IsRValueExpr:
     return E->isPRValue();
   }
   llvm_unreachable("Expression trait not covered by switch");
 }
 
-ExprResult Sema::BuildExpressionTrait(ExpressionTrait ET,
-                                      SourceLocation KWLoc,
-                                      Expr *Queried,
-                                      SourceLocation RParen) {
+ExprResult Sema::BuildExpressionTrait(ExpressionTrait ET, SourceLocation KWLoc,
+                                      Expr *Queried, SourceLocation RParen) {
   if (Queried->isTypeDependent()) {
     // Delay type-checking for type-dependent expressions.
   } else if (Queried->hasPlaceholderType()) {
     ExprResult PE = CheckPlaceholderExpr(Queried);
-    if (PE.isInvalid()) return ExprError();
+    if (PE.isInvalid())
+      return ExprError();
     return BuildExpressionTrait(ET, KWLoc, PE.get(), RParen);
   }
 



More information about the cfe-commits mailing list