https://github.com/YutongZhuu updated 
https://github.com/llvm/llvm-project/pull/133653

>From ca795c3f27e37ad8a8f165a3b10e9415cbfd66a5 Mon Sep 17 00:00:00 2001
From: Yutong Zhu <y25...@uwaterloo.ca>
Date: Sat, 12 Apr 2025 15:32:46 -0400
Subject: [PATCH 1/2] Improved the -Wtautological-overlap-compare diagnostics
 to warn about overlapping and non-overlapping ranges involving character
 literals and floating-point literals.

---
 clang/docs/ReleaseNotes.rst                   |   3 +
 .../clang/Basic/DiagnosticSemaKinds.td        |   2 +-
 clang/lib/Analysis/CFG.cpp                    | 179 +++++++++++-------
 clang/lib/Sema/AnalysisBasedWarnings.cpp      |   5 +-
 clang/test/Sema/warn-overlap.c                | 119 ++++++++++--
 5 files changed, 211 insertions(+), 97 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 11f62bc881b03..de5c877cf996b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -352,6 +352,9 @@ Improvements to Clang's diagnostics
 - Now correctly diagnose a tentative definition of an array with static
   storage duration in pedantic mode in C. (#GH50661)
 
+- Improved the ``-Wtautological-overlap-compare`` diagnostics to warn about 
overlapping and non-overlapping ranges involving character literals and 
floating-point literals. 
+  The warning message for non-overlapping cases has also been improved 
(#GH13473).
+  
 Improvements to Clang's time-trace
 ----------------------------------
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 180ca39bc07e9..c8b5c94676d18 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10356,7 +10356,7 @@ def warn_tautological_negation_or_compare: Warning<
   "'||' of a value and its negation always evaluates to true">,
   InGroup<TautologicalNegationCompare>, DefaultIgnore;
 def warn_tautological_overlap_comparison : Warning<
-  "overlapping comparisons always evaluate to %select{false|true}0">,
+  "%select{non-|}0overlapping comparisons always evaluate to 
%select{false|true}0">,
   InGroup<TautologicalOverlapCompare>, DefaultIgnore;
 def warn_depr_array_comparison : Warning<
   "comparison between two arrays is deprecated; "
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index 9af1e915482da..ec7c1fbfc423a 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -70,19 +70,18 @@ static SourceLocation GetEndLoc(Decl *D) {
   return D->getLocation();
 }
 
-/// Returns true on constant values based around a single IntegerLiteral.
-/// Allow for use of parentheses, integer casts, and negative signs.
-/// FIXME: it would be good to unify this function with
-/// getIntegerLiteralSubexpressionValue at some point given the similarity
-/// between the functions.
+/// Returns true on constant values based around a single IntegerLiteral,
+/// CharacterLiteral, or FloatingLiteral. Allow for use of parentheses, integer
+/// casts, and negative signs.
 
-static bool IsIntegerLiteralConstantExpr(const Expr *E) {
+static bool IsLiteralConstantExpr(const Expr *E) {
   // Allow parentheses
   E = E->IgnoreParens();
 
   // Allow conversions to different integer kind.
   if (const auto *CE = dyn_cast<CastExpr>(E)) {
-    if (CE->getCastKind() != CK_IntegralCast)
+    if (CE->getCastKind() != CK_IntegralCast &&
+        CE->getCastKind() != CK_IntegralToFloating)
       return false;
     E = CE->getSubExpr();
   }
@@ -93,16 +92,16 @@ static bool IsIntegerLiteralConstantExpr(const Expr *E) {
       return false;
     E = UO->getSubExpr();
   }
-
-  return isa<IntegerLiteral>(E);
+  return isa<IntegerLiteral>(E) || isa<CharacterLiteral>(E) ||
+         isa<FloatingLiteral>(E);
 }
 
 /// Helper for tryNormalizeBinaryOperator. Attempts to extract an 
IntegerLiteral
-/// constant expression or EnumConstantDecl from the given Expr. If it fails,
-/// returns nullptr.
-static const Expr *tryTransformToIntOrEnumConstant(const Expr *E) {
+/// FloatingLiteral, CharacterLiteral or EnumConstantDecl from the given Expr.
+/// If it fails, returns nullptr.
+static const Expr *tryTransformToLiteralConstant(const Expr *E) {
   E = E->IgnoreParens();
-  if (IsIntegerLiteralConstantExpr(E))
+  if (IsLiteralConstantExpr(E))
     return E;
   if (auto *DR = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
     return isa<EnumConstantDecl>(DR->getDecl()) ? DR : nullptr;
@@ -119,7 +118,7 @@ tryNormalizeBinaryOperator(const BinaryOperator *B) {
   BinaryOperatorKind Op = B->getOpcode();
 
   const Expr *MaybeDecl = B->getLHS();
-  const Expr *Constant = tryTransformToIntOrEnumConstant(B->getRHS());
+  const Expr *Constant = tryTransformToLiteralConstant(B->getRHS());
   // Expr looked like `0 == Foo` instead of `Foo == 0`
   if (Constant == nullptr) {
     // Flip the operator
@@ -133,7 +132,7 @@ tryNormalizeBinaryOperator(const BinaryOperator *B) {
       Op = BO_GE;
 
     MaybeDecl = B->getRHS();
-    Constant = tryTransformToIntOrEnumConstant(B->getLHS());
+    Constant = tryTransformToLiteralConstant(B->getLHS());
   }
 
   return std::make_tuple(MaybeDecl, Op, Constant);
@@ -1082,10 +1081,10 @@ class CFGBuilder {
     return std::nullopt;
   }
 
+  template <typename APFloatOrInt>
   TryResult analyzeLogicOperatorCondition(BinaryOperatorKind Relation,
-                                          const llvm::APSInt &Value1,
-                                          const llvm::APSInt &Value2) {
-    assert(Value1.isSigned() == Value2.isSigned());
+                                          const APFloatOrInt &Value1,
+                                          const APFloatOrInt &Value2) {
     switch (Relation) {
       default:
         return TryResult();
@@ -1170,82 +1169,116 @@ class CFGBuilder {
     if (!areExprTypesCompatible(NumExpr1, NumExpr2))
       return {};
 
+    // Check that the two expressions are of the same type.
     Expr::EvalResult L1Result, L2Result;
-    if (!NumExpr1->EvaluateAsInt(L1Result, *Context) ||
-        !NumExpr2->EvaluateAsInt(L2Result, *Context))
-      return {};
-
-    llvm::APSInt L1 = L1Result.Val.getInt();
-    llvm::APSInt L2 = L2Result.Val.getInt();
-
-    // Can't compare signed with unsigned or with different bit width.
-    if (L1.isSigned() != L2.isSigned() || L1.getBitWidth() != L2.getBitWidth())
+    if (!NumExpr1->EvaluateAsRValue(L1Result, *Context) ||
+        !NumExpr2->EvaluateAsRValue(L2Result, *Context))
       return {};
 
-    // Values that will be used to determine if result of logical
-    // operator is always true/false
-    const llvm::APSInt Values[] = {
-      // Value less than both Value1 and Value2
-      llvm::APSInt::getMinValue(L1.getBitWidth(), L1.isUnsigned()),
-      // L1
-      L1,
-      // Value between Value1 and Value2
-      ((L1 < L2) ? L1 : L2) + llvm::APSInt(llvm::APInt(L1.getBitWidth(), 1),
-                              L1.isUnsigned()),
-      // L2
-      L2,
-      // Value greater than both Value1 and Value2
-      llvm::APSInt::getMaxValue(L1.getBitWidth(), L1.isUnsigned()),
-    };
-
-    // Check whether expression is always true/false by evaluating the 
following
+    // Check whether expression is always true/false by evaluating the
+    // following
     // * variable x is less than the smallest literal.
     // * variable x is equal to the smallest literal.
     // * Variable x is between smallest and largest literal.
     // * Variable x is equal to the largest literal.
     // * Variable x is greater than largest literal.
-    bool AlwaysTrue = true, AlwaysFalse = true;
-    // Track value of both subexpressions.  If either side is always
-    // true/false, another warning should have already been emitted.
-    bool LHSAlwaysTrue = true, LHSAlwaysFalse = true;
-    bool RHSAlwaysTrue = true, RHSAlwaysFalse = true;
-    for (const llvm::APSInt &Value : Values) {
-      TryResult Res1, Res2;
-      Res1 = analyzeLogicOperatorCondition(BO1, Value, L1);
-      Res2 = analyzeLogicOperatorCondition(BO2, Value, L2);
-
-      if (!Res1.isKnown() || !Res2.isKnown())
-        return {};
+    auto analyzeConditions = [&](const auto &Values,
+                                 const BinaryOperatorKind *BO1,
+                                 const BinaryOperatorKind *BO2) -> TryResult {
+      bool AlwaysTrue = true, AlwaysFalse = true;
+      // Track value of both subexpressions.  If either side is always
+      // true/false, another warning should have already been emitted.
+      bool LHSAlwaysTrue = true, LHSAlwaysFalse = true;
+      bool RHSAlwaysTrue = true, RHSAlwaysFalse = true;
+
+      for (const auto &Value : Values) {
+        TryResult Res1 =
+            analyzeLogicOperatorCondition(*BO1, Value, Values[1] /* L1 */);
+        TryResult Res2 =
+            analyzeLogicOperatorCondition(*BO2, Value, Values[3] /* L2 */);
+
+        if (!Res1.isKnown() || !Res2.isKnown())
+          return {};
+
+        const bool isAnd = B->getOpcode() == BO_LAnd;
+        const bool combine = isAnd ? (Res1.isTrue() && Res2.isTrue())
+                                   : (Res1.isTrue() || Res2.isTrue());
+
+        AlwaysTrue &= combine;
+        AlwaysFalse &= !combine;
+
+        LHSAlwaysTrue &= Res1.isTrue();
+        LHSAlwaysFalse &= Res1.isFalse();
+        RHSAlwaysTrue &= Res2.isTrue();
+        RHSAlwaysFalse &= Res2.isFalse();
+      }
 
-      if (B->getOpcode() == BO_LAnd) {
-        AlwaysTrue &= (Res1.isTrue() && Res2.isTrue());
-        AlwaysFalse &= !(Res1.isTrue() && Res2.isTrue());
-      } else {
-        AlwaysTrue &= (Res1.isTrue() || Res2.isTrue());
-        AlwaysFalse &= !(Res1.isTrue() || Res2.isTrue());
+      if (AlwaysTrue || AlwaysFalse) {
+        if (!LHSAlwaysTrue && !LHSAlwaysFalse && !RHSAlwaysTrue &&
+            !RHSAlwaysFalse && BuildOpts.Observer) {
+          BuildOpts.Observer->compareAlwaysTrue(B, AlwaysTrue);
+        }
+        return TryResult(AlwaysTrue);
       }
+      return {};
+    };
 
-      LHSAlwaysTrue &= Res1.isTrue();
-      LHSAlwaysFalse &= Res1.isFalse();
-      RHSAlwaysTrue &= Res2.isTrue();
-      RHSAlwaysFalse &= Res2.isFalse();
+    // Handle integer comparison
+    if (L1Result.Val.getKind() == APValue::Int &&
+        L2Result.Val.getKind() == APValue::Int) {
+      llvm::APSInt L1 = L1Result.Val.getInt();
+      llvm::APSInt L2 = L2Result.Val.getInt();
+
+      // Can't compare signed with unsigned or with different bit width.
+      if (L1.isSigned() != L2.isSigned() ||
+          L1.getBitWidth() != L2.getBitWidth())
+        return {};
+
+      // Values that will be used to determine if result of logical
+      // operator is always true/false
+      const llvm::APSInt Values[] = {
+          // Value less than both Value1 and Value2
+          llvm::APSInt::getMinValue(L1.getBitWidth(), L1.isUnsigned()),
+          // L1
+          L1,
+          // Value between Value1 and Value2
+          ((L1 < L2) ? L1 : L2) +
+              llvm::APSInt(llvm::APInt(L1.getBitWidth(), 1), L1.isUnsigned()),
+          // L2
+          L2,
+          // Value greater than both Value1 and Value2
+          llvm::APSInt::getMaxValue(L1.getBitWidth(), L1.isUnsigned()),
+      };
+
+      return analyzeConditions(Values, &BO1, &BO2);
     }
 
-    if (AlwaysTrue || AlwaysFalse) {
-      if (!LHSAlwaysTrue && !LHSAlwaysFalse && !RHSAlwaysTrue &&
-          !RHSAlwaysFalse && BuildOpts.Observer)
-        BuildOpts.Observer->compareAlwaysTrue(B, AlwaysTrue);
-      return TryResult(AlwaysTrue);
+    // Handle float comparison
+    if (L1Result.Val.getKind() == APValue::Float &&
+        L2Result.Val.getKind() == APValue::Float) {
+      llvm::APFloat L1 = L1Result.Val.getFloat();
+      llvm::APFloat L2 = L2Result.Val.getFloat();
+      llvm::APFloat MidValue = L1;
+      MidValue.add(L2, llvm::APFloat::rmNearestTiesToEven);
+      MidValue.divide(llvm::APFloat(2.0), llvm::APFloat::rmNearestTiesToEven);
+
+      const llvm::APFloat Values[] = {
+          llvm::APFloat::getSmallest(L1.getSemantics(), true), L1, MidValue, 
L2,
+          llvm::APFloat::getLargest(L2.getSemantics(), false),
+      };
+
+      return analyzeConditions(Values, &BO1, &BO2);
     }
+
     return {};
   }
 
   /// A bitwise-or with a non-zero constant always evaluates to true.
   TryResult checkIncorrectBitwiseOrOperator(const BinaryOperator *B) {
     const Expr *LHSConstant =
-        tryTransformToIntOrEnumConstant(B->getLHS()->IgnoreParenImpCasts());
+        tryTransformToLiteralConstant(B->getLHS()->IgnoreParenImpCasts());
     const Expr *RHSConstant =
-        tryTransformToIntOrEnumConstant(B->getRHS()->IgnoreParenImpCasts());
+        tryTransformToLiteralConstant(B->getRHS()->IgnoreParenImpCasts());
 
     if ((LHSConstant && RHSConstant) || (!LHSConstant && !RHSConstant))
       return {};
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp 
b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 38aa3f0edf718..9173758cb143e 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -166,13 +166,14 @@ class LogicalErrorHandler : public CFGCallback {
     S.Diag(B->getExprLoc(), DiagID) << DiagRange;
   }
 
-  void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) override {
+  void compareAlwaysTrue(const BinaryOperator *B,
+                         bool isAlwaysTrueOrFalse) override {
     if (HasMacroID(B))
       return;
 
     SourceRange DiagRange = B->getSourceRange();
     S.Diag(B->getExprLoc(), diag::warn_tautological_overlap_comparison)
-        << DiagRange << isAlwaysTrue;
+        << DiagRange << isAlwaysTrueOrFalse;
   }
 
   void compareBitwiseEquality(const BinaryOperator *B,
diff --git a/clang/test/Sema/warn-overlap.c b/clang/test/Sema/warn-overlap.c
index 2db07ebcd17b8..6b9ff65006cc4 100644
--- a/clang/test/Sema/warn-overlap.c
+++ b/clang/test/Sema/warn-overlap.c
@@ -37,37 +37,37 @@ void f(int x) {
   if (x >= 0 || x <= 0) { } // expected-warning {{overlapping comparisons 
always evaluate to true}}
 
   // > && <
-  if (x > 2 && x < 1) { }  // expected-warning {{overlapping comparisons 
always evaluate to false}}
-  if (x > 2 && x < 2) { }  // expected-warning {{overlapping comparisons 
always evaluate to false}}
-  if (x > 2 && x < 3) { }  // expected-warning {{overlapping comparisons 
always evaluate to false}}
-  if (x > 0 && x < 1) { }  // expected-warning {{overlapping comparisons 
always evaluate to false}}
+  if (x > 2 && x < 1) { }  // expected-warning {{non-overlapping comparisons 
always evaluate to false}}
+  if (x > 2 && x < 2) { }  // expected-warning {{non-overlapping comparisons 
always evaluate to false}}
+  if (x > 2 && x < 3) { }  // expected-warning {{non-overlapping comparisons 
always evaluate to false}}
+  if (x > 0 && x < 1) { }  // expected-warning {{non-overlapping comparisons 
always evaluate to false}}
 
