Skip to content

Commit 0731df7

Browse files
authored
ExprEngine: Add FP and String literals in determining that condition can (danmar#2969)
1 parent fcb496f commit 0731df7

File tree

2 files changed

+82
-3
lines changed

2 files changed

+82
-3
lines changed

lib/exprengine.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1404,13 +1404,13 @@ bool ExprEngine::IntRange::isLessThan(DataBase *dataBase, int value) const
14041404

14051405
bool ExprEngine::FloatRange::isEqual(DataBase *dataBase, int value) const
14061406
{
1407-
const Data *data = dynamic_cast<Data *>(dataBase);
1408-
if (data->constraints.empty())
1409-
return true;
14101407
if (MathLib::isFloat(name)) {
14111408
float f = MathLib::toDoubleNumber(name);
14121409
return value >= f - 0.00001 && value <= f + 0.00001;
14131410
}
1411+
const Data *data = dynamic_cast<Data *>(dataBase);
1412+
if (data->constraints.empty())
1413+
return true;
14141414
#ifdef USE_Z3
14151415
// Check the value against the constraints
14161416
ExprData exprData;
@@ -2555,6 +2555,12 @@ static std::string execute(const Token *start, const Token *end, Data &data)
25552555
} else if (auto i = std::dynamic_pointer_cast<ExprEngine::IntRange>(condValue)) {
25562556
canBeFalse = i->isEqual(&data, 0);
25572557
canBeTrue = ExprEngine::BinOpResult("!=", i, std::make_shared<ExprEngine::IntRange>("0", 0, 0)).isTrue(&data);
2558+
} else if (std::dynamic_pointer_cast<ExprEngine::StringLiteralValue>(condValue)) {
2559+
canBeFalse = false;
2560+
canBeTrue = true;
2561+
} else if (auto f = std::dynamic_pointer_cast<ExprEngine::FloatRange>(condValue)) {
2562+
canBeFalse = f->isEqual(&data, 0);
2563+
canBeTrue = ExprEngine::BinOpResult("!=", f, std::make_shared<ExprEngine::FloatRange>("0.0", 0.0, 0.0)).isTrue(&data);
25582564
}
25592565

25602566
Data &thenData(data);

test/testexprengine.cpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ class TestExprEngine : public TestFixture {
6262
TEST_CASE(if3);
6363
TEST_CASE(if4);
6464
TEST_CASE(if5);
65+
TEST_CASE(ifAlwaysTrue1);
66+
TEST_CASE(ifAlwaysTrue2);
67+
TEST_CASE(ifAlwaysTrue3);
68+
TEST_CASE(ifAlwaysFalse1);
69+
TEST_CASE(ifAlwaysFalse2);
6570
TEST_CASE(ifelse1);
6671
TEST_CASE(ifif);
6772
TEST_CASE(ifreturn);
@@ -152,6 +157,7 @@ class TestExprEngine : public TestFixture {
152157
}
153158
replace(line, "(fp.gt ", "(> ");
154159
replace(line, "(fp.lt ", "(< ");
160+
replace(line, "(_ +zero 11 53)", "0.0");
155161
replace(line, "(fp #b0 #b10000000010 #x899999999999a)", "12.3");
156162
replace(line, "(/ 123.0 10.0)", "12.3");
157163
int par = 0;
@@ -448,6 +454,73 @@ class TestExprEngine : public TestFixture {
448454
expr("void foo(const int *x) { if (f1() && *x > 12) dostuff(*x == 5); }", "=="));
449455
}
450456

457+
void ifAlwaysTrue1() {
458+
const char code[] = "int foo() {\n"
459+
" int a = 42;\n"
460+
" if (1) {\n"
461+
" a = 0;\n"
462+
" }\n"
463+
" return a == 0;\n"
464+
"}";
465+
const char expected[] = "(distinct 1 0)\n"
466+
"(= 0 0)\n"
467+
"z3::sat\n";
468+
ASSERT_EQUALS(expected, expr(code, "=="));
469+
}
470+
471+
void ifAlwaysTrue2() {
472+
const char code[] = "int foo() {\n"
473+
" int a = 42;\n"
474+
" if (12.3) {\n"
475+
" a = 0;\n"
476+
" }\n"
477+
" return a == 0;\n"
478+
"}";
479+
const char expected[] = "(distinct 12.3 0.0)\n"
480+
"(= 0 0)\n"
481+
"z3::sat\n";
482+
ASSERT_EQUALS(expected, expr(code, "=="));
483+
}
484+
485+
void ifAlwaysTrue3() {
486+
const char code[] = "int foo() {\n"
487+
" int a = 42;\n"
488+
" if (\"test\") {\n"
489+
" a = 0;\n"
490+
" }\n"
491+
" return a == 0;\n"
492+
"}";
493+
// String literals are always true. z3 will not be involved.
494+
ASSERT_EQUALS("", expr(code, "=="));
495+
}
496+
497+
void ifAlwaysFalse1() {
498+
const char code[] = "int foo() {\n"
499+
" int a = 42;\n"
500+
" if (0) {\n"
501+
" a = 0;\n"
502+
" }\n"
503+
" return a == 0;\n"
504+
"}";
505+
const char expected[] = "(= 0 0)\n"
506+
"(= 42 0)\n"
507+
"z3::unsat\n";
508+
ASSERT_EQUALS(expected, expr(code, "=="));
509+
}
510+
511+
void ifAlwaysFalse2() {
512+
const char code[] = "int foo() {\n"
513+
" int a = 42;\n"
514+
" if (0.0) {\n"
515+
" a = 0;\n"
516+
" }\n"
517+
" return a == 0;\n"
518+
"}";
519+
const char expected[] = "(= 0.0 0.0)\n"
520+
"(= 42 0)\n"
521+
"z3::unsat\n";
522+
ASSERT_EQUALS(expected, expr(code, "=="));
523+
}
451524

452525
void ifelse1() {
453526
ASSERT_EQUALS("(<= $1 5)\n"

0 commit comments

Comments
 (0)