Skip to content

Commit f32d7c2

Browse files
committed
introduce code_with_contract_typet
This documents an existing, informal, variant of code_typet, which is decorated with predicates for code contracts.
1 parent ae4dca8 commit f32d7c2

File tree

3 files changed

+108
-30
lines changed

3 files changed

+108
-30
lines changed

src/ansi-c/c_typecheck_base.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -754,15 +754,19 @@ void c_typecheck_baset::typecheck_declaration(
754754
typecheck_spec_expr(static_cast<codet &>(contract), ID_C_spec_ensures);
755755
parameter_map.clear();
756756

757-
irept assigns_to_add = contract.find(ID_C_spec_assigns);
757+
exprt assigns_to_add =
758+
static_cast<const exprt &>(contract.find(ID_C_spec_assigns));
758759
if(assigns_to_add.is_not_nil())
759-
new_symbol.type.add(ID_C_spec_assigns) = assigns_to_add;
760-
irept requires_to_add = contract.find(ID_C_spec_requires);
760+
to_code_with_contract_type(new_symbol.type).assigns() = assigns_to_add;
761+
exprt requires_to_add =
762+
static_cast<const exprt &>(contract.find(ID_C_spec_requires));
761763
if(requires_to_add.is_not_nil())
762-
new_symbol.type.add(ID_C_spec_requires) = requires_to_add;
763-
irept ensures_to_add = contract.find(ID_C_spec_ensures);
764+
to_code_with_contract_type(new_symbol.type).requires() =
765+
requires_to_add;
766+
exprt ensures_to_add =
767+
static_cast<const exprt &>(contract.find(ID_C_spec_ensures));
764768
if(ensures_to_add.is_not_nil())
765-
new_symbol.type.add(ID_C_spec_ensures) = ensures_to_add;
769+
to_code_with_contract_type(new_symbol.type).ensures() = ensures_to_add;
766770
}
767771
}
768772
}

