Skip to content

Commit 76593f8

Browse files
authored
Merge pull request #7533 from tautschnig/cleanup/library-decls
Make CPROVER intrinsics proper prototypes
2 parents e1e7dc7 + 04886f5 commit 76593f8

29 files changed

+327
-284
lines changed

regression/cbmc/enum_is_in_range/enum_test3-simplified.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
CORE new-smt-backend
22
enum_test3.c
33
--show-goto-functions
4-
0 ≤ cast\(main::1::ev1, (un)?signedbv\[\d+\]\) ∧ cast\(main::1::ev1, (un)?signedbv\[\d+\]\) ≤ 4$
4+
0 ≤ cast\(main::1::ev1, (un)?signedbv\[\d+\]\) ∧ cast\(main::1::ev1, (un)?signedbv\[\d+\]\) ≤ 4
55
^EXIT=0$
66
^SIGNAL=0$
77
--

src/ansi-c/c_expr.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ Author: Daniel Kroening, [email protected]
99
#include "c_expr.h"
1010

1111
#include <util/arith_tools.h>
12+
#include <util/c_types.h>
13+
#include <util/namespace.h>
14+
#include <util/simplify_expr.h>
1215

1316
shuffle_vector_exprt::shuffle_vector_exprt(
1417
exprt vector1,
@@ -64,3 +67,19 @@ vector_exprt shuffle_vector_exprt::lower() const
6467

6568
return vector_exprt{std::move(operands), type()};
6669
}
70+
71+
exprt enum_is_in_range_exprt::lower(const namespacet &ns) const
72+
{
73+
const auto &enum_type = to_c_enum_tag_type(op().type());
74+
const c_enum_typet &c_enum_type = ns.follow_tag(enum_type);
75+
const c_enum_typet::memberst enum_values = c_enum_type.members();
76+
77+
exprt::operandst disjuncts;
78+
for(const auto &enum_value : enum_values)
79+
{
80+
constant_exprt val{enum_value.get_value(), enum_type};
81+
disjuncts.push_back(equal_exprt(op(), std::move(val)));
82+
}
83+
84+
return simplify_expr(disjunction(disjuncts), ns);
85+
}

src/ansi-c/c_expr.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,4 +320,54 @@ to_conditional_target_group_expr(exprt &expr)
320320
return ret;
321321
}
322322

323+
/// \brief A Boolean expression returning true, iff the value of an enum-typed
324+
/// symbol equals one of the enum's declared values.
325+
class enum_is_in_range_exprt : public unary_predicate_exprt
326+
{
327+
public:
328+
explicit enum_is_in_range_exprt(exprt _op)
329+
: unary_predicate_exprt(ID_enum_is_in_range, std::move(_op))
330+
{
331+
op().add_source_location().add_pragma("disable:enum-range-check");
332+
}
333+
334+
exprt lower(const namespacet &ns) const;
335+
};
336+
337+
template <>
338+
inline bool can_cast_expr<enum_is_in_range_exprt>(const exprt &base)
339+
{
340+
return base.id() == ID_enum_is_in_range;
341+
}
342+
343+
inline void validate_expr(const enum_is_in_range_exprt &expr)
344+
{
345+
validate_operands(
346+
expr, 1, "enum_is_in_range expression must have one operand");
347+
}
348+
349+
/// \brief Cast an exprt to an \ref enum_is_in_range_exprt
350+
///
351+
/// \a expr must be known to be \ref enum_is_in_range_exprt.
352+
///
353+
/// \param expr: Source expression
354+
/// \return Object of type \ref enum_is_in_range_exprt
355+
inline const enum_is_in_range_exprt &to_enum_is_in_range_expr(const exprt &expr)
356+
{
357+
PRECONDITION(expr.id() == ID_enum_is_in_range);
358+
const enum_is_in_range_exprt &ret =
359+
static_cast<const enum_is_in_range_exprt &>(expr);
360+
validate_expr(ret);
361+
return ret;
362+
}
363+
364+
/// \copydoc to_side_effect_expr_overflow(const exprt &)
365+
inline enum_is_in_range_exprt &to_enum_is_in_range_expr(exprt &expr)
366+
{
367+
PRECONDITION(expr.id() == ID_enum_is_in_range);
368+
enum_is_in_range_exprt &ret = static_cast<enum_is_in_range_exprt &>(expr);
369+
validate_expr(ret);
370+
return ret;
371+
}
372+
323373
#endif // CPROVER_ANSI_C_C_EXPR_H

src/ansi-c/c_typecheck_expr.cpp

