Skip to content

Commit c6e996a

Browse files
authored
Reapply "[Clang] Fix __is_trivially_equality_comparable returning true with ineligebile defaulted overloads" (#97002) (#97894)
This reverts commit 567b2c6.
1 parent 5ff3ff3 commit c6e996a

File tree

5 files changed

+130
-64
lines changed

5 files changed

+130
-64
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,9 @@ Bug Fixes in This Version
827827

828828
- Fixed Clang crashing when failing to perform some C++ Initialization Sequences. (#GH98102)
829829

830+
- ``__is_trivially_equality_comparable`` no longer returns true for types which
831+
have a constrained defaulted comparison operator (#GH89293).
832+
830833
Bug Fixes to Compiler Builtins
831834
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
832835

clang/include/clang/AST/Type.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1142,9 +1142,6 @@ class QualType {
11421142
/// Return true if this is a trivially relocatable type.
11431143
bool isTriviallyRelocatableType(const ASTContext &Context) const;
11441144

1145-
/// Return true if this is a trivially equality comparable type.
1146-
bool isTriviallyEqualityComparableType(const ASTContext &Context) const;
1147-
11481145
/// Returns true if it is a class and it might be dynamic.
11491146
bool mayBeDynamicClass() const;
11501147

clang/lib/AST/Type.cpp

Lines changed: 0 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -2815,66 +2815,6 @@ bool QualType::isTriviallyRelocatableType(const ASTContext &Context) const {
28152815
}
28162816
}
28172817

2818-
static bool
2819-
HasNonDeletedDefaultedEqualityComparison(const CXXRecordDecl *Decl) {
2820-
if (Decl->isUnion())
2821-
return false;
2822-
if (Decl->isLambda())
2823-
return Decl->isCapturelessLambda();
2824-
2825-
auto IsDefaultedOperatorEqualEqual = [&](const FunctionDecl *Function) {
2826-
return Function->getOverloadedOperator() ==
2827-
OverloadedOperatorKind::OO_EqualEqual &&
2828-
Function->isDefaulted() && Function->getNumParams() > 0 &&
2829-
(Function->getParamDecl(0)->getType()->isReferenceType() ||
2830-
Decl->isTriviallyCopyable());
2831-
};
2832-
2833-
if (llvm::none_of(Decl->methods(), IsDefaultedOperatorEqualEqual) &&
2834-
llvm::none_of(Decl->friends(), [&](const FriendDecl *Friend) {
2835-
if (NamedDecl *ND = Friend->getFriendDecl()) {
2836-
return ND->isFunctionOrFunctionTemplate() &&
2837-
IsDefaultedOperatorEqualEqual(ND->getAsFunction());
2838-
}
2839-
return false;
2840-
}))
2841-
return false;
2842-
2843-
return llvm::all_of(Decl->bases(),
2844-
[](const CXXBaseSpecifier &BS) {
2845-
if (const auto *RD = BS.getType()->getAsCXXRecordDecl())
2846-
return HasNonDeletedDefaultedEqualityComparison(RD);
2847-
return true;
2848-
}) &&
2849-
llvm::all_of(Decl->fields(), [](const FieldDecl *FD) {
2850-
auto Type = FD->getType();
2851-
if (Type->isArrayType())
2852-
Type = Type->getBaseElementTypeUnsafe()->getCanonicalTypeUnqualified();
2853-
2854-
if (Type->isReferenceType() || Type->isEnumeralType())
2855-
return false;
2856-
if (const auto *RD = Type->getAsCXXRecordDecl())
2857-
return HasNonDeletedDefaultedEqualityComparison(RD);
2858-
return true;
2859-
});
2860-
}
2861-
2862-
bool QualType::isTriviallyEqualityComparableType(
2863-
const ASTContext &Context) const {
2864-
QualType CanonicalType = getCanonicalType();
2865-
if (CanonicalType->isIncompleteType() || CanonicalType->isDependentType() ||
2866-
CanonicalType->isEnumeralType() || CanonicalType->isArrayType())
2867-
return false;
2868-
2869-
if (const auto *RD = CanonicalType->getAsCXXRecordDecl()) {
2870-
if (!HasNonDeletedDefaultedEqualityComparison(RD))
2871-
return false;
2872-
}
2873-
2874-
return Context.hasUniqueObjectRepresentations(
2875-
CanonicalType, /*CheckIfTriviallyCopyable=*/false);
2876-
}
2877-
28782818
bool QualType::isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const {
28792819
return !Context.getLangOpts().ObjCAutoRefCount &&
28802820
Context.getLangOpts().ObjCWeak &&

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5129,6 +5129,83 @@ static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op,
51295129
return false;
51305130
}
51315131

5132+
static bool HasNonDeletedDefaultedEqualityComparison(Sema &S,
5133+
const CXXRecordDecl *Decl,
5134+
SourceLocation KeyLoc) {
5135+
if (Decl->isUnion())
5136+
return false;
5137+
if (Decl->isLambda())
5138+
return Decl->isCapturelessLambda();
5139+
5140+
{
5141+
EnterExpressionEvaluationContext UnevaluatedContext(
5142+
S, Sema::ExpressionEvaluationContext::Unevaluated);
5143+
Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true);
5144+
Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
5145+
5146+
// const ClassT& obj;
5147+
OpaqueValueExpr Operand(
5148+
{}, Decl->getTypeForDecl()->getCanonicalTypeUnqualified().withConst(),
5149+
ExprValueKind::VK_LValue);
5150+
UnresolvedSet<16> Functions;
5151+
// obj == obj;
5152+
S.LookupBinOp(S.TUScope, {}, BinaryOperatorKind::BO_EQ, Functions);
5153+
5154+
auto Result = S.CreateOverloadedBinOp(KeyLoc, BinaryOperatorKind::BO_EQ,
5155+
Functions, &Operand, &Operand);
5156+
if (Result.isInvalid() || SFINAE.hasErrorOccurred())
5157+
return false;
5158+
5159+
const auto *CallExpr = dyn_cast<CXXOperatorCallExpr>(Result.get());
5160+
if (!CallExpr)
5161+
return false;
5162+
const auto *Callee = CallExpr->getDirectCallee();
5163+
auto ParamT = Callee->getParamDecl(0)->getType();
5164+
if (!Callee->isDefaulted())
5165+
return false;
5166+
if (!ParamT->isReferenceType() && !Decl->isTriviallyCopyable())
5167+
return false;
5168+
if (ParamT.getNonReferenceType()->getUnqualifiedDesugaredType() !=
5169+
Decl->getTypeForDecl())
5170+
return false;
5171+
}
5172+
5173+
return llvm::all_of(Decl->bases(),
5174+
[&](const CXXBaseSpecifier &BS) {
5175+
if (const auto *RD = BS.getType()->getAsCXXRecordDecl())
5176+
return HasNonDeletedDefaultedEqualityComparison(
5177+
S, RD, KeyLoc);
5178+
return true;
5179+
}) &&
5180+
llvm::all_of(Decl->fields(), [&](const FieldDecl *FD) {
5181+
auto Type = FD->getType();
5182+
if (Type->isArrayType())
5183+
Type = Type->getBaseElementTypeUnsafe()
5184+
->getCanonicalTypeUnqualified();
5185+
5186+
if (Type->isReferenceType() || Type->isEnumeralType())
5187+
return false;
5188+
if (const auto *RD = Type->getAsCXXRecordDecl())
5189+
return HasNonDeletedDefaultedEqualityComparison(S, RD, KeyLoc);
5190+
return true;
5191+
});
5192+
}
5193+
5194+
static bool isTriviallyEqualityComparableType(Sema &S, QualType Type, SourceLocation KeyLoc) {
5195+
QualType CanonicalType = Type.getCanonicalType();
5196+
if (CanonicalType->isIncompleteType() || CanonicalType->isDependentType() ||
5197+
CanonicalType->isEnumeralType() || CanonicalType->isArrayType())
5198+
return false;
5199+
5200+
if (const auto *RD = CanonicalType->getAsCXXRecordDecl()) {
5201+
if (!HasNonDeletedDefaultedEqualityComparison(S, RD, KeyLoc))
5202+
return false;
5203+
}
5204+
5205+
return S.getASTContext().hasUniqueObjectRepresentations(
5206+
CanonicalType, /*CheckIfTriviallyCopyable=*/false);
5207+
}
5208+
51325209
static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
51335210
SourceLocation KeyLoc,
51345211
TypeSourceInfo *TInfo) {
@@ -5561,7 +5638,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
55615638
Self.Diag(KeyLoc, diag::err_builtin_pass_in_regs_non_class) << T;
55625639
return false;
55635640
case UTT_IsTriviallyEqualityComparable:
5564-
return T.isTriviallyEqualityComparableType(C);
5641+
return isTriviallyEqualityComparableType(Self, T, KeyLoc);
55655642
}
55665643
}
55675644

