diff --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp --- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -21,8 +21,8 @@ #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/ImmutableSet.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include @@ -956,6 +956,8 @@ RangeSet VisitBinaryOperator(RangeSet LHS, BinaryOperator::Opcode Op, RangeSet RHS, QualType T) { switch (Op) { + case BO_NE: + return VisitBinaryOperator(LHS, RHS, T); case BO_Or: return VisitBinaryOperator(LHS, RHS, T); case BO_And: @@ -1029,6 +1031,27 @@ return infer(T); } + template <> + RangeSet VisitBinaryOperator(RangeSet LHS, RangeSet RHS, QualType T) { + // When both the RangeSets are non-overlapping then all possible pairs of + // (x, y) in LHS, RHS respectively, will satisfy expression (x != y). + if ((LHS.getMaxValue() < RHS.getMinValue()) || + (LHS.getMinValue() > RHS.getMaxValue())) { + return getTrueRange(T); + } + + // If both RangeSets contain only one Point which is equal then the + // expression will always return true. + if ((LHS.getMinValue() == RHS.getMaxValue()) && + (LHS.getMaxValue() == RHS.getMaxValue()) && + (LHS.getMinValue() == RHS.getMinValue())) { + return getFalseRange(T); + } + + // In all other cases, the resulting range cannot be deduced. + return infer(T); + } + /// Return a symmetrical range for the given range and type. /// /// If T is signed, return the smallest range [-x..x] that covers the original diff --git a/clang/test/Analysis/constant-folding.c b/clang/test/Analysis/constant-folding.c --- a/clang/test/Analysis/constant-folding.c +++ b/clang/test/Analysis/constant-folding.c @@ -466,3 +466,49 @@ clang_analyzer_eval((c - d) > -71); // expected-warning{{FALSE}} } } + +void testDisequalityRules(unsigned int u1, unsigned int u2, int s1, int s2) { + // Checks when ranges are not overlapping + if (u1 <= 10 && u2 >= 20) { + // u1: [0,10], u2: [20,UINT_MAX] + clang_analyzer_eval((u1 != u2) != 0); // expected-warning{{TRUE}} + } + + if (s1 <= INT_MIN + 10 && s2 >= INT_MAX - 10) { + // s1: [INT_MIN,INT_MIN + 10], s2: [INT_MIN - 10,INT_MAX] + clang_analyzer_eval((s1 != s2) == 0); // expected-warning{{FALSE}} + } + + // Checks when ranges are completely overlapping and have more than one point + if (u1 >= 20 && u1 <= 50 && u2 >= 20 && u2 <= 50) { + // u1: [20,50], u2: [20,50] + clang_analyzer_eval((u1 != u2) != 0); // expected-warning{{UNKNOWN}} + } + + if (s1 >= -20 && s1 <= 20 && s2 >= -20 && s2 <= 20) { + // s1: [-20,20], s2: [-20,20] + clang_analyzer_eval((s1 != s2) != 0); // expected-warning{{UNKNOWN}} + } + + // Checks when ranges are partially overlapping + if (u1 >= 100 && u1 <= 200 && u2 >= 150 && u2 <= 300) { + // u1: [100,200], u2: [150,300] + clang_analyzer_eval((u1 != u2) != 0); // expected-warning{{UNKNOWN}} + } + + if (s1 >= -80 && s1 <= -50 && s2 >= -100 && s2 <= -75) { + // s1: [-80,-50], s2: [-100,-75] + clang_analyzer_eval((s1 != s2) == 0); // expected-warning{{UNKNOWN}} + } + + // Checks for ranges which are subset of one-another + if (u1 >= 500 && u1 <= 1000 && u2 >= 750 && u2 <= 1000) { + // u1: [500,1000], u2: [750,1000] + clang_analyzer_eval((u1 != u2) == 0); // expected-warning{{UNKNOWN}} + } + + if (s1 >= -1000 && s1 <= -500 && s2 <= -500 && s2 >= -750) { + // s1: [-1000,-500], s2: [-500,-750] + clang_analyzer_eval((s1 != s2) == 0); // expected-warning{{UNKNOWN}} + } +}