-  if (x > 2 && x <= 1) { }  // expected-warning {{overlapping comparisons 
always evaluate to false}}
-  if (x > 2 && x <= 2) { }  // expected-warning {{overlapping comparisons 
always evaluate to false}}
+  if (x > 2 && x <= 1) { }  // expected-warning {{non-overlapping comparisons 
always evaluate to false}}
+  if (x > 2 && x <= 2) { }  // expected-warning {{non-overlapping comparisons 
always evaluate to false}}
   if (x > 2 && x <= 3) { }
 
-  if (x >= 2 && x < 1) { }  // expected-warning {{overlapping comparisons 
always evaluate to false}}
-  if (x >= 2 && x < 2) { }  // expected-warning {{overlapping comparisons 
always evaluate to false}}
+  if (x >= 2 && x < 1) { }  // expected-warning {{non-overlapping comparisons 
always evaluate to false}}
+  if (x >= 2 && x < 2) { }  // expected-warning {{non-overlapping comparisons 
always evaluate to false}}
   if (x >= 2 && x < 3) { }
-  if (x >= 0 && x < 0) { }  // expected-warning {{overlapping comparisons 
always evaluate to false}}
+  if (x >= 0 && x < 0) { }  // expected-warning {{non-overlapping comparisons 
always evaluate to false}}
 
