r209221 - Add a check for tautological bitwise comparisons to -Wtautological-compare.
Jordan Rose
jordan_rose at apple.com
Tue May 20 10:31:11 PDT 2014
Author: jrose
Date: Tue May 20 12:31:11 2014
New Revision: 209221
URL: http://llvm.org/viewvc/llvm-project?rev=209221&view=rev
Log:
Add a check for tautological bitwise comparisons to -Wtautological-compare.
This catches issues like:
if ((x & 8) == 4) { ... }
if ((x | 4) != 3) { ... }
Patch by Anders Rönnholm!
Added:
cfe/trunk/test/Sema/warn-bitwise-compare.c
Modified:
cfe/trunk/include/clang/Analysis/CFG.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Analysis/CFG.cpp
cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp
Modified: cfe/trunk/include/clang/Analysis/CFG.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/CFG.h?rev=209221&r1=209220&r2=209221&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/CFG.h (original)
+++ cfe/trunk/include/clang/Analysis/CFG.h Tue May 20 12:31:11 2014
@@ -706,6 +706,8 @@ class CFGCallback {
public:
CFGCallback() {}
virtual void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) {}
+ virtual void compareBitwiseEquality(const BinaryOperator *B,
+ bool isAlwaysTrue) {}
virtual ~CFGCallback() {}
};
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=209221&r1=209220&r2=209221&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue May 20 12:31:11 2014
@@ -6404,6 +6404,9 @@ def note_ref_subobject_of_member_declare
def warn_comparison_always : Warning<
"%select{self-|array }0comparison always evaluates to %select{false|true|a constant}1">,
InGroup<TautologicalCompare>;
+def warn_comparison_bitwise_always : Warning<
+ "bitwise comparison always evaluates to %select{false|true}0">,
+ InGroup<TautologicalCompare>;
def warn_tautological_overlap_comparison : Warning<
"overlapping comparisons always evaluate to %select{false|true}0">,
InGroup<TautologicalOverlapCompare>, DefaultIgnore;
Modified: cfe/trunk/lib/Analysis/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=209221&r1=209220&r2=209221&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CFG.cpp (original)
+++ cfe/trunk/lib/Analysis/CFG.cpp Tue May 20 12:31:11 2014
@@ -534,9 +534,10 @@ private:
}
}
- /// Find a equality comparison with an expression evaluating to a boolean and
- /// a constant other than 0 and 1.
- /// e.g. if (!x == 10)
+ /// Find an incorrect equality comparison. Either with an expression
+ /// evaluating to a boolean and a constant other than 0 and 1.
+ /// e.g. if (!x == 10) or a bitwise and/or operation that always evaluates to
+ /// true/false e.q. (x & 8) == 4.
TryResult checkIncorrectEqualityOperator(const BinaryOperator *B) {
const Expr *LHSExpr = B->getLHS()->IgnoreParens();
const Expr *RHSExpr = B->getRHS()->IgnoreParens();
@@ -549,15 +550,41 @@ private:
BoolExpr = LHSExpr;
}
- if (!IntLiteral || !BoolExpr->isKnownToHaveBooleanValue())
+ if (!IntLiteral)
return TryResult();
- llvm::APInt IntValue = IntLiteral->getValue();
- if ((IntValue == 1) || (IntValue == 0)) {
- return TryResult();
+ const BinaryOperator *BitOp = dyn_cast<BinaryOperator>(BoolExpr);
+ if (BitOp && (BitOp->getOpcode() == BO_And ||
+ BitOp->getOpcode() == BO_Or)) {
+ const Expr *LHSExpr2 = BitOp->getLHS()->IgnoreParens();
+ const Expr *RHSExpr2 = BitOp->getRHS()->IgnoreParens();
+
+ const IntegerLiteral *IntLiteral2 = dyn_cast<IntegerLiteral>(LHSExpr2);
+
+ if (!IntLiteral2)
+ IntLiteral2 = dyn_cast<IntegerLiteral>(RHSExpr2);
+
+ if (!IntLiteral2)
+ return TryResult();
+
+ llvm::APInt L1 = IntLiteral->getValue();
+ llvm::APInt L2 = IntLiteral2->getValue();
+ if ((BitOp->getOpcode() == BO_And && (L2 & L1) != L1) ||
+ (BitOp->getOpcode() == BO_Or && (L2 | L1) != L1)) {
+ if (BuildOpts.Observer)
+ BuildOpts.Observer->compareBitwiseEquality(B,
+ B->getOpcode() != BO_EQ);
+ TryResult(B->getOpcode() != BO_EQ);
+ }
+ } else if (BoolExpr->isKnownToHaveBooleanValue()) {
+ llvm::APInt IntValue = IntLiteral->getValue();
+ if ((IntValue == 1) || (IntValue == 0)) {
+ return TryResult();
+ }
+ return TryResult(B->getOpcode() != BO_EQ);
}
- return TryResult(B->getOpcode() != BO_EQ);
+ return TryResult();
}
TryResult analyzeLogicOperatorCondition(BinaryOperatorKind Relation,
Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp?rev=209221&r1=209220&r2=209221&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp (original)
+++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Tue May 20 12:31:11 2014
@@ -146,6 +146,15 @@ public:
S.Diag(B->getExprLoc(), diag::warn_tautological_overlap_comparison)
<< DiagRange << isAlwaysTrue;
}
+
+ void compareBitwiseEquality(const BinaryOperator *B, bool isAlwaysTrue) {
+ if (HasMacroID(B))
+ return;
+
+ SourceRange DiagRange = B->getSourceRange();
+ S.Diag(B->getExprLoc(), diag::warn_comparison_bitwise_always)
+ << DiagRange << isAlwaysTrue;
+ }
};
Added: cfe/trunk/test/Sema/warn-bitwise-compare.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/warn-bitwise-compare.c?rev=209221&view=auto
==============================================================================
--- cfe/trunk/test/Sema/warn-bitwise-compare.c (added)
+++ cfe/trunk/test/Sema/warn-bitwise-compare.c Tue May 20 12:31:11 2014
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wtautological-compare %s
+
+#define mydefine 2
+
+void f(int x) {
+ if ((8 & x) == 3) {} // expected-warning {{bitwise comparison always evaluates to false}}
+ if ((x & 8) == 4) {} // expected-warning {{bitwise comparison always evaluates to false}}
+ if ((x & 8) != 4) {} // expected-warning {{bitwise comparison always evaluates to true}}
+ if ((2 & x) != 4) {} // expected-warning {{bitwise comparison always evaluates to true}}
+ if ((x | 4) == 3) {} // expected-warning {{bitwise comparison always evaluates to false}}
+ if ((x | 3) != 4) {} // expected-warning {{bitwise comparison always evaluates to true}}
+ if ((5 | x) != 3) {} // expected-warning {{bitwise comparison always evaluates to true}}
+ if ((x & 0x15) == 0x13) {} // expected-warning {{bitwise comparison always evaluates to false}}
+ if ((0x23 | x) == 0x155){} // expected-warning {{bitwise comparison always evaluates to false}}
+
+ if ((x & 8) == 8) {}
+ if ((x & 8) != 8) {}
+ if ((x | 4) == 4) {}
+ if ((x | 4) != 4) {}
+
+ if ((x & 9) == 8) {}
+ if ((x & 9) != 8) {}
+ if ((x | 4) == 5) {}
+ if ((x | 4) != 5) {}
+
+ if ((x & mydefine) == 8) {}
+ if ((x | mydefine) == 4) {}
+}
More information about the cfe-commits
mailing list