llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: cor3ntin (cor3ntin)

<details>
<summary>Changes</summary>

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

As discussed in #<!-- -->141238

---

Patch is 147.71 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/141245.diff


4 Files Affected:

- (modified) clang/lib/Sema/CMakeLists.txt (+1) 
- (modified) clang/lib/Sema/SemaDeclCXX.cpp (-273) 
- (modified) clang/lib/Sema/SemaExprCXX.cpp (-1621) 
- (added) clang/lib/Sema/SemaTypeTraits.cpp (+1919) 


``````````diff
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...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/141245
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to