-  if (x >= 2 && x <= 1) { }  // expected-warning {{overlapping comparisons 
always evaluate to false}}
+  if (x >= 2 && x <= 1) { }  // expected-warning {{non-overlapping comparisons 
always evaluate to false}}
   if (x >= 2 && x <= 2) { }
   if (x >= 2 && x <= 3) { }
 
   // !=, ==, ..
   if (x != 2 || x != 3) { }  // expected-warning {{overlapping comparisons 
always evaluate to true}}
   if (x != 2 || x < 3) { }   // expected-warning {{overlapping comparisons 
always evaluate to true}}
-  if (x == 2 && x == 3) { }  // expected-warning {{overlapping comparisons 
always evaluate to false}}
-  if (x == 2 && x > 3) { }   // expected-warning {{overlapping comparisons 
always evaluate to false}}
-  if (x == 3 && x < 0) { }  // expected-warning {{overlapping comparisons 
always evaluate to false}}
-  if (3 == x && x < 0) { }  // expected-warning {{overlapping comparisons 
always evaluate to false}}
+  if (x == 2 && x == 3) { }  // expected-warning {{non-overlapping comparisons 
always evaluate to false}}
+  if (x == 2 && x > 3) { }   // expected-warning {{non-overlapping comparisons 
always evaluate to false}}
+  if (x == 3 && x < 0) { }  // expected-warning {{non-overlapping comparisons 
always evaluate to false}}
+  if (3 == x && x < 0) { }  // expected-warning {{non-overlapping comparisons 
always evaluate to false}}
 
   if (x == mydefine && x > 3) { }
   if (x == (mydefine + 1) && x > 3) { }
 
   if (x != CHOICE_0 || x != CHOICE_1) { } // expected-warning {{overlapping 