clang/test/SemaCXX/type-traits.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3677,6 +3677,12 @@ struct NonTriviallyEqualityComparableNoComparator {
36773677
};
36783678
static_assert(!__is_trivially_equality_comparable(NonTriviallyEqualityComparableNoComparator));
36793679

3680+
struct NonTriviallyEqualityComparableConvertibleToBuiltin {
3681+
int i;
3682+
operator unsigned() const;
3683+
};
3684+
static_assert(!__is_trivially_equality_comparable(NonTriviallyEqualityComparableConvertibleToBuiltin));
3685+
36803686
struct NonTriviallyEqualityComparableNonDefaultedComparator {
36813687
int i;
36823688
int j;
@@ -3885,8 +3891,51 @@ struct NotTriviallyEqualityComparableNonTriviallyEqualityComparableArrs2 {
38853891

38863892
bool operator==(const NotTriviallyEqualityComparableNonTriviallyEqualityComparableArrs2&) const = default;
38873893
};
3894+
38883895
static_assert(!__is_trivially_equality_comparable(NotTriviallyEqualityComparableNonTriviallyEqualityComparableArrs2));
38893896

3897+
template<bool B>
3898+
struct MaybeTriviallyEqualityComparable {
3899+
int i;
3900+
bool operator==(const MaybeTriviallyEqualityComparable&) const requires B = default;
3901+
bool operator==(const MaybeTriviallyEqualityComparable& rhs) const { return (i % 3) == (rhs.i % 3); }
3902+
};
3903+
static_assert(__is_trivially_equality_comparable(MaybeTriviallyEqualityComparable<true>));
3904+
static_assert(!__is_trivially_equality_comparable(MaybeTriviallyEqualityComparable<false>));
3905+
3906+
struct NotTriviallyEqualityComparableMoreConstrainedExternalOp {
3907+
int i;
3908+
bool operator==(const NotTriviallyEqualityComparableMoreConstrainedExternalOp&) const = default;
3909+
};
3910+
3911+
bool operator==(const NotTriviallyEqualityComparableMoreConstrainedExternalOp&,
3912+
const NotTriviallyEqualityComparableMoreConstrainedExternalOp&) __attribute__((enable_if(true, ""))) {}
3913+
3914+
static_assert(!__is_trivially_equality_comparable(NotTriviallyEqualityComparableMoreConstrainedExternalOp));
3915+
3916+
struct TriviallyEqualityComparableExternalDefaultedOp {
3917+
int i;
3918+
friend bool operator==(TriviallyEqualityComparableExternalDefaultedOp, TriviallyEqualityComparableExternalDefaultedOp);
3919+
};
3920+
bool operator==(TriviallyEqualityComparableExternalDefaultedOp, TriviallyEqualityComparableExternalDefaultedOp) = default;
3921+
3922+
static_assert(__is_trivially_equality_comparable(TriviallyEqualityComparableExternalDefaultedOp));
3923+
3924+
struct EqualityComparableBase {
3925+
bool operator==(const EqualityComparableBase&) const = default;
3926+
};
3927+
3928+
struct ComparingBaseOnly : EqualityComparableBase {
3929+
int j_ = 0;
3930+
};
3931+
static_assert(!__is_trivially_equality_comparable(ComparingBaseOnly));
3932+
3933+
template <class>
3934+
class Template {};
3935+
3936+
// Make sure we don't crash when instantiating a type
3937+
static_assert(!__is_trivially_equality_comparable(Template<Template<int>>));
3938+
38903939
namespace hidden_friend {
38913940

38923941
struct TriviallyEqualityComparable {

0 commit comments

Comments
 (0)