Skip to content

Commit 0cc3c18

Browse files
CodesbyusmanAaronBallman
authored andcommitted
Missing tautological compare warnings due to unary operators
The patch mainly focuses on the lack of warnings for -Wtautological-compare. It works fine for positive numbers but doesn't for negative numbers. This is because the warning explicitly checks for an IntegerLiteral AST node, but -1 is represented by a UnaryOperator with an IntegerLiteral sub-Expr. For the below code we have warnings: if (0 == (5 | x)) {} but not for if (0 == (-5 | x)) {} This patch changes the analysis to not look at the AST node directly to see if it is an IntegerLiteral, but instead attempts to evaluate the expression to see if it is an integer constant expression. This handles unary negation signs, but also handles all the other possible operators as well. Fixes #42918 Differential Revision: https://reviews.llvm.org/D130510
1 parent 955cc56 commit 0cc3c18

File tree

4 files changed

+72
-27
lines changed

4 files changed

+72
-27
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ Major New Features
4949

5050
Bug Fixes
5151
---------
52+
- ``-Wtautological-compare`` missed warnings for tautological comparisons
53+
involving a negative integer literal. This fixes
54+
`Issue 42918 <https://github.com/llvm/llvm-project/issues/42918>`_.
55+
5256

5357
Improvements to Clang's diagnostics
5458
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Analysis/CFG.cpp

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -964,43 +964,44 @@ class CFGBuilder {
964964
const Expr *LHSExpr = B->getLHS()->IgnoreParens();
965965
const Expr *RHSExpr = B->getRHS()->IgnoreParens();
966966

967-
const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(LHSExpr);
968-
const Expr *BoolExpr = RHSExpr;
967+
const Expr *BoolExpr = nullptr; // To store the expression.
968+
Expr::EvalResult IntExprResult; // If integer literal then will save value.
969969

970-
if (!IntLiteral) {
971-
IntLiteral = dyn_cast<IntegerLiteral>(RHSExpr);
970+
if (LHSExpr->EvaluateAsInt(IntExprResult, *Context))
971+
BoolExpr = RHSExpr;
972+
else if (RHSExpr->EvaluateAsInt(IntExprResult, *Context))
972973
BoolExpr = LHSExpr;
973-
}
974-
975-
if (!IntLiteral)
974+
else
976975
return TryResult();
977976

977+
llvm::APInt L1 = IntExprResult.Val.getInt();
978+
978979
const BinaryOperator *BitOp = dyn_cast<BinaryOperator>(BoolExpr);
979-
if (BitOp && (BitOp->getOpcode() == BO_And ||
980-
BitOp->getOpcode() == BO_Or)) {
981-
const Expr *LHSExpr2 = BitOp->getLHS()->IgnoreParens();
982-
const Expr *RHSExpr2 = BitOp->getRHS()->IgnoreParens();
980+
if (BitOp &&
981+
(BitOp->getOpcode() == BO_And || BitOp->getOpcode() == BO_Or)) {
983982

984-
const IntegerLiteral *IntLiteral2 = dyn_cast<IntegerLiteral>(LHSExpr2);
983+
// If integer literal in expression identified then will save value.
984+
Expr::EvalResult IntExprResult2;
985985

986-
if (!IntLiteral2)
987-
IntLiteral2 = dyn_cast<IntegerLiteral>(RHSExpr2);
986+
if (BitOp->getLHS()->EvaluateAsInt(IntExprResult2, *Context))
987+
; // LHS is a constant expression.
988+
else if (BitOp->getRHS()->EvaluateAsInt(IntExprResult2, *Context))
989+
; // RHS is a constant expression.
990+
else
991+
return TryResult(); // Neither is a constant expression, bail out.
988992

989-
if (!IntLiteral2)
990-
return TryResult();
993+
llvm::APInt L2 = IntExprResult2.Val.getInt();
991994

992-
llvm::APInt L1 = IntLiteral->getValue();
993-
llvm::APInt L2 = IntLiteral2->getValue();
994995
if ((BitOp->getOpcode() == BO_And && (L2 & L1) != L1) ||
995-
(BitOp->getOpcode() == BO_Or && (L2 | L1) != L1)) {
996+
(BitOp->getOpcode() == BO_Or && (L2 | L1) != L1)) {
996997
if (BuildOpts.Observer)
997998
BuildOpts.Observer->compareBitwiseEquality(B,
998999
B->getOpcode() != BO_EQ);
9991000
TryResult(B->getOpcode() != BO_EQ);
10001001
}
10011002
} else if (BoolExpr->isKnownToHaveBooleanValue()) {
1002-
llvm::APInt IntValue = IntLiteral->getValue();
1003-
if ((IntValue == 1) || (IntValue == 0)) {
1003+
llvm::APInt IntValue = IntExprResult.Val.getInt(); // Getting the value.
1004+
if ((L1 == 1) || (L1 == 0)) {
10041005
return TryResult();
10051006
}
10061007
return TryResult(B->getOpcode() != BO_EQ);

clang/test/Sema/warn-bitwise-compare.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// RUN: %clang_cc1 -fsyntax-only -verify -Wall -Wno-unused %s
33

44
#define mydefine 2
5+
#define mydefine2 -2
56

67
enum {
78
ZERO,
@@ -11,29 +12,67 @@ enum {
1112
void f(int x) {
1213
if ((8 & x) == 3) {} // expected-warning {{bitwise comparison always evaluates to false}}
1314
if ((x & 8) == 4) {} // expected-warning {{bitwise comparison always evaluates to false}}
15+
if ((-8 & x) == 3) {} // expected-warning {{bitwise comparison always evaluates to false}}
16+
if ((x & -8) == 4) {} // expected-warning {{bitwise comparison always evaluates to false}}
17+
1418
if ((x & 8) != 4) {} // expected-warning {{bitwise comparison always evaluates to true}}
1519
if ((2 & x) != 4) {} // expected-warning {{bitwise comparison always evaluates to true}}
20+
if ((x & -8) != 4) {} // expected-warning {{bitwise comparison always evaluates to true}}
21+
if ((-2 & x) != 3) {} // expected-warning {{bitwise comparison always evaluates to true}}
22+
1623
if ((x | 4) == 3) {} // expected-warning {{bitwise comparison always evaluates to false}}
1724
if ((x | 3) != 4) {} // expected-warning {{bitwise comparison always evaluates to true}}
1825
if ((5 | x) != 3) {} // expected-warning {{bitwise comparison always evaluates to true}}
26+
27+
if ((x | -4) == 3) {} // expected-warning {{bitwise comparison always evaluates to false}}
28+
if ((x | -3) != 4) {} // expected-warning {{bitwise comparison always evaluates to true}}
29+
if ((-5 | x) != 3) {} // expected-warning {{bitwise comparison always evaluates to true}}
30+
31+
1932
if ((x & 0x15) == 0x13) {} // expected-warning {{bitwise comparison always evaluates to false}}
33+
if ((x & 0xFFEB) == 0x13) {} // expected-warning {{bitwise comparison always evaluates to false}}
34+
2035
if ((0x23 | x) == 0x155){} // expected-warning {{bitwise comparison always evaluates to false}}
36+
if ((0xFFDD | x) == 0x155){} // expected-warning {{bitwise comparison always evaluates to false}}
2137

2238
if (!!((8 & x) == 3)) {} // expected-warning {{bitwise comparison always evaluates to false}}
39+
if (!!((-8 & x) == 3)) {} // expected-warning {{bitwise comparison always evaluates to false}}
40+
2341
int y = ((8 & x) == 3) ? 1 : 2; // expected-warning {{bitwise comparison always evaluates to false}}
42+
y = ((-8 & x) == 3) ? 1 : 2; // expected-warning {{bitwise comparison always evaluates to false}}
43+
y = ((3 | x) != 5) ? 1 : 2; // expected-warning {{bitwise comparison always evaluates to true}}
44+
y = ((-3 | x) != 5) ? 1 : 2; // expected-warning {{bitwise comparison always evaluates to true}}
2445

2546
if ((x & 8) == 8) {}
2647
if ((x & 8) != 8) {}
2748
if ((x | 4) == 4) {}
2849
if ((x | 4) != 4) {}
2950

51+
if ((-2 & x) != 4) {}
52+
if ((x & -8) == -8) {}
53+
if ((x & -8) != -8) {}
54+
if ((x | -4) == -4) {}
55+
if ((x | -4) != -4) {}
56+
57+
3058
if ((x & 9) == 8) {}
3159
if ((x & 9) != 8) {}
3260
if ((x | 4) == 5) {}
3361
if ((x | 4) != 5) {}
3462

63+
if ((x & -9) == -10) {}
64+
if ((x & -9) != -10) {}
65+
if ((x | -4) == -3) {}
66+
if ((x | -4) != -3) {}
67+
68+
if ((x^0) == 0) {}
69+
3570
if ((x & mydefine) == 8) {}
3671
if ((x | mydefine) == 4) {}
72+
73+
if ((x & mydefine2) == 8) {}
74+
if ((x | mydefine2) == 4) {}
75+
3776
}
3877

3978
void g(int x) {

clang/test/SemaCXX/warn-unreachable.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -396,15 +396,16 @@ void tautological_compare(bool x, int y) {
396396
if (y == -1 && y != -1) // expected-note {{silence}}
397397
calledFun(); // expected-warning {{will never be executed}}
398398

399-
// TODO: Extend warning to the following code:
400-
if (x < -1)
401-
calledFun();
402-
if (x == -1)
403-
calledFun();
399+
if (x == -1) // expected-note {{silence}}
400+
calledFun(); // expected-warning {{will never be executed}}
404401

405-
if (x != -1)
402+
if (x != -1) // expected-note {{silence}}
406403
calledFun();
407404
else
405+
calledFun(); // expected-warning {{will never be executed}}
406+
407+
// TODO: Extend warning to the following code:
408+
if (x < -1)
408409
calledFun();
409410
if (-1 > x)
410411
calledFun();

0 commit comments

Comments
 (0)