comparisons always evaluate to true}}
-  if (x == CHOICE_0 && x == CHOICE_1) { } // expected-warning {{overlapping 
comparisons always evaluate to false}}
+  if (x == CHOICE_0 && x == CHOICE_1) { } // expected-warning 
{{non-overlapping comparisons always evaluate to false}}
 
   // Don't warn if comparing x to different types
   if (x == CHOICE_0 && x == 1) { }
@@ -80,7 +80,7 @@ void f(int x) {
 
 void enums(enum Choices c) {
   if (c != CHOICE_0 || c != CHOICE_1) { } // expected-warning {{overlapping 
comparisons always evaluate to true}}
-  if (c == CHOICE_0 && c == CHOICE_1) { } // expected-warning {{overlapping 
comparisons always evaluate to false}}
+  if (c == CHOICE_0 && c == CHOICE_1) { } // expected-warning 
{{non-overlapping comparisons always evaluate to false}}
 
   // Don't warn if comparing x to different types
   if (c == CHOICE_0 && c == 1) { }
@@ -117,12 +117,12 @@ void assignment(int x) {
   int a = x > 4 || x < 10;
   // expected-warning@-1{{overlapping comparisons always evaluate to true}}
   int b = x < 2 && x > 5;
-  // expected-warning@-1{{overlapping comparisons always evaluate to false}}
+  // expected-warning@-1{{non-overlapping comparisons always evaluate to 
false}}
 
   int c = x != 1 || x != 3;
   // expected-warning@-1{{overlapping comparisons always evaluate to true}}
   int d = x == 1 && x == 2;
