-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[Clang] Force expressions with UO_Not to not be non-negative #126846
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-clang Author: Yutong Zhu (YutongZhuu) ChangesFix to issue #18878 This PR issues the bug of not throwing warning for the following code: 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. Full diff: https://git.1-hub.cnllvm/llvm-project/pull/126846.diff 3 Files Affected:
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}}
+}
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
099a872
to
dd3f28f
Compare
dd3f28f
to
44673eb
Compare
44673eb
to
d740402
Compare
d6d2e4d
to
3dfac14
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code side of this looks good to me, but I think we should have more tests to make sure we're doing the right thing in the various corner cases (unsigned operations, negation of the most-negative value, etc).
Added, are there anything else you would like add? |
We should have some tests that check we're properly computing the bool f(int n) {
// Should not warn. (Does warn with trunk.)
return -(n & 15) <= -15;
}
bool g(int n) {
// Should continue to warn.
return -(n & 15) <= -17;
} (The -16 case would ideally warn, but because we're only tracking active bits and not ranges, we can't tell that.) Similarly: bool f(short n) {
// Should not warn, currently does.
return -n == 32768;
}
bool g(short n) {
// Should continue to warn.
return -n == 65536;
} (And again, cases between these two would ideally warn, but won't.) And analogous cases for |
Added more tests, thanks for your patience! |
749881a
to
bb3dea2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great, thanks!
Sorry, I accidentally requested for a review. Did not mean it. |
@YutongZhuu Will you need someone to merge this for you? |
Hi, I think this broke two of our buildbots -- for reasons I don't quite understand, but reverting fixed the issue locally. https://lab.llvm.org/buildbot/#/builders/10/builds/980 |
I realized that |
This fixes a build issue on the AMDGPU libc bot after llvm#126846 landed that introduced a warning.
This fixes a build issue on the AMDGPU libc bot after #126846 landed that introduced a warning. --------- Co-authored-by: Joseph Huber <huberjn@outlook.com>
Those two instanced were also flagged with a warning after llvm#126846 landed. I believe using type T here makes sense, but I can very well be wrong.
This fixes a build issue on the AMDGPU libc bot after llvm/llvm-project#126846 landed that introduced a warning. --------- Co-authored-by: Joseph Huber <huberjn@outlook.com>
This had the side effect of adding implicit-int-conversion warnings on e.g. the following code:
This seems correct, but this should probably be highlighted in the release notes. Another example is:
|
Hi, could you edit the release note for me? I don't have write access, so I would have to submit a PR to do so. I don't think a PR with changes only in the release notes is a great idea. |
Once you're merged there is no way to edit the release note other than a PR. So whether or not it is a great idea, it is the only way to go :) Please submit a PR to update it and we can all review the wording |
This fixes a build issue on the AMDGPU libc bot after llvm#126846 landed that introduced a warning. --------- Co-authored-by: Joseph Huber <huberjn@outlook.com>
I think this change might went too far. We are seeing this check flagging code like this:
While technically this is an implicit int conversion, as '-' promote value of 'shift' from |
I agree, I will look into this :) |
The warning being produced is a That said, it looks strange that this warns: int8_t n = ...;
n = -n; but this does not: int8_t n = ...;
n = n + 1; Both have the property that the right-hand side is sometimes 128, and if so, it gets implicitly wrapped to |
128 for int8_t is a valid point. Thanks for pointing that out.
As you can see, gcc doesn't generate warnings for the cases I raised. Only the |
Yeah, that's probably right. Maybe for |
Hm. That change will reintroduce a false positive warning for: bool b(signed char c) {
return -c >= 128;
} ... that this patch fixed. But we don't produce a false positive for |
Could you help me understand why clang is emitting the warning? Isn't it semantically equivalent to the following code?
|
I don't think I can fix the problem without re-introducing the false positive in unsigned char b = -a has a implCast to unsigned char right before the unary operator but the false positive case does not. By the time that the expression is passed into |
Fix to issue #18878
This PR addresses the bug of not throwing warning for the following code:
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.
Edit: I was able to find a fix for the UO_Minus operation and included the fix in this PR too.