}
if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(SE)) {
- if (SSE->getOpcode() == BO_EQ || SSE->getOpcode() == BO_NE)
+ if (BinaryOperator::isComparisonOp(SSE->getOpcode()))
return true;
}
}
} else if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(sym)) {
- BinaryOperator::Opcode Op = SSE->getOpcode();
-
// Translate "a != b" to "(b - a) != 0".
// We invert the order of the operands as a heuristic for how loop
// conditions are usually written ("begin != end") as compared to length
// calculations ("end - begin"). The more correct thing to do would be to
// canonicalize "a - b" and "b - a", which would allow us to treat
// "a != b" and "b != a" the same.
- if (BinaryOperator::isEqualityOp(Op)) {
- SymbolManager &SymMgr = getSymbolManager();
-
- assert(Loc::isLocType(SSE->getLHS()->getType()));
- assert(Loc::isLocType(SSE->getRHS()->getType()));
- QualType DiffTy = SymMgr.getContext().getPointerDiffType();
- SymbolRef Subtraction = SymMgr.getSymSymExpr(SSE->getRHS(), BO_Sub,
- SSE->getLHS(), DiffTy);
-
- Assumption ^= (SSE->getOpcode() == BO_EQ);
- return assumeAuxForSymbol(state, Subtraction, Assumption);
- }
+ SymbolManager &SymMgr = getSymbolManager();
+ BinaryOperator::Opcode Op = SSE->getOpcode();
+ assert(BinaryOperator::isComparisonOp(Op));
+
+ // For now, we only support comparing pointers.
+ assert(Loc::isLocType(SSE->getLHS()->getType()));
+ assert(Loc::isLocType(SSE->getRHS()->getType()));
+ QualType DiffTy = SymMgr.getContext().getPointerDiffType();
+ SymbolRef Subtraction = SymMgr.getSymSymExpr(SSE->getRHS(), BO_Sub,
+ SSE->getLHS(), DiffTy);
+
+ const llvm::APSInt &Zero = getBasicVals().getValue(0, DiffTy);
+ Op = BinaryOperator::reverseComparisonOp(Op);
+ if (!Assumption)
+ Op = BinaryOperator::negateComparisonOp(Op);
+ return assumeSymRel(state, Subtraction, Op, Zero);
}
// If we get here, there's nothing else we can do but treat the symbol as
clang_analyzer_eval(lhs != rhs); // expected-warning{{TRUE}}
}
+void comparisons_imply_size(int *lhs, int *rhs) {
+ clang_analyzer_eval(lhs <= rhs); // expected-warning{{UNKNOWN}}
+
+ if (lhs > rhs) {
+ clang_analyzer_eval((rhs - lhs) == 0); // expected-warning{{FALSE}}
+ return;
+ }
+
+ clang_analyzer_eval(lhs <= rhs); // expected-warning{{TRUE}}
+ clang_analyzer_eval((rhs - lhs) >= 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval((rhs - lhs) > 0); // expected-warning{{UNKNOWN}}
+
+ if (lhs >= rhs) {
+ clang_analyzer_eval((rhs - lhs) == 0); // expected-warning{{TRUE}}
+ return;
+ }
+
+ clang_analyzer_eval(lhs == rhs); // expected-warning{{FALSE}}
+ clang_analyzer_eval(lhs < rhs); // expected-warning{{TRUE}}
+ clang_analyzer_eval((rhs - lhs) > 0); // expected-warning{{TRUE}}
+}
+
+void size_implies_comparison(int *lhs, int *rhs) {
+ clang_analyzer_eval(lhs <= rhs); // expected-warning{{UNKNOWN}}
+
+ if ((rhs - lhs) < 0) {
+ clang_analyzer_eval(lhs == rhs); // expected-warning{{FALSE}}
+ return;
+ }
+
+ clang_analyzer_eval(lhs <= rhs); // expected-warning{{TRUE}}
+ clang_analyzer_eval((rhs - lhs) >= 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval((rhs - lhs) > 0); // expected-warning{{UNKNOWN}}
+
+ if ((rhs - lhs) <= 0) {
+ clang_analyzer_eval(lhs == rhs); // expected-warning{{TRUE}}
+ return;
+ }
+
+ clang_analyzer_eval(lhs == rhs); // expected-warning{{FALSE}}
+ clang_analyzer_eval(lhs < rhs); // expected-warning{{TRUE}}
+ clang_analyzer_eval((rhs - lhs) > 0); // expected-warning{{TRUE}}
+}
+
//-------------------------------
// False positives
//-------------------------------