src/goto-instrument/code_contracts.cpp

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -147,12 +147,8 @@ static void check_apply_invariants(
147147
bool code_contractst::has_contract(const irep_idt fun_name)
148148
{
149149
const symbolt &function_symbol = ns.lookup(fun_name);
150-
const code_typet &type = to_code_type(function_symbol.type);
151-
if(type.find(ID_C_spec_assigns).is_not_nil())
152-
return true;
153-
154-
return type.find(ID_C_spec_requires).is_not_nil() ||
155-
type.find(ID_C_spec_ensures).is_not_nil();
150+
const auto &type = to_code_with_contract_type(function_symbol.type);
151+
return type.has_contract();
156152
}
157153

158154
bool code_contractst::apply_function_contract(
@@ -171,12 +167,12 @@ bool code_contractst::apply_function_contract(
171167
// components.
172168
const irep_idt &function = to_symbol_expr(call.function()).get_identifier();
173169
const symbolt &function_symbol = ns.lookup(function);
174-
const code_typet &type = to_code_type(function_symbol.type);
170+
const auto &type = to_code_with_contract_type(function_symbol.type);
175171

176172
// Isolate each component of the contract.
177-
exprt assigns = static_cast<const exprt &>(type.find(ID_C_spec_assigns));
178-
exprt requires = static_cast<const exprt &>(type.find(ID_C_spec_requires));
179-
exprt ensures = static_cast<const exprt &>(type.find(ID_C_spec_ensures));
173+
exprt assigns = type.assigns();
174+
exprt requires = type.requires();
175+
exprt ensures = type.ensures();
180176

181177
// Check to see if the function contract actually constrains its effect on
182178
// the program state; if not, return.
@@ -359,9 +355,8 @@ void code_contractst::populate_assigns_references(
359355
goto_programt &created_decls,
360356
std::vector<exprt> &created_references)
361357
{
362-
const code_typet &type = to_code_type(function_symbol.type);
363-
const exprt &assigns =
364-
static_cast<const exprt &>(type.find(ID_C_spec_assigns));
358+
const auto &type = to_code_with_contract_type(function_symbol.type);
359+
const exprt &assigns = type.assigns();
365360

366361
const exprt::operandst &targets = assigns.operands();
367362
for(const exprt &curr_op : targets)
@@ -475,7 +470,7 @@ void code_contractst::instrument_call_statement(
475470
}
476471

477472
exprt called_assigns =
478-
static_cast<const exprt &>(called_sym.type.find(ID_C_spec_assigns));
473+
to_code_with_contract_type(called_sym.type).assigns();
479474
if(called_assigns.is_nil()) // Called function has no assigns clause
480475
{
481476
// Fail if called function has no assigns clause.
@@ -618,9 +613,9 @@ bool code_contractst::add_pointer_checks(const std::string &function_name)
618613

619614
const irep_idt function_id(function_name);
620615
const symbolt &function_symbol = ns.lookup(function_id);
621-
const code_typet &type = to_code_type(function_symbol.type);
616+
const auto &type = to_code_with_contract_type(function_symbol.type);
622617

623-
exprt assigns = static_cast<const exprt &>(type.find(ID_C_spec_assigns));
618+
exprt assigns = type.assigns();
624619

625620
// Return if there are no reference checks to perform.
626621
if(assigns.is_nil())
@@ -752,14 +747,11 @@ void code_contractst::add_contract_check(
752747
PRECONDITION(!dest.instructions.empty());
753748

754749
const symbolt &function_symbol = ns.lookup(mangled_fun);
755-
const code_typet &code_type = to_code_type(function_symbol.type);
756-
757-
const exprt &assigns =
758-
static_cast<const exprt &>(code_type.find(ID_C_spec_assigns));
759-
const exprt &requires =
760-
static_cast<const exprt &>(code_type.find(ID_C_spec_requires));
761-
const exprt &ensures =
762-
static_cast<const exprt &>(code_type.find(ID_C_spec_ensures));
750+
const auto &code_type = to_code_with_contract_type(function_symbol.type);
751+
752+
const exprt &assigns = code_type.assigns();
753+
const exprt &requires = code_type.requires();
754+
const exprt &ensures = code_type.ensures();
763755
INVARIANT(
764756
ensures.is_not_nil() || assigns.is_not_nil(),
765757
"Code contract enforcement is trivial without an ensures or assigns "

src/util/c_types.h

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,88 @@ inline c_enum_tag_typet &to_c_enum_tag_type(typet &type)
327327
return static_cast<c_enum_tag_typet &>(type);
328328
}
329329

330+
class code_with_contract_typet : public code_typet
331+
{
332+
public:
333+
/// Constructs a new 'code with contract' type, i.e., a function type
334+
/// decorated with a function contract.
335+
/// \param _parameters: The vector of function parameters.
336+
/// \param _return_type: The return type.
337+
code_with_contract_typet(parameterst _parameters, typet _return_type)
338+
: code_typet(std::move(_parameters), std::move(_return_type))
339+
{
340+
}
341+
342+
bool has_contract() const
343+
{
344+
return assigns().is_not_nil() || requires().is_not_nil() ||
345+
ensures().is_not_nil();
346+
}
347+
348+
const exprt &assigns() const
349+
{
350+
return static_cast<const exprt &>(find(ID_C_spec_assigns));
351+
}
352+
353+
exprt &assigns()
354+
{
355+
return static_cast<exprt &>(add(ID_C_spec_assigns));
356+
}
357+
358+
const exprt &requires() const
359+
{
360+
return static_cast<const exprt &>(find(ID_C_spec_requires));
361+
}
362+
363+
exprt &requires()
364+
{
365+
return static_cast<exprt &>(add(ID_C_spec_requires));
366+
}
367+
368+
const exprt &ensures() const
369+
{
370+
return static_cast<const exprt &>(find(ID_C_spec_ensures));
371+
}
372+
373+
exprt &ensures()
374+
{
375+
return static_cast<exprt &>(add(ID_C_spec_ensures));
376+
}
377+
};
378+
379+
/// Check whether a reference to a typet is a \ref code_typet.
380+
/// \param type: Source type.
381+
/// \return True if \p type is a \ref code_typet.
382+
template <>
383+
inline bool can_cast_type<code_with_contract_typet>(const typet &type)
384+
{
385+
return type.id() == ID_code;
386+
}
387+
388+
/// \brief Cast a typet to a \ref code_with_contract_typet
389+
///
390+
/// This is an unchecked conversion. \a type must be known to be \ref
391+
/// code_with_contract_typet. Will fail with a precondition violation if type
392+
/// doesn't match.
393+
///
394+
/// \param type: Source type.
395+
/// \return Object of type \ref code_with_contract_typet.
396+
inline const code_with_contract_typet &
397+
to_code_with_contract_type(const typet &type)
398+
{
399+
PRECONDITION(can_cast_type<code_with_contract_typet>(type));
400+
code_with_contract_typet::check(type);
401+
return static_cast<const code_with_contract_typet &>(type);
402+
}
403+
404+
/// \copydoc to_code_type(const typet &)
405+
inline code_with_contract_typet &to_code_with_contract_type(typet &type)
406+
{
407+
PRECONDITION(can_cast_type<code_with_contract_typet>(type));
408+
code_with_contract_typet::check(type);
409+
return static_cast<code_with_contract_typet &>(type);
410+
}
411+
330412
bitvector_typet index_type();
331413
bitvector_typet enum_constant_type();
332414
signedbv_typet signed_int_type();

0 commit comments

Comments
 (0)