CBMC
cpp_typecheck_initializer.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 
15 
16 #include <util/arith_tools.h>
17 #include <util/c_types.h>
18 #include <util/expr_initializer.h>
19 #include <util/pointer_expr.h>
21 
22 #include "cpp_convert_type.h"
23 #include "cpp_typecheck_fargs.h"
24 
27 {
28  // this is needed for template arguments that are types
29 
30  if(symbol.is_type)
31  {
32  if(symbol.value.is_nil())
33  return;
34 
35  if(symbol.value.id()!=ID_type)
36  {
38  error() << "expected type as initializer for '" << symbol.base_name << "'"
39  << eom;
40  throw 0;
41  }
42 
43  typecheck_type(symbol.value.type());
44 
45  return;
46  }
47 
48  // do we have an initializer?
49  if(symbol.value.is_nil())
50  {
51  // do we need one?
52  if(is_reference(symbol.type))
53  {
55  error() << "'" << symbol.base_name
56  << "' is declared as reference but is not initialized" << eom;
57  throw 0;
58  }
59 
60  // done
61  return;
62  }
63 
64  // we do have an initializer
65 
66  if(is_reference(symbol.type))
67  {
68  typecheck_expr(symbol.value);
69 
70  if(has_auto(symbol.type))
71  {
72  cpp_convert_auto(symbol.type, symbol.value.type(), get_message_handler());
73  typecheck_type(symbol.type);
74  implicit_typecast(symbol.value, symbol.type);
75  }
76 
77  reference_initializer(symbol.value, symbol.type);
78  }
79  else if(cpp_is_pod(symbol.type))
80  {
81  if(
82  symbol.type.id() == ID_pointer &&
83  to_pointer_type(symbol.type).base_type().id() == ID_code &&
84  symbol.value.id() == ID_address_of &&
85  to_address_of_expr(symbol.value).object().id() == ID_cpp_name)
86  {
87  // initialization of a function pointer with
88  // the address of a function: use pointer type information
89  // for the sake of overload resolution
90 
92  fargs.in_use = true;
93 
94  const code_typet &code_type =
96 
97  for(const auto &parameter : code_type.parameters())
98  {
99  exprt new_object(ID_new_object, parameter.type());
100  new_object.set(ID_C_lvalue, true);
101 
102  if(parameter.get_this())
103  {
104  fargs.has_object = true;
105  new_object.type() = to_pointer_type(parameter.type()).base_type();
106  }
107 
108  fargs.operands.push_back(new_object);
109  }
110 
111  exprt resolved_expr = resolve(
112  to_cpp_name(
113  static_cast<irept &>(to_address_of_expr(symbol.value).object())),
115  fargs);
116 
118  to_pointer_type(symbol.type).base_type() == resolved_expr.type(),
119  "symbol type must match");
120 
121  if(resolved_expr.id()==ID_symbol)
122  {
123  symbol.value=
124  address_of_exprt(resolved_expr);
125  }
126  else if(resolved_expr.id()==ID_member)
127  {
128  symbol.value =
130  lookup(resolved_expr.get(ID_component_name)).symbol_expr());
131 
132  symbol.value.type().add(ID_to_member) =
133  to_member_expr(resolved_expr).compound().type();
134  }
135  else
136  UNREACHABLE;
137 
138  if(symbol.type != symbol.value.type())
139  {
140  error().source_location=symbol.location;
141  error() << "conversion from '" << to_string(symbol.value.type())
142  << "' to '" << to_string(symbol.type) << "' " << eom;
143  throw 0;
144  }
145 
146  return;
147  }
148 
149  typecheck_expr(symbol.value);
150 
151  if(symbol.value.type().find(ID_to_member).is_not_nil())
152  symbol.type.add(ID_to_member) = symbol.value.type().find(ID_to_member);
153 
154  if(symbol.value.id()==ID_initializer_list ||
155  symbol.value.id()==ID_string_constant)
156  {
157  do_initializer(symbol.value, symbol.type, true);
158 
159  if(symbol.type.find(ID_size).is_nil())
160  symbol.type=symbol.value.type();
161  }
162  else if(has_auto(symbol.type))
163  {
164  cpp_convert_auto(symbol.type, symbol.value.type(), get_message_handler());
165  typecheck_type(symbol.type);
166  implicit_typecast(symbol.value, symbol.type);
167  }
168  else
169  implicit_typecast(symbol.value, symbol.type);
170 
171  #if 0
172  simplify_exprt simplify(*this);
173  exprt tmp_value = symbol.value;
174  if(!simplify.simplify(tmp_value))
175  symbol.value.swap(tmp_value);
176  #endif
177  }
178  else
179  {
180  // we need a constructor
181 
182  symbol_exprt expr_symbol(symbol.name, symbol.type);
184 
185  exprt::operandst ops;
186  ops.push_back(symbol.value);
187 
188  auto constructor =
189  cpp_constructor(symbol.value.source_location(), expr_symbol, ops);
190 
191  if(constructor.has_value())
192  symbol.value = constructor.value();
193  else
194  symbol.value = nil_exprt();
195  }
196 }
197 
199  const exprt &object,
200  const typet &type,
201  const source_locationt &source_location,
202  exprt::operandst &ops)
203 {
204  const typet &final_type=follow(type);
205 
206  if(final_type.id()==ID_struct)
207  {
208  const auto &struct_type = to_struct_type(final_type);
209 
210  if(struct_type.is_incomplete())
211  {
212  error().source_location = source_location;
213  error() << "cannot zero-initialize incomplete struct" << eom;
214  throw 0;
215  }
216 
217  for(const auto &component : struct_type.components())
218  {
219  if(component.type().id()==ID_code)
220  continue;
221 
222  if(component.get_bool(ID_is_type))
223  continue;
224 
225  if(component.get_bool(ID_is_static))
226  continue;
227 
228  member_exprt member(object, component.get_name(), component.type());
229 
230  // recursive call
231  zero_initializer(member, component.type(), source_location, ops);
232  }
233  }
234  else if(
235  final_type.id() == ID_array &&
236  !cpp_is_pod(to_array_type(final_type).element_type()))
237  {
238  const array_typet &array_type=to_array_type(type);
239  const exprt &size_expr=array_type.size();
240 
241  if(size_expr.id()==ID_infinity)
242  return; // don't initialize
243 
244  const mp_integer size =
245  numeric_cast_v<mp_integer>(to_constant_expr(size_expr));
246  CHECK_RETURN(size>=0);
247 
248  exprt::operandst empty_operands;
249  for(mp_integer i=0; i<size; ++i)
250  {
251  index_exprt index(
252  object, from_integer(i, c_index_type()), array_type.element_type());
253  zero_initializer(index, array_type.element_type(), source_location, ops);
254  }
255  }
256  else if(final_type.id()==ID_union)
257  {
258  const auto &union_type = to_union_type(final_type);
259 
260  if(union_type.is_incomplete())
261  {
262  error().source_location = source_location;
263  error() << "cannot zero-initialize incomplete union" << eom;
264  throw 0;
265  }
266 
267  // Select the largest component for zero-initialization
268  mp_integer max_comp_size=0;
269 
271 
272  for(const auto &component : union_type.components())
273  {
274  assert(component.type().is_not_nil());
275 
276  if(component.type().id()==ID_code)
277  continue;
278 
279  auto component_size_opt = size_of_expr(component.type(), *this);
280 
281  const auto size_int =
282  numeric_cast<mp_integer>(component_size_opt.value_or(nil_exprt()));
283  if(size_int.has_value())
284  {
285  if(*size_int > max_comp_size)
286  {
287  max_comp_size = *size_int;
288  comp=component;
289  }
290  }
291  }
292 
293  if(max_comp_size>0)
294  {
295  const cpp_namet cpp_name(comp.get_base_name(), source_location);
296 
297  exprt member(ID_member);
298  member.copy_to_operands(object);
299  member.set(ID_component_cpp_name, cpp_name);
300  zero_initializer(member, comp.type(), source_location, ops);
301  }
302  }
303  else if(final_type.id()==ID_c_enum)
304  {
305  const unsignedbv_typet enum_type(
306  to_bitvector_type(to_c_enum_type(final_type).underlying_type())
307  .get_width());
308 
309  exprt zero =
310  typecast_exprt::conditional_cast(from_integer(0, enum_type), type);
312 
313  code_frontend_assignt assign;
314  assign.lhs()=object;
315  assign.rhs()=zero;
316  assign.add_source_location()=source_location;
317 
318  typecheck_expr(assign.lhs());
319  assign.lhs().type().set(ID_C_constant, false);
321 
322  typecheck_code(assign);
323  ops.push_back(assign);
324  }
325  else
326  {
327  const auto value = ::zero_initializer(final_type, source_location, *this);
328  if(!value.has_value())
329  {
330  error().source_location = source_location;
331  error() << "cannot zero-initialize '" << to_string(final_type) << "'"
332  << eom;
333  throw 0;
334  }
335 
336  code_frontend_assignt assign(object, *value);
337  assign.add_source_location()=source_location;
338 
339  typecheck_expr(assign.lhs());
340  assign.lhs().type().set(ID_C_constant, false);
342 
343  typecheck_code(assign);
344  ops.push_back(assign);
345  }
346 }
c_typecheck_baset::do_initializer
virtual void do_initializer(exprt &initializer, const typet &type, bool force_constant)
Definition: c_typecheck_initializer.cpp:26
exprt::copy_to_operands
void copy_to_operands(const exprt &expr)
Copy the given argument to the end of exprt's operands.
Definition: expr.h:155
UNREACHABLE
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:503
pointer_offset_size.h
to_union_type
const union_typet & to_union_type(const typet &type)
Cast a typet to a union_typet.
Definition: c_types.h:162
typecast_exprt::conditional_cast
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition: std_expr.h:2025
mp_integer
BigInt mp_integer
Definition: smt_terms.h:17
arith_tools.h
cpp_typecheck_fargst
Definition: cpp_typecheck_fargs.h:21
goto_instruction_code.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
address_of_exprt::object
exprt & object()
Definition: pointer_expr.h:380
CHECK_RETURN
#define CHECK_RETURN(CONDITION)
Definition: invariant.h:495
typet
The type of an expression, extends irept.
Definition: type.h:28
irept::find
const irept & find(const irep_idt &name) const
Definition: irep.cpp:106
cpp_typecheck_fargs.h
symbolt::type
typet type
Type of symbol.
Definition: symbol.h:31
cpp_typecheck_fargst::operands
exprt::operandst operands
Definition: cpp_typecheck_fargs.h:25
to_c_enum_type
const c_enum_typet & to_c_enum_type(const typet &type)
Cast a typet to a c_enum_typet.
Definition: c_types.h:302
exprt
Base class for all expressions.
Definition: expr.h:55
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
symbolt::base_name
irep_idt base_name
Base (non-scoped) name.
Definition: symbol.h:46
component
auto component(T &struct_expr, const irep_idt &name, const namespacet &ns) -> decltype(struct_expr.op0())
Definition: std_expr.cpp:76
messaget::eom
static eomt eom
Definition: message.h:297
cpp_typecheckt::zero_initializer
void zero_initializer(const exprt &object, const typet &type, const source_locationt &source_location, exprt::operandst &ops)
Definition: cpp_typecheck_initializer.cpp:198
to_bitvector_type
const bitvector_typet & to_bitvector_type(const typet &type)
Cast a typet to a bitvector_typet.
Definition: bitvector_types.h:32
symbol_exprt
Expression to hold a symbol (variable)
Definition: std_expr.h:112
code_frontend_assignt::lhs
exprt & lhs()
Definition: std_code.h:41
unsignedbv_typet
Fixed-width bit-vector with unsigned binary interpretation.
Definition: bitvector_types.h:158
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
cpp_typecheckt::cpp_is_pod
bool cpp_is_pod(const typet &type) const
Definition: cpp_is_pod.cpp:16
exprt::type
typet & type()
Return the type of the expression.
Definition: expr.h:84
namespacet::lookup
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
Definition: namespace.cpp:138
cpp_typecheck_fargst::has_object
bool has_object
Definition: cpp_typecheck_fargs.h:24
cpp_typecheckt::typecheck_type
void typecheck_type(typet &) override
Definition: cpp_typecheck_type.cpp:23
irept::is_not_nil
bool is_not_nil() const
Definition: irep.h:380
code_frontend_assignt::rhs
exprt & rhs()
Definition: std_code.h:46
to_code_type
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition: std_types.h:744
expr_initializer.h
messaget::error
mstreamt & error() const
Definition: message.h:399
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::convert_initializer
void convert_initializer(symbolt &symbol)
Initialize an object with a value.
Definition: cpp_typecheck_initializer.cpp:26
member_exprt::compound
const exprt & compound() const
Definition: std_expr.h:2843
messaget::mstreamt::source_location
source_locationt source_location
Definition: message.h:247
cpp_typecheckt::reference_initializer
void reference_initializer(exprt &expr, const typet &type)
A reference to type "cv1 T1" is initialized by an expression of type "cv2 T2" as follows:
Definition: cpp_typecheck_conversions.cpp:1560
irept::set
void set(const irep_idt &name, const irep_idt &value)
Definition: irep.h:420
nil_exprt
The NIL expression.
Definition: std_expr.h:3025
pointer_expr.h
simplify
bool simplify(exprt &expr, const namespacet &ns)
Definition: simplify_expr.cpp:2926
cpp_typecheck_resolvet::wantt::BOTH
@ BOTH
to_pointer_type
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition: pointer_expr.h:79
simplify_exprt
Definition: simplify_expr_class.h:79
code_frontend_assignt
A codet representing an assignment in the program.
Definition: std_code.h:23
irept::swap
void swap(irept &irep)
Definition: irep.h:442
cpp_typecheck_fargst::in_use
bool in_use
Definition: cpp_typecheck_fargs.h:24
code_typet
Base type of functions.
Definition: std_types.h:538
cpp_convert_type.h
irept::is_nil
bool is_nil() const
Definition: irep.h:376
irept::id
const irep_idt & id() const
Definition: irep.h:396
exprt::operandst
std::vector< exprt > operandst
Definition: expr.h:58
code_typet::parameters
const parameterst & parameters() const
Definition: std_types.h:655
cpp_typecheck.h
source_locationt
Definition: source_location.h:18
member_exprt
Extract member of struct or union.
Definition: std_expr.h:2793
struct_union_typet::componentt
Definition: std_types.h:68
cpp_typecheckt::typecheck_expr
void typecheck_expr(exprt &) override
Definition: cpp_typecheck_expr.cpp:2263
symbolt::value
exprt value
Initial value of symbol.
Definition: symbol.h:34
messaget::get_message_handler
message_handlert & get_message_handler()
Definition: message.h:184
is_reference
bool is_reference(const typet &type)
Returns true if the type is a reference.
Definition: std_types.cpp:143
irept::add
irept & add(const irep_idt &name)
Definition: irep.cpp:116
array_typet
Arrays with given size.
Definition: std_types.h:762
cpp_typecheckt::typecheck_code
void typecheck_code(codet &) override
Definition: cpp_typecheck_code.cpp:24
namespace_baset::follow
const typet & follow(const typet &) const
Resolve type symbol to the type it points to.
Definition: namespace.cpp:49
symbolt::location
source_locationt location
Source code location of definition of symbol.
Definition: symbol.h:37
symbolt
Symbol table entry.
Definition: symbol.h:27
from_integer
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
Definition: arith_tools.cpp:100
symbolt::is_type
bool is_type
Definition: symbol.h:61
cpp_typecheckt::has_auto
static bool has_auto(const typet &type)
Definition: cpp_typecheck_compound_type.cpp:67
pointer_typet::base_type
const typet & base_type() const
The type of the data what we point to.
Definition: pointer_expr.h:35
cpp_typecheckt::implicit_typecast
void implicit_typecast(exprt &expr, const typet &type) override
Definition: cpp_typecheck_conversions.cpp:1493
to_array_type
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:844
cpp_convert_auto
void cpp_convert_auto(typet &dest, const typet &src, message_handlert &message_handler)
Definition: cpp_convert_type.cpp:350
size_of_expr
optionalt< exprt > size_of_expr(const typet &type, const namespacet &ns)
Definition: pointer_offset_size.cpp:280
to_member_expr
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition: std_expr.h:2886
irept
There are a large number of kinds of tree structured or tree-like data in CPROVER.
Definition: irep.h:359
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
struct_union_typet::componentt::get_base_name
const irep_idt & get_base_name() const
Definition: std_types.h:89
cpp_typecheckt::resolve
exprt resolve(const cpp_namet &cpp_name, const cpp_typecheck_resolvet::wantt want, const cpp_typecheck_fargst &fargs, bool fail_with_exception=true)
Definition: cpp_typecheck.h:83
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
symbolt::name
irep_idt name
The unique identifier.
Definition: symbol.h:40
to_cpp_name
cpp_namet & to_cpp_name(irept &cpp_name)
Definition: cpp_name.h:148
array_typet::element_type
const typet & element_type() const
The type of the elements of the array.
Definition: std_types.h:785
to_constant_expr
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition: std_expr.h:2992