cprover
cpp_constructor.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: C++ Language Type Checking
4
5Author: 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(object, 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
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
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{
300 ops.push_back(op);
301 new_temporary(source_location, type, ops, temporary);
302}
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
Definition: arith_tools.cpp:99
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:19
bitvector_typet c_index_type()
Definition: c_types.cpp:16
Operator to return the address of an object.
Definition: pointer_expr.h:361
static void make_already_typechecked(exprt &expr)
const exprt & size() const
Definition: std_types.h:790
The Boolean type.
Definition: std_types.h:36
virtual void make_constant_index(exprt &expr)
A codet representing sequential composition of program statements.
Definition: std_code.h:130
code_operandst & statements()
Definition: std_code.h:138
void add(const codet &code)
Definition: std_code.h:168
codet representation of an expression statement.
Definition: std_code.h:1394
cpp_scopet & set_scope(const irep_idt &identifier)
Definition: cpp_scopes.h:87
void typecheck_side_effect_assignment(side_effect_exprt &) override
void typecheck_side_effect_function_call(side_effect_expr_function_callt &) override
bool cpp_is_pod(const typet &type) const
Definition: cpp_is_pod.cpp:16
void new_temporary(const source_locationt &source_location, const typet &, const exprt::operandst &ops, exprt &temporary)
optionalt< codet > cpp_constructor(const source_locationt &source_location, const exprt &object, const exprt::operandst &operands)
void elaborate_class_template(const typet &type)
elaborate class template instances
void add_implicit_dereference(exprt &)
void typecheck_expr(exprt &) override
std::string to_string(const typet &) override
cpp_scopest cpp_scopes
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:37
bool empty() const
Definition: dstring.h:88
Base class for all expressions.
Definition: expr.h:54
std::vector< exprt > operandst
Definition: expr.h:56
typet & type()
Return the type of the expression.
Definition: expr.h:82
const source_locationt & source_location() const
Definition: expr.h:230
source_locationt & add_source_location()
Definition: expr.h:235
void add_to_operands(const exprt &expr)
Add the given argument to the end of exprt's operands.
Definition: expr.h:136
The Boolean constant false.
Definition: std_expr.h:2865
Array index operator.
Definition: std_expr.h:1328
bool get_bool(const irep_idt &name) const
Definition: irep.cpp:58
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:45
void set(const irep_idt &name, const irep_idt &value)
Definition: irep.h:420
void swap(irept &irep)
Definition: irep.h:442
const irep_idt & id() const
Definition: irep.h:396
irept & add(const irep_idt &name)
Definition: irep.cpp:116
Extract member of struct or union.
Definition: std_expr.h:2667
source_locationt source_location
Definition: message.h:247
mstreamt & error() const
Definition: message.h:399
static eomt eom
Definition: message.h:297
const typet & follow(const typet &) const
Resolve type symbol to the type it points to.
Definition: namespace.cpp:49
A side_effect_exprt that performs an assignment.
Definition: std_code.h:1565
A side_effect_exprt representation of a function call side effect.
Definition: std_code.h:1692
exprt::operandst & arguments()
Definition: std_code.h:1718
An expression containing a side effect.
Definition: std_code.h:1450
Structure type, corresponds to C style structs.
Definition: std_types.h:231
const componentst & components() const
Definition: std_types.h:147
std::vector< componentt > componentst
Definition: std_types.h:140
The Boolean constant true.
Definition: std_expr.h:2856
The type of an expression, extends irept.
Definition: type.h:29
C++ Language Type Checking.
nonstd::optional< T > optionalt
Definition: optional.h:35
API to expression classes for Pointers.
bool is_reference(const typet &type)
Returns true if the type is a reference.
Definition: std_types.cpp:137
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
Definition: pointer_expr.h:398
BigInt mp_integer
Definition: smt_terms.h:12
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:503
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition: invariant.h:510
side_effect_expr_function_callt & to_side_effect_expr_function_call(exprt &expr)
Definition: std_code.h:1739
code_expressiont & to_code_expression(codet &code)
Definition: std_code.h:1428
const codet & to_code(const exprt &expr)
auto component(T &struct_expr, const irep_idt &name, const namespacet &ns) -> decltype(struct_expr.op0())
Definition: std_expr.cpp:48
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition: std_expr.h:2840
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition: std_types.h:744
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition: std_types.h:308
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:832