summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/Expr.cpp2
-rw-r--r--clang/lib/AST/ExprConstant.cpp1
-rw-r--r--clang/lib/Analysis/ThreadSafetyCommon.cpp1
-rw-r--r--clang/lib/Analysis/ThreadSafetyTIL.cpp1
-rw-r--r--clang/lib/Basic/OperatorPrecedence.cpp1
-rw-r--r--clang/lib/CodeGen/CGExprScalar.cpp1
-rw-r--r--clang/lib/CodeGen/CGStmtOpenMP.cpp1
-rw-r--r--clang/lib/Format/ContinuationIndenter.cpp6
-rw-r--r--clang/lib/Format/Format.cpp1
-rw-r--r--clang/lib/Format/TokenAnnotator.cpp2
-rw-r--r--clang/lib/Parse/ParseExpr.cpp17
-rw-r--r--clang/lib/Sema/SemaChecking.cpp25
-rw-r--r--clang/lib/Sema/SemaExpr.cpp8
-rw-r--r--clang/lib/Sema/SemaOpenMP.cpp1
-rw-r--r--clang/lib/Sema/SemaStmt.cpp37
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp2
20 files changed, 87 insertions, 33 deletions
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 6cda82b2b0c..55061aa462e 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -1780,6 +1780,7 @@ BinaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO) {
case OO_Amp: return BO_And;
case OO_Pipe: return BO_Or;
case OO_Equal: return BO_Assign;
+ case OO_Spaceship: return BO_Cmp;
case OO_Less: return BO_LT;
case OO_Greater: return BO_GT;
case OO_PlusEqual: return BO_AddAssign;
@@ -1811,6 +1812,7 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) {
OO_Star, OO_Slash, OO_Percent,
OO_Plus, OO_Minus,
OO_LessLess, OO_GreaterGreater,
+ OO_Spaceship,
OO_Less, OO_Greater, OO_LessEqual, OO_GreaterEqual,
OO_EqualEqual, OO_ExclaimEqual,
OO_Amp,
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index e899b7ca164..9c9eeb79b40 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -10471,6 +10471,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case BO_AndAssign:
case BO_XorAssign:
case BO_OrAssign:
+ case BO_Cmp: // FIXME: Re-enable once we can evaluate this.
// C99 6.6/3 allows assignments within unevaluated subexpressions of
// constant expressions, but they can never be ICEs because an ICE cannot
// contain an lvalue operand.
diff --git a/clang/lib/Analysis/ThreadSafetyCommon.cpp b/clang/lib/Analysis/ThreadSafetyCommon.cpp
index 875f28c6e94..c1421b09c98 100644
--- a/clang/lib/Analysis/ThreadSafetyCommon.cpp
+++ b/clang/lib/Analysis/ThreadSafetyCommon.cpp
@@ -505,6 +505,7 @@ til::SExpr *SExprBuilder::translateBinaryOperator(const BinaryOperator *BO,
case BO_GE: return translateBinOp(til::BOP_Leq, BO, Ctx, true);
case BO_EQ: return translateBinOp(til::BOP_Eq, BO, Ctx);
case BO_NE: return translateBinOp(til::BOP_Neq, BO, Ctx);
+ case BO_Cmp: return translateBinOp(til::BOP_Cmp, BO, Ctx);
case BO_And: return translateBinOp(til::BOP_BitAnd, BO, Ctx);
case BO_Xor: return translateBinOp(til::BOP_BitXor, BO, Ctx);
case BO_Or: return translateBinOp(til::BOP_BitOr, BO, Ctx);
diff --git a/clang/lib/Analysis/ThreadSafetyTIL.cpp b/clang/lib/Analysis/ThreadSafetyTIL.cpp
index 83aa90435e2..cd7cdc69ab7 100644
--- a/clang/lib/Analysis/ThreadSafetyTIL.cpp
+++ b/clang/lib/Analysis/ThreadSafetyTIL.cpp
@@ -38,6 +38,7 @@ StringRef til::getBinaryOpcodeString(TIL_BinaryOpcode Op) {
case BOP_Neq: return "!=";
case BOP_Lt: return "<";
case BOP_Leq: return "<=";
+ case BOP_Cmp: return "<=>";
case BOP_LogicAnd: return "&&";
case BOP_LogicOr: return "||";
}
diff --git a/clang/lib/Basic/OperatorPrecedence.cpp b/clang/lib/Basic/OperatorPrecedence.cpp
index 384d23c38af..3743b6ad5fe 100644
--- a/clang/lib/Basic/OperatorPrecedence.cpp
+++ b/clang/lib/Basic/OperatorPrecedence.cpp
@@ -63,6 +63,7 @@ prec::Level getBinOpPrecedence(tok::TokenKind Kind, bool GreaterThanIsOperator,
case tok::lessequal:
case tok::less:
case tok::greaterequal: return prec::Relational;
+ case tok::spaceship: return prec::Spaceship;
case tok::lessless: return prec::Shift;
case tok::plus:
case tok::minus: return prec::Additive;
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 32e0f885304..c46215067a6 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -3922,6 +3922,7 @@ LValue CodeGenFunction::EmitCompoundAssignmentLValue(
case BO_GE:
case BO_EQ:
case BO_NE:
+ case BO_Cmp:
case BO_And:
case BO_Xor:
case BO_Or:
diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index a24aaa046ab..f04d28ed0d4 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -3408,6 +3408,7 @@ static std::pair<bool, RValue> emitOMPAtomicRMW(CodeGenFunction &CGF, LValue X,
case BO_GE:
case BO_EQ:
case BO_NE:
+ case BO_Cmp:
case BO_AddAssign:
case BO_SubAssign:
case BO_AndAssign:
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index e022a3a8c77..a3d38b244c5 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -323,7 +323,8 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
// We need special cases for ">>" which we have split into two ">" while
// lexing in order to make template parsing easier.
bool IsComparison = (Previous.getPrecedence() == prec::Relational ||
- Previous.getPrecedence() == prec::Equality) &&
+ Previous.getPrecedence() == prec::Equality ||
+ Previous.getPrecedence() == prec::Spaceship) &&
Previous.Previous &&
Previous.Previous->isNot(TT_BinaryOperator); // For >>.
bool LHSIsBinaryExpr =
@@ -536,7 +537,8 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
(P->is(TT_ConditionalExpr) && P->is(tok::colon))) &&
!P->isOneOf(TT_OverloadedOperator, TT_CtorInitializerComma) &&
P->getPrecedence() != prec::Assignment &&
- P->getPrecedence() != prec::Relational) {
+ P->getPrecedence() != prec::Relational &&
+ P->getPrecedence() != prec::Spaceship) {
bool BreakBeforeOperator =
P->MustBreakBefore || P->is(tok::lessless) ||
(P->is(TT_BinaryOperator) &&
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 38e8163d3fe..217c6729ee3 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -2074,6 +2074,7 @@ LangOptions getFormattingLangOpts(const FormatStyle &Style) {
LangOpts.CPlusPlus11 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
LangOpts.CPlusPlus14 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
LangOpts.CPlusPlus17 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
+ LangOpts.CPlusPlus2a = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
LangOpts.LineComment = 1;
bool AlternativeOperators = Style.isCpp();
LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0;
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index c394fa03b26..298c72b002f 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -2153,7 +2153,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
if (Left.isOneOf(tok::plus, tok::comma) && Left.Previous &&
Left.Previous->isLabelString() &&
(Left.NextOperator || Left.OperatorIndex != 0))
- return 45;
+ return 50;
if (Right.is(tok::plus) && Left.isLabelString() &&
(Right.NextOperator || Right.OperatorIndex != 0))
return 25;
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 233e0accce9..bc587628c95 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -66,12 +66,16 @@ using namespace clang;
/// shift-expression '<<' additive-expression
/// shift-expression '>>' additive-expression
///
-/// relational-expression: [C99 6.5.8]
+/// compare-expression: [C++20 expr.spaceship]
/// shift-expression
-/// relational-expression '<' shift-expression
-/// relational-expression '>' shift-expression
-/// relational-expression '<=' shift-expression
-/// relational-expression '>=' shift-expression
+/// compare-expression '<=>' shift-expression
+///
+/// relational-expression: [C99 6.5.8]
+/// compare-expression
+/// relational-expression '<' compare-expression
+/// relational-expression '>' compare-expression
+/// relational-expression '<=' compare-expression
+/// relational-expression '>=' compare-expression
///
/// equality-expression: [C99 6.5.9]
/// relational-expression
@@ -267,7 +271,8 @@ bool Parser::diagnoseUnknownTemplateId(ExprResult LHS, SourceLocation Less) {
}
bool Parser::isFoldOperator(prec::Level Level) const {
- return Level > prec::Unknown && Level != prec::Conditional;
+ return Level > prec::Unknown && Level != prec::Conditional &&
+ Level != prec::Spaceship;
}
bool Parser::isFoldOperator(tok::TokenKind Kind) const {
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 9ed21daad60..94070bb9c9a 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -7279,8 +7279,8 @@ static bool CheckMemorySizeofForComparison(Sema &S, const Expr *E,
if (!Size)
return false;
- // if E is binop and op is >, <, >=, <=, ==, &&, ||:
- if (!Size->isComparisonOp() && !Size->isEqualityOp() && !Size->isLogicalOp())
+ // if E is binop and op is <=>, >, <, >=, <=, ==, &&, ||:
+ if (!Size->isComparisonOp() && !Size->isLogicalOp())
return false;
SourceRange SizeRange = Size->getSourceRange();
@@ -8433,6 +8433,8 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) {
if (const auto *BO = dyn_cast<BinaryOperator>(E)) {
switch (BO->getOpcode()) {
+ case BO_Cmp:
+ llvm_unreachable("builtin <=> should have class type");
// Boolean-valued operations are single-bit and positive.
case BO_LAnd:
@@ -8747,9 +8749,18 @@ struct PromotedRange {
llvm_unreachable("impossible compare result");
}
- static llvm::Optional<bool> constantValue(BinaryOperatorKind Op,
- ComparisonResult R,
- bool ConstantOnRHS) {
+ static llvm::Optional<StringRef>
+ constantValue(BinaryOperatorKind Op, ComparisonResult R, bool ConstantOnRHS) {
+ if (Op == BO_Cmp) {
+ ComparisonResult LTFlag = LT, GTFlag = GT;
+ if (ConstantOnRHS) std::swap(LTFlag, GTFlag);
+
+ if (R & EQ) return StringRef("'std::strong_ordering::equal'");
+ if (R & LTFlag) return StringRef("'std::strong_ordering::less'");
+ if (R & GTFlag) return StringRef("'std::strong_ordering::greater'");
+ return llvm::None;
+ }
+
ComparisonResult TrueFlag, FalseFlag;
if (Op == BO_EQ) {
TrueFlag = EQ;
@@ -8769,9 +8780,9 @@ struct PromotedRange {
std::swap(TrueFlag, FalseFlag);
}
if (R & TrueFlag)
- return true;
+ return StringRef("true");
if (R & FalseFlag)
- return false;
+ return StringRef("false");
return llvm::None;
}
};
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 8c6d11b4957..929806ac6bf 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -11375,6 +11375,7 @@ BinaryOperatorKind Sema::ConvertTokenKindToBinaryOpcode(tok::TokenKind Kind) {
case tok::greater: Opc = BO_GT; break;
case tok::exclaimequal: Opc = BO_NE; break;
case tok::equalequal: Opc = BO_EQ; break;
+ case tok::spaceship: Opc = BO_Cmp; break;
case tok::amp: Opc = BO_And; break;
case tok::caret: Opc = BO_Xor; break;
case tok::pipe: Opc = BO_Or; break;
@@ -11683,6 +11684,13 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
ConvertHalfVec = true;
ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, false);
break;
+ case BO_Cmp:
+ // FIXME: Implement proper semantic checking of '<=>'.
+ ConvertHalfVec = true;
+ ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, true);
+ if (!ResultTy.isNull())
+ ResultTy = Context.VoidTy;
+ break;
case BO_And:
checkObjCPointerIntrospection(*this, LHS, RHS, OpLoc);
LLVM_FALLTHROUGH;
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index b9323388579..b34bb3388d7 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -10343,6 +10343,7 @@ static bool ActOnOMPReductionKindClause(
case BO_GE:
case BO_EQ:
case BO_NE:
+ case BO_Cmp:
case BO_AndAssign:
case BO_XorAssign:
case BO_OrAssign:
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 45b73f0a2bf..ff0f4d99585 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -127,34 +127,47 @@ void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) {
/// warning from firing.
static bool DiagnoseUnusedComparison(Sema &S, const Expr *E) {
SourceLocation Loc;
- bool IsNotEqual, CanAssign, IsRelational;
+ bool CanAssign;
+ enum { Equality, Inequality, Relational, ThreeWay } Kind;
if (const BinaryOperator *Op = dyn_cast<BinaryOperator>(E)) {
if (!Op->isComparisonOp())
return false;
- IsRelational = Op->isRelationalOp();
+ if (Op->getOpcode() == BO_EQ)
+ Kind = Equality;
+ else if (Op->getOpcode() == BO_NE)
+ Kind = Inequality;
+ else if (Op->getOpcode() == BO_Cmp)
+ Kind = ThreeWay;
+ else {
+ assert(Op->isRelationalOp());
+ Kind = Relational;
+ }
Loc = Op->getOperatorLoc();
- IsNotEqual = Op->getOpcode() == BO_NE;
CanAssign = Op->getLHS()->IgnoreParenImpCasts()->isLValue();
} else if (const CXXOperatorCallExpr *Op = dyn_cast<CXXOperatorCallExpr>(E)) {
switch (Op->getOperator()) {
- default:
- return false;
case OO_EqualEqual:
+ Kind = Equality;
+ break;
case OO_ExclaimEqual:
- IsRelational = false;
+ Kind = Inequality;
break;
case OO_Less:
case OO_Greater:
case OO_GreaterEqual:
case OO_LessEqual:
- IsRelational = true;
+ Kind = Relational;
break;
+ case OO_Spaceship:
+ Kind = ThreeWay;
+ break;
+ default:
+ return false;
}
Loc = Op->getOperatorLoc();
- IsNotEqual = Op->getOperator() == OO_ExclaimEqual;
CanAssign = Op->getArg(0)->IgnoreParenImpCasts()->isLValue();
} else {
// Not a typo-prone comparison.
@@ -167,15 +180,15 @@ static bool DiagnoseUnusedComparison(Sema &S, const Expr *E) {
return false;
S.Diag(Loc, diag::warn_unused_comparison)
- << (unsigned)IsRelational << (unsigned)IsNotEqual << E->getSourceRange();
+ << (unsigned)Kind << E->getSourceRange();
// If the LHS is a plausible entity to assign to, provide a fixit hint to
// correct common typos.
- if (!IsRelational && CanAssign) {
- if (IsNotEqual)
+ if (CanAssign) {
+ if (Kind == Inequality)
S.Diag(Loc, diag::note_inequality_comparison_to_or_assign)
<< FixItHint::CreateReplacement(Loc, "|=");
- else
+ else if (Kind == Equality)
S.Diag(Loc, diag::note_equality_comparison_to_assign)
<< FixItHint::CreateReplacement(Loc, "=");
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
index 0c3bff5b63b..cf57b8dca06 100644
--- a/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
@@ -255,7 +255,10 @@ void FindIdenticalExprVisitor::checkComparisonOp(const BinaryOperator *B) {
PathDiagnosticLocation ELoc =
PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager());
StringRef Message;
- if (((Op == BO_EQ) || (Op == BO_LE) || (Op == BO_GE)))
+ if (Op == BO_Cmp)
+ Message = "comparison of identical expressions always evaluates to "
+ "'equal'";
+ else if (((Op == BO_EQ) || (Op == BO_LE) || (Op == BO_GE)))
Message = "comparison of identical expressions always evaluates to true";
else
Message = "comparison of identical expressions always evaluates to false";
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index f651596006b..7304d789431 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -1541,7 +1541,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, const BinaryOperator *BExpr,
// For non-assignment operations, we require that we can understand
// both the LHS and RHS.
if (LhsString.empty() || RhsString.empty() ||
- !BinaryOperator::isComparisonOp(Op))
+ !BinaryOperator::isComparisonOp(Op) || Op == BO_Cmp)
return nullptr;
// Should we invert the strings if the LHS is not a variable name?
diff --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 6a4c4d11585..5a4031c0b4a 100644
--- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -396,7 +396,9 @@ bool RangeConstraintManager::canReasonAbout(SVal X) const {
}
if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(SE)) {
- if (BinaryOperator::isComparisonOp(SSE->getOpcode())) {
+ // FIXME: Handle <=> here.
+ if (BinaryOperator::isEqualityOp(SSE->getOpcode()) ||
+ BinaryOperator::isRelationalOp(SSE->getOpcode())) {
// We handle Loc <> Loc comparisons, but not (yet) NonLoc <> NonLoc.
if (Loc::isLocType(SSE->getLHS()->getType())) {
assert(Loc::isLocType(SSE->getRHS()->getType()));
diff --git a/clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp
index 1304116f497..55ff15806ef 100644
--- a/clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp
@@ -33,7 +33,7 @@ ProgramStateRef RangedConstraintManager::assumeSym(ProgramStateRef State,
// We can only simplify expressions whose RHS is an integer.
BinaryOperator::Opcode op = SIE->getOpcode();
- if (BinaryOperator::isComparisonOp(op)) {
+ if (BinaryOperator::isComparisonOp(op) && op != BO_Cmp) {
if (!Assumption)
op = BinaryOperator::negateComparisonOp(op);
diff --git a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index a5b5744c3fb..94d29d5a6ba 100644
--- a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -679,7 +679,7 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
if (SymbolRef rSym = rhs.getAsLocSymbol()) {
// We can only build expressions with symbols on the left,
// so we need a reversible operator.
- if (!BinaryOperator::isComparisonOp(op))
+ if (!BinaryOperator::isComparisonOp(op) || op == BO_Cmp)
return UnknownVal();
const llvm::APSInt &lVal = lhs.castAs<loc::ConcreteInt>().getValue();
OpenPOWER on IntegriCloud