CBMC
cpp_declarator_converter.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 
13 
14 #include <util/c_types.h>
16 #include <util/source_location.h>
17 #include <util/std_types.h>
18 #include <util/symbol_table_base.h>
19 
20 #include "cpp_type2name.h"
21 #include "cpp_typecheck.h"
22 #include "cpp_typecheck_fargs.h"
23 
25  class cpp_typecheckt &_cpp_typecheck):
26  is_typedef(false),
27  is_template(false),
28  is_template_parameter(false),
29  is_friend(false),
30  linkage_spec(_cpp_typecheck.current_linkage_spec),
31  cpp_typecheck(_cpp_typecheck),
32  is_code(false)
33 {
34 }
35 
37  const typet &declaration_type,
38  const cpp_storage_spect &storage_spec,
39  const cpp_member_spect &member_spec,
40  cpp_declaratort &declarator)
41 {
42  PRECONDITION(declaration_type.is_not_nil());
43 
44  if(declaration_type.id()=="cpp-cast-operator")
45  {
46  typet type;
47  type.swap(declarator.name().get_sub().back());
48  declarator.type().add_subtype() = type;
50  cpp_namet::namet name("(" + cpp_type2name(type) + ")");
51  declarator.name().get_sub().back().swap(name);
52  }
53 
54  PRECONDITION(declarator.id() == ID_cpp_declarator);
55  final_type=declarator.merge_type(declaration_type);
57 
58  cpp_storage_spect final_storage_spec = storage_spec;
59  final_storage_spec |= cpp_storage_spect(final_type);
60 
61  cpp_template_args_non_tct template_args;
62 
63  // run resolver on scope
64  {
66 
67  cpp_typecheck_resolvet cpp_typecheck_resolve(cpp_typecheck);
68 
69  cpp_typecheck_resolve.resolve_scope(
70  declarator.name(), base_name, template_args);
71 
72  cpp_scopet *friend_scope = nullptr;
73 
74  if(is_friend)
75  {
76  friend_scope = &cpp_typecheck.cpp_scopes.current_scope();
77  save_scope.restore();
78  }
79 
81 
82  // check the declarator-part of the type, in the current scope
83  if(declarator.value().is_nil() || !cpp_typecheck.has_auto(final_type))
85 
86  if(friend_scope)
87  scope = friend_scope;
88  }
89 
91 
92  // global-scope arrays must have fixed size
93  if(scope->is_global_scope())
95 
97 
98  if(is_typedef)
99  final_type.set(ID_C_typedef, final_identifier);
100 
101  // first see if it is a member
103  {
104  // it's a member! it must be declared already, unless it's a friend
105 
106  typet &method_qualifier=
107  static_cast<typet &>(declarator.method_qualifier());
108 
109  // adjust template type
110  if(final_type.id()==ID_template)
111  {
112  UNREACHABLE;
113  typet tmp;
115  final_type.swap(tmp);
116  }
117 
118  // try static first
119  auto maybe_symbol=
121 
122  if(!maybe_symbol)
123  {
124  // adjust type if it's a non-static member function
125  if(final_type.id()==ID_code)
126  {
129 
133  method_qualifier);
134  }
135 
137 
138  // try again
140  if(!maybe_symbol && is_friend)
141  {
142  symbolt &friend_symbol =
143  convert_new_symbol(final_storage_spec, member_spec, declarator);
144  // mark it as weak so that the full declaration can replace the symbol
145  friend_symbol.is_weak = true;
146  return friend_symbol;
147  }
148  else if(!maybe_symbol)
149  {
151  declarator.name().source_location();
153  << "member '" << base_name << "' not found in scope '"
154  << scope->identifier << "'" << messaget::eom;
155  throw 0;
156  }
157  }
158 
159  symbolt &symbol=*maybe_symbol;
160 
161  combine_types(declarator.name().source_location(), final_type, symbol);
162  enforce_rules(symbol);
163 
164  // If it is a constructor, we take care of the
165  // object initialization
166  if(to_code_type(final_type).return_type().id() == ID_constructor)
167  {
168  const cpp_namet &name=declarator.name();
169 
170  exprt symbol_expr=
172  name,
175 
176  if(symbol_expr.id() != ID_type)
177  {
179  cpp_typecheck.error() << "expected type" << messaget::eom;
180  throw 0;
181  }
182 
183  irep_idt identifier=symbol_expr.type().get(ID_identifier);
184  const symbolt &symb=cpp_typecheck.lookup(identifier);
185  const struct_typet &type = to_struct_type(symb.type);
186 
187  if(declarator.find(ID_member_initializers).is_nil())
188  declarator.set(ID_member_initializers, ID_member_initializers);
189 
191  type.bases(), type.components(), declarator.member_initializers());
192 
194  type, declarator.member_initializers());
195  }
196 
197  if(!final_storage_spec.is_extern())
198  symbol.is_extern=false;
199 
200  // initializer?
201  handle_initializer(symbol, declarator);
202 
203  return symbol;
204  }
205  else
206  {
207  // no, it's no way a method
208 
209  // we won't allow the constructor/destructor type
210  if(final_type.id()==ID_code &&
211  to_code_type(final_type).return_type().id()==ID_constructor)
212  {
214  cpp_typecheck.error() << "function must have return type"
215  << messaget::eom;
216  throw 0;
217  }
218 
219  // already there?
220  const auto maybe_symbol=
222  if(!maybe_symbol)
223  return convert_new_symbol(final_storage_spec, member_spec, declarator);
224  symbolt &symbol=*maybe_symbol;
225 
226  if(!final_storage_spec.is_extern())
227  symbol.is_extern = false;
228 
229  if(declarator.get_bool(ID_C_template_case))
230  return symbol;
231 
232  combine_types(declarator.name().source_location(), final_type, symbol);
233  enforce_rules(symbol);
234 
235  // initializer?
236  handle_initializer(symbol, declarator);
237 
238  if(symbol.type.id()=="cpp-template-type")
239  {
240  const auto id_set = scope->lookup_identifier(
242 
243  if(id_set.empty())
244  {
245  cpp_idt &identifier=
248  }
249  }
250 
251  return symbol;
252  }
253 }
254 
256  const source_locationt &source_location,
257  const typet &decl_type,
258  symbolt &symbol)
259 {
260  if(symbol.type.id()==decl_type.id() &&
261  decl_type.id()==ID_code)
262  {
263  // functions need special treatment due
264  // to argument names, default values, and inlined-ness
265  const code_typet &decl_code_type=to_code_type(decl_type);
266  code_typet &symbol_code_type=to_code_type(symbol.type);
267 
268  if(decl_code_type.get_inlined())
269  symbol_code_type.set_inlined(true);
270 
271  if(decl_code_type.return_type()==symbol_code_type.return_type() &&
272  decl_code_type.parameters().size()==symbol_code_type.parameters().size())
273  {
274  for(std::size_t i=0; i<decl_code_type.parameters().size(); i++)
275  {
276  const code_typet::parametert &decl_parameter=
277  decl_code_type.parameters()[i];
278  code_typet::parametert &symbol_parameter=
279  symbol_code_type.parameters()[i];
280 
281  // first check type
282  if(decl_parameter.type()!=symbol_parameter.type())
283  {
284  // The 'this' parameter of virtual functions mismatches
285  if(i != 0 || !symbol_code_type.get_bool(ID_C_is_virtual))
286  {
287  cpp_typecheck.error().source_location=source_location;
289  << "symbol '" << symbol.display_name() << "': parameter "
290  << (i + 1) << " type mismatch\n"
291  << "previous type: "
292  << cpp_typecheck.to_string(symbol_parameter.type())
293  << "\nnew type: "
294  << cpp_typecheck.to_string(decl_parameter.type())
295  << messaget::eom;
296  throw 0;
297  }
298  }
299 
300  if(symbol.value.is_nil())
301  {
302  symbol_parameter.set_base_name(decl_parameter.get_base_name());
303  // set an empty identifier when no body is available
304  symbol_parameter.set_identifier(irep_idt());
305  symbol_parameter.add_source_location()=
306  decl_parameter.source_location();
307  }
308  }
309 
310  // ok
311  return;
312  }
313  }
314  else if(symbol.type==decl_type)
315  return; // ok
316  else if(
317  symbol.type.id() == ID_array &&
318  to_array_type(symbol.type).size().is_nil() && decl_type.id() == ID_array &&
319  to_array_type(symbol.type).element_type() ==
320  to_array_type(decl_type).element_type())
321  {
322  symbol.type = decl_type;
323  return; // ok
324  }
325 
326  cpp_typecheck.error().source_location=source_location;
327  cpp_typecheck.error() << "symbol '" << symbol.display_name()
328  << "' already declared with different type:\n"
329  << "original: " << cpp_typecheck.to_string(symbol.type)
330  << "\n new: " << cpp_typecheck.to_string(final_type)
331  << messaget::eom;
332  throw 0;
333 }
334 
336 {
337  // enforce rules for operator overloading
339 
340  // enforce rules about main()
341  main_function_rules(symbol);
342 }
343 
345  symbolt &symbol,
346  cpp_declaratort &declarator)
347 {
348  exprt &value=declarator.value();
349 
350  // moves member initializers into 'value' - only methods have these
351  if(symbol.type.id() == ID_code)
353  declarator.member_initializers(), to_code_type(symbol.type), value);
354 
355  // any initializer to be done?
356  if(value.is_nil())
357  return;
358 
359  if(symbol.is_extern)
360  {
361  // the symbol is really located here
362  symbol.is_extern=false;
363  }
364 
365  if(symbol.value.is_nil())
366  {
367  // no initial value yet
368  symbol.value.swap(value);
369 
370  if(!is_code)
372  }
373  else
374  {
375 #if 0
376  cpp_typecheck.error().source_location=source_location;
377 
378  if(is_code)
379  {
380  cpp_typecheck.error() << "body of function '"
381  << symbol.display_name()
382  << "' has already been defined" << messaget::eom;
383  }
384  else
385  {
386  cpp_typecheck.error() << "symbol '"
387  << symbol.display_name()
388  << "' already has an initializer" << messaget::eom;
389  }
390 
391  throw 0;
392 #endif
393  }
394 }
395 
397 {
398  std::string identifier=id2string(base_name);
399 
400  // main is always "C" linkage, as a matter of principle
401  if(is_code && base_name == ID_main && scope->prefix.empty())
402  {
403  linkage_spec=ID_C;
404  }
405 
406  if(is_code)
407  {
408  if(linkage_spec==ID_C)
409  {
410  // fine as is
411  }
412  else if(linkage_spec==ID_auto ||
413  linkage_spec==ID_cpp)
414  {
415  // Is there already an `extern "C"' function with the same name
416  // and the same signature?
417  symbol_table_baset::symbolst::const_iterator c_it =
418  cpp_typecheck.symbol_table.symbols.find(identifier);
419 
420  if(c_it!=cpp_typecheck.symbol_table.symbols.end() &&
421  c_it->second.type.id()==ID_code &&
423  cpp_typecheck.function_identifier(c_it->second.type))
424  {
425  // leave as is, no decoration
426  }
427  else
428  {
429  // add C++ decoration
431  }
432  }
433  }
434 
435  final_identifier = scope->prefix + identifier;
436 }
437 
439  const cpp_storage_spect &storage_spec,
440  const cpp_member_spect &member_spec,
441  cpp_declaratort &declarator)
442 {
443  irep_idt pretty_name=get_pretty_name();
444 
445  symbolt symbol{
447  final_type,
448  linkage_spec == ID_auto ? ID_cpp : linkage_spec};
449  symbol.base_name=base_name;
450  symbol.value=declarator.value();
451  symbol.location=declarator.name().source_location();
452  symbol.is_extern = storage_spec.is_extern();
453  symbol.is_parameter = declarator.get_is_parameter();
454  symbol.is_weak = storage_spec.is_weak();
455  symbol.module=cpp_typecheck.module;
456  symbol.is_type=is_typedef;
457  symbol.is_macro=is_typedef && !is_template_parameter;
458  symbol.pretty_name=pretty_name;
459 
460  if(is_code && !symbol.is_type)
461  {
462  // it is a function
463  symbol.is_static_lifetime = false;
464  symbol.is_thread_local = false;
465 
466  symbol.is_file_local = storage_spec.is_static();
467 
468  if(member_spec.is_inline())
469  to_code_type(symbol.type).set_inlined(true);
470 
471  if(symbol.value.is_nil())
472  {
473  // we don't need the identifiers
474  for(auto &parameter : to_code_type(symbol.type).parameters())
475  parameter.set_identifier(irep_idt());
476  }
477  }
478  else
479  {
480  symbol.is_lvalue = !is_reference(symbol.type) &&
481  !(symbol.type.get_bool(ID_C_constant) &&
482  is_number(symbol.type) && symbol.value.is_constant());
483 
484  symbol.is_static_lifetime =
485  !symbol.is_macro && !symbol.is_type &&
487  storage_spec.is_static());
488 
489  symbol.is_thread_local =
490  (!symbol.is_static_lifetime && !storage_spec.is_extern()) ||
491  storage_spec.is_thread_local();
492 
493  symbol.is_file_local =
494  symbol.is_macro ||
496  !storage_spec.is_extern()) ||
498  storage_spec.is_static()) ||
499  symbol.is_parameter;
500  }
501 
502  if(symbol.is_static_lifetime)
503  cpp_typecheck.dynamic_initializations.push_back(symbol.name);
504 
505  // move early, it must be visible before doing any value
506  symbolt *new_symbol;
507 
508  if(cpp_typecheck.symbol_table.move(symbol, new_symbol))
509  {
510  cpp_typecheck.error().source_location=symbol.location;
512  << "cpp_typecheckt::convert_declarator: symbol_table.move() failed"
513  << messaget::eom;
514  throw 0;
515  }
516 
517  if(!is_code)
518  {
519  const auto id_set = cpp_typecheck.cpp_scopes.current_scope().lookup(
521 
522  for(const auto &id_ptr : id_set)
523  {
524  const cpp_idt &id = *id_ptr;
525  // the name is already in the scope
526  // this is ok if they belong to different categories
527 
528  if(!id.is_class() && !id.is_enum())
529  {
532  << "'" << base_name << "' already in scope" << messaget::eom;
533  throw 0;
534  }
535  }
536  }
537 
538  // put into scope
539  cpp_idt &identifier=
541 
542  if(is_template)
544  else if(is_template_parameter)
546  else if(is_typedef)
548  else
550 
551  // do the value
552  if(!new_symbol->is_type)
553  {
554  if(is_code && declarator.type().id()!=ID_template)
555  cpp_typecheck.add_method_body(new_symbol);
556 
557  if(!is_code)
558  cpp_typecheck.convert_initializer(*new_symbol);
559  }
560 
561  enforce_rules(*new_symbol);
562 
563  return *new_symbol;
564 }
565 
567 {
568  if(is_code)
569  {
570  const irept::subt &parameters=
571  final_type.find(ID_parameters).get_sub();
572 
573  std::string result=scope->prefix+id2string(base_name)+"(";
574 
575  for(auto it = parameters.begin(); it != parameters.end(); ++it)
576  {
577  const typet &parameter_type = ((exprt &)*it).type();
578 
579  if(it!=parameters.begin())
580  result+=", ";
581 
582  result+=cpp_typecheck.to_string(parameter_type);
583  }
584 
585  result+=')';
586 
587  return result;
588  }
589 
590  return scope->prefix+id2string(base_name);
591 }
592 
594  const symbolt &)
595 {
596 }
597 
599  const symbolt &symbol)
600 {
601  if(symbol.name==ID_main)
602  {
603  if(symbol.type.id()!=ID_code)
604  {
606  cpp_typecheck.error() << "main must be function" << messaget::eom;
607  throw 0;
608  }
609 
610  const typet &return_type=
611  to_code_type(symbol.type).return_type();
612 
613  if(return_type!=signed_int_type())
614  {
615  // Too many embedded compilers ignore this rule.
616  #if 0
618  throw "main must return int";
619  #endif
620  }
621  }
622 }
signedbv_typet signed_int_type()
Definition: c_types.cpp:22
const typet & element_type() const
The type of the elements of the array.
Definition: std_types.h:827
const exprt & size() const
Definition: std_types.h:840
symbol_table_baset & symbol_table
const irep_idt module
void set_base_name(const irep_idt &name)
Definition: std_types.h:629
const irep_idt & get_base_name() const
Definition: std_types.h:639
void set_identifier(const irep_idt &identifier)
Definition: std_types.h:624
Base type of functions.
Definition: std_types.h:583
const typet & return_type() const
Definition: std_types.h:689
void set_inlined(bool value)
Definition: std_types.h:714
bool get_inlined() const
Definition: std_types.h:709
const parameterst & parameters() const
Definition: std_types.h:699
void handle_initializer(symbolt &symbol, cpp_declaratort &declarator)
symbolt & convert_new_symbol(const cpp_storage_spect &storage_spec, const cpp_member_spect &member_spec, cpp_declaratort &declarator)
bool is_code_type(const typet &type) const
void operator_overloading_rules(const symbolt &symbol)
cpp_declarator_convertert(class cpp_typecheckt &_cpp_typecheck)
void combine_types(const source_locationt &source_location, const typet &decl_type, symbolt &symbol)
void main_function_rules(const symbolt &symbol)
symbolt & convert(const typet &type, const cpp_storage_spect &storage_spec, const cpp_member_spect &member_spec, cpp_declaratort &declarator)
class cpp_typecheckt & cpp_typecheck
void enforce_rules(const symbolt &symbol)
irept & member_initializers()
irept & method_qualifier()
cpp_namet & name()
typet merge_type(const typet &declaration_type) const
bool get_is_parameter() const
Definition: cpp_id.h:23
irep_idt identifier
Definition: cpp_id.h:72
std::string prefix
Definition: cpp_id.h:79
id_classt id_class
Definition: cpp_id.h:45
bool is_inline() const
const source_locationt & source_location() const
Definition: cpp_name.h:73
void go_to(cpp_idt &id)
Definition: cpp_scopes.h:103
cpp_scopet & current_scope()
Definition: cpp_scopes.h:32
cpp_idt & put_into_scope(const symbolt &symbol, cpp_scopet &scope, bool is_friend=false)
Definition: cpp_scopes.cpp:24
bool is_global_scope() const
Definition: cpp_scope.h:82
@ SCOPE_ONLY
Definition: cpp_scope.h:30
id_sett lookup_identifier(const irep_idt &id, cpp_idt::id_classt identifier_class)
Definition: cpp_scope.cpp:157
id_sett lookup(const irep_idt &base_name_to_lookup, lookup_kindt kind)
Definition: cpp_scope.h:32
bool is_static() const
bool is_thread_local() const
bool is_extern() const
bool is_weak() const
cpp_scopet & resolve_scope(const cpp_namet &cpp_name, irep_idt &base_name, cpp_template_args_non_tct &template_args)
void typecheck_type(typet &) override
void full_member_initialization(const struct_union_typet &struct_union_type, irept &initializers)
Build the full initialization list of the constructor.
dynamic_initializationst dynamic_initializations
void convert_initializer(symbolt &symbol)
Initialize an object with a value.
void check_fixed_size_array(typet &type)
check that an array has fixed size
void add_method_body(symbolt *_method_symbol)
void check_member_initializers(const struct_typet::basest &bases, const struct_typet::componentst &components, const irept &initializers)
Check a constructor initialization-list.
static bool has_auto(const typet &type)
irep_idt function_identifier(const typet &type)
for function overloading
void add_this_to_method_type(const symbolt &compound_symbol, code_typet &method_type, const typet &method_qualifier)
void move_member_initializers(irept &initializers, const code_typet &type, exprt &value)
std::string to_string(const typet &) override
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:71
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
source_locationt & add_source_location()
Definition: expr.h:236
const source_locationt & source_location() const
Definition: expr.h:231
typet & type()
Return the type of the expression.
Definition: expr.h:84
bool get_bool(const irep_idt &name) const
Definition: irep.cpp:57
subt & get_sub()
Definition: irep.h:444
const irept & find(const irep_idt &name) const
Definition: irep.cpp:93
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:44
void set(const irep_idt &name, const irep_idt &value)
Definition: irep.h:408
bool is_not_nil() const
Definition: irep.h:368
const irep_idt & id() const
Definition: irep.h:384
void swap(irept &irep)
Definition: irep.h:430
bool is_nil() const
Definition: irep.h:364
source_locationt source_location
Definition: message.h:247
mstreamt & error() const
Definition: message.h:399
static eomt eom
Definition: message.h:297
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
Definition: namespace.cpp:148
Structure type, corresponds to C style structs.
Definition: std_types.h:231
const basest & bases() const
Get the collection of base classes/structs.
Definition: std_types.h:262
const componentst & components() const
Definition: std_types.h:147
virtual bool move(symbolt &symbol, symbolt *&new_symbol)=0
const symbolst & symbols
Read-only field, used to look up symbols given their names.
virtual symbolt * get_writeable(const irep_idt &name)=0
Find a symbol in the symbol table for read-write access.
Symbol table entry.
Definition: symbol.h:28
bool is_extern
Definition: symbol.h:74
const irep_idt & display_name() const
Return language specific display name if present.
Definition: symbol.h:55
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
bool is_weak
Definition: symbol.h:78
irep_idt name
The unique identifier.
Definition: symbol.h:40
exprt value
Initial value of symbol.
Definition: symbol.h:34
const typet & subtype() const
The type of an expression, extends irept.
Definition: type.h:29
typet & add_subtype()
Definition: type.h:53
C++ Language Type Checking.
template_typet & to_template_type(typet &type)
std::string cpp_type2name(const typet &type)
C++ Language Module.
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.
C++ Language Type Checking.
const std::string & id2string(const irep_idt &d)
Definition: irep.h:40
bool is_number(const typet &type)
Returns true if the type is a rational, real, integer, natural, complex, unsignedbv,...
Mathematical types.
bool is_reference(const typet &type)
Returns true if the type is a reference.
Definition: std_types.cpp:144
#define CHECK_RETURN(CONDITION)
Definition: invariant.h:495
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:525
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
Pre-defined types.
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition: std_types.h:308
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition: std_types.h:788
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:888
Author: Diffblue Ltd.
dstringt irep_idt