Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions regression/cbmc/Union_Initialization2/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
union U {
};

struct S
{
int a;
union U u;
int b;
} s;

int main()
{
__CPROVER_assert(0, "");
}
9 changes: 9 additions & 0 deletions regression/cbmc/Union_Initialization2/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
CORE
main.c

^EXIT=10$
^SIGNAL=0$
^VERIFICATION FAILED$
--
^warning: ignoring
^Invariant check failed
2 changes: 2 additions & 0 deletions src/solvers/flattening/boolbv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ bvt boolbvt::convert_bitvector(const exprt &expr)
return convert_struct(to_struct_expr(expr));
else if(expr.id()==ID_union)
return convert_union(to_union_expr(expr));
else if(expr.id() == ID_empty_union)
return convert_empty_union(to_empty_union_expr(expr));
else if(expr.id()==ID_string_constant)
return convert_bitvector(
to_string_constant(expr).to_array_expr());
Expand Down
1 change: 1 addition & 0 deletions src/solvers/flattening/boolbv.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ class boolbvt:public arrayst
virtual bvt convert_let(const let_exprt &);
virtual bvt convert_array_of(const array_of_exprt &expr);
virtual bvt convert_union(const union_exprt &expr);
virtual bvt convert_empty_union(const empty_union_exprt &expr);
virtual bvt convert_bv_typecast(const typecast_exprt &expr);
virtual bvt convert_add_sub(const exprt &expr);
virtual bvt convert_mult(const mult_exprt &expr);
Expand Down
3 changes: 2 additions & 1 deletion src/solvers/flattening/boolbv_get.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ exprt boolbvt::bv_get_rec(
const union_typet &union_type=to_union_type(type);
const union_typet::componentst &components=union_type.components();

assert(!components.empty());
if(components.empty())
return empty_union_exprt(type);

// Any idea that's better than just returning the first component?
std::size_t component_nr=0;
Expand Down
5 changes: 5 additions & 0 deletions src/solvers/flattening/boolbv_union.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,8 @@ bvt boolbvt::convert_union(const union_exprt &expr)

return bv;
}

bvt boolbvt::convert_empty_union(const empty_union_exprt &expr)
{
return {};
}
12 changes: 10 additions & 2 deletions src/solvers/smt2/smt2_conv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2126,6 +2126,10 @@ void smt2_convt::convert_expr(const exprt &expr)
{
convert_expr(simplify_expr(to_count_trailing_zeros_expr(expr).lower(), ns));
}
else if(expr.id() == ID_empty_union)
{
out << "()";
}
else
INVARIANT_WITH_DIAGNOSTICS(
false,
Expand Down Expand Up @@ -4403,7 +4407,9 @@ void smt2_convt::set_to(const exprt &expr, bool value)
if(expr.id() == ID_equal && value)
{
const equal_exprt &equal_expr=to_equal_expr(expr);
if(equal_expr.lhs().type().id() == ID_empty)
if(
equal_expr.lhs().type().id() == ID_empty ||
equal_expr.rhs().id() == ID_empty_union)
{
// ignore equality checking over expressions with empty (void) type
return;
Expand Down Expand Up @@ -4891,7 +4897,9 @@ void smt2_convt::convert_type(const typet &type)
else if(type.id() == ID_union || type.id() == ID_union_tag)
{
std::size_t width=boolbv_width(type);
CHECK_RETURN_WITH_DIAGNOSTICS(width != 0, "failed to get width of union");
CHECK_RETURN_WITH_DIAGNOSTICS(
to_union_type(ns.follow(type)).components().empty() || width != 0,
"failed to get width of union");

out << "(_ BitVec " << width << ")";
}
Expand Down
52 changes: 15 additions & 37 deletions src/util/expr_initializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,51 +208,29 @@ optionalt<exprt> expr_initializert<nondet>::expr_initializer_rec(
}
else if(type_id==ID_union)
{
const union_typet::componentst &components=
to_union_type(type).components();
const union_typet &union_type = to_union_type(type);

union_typet::componentt component;
bool found=false;
mp_integer component_size=0;

// we need to find the largest member

for(const auto &c : components)
{
// skip methods
if(c.type().id() == ID_code)
continue;

auto bits = pointer_offset_bits(c.type(), ns);

if(bits.has_value() && *bits > component_size)
{
component = c;
found=true;
component_size = *bits;
}
}

if(!found)
if(union_type.components().empty())
{
// stupid empty union
union_exprt value(irep_idt(), nil_exprt(), type);
empty_union_exprt value{type};
value.add_source_location() = source_location;
return std::move(value);
}
else
{
auto component_value =
expr_initializer_rec(component.type(), source_location);

if(!component_value.has_value())
return {};
const auto &widest_member = union_type.find_widest_union_component(ns);
if(!widest_member.has_value())
return {};

union_exprt value(component.get_name(), *component_value, type);
value.add_source_location() = source_location;
auto component_value =
expr_initializer_rec(widest_member->first.type(), source_location);

return std::move(value);
}
if(!component_value.has_value())
return {};

union_exprt value{widest_member->first.get_name(), *component_value, type};
value.add_source_location() = source_location;

return std::move(value);
}
else if(type_id==ID_c_enum_tag)
{
Expand Down
1 change: 1 addition & 0 deletions src/util/irep_ids.def
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,7 @@ IREP_ID_TWO(vector_gt, vector->)
IREP_ID_TWO(vector_lt, vector-<)
IREP_ID_ONE(shuffle_vector)
IREP_ID_ONE(count_trailing_zeros)
IREP_ID_ONE(empty_union)

// Projects depending on this code base that wish to extend the list of
// available ids should provide a file local_irep_ids.def in their source tree
Expand Down
45 changes: 45 additions & 0 deletions src/util/std_expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -1662,6 +1662,51 @@ inline union_exprt &to_union_expr(exprt &expr)
return ret;
}

/// \brief Union constructor to support unions without any member (a GCC/Clang
/// feature).
class empty_union_exprt : public nullary_exprt
{
public:
explicit empty_union_exprt(typet _type)
: nullary_exprt(ID_empty_union, std::move(_type))
{
}
};

template <>
inline bool can_cast_expr<empty_union_exprt>(const exprt &base)
{
return base.id() == ID_empty_union;
}

inline void validate_expr(const empty_union_exprt &value)
{
validate_operands(
value, 0, "Empty-union constructor must not have any operand");
}

/// \brief Cast an exprt to an \ref empty_union_exprt
///
/// \a expr must be known to be \ref empty_union_exprt.
///
/// \param expr: Source expression
/// \return Object of type \ref empty_union_exprt
inline const empty_union_exprt &to_empty_union_expr(const exprt &expr)
{
PRECONDITION(expr.id() == ID_empty_union);
const empty_union_exprt &ret = static_cast<const empty_union_exprt &>(expr);
validate_expr(ret);
return ret;
}

/// \copydoc to_empty_union_expr(const exprt &)
inline empty_union_exprt &to_empty_union_expr(exprt &expr)
{
PRECONDITION(expr.id() == ID_empty_union);
empty_union_exprt &ret = static_cast<empty_union_exprt &>(expr);
validate_expr(ret);
return ret;
}

/// \brief Struct constructor from list of elements
class struct_exprt : public multi_ary_exprt
Expand Down