Skip to content

Conversation

jlallas384
Copy link

This doesn't check whether the negated operator is defined, following the same behavior in other parts of the code that deal with overloaded operators.

Fixes #163128

Copy link

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot
Copy link
Member

llvmbot commented Oct 19, 2025

@llvm/pr-subscribers-clang-tools-extra

Author: None (jlallas384)

Changes

This doesn't check whether the negated operator is defined, following the same behavior in other parts of the code that deal with overloaded operators.

Fixes #163128


Full diff: https://github.com/llvm/llvm-project/pull/164141.diff

2 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.cpp (+62-31)
  • (modified) clang-tools-extra/test/clang-tidy/checkers/readability/simplify-boolean-expr-demorgan.cpp (+12)
diff --git a/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.cpp b/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.cpp
index 4184c295b5f0a..4cea2b5030f42 100644
--- a/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.cpp
@@ -809,14 +809,14 @@ void SimplifyBooleanExprCheck::replaceWithAssignment(const ASTContext &Context,
             Range, Replacement);
 }
 
-/// Swaps a \c BinaryOperator opcode from `&&` to `||` or vice-versa.
+/// Swaps \p BO from `&&` to `||` or vice-versa.
 static bool flipDemorganOperator(llvm::SmallVectorImpl<FixItHint> &Output,
-                                 const BinaryOperator *BO) {
-  assert(BO->isLogicalOp());
-  if (BO->getOperatorLoc().isMacroID())
+                                 BinaryOperatorKind BO, SourceLocation BOLoc) {
+  assert(BinaryOperator::isLogicalOp(BO));
+  if (BOLoc.isMacroID())
     return true;
-  Output.push_back(FixItHint::CreateReplacement(
-      BO->getOperatorLoc(), BO->getOpcode() == BO_LAnd ? "||" : "&&"));
+  Output.push_back(
+      FixItHint::CreateReplacement(BOLoc, BO == BO_LAnd ? "||" : "&&"));
   return false;
 }
 
@@ -829,22 +829,22 @@ static bool flipDemorganSide(SmallVectorImpl<FixItHint> &Fixes,
                              const ASTContext &Ctx, const Expr *E,
                              std::optional<BinaryOperatorKind> OuterBO);
 
