CBMC
cpp_typecheck.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/pointer_expr.h>
15 #include <util/source_location.h>
16 #include <util/symbol_table.h>
17 
18 #include <ansi-c/builtin_factory.h>
19 #include <ansi-c/gcc_version.h>
20 
21 #include "cpp_declarator.h"
22 #include "cpp_util.h"
23 #include "expr2cpp.h"
24 
26  cpp_parse_treet &_cpp_parse_tree,
27  symbol_table_baset &_symbol_table,
28  const std::string &_module,
29  message_handlert &message_handler)
30  : c_typecheck_baset(_symbol_table, _module, message_handler),
31  cpp_parse_tree(_cpp_parse_tree),
32  template_counter(0),
33  anon_counter(0),
34  disable_access_control(false),
35  support_float16_type(false)
36 {
38  {
39  gcc_versiont gcc_version;
40  gcc_version.get("gcc");
41  if(
42  gcc_version.flavor == gcc_versiont::flavort::GCC &&
43  gcc_version.is_at_least(13u))
44  {
45  support_float16_type = true;
46  }
47  }
48 }
49 
51  cpp_parse_treet &_cpp_parse_tree,
52  symbol_table_baset &_symbol_table1,
53  const symbol_table_baset &_symbol_table2,
54  const std::string &_module,
55  message_handlert &message_handler)
56  : c_typecheck_baset(_symbol_table1, _symbol_table2, _module, message_handler),
57  cpp_parse_tree(_cpp_parse_tree),
58  template_counter(0),
59  anon_counter(0),
60  disable_access_control(false),
61  support_float16_type(false)
62 {
64  {
65  gcc_versiont gcc_version;
66  gcc_version.get("gcc");
67  if(
68  gcc_version.flavor == gcc_versiont::flavort::GCC &&
69  gcc_version.is_at_least(13u))
70  {
71  support_float16_type = true;
72  }
73  }
74 }
75 
77 {
78  if(item.is_declaration())
80  else if(item.is_linkage_spec())
81  convert(item.get_linkage_spec());
82  else if(item.is_namespace_spec())
84  else if(item.is_using())
85  convert(item.get_using());
86  else if(item.is_static_assert())
87  convert(item.get_static_assert());
88  else
89  {
91  error() << "unknown parse-tree element: " << item.id() << eom;
92  throw 0;
93  }
94 }
95 
98 {
99  // default linkage is "automatic"
100  current_linkage_spec=ID_auto;
101 
102  for(auto &item : cpp_parse_tree.items)
103  convert(item);
104 
106 
108 
110 
111  clean_up();
112 }
113 
115 {
116  const exprt &this_expr=
118 
119  CHECK_RETURN(this_expr.is_not_nil());
120  CHECK_RETURN(this_expr.type().id() == ID_pointer);
121 
122  const typet &t = to_pointer_type(this_expr.type()).base_type();
123  CHECK_RETURN(t.id() == ID_struct_tag);
124  return follow_tag(to_struct_tag_type(t));
125 }
126 
127 std::string cpp_typecheckt::to_string(const exprt &expr)
128 {
129  return expr2cpp(expr, *this);
130 }
131 
132 std::string cpp_typecheckt::to_string(const typet &type)
133 {
134  return type2cpp(type, *this);
135 }
136 
138  cpp_parse_treet &cpp_parse_tree,
139  symbol_table_baset &symbol_table,
140  const std::string &module,
141  message_handlert &message_handler)
142 {
144  cpp_parse_tree, symbol_table, module, message_handler);
145  return cpp_typecheck.typecheck_main();
146 }
147 
149  exprt &expr,
150  message_handlert &message_handler,
151  const namespacet &ns)
152 {
153  const unsigned errors_before=
154  message_handler.get_message_count(messaget::M_ERROR);
155 
156  symbol_tablet symbol_table;
157  cpp_parse_treet cpp_parse_tree;
158 
159  cpp_typecheckt cpp_typecheck(cpp_parse_tree, symbol_table,
160  ns.get_symbol_table(), "", message_handler);
161 
162  try
163  {
164  cpp_typecheck.typecheck_expr(expr);
165  }
166 
167  catch(int)
168  {
169  cpp_typecheck.error();
170  }
171 
172  catch(const char *e)
173  {
174  cpp_typecheck.error() << e << messaget::eom;
175  }
176 
177  catch(const std::string &e)
178  {
179  cpp_typecheck.error() << e << messaget::eom;
180  }
181 
182  catch(const invalid_source_file_exceptiont &e)
183  {
184  cpp_typecheck.error().source_location = e.get_source_location();
185  cpp_typecheck.error() << e.get_reason() << messaget::eom;
186  }
187 
188  return message_handler.get_message_count(messaget::M_ERROR)!=errors_before;
189 }
190 
206 {
207  code_blockt init_block; // Dynamic Initialization Block
208 
209  disable_access_control = true;
210 
211  for(const irep_idt &d_it : dynamic_initializations)
212  {
213  symbolt &symbol = symbol_table.get_writeable_ref(d_it);
214 
215  if(symbol.is_extern)
216  continue;
217 
218  // PODs are always statically initialized
219  if(cpp_is_pod(symbol.type))
220  continue;
221 
222  DATA_INVARIANT(symbol.is_static_lifetime, "should be static");
223  DATA_INVARIANT(!symbol.is_type, "should not be a type");
224  DATA_INVARIANT(symbol.type.id() != ID_code, "should not be code");
225 
226  exprt symbol_expr=cpp_symbol_expr(symbol);
227 
228  // initializer given?
229  if(symbol.value.is_not_nil())
230  {
231  // This will be a constructor call,
232  // which we execute.
233  init_block.add(to_code(symbol.value));
234 
235  // Make it nil to get zero initialization by
236  // __CPROVER_initialize
237  symbol.value.make_nil();
238  }
239  else
240  {
241  // use default constructor
242  exprt::operandst ops;
243 
244  auto call = cpp_constructor(symbol.location, symbol_expr, ops);
245 
246  if(call.has_value())
247  init_block.add(call.value());
248  }
249  }
250 
251  dynamic_initializations.clear();
252 
253  // Create the dynamic initialization procedure
255  "#cpp_dynamic_initialization#" + id2string(module),
256  code_typet({}, typet(ID_constructor)),
257  ID_cpp};
258  init_symbol.base_name="#cpp_dynamic_initialization#"+id2string(module);
259  init_symbol.value.swap(init_block);
260  init_symbol.module=module;
261 
262  symbol_table.insert(std::move(init_symbol));
263 
265 }
266 
268 {
269  bool cont;
270 
271  do
272  {
273  cont = false;
274 
275  for(auto it = symbol_table.begin(); it != symbol_table.end(); ++it)
276  {
277  const symbolt &symbol = it->second;
278 
279  if(
280  symbol.value.id() == ID_cpp_not_typechecked &&
281  symbol.value.get_bool(ID_is_used))
282  {
283  DATA_INVARIANT(symbol.type.id() == ID_code, "must be code");
284  exprt value = symbol.value;
285 
286  if(symbol.base_name=="operator=")
287  {
288  cpp_declaratort declarator;
289  declarator.add_source_location() = symbol.location;
291  lookup(symbol.type.get(ID_C_member_name)), declarator);
292  value.swap(declarator.value());
293  cont=true;
294  }
295  else if(symbol.value.operands().size()==1)
296  {
297  value = to_unary_expr(symbol.value).op();
298  cont=true;
299  }
300  else
301  UNREACHABLE; // Don't know what to do!
302 
303  symbolt &writable_symbol = it.get_writeable_symbol();
304  writable_symbol.value.swap(value);
305  convert_function(writable_symbol);
306  }
307  }
308  }
309  while(cont);
310 
311  for(auto it = symbol_table.begin(); it != symbol_table.end(); ++it)
312  {
313  if(it->second.value.id() == ID_cpp_not_typechecked)
314  it.get_writeable_symbol().value.make_nil();
315  }
316 }
317 
319 {
320  auto it = symbol_table.begin();
321 
322  while(it != symbol_table.end())
323  {
324  auto cur_it = it;
325  it++;
326 
327  const symbolt &symbol=cur_it->second;
328 
329  // erase templates and all member functions that have not been converted
330  if(
331  symbol.type.get_bool(ID_is_template) ||
332  deferred_typechecking.find(symbol.name) != deferred_typechecking.end())
333  {
334  symbol_table.erase(cur_it);
335  continue;
336  }
337  else if(symbol.type.id()==ID_struct ||
338  symbol.type.id()==ID_union)
339  {
340  // remove methods from 'components'
341  struct_union_typet &struct_union_type =
342  to_struct_union_type(cur_it.get_writeable_symbol().type);
343 
344  const struct_union_typet::componentst &components=
345  struct_union_type.components();
346 
347  struct_union_typet::componentst data_members;
348  data_members.reserve(components.size());
349 
350  struct_union_typet::componentst &function_members=
352  (struct_union_type.add(ID_methods).get_sub());
353 
354  function_members.reserve(components.size());
355 
356  for(const auto &compo_it : components)
357  {
358  if(compo_it.get_bool(ID_is_static) ||
359  compo_it.get_bool(ID_is_type))
360  {
361  // skip it
362  }
363  else if(compo_it.type().id()==ID_code)
364  {
365  function_members.push_back(compo_it);
366  }
367  else
368  {
369  data_members.push_back(compo_it);
370  }
371  }
372 
373  struct_union_type.components().swap(data_members);
374  }
375  }
376 }
377 
379 {
382 }
383 
385 {
386  if(expr.id() == ID_cpp_name || expr.id() == ID_cpp_declaration)
387  return true;
388 
389  for(const exprt &op : expr.operands())
390  {
391  if(contains_cpp_name(op))
392  return true;
393  }
394  return false;
395 }
configt config
Definition: config.cpp:25
bool builtin_factory(const irep_idt &identifier, bool support_float16_type, symbol_table_baset &symbol_table, message_handlert &mh)
Check whether given identifier is a compiler built-in.
symbol_table_baset & symbol_table
const irep_idt module
A codet representing sequential composition of program statements.
Definition: std_code.h:130
void add(const codet &code)
Definition: std_code.h:168
Base type of functions.
Definition: std_types.h:583
struct configt::ansi_ct ansi_c
exprt this_expr
Definition: cpp_id.h:76
bool is_namespace_spec() const
Definition: cpp_item.h:94
const source_locationt & source_location() const
Definition: cpp_item.h:143
cpp_usingt & get_using()
Definition: cpp_item.h:107
cpp_static_assertt & get_static_assert()
Definition: cpp_item.h:132
cpp_linkage_spect & get_linkage_spec()
Definition: cpp_item.h:57
bool is_static_assert() const
Definition: cpp_item.h:138
bool is_using() const
Definition: cpp_item.h:119
bool is_declaration() const
Definition: cpp_item.h:44
bool is_linkage_spec() const
Definition: cpp_item.h:69
cpp_namespace_spect & get_namespace_spec()
Definition: cpp_item.h:82
cpp_scopet & current_scope()
Definition: cpp_scopes.h:32
void static_and_dynamic_initialization()
Initialization of static objects:
bool contains_cpp_name(const exprt &)
void do_not_typechecked()
dynamic_initializationst dynamic_initializations
void convert_function(symbolt &symbol)
irep_idt current_linkage_spec
Definition: cpp_typecheck.h:95
bool cpp_is_pod(const typet &type) const
Definition: cpp_is_pod.cpp:16
std::optional< codet > cpp_constructor(const source_locationt &source_location, const exprt &object, const exprt::operandst &operands)
void convert(cpp_linkage_spect &)
std::unordered_set< irep_idt > deferred_typechecking
void default_assignop_value(const symbolt &symbol, cpp_declaratort &declarator)
Generate code for the implicit default assignment operator.
bool support_float16_type
cpp_typecheckt(cpp_parse_treet &_cpp_parse_tree, symbol_table_baset &_symbol_table, const std::string &_module, message_handlert &message_handler)
bool builtin_factory(const irep_idt &) override
void typecheck() override
typechecking main method
std::string to_string(const typet &) override
bool disable_access_control
const struct_typet & this_struct_type()
cpp_parse_treet & cpp_parse_tree
Definition: cpp_typecheck.h:94
cpp_scopest cpp_scopes
Definition: cpp_typecheck.h:92
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
source_locationt & add_source_location()
Definition: expr.h:236
typet & type()
Return the type of the expression.
Definition: expr.h:84
operandst & operands()
Definition: expr.h:94
bool is_at_least(unsigned v_major, unsigned v_minor=0, unsigned v_patchlevel=0) const
void get(const std::string &executable)
Definition: gcc_version.cpp:18
enum gcc_versiont::flavort flavor
Thrown when we can't handle something in an input source file.
bool get_bool(const irep_idt &name) const
Definition: irep.cpp:57
subt & get_sub()
Definition: irep.h:444
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:44
bool is_not_nil() const
Definition: irep.h:368
const irep_idt & id() const
Definition: irep.h:384
void make_nil()
Definition: irep.h:442
void swap(irept &irep)
Definition: irep.h:430
irept & add(const irep_idt &name)
Definition: irep.cpp:103
std::size_t get_message_count(unsigned level) const
Definition: message.h:56
source_locationt source_location
Definition: message.h:247
mstreamt & error() const
Definition: message.h:399
message_handlert & get_message_handler()
Definition: message.h:184
@ M_ERROR
Definition: message.h:170
static eomt eom
Definition: message.h:297
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
const symbolt & lookup(const irep_idt &name) const
Lookup a symbol in the namespace.
Definition: namespace.h:46
const symbol_table_baset & get_symbol_table() const
Return first symbol table registered with the namespace.
Definition: namespace.h:126
const typet & base_type() const
The type of the data what we point to.
Definition: pointer_expr.h:35
Structure type, corresponds to C style structs.
Definition: std_types.h:231
Base type for structs and unions.
Definition: std_types.h:62
const componentst & components() const
Definition: std_types.h:147
std::vector< componentt > componentst
Definition: std_types.h:140
The symbol table base class interface.
symbolt & get_writeable_ref(const irep_idt &name)
Find a symbol in the symbol table for read-write access.
virtual void erase(const symbolst::const_iterator &entry)=0
Remove a symbol from the symbol table.
virtual iteratort begin()=0
virtual iteratort end()=0
virtual std::pair< symbolt &, bool > insert(symbolt symbol)=0
Move or copy a new symbol to the symbol table.
The symbol table.
Definition: symbol_table.h:14
Symbol table entry.
Definition: symbol.h:28
irep_idt base_name
Base (non-scoped) name.
Definition: symbol.h:46
bool is_extern
Definition: symbol.h:74
bool is_static_lifetime
Definition: symbol.h:70
bool is_type
Definition: symbol.h:61
source_locationt location
Source code location of definition of symbol.
Definition: symbol.h:37
typet type
Type of symbol.
Definition: symbol.h:31
irep_idt name
The unique identifier.
Definition: symbol.h:40
exprt value
Initial value of symbol.
Definition: symbol.h:34
The type of an expression, extends irept.
Definition: type.h:29
const exprt & op() const
Definition: std_expr.h:391
cpp_declarationt & to_cpp_declaration(irept &irep)
C++ Language Type Checking.
bool cpp_typecheck(cpp_parse_treet &cpp_parse_tree, symbol_table_baset &symbol_table, const std::string &module, message_handlert &message_handler)
C++ Language Type Checking.
symbol_exprt cpp_symbol_expr(const symbolt &symbol)
Definition: cpp_util.cpp:14
std::string type2cpp(const typet &type, const namespacet &ns)
Definition: expr2cpp.cpp:507
std::string expr2cpp(const exprt &expr, const namespacet &ns)
Definition: expr2cpp.cpp:500
const std::string & id2string(const irep_idt &d)
Definition: irep.h:40
static std::unordered_set< irep_idt > init_symbol(const symbolt &sym, code_blockt &code_block, symbol_table_baset &symbol_table, const source_locationt &source_location, bool assume_init_pointers_not_null, const java_object_factory_parameterst &object_factory_parameters, const select_pointer_typet &pointer_type_selector, bool string_refinement_enabled, message_handlert &message_handler)
API to expression classes for Pointers.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition: pointer_expr.h:93
#define CHECK_RETURN(CONDITION)
Definition: invariant.h:495
#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
const codet & to_code(const exprt &expr)
const unary_exprt & to_unary_expr(const exprt &expr)
Cast an exprt to a unary_exprt.
Definition: std_expr.h:426
const struct_union_typet & to_struct_union_type(const typet &type)
Cast a typet to a struct_union_typet.
Definition: std_types.h:214
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition: std_types.h:518
preprocessort preprocessor
Definition: config.h:263
Author: Diffblue Ltd.