[clang] c6e996a - Reapply "[Clang] Fix __is_trivially_equality_comparable returning true with ineligebile defaulted overloads" (#97002) (#97894)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 12 09:29:42 PDT 2024
Author: Nikolas Klauser
Date: 2024-07-12T18:29:39+02:00
New Revision: c6e996a931f810db9b43c24f74931cea79337511
URL: https://github.com/llvm/llvm-project/commit/c6e996a931f810db9b43c24f74931cea79337511
DIFF: https://github.com/llvm/llvm-project/commit/c6e996a931f810db9b43c24f74931cea79337511.diff
LOG: Reapply "[Clang] Fix __is_trivially_equality_comparable returning true with ineligebile defaulted overloads" (#97002) (#97894)
This reverts commit 567b2c608c307c097315dd5ec4d6a5bbcddf898d.
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/AST/Type.h
clang/lib/AST/Type.cpp
clang/lib/Sema/SemaExprCXX.cpp
clang/test/SemaCXX/type-traits.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index b211e8255ec0c..ceead8c362e9c 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -827,6 +827,9 @@ Bug Fixes in This Version
- Fixed Clang crashing when failing to perform some C++ Initialization Sequences. (#GH98102)
+- ``__is_trivially_equality_comparable`` no longer returns true for types which
+ have a constrained defaulted comparison operator (#GH89293).
+
Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index a2194361abd53..3aa0f05b0ab60 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -1142,9 +1142,6 @@ class QualType {
/// Return true if this is a trivially relocatable type.
bool isTriviallyRelocatableType(const ASTContext &Context) const;
- /// Return true if this is a trivially equality comparable type.
- bool isTriviallyEqualityComparableType(const ASTContext &Context) const;
-
/// Returns true if it is a class and it might be dynamic.
bool mayBeDynamicClass() const;
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index d8b885870de3a..cc535aba4936e 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -2815,66 +2815,6 @@ bool QualType::isTriviallyRelocatableType(const ASTContext &Context) const {
}
}
-static bool
-HasNonDeletedDefaultedEqualityComparison(const CXXRecordDecl *Decl) {
- if (Decl->isUnion())
- return false;
- if (Decl->isLambda())
- return Decl->isCapturelessLambda();
-
- auto IsDefaultedOperatorEqualEqual = [&](const FunctionDecl *Function) {
- return Function->getOverloadedOperator() ==
- OverloadedOperatorKind::OO_EqualEqual &&
- Function->isDefaulted() && Function->getNumParams() > 0 &&
- (Function->getParamDecl(0)->getType()->isReferenceType() ||
- Decl->isTriviallyCopyable());
- };
-
- if (llvm::none_of(Decl->methods(), IsDefaultedOperatorEqualEqual) &&
- llvm::none_of(Decl->friends(), [&](const FriendDecl *Friend) {
- if (NamedDecl *ND = Friend->getFriendDecl()) {
- return ND->isFunctionOrFunctionTemplate() &&
- IsDefaultedOperatorEqualEqual(ND->getAsFunction());
- }
- return false;
- }))
- return false;
-
- return llvm::all_of(Decl->bases(),
- [](const CXXBaseSpecifier &BS) {
- if (const auto *RD = BS.getType()->getAsCXXRecordDecl())
- return HasNonDeletedDefaultedEqualityComparison(RD);
- 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(RD);
- return true;
- });
-}
-
-bool QualType::isTriviallyEqualityComparableType(
- const ASTContext &Context) const {
- QualType CanonicalType = getCanonicalType();
- if (CanonicalType->isIncompleteType() || CanonicalType->isDependentType() ||
- CanonicalType->isEnumeralType() || CanonicalType->isArrayType())
- return false;
-
- if (const auto *RD = CanonicalType->getAsCXXRecordDecl()) {
- if (!HasNonDeletedDefaultedEqualityComparison(RD))
- return false;
- }
-
- return Context.hasUniqueObjectRepresentations(
- CanonicalType, /*CheckIfTriviallyCopyable=*/false);
-}
-
bool QualType::isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const {
return !Context.getLangOpts().ObjCAutoRefCount &&
Context.getLangOpts().ObjCWeak &&
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index fcf2189a308a8..d0e963441d79a 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -5129,6 +5129,83 @@ static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op,
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, /*AccessCheckingSFINAE=*/true);
+ Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
+
+ // const ClassT& obj;
+ OpaqueValueExpr Operand(
+ {}, 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 EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
SourceLocation KeyLoc,
TypeSourceInfo *TInfo) {
@@ -5561,7 +5638,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
Self.Diag(KeyLoc, diag::err_builtin_pass_in_regs_non_class) << T;
return false;
case UTT_IsTriviallyEqualityComparable:
- return T.isTriviallyEqualityComparableType(C);
+ return isTriviallyEqualityComparableType(Self, T, KeyLoc);
}
}
diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index d40605f56f1ed..7adbf4aad7afe 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -3677,6 +3677,12 @@ struct NonTriviallyEqualityComparableNoComparator {
};
static_assert(!__is_trivially_equality_comparable(NonTriviallyEqualityComparableNoComparator));
+struct NonTriviallyEqualityComparableConvertibleToBuiltin {
+ int i;
+ operator unsigned() const;
+};
+static_assert(!__is_trivially_equality_comparable(NonTriviallyEqualityComparableConvertibleToBuiltin));
+
struct NonTriviallyEqualityComparableNonDefaultedComparator {
int i;
int j;
@@ -3885,8 +3891,51 @@ struct NotTriviallyEqualityComparableNonTriviallyEqualityComparableArrs2 {
bool operator==(const NotTriviallyEqualityComparableNonTriviallyEqualityComparableArrs2&) const = default;
};
+
static_assert(!__is_trivially_equality_comparable(NotTriviallyEqualityComparableNonTriviallyEqualityComparableArrs2));
+template<bool B>
+struct MaybeTriviallyEqualityComparable {
+ int i;
+ bool operator==(const MaybeTriviallyEqualityComparable&) const requires B = default;
+ bool operator==(const MaybeTriviallyEqualityComparable& rhs) const { return (i % 3) == (rhs.i % 3); }
+};
+static_assert(__is_trivially_equality_comparable(MaybeTriviallyEqualityComparable<true>));
+static_assert(!__is_trivially_equality_comparable(MaybeTriviallyEqualityComparable<false>));
+
+struct NotTriviallyEqualityComparableMoreConstrainedExternalOp {
+ int i;
+ bool operator==(const NotTriviallyEqualityComparableMoreConstrainedExternalOp&) const = default;
+};
+
+bool operator==(const NotTriviallyEqualityComparableMoreConstrainedExternalOp&,
+ const NotTriviallyEqualityComparableMoreConstrainedExternalOp&) __attribute__((enable_if(true, ""))) {}
+
+static_assert(!__is_trivially_equality_comparable(NotTriviallyEqualityComparableMoreConstrainedExternalOp));
+
+struct TriviallyEqualityComparableExternalDefaultedOp {
+ int i;
+ friend bool operator==(TriviallyEqualityComparableExternalDefaultedOp, TriviallyEqualityComparableExternalDefaultedOp);
+};
+bool operator==(TriviallyEqualityComparableExternalDefaultedOp, TriviallyEqualityComparableExternalDefaultedOp) = default;
+
+static_assert(__is_trivially_equality_comparable(TriviallyEqualityComparableExternalDefaultedOp));
+
+struct EqualityComparableBase {
+ bool operator==(const EqualityComparableBase&) const = default;
+};
+
+struct ComparingBaseOnly : EqualityComparableBase {
+ int j_ = 0;
+};
+static_assert(!__is_trivially_equality_comparable(ComparingBaseOnly));
+
+template <class>
+class Template {};
+
+// Make sure we don't crash when instantiating a type
+static_assert(!__is_trivially_equality_comparable(Template<Template<int>>));
+
namespace hidden_friend {
struct TriviallyEqualityComparable {
More information about the cfe-commits
mailing list