-  // expected-warning@-1{{overlapping comparisons always evaluate to false}}
+  // expected-warning@-1{{non-overlapping comparisons always evaluate to 
false}}
 
   int e = x < 1 || x != 0;
   // expected-warning@-1{{overlapping comparisons always evaluate to true}}
@@ -132,12 +132,12 @@ int returns(int x) {
   return x > 4 || x < 10;
   // expected-warning@-1{{overlapping comparisons always evaluate to true}}
   return x < 2 && x > 5;
-  // expected-warning@-1{{overlapping comparisons always evaluate to false}}
+  // expected-warning@-1{{non-overlapping comparisons always evaluate to 
false}}
 
   return x != 1 || x != 3;
   // expected-warning@-1{{overlapping comparisons always evaluate to true}}
   return x == 1 && x == 2;
-  // expected-warning@-1{{overlapping comparisons always evaluate to false}}
+  // expected-warning@-1{{non-overlapping comparisons always evaluate to 
false}}
 
   return x < 1 || x != 0;
   // expected-warning@-1{{overlapping comparisons always evaluate to true}}
@@ -169,7 +169,84 @@ int struct_test(struct A a) {
   return a.x > 5 && a.y < 1;  // no warning, different variables
 
   return a.x > 5 && a.x < 1;
-  // expected-warning@-1{{overlapping comparisons always evaluate to false}}
+  // expected-warning@-1{{non-overlapping comparisons always evaluate to 
false}}
   return a.y == 1 || a.y != 1;
   // expected-warning@-1{{overlapping comparisons always evaluate to true}}
 }
