mirror of https://github.com/microsoft/clang.git
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! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@209221 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
ca90717aad
commit
b85e94189d
|
@ -706,6 +706,8 @@ class CFGCallback {
|
||||||
public:
|
public:
|
||||||
CFGCallback() {}
|
CFGCallback() {}
|
||||||
virtual void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) {}
|
virtual void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) {}
|
||||||
|
virtual void compareBitwiseEquality(const BinaryOperator *B,
|
||||||
|
bool isAlwaysTrue) {}
|
||||||
virtual ~CFGCallback() {}
|
virtual ~CFGCallback() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -6404,6 +6404,9 @@ def note_ref_subobject_of_member_declared_here : Note<
|
||||||
def warn_comparison_always : Warning<
|
def warn_comparison_always : Warning<
|
||||||
"%select{self-|array }0comparison always evaluates to %select{false|true|a constant}1">,
|
"%select{self-|array }0comparison always evaluates to %select{false|true|a constant}1">,
|
||||||
InGroup<TautologicalCompare>;
|
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<
|
def warn_tautological_overlap_comparison : Warning<
|
||||||
"overlapping comparisons always evaluate to %select{false|true}0">,
|
"overlapping comparisons always evaluate to %select{false|true}0">,
|
||||||
InGroup<TautologicalOverlapCompare>, DefaultIgnore;
|
InGroup<TautologicalOverlapCompare>, DefaultIgnore;
|
||||||
|
|
|
@ -534,9 +534,10 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find a equality comparison with an expression evaluating to a boolean and
|
/// Find an incorrect equality comparison. Either with an expression
|
||||||
/// a constant other than 0 and 1.
|
/// evaluating to a boolean and a constant other than 0 and 1.
|
||||||
/// e.g. if (!x == 10)
|
/// 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) {
|
TryResult checkIncorrectEqualityOperator(const BinaryOperator *B) {
|
||||||
const Expr *LHSExpr = B->getLHS()->IgnoreParens();
|
const Expr *LHSExpr = B->getLHS()->IgnoreParens();
|
||||||
const Expr *RHSExpr = B->getRHS()->IgnoreParens();
|
const Expr *RHSExpr = B->getRHS()->IgnoreParens();
|
||||||
|
@ -549,15 +550,41 @@ private:
|
||||||
BoolExpr = LHSExpr;
|
BoolExpr = LHSExpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IntLiteral || !BoolExpr->isKnownToHaveBooleanValue())
|
if (!IntLiteral)
|
||||||
return TryResult();
|
return TryResult();
|
||||||
|
|
||||||
llvm::APInt IntValue = IntLiteral->getValue();
|
const BinaryOperator *BitOp = dyn_cast<BinaryOperator>(BoolExpr);
|
||||||
if ((IntValue == 1) || (IntValue == 0)) {
|
if (BitOp && (BitOp->getOpcode() == BO_And ||
|
||||||
return TryResult();
|
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,
|
TryResult analyzeLogicOperatorCondition(BinaryOperatorKind Relation,
|
||||||
|
|
|
@ -146,6 +146,15 @@ public:
|
||||||
S.Diag(B->getExprLoc(), diag::warn_tautological_overlap_comparison)
|
S.Diag(B->getExprLoc(), diag::warn_tautological_overlap_comparison)
|
||||||
<< DiagRange << isAlwaysTrue;
|
<< 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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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) {}
|
||||||
|
}
|
Loading…
Reference in New Issue