Merge pull request #2723 from tautschnig/replace_symbol-cleanup
replace_symbolt refactoring and stricter type checking
This commit is contained in:
commit
ef7e55bf48
|
@ -0,0 +1,9 @@
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
int *p = &i;
|
||||||
|
assert(*p == 0);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
CORE
|
||||||
|
main.c
|
||||||
|
--constant-propagator
|
||||||
|
^EXIT=0$
|
||||||
|
^SIGNAL=0$
|
||||||
|
VERIFICATION SUCCESSFUL
|
||||||
|
--
|
||||||
|
^warning: ignoring
|
|
@ -81,7 +81,7 @@ public:
|
||||||
struct valuest
|
struct valuest
|
||||||
{
|
{
|
||||||
// maps variables to constants
|
// maps variables to constants
|
||||||
replace_symbolt replace_const;
|
address_of_aware_replace_symbolt replace_const;
|
||||||
bool is_bottom = true;
|
bool is_bottom = true;
|
||||||
|
|
||||||
bool merge(const valuest &src);
|
bool merge(const valuest &src);
|
||||||
|
|
|
@ -189,7 +189,10 @@ void code_contractst::apply_contract(
|
||||||
|
|
||||||
// TODO: return value could be nil
|
// TODO: return value could be nil
|
||||||
if(type.return_type()!=empty_typet())
|
if(type.return_type()!=empty_typet())
|
||||||
replace.insert("__CPROVER_return_value", call.lhs());
|
{
|
||||||
|
symbol_exprt ret_val(CPROVER_PREFIX "return_value", call.lhs().type());
|
||||||
|
replace.insert(ret_val, call.lhs());
|
||||||
|
}
|
||||||
|
|
||||||
// formal parameters
|
// formal parameters
|
||||||
code_function_callt::argumentst::const_iterator a_it=
|
code_function_callt::argumentst::const_iterator a_it=
|
||||||
|
@ -200,7 +203,10 @@ void code_contractst::apply_contract(
|
||||||
a_it!=call.arguments().end();
|
a_it!=call.arguments().end();
|
||||||
++p_it, ++a_it)
|
++p_it, ++a_it)
|
||||||
if(!p_it->get_identifier().empty())
|
if(!p_it->get_identifier().empty())
|
||||||
replace.insert(p_it->get_identifier(), *a_it);
|
{
|
||||||
|
symbol_exprt p(p_it->get_identifier(), p_it->type());
|
||||||
|
replace.insert(p, *a_it);
|
||||||
|
}
|
||||||
|
|
||||||
replace(requires);
|
replace(requires);
|
||||||
replace(ensures);
|
replace(ensures);
|
||||||
|
@ -318,7 +324,8 @@ void code_contractst::add_contract_check(
|
||||||
|
|
||||||
call.lhs()=r;
|
call.lhs()=r;
|
||||||
|
|
||||||
replace.insert("__CPROVER_return_value", r);
|
symbol_exprt ret_val(CPROVER_PREFIX "return_value", call.lhs().type());
|
||||||
|
replace.insert(ret_val, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
// decl parameter1 ...
|
// decl parameter1 ...
|
||||||
|
@ -339,7 +346,10 @@ void code_contractst::add_contract_check(
|
||||||
call.arguments().push_back(p);
|
call.arguments().push_back(p);
|
||||||
|
|
||||||
if(!p_it->get_identifier().empty())
|
if(!p_it->get_identifier().empty())
|
||||||
replace.insert(p_it->get_identifier(), p);
|
{
|
||||||
|
symbol_exprt cur_p(p_it->get_identifier(), p_it->type());
|
||||||
|
replace.insert(cur_p, p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// assume(requires)
|
// assume(requires)
|
||||||
|
|
|
@ -89,11 +89,9 @@ void concurrency_instrumentationt::instrument(exprt &expr)
|
||||||
{
|
{
|
||||||
if(s_it->id()==ID_symbol)
|
if(s_it->id()==ID_symbol)
|
||||||
{
|
{
|
||||||
const irep_idt identifier=
|
const symbol_exprt &s = to_symbol_expr(*s_it);
|
||||||
to_symbol_expr(*s_it).get_identifier();
|
|
||||||
|
|
||||||
shared_varst::const_iterator
|
shared_varst::const_iterator v_it = shared_vars.find(s.get_identifier());
|
||||||
v_it=shared_vars.find(identifier);
|
|
||||||
|
|
||||||
if(v_it!=shared_vars.end())
|
if(v_it!=shared_vars.end())
|
||||||
{
|
{
|
||||||
|
@ -101,7 +99,7 @@ void concurrency_instrumentationt::instrument(exprt &expr)
|
||||||
// new_expr.array()=symbol_expr();
|
// new_expr.array()=symbol_expr();
|
||||||
// new_expr.index()=symbol_expr();
|
// new_expr.index()=symbol_expr();
|
||||||
|
|
||||||
replace_symbol.insert(identifier, new_expr);
|
replace_symbol.insert(s, new_expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -915,7 +915,7 @@ void dump_ct::cleanup_harness(code_blockt &b)
|
||||||
if(!ns.lookup("argc'", argc_sym))
|
if(!ns.lookup("argc'", argc_sym))
|
||||||
{
|
{
|
||||||
symbol_exprt argc("argc", argc_sym->type);
|
symbol_exprt argc("argc", argc_sym->type);
|
||||||
replace.insert(argc_sym->name, argc);
|
replace.insert(argc_sym->symbol_expr(), argc);
|
||||||
code_declt d(argc);
|
code_declt d(argc);
|
||||||
decls.add(d);
|
decls.add(d);
|
||||||
}
|
}
|
||||||
|
@ -923,7 +923,10 @@ void dump_ct::cleanup_harness(code_blockt &b)
|
||||||
if(!ns.lookup("argv'", argv_sym))
|
if(!ns.lookup("argv'", argv_sym))
|
||||||
{
|
{
|
||||||
symbol_exprt argv("argv", argv_sym->type);
|
symbol_exprt argv("argv", argv_sym->type);
|
||||||
replace.insert(argv_sym->name, argv);
|
// replace argc' by argc in the type of argv['] to maintain type consistency
|
||||||
|
// while replacing
|
||||||
|
replace(argv);
|
||||||
|
replace.insert(symbol_exprt(argv_sym->name, argv.type()), argv);
|
||||||
code_declt d(argv);
|
code_declt d(argv);
|
||||||
decls.add(d);
|
decls.add(d);
|
||||||
}
|
}
|
||||||
|
@ -931,7 +934,7 @@ void dump_ct::cleanup_harness(code_blockt &b)
|
||||||
if(!ns.lookup("return'", return_sym))
|
if(!ns.lookup("return'", return_sym))
|
||||||
{
|
{
|
||||||
symbol_exprt return_value("return_value", return_sym->type);
|
symbol_exprt return_value("return_value", return_sym->type);
|
||||||
replace.insert(return_sym->name, return_value);
|
replace.insert(return_sym->symbol_expr(), return_value);
|
||||||
code_declt d(return_value);
|
code_declt d(return_value);
|
||||||
decls.add(d);
|
decls.add(d);
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,11 @@ bool model_argc_argv(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const symbolt &argc_primed = ns.lookup("argc'");
|
||||||
|
symbol_exprt ARGC("ARGC", argc_primed.type);
|
||||||
|
const symbolt &argv_primed = ns.lookup("argv'");
|
||||||
|
symbol_exprt ARGV("ARGV", argv_primed.type);
|
||||||
|
|
||||||
// set the size of ARGV storage to 4096, which matches the minimum
|
// set the size of ARGV storage to 4096, which matches the minimum
|
||||||
// guaranteed by POSIX (_POSIX_ARG_MAX):
|
// guaranteed by POSIX (_POSIX_ARG_MAX):
|
||||||
// http://pubs.opengroup.org/onlinepubs/009695399/basedefs/limits.h.html
|
// http://pubs.opengroup.org/onlinepubs/009695399/basedefs/limits.h.html
|
||||||
|
@ -125,9 +130,9 @@ bool model_argc_argv(
|
||||||
{
|
{
|
||||||
value = symbol_pair.second.value;
|
value = symbol_pair.second.value;
|
||||||
|
|
||||||
replace_symbolt replace;
|
unchecked_replace_symbolt replace;
|
||||||
replace.insert("ARGC", ns.lookup("argc'").symbol_expr());
|
replace.insert(ARGC, ns.lookup("argc'").symbol_expr());
|
||||||
replace.insert("ARGV", ns.lookup("argv'").symbol_expr());
|
replace.insert(ARGV, ns.lookup("argv'").symbol_expr());
|
||||||
replace(value);
|
replace(value);
|
||||||
}
|
}
|
||||||
else if(
|
else if(
|
||||||
|
|
|
@ -993,7 +993,8 @@ void linkingt::duplicate_object_symbol(
|
||||||
else if(set_to_new)
|
else if(set_to_new)
|
||||||
old_symbol.type=new_symbol.type;
|
old_symbol.type=new_symbol.type;
|
||||||
|
|
||||||
object_type_updates.insert(old_symbol.name, old_symbol.symbol_expr());
|
object_type_updates.insert(
|
||||||
|
old_symbol.symbol_expr(), old_symbol.symbol_expr());
|
||||||
}
|
}
|
||||||
|
|
||||||
// care about initializers
|
// care about initializers
|
||||||
|
|
|
@ -35,7 +35,7 @@ public:
|
||||||
virtual void typecheck();
|
virtual void typecheck();
|
||||||
|
|
||||||
rename_symbolt rename_symbol;
|
rename_symbolt rename_symbol;
|
||||||
replace_symbolt object_type_updates;
|
unchecked_replace_symbolt object_type_updates;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool needs_renaming_type(
|
bool needs_renaming_type(
|
||||||
|
|
|
@ -79,7 +79,7 @@ static exprt unpack_rec(
|
||||||
{
|
{
|
||||||
index_exprt index(src, from_integer(i, index_type()));
|
index_exprt index(src, from_integer(i, index_type()));
|
||||||
replace_symbolt replace;
|
replace_symbolt replace;
|
||||||
replace.insert(ID_C_incomplete, index);
|
replace.insert(dummy, index);
|
||||||
|
|
||||||
for(const auto &op : sub.operands())
|
for(const auto &op : sub.operands())
|
||||||
{
|
{
|
||||||
|
|
|
@ -106,10 +106,9 @@ void smt2_solvert::expand_function_applications(exprt &expr)
|
||||||
std::map<irep_idt, exprt> parameter_map;
|
std::map<irep_idt, exprt> parameter_map;
|
||||||
for(std::size_t i=0; i<f_type.domain().size(); i++)
|
for(std::size_t i=0; i<f_type.domain().size(); i++)
|
||||||
{
|
{
|
||||||
const irep_idt p_identifier=
|
const auto &var = f_type.domain()[i];
|
||||||
f_type.domain()[i].get_identifier();
|
const symbol_exprt s(var.get_identifier(), var.type());
|
||||||
|
replace_symbol.insert(s, app.arguments()[i]);
|
||||||
replace_symbol.insert(p_identifier, app.arguments()[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exprt body=f.definition;
|
exprt body=f.definition;
|
||||||
|
|
|
@ -8,8 +8,9 @@ Author: Daniel Kroening, kroening@kroening.com
|
||||||
|
|
||||||
#include "replace_symbol.h"
|
#include "replace_symbol.h"
|
||||||
|
|
||||||
#include "std_types.h"
|
#include "invariant.h"
|
||||||
#include "std_expr.h"
|
#include "std_expr.h"
|
||||||
|
#include "std_types.h"
|
||||||
|
|
||||||
replace_symbolt::replace_symbolt()
|
replace_symbolt::replace_symbolt()
|
||||||
{
|
{
|
||||||
|
@ -23,13 +24,27 @@ void replace_symbolt::insert(
|
||||||
const symbol_exprt &old_expr,
|
const symbol_exprt &old_expr,
|
||||||
const exprt &new_expr)
|
const exprt &new_expr)
|
||||||
{
|
{
|
||||||
|
PRECONDITION(old_expr.type() == new_expr.type());
|
||||||
expr_map.insert(std::pair<irep_idt, exprt>(
|
expr_map.insert(std::pair<irep_idt, exprt>(
|
||||||
old_expr.get_identifier(), new_expr));
|
old_expr.get_identifier(), new_expr));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool replace_symbolt::replace(
|
bool replace_symbolt::replace_symbol_expr(symbol_exprt &s) const
|
||||||
exprt &dest,
|
{
|
||||||
const bool replace_with_const) const
|
expr_mapt::const_iterator it = expr_map.find(s.get_identifier());
|
||||||
|
|
||||||
|
if(it == expr_map.end())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
DATA_INVARIANT(
|
||||||
|
s.type() == it->second.type(),
|
||||||
|
"type of symbol to be replaced should match");
|
||||||
|
static_cast<exprt &>(s) = it->second;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool replace_symbolt::replace(exprt &dest) const
|
||||||
{
|
{
|
||||||
bool result=true; // unchanged
|
bool result=true; // unchanged
|
||||||
|
|
||||||
|
@ -49,14 +64,14 @@ bool replace_symbolt::replace(
|
||||||
{
|
{
|
||||||
member_exprt &me=to_member_expr(dest);
|
member_exprt &me=to_member_expr(dest);
|
||||||
|
|
||||||
if(!replace(me.struct_op(), replace_with_const)) // Could give non l-value.
|
if(!replace(me.struct_op()))
|
||||||
result=false;
|
result=false;
|
||||||
}
|
}
|
||||||
else if(dest.id()==ID_index)
|
else if(dest.id()==ID_index)
|
||||||
{
|
{
|
||||||
index_exprt &ie=to_index_expr(dest);
|
index_exprt &ie=to_index_expr(dest);
|
||||||
|
|
||||||
if(!replace(ie.array(), replace_with_const)) // Could give non l-value.
|
if(!replace(ie.array()))
|
||||||
result=false;
|
result=false;
|
||||||
|
|
||||||
if(!replace(ie.index()))
|
if(!replace(ie.index()))
|
||||||
|
@ -66,27 +81,13 @@ bool replace_symbolt::replace(
|
||||||
{
|
{
|
||||||
address_of_exprt &aoe=to_address_of_expr(dest);
|
address_of_exprt &aoe=to_address_of_expr(dest);
|
||||||
|
|
||||||
if(!replace(aoe.object(), false))
|
if(!replace(aoe.object()))
|
||||||
result=false;
|
result=false;
|
||||||
}
|
}
|
||||||
else if(dest.id()==ID_symbol)
|
else if(dest.id()==ID_symbol)
|
||||||
{
|
{
|
||||||
const symbol_exprt &s=to_symbol_expr(dest);
|
if(!replace_symbol_expr(to_symbol_expr(dest)))
|
||||||
|
|
||||||
expr_mapt::const_iterator it=
|
|
||||||
expr_map.find(s.get_identifier());
|
|
||||||
|
|
||||||
if(it!=expr_map.end())
|
|
||||||
{
|
|
||||||
const exprt &e=it->second;
|
|
||||||
|
|
||||||
if(!replace_with_const && e.is_constant()) // Would give non l-value.
|
|
||||||
return true;
|
|
||||||
|
|
||||||
dest=e;
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -110,7 +111,7 @@ bool replace_symbolt::replace(
|
||||||
|
|
||||||
bool replace_symbolt::have_to_replace(const exprt &dest) const
|
bool replace_symbolt::have_to_replace(const exprt &dest) const
|
||||||
{
|
{
|
||||||
if(expr_map.empty() && type_map.empty())
|
if(expr_map.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// first look at type
|
// first look at type
|
||||||
|
@ -186,17 +187,6 @@ bool replace_symbolt::replace(typet &dest) const
|
||||||
if(!replace(*it))
|
if(!replace(*it))
|
||||||
result=false;
|
result=false;
|
||||||
}
|
}
|
||||||
else if(dest.id() == ID_symbol_type)
|
|
||||||
{
|
|
||||||
type_mapt::const_iterator it =
|
|
||||||
type_map.find(to_symbol_type(dest).get_identifier());
|
|
||||||
|
|
||||||
if(it!=type_map.end())
|
|
||||||
{
|
|
||||||
dest=it->second;
|
|
||||||
result=false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(dest.id()==ID_array)
|
else if(dest.id()==ID_array)
|
||||||
{
|
{
|
||||||
array_typet &array_type=to_array_type(dest);
|
array_typet &array_type=to_array_type(dest);
|
||||||
|
@ -209,7 +199,7 @@ bool replace_symbolt::replace(typet &dest) const
|
||||||
|
|
||||||
bool replace_symbolt::have_to_replace(const typet &dest) const
|
bool replace_symbolt::have_to_replace(const typet &dest) const
|
||||||
{
|
{
|
||||||
if(expr_map.empty() && type_map.empty())
|
if(expr_map.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(dest.has_subtype())
|
if(dest.has_subtype())
|
||||||
|
@ -251,13 +241,109 @@ bool replace_symbolt::have_to_replace(const typet &dest) const
|
||||||
if(have_to_replace(*it))
|
if(have_to_replace(*it))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if(dest.id() == ID_symbol_type)
|
|
||||||
{
|
|
||||||
const irep_idt &identifier = to_symbol_type(dest).get_identifier();
|
|
||||||
return type_map.find(identifier) != type_map.end();
|
|
||||||
}
|
|
||||||
else if(dest.id()==ID_array)
|
else if(dest.id()==ID_array)
|
||||||
return have_to_replace(to_array_type(dest).size());
|
return have_to_replace(to_array_type(dest).size());
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void unchecked_replace_symbolt::insert(
|
||||||
|
const symbol_exprt &old_expr,
|
||||||
|
const exprt &new_expr)
|
||||||
|
{
|
||||||
|
expr_map.emplace(old_expr.get_identifier(), new_expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool unchecked_replace_symbolt::replace_symbol_expr(symbol_exprt &s) const
|
||||||
|
{
|
||||||
|
expr_mapt::const_iterator it = expr_map.find(s.get_identifier());
|
||||||
|
|
||||||
|
if(it == expr_map.end())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
static_cast<exprt &>(s) = it->second;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool address_of_aware_replace_symbolt::replace(exprt &dest) const
|
||||||
|
{
|
||||||
|
const exprt &const_dest(dest);
|
||||||
|
if(!require_lvalue && const_dest.id() != ID_address_of)
|
||||||
|
return unchecked_replace_symbolt::replace(dest);
|
||||||
|
|
||||||
|
bool result = true; // unchanged
|
||||||
|
|
||||||
|
// first look at type
|
||||||
|
if(have_to_replace(const_dest.type()))
|
||||||
|
{
|
||||||
|
const set_require_lvalue_and_backupt backup(require_lvalue, false);
|
||||||
|
if(!unchecked_replace_symbolt::replace(dest.type()))
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now do expression itself
|
||||||
|
|
||||||
|
if(!have_to_replace(dest))
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if(dest.id() == ID_index)
|
||||||
|
{
|
||||||
|
index_exprt &ie = to_index_expr(dest);
|
||||||
|
|
||||||
|
// Could yield non l-value.
|
||||||
|
if(!replace(ie.array()))
|
||||||
|
result = false;
|
||||||
|
|
||||||
|
const set_require_lvalue_and_backupt backup(require_lvalue, false);
|
||||||
|
if(!replace(ie.index()))
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
else if(dest.id() == ID_address_of)
|
||||||
|
{
|
||||||
|
address_of_exprt &aoe = to_address_of_expr(dest);
|
||||||
|
|
||||||
|
const set_require_lvalue_and_backupt backup(require_lvalue, true);
|
||||||
|
if(!replace(aoe.object()))
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!unchecked_replace_symbolt::replace(dest))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const set_require_lvalue_and_backupt backup(require_lvalue, false);
|
||||||
|
|
||||||
|
const typet &c_sizeof_type =
|
||||||
|
static_cast<const typet &>(dest.find(ID_C_c_sizeof_type));
|
||||||
|
if(c_sizeof_type.is_not_nil() && have_to_replace(c_sizeof_type))
|
||||||
|
result &= unchecked_replace_symbolt::replace(
|
||||||
|
static_cast<typet &>(dest.add(ID_C_c_sizeof_type)));
|
||||||
|
|
||||||
|
const typet &va_arg_type =
|
||||||
|
static_cast<const typet &>(dest.find(ID_C_va_arg_type));
|
||||||
|
if(va_arg_type.is_not_nil() && have_to_replace(va_arg_type))
|
||||||
|
result &= unchecked_replace_symbolt::replace(
|
||||||
|
static_cast<typet &>(dest.add(ID_C_va_arg_type)));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool address_of_aware_replace_symbolt::replace_symbol_expr(
|
||||||
|
symbol_exprt &s) const
|
||||||
|
{
|
||||||
|
expr_mapt::const_iterator it = expr_map.find(s.get_identifier());
|
||||||
|
|
||||||
|
if(it == expr_map.end())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const exprt &e = it->second;
|
||||||
|
|
||||||
|
if(require_lvalue && e.is_constant()) // Would give non l-value.
|
||||||
|
return true;
|
||||||
|
|
||||||
|
static_cast<exprt &>(s) = e;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -20,43 +20,16 @@ Author: Daniel Kroening, kroening@kroening.com
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
/// Replace expression or type symbols by an expression or type, respectively.
|
/// Replace expression or type symbols by an expression or type, respectively.
|
||||||
|
/// The resolved type of the symbol must match the type of the replacement.
|
||||||
class replace_symbolt
|
class replace_symbolt
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef std::unordered_map<irep_idt, exprt> expr_mapt;
|
typedef std::unordered_map<irep_idt, exprt> expr_mapt;
|
||||||
typedef std::unordered_map<irep_idt, typet> type_mapt;
|
|
||||||
|
|
||||||
void insert(const irep_idt &identifier,
|
|
||||||
const exprt &expr)
|
|
||||||
{
|
|
||||||
expr_map.insert(std::pair<irep_idt, exprt>(identifier, expr));
|
|
||||||
}
|
|
||||||
|
|
||||||
void insert(const class symbol_exprt &old_expr,
|
void insert(const class symbol_exprt &old_expr,
|
||||||
const exprt &new_expr);
|
const exprt &new_expr);
|
||||||
|
|
||||||
void insert(const irep_idt &identifier,
|
virtual bool replace(exprt &dest) const;
|
||||||
const typet &type)
|
|
||||||
{
|
|
||||||
type_map.insert(std::pair<irep_idt, typet>(identifier, type));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Replaces a symbol with a constant
|
|
||||||
/// If you are replacing symbols with constants in an l-value, you can
|
|
||||||
/// create something that is not an l-value. For example if your
|
|
||||||
/// l-value is "a[i]" then substituting i for a constant results in an
|
|
||||||
/// l-value but substituting a for a constant (array) wouldn't. This
|
|
||||||
/// only applies to the "top level" of the expression, for example, it
|
|
||||||
/// is OK to replace b with a constant array in a[b[0]].
|
|
||||||
///
|
|
||||||
/// \param dest The expression in which to do the replacement
|
|
||||||
/// \param replace_with_const If false then it disables the rewrites that
|
|
||||||
/// could result in something that is not an l-value.
|
|
||||||
///
|
|
||||||
virtual bool replace(
|
|
||||||
exprt &dest,
|
|
||||||
const bool replace_with_const=true) const;
|
|
||||||
|
|
||||||
virtual bool replace(typet &dest) const;
|
virtual bool replace(typet &dest) const;
|
||||||
|
|
||||||
void operator()(exprt &dest) const
|
void operator()(exprt &dest) const
|
||||||
|
@ -72,23 +45,21 @@ public:
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
expr_map.clear();
|
expr_map.clear();
|
||||||
type_map.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() const
|
bool empty() const
|
||||||
{
|
{
|
||||||
return expr_map.empty() && type_map.empty();
|
return expr_map.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t erase(const irep_idt &id)
|
std::size_t erase(const irep_idt &id)
|
||||||
{
|
{
|
||||||
return expr_map.erase(id) + type_map.erase(id);
|
return expr_map.erase(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool replaces_symbol(const irep_idt &id) const
|
bool replaces_symbol(const irep_idt &id) const
|
||||||
{
|
{
|
||||||
return expr_map.find(id) != expr_map.end() ||
|
return expr_map.find(id) != expr_map.end();
|
||||||
type_map.find(id) != type_map.end();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
replace_symbolt();
|
replace_symbolt();
|
||||||
|
@ -106,11 +77,62 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
expr_mapt expr_map;
|
expr_mapt expr_map;
|
||||||
type_mapt type_map;
|
|
||||||
|
|
||||||
protected:
|
virtual bool replace_symbol_expr(symbol_exprt &dest) const;
|
||||||
|
|
||||||
bool have_to_replace(const exprt &dest) const;
|
bool have_to_replace(const exprt &dest) const;
|
||||||
bool have_to_replace(const typet &type) const;
|
bool have_to_replace(const typet &type) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class unchecked_replace_symbolt : public replace_symbolt
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
unchecked_replace_symbolt()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(const symbol_exprt &old_expr, const exprt &new_expr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool replace_symbol_expr(symbol_exprt &dest) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Replace symbols with constants while maintaining syntactically valid
|
||||||
|
/// expressions.
|
||||||
|
/// If you are replacing symbols with constants in an l-value, you can
|
||||||
|
/// create something that is not an l-value. For example if your
|
||||||
|
/// l-value is "a[i]" then substituting i for a constant results in an
|
||||||
|
/// l-value but substituting a for a constant (array) wouldn't. This
|
||||||
|
/// only applies to the "top level" of the expression, for example, it
|
||||||
|
/// is OK to replace b with a constant array in a[b[0]].
|
||||||
|
class address_of_aware_replace_symbolt : public unchecked_replace_symbolt
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool replace(exprt &dest) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable bool require_lvalue = false;
|
||||||
|
|
||||||
|
class set_require_lvalue_and_backupt
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
set_require_lvalue_and_backupt(bool &require_lvalue, const bool value)
|
||||||
|
: require_lvalue(require_lvalue), prev_value(require_lvalue)
|
||||||
|
{
|
||||||
|
require_lvalue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
~set_require_lvalue_and_backupt()
|
||||||
|
{
|
||||||
|
require_lvalue = prev_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool &require_lvalue;
|
||||||
|
bool prev_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool replace_symbol_expr(symbol_exprt &dest) const override;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // CPROVER_UTIL_REPLACE_SYMBOL_H
|
#endif // CPROVER_UTIL_REPLACE_SYMBOL_H
|
||||||
|
|
|
@ -23,12 +23,12 @@ TEST_CASE("Replace all symbols in expression", "[core][util][replace_symbol]")
|
||||||
array_typet array_type(typet("sub-type"), s1);
|
array_typet array_type(typet("sub-type"), s1);
|
||||||
REQUIRE(array_type.size() == s1);
|
REQUIRE(array_type.size() == s1);
|
||||||
|
|
||||||
exprt other_expr("other");
|
exprt other_expr("other", typet("some_type"));
|
||||||
|
|
||||||
replace_symbolt r;
|
replace_symbolt r;
|
||||||
REQUIRE(r.empty());
|
REQUIRE(r.empty());
|
||||||
|
|
||||||
r.insert("a", other_expr);
|
r.insert(s1, other_expr);
|
||||||
REQUIRE(r.replaces_symbol("a"));
|
REQUIRE(r.replaces_symbol("a"));
|
||||||
REQUIRE(r.get_expr_map().size() == 1);
|
REQUIRE(r.get_expr_map().size() == 1);
|
||||||
|
|
||||||
|
@ -62,8 +62,8 @@ TEST_CASE("Lvalue only", "[core][util][replace_symbol]")
|
||||||
|
|
||||||
constant_exprt c("some_value", typet("some_type"));
|
constant_exprt c("some_value", typet("some_type"));
|
||||||
|
|
||||||
replace_symbolt r;
|
address_of_aware_replace_symbolt r;
|
||||||
r.insert("a", c);
|
r.insert(s1, c);
|
||||||
|
|
||||||
REQUIRE(r.replace(binary) == false);
|
REQUIRE(r.replace(binary) == false);
|
||||||
REQUIRE(binary.op0() == address_of_exprt(s1));
|
REQUIRE(binary.op0() == address_of_exprt(s1));
|
||||||
|
@ -72,3 +72,27 @@ TEST_CASE("Lvalue only", "[core][util][replace_symbol]")
|
||||||
REQUIRE(to_array_type(index_expr.array().type()).size() == c);
|
REQUIRE(to_array_type(index_expr.array().type()).size() == c);
|
||||||
REQUIRE(index_expr.index() == c);
|
REQUIRE(index_expr.index() == c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Replace always", "[core][util][replace_symbol]")
|
||||||
|
{
|
||||||
|
symbol_exprt s1("a", typet("some_type"));
|
||||||
|
array_typet array_type(typet("some_type"), s1);
|
||||||
|
symbol_exprt array("b", array_type);
|
||||||
|
index_exprt index(array, s1);
|
||||||
|
|
||||||
|
exprt binary("binary", typet("some_type"));
|
||||||
|
binary.copy_to_operands(address_of_exprt(s1));
|
||||||
|
binary.copy_to_operands(address_of_exprt(index));
|
||||||
|
|
||||||
|
constant_exprt c("some_value", typet("some_type"));
|
||||||
|
|
||||||
|
unchecked_replace_symbolt r;
|
||||||
|
r.insert(s1, c);
|
||||||
|
|
||||||
|
REQUIRE(r.replace(binary) == false);
|
||||||
|
REQUIRE(binary.op0() == address_of_exprt(c));
|
||||||
|
const index_exprt &index_expr =
|
||||||
|
to_index_expr(to_address_of_expr(binary.op1()).object());
|
||||||
|
REQUIRE(to_array_type(index_expr.array().type()).size() == c);
|
||||||
|
REQUIRE(index_expr.index() == c);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue