CBMC
std_expr.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module:
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
9 #include "std_expr.h"
10 
11 #include "config.h"
12 #include "namespace.h"
13 #include "pointer_expr.h"
14 #include "range.h"
15 #include "substitute_symbols.h"
16 
17 #include <map>
18 
20 {
21  const std::string val=id2string(get_value());
22  return val.find_first_not_of('0')==std::string::npos;
23 }
24 
26 {
27  if(type().id() != ID_pointer)
28  return false;
29 
30  if(get_value() == ID_NULL)
31  return true;
32 
33  // We used to support "0" (when NULL_is_zero), but really front-ends should
34  // resolve this and generate ID_NULL instead.
35  INVARIANT(
37  "front-end should use ID_NULL");
38  return false;
39 }
40 
41 void constant_exprt::check(const exprt &expr, const validation_modet vm)
42 {
43  nullary_exprt::check(expr, vm);
44 
45  const auto value = expr.get(ID_value);
46 
47  DATA_CHECK(
48  vm,
49  !can_cast_type<bitvector_typet>(expr.type()) || !value.empty(),
50  "bitvector constant must have a non-empty value");
51 
52  DATA_CHECK(
53  vm,
56  expr.type().id() == ID_verilog_unsignedbv ||
57  expr.type().id() == ID_verilog_signedbv ||
58  id2string(value).find_first_not_of("0123456789ABCDEF") ==
59  std::string::npos,
60  "negative bitvector constant must use two's complement");
61 
62  DATA_CHECK(
63  vm,
65  expr.type().id() == ID_verilog_unsignedbv ||
66  expr.type().id() == ID_verilog_signedbv || value == ID_0 ||
67  id2string(value)[0] != '0',
68  "bitvector constant must not have leading zeros");
69 }
70 
72 {
73  if(op.empty())
74  return false_exprt();
75  else if(op.size()==1)
76  return op.front();
77  else
78  {
79  return or_exprt(exprt::operandst(op));
80  }
81 }
82 
84 {
85  if(op.empty())
86  return true_exprt();
87  else if(op.size()==1)
88  return op.front();
89  else
90  {
91  return and_exprt(exprt::operandst(op));
92  }
93 }
94 
95 // Implementation of struct_exprt::component for const / non const overloads.
96 template <typename T>
97 auto component(T &struct_expr, const irep_idt &name, const namespacet &ns)
98  -> decltype(struct_expr.op0())
99 {
100  static_assert(
101  std::is_base_of<struct_exprt, T>::value, "T must be a struct_exprt.");
102  const struct_typet &struct_type =
103  struct_expr.type().id() == ID_struct_tag
104  ? ns.follow_tag(to_struct_tag_type(struct_expr.type()))
105  : to_struct_type(struct_expr.type());
106  const auto index = struct_type.component_number(name);
108  index < struct_expr.operands().size(),
109  "component matching index should exist");
110  return struct_expr.operands()[index];
111 }
112 
115 {
116  return ::component(*this, name, ns);
117 }
118 
120 const exprt &
121 struct_exprt::component(const irep_idt &name, const namespacet &ns) const
122 {
123  return ::component(*this, name, ns);
124 }
125 
134  const exprt &expr,
135  const namespacet &ns,
136  const validation_modet vm)
137 {
138  check(expr, vm);
139 
140  const auto &member_expr = to_member_expr(expr);
141 
142  const typet &compound_type = member_expr.compound().type();
143  const auto *struct_union_type =
144  (compound_type.id() == ID_struct_tag || compound_type.id() == ID_union_tag)
145  ? &ns.follow_tag(to_struct_or_union_tag_type(compound_type))
146  : type_try_dynamic_cast<struct_union_typet>(compound_type);
147  DATA_CHECK(
148  vm,
149  struct_union_type != nullptr,
150  "member must address a struct, union or compatible type");
151 
152  const auto &component =
153  struct_union_type->get_component(member_expr.get_component_name());
154 
155  DATA_CHECK(
156  vm,
157  component.is_not_nil(),
158  "member component '" + id2string(member_expr.get_component_name()) +
159  "' must exist on addressed type");
160 
161  DATA_CHECK(
162  vm,
163  component.type() == member_expr.type(),
164  "member expression's type must match the addressed struct or union "
165  "component");
166 }
167 
168 void let_exprt::validate(const exprt &expr, const validation_modet vm)
169 {
170  check(expr, vm);
171 
172  const auto &let_expr = to_let_expr(expr);
173 
174  DATA_CHECK(
175  vm,
176  let_expr.values().size() == let_expr.variables().size(),
177  "number of variables must match number of values");
178 
179  for(const auto &binding :
180  make_range(let_expr.variables()).zip(let_expr.values()))
181  {
182  DATA_CHECK(
183  vm,
184  binding.first.id() == ID_symbol,
185  "let binding symbols must be symbols");
186 
187  DATA_CHECK(
188  vm,
189  binding.first.type() == binding.second.type(),
190  "let bindings must be type consistent");
191  }
192 }
193 
195 {
196  const exprt::operandst &designators = designator();
197  PRECONDITION(!designators.empty());
198 
199  with_exprt result{exprt{}, exprt{}, exprt{}};
200  exprt *dest = &result;
201 
202  for(const auto &expr : designators)
203  {
204  with_exprt tmp{exprt{}, exprt{}, exprt{}};
205 
206  if(expr.id() == ID_index_designator)
207  {
208  tmp.where() = to_index_designator(expr).index();
209  }
210  else if(expr.id() == ID_member_designator)
211  {
212  // irep_idt component_name=
213  // to_member_designator(*it).get_component_name();
214  }
215  else
216  UNREACHABLE;
217 
218  *dest = tmp;
219  dest = &to_with_expr(*dest).new_value();
220  }
221 
222  return result;
223 }
224 
226 {
227  // number of values must match the number of bound variables
228  auto &variables = this->variables();
229  PRECONDITION(variables.size() == values.size());
230 
231  std::map<symbol_exprt, exprt> value_map;
232 
233  for(std::size_t i = 0; i < variables.size(); i++)
234  {
235  // types must match
236  PRECONDITION(variables[i].type() == values[i].type());
237  value_map[variables[i]] = values[i];
238  }
239 
240  // build a substitution map
241  std::map<irep_idt, exprt> substitutions;
242 
243  for(std::size_t i = 0; i < variables.size(); i++)
244  substitutions[variables[i].get_identifier()] = values[i];
245 
246  // now recurse downwards and substitute in 'where'
247  auto substitute_result = substitute_symbols(substitutions, where());
248 
249  if(substitute_result.has_value())
250  return substitute_result.value();
251  else
252  return where(); // trivial case, variables not used
253 }
254 
255 exprt binding_exprt::instantiate(const variablest &new_variables) const
256 {
257  std::vector<exprt> values;
258  values.reserve(new_variables.size());
259  for(const auto &new_variable : new_variables)
260  values.push_back(new_variable);
261  return instantiate(values);
262 }
configt config
Definition: config.cpp:25
Boolean AND.
Definition: std_expr.h:2125
static void check(const exprt &expr, const validation_modet vm=validation_modet::INVARIANT)
Definition: std_expr.h:650
exprt & where()
Definition: std_expr.h:3148
exprt instantiate(const exprt::operandst &) const
substitute free occurrences of the variables in where() by the given values
Definition: std_expr.cpp:225
variablest & variables()
Definition: std_expr.h:3138
std::vector< symbol_exprt > variablest
Definition: std_expr.h:3119
struct configt::ansi_ct ansi_c
const irep_idt & get_value() const
Definition: std_expr.h:3008
bool value_is_zero_string() const
Definition: std_expr.cpp:19
bool is_null_pointer() const
Returns true if expr has a pointer type and a value NULL; it also returns true when expr has value ze...
Definition: std_expr.cpp:25
static void check(const exprt &expr, const validation_modet vm=validation_modet::INVARIANT)
Definition: std_expr.cpp:41
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
Base class for all expressions.
Definition: expr.h:56
std::vector< exprt > operandst
Definition: expr.h:58
typet & type()
Return the type of the expression.
Definition: expr.h:84
The Boolean constant false.
Definition: std_expr.h:3082
const exprt & index() const
Definition: std_expr.h:2568
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:44
const irep_idt & id() const
Definition: irep.h:388
static void validate(const exprt &, validation_modet)
Definition: std_expr.cpp:168
binding_exprt & binding()
Definition: std_expr.h:3242
static void validate(const exprt &expr, const namespacet &ns, const validation_modet vm=validation_modet::INVARIANT)
Check that the member expression has the right number of operands, refers to a component that exists ...
Definition: std_expr.cpp:133
static void check(const exprt &expr, const validation_modet vm=validation_modet::INVARIANT)
Definition: std_expr.h:2913
const union_typet & follow_tag(const union_tag_typet &) const
Follow type tag of union type.
Definition: namespace.cpp:63
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:94
static void check(const exprt &expr, const validation_modet vm=validation_modet::INVARIANT)
Definition: std_expr.h:29
Boolean OR.
Definition: std_expr.h:2233
exprt & component(const irep_idt &name, const namespacet &ns)
Definition: std_expr.cpp:114
Structure type, corresponds to C style structs.
Definition: std_types.h:231
std::size_t component_number(const irep_idt &component_name) const
Return the sequence number of the component with given name.
Definition: std_types.cpp:47
The Boolean constant true.
Definition: std_expr.h:3073
The type of an expression, extends irept.
Definition: type.h:29
exprt::operandst & designator()
Definition: std_expr.h:2691
with_exprt make_with_expr() const
converts an update expr into a (possibly nested) with expression
Definition: std_expr.cpp:194
Operator to update elements in structs and arrays.
Definition: std_expr.h:2481
exprt & new_value()
Definition: std_expr.h:2511
const std::string & id2string(const irep_idt &d)
Definition: irep.h:44
API to expression classes for Pointers.
bool can_cast_type< pointer_typet >(const typet &type)
Check whether a reference to a typet is a pointer_typet.
Definition: pointer_expr.h:80
Ranges: pair of begin and end iterators, which can be initialized from containers,...
ranget< iteratort > make_range(iteratort begin, iteratort end)
Definition: range.h:522
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:525
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition: invariant.h:534
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
exprt conjunction(const exprt::operandst &op)
1) generates a conjunction for two or more operands 2) for one operand, returns the operand 3) return...
Definition: std_expr.cpp:83
exprt disjunction(const exprt::operandst &op)
1) generates a disjunction for two or more operands 2) for one operand, returns the operand 3) return...
Definition: std_expr.cpp:71
auto component(T &struct_expr, const irep_idt &name, const namespacet &ns) -> decltype(struct_expr.op0())
Definition: std_expr.cpp:97
API to expression classes.
const index_designatort & to_index_designator(const exprt &expr)
Cast an exprt to an index_designatort.
Definition: std_expr.h:2596
const let_exprt & to_let_expr(const exprt &expr)
Cast an exprt to a let_exprt.
Definition: std_expr.h:3338
const with_exprt & to_with_expr(const exprt &expr)
Cast an exprt to a with_exprt.
Definition: std_expr.h:2543
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition: std_expr.h:2946
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition: std_types.h:308
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition: std_types.h:518
const struct_or_union_tag_typet & to_struct_or_union_tag_type(const typet &type)
Cast a typet to a struct_or_union_tag_typet.
Definition: std_types.h:478
bool can_cast_type< bitvector_typet >(const typet &type)
Check whether a reference to a typet is a bitvector_typet.
Definition: std_types.h:952
bool NULL_is_zero
Definition: config.h:226
std::optional< exprt > substitute_symbols(const std::map< irep_idt, exprt > &substitutions, exprt src)
Substitute free occurrences of the variables given by their identifiers in the keys of the map in the...
Symbol Substitution.
#define DATA_CHECK(vm, condition, message)
This macro takes a condition which denotes a well-formedness criterion on goto programs,...
Definition: validate.h:22
validation_modet