+
+void char_tests(char c) {
+  if (c > 'a' || c < 'z') {}
+  // expected-warning@-1{{overlapping comparisons always evaluate to true}}
+  if (c > 'z' && c < 'a') {}
+  // expected-warning@-1{{non-overlapping comparisons always evaluate to 
false}}
+  if (c == 'a' && c == 'z') {}
+  // expected-warning@-1{{non-overlapping comparisons always evaluate to 
false}}
+  if (c != 'a' || c != 'z') {}
+  // expected-warning@-1{{overlapping comparisons always evaluate to true}}
+}
+
+void float_tests(float f) {
+  if (f > 1.0 || f < 2.0) {}
+  // expected-warning@-1{{overlapping comparisons always evaluate to true}}
+  if (f > 2.0 && f < 1.0) {}
+  // expected-warning@-1{{non-overlapping comparisons always evaluate to 
false}}
+  if (f == 1.0 && f == 2.0) {}
+  // expected-warning@-1{{non-overlapping comparisons always evaluate to 
false}}
+  if (f != 1.0 || f != 2.0) {}
+  // expected-warning@-1{{overlapping comparisons always evaluate to true}}
+}
+
+void double_tests(double d) {
+  if (d > 3.5 || d < 4.5) {}
+  // expected-warning@-1{{overlapping comparisons always evaluate to true}}
+  if (d > 4.5 && d < 3.5) {}
+  // expected-warning@-1{{non-overlapping comparisons always evaluate to 
false}}
+  if (d == 3.5 && d == 4.5) {}
+  // expected-warning@-1{{non-overlapping comparisons always evaluate to 
false}}
+  if (d != 3.5 || d != 4.5) {}
+  // expected-warning@-1{{overlapping comparisons always evaluate to true}}
+}
+
+void mixed_float_double_tests(float f, double d) {
+  if (f > 1.0 || d < 2.0) {}
+  // no warning, different types
+  if (f > 2.0 && d < 1.0) {}
+  // no warning, different types
+  if (f == 1.0 && d == 2.0) {}
+  // no warning, different types
+  if (f != 1.0 || d != 2.0) {}
+  // no warning, different types
+}
+
+void float_edge_cases(float f) {
+  if (f > 0.0 || f < 0.0) {}
+  // no-warning
+  if (f > 0.0 && f < 0.0) {}
+  // expected-warning@-1{{non-overlapping comparisons always evaluate to 
false}}}
+  if (f == 0.0 && f == -0.0) {}
+  // no-warning
+  if (f != 0.0 || f != -0.0) {}
+  // no warning
+}
+
+void double_edge_cases(double d) {
+  if (d > 0.0 || d < 0.0) {}
+  // no-warning
+  if (d > 0.0 && d < 0.0) {}
+  // expected-warning@-1{{non-overlapping comparisons always evaluate to 
false}}
+  if (d == 0.0 && d == -0.0) {}
+  // no warning
+  if (d != 0.0 || d != -0.0) {}
+  // no warning
+}
+
+void float_int_literal_tests(float f) {
+  if (f > 1 || f < 2) {}
+  // expected-warning@-1{{overlapping comparisons always evaluate to true}}
+  if (f > 2 && f < 1) {}
+  // expected-warning@-1{{non-overlapping comparisons always evaluate to 
false}}
+  if (f == 1 && f == 2) {}
+  // expected-warning@-1{{non-overlapping comparisons always evaluate to 
false}}
+  if (f != 1 || f != 2) {}
+  // expected-warning@-1{{overlapping comparisons always evaluate to true}}
+}

