[Clang] Force expressions with UO_Not to not be non-negative (#126846)
This PR addresses the bug of not throwing warnings 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.
Fixes #18878
This commit is contained in:
@@ -238,6 +238,9 @@ Improvements to Clang's diagnostics
|
||||
as function arguments or return value respectively. Note that
|
||||
:doc:`ThreadSafetyAnalysis` still does not perform alias analysis. The
|
||||
feature will be default-enabled with ``-Wthread-safety`` in a future release.
|
||||
- The ``-Wsign-compare`` warning now treats expressions with bitwise not(~) and minus(-) as signed integers
|
||||
except for the case where the operand is an unsigned integer
|
||||
and throws warning if they are compared with unsigned integers (##18878).
|
||||
|
||||
- Improve the diagnostics for chained comparisons to report actual expressions and operators (#GH129069).
|
||||
|
||||
|
||||
@@ -10620,6 +10620,42 @@ static std::optional<IntRange> TryGetExprRange(ASTContext &C, const Expr *E,
|
||||
case UO_AddrOf: // should be impossible
|
||||
return IntRange::forValueOfType(C, GetExprType(E));
|
||||
|
||||
case UO_Minus: {
|
||||
if (E->getType()->isUnsignedIntegerType()) {
|
||||
return TryGetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext,
|
||||
Approximate);
|
||||
}
|
||||
|
||||
std::optional<IntRange> SubRange = TryGetExprRange(
|
||||
C, UO->getSubExpr(), MaxWidth, InConstantContext, Approximate);
|
||||
|
||||
if (!SubRange)
|
||||
return std::nullopt;
|
||||
|
||||
// If the range was previously non-negative, we need an extra bit for the
|
||||
// sign bit. If the range was not non-negative, we need an extra bit
|
||||
// because the negation of the most-negative value is one bit wider than
|
||||
// that value.
|
||||
return IntRange(SubRange->Width + 1, false);
|
||||
}
|
||||
|
||||
case UO_Not: {
|
||||
if (E->getType()->isUnsignedIntegerType()) {
|
||||
return TryGetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext,
|
||||
Approximate);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -pedantic -verify -Wsign-compare -Wtautological-constant-in-range-compare %s -Wno-unreachable-code
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -pedantic -verify -Wsign-compare -Wtype-limits %s -Wno-unreachable-code
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -pedantic -verify -Wsign-compare -Wtautological-constant-in-range-compare %s -Wno-unreachable-code -DTEST=1
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -pedantic -verify -Wsign-compare -Wtype-limits %s -Wno-unreachable-code -DTEST=2
|
||||
|
||||
int test(char *C) { // nothing here should warn.
|
||||
return C != ((void*)0);
|
||||
@@ -419,3 +419,65 @@ 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}}
|
||||
}
|
||||
|
||||
int test14(unsigned a, unsigned b) {
|
||||
return a > ~b; // no-warning
|
||||
}
|
||||
|
||||
int test15(unsigned a, int b) {
|
||||
return a > -(95 != b); // expected-warning {{comparison of integers of different signs}}
|
||||
}
|
||||
|
||||
int test16(unsigned a, unsigned b) {
|
||||
return a > -b; // no-warning
|
||||
}
|
||||
|
||||
int test17(int a, unsigned b) {
|
||||
return a > -(-b); // expected-warning {{comparison of integers of different signs}}
|
||||
}
|
||||
|
||||
int test18(int a) {
|
||||
return a == -(-2147483648); // expected-warning {{result of comparison of constant 2147483648 with expression of type 'int' is always false}}
|
||||
}
|
||||
|
||||
int test19(int n) {
|
||||
return -(n & 15) <= -15; // no-warning
|
||||
}
|
||||
|
||||
#if TEST == 1
|
||||
int test20(int n) {
|
||||
return -(n & 15) <= -17; // expected-warning {{result of comparison of 5-bit signed value <= -17 is always false}}
|
||||
}
|
||||
#endif
|
||||
|
||||
int test21(short n) {
|
||||
return -n == 32768; // no-warning
|
||||
}
|
||||
|
||||
#if TEST == 1
|
||||
int test22(short n) {
|
||||
return -n == 65536; // expected-warning {{result of comparison of 17-bit signed value == 65536 is always false}}
|
||||
}
|
||||
#endif
|
||||
|
||||
int test23(unsigned short n) {
|
||||
return ~n == 32768; // no-warning
|
||||
}
|
||||
|
||||
int test24(short n) {
|
||||
return ~n == 32767; // no-warning
|
||||
}
|
||||
|
||||
#if TEST == 1
|
||||
int test25(unsigned short n) {
|
||||
return ~n == 65536; // expected-warning {{result of comparison of 17-bit signed value == 65536 is always false}}
|
||||
}
|
||||
|
||||
int test26(short n) {
|
||||
return ~n == 32768; // expected-warning {{result of comparison of 16-bit signed value == 32768 is always false}}
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user