Author: Nikolas Klauser
Date: 2023-05-30T08:33:31-07:00
New Revision: 0e4c4c77730810db235d377d49ba5860dfa0bd8d

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

LOG: [clang] Extend __is_trivially_equality_comparable to check for hidden 
friends

This allows types to be considered trivially equality comparable if a defaulted 
hidden friend is used.

Reviewed By: erichkeane

Spies: cfe-commits

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

Added: 
    

Modified: 
    clang/lib/AST/Type.cpp
    clang/test/SemaCXX/type-traits.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 508965fc38e55..bde88653417d9 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -18,6 +18,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclBase.h"
 #include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclFriend.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/DependenceFlags.h"
@@ -2640,11 +2641,21 @@ HasNonDeletedDefaultedEqualityComparison(const 
CXXRecordDecl *Decl) {
   if (Decl->isUnion())
     return false;
 
-  if (llvm::none_of(Decl->methods(), [](const CXXMethodDecl *MemberFunction) {
-        return MemberFunction->isOverloadedOperator() &&
-               MemberFunction->getOverloadedOperator() ==
-                   OverloadedOperatorKind::OO_EqualEqual &&
-               MemberFunction->isDefaulted();
+  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;
 

diff  --git a/clang/test/SemaCXX/type-traits.cpp 
b/clang/test/SemaCXX/type-traits.cpp
index 75f172d1c3452..d5388d4eb89be 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -3270,6 +3270,172 @@ struct NotTriviallyEqualityComparableHasEnum {
 };
 
static_assert(!__is_trivially_equality_comparable(NotTriviallyEqualityComparableHasEnum));
 
+namespace hidden_friend {
+
+struct TriviallyEqualityComparable {
+  int i;
+  int j;
+
+  void func();
+  bool operator==(int) const { return false; }
+
+  friend bool operator==(const TriviallyEqualityComparable&, const 
TriviallyEqualityComparable&) = default;
+};
+static_assert(__is_trivially_equality_comparable(TriviallyEqualityComparable), 
"");
+
+struct TriviallyEqualityComparableNonTriviallyCopyable {
+  TriviallyEqualityComparableNonTriviallyCopyable(const 
TriviallyEqualityComparableNonTriviallyCopyable&);
+  ~TriviallyEqualityComparableNonTriviallyCopyable();
+  friend bool operator==(const 
TriviallyEqualityComparableNonTriviallyCopyable&, const 
TriviallyEqualityComparableNonTriviallyCopyable&) = default;
+  int i;
+};
+static_assert(__is_trivially_equality_comparable(TriviallyEqualityComparableNonTriviallyCopyable));
+
+struct NotTriviallyEqualityComparableHasPadding {
+  short i;
+  int j;
+
+  friend bool operator==(const NotTriviallyEqualityComparableHasPadding&, 
const NotTriviallyEqualityComparableHasPadding&) = default;
+};
+static_assert(!__is_trivially_equality_comparable(NotTriviallyEqualityComparableHasPadding),
 "");
+
+struct NotTriviallyEqualityComparableHasFloat {
+  float i;
+  int j;
+
+  friend bool operator==(const NotTriviallyEqualityComparableHasFloat&, const 
NotTriviallyEqualityComparableHasFloat&) = default;
+};
+static_assert(!__is_trivially_equality_comparable(NotTriviallyEqualityComparableHasFloat),
 "");
+
+struct NotTriviallyEqualityComparableHasTailPadding {
+  int i;
+  char j;
+
+  friend bool operator==(const NotTriviallyEqualityComparableHasTailPadding&, 
const NotTriviallyEqualityComparableHasTailPadding&) = default;
+};
+static_assert(!__is_trivially_equality_comparable(NotTriviallyEqualityComparableHasTailPadding),
 "");
+
+struct NotTriviallyEqualityComparableBase : 
NotTriviallyEqualityComparableHasTailPadding {
+  char j;
+
+  friend bool operator==(const NotTriviallyEqualityComparableBase&, const 
NotTriviallyEqualityComparableBase&) = default;
+};
+static_assert(!__is_trivially_equality_comparable(NotTriviallyEqualityComparableBase),
 "");
+
+class TriviallyEqualityComparablePaddedOutBase {
+  int i;
+  char c;
+
+public:
+  friend bool operator==(const TriviallyEqualityComparablePaddedOutBase&, 
const TriviallyEqualityComparablePaddedOutBase&) = default;
+};
+static_assert(!__is_trivially_equality_comparable(TriviallyEqualityComparablePaddedOutBase),
 "");
+
+struct TriviallyEqualityComparablePaddedOut : 
TriviallyEqualityComparablePaddedOutBase {
+  char j[3];
+
+  friend bool operator==(const TriviallyEqualityComparablePaddedOut&, const 
TriviallyEqualityComparablePaddedOut&) = default;
+};
+static_assert(__is_trivially_equality_comparable(TriviallyEqualityComparablePaddedOut),
 "");
+
+struct TriviallyEqualityComparable1 {
+  char i;
+
+  friend bool operator==(const TriviallyEqualityComparable1&, const 
TriviallyEqualityComparable1&) = default;
+};
+static_assert(__is_trivially_equality_comparable(TriviallyEqualityComparable1));
+
+struct TriviallyEqualityComparable2 {
+  int i;
+
+  friend bool operator==(const TriviallyEqualityComparable2&, const 
TriviallyEqualityComparable2&) = default;
+};
+static_assert(__is_trivially_equality_comparable(TriviallyEqualityComparable2));
+
+struct NotTriviallyEqualityComparableTriviallyEqualityComparableBases
+    : TriviallyEqualityComparable1, TriviallyEqualityComparable2 {
+  friend bool operator==(const 
NotTriviallyEqualityComparableTriviallyEqualityComparableBases&, const 
NotTriviallyEqualityComparableTriviallyEqualityComparableBases&) = default;
+};
+static_assert(!__is_trivially_equality_comparable(NotTriviallyEqualityComparableTriviallyEqualityComparableBases));
+
+struct NotTriviallyEqualityComparableBitfield {
+  int i : 1;
+
+  friend bool operator==(const NotTriviallyEqualityComparableBitfield&, const 
NotTriviallyEqualityComparableBitfield&) = default;
+};
+static_assert(!__is_trivially_equality_comparable(NotTriviallyEqualityComparableBitfield));
+
+// TODO: This is trivially equality comparable
+struct NotTriviallyEqualityComparableBitfieldFilled {
+  char i : __CHAR_BIT__;
+
+  friend bool operator==(const NotTriviallyEqualityComparableBitfieldFilled&, 
const NotTriviallyEqualityComparableBitfieldFilled&) = default;
+};
+static_assert(!__is_trivially_equality_comparable(NotTriviallyEqualityComparableBitfield));
+
+union U {
+  int i;
+
+  friend bool operator==(const U&, const U&) = default;
+};
+
+struct NotTriviallyEqualityComparableImplicitlyDeletedOperatorByUnion {
+  U u;
+
+  friend bool operator==(const 
NotTriviallyEqualityComparableImplicitlyDeletedOperatorByUnion&, const 
NotTriviallyEqualityComparableImplicitlyDeletedOperatorByUnion&) = default;
+};
+static_assert(!__is_trivially_equality_comparable(NotTriviallyEqualityComparableImplicitlyDeletedOperatorByUnion));
+
+struct NotTriviallyEqualityComparableExplicitlyDeleted {
+  int i;
+
+  friend bool operator==(const 
NotTriviallyEqualityComparableExplicitlyDeleted&, const 
NotTriviallyEqualityComparableExplicitlyDeleted&) = delete;
+};
+
+struct NotTriviallyEqualityComparableImplicitlyDeletedOperatorByStruct {
+  NotTriviallyEqualityComparableExplicitlyDeleted u;
+
+  friend bool operator==(const 
NotTriviallyEqualityComparableImplicitlyDeletedOperatorByStruct&, const 
NotTriviallyEqualityComparableImplicitlyDeletedOperatorByStruct&) = default;
+};
+static_assert(!__is_trivially_equality_comparable(NotTriviallyEqualityComparableImplicitlyDeletedOperatorByStruct));
+
+struct NotTriviallyEqualityComparableHasReferenceMember {
+  int& i;
+
+  friend bool operator==(const 
NotTriviallyEqualityComparableHasReferenceMember&, const 
NotTriviallyEqualityComparableHasReferenceMember&) = default;
+};
+static_assert(!__is_trivially_equality_comparable(NotTriviallyEqualityComparableHasReferenceMember));
+
+enum E {
+  a,
+  b
+};
+bool operator==(E, E) { return false; }
+static_assert(!__is_trivially_equality_comparable(E));
+
+struct NotTriviallyEqualityComparableHasEnum {
+  E e;
+  friend bool operator==(const NotTriviallyEqualityComparableHasEnum&, const 
NotTriviallyEqualityComparableHasEnum&) = default;
+};
+static_assert(!__is_trivially_equality_comparable(NotTriviallyEqualityComparableHasEnum));
+
+struct NonTriviallyEqualityComparableValueComparisonNonTriviallyCopyable {
+  int i;
+  NonTriviallyEqualityComparableValueComparisonNonTriviallyCopyable(const 
NonTriviallyEqualityComparableValueComparisonNonTriviallyCopyable&);
+
+  friend bool 
operator==(NonTriviallyEqualityComparableValueComparisonNonTriviallyCopyable, 
NonTriviallyEqualityComparableValueComparisonNonTriviallyCopyable) = default;
+};
+static_assert(!__is_trivially_equality_comparable(NonTriviallyEqualityComparableValueComparisonNonTriviallyCopyable));
+
+struct TriviallyEqualityComparableRefComparisonNonTriviallyCopyable {
+  int i;
+  TriviallyEqualityComparableRefComparisonNonTriviallyCopyable(const 
TriviallyEqualityComparableRefComparisonNonTriviallyCopyable&);
+
+  friend bool operator==(const 
TriviallyEqualityComparableRefComparisonNonTriviallyCopyable&, const 
TriviallyEqualityComparableRefComparisonNonTriviallyCopyable&) = default;
+};
+static_assert(__is_trivially_equality_comparable(TriviallyEqualityComparableRefComparisonNonTriviallyCopyable));
+}
+
 #endif // __cplusplus >= 202002L
 };
 


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to