[clang] Force expressions with UO_Not to not be non-negative (PR #126846)

Yutong Zhu via cfe-commits cfe-commits at lists.llvm.org
Tue Feb 11 19:56:39 PST 2025


https://github.com/YutongZhuu created https://github.com/llvm/llvm-project/pull/126846

Fix to issue #18878

This PR issues the bug of not throwing warning for the following code:
```c++
int test13(unsigned a, int *b) {
        return a > ~(95 != *b); // expected-warning {{comparison of integers of different signs}}
}
```

However, in the original issue, a comment mentioned that negation, pre-increment, and pre-decrement operators are also incorrect in this case. For negation, I am not able to implement a trivial fix without failing other tests, I will research further and submit another PR for that if necessary. For pre-increment, and pre-decrement, I don't think any fixes are required since errors will be triggered if that is the case.

>From e660f4070dbc11ffcf8d333f9f79516c4d2f32f9 Mon Sep 17 00:00:00 2001
From: Yutong Zhu <y25zhu at uwaterloo.ca>
Date: Tue, 11 Feb 2025 22:49:40 -0500
Subject: [PATCH] Force expressions with UO_Not to not be non-negative

---
 clang/docs/ReleaseNotes.rst     |  2 ++
 clang/lib/Sema/SemaChecking.cpp | 14 +++++++++++++-
 clang/test/Sema/compare.c       |  5 +++++
 3 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 6344c4b36e357..e8aeaa6e514e4 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -135,6 +135,8 @@ Improvements to Clang's diagnostics
 - Fixed a bug where Clang's Analysis did not correctly model the destructor behavior of ``union`` members (#GH119415).
 - A statement attribute applied to a ``case`` label no longer suppresses
   'bypassing variable initialization' diagnostics (#84072).
+- The ``-Wsign-compare`` warning now treats expressions with bitwise NOT(~) as signed integers 
+  and throws warning if they are compared with unsigned integers (##18878).
 
 Improvements to Clang's time-trace
 ----------------------------------
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 66c233de4ef30..37da477637c00 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -10069,6 +10069,16 @@ static std::optional<IntRange> TryGetExprRange(ASTContext &C, const Expr *E,
     case UO_AddrOf: // should be impossible
       return IntRange::forValueOfType(C, GetExprType(E));
 
+    case UO_Not:{
+      std::optional<IntRange> SubRange = TryGetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext,
+                             Approximate);
+      if (!SubRange) 
+        return std::nullopt;
+      
+      // The width increments by 1 if the sub-expression cannot be negative since it now can be.
+      return IntRange(SubRange->Width + (int)SubRange->NonNegative, false);
+    }
+    
     default:
       return TryGetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext,
                              Approximate);
@@ -10543,6 +10553,8 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) {
   // Check to see if one of the (unmodified) operands is of different
   // signedness.
   Expr *signedOperand, *unsignedOperand;
+  llvm::outs() << LHS->getType()->hasSignedIntegerRepresentation() << "\n";
+  llvm::outs() << RHS->getType()->hasSignedIntegerRepresentation() << "\n";
   if (LHS->getType()->hasSignedIntegerRepresentation()) {
     assert(!RHS->getType()->hasSignedIntegerRepresentation() &&
            "unsigned comparison between two signed integer expressions?");
@@ -10561,7 +10573,7 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) {
                       /*Approximate=*/true);
   if (!signedRange)
     return;
-
+  llvm::outs() << signedRange->NonNegative << "\n";
   // Go ahead and analyze implicit conversions in the operands.  Note
   // that we skip the implicit conversions on both sides.
   AnalyzeImplicitConversions(S, LHS, E->getOperatorLoc());
diff --git a/clang/test/Sema/compare.c b/clang/test/Sema/compare.c
index 17cf0351ef4f5..7abd6fb35976c 100644
--- a/clang/test/Sema/compare.c
+++ b/clang/test/Sema/compare.c
@@ -419,3 +419,8 @@ void pr36008(enum PR36008EnumTest lhs) {
   if (x == y) x = y; // no warning
   if (y == x) y = x; // no warning
 }
+
+
+int test13(unsigned a, int *b) {
+        return a > ~(95 != *b); // expected-warning {{comparison of integers of different signs}}
+}



More information about the cfe-commits mailing list