-/// Inverts \p BinOp, Removing \p Parens if they exist and are safe to remove.
-/// returns \c true if there is any issue building the Fixes, \c false
-/// otherwise.
-static bool
-flipDemorganBinaryOperator(SmallVectorImpl<FixItHint> &Fixes,
-                           const ASTContext &Ctx, const BinaryOperator *BinOp,
-                           std::optional<BinaryOperatorKind> OuterBO,
-                           const ParenExpr *Parens = nullptr) {
-  switch (BinOp->getOpcode()) {
+/// Inverts \p BO, \p LHS, and \p RHS, Removing \p Parens if they exist and are
+/// safe to remove. returns \c true if there is any issue building the Fixes, \c
+/// false otherwise.
+static bool flipDemorganBinaryOperator(
+    SmallVectorImpl<FixItHint> &Fixes, const ASTContext &Ctx,
+    BinaryOperatorKind BO, const Expr *LHS, const Expr *RHS, SourceRange Range,
+    SourceLocation BOLoc, std::optional<BinaryOperatorKind> OuterBO,
+    const ParenExpr *Parens = nullptr) {
+  switch (BO) {
   case BO_LAnd:
   case BO_LOr: {
     // if we have 'a && b' or 'a || b', use demorgan to flip it to '!a || !b'
     // or '!a && !b'.
-    if (flipDemorganOperator(Fixes, BinOp))
+    if (flipDemorganOperator(Fixes, BO, BOLoc))
       return true;
-    auto NewOp = getDemorganFlippedOperator(BinOp->getOpcode());
+    auto NewOp = getDemorganFlippedOperator(BO);
     if (OuterBO) {
       // The inner parens are technically needed in a fix for
       // `!(!A1 && !(A2 || A3)) -> (A1 || (A2 && A3))`,
@@ -862,16 +862,15 @@ flipDemorganBinaryOperator(SmallVectorImpl<FixItHint> &Fixes,
         }
       }
       if (*OuterBO == BO_LAnd && NewOp == BO_LOr && !Parens) {
-        Fixes.push_back(FixItHint::CreateInsertion(BinOp->getBeginLoc(), "("));
+        Fixes.push_back(FixItHint::CreateInsertion(Range.getBegin(), "("));
         Fixes.push_back(FixItHint::CreateInsertion(
-            Lexer::getLocForEndOfToken(BinOp->getEndLoc(), 0,
-                                       Ctx.getSourceManager(),
-                                       Ctx.getLangOpts()),
+            Lexer::getLocForEndOfToken(
+                Range.getEnd(), 0, Ctx.getSourceManager(), Ctx.getLangOpts()),
             ")"));
       }
     }
-    if (flipDemorganSide(Fixes, Ctx, BinOp->getLHS(), NewOp) ||
-        flipDemorganSide(Fixes, Ctx, BinOp->getRHS(), NewOp))
+    if (flipDemorganSide(Fixes, Ctx, LHS, NewOp) ||
+        flipDemorganSide(Fixes, Ctx, RHS, NewOp))
       return true;
     return false;
   };
@@ -882,12 +881,11 @@ flipDemorganBinaryOperator(SmallVectorImpl<FixItHint> &Fixes,
   case BO_EQ:
   case BO_NE:
     // For comparison operators, just negate the comparison.
-    if (BinOp->getOperatorLoc().isMacroID())
+    if (BOLoc.isMacroID())
       return true;
     Fixes.push_back(FixItHint::CreateReplacement(
-        BinOp->getOperatorLoc(),
-        BinaryOperator::getOpcodeStr(
-            BinaryOperator::negateComparisonOp(BinOp->getOpcode()))));
+        BOLoc,
+        BinaryOperator::getOpcodeStr(BinaryOperator::negateComparisonOp(BO))));
     return false;
   default:
     // for any other binary operator, just use logical not and wrap in
@@ -897,11 +895,11 @@ flipDemorganBinaryOperator(SmallVectorImpl<FixItHint> &Fixes,
         return true;
       Fixes.push_back(FixItHint::CreateInsertion(Parens->getBeginLoc(), "!"));
     } else {
-      if (BinOp->getBeginLoc().isMacroID() || BinOp->getEndLoc().isMacroID())
+      if (Range.getBegin().isMacroID() || Range.getEnd().isMacroID())
         return true;
-      Fixes.append({FixItHint::CreateInsertion(BinOp->getBeginLoc(), "!("),
+      Fixes.append({FixItHint::CreateInsertion(Range.getBegin(), "!("),
                     FixItHint::CreateInsertion(
-                        Lexer::getLocForEndOfToken(BinOp->getEndLoc(), 0,
+                        Lexer::getLocForEndOfToken(Range.getEnd(), 0,
                                                    Ctx.getSourceManager(),
                                                    Ctx.getLangOpts()),
                         ")")});
@@ -911,6 +909,28 @@ flipDemorganBinaryOperator(SmallVectorImpl<FixItHint> &Fixes,
   return false;
 }
 
+static bool
+flipDemorganBinaryOperator(SmallVectorImpl<FixItHint> &Fixes,
+                           const ASTContext &Ctx, const BinaryOperator *BinOp,
+                           std::optional<BinaryOperatorKind> OuterBO,
+                           const ParenExpr *Parens = nullptr) {
+  return flipDemorganBinaryOperator(
+      Fixes, Ctx, BinOp->getOpcode(), BinOp->getLHS(), BinOp->getRHS(),
+      BinOp->getSourceRange(), BinOp->getOperatorLoc(), OuterBO, Parens);
+}
+
+static bool
+flipDemorganOverloadedBinaryOperator(SmallVectorImpl<FixItHint> &Fixes,
+                                     const ASTContext &Ctx,
+                                     const CXXOperatorCallExpr *OpCall,
+                                     std::optional<BinaryOperatorKind> OuterBO,
+                                     const ParenExpr *Parens = nullptr) {
+  auto BO = BinaryOperator::getOverloadedOpcode(OpCall->getOperator());
+  return flipDemorganBinaryOperator(Fixes, Ctx, BO, OpCall->getArg(0),
+                                    OpCall->getArg(1), OpCall->getSourceRange(),
+                                    OpCall->getOperatorLoc(), OuterBO, Parens);
+}
+
 static bool flipDemorganSide(SmallVectorImpl<FixItHint> &Fixes,
                              const ASTContext &Ctx, const Expr *E,
                              std::optional<BinaryOperatorKind> OuterBO) {
@@ -930,6 +950,17 @@ static bool flipDemorganSide(SmallVectorImpl<FixItHint> &Fixes,
       return flipDemorganBinaryOperator(Fixes, Ctx, BinOp, OuterBO, Paren);
     }
   }
+  if (const auto *OpCall = dyn_cast<CXXOperatorCallExpr>(E);
+      OpCall && OpCall->isInfixBinaryOp()) {
+    return flipDemorganOverloadedBinaryOperator(Fixes, Ctx, OpCall, OuterBO);
+  }
+  if (const auto *Paren = dyn_cast<ParenExpr>(E)) {
+    if (const auto *OpCall = dyn_cast<CXXOperatorCallExpr>(E);
+        OpCall && OpCall->isInfixBinaryOp()) {
+      return flipDemorganOverloadedBinaryOperator(Fixes, Ctx, OpCall, OuterBO,
+                                                  Paren);
+    }
+  }
   // Fallback case just insert a logical not operator.
   if (E->getBeginLoc().isMacroID())
     return true;
@@ -991,7 +1022,7 @@ bool SimplifyBooleanExprCheck::reportDeMorgan(const ASTContext &Context,
   } else {
     Fixes.push_back(FixItHint::CreateRemoval(Outer->getOperatorLoc()));
   }
-  if (flipDemorganOperator(Fixes, Inner))
+  if (flipDemorganOperator(Fixes, Inner->getOpcode(), Inner->getOperatorLoc()))
     return false;
   if (flipDemorganSide(Fixes, Context, Inner->getLHS(), NewOpcode) ||
       flipDemorganSide(Fixes, Context, Inner->getRHS(), NewOpcode))
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/simplify-boolean-expr-demorgan.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/simplify-boolean-expr-demorgan.cpp
index bab9e17a7775b..b70ea72610b16 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/simplify-boolean-expr-demorgan.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/simplify-boolean-expr-demorgan.cpp
@@ -105,4 +105,16 @@ void foo(bool A1, bool A2, bool A3, bool A4) {
   // CHECK-FIXES: X = A1 && A2 && A3;
   // CHECK-FIXES-NEXT: X = A1 || (A2 && A3);
   // CHECK-FIXES-NEXT: X = A1 && (A2 || A3);
+
+  struct T {
+    bool operator==(const T&) const;
+    bool operator<(const T&) const;
+  };
+  T T1, T2;
+  X = !(T1 == T2 && A1 == A2);
+  X = !(T1 < T2 || (A1 || !A2));
+  // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: boolean expression can be simplified by DeMorgan's theorem
+  // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: boolean expression can be simplified by DeMorgan's theorem
+  // CHECK-FIXES: X = T1 != T2 || A1 != A2;
+  // CHECK-FIXES-NEXT: X = T1 >= T2 && !A1 && A2;
 }

@llvmbot
Copy link
Member

llvmbot commented Oct 19, 2025

@llvm/pr-subscribers-clang-tidy

Author: None (jlallas384)

Changes

This doesn't check whether the negated operator is defined, following the same behavior in other parts of the code that deal with overloaded operators.

Fixes #163128


Full diff: https://github.com/llvm/llvm-project/pull/164141.diff

2 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.cpp (+62-31)
  • (modified) clang-tools-extra/test/clang-tidy/checkers/readability/simplify-boolean-expr-demorgan.cpp (+12)
diff --git a/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.cpp b/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.cpp
index 4184c295b5f0a..4cea2b5030f42 100644
--- a/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.cpp
@@ -809,14 +809,14 @@ void SimplifyBooleanExprCheck::replaceWithAssignment(const ASTContext &Context,
             Range, Replacement);
 }
 
-/// Swaps a \c BinaryOperator opcode from `&&` to `||` or vice-versa.
+/// Swaps \p BO from `&&` to `||` or vice-versa.
 static bool flipDemorganOperator(llvm::SmallVectorImpl<FixItHint> &Output,
-                                 const BinaryOperator *BO) {
-  assert(BO->isLogicalOp());
-  if (BO->getOperatorLoc().isMacroID())
+                                 BinaryOperatorKind BO, SourceLocation BOLoc) {
+  assert(BinaryOperator::isLogicalOp(BO));
+  if (BOLoc.isMacroID())
     return true;
-  Output.push_back(FixItHint::CreateReplacement(
-      BO->getOperatorLoc(), BO->getOpcode() == BO_LAnd ? "||" : "&&"));
+  Output.push_back(
+      FixItHint::CreateReplacement(BOLoc, BO == BO_LAnd ? "||" : "&&"));
   return false;
 }
 
@@ -829,22 +829,22 @@ static bool flipDemorganSide(SmallVectorImpl<FixItHint> &Fixes,
                              const ASTContext &Ctx, const Expr *E,
                              std::optional<BinaryOperatorKind> OuterBO);
 
-/// Inverts \p BinOp, Removing \p Parens if they exist and are safe to remove.
-/// returns \c true if there is any issue building the Fixes, \c false
-/// otherwise.
-static bool
-flipDemorganBinaryOperator(SmallVectorImpl<FixItHint> &Fixes,
-                           const ASTContext &Ctx, const BinaryOperator *BinOp,
-                           std::optional<BinaryOperatorKind> OuterBO,
-                           const ParenExpr *Parens = nullptr) {
-  switch (BinOp->getOpcode()) {
+/// Inverts \p BO, \p LHS, and \p RHS, Removing \p Parens if they exist and are
+/// safe to remove. returns \c true if there is any issue building the Fixes, \c
+/// false otherwise.
+static bool flipDemorganBinaryOperator(
+    SmallVectorImpl<FixItHint> &Fixes, const ASTContext &Ctx,
+    BinaryOperatorKind BO, const Expr *LHS, const Expr *RHS, SourceRange Range,
+    SourceLocation BOLoc, std::optional<BinaryOperatorKind> OuterBO,
+    const ParenExpr *Parens = nullptr) {
+  switch (BO) {
   case BO_LAnd:
   case BO_LOr: {
     // if we have 'a && b' or 'a || b', use demorgan to flip it to '!a || !b'
     // or '!a && !b'.
-    if (flipDemorganOperator(Fixes, BinOp))
+    if (flipDemorganOperator(Fixes, BO, BOLoc))
       return true;
-    auto NewOp = getDemorganFlippedOperator(BinOp->getOpcode());
+    auto NewOp = getDemorganFlippedOperator(BO);
     if (OuterBO) {
       // The inner parens are technically needed in a fix for
       // `!(!A1 && !(A2 || A3)) -> (A1 || (A2 && A3))`,
@@ -862,16 +862,15 @@ flipDemorganBinaryOperator(SmallVectorImpl<FixItHint> &Fixes,
         }
       }
       if (*OuterBO == BO_LAnd && NewOp == BO_LOr && !Parens) {
-        Fixes.push_back(FixItHint::CreateInsertion(BinOp->getBeginLoc(), "("));
+        Fixes.push_back(FixItHint::CreateInsertion(Range.getBegin(), "("));
         Fixes.push_back(FixItHint::CreateInsertion(
-            Lexer::getLocForEndOfToken(BinOp->getEndLoc(), 0,
-                                       Ctx.getSourceManager(),
-                                       Ctx.getLangOpts()),
+            Lexer::getLocForEndOfToken(
+                Range.getEnd(), 0, Ctx.getSourceManager(), Ctx.getLangOpts()),
             ")"));
       }
     }
-    if (flipDemorganSide(Fixes, Ctx, BinOp->getLHS(), NewOp) ||
-        flipDemorganSide(Fixes, Ctx, BinOp->getRHS(), NewOp))
+    if (flipDemorganSide(Fixes, Ctx, LHS, NewOp) ||
+        flipDemorganSide(Fixes, Ctx, RHS, NewOp))
       return true;
     return false;
   };
@@ -882,12 +881,11 @@ flipDemorganBinaryOperator(SmallVectorImpl<FixItHint> &Fixes,
   case BO_EQ:
   case BO_NE:
     // For comparison operators, just negate the comparison.
-    if (BinOp->getOperatorLoc().isMacroID())
+    if (BOLoc.isMacroID())
       return true;
     Fixes.push_back(FixItHint::CreateReplacement(
-        BinOp->getOperatorLoc(),
-        BinaryOperator::getOpcodeStr(
-            BinaryOperator::negateComparisonOp(BinOp->getOpcode()))));
+        BOLoc,
+        BinaryOperator::getOpcodeStr(BinaryOperator::negateComparisonOp(BO))));
     return false;
   default:
     // for any other binary operator, just use logical not and wrap in
@@ -897,11 +895,11 @@ flipDemorganBinaryOperator(SmallVectorImpl<FixItHint> &Fixes,
         return true;
       Fixes.push_back(FixItHint::CreateInsertion(Parens->getBeginLoc(), "!"));
     } else {
-      if (BinOp->getBeginLoc().isMacroID() || BinOp->getEndLoc().isMacroID())
+      if (Range.getBegin().isMacroID() || Range.getEnd().isMacroID())
         return true;
-      Fixes.append({FixItHint::CreateInsertion(BinOp->getBeginLoc(), "!("),
+      Fixes.append({FixItHint::CreateInsertion(Range.getBegin(), "!("),
                     FixItHint::CreateInsertion(
-                        Lexer::getLocForEndOfToken(BinOp->getEndLoc(), 0,
+                        Lexer::getLocForEndOfToken(Range.getEnd(), 0,
                                                    Ctx.getSourceManager(),
                                                    Ctx.getLangOpts()),
                         ")")});
@@ -911,6 +909,28 @@ flipDemorganBinaryOperator(SmallVectorImpl<FixItHint> &Fixes,
   return false;
 }
 
+static bool
+flipDemorganBinaryOperator(SmallVectorImpl<FixItHint> &Fixes,
+                           const ASTContext &Ctx, const BinaryOperator *BinOp,
+                           std::optional<BinaryOperatorKind> OuterBO,
+                           const ParenExpr *Parens = nullptr) {
+  return flipDemorganBinaryOperator(
+      Fixes, Ctx, BinOp->getOpcode(), BinOp->getLHS(), BinOp->getRHS(),
+      BinOp->getSourceRange(), BinOp->getOperatorLoc(), OuterBO, Parens);
+}
+
+static bool
+flipDemorganOverloadedBinaryOperator(SmallVectorImpl<FixItHint> &Fixes,
+                                     const ASTContext &Ctx,
+                                     const CXXOperatorCallExpr *OpCall,
+                                     std::optional<BinaryOperatorKind> OuterBO,
+                                     const ParenExpr *Parens = nullptr) {
+  auto BO = BinaryOperator::getOverloadedOpcode(OpCall->getOperator());
+  return flipDemorganBinaryOperator(Fixes, Ctx, BO, OpCall->getArg(0),
+                                    OpCall->getArg(1), OpCall->getSourceRange(),
+                                    OpCall->getOperatorLoc(), OuterBO, Parens);
+}
+
 static bool flipDemorganSide(SmallVectorImpl<FixItHint> &Fixes,
                              const ASTContext &Ctx, const Expr *E,
                              std::optional<BinaryOperatorKind> OuterBO) {
@@ -930,6 +950,17 @@ static bool flipDemorganSide(SmallVectorImpl<FixItHint> &Fixes,
       return flipDemorganBinaryOperator(Fixes, Ctx, BinOp, OuterBO, Paren);
     }
   }
+  if (const auto *OpCall = dyn_cast<CXXOperatorCallExpr>(E);
+      OpCall && OpCall->isInfixBinaryOp()) {
+    return flipDemorganOverloadedBinaryOperator(Fixes, Ctx, OpCall, OuterBO);
+  }
+  if (const auto *Paren = dyn_cast<ParenExpr>(E)) {
+    if (const auto *OpCall = dyn_cast<CXXOperatorCallExpr>(E);
+        OpCall && OpCall->isInfixBinaryOp()) {
+      return flipDemorganOverloadedBinaryOperator(Fixes, Ctx, OpCall, OuterBO,
+                                                  Paren);
+    }
+  }
   // Fallback case just insert a logical not operator.
   if (E->getBeginLoc().isMacroID())
     return true;
@@ -991,7 +1022,7 @@ bool SimplifyBooleanExprCheck::reportDeMorgan(const ASTContext &Context,
   } else {
     Fixes.push_back(FixItHint::CreateRemoval(Outer->getOperatorLoc()));
   }
-  if (flipDemorganOperator(Fixes, Inner))
+  if (flipDemorganOperator(Fixes, Inner->getOpcode(), Inner->getOperatorLoc()))
     return false;
   if (flipDemorganSide(Fixes, Context, Inner->getLHS(), NewOpcode) ||
       flipDemorganSide(Fixes, Context, Inner->getRHS(), NewOpcode))
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/simplify-boolean-expr-demorgan.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/simplify-boolean-expr-demorgan.cpp
index bab9e17a7775b..b70ea72610b16 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/simplify-boolean-expr-demorgan.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/simplify-boolean-expr-demorgan.cpp
@@ -105,4 +105,16 @@ void foo(bool A1, bool A2, bool A3, bool A4) {
   // CHECK-FIXES: X = A1 && A2 && A3;
   // CHECK-FIXES-NEXT: X = A1 || (A2 && A3);
   // CHECK-FIXES-NEXT: X = A1 && (A2 || A3);
+
+  struct T {
+    bool operator==(const T&) const;
+    bool operator<(const T&) const;
+  };
+  T T1, T2;
+  X = !(T1 == T2 && A1 == A2);
+  X = !(T1 < T2 || (A1 || !A2));
+  // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: boolean expression can be simplified by DeMorgan's theorem
+  // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: boolean expression can be simplified by DeMorgan's theorem
+  // CHECK-FIXES: X = T1 != T2 || A1 != A2;
+  // CHECK-FIXES-NEXT: X = T1 >= T2 && !A1 && A2;
 }

Copy link
Contributor

@zwuis zwuis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your patch! Please add a release note entry to "clang-tools-extra/docs/ReleaseNotes.rst".

…y-simplify-boolean-expr' check

This doesn't check whether the negated operator is defined, following the
same behavior in other parts of the code that deal with overloaded
operators.

Fixes llvm#163128
Copy link
Contributor

@HerrCai0907 HerrCai0907 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For operator== LGTM.
For operator>, <=, that is not true, when then overloaded operation provide the partial order sema, when the check will cause the wrong result.
e.g.

#include <compare>
#include <iostream>

struct A {
  int v;
  bool isValid;
  std::partial_ordering operator<=>(const A &other) const {
    if (!isValid || !other.isValid) {
      return std::partial_ordering::unordered;
    }
    if (v < other.v) {
      return std::partial_ordering::less;
    } else if (v > other.v) {
      return std::partial_ordering::greater;
    } else {
      return std::partial_ordering::equivalent;
    }
  }
};

int main() {
  A a{5, true};
  A b{0, false};

  std::cout << "a > b: " << (a > b) << std::endl;
  std::cout << "a <= b: " << (a <= b) << std::endl;
  return 0;
}

The result will be

a > b: 0
a <= b: 0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[clang-tidy] Incorrect suggestion for readability-simplify-boolean-expr

5 participants