>From 21ff235f988dec97e4dedcee29b9c52fc1181b9a Mon Sep 17 00:00:00 2001
From: Yutong Zhu <y25...@uwaterloo.ca>
Date: Sat, 12 Apr 2025 17:12:13 -0400
Subject: [PATCH 2/2] Fix github test case failure

---
 clang/lib/Analysis/CFG.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index ec7c1fbfc423a..0a7cbdb70c4f6 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -36,6 +36,7 @@
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/Specifiers.h"
+#include "llvm/ADT/APFloat.h"
 #include "llvm/ADT/APInt.h"
 #include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/ArrayRef.h"
@@ -1260,7 +1261,7 @@ class CFGBuilder {
       llvm::APFloat L2 = L2Result.Val.getFloat();
       llvm::APFloat MidValue = L1;
       MidValue.add(L2, llvm::APFloat::rmNearestTiesToEven);
-      MidValue.divide(llvm::APFloat(2.0), llvm::APFloat::rmNearestTiesToEven);
+      MidValue.divide(llvm::APFloat(L1.getSemantics(), llvm::APInt(64, 2)), 
llvm::APFloat::rmNearestTiesToEven);
 
       const llvm::APFloat Values[] = {
           llvm::APFloat::getSmallest(L1.getSemantics(), true), L1, MidValue, 
L2,

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

Reply via email to