Skip to content

Commit b875a22

Browse files
authored
Merge pull request #8997 from diffblue/fix/no-unary-bv-concat-smt2
SMT2: avoid emitting unary bitvector concat
2 parents 4993eb9 + 425b797 commit b875a22

3 files changed

Lines changed: 37 additions & 11 deletions

File tree

‎src/solvers/smt2/smt2_conv.cpp‎

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,22 +1299,31 @@ void smt2_convt::convert_expr(const exprt &expr)
12991299
"concatenation expression should have at least one operand",
13001300
expr.id_string());
13011301

1302-
if(expr.operands().size() == 1)
1302+
// collect non-zero-width operands (zero-width not allowed by SMT-LIB)
1303+
exprt::operandst non_zero_width_ops;
1304+
for(const auto &op : expr.operands())
13031305
{
1304-
flatten2bv(expr.operands().front());
1306+
if(!is_zero_width(op.type(), ns))
1307+
non_zero_width_ops.push_back(op);
13051308
}
1306-
else // >= 2
1309+
1310+
DATA_INVARIANT(
1311+
!non_zero_width_ops.empty(),
1312+
"concatenation must have at least one non-zero-width operand");
1313+
1314+
if(non_zero_width_ops.size() == 1)
1315+
{
1316+
// unary concat is not valid SMT-LIB; emit the operand directly
1317+
flatten2bv(non_zero_width_ops.front());
1318+
}
1319+
else
13071320
{
13081321
out << "(concat";
13091322

1310-
for(const auto &op : expr.operands())
1323+
for(const auto &op : non_zero_width_ops)
13111324
{
1312-
// drop zero-width operands, which are not allowed by SMT-LIB
1313-
if(!is_zero_width(op.type(), ns))
1314-
{
1315-
out << ' ';
1316-
flatten2bv(op);
1317-
}
1325+
out << ' ';
1326+
flatten2bv(op);
13181327
}
13191328

13201329
out << ')';

‎src/util/bitvector_expr.h‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -952,7 +952,8 @@ inline replication_exprt &to_replication_expr(exprt &expr)
952952

953953
/// \brief Concatenation of bit-vector operands
954954
///
955-
/// This expression takes any number of operands
955+
/// This expression takes any number of operands, including
956+
/// zero-width operands.
956957
/// The ordering of the operands is the same as in the SMT-LIB 2 standard,
957958
/// i.e., most-significant operands come first.
958959
class concatenation_exprt : public multi_ary_exprt

‎unit/solvers/smt2/smt2_conv.cpp‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
/// \file
44
/// Unit tests for smt2_convt
55

6+
#include <util/bitvector_expr.h>
67
#include <util/bitvector_types.h>
78
#include <util/namespace.h>
89
#include <util/std_expr.h>
@@ -114,3 +115,18 @@ TEST_CASE("smt2_convt reduction operators", "[core][solvers][smt2]")
114115
"(assert (not (= y (_ bv0 1))))");
115116
}
116117
}
118+
119+
TEST_CASE(
120+
"smt2_convt no unary concat for zero-width operand",
121+
"[core][solvers][smt2]")
122+
{
123+
unsignedbv_typet u8{8};
124+
unsignedbv_typet u0{0};
125+
symbol_exprt x{"x", u8};
126+
symbol_exprt z{"z", u0};
127+
128+
// concat of a zero-width and a non-zero-width operand should emit
129+
// the non-zero-width operand directly, not (concat x)
130+
concatenation_exprt concat{{z, x}, u8};
131+
REQUIRE(get_assert(equal_exprt{concat, x}) == "(assert (= x x))");
132+
}

0 commit comments

Comments
 (0)