Lines changed: 107 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -2118,6 +2118,106 @@ void c_typecheck_baset::typecheck_side_effect_function_call(
21182118

21192119
return;
21202120
}
2121+
else if(identifier == CPROVER_PREFIX "equal")
2122+
{
2123+
if(expr.arguments().size() != 2)
2124+
{
2125+
error().source_location = f_op.source_location();
2126+
error() << "equal expects two operands" << eom;
2127+
throw 0;
2128+
}
2129+
2130+
equal_exprt equality_expr(
2131+
expr.arguments().front(), expr.arguments().back());
2132+
equality_expr.add_source_location() = expr.source_location();
2133+
2134+
if(equality_expr.lhs().type() != equality_expr.rhs().type())
2135+
{
2136+
error().source_location = f_op.source_location();
2137+
error() << "equal expects two operands of same type" << eom;
2138+
throw 0;
2139+
}
2140+
2141+
expr.swap(equality_expr);
2142+
return;
2143+
}
2144+
else if(
2145+
identifier == CPROVER_PREFIX "overflow_minus" ||
2146+
identifier == CPROVER_PREFIX "overflow_mult" ||
2147+
identifier == CPROVER_PREFIX "overflow_plus" ||
2148+
identifier == CPROVER_PREFIX "overflow_shl")
2149+
{
2150+
exprt overflow{identifier, typet{}, exprt::operandst{expr.arguments()}};
2151+
overflow.add_source_location() = f_op.source_location();
2152+
2153+
if(identifier == CPROVER_PREFIX "overflow_minus")
2154+
{
2155+
overflow.id(ID_minus);
2156+
typecheck_expr_binary_arithmetic(overflow);
2157+
}
2158+
else if(identifier == CPROVER_PREFIX "overflow_mult")
2159+
{
2160+
overflow.id(ID_mult);
2161+
typecheck_expr_binary_arithmetic(overflow);
2162+
}
2163+
else if(identifier == CPROVER_PREFIX "overflow_plus")
2164+
{
2165+
overflow.id(ID_plus);
2166+
typecheck_expr_binary_arithmetic(overflow);
2167+
}
2168+
else if(identifier == CPROVER_PREFIX "overflow_shl")
2169+
{
2170+
overflow.id(ID_shl);
2171+
typecheck_expr_shifts(to_shift_expr(overflow));
2172+
}
2173+
2174+
binary_overflow_exprt of{
2175+
overflow.operands()[0], overflow.id(), overflow.operands()[1]};
2176+
of.add_source_location() = overflow.source_location();
2177+
expr.swap(of);
2178+
return;
2179+
}
2180+
else if(identifier == CPROVER_PREFIX "overflow_unary_minus")
2181+
{
2182+
exprt tmp{ID_unary_minus, typet{}, exprt::operandst{expr.arguments()}};
2183+
tmp.add_source_location() = f_op.source_location();
2184+
2185+
typecheck_expr_unary_arithmetic(tmp);
2186+
2187+
unary_minus_overflow_exprt overflow{tmp.operands().front()};
2188+
overflow.add_source_location() = tmp.source_location();
2189+
expr.swap(overflow);
2190+
return;
2191+
}
2192+
else if(identifier == CPROVER_PREFIX "enum_is_in_range")
2193+
{
2194+
// Check correct number of arguments
2195+
if(expr.arguments().size() != 1)
2196+
{
2197+
std::ostringstream error_message;
2198+
error_message << identifier << " takes exactly 1 argument, but "
2199+
<< expr.arguments().size() << " were provided";
2200+
throw invalid_source_file_exceptiont{
2201+
error_message.str(), expr.source_location()};
2202+
}
2203+
const auto &arg1 = expr.arguments()[0];
2204+
if(!can_cast_type<c_enum_tag_typet>(arg1.type()))
2205+
{
2206+
// Can't enum range check a non-enum
2207+
std::ostringstream error_message;
2208+
error_message << identifier << " expects enum, but ("
2209+
<< expr2c(arg1, *this) << ") has type `"
2210+
<< type2c(arg1.type(), *this) << '`';
2211+
throw invalid_source_file_exceptiont{
2212+
error_message.str(), expr.source_location()};
2213+
}
2214+
2215+
enum_is_in_range_exprt in_range{arg1};
2216+
in_range.add_source_location() = expr.source_location();
2217+
exprt lowered = in_range.lower(*this);
2218+
expr.swap(lowered);
2219+
return;
2220+
}
21212221
else if(
21222222
auto gcc_polymorphic = typecheck_gcc_polymorphic_builtin(
21232223
identifier, expr.arguments(), f_op.source_location()))
@@ -2534,11 +2634,15 @@ exprt c_typecheck_baset::do_special_functions(
25342634

25352635
typecheck_function_call_arguments(expr);
25362636

2637+
exprt::operandst args_no_cast;
2638+
args_no_cast.reserve(expr.arguments().size());
25372639
for(const auto &argument : expr.arguments())
25382640
{
2641+
args_no_cast.push_back(skip_typecast(argument));
25392642
if(
2540-
argument.type().id() != ID_pointer ||
2541-
to_pointer_type(argument.type()).base_type().id() != ID_struct_tag)
2643+
args_no_cast.back().type().id() != ID_pointer ||
2644+
to_pointer_type(args_no_cast.back().type()).base_type().id() !=
2645+
ID_struct_tag)
25422646
{
25432647
error().source_location = expr.arguments()[0].source_location();
25442648
error() << "is_sentinel_dll_node expects struct-pointer operands"
@@ -2548,7 +2652,7 @@ exprt c_typecheck_baset::do_special_functions(
25482652
}
25492653

25502654
predicate_exprt is_sentinel_dll_expr("is_sentinel_dll");
2551-
is_sentinel_dll_expr.operands() = expr.arguments();
2655+
is_sentinel_dll_expr.operands() = args_no_cast;
25522656
is_sentinel_dll_expr.add_source_location() = source_location;
25532657

25542658
return std::move(is_sentinel_dll_expr);
@@ -3324,30 +3428,6 @@ exprt c_typecheck_baset::do_special_functions(
33243428

33253429
return std::move(ffs);
33263430
}
3327-
else if(identifier==CPROVER_PREFIX "equal")
3328-
{
3329-
if(expr.arguments().size()!=2)
3330-
{
3331-
error().source_location = f_op.source_location();
3332-
error() << "equal expects two operands" << eom;
3333-
throw 0;
3334-
}
3335-
3336-
typecheck_function_call_arguments(expr);
3337-
3338-
equal_exprt equality_expr(
3339-
expr.arguments().front(), expr.arguments().back());
3340-
equality_expr.add_source_location()=source_location;
3341-
3342-
if(equality_expr.lhs().type() != equality_expr.rhs().type())
3343-
{
3344-
error().source_location = f_op.source_location();
3345-
error() << "equal expects two operands of same type" << eom;
3346-
throw 0;
3347-
}
3348-
3349-
return std::move(equality_expr);
3350-
}
33513431
else if(identifier=="__builtin_expect")
33523432
{
33533433
// This is a gcc extension to provide branch prediction.
@@ -3533,80 +3613,6 @@ exprt c_typecheck_baset::do_special_functions(
35333613

35343614
return tmp;
35353615
}
3536-
else if(
3537-
identifier == CPROVER_PREFIX "overflow_minus" ||
3538-
identifier == CPROVER_PREFIX "overflow_mult" ||
3539-
identifier == CPROVER_PREFIX "overflow_plus" ||
3540-
identifier == CPROVER_PREFIX "overflow_shl")
3541-
{
3542-
exprt overflow{identifier, typet{}, exprt::operandst{expr.arguments()}};
3543-
overflow.add_source_location() = f_op.source_location();
3544-
3545-
if(identifier == CPROVER_PREFIX "overflow_minus")
3546-
{
3547-
overflow.id(ID_minus);
3548-
typecheck_expr_binary_arithmetic(overflow);
3549-
}
3550-
else if(identifier == CPROVER_PREFIX "overflow_mult")
3551-
{
3552-
overflow.id(ID_mult);
3553-
typecheck_expr_binary_arithmetic(overflow);
3554-
}
3555-
else if(identifier == CPROVER_PREFIX "overflow_plus")
3556-
{
3557-
overflow.id(ID_plus);
3558-
typecheck_expr_binary_arithmetic(overflow);
3559-
}
3560-
else if(identifier == CPROVER_PREFIX "overflow_shl")
3561-
{
3562-
overflow.id(ID_shl);
3563-
typecheck_expr_shifts(to_shift_expr(overflow));
3564-
}
3565-
3566-
binary_overflow_exprt of{
3567-
overflow.operands()[0], overflow.id(), overflow.operands()[1]};
3568-
of.add_source_location() = overflow.source_location();
3569-
return std::move(of);
3570-
}
3571-
else if(identifier == CPROVER_PREFIX "overflow_unary_minus")
3572-
{
3573-
exprt tmp{ID_unary_minus, typet{}, exprt::operandst{expr.arguments()}};
3574-
tmp.add_source_location() = f_op.source_location();
3575-
3576-
typecheck_expr_unary_arithmetic(tmp);
3577-
3578-
unary_minus_overflow_exprt overflow{tmp.operands().front()};
3579-
overflow.add_source_location() = tmp.source_location();
3580-
return std::move(overflow);
3581-
}
3582-
else if(identifier == CPROVER_PREFIX "enum_is_in_range")
3583-
{
3584-
// Check correct number of arguments
3585-
if(expr.arguments().size() != 1)
3586-
{
3587-
std::ostringstream error_message;
3588-
error_message << identifier << " takes exactly 1 argument, but "
3589-
<< expr.arguments().size() << " were provided";
3590-
throw invalid_source_file_exceptiont{
3591-
error_message.str(), expr.source_location()};
3592-
}
3593-
auto arg1 = expr.arguments()[0];
3594-
typecheck_expr(arg1);
3595-
if(!can_cast_type<c_enum_tag_typet>(arg1.type()))
3596-
{
3597-
// Can't enum range check a non-enum
3598-
std::ostringstream error_message;
3599-
error_message << identifier << " expects enum, but ("
3600-
<< expr2c(arg1, *this) << ") has type `"
3601-
<< type2c(arg1.type(), *this) << '`';
3602-
throw invalid_source_file_exceptiont{
3603-
error_message.str(), expr.source_location()};
3604-
}
3605-
else
3606-
{
3607-
return expr;
3608-
}
3609-
}
36103616
else if(
36113617
identifier == "__builtin_add_overflow" ||
36123618
identifier == "__builtin_sadd_overflow" ||

0 commit comments

Comments
 (0)