CBMC
cpp_constructor.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: C++ Language Type Checking
4 
5 Author: Daniel Kroening, kroening@cs.cmu.edu
6 
7 \*******************************************************************/
8 
11 
12 #include "cpp_typecheck.h"
13 
14 #include <util/arith_tools.h>
15 #include <util/c_types.h>
16 #include <util/pointer_expr.h>
17 
23  const source_locationt &source_location,
24  const exprt &object,
25  const exprt::operandst &operands)
26 {
27  exprt object_tc=object;
28 
29  typecheck_expr(object_tc);
30 
31  elaborate_class_template(object_tc.type());
32 
33  typet tmp_type(follow(object_tc.type()));
34 
35  assert(!is_reference(tmp_type));
36 
37  if(tmp_type.id()==ID_array)
38  {
39  // We allow only one operand and it must be tagged with '#array_ini'.
40  // Note that the operand is an array that is used for copy-initialization.
41  // In the general case, a program is not allowed to use this form of
42  // construct. This way of initializing an array is used internally only.
43  // The purpose of the tag #array_ini is to rule out ill-formed
44  // programs.
45 
46  if(!operands.empty() && !operands.front().get_bool(ID_C_array_ini))
47  {
48  error().source_location=source_location;
49  error() << "bad array initializer" << eom;
50  throw 0;
51  }
52 
53  assert(operands.empty() || operands.size()==1);
54 
55  if(operands.empty() && cpp_is_pod(tmp_type))
56  return {};
57 
58  const exprt &size_expr=
59  to_array_type(tmp_type).size();
60 
61  if(size_expr.id() == ID_infinity)
62  return {}; // don't initialize
63 
64  exprt tmp_size=size_expr;
65  make_constant_index(tmp_size);
66 
67  mp_integer s;
68  if(to_integer(to_constant_expr(tmp_size), s))
69  {
70  error().source_location=source_location;
71  error() << "array size '" << to_string(size_expr) << "' is not a constant"
72  << eom;
73  throw 0;
74  }
75 
76  /*if(cpp_is_pod(tmp_type))
77  {
78  code_expressiont new_code;
79  exprt op_tc=operands.front();
80  typecheck_expr(op_tc);
81  // Override constantness
82  object_tc.type().set("ID_C_constant", false);
83  object_tc.set("ID_C_lvalue", true);
84  side_effect_exprt assign(ID_assign);
85  assign.add_source_location()=source_location;
86  assign.copy_to_operands(object_tc, op_tc);
87  typecheck_side_effect_assignment(assign);
88  new_code.expression()=assign;
89  return new_code;
90  }
91  else*/
92  {
93  code_blockt new_code;
94 
95  // for each element of the array, call the default constructor
96  for(mp_integer i=0; i < s; ++i)
97  {
98  exprt::operandst tmp_operands;
99 
100  exprt constant = from_integer(i, c_index_type());
101  constant.add_source_location()=source_location;
102 
103  index_exprt index = index_exprt(object_tc, constant);
104  index.add_source_location()=source_location;
105 
106  if(!operands.empty())
107  {
108  index_exprt operand(operands.front(), constant);
109  operand.add_source_location()=source_location;
110  tmp_operands.push_back(operand);
111  }
112 
113  auto i_code = cpp_constructor(source_location, index, tmp_operands);
114 
115  if(i_code.has_value())
116  new_code.add(std::move(i_code.value()));
117  }
118  return std::move(new_code);
119  }
120  }
121  else if(cpp_is_pod(tmp_type))
122  {
123  exprt::operandst operands_tc=operands;
124 
125  for(auto &op : operands_tc)
126  {
127  typecheck_expr(op);
129  }
130 
131  if(operands_tc.empty())
132  {
133  // a POD is NOT initialized
134  return {};
135  }
136  else if(operands_tc.size()==1)
137  {
138  // Override constantness
139  object_tc.type().set(ID_C_constant, false);
140  object_tc.set(ID_C_lvalue, true);
142  object_tc, operands_tc.front(), typet(), source_location);
144  return code_expressiont(std::move(assign));
145  }
146  else
147  {
148  error().source_location=source_location;
149  error() << "initialization of POD requires one argument, "
150  "but got " << operands.size() << eom;
151  throw 0;
152  }
153  }
154  else if(tmp_type.id()==ID_union)
155  {
156  UNREACHABLE; // Todo: union
157  }
158  else if(tmp_type.id()==ID_struct)
159  {
160  exprt::operandst operands_tc=operands;
161 
162  for(auto &op : operands_tc)
163  {
164  typecheck_expr(op);
166  }
167 
168  const struct_typet &struct_type=
169  to_struct_type(tmp_type);
170 
171  // set most-derived bits
172  code_blockt block;
173  for(const auto &component : struct_type.components())
174  {
175  if(component.get_base_name() != "@most_derived")
176  continue;
177 
178  member_exprt member(object_tc, component.get_name(), bool_typet());
179  member.add_source_location()=source_location;
180  member.set(ID_C_lvalue, object_tc.get_bool(ID_C_lvalue));
181 
182  exprt val=false_exprt();
183 
184  if(!component.get_bool(ID_from_base))
185  val=true_exprt();
186 
188  std::move(member), std::move(val), typet(), source_location);
189 
191 
192  block.add(code_expressiont(std::move(assign)));
193  }
194 
195  // enter struct scope
196  cpp_save_scopet save_scope(cpp_scopes);
197  cpp_scopes.set_scope(struct_type.get(ID_name));
198 
199  // find name of constructor
200  const struct_typet::componentst &components=
201  struct_type.components();
202 
203  irep_idt constructor_name;
204 
205  for(const auto &c : components)
206  {
207  const typet &type = c.type();
208 
209  if(
210  !c.get_bool(ID_from_base) && type.id() == ID_code &&
211  to_code_type(type).return_type().id() == ID_constructor)
212  {
213  constructor_name = c.get_base_name();
214  break;
215  }
216  }
217 
218  INVARIANT(!constructor_name.empty(), "non-PODs should have a constructor");
219 
220  side_effect_expr_function_callt function_call(
221  cpp_namet(constructor_name, source_location).as_expr(),
222  operands_tc,
224  source_location);
225 
227  assert(function_call.get(ID_statement)==ID_temporary_object);
228 
229  exprt &initializer =
230  static_cast<exprt &>(function_call.add(ID_initializer));
231 
232  assert(initializer.id()==ID_code &&
233  initializer.get(ID_statement)==ID_expression);
234 
235  auto &statement_expr = to_code_expression(to_code(initializer));
236 
238  to_side_effect_expr_function_call(statement_expr.expression());
239 
240  exprt &tmp_this=func_ini.arguments().front();
242  to_address_of_expr(tmp_this).object().id() == ID_new_object,
243  "expected new_object operand in address_of expression");
244 
245  tmp_this=address_of_exprt(object_tc);
246 
247  const auto &initializer_code=to_code(initializer);
248 
249  if(block.statements().empty())
250  return initializer_code;
251  else
252  {
253  block.add(initializer_code);
254  return std::move(block);
255  }
256  }
257  else
258  UNREACHABLE;
259 
260  return {};
261 }
262 
264  const source_locationt &source_location,
265  const typet &type,
266  const exprt::operandst &ops,
267  exprt &temporary)
268 {
269  // create temporary object
270  side_effect_exprt tmp_object_expr(ID_temporary_object, type, source_location);
271  tmp_object_expr.set(ID_mode, ID_cpp);
272 
273  exprt new_object(ID_new_object);
274  new_object.add_source_location()=tmp_object_expr.source_location();
275  new_object.set(ID_C_lvalue, true);
276  new_object.type()=tmp_object_expr.type();
277 
279 
280  auto new_code = cpp_constructor(source_location, new_object, ops);
281 
282  if(new_code.has_value())
283  {
284  if(new_code->get_statement() == ID_assign)
285  tmp_object_expr.add_to_operands(std::move(new_code->op1()));
286  else
287  tmp_object_expr.add(ID_initializer) = *new_code;
288  }
289 
290  temporary.swap(tmp_object_expr);
291 }
292 
294  const source_locationt &source_location,
295  const typet &type,
296  const exprt &op,
297  exprt &temporary)
298 {
299  exprt::operandst ops;
300  ops.push_back(op);
301  new_temporary(source_location, type, ops, temporary);
302 }
UNREACHABLE
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:503
struct_union_typet::components
const componentst & components() const
Definition: std_types.h:147
dstringt
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:36
code_blockt
A codet representing sequential composition of program statements.
Definition: std_code.h:129
to_code_expression
code_expressiont & to_code_expression(codet &code)
Definition: std_code.h:1428
to_side_effect_expr_function_call
side_effect_expr_function_callt & to_side_effect_expr_function_call(exprt &expr)
Definition: std_code.h:1739
mp_integer
BigInt mp_integer
Definition: smt_terms.h:17
cpp_typecheckt::elaborate_class_template
void elaborate_class_template(const typet &type)
elaborate class template instances
Definition: cpp_instantiate_template.cpp:221
arith_tools.h
to_struct_type
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition: std_types.h:308
cpp_save_scopet
Definition: cpp_scopes.h:127
cpp_typecheckt::cpp_scopes
cpp_scopest cpp_scopes
Definition: cpp_typecheck.h:104
typet
The type of an expression, extends irept.
Definition: type.h:28
cpp_typecheckt::typecheck_side_effect_assignment
void typecheck_side_effect_assignment(side_effect_exprt &) override
Definition: cpp_typecheck_expr.cpp:2007
side_effect_expr_function_callt
A side_effect_exprt representation of a function call side effect.
Definition: std_code.h:1691
cpp_typecheckt::new_temporary
void new_temporary(const source_locationt &source_location, const typet &, const exprt::operandst &ops, exprt &temporary)
Definition: cpp_constructor.cpp:263
exprt
Base class for all expressions.
Definition: expr.h:55
struct_union_typet::componentst
std::vector< componentt > componentst
Definition: std_types.h:140
cpp_typecheckt::cpp_constructor
optionalt< codet > cpp_constructor(const source_locationt &source_location, const exprt &object, const exprt::operandst &operands)
Definition: cpp_constructor.cpp:22
component
auto component(T &struct_expr, const irep_idt &name, const namespacet &ns) -> decltype(struct_expr.op0())
Definition: std_expr.cpp:76
to_integer
bool to_integer(const constant_exprt &expr, mp_integer &int_value)
Convert a constant expression expr to an arbitrary-precision integer.
Definition: arith_tools.cpp:20
bool_typet
The Boolean type.
Definition: std_types.h:35
messaget::eom
static eomt eom
Definition: message.h:297
irept::get
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:45
array_typet::size
const exprt & size() const
Definition: std_types.h:800
code_blockt::statements
code_operandst & statements()
Definition: std_code.h:138
cpp_typecheckt::cpp_is_pod
bool cpp_is_pod(const typet &type) const
Definition: cpp_is_pod.cpp:16
to_code
const codet & to_code(const exprt &expr)
Definition: std_code_base.h:104
exprt::type
typet & type()
Return the type of the expression.
Definition: expr.h:84
to_code_type
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition: std_types.h:744
messaget::error
mstreamt & error() const
Definition: message.h:399
cpp_typecheckt::typecheck_side_effect_function_call
void typecheck_side_effect_function_call(side_effect_expr_function_callt &) override
Definition: cpp_typecheck_expr.cpp:1504
already_typechecked_exprt::make_already_typechecked
static void make_already_typechecked(exprt &expr)
Definition: c_typecheck_base.h:316
DATA_INVARIANT
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition: invariant.h:510
cpp_typecheckt::add_implicit_dereference
void add_implicit_dereference(exprt &)
Definition: cpp_typecheck_expr.cpp:1491
messaget::mstreamt::source_location
source_locationt source_location
Definition: message.h:247
irept::set
void set(const irep_idt &name, const irep_idt &value)
Definition: irep.h:420
pointer_expr.h
side_effect_expr_assignt
A side_effect_exprt that performs an assignment.
Definition: std_code.h:1564
irept::swap
void swap(irept &irep)
Definition: irep.h:442
c_typecheck_baset::make_constant_index
virtual void make_constant_index(exprt &expr)
Definition: c_typecheck_expr.cpp:4414
irept::id
const irep_idt & id() const
Definition: irep.h:396
exprt::operandst
std::vector< exprt > operandst
Definition: expr.h:58
dstringt::empty
bool empty() const
Definition: dstring.h:88
code_blockt::add
void add(const codet &code)
Definition: std_code.h:168
false_exprt
The Boolean constant false.
Definition: std_expr.h:3016
optionalt
nonstd::optional< T > optionalt
Definition: optional.h:35
cpp_typecheck.h
source_locationt
Definition: source_location.h:18
member_exprt
Extract member of struct or union.
Definition: std_expr.h:2793
cpp_typecheckt::typecheck_expr
void typecheck_expr(exprt &) override
Definition: cpp_typecheck_expr.cpp:2263
is_reference
bool is_reference(const typet &type)
Returns true if the type is a reference.
Definition: std_types.cpp:143
struct_typet
Structure type, corresponds to C style structs.
Definition: std_types.h:230
irept::add
irept & add(const irep_idt &name)
Definition: irep.cpp:116
namespace_baset::follow
const typet & follow(const typet &) const
Resolve type symbol to the type it points to.
Definition: namespace.cpp:49
from_integer
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
Definition: arith_tools.cpp:100
side_effect_expr_function_callt::arguments
exprt::operandst & arguments()
Definition: std_code.h:1718
c_typecheck_baset::return_type
typet return_type
Definition: c_typecheck_base.h:170
to_array_type
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:844
exprt::add_to_operands
void add_to_operands(const exprt &expr)
Add the given argument to the end of exprt's operands.
Definition: expr.h:162
cpp_typecheckt::to_string
std::string to_string(const typet &) override
Definition: cpp_typecheck.cpp:82
to_address_of_expr
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
Definition: pointer_expr.h:408
index_exprt
Array index operator.
Definition: std_expr.h:1409
address_of_exprt
Operator to return the address of an object.
Definition: pointer_expr.h:370
exprt::add_source_location
source_locationt & add_source_location()
Definition: expr.h:216
true_exprt
The Boolean constant true.
Definition: std_expr.h:3007
uninitialized_typet
Definition: cpp_parse_tree.h:31
c_index_type
bitvector_typet c_index_type()
Definition: c_types.cpp:16
cpp_namet
Definition: cpp_name.h:16
exprt::source_location
const source_locationt & source_location() const
Definition: expr.h:211
c_types.h
cpp_scopest::set_scope
cpp_scopet & set_scope(const irep_idt &identifier)
Definition: cpp_scopes.h:87
irept::get_bool
bool get_bool(const irep_idt &name) const
Definition: irep.cpp:58
side_effect_exprt
An expression containing a side effect.
Definition: std_code.h:1449
validation_modet::INVARIANT
@ INVARIANT
code_expressiont
codet representation of an expression statement.
Definition: std_code.h:1393
to_constant_expr
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition: std_expr.h:2992