cprover
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/source_location.h>
15 #include <util/std_types.h>
16 
17 #include <util/c_types.h>
18 
19 #include "cpp_type2name.h"
20 #include "cpp_typecheck.h"
21 
23  class cpp_typecheckt &_cpp_typecheck):
24  is_typedef(false),
25  is_template(false),
26  is_template_parameter(false),
27  is_friend(false),
28  linkage_spec(_cpp_typecheck.current_linkage_spec),
29  cpp_typecheck(_cpp_typecheck),
30  is_code(false)
31 {
32 }
33 
35  const typet &declaration_type,
36  const cpp_storage_spect &storage_spec,
37  const cpp_member_spect &member_spec,
38  cpp_declaratort &declarator)
39 {
40  assert(declaration_type.is_not_nil());
41 
42  if(declaration_type.id()=="cpp-cast-operator")
43  {
44  typet type;
45  type.swap(declarator.name().get_sub().back());
46  declarator.type().subtype()=type;
48  irept name(ID_name);
49  name.set(ID_identifier, "("+cpp_type2name(type)+")");
50  declarator.name().get_sub().back().swap(name);
51  }
52 
53  assert(declarator.id()==ID_cpp_declarator);
54  final_type=declarator.merge_type(declaration_type);
55  assert(final_type.is_not_nil());
56 
57  cpp_template_args_non_tct template_args;
58 
59  // run resolver on scope
60  {
62 
63  cpp_typecheck_resolvet cpp_typecheck_resolve(cpp_typecheck);
64 
65  cpp_typecheck_resolve.resolve_scope(
66  declarator.name(), base_name, template_args);
67 
69 
70  // check the declarator-part of the type, in that scope
71  if(declarator.value().is_nil() || !cpp_typecheck.has_auto(final_type))
73  }
74 
76 
77  // global-scope arrays must have fixed size
78  if(scope->is_global_scope())
80 
82 
83  // first see if it is a member
85  {
86  // it's a member! it must be declared already
87 
88  typet &method_qualifier=
89  static_cast<typet &>(declarator.method_qualifier());
90 
91  // adjust template type
92  if(final_type.id()==ID_template)
93  {
95  typet tmp;
96  tmp.swap(final_type.subtype());
97  final_type.swap(tmp);
98  }
99 
100  // try static first
101  auto maybe_symbol=
103 
104  if(!maybe_symbol)
105  {
106  // adjust type if it's a non-static member function
107  if(final_type.id()==ID_code)
109  scope->identifier, final_type, method_qualifier);
110 
112 
113  // try again
115  if(!maybe_symbol)
116  {
118  declarator.name().source_location();
119  cpp_typecheck.error() << "member `" << base_name
120  << "' not found in scope `"
121  << scope->identifier << "'"
122  << messaget::eom;
123  throw 0;
124  }
125  }
126 
127  symbolt &symbol=*maybe_symbol;
128 
129  combine_types(declarator.name().source_location(), final_type, symbol);
130  enforce_rules(symbol);
131 
132  // If it is a constructor, we take care of the
133  // object initialization
134  if(final_type.get(ID_return_type)==ID_constructor)
135  {
136  const cpp_namet &name=declarator.name();
137 
138  exprt symbol_expr=
140  name,
143 
144  if(symbol_expr.id()!=ID_type ||
145  symbol_expr.type().id()!=ID_symbol)
146  {
148  cpp_typecheck.error() << "error: expected type"
149  << messaget::eom;
150  throw 0;
151  }
152 
153  irep_idt identifier=symbol_expr.type().get(ID_identifier);
154  const symbolt &symb=cpp_typecheck.lookup(identifier);
155  const typet &type = symb.type;
156  assert(type.id()==ID_struct);
157 
158  if(declarator.find(ID_member_initializers).is_nil())
159  declarator.set(ID_member_initializers, ID_member_initializers);
160 
162  type.find(ID_bases),
163  to_struct_type(type).components(),
164  declarator.member_initializers());
165 
167  to_struct_type(type),
168  declarator.member_initializers());
169  }
170 
171  if(!storage_spec.is_extern())
172  symbol.is_extern=false;
173 
174  // initializer?
175  handle_initializer(symbol, declarator);
176 
177  return symbol;
178  }
179  else
180  {
181  // no, it's no way a method
182 
183  // we won't allow the constructor/destructor type
184  if(final_type.id()==ID_code &&
185  to_code_type(final_type).return_type().id()==ID_constructor)
186  {
188  cpp_typecheck.error() << "function must have return type"
189  << messaget::eom;
190  throw 0;
191  }
192 
193  // already there?
194  const auto maybe_symbol=
196  if(!maybe_symbol)
197  return convert_new_symbol(storage_spec, member_spec, declarator);
198  symbolt &symbol=*maybe_symbol;
199 
200  if(!storage_spec.is_extern())
201  symbol.is_extern = false;
202 
203  if(declarator.get_bool(ID_C_template_case))
204  return symbol;
205 
206  combine_types(declarator.name().source_location(), final_type, symbol);
207  enforce_rules(symbol);
208 
209  // initializer?
210  handle_initializer(symbol, declarator);
211 
212  if(symbol.type.id()=="cpp-template-type")
213  {
215 
218 
219  if(id_set.empty())
220  {
221  cpp_idt &identifier=
224  }
225  }
226 
227  return symbol;
228  }
229 }
230 
232  const source_locationt &source_location,
233  const typet &decl_type,
234  symbolt &symbol)
235 {
236  if(symbol.type.id()==decl_type.id() &&
237  decl_type.id()==ID_code)
238  {
239  // functions need special treatment due
240  // to argument names, default values, and inlined-ness
241  const code_typet &decl_code_type=to_code_type(decl_type);
242  code_typet &symbol_code_type=to_code_type(symbol.type);
243 
244  if(decl_code_type.get_inlined())
245  symbol_code_type.set_inlined(true);
246 
247  if(decl_code_type.return_type()==symbol_code_type.return_type() &&
248  decl_code_type.parameters().size()==symbol_code_type.parameters().size())
249  {
250  for(std::size_t i=0; i<decl_code_type.parameters().size(); i++)
251  {
252  const code_typet::parametert &decl_parameter=
253  decl_code_type.parameters()[i];
254  code_typet::parametert &symbol_parameter=
255  symbol_code_type.parameters()[i];
256 
257  // first check type
258  if(decl_parameter.type()!=symbol_parameter.type())
259  {
260  // The 'this' parameter of virtual functions mismatches
261  if(i != 0 || !symbol_code_type.get_bool(ID_C_is_virtual))
262  {
263  cpp_typecheck.error().source_location=source_location;
264  cpp_typecheck.error() << "symbol `" << symbol.display_name()
265  << "': parameter " << (i+1)
266  << " type mismatch\n"
267  << "previous type: "
269  symbol_parameter.type())
270  << "\nnew type: "
272  decl_parameter.type())
273  << messaget::eom;
274  throw 0;
275  }
276  }
277 
278  if(symbol.value.is_nil())
279  {
280  symbol_parameter.set_base_name(decl_parameter.get_base_name());
281  symbol_parameter.set_identifier(decl_parameter.get_identifier());
282  symbol_parameter.add_source_location()=
283  decl_parameter.source_location();
284  }
285  }
286 
287  // ok
288  return;
289  }
290  }
291  else if(symbol.type==decl_type)
292  return; // ok
293  else if(symbol.type.id()==ID_array &&
294  symbol.type.find(ID_size).is_nil() &&
295  decl_type.id()==ID_array &&
296  symbol.type.subtype()==decl_type.subtype())
297  {
298  symbol.type = decl_type;
299  return; // ok
300  }
301 
302  cpp_typecheck.error().source_location=source_location;
303  cpp_typecheck.error() << "symbol `" << symbol.display_name()
304  << "' already declared with different type:\n"
305  << "original: "
306  << cpp_typecheck.to_string(symbol.type)
307  << "\n new: "
309  << messaget::eom;
310  throw 0;
311 }
312 
314 {
315  // enforce rules for operator overloading
317 
318  // enforce rules about main()
319  main_function_rules(symbol);
320 }
321 
323  symbolt &symbol,
324  cpp_declaratort &declarator)
325 {
326  exprt &value=declarator.value();
327 
328  // moves member initializers into 'value'
330  declarator.member_initializers(),
331  symbol.type,
332  value);
333 
334  // any initializer to be done?
335  if(value.is_nil())
336  return;
337 
338  if(symbol.is_extern)
339  {
340  // the symbol is really located here
341  symbol.is_extern=false;
342  }
343 
344  if(symbol.value.is_nil())
345  {
346  // no initial value yet
347  symbol.value.swap(value);
348 
349  if(!is_code)
351  }
352  else
353  {
354  #if 0
355  cpp_typecheck.error().source_location=declarator.name());
356 
357  if(is_code)
358  cpp_typecheck.str << "body of function `"
359  << symbol.display_name()
360  << "' has already been defined";
361  else
362  cpp_typecheck.str << "symbol `"
363  << symbol.display_name()
364  << "' already has an initializer";
365 
366  throw 0;
367  #endif
368  }
369 }
370 
372 {
373  std::string identifier=id2string(base_name);
374 
375  // main is always "C" linkage, as a matter of principle
376  if(is_code &&
377  base_name==ID_main &&
378  scope->prefix=="")
379  {
380  linkage_spec=ID_C;
381  }
382 
383  if(is_code)
384  {
385  if(linkage_spec==ID_C)
386  {
387  // fine as is
388  }
389  else if(linkage_spec==ID_auto ||
390  linkage_spec==ID_cpp)
391  {
392  // Is there already an `extern "C"' function with the same name
393  // and the same signature?
394  symbol_tablet::symbolst::const_iterator
395  c_it=cpp_typecheck.symbol_table.symbols.find(identifier);
396 
397  if(c_it!=cpp_typecheck.symbol_table.symbols.end() &&
398  c_it->second.type.id()==ID_code &&
400  cpp_typecheck.function_identifier(c_it->second.type))
401  {
402  // leave as is, no decoration
403  }
404  else
405  {
406  // add C++ decoration
408  }
409  }
410  }
411 
413  scope->prefix+
414  identifier;
415 }
416 
418  const cpp_storage_spect &storage_spec,
419  const cpp_member_spect &member_spec,
420  cpp_declaratort &declarator)
421 {
422  irep_idt pretty_name=get_pretty_name();
423 
424  symbolt symbol;
425 
426  symbol.name=final_identifier;
427  symbol.base_name=base_name;
428  symbol.value=declarator.value();
429  symbol.location=declarator.name().source_location();
430  symbol.mode=linkage_spec==ID_auto?ID_cpp:linkage_spec;
431  symbol.module=cpp_typecheck.module;
432  symbol.type=final_type;
433  symbol.is_type=is_typedef;
435  symbol.pretty_name=pretty_name;
436 
437  // Constant? These are propagated.
438  if(symbol.type.get_bool(ID_C_constant) &&
439  symbol.value.is_not_nil())
440  symbol.is_macro=true;
441 
442  if(member_spec.is_inline())
443  symbol.type.set(ID_C_inlined, true);
444 
445  if(!symbol.is_type)
446  {
447  if(is_code)
448  {
449  // it is a function
450  if(storage_spec.is_static())
451  symbol.is_file_local=true;
452  }
453  else
454  {
455  // it is a variable
456  symbol.is_state_var=true;
457  symbol.is_lvalue = !is_reference(symbol.type) &&
458  !(symbol.type.get_bool(ID_C_constant) &&
459  is_number(symbol.type) &&
460  symbol.value.id() == ID_constant);
461 
463  {
464  symbol.is_static_lifetime=true;
465 
466  if(storage_spec.is_extern())
467  symbol.is_extern=true;
468  }
469  else
470  {
471  if(storage_spec.is_static())
472  {
473  symbol.is_static_lifetime=true;
474  symbol.is_file_local=true;
475  }
476  else if(storage_spec.is_extern())
477  {
478  cpp_typecheck.error().source_location=storage_spec.location();
479  cpp_typecheck.error() << "external storage not permitted here"
480  << messaget::eom;
481  throw 0;
482  }
483  }
484  }
485  }
486 
487  if(symbol.is_static_lifetime)
488  cpp_typecheck.dynamic_initializations.push_back(symbol.name);
489 
490  // move early, it must be visible before doing any value
491  symbolt *new_symbol;
492 
493  if(cpp_typecheck.symbol_table.move(symbol, new_symbol))
494  {
497  << "cpp_typecheckt::convert_declarator: symbol_table.move() failed"
498  << messaget::eom;
499  throw 0;
500  }
501 
502  if(!is_code)
503  {
505 
508 
509  for(cpp_scopest::id_sett::const_iterator
510  id_it=id_set.begin();
511  id_it!=id_set.end();
512  id_it++)
513  {
514  const cpp_idt &id=**id_it;
515  // the name is already in the scope
516  // this is ok if they belong to different categories
517 
518  if(!id.is_class() && !id.is_enum())
519  {
521  cpp_typecheck.error() << "`" << base_name
522  << "' already in scope"
523  << messaget::eom;
524  throw 0;
525  }
526  }
527  }
528 
529  // put into scope
530  cpp_idt &identifier=
532 
533  if(is_template)
535  else if(is_template_parameter)
537  else if(is_typedef)
539  else
541 
542  // do the value
543  if(!new_symbol->is_type)
544  {
545  if(is_code && declarator.type().id()!=ID_template)
546  cpp_typecheck.add_method_body(new_symbol);
547 
548  if(!is_code)
549  cpp_typecheck.convert_initializer(*new_symbol);
550  }
551 
552  enforce_rules(*new_symbol);
553 
554  return *new_symbol;
555 }
556 
558 {
559  if(is_code)
560  {
561  const irept::subt &parameters=
562  final_type.find(ID_parameters).get_sub();
563 
564  std::string result=scope->prefix+id2string(base_name)+"(";
565 
566  forall_irep(it, parameters)
567  {
568  const typet &parameter_type=((exprt &)*it).type();
569 
570  if(it!=parameters.begin())
571  result+=", ";
572 
573  result+=cpp_typecheck.to_string(parameter_type);
574  }
575 
576  result+=')';
577 
578  return result;
579  }
580 
581  return scope->prefix+id2string(base_name);
582 }
583 
585  const symbolt &)
586 {
587 }
588 
590  const symbolt &symbol)
591 {
592  if(symbol.name==ID_main)
593  {
594  if(symbol.type.id()!=ID_code)
595  {
597  cpp_typecheck.error() << "main must be function" << messaget::eom;
598  throw 0;
599  }
600 
601  const typet &return_type=
602  to_code_type(symbol.type).return_type();
603 
604  if(return_type!=signed_int_type())
605  {
606  // Too many embedded compilers ignore this rule.
607  #if 0
609  throw "main must return int";
610  #endif
611  }
612  }
613 }
C++ Language Type Checking.
The type of an expression.
Definition: type.h:22
irep_idt name
The unique identifier.
Definition: symbol.h:43
void main_function_rules(const symbolt &symbol)
void check_fixed_size_array(typet &type)
check that an array has fixed size
void typecheck_type(typet &type)
Base type of functions.
Definition: std_types.h:764
bool is_nil() const
Definition: irep.h:172
const std::string & id2string(const irep_idt &d)
Definition: irep.h:44
bool is_not_nil() const
Definition: irep.h:173
std::set< cpp_idt * > id_sett
Definition: cpp_scopes.h:31
class cpp_typecheckt & cpp_typecheck
void lookup(const irep_idt &base_name, lookup_kindt kind, id_sett &id_set)
Definition: cpp_scope.cpp:29
static bool has_auto(const typet &type)
std::vector< irept > subt
Definition: irep.h:160
irep_idt mode
Language mode.
Definition: symbol.h:52
bool is_code_type(const typet &type) const
const code_typet & to_code_type(const typet &type)
Cast a generic typet to a code_typet.
Definition: std_types.h:993
void full_member_initialization(const struct_union_typet &struct_union_type, irept &initializers)
Build the full initialization list of the constructor.
exprt value
Initial value of symbol.
Definition: symbol.h:37
const componentst & components() const
Definition: std_types.h:245
cpp_idt & put_into_scope(const symbolt &symbol, cpp_scopet &scope, bool is_friend=false)
Definition: cpp_scopes.cpp:22
irep_idt module
Name of module the symbol belongs to.
Definition: symbol.h:46
irep_idt pretty_name
Language-specific display name.
Definition: symbol.h:55
typet & type()
Definition: expr.h:56
bool cpp_typecheck(cpp_parse_treet &cpp_parse_tree, symbol_tablet &symbol_table, const std::string &module, message_handlert &message_handler)
void move_member_initializers(irept &initializers, const typet &type, exprt &value)
void add_this_to_method_type(const irep_idt &compound_identifier, typet &method_type, const typet &method_qualifier)
typet merge_type(const typet &declaration_type) const
Symbol table entry.This is a symbol in the symbol table, stored in an object of type symbol_tablet...
Definition: symbol.h:30
static mstreamt & eom(mstreamt &m)
Definition: message.h:272
void check_member_initializers(const irept &bases, const struct_typet::componentst &components, const irept &initializers)
Check a constructor initialization-list.
bool get_bool(const irep_namet &name) const
Definition: irep.cpp:240
bool is_static_lifetime
Definition: symbol.h:67
subt & get_sub()
Definition: irep.h:317
void set_base_name(const irep_idt &name)
Definition: std_types.h:835
symbol_tablet & symbol_table
virtual symbolt * get_writeable(const irep_idt &name) override
Find a symbol in the symbol table for read-write access.
Definition: symbol_table.h:87
std::string prefix
Definition: cpp_id.h:80
void add_method_body(symbolt *_method_symbol)
const irep_idt & id() const
Definition: irep.h:259
const source_locationt & source_location() const
Definition: cpp_name.h:73
const irep_idt & get_base_name() const
Definition: std_types.h:845
void set_inlined(bool value)
Definition: std_types.h:920
source_locationt & location()
bool is_extern() const
virtual bool move(symbolt &symbol, symbolt *&new_symbol) override
Move a symbol into the symbol table.
C++ Language Module.
source_locationt source_location
Definition: message.h:214
irep_idt identifier
Definition: cpp_id.h:73
symbolt & convert_new_symbol(const cpp_storage_spect &storage_spec, const cpp_member_spect &member_spec, cpp_declaratort &declarator)
id_classt id_class
Definition: cpp_id.h:51
bool is_reference(const typet &type)
TO_BE_DOCUMENTED.
Definition: std_types.cpp:105
const irep_idt & get(const irep_namet &name) const
Definition: irep.cpp:213
mstreamt & error() const
Definition: message.h:302
bool is_static() const
void enforce_rules(const symbolt &symbol)
void convert_initializer(symbolt &symbol)
Initialize an object with a value.
std::string cpp_type2name(const typet &type)
irept & method_qualifier()
Base class for tree-like data structures with sharing.
Definition: irep.h:156
C++ Language Type Checking.
const struct_typet & to_struct_type(const typet &type)
Cast a generic typet to a struct_typet.
Definition: std_types.h:318
dstringt has one field, an unsigned integer no which is an index into a static table of strings...
Definition: dstring.h:33
const symbolst & symbols
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:87
cpp_declarator_convertert(class cpp_typecheckt &_cpp_typecheck)
bool is_global_scope() const
Definition: cpp_scope.h:78
const irep_idt & display_name() const
Definition: symbol.h:57
bool is_extern
Definition: symbol.h:68
irep_idt function_identifier(const typet &type)
for function overloading
typet type
Type of symbol.
Definition: symbol.h:34
source_locationt location
Source code location of definition of symbol.
Definition: symbol.h:40
void set_identifier(const irep_idt &identifier)
Definition: std_types.h:830
API to type classes.
bool is_number(const typet &type)
Definition: type.cpp:25
Base class for all expressions.
Definition: expr.h:42
bool is_state_var
Definition: symbol.h:63
void operator_overloading_rules(const symbolt &symbol)
const parameterst & parameters() const
Definition: std_types.h:905
irep_idt base_name
Base (non-scoped) name.
Definition: symbol.h:49
cpp_scopet & current_scope()
Definition: cpp_scopes.h:33
irept & member_initializers()
symbolt & convert(const typet &type, const cpp_storage_spect &storage_spec, const cpp_member_spect &member_spec, cpp_declaratort &declarator)
const source_locationt & source_location() const
Definition: expr.h:125
#define UNREACHABLE
Definition: invariant.h:271
bool is_file_local
Definition: symbol.h:68
virtual std::string to_string(const typet &type)
const irep_idt module
dynamic_initializationst dynamic_initializations
void swap(irept &irep)
Definition: irep.h:303
source_locationt & add_source_location()
Definition: expr.h:130
cpp_namet & name()
Definition: cpp_id.h:28
signedbv_typet signed_int_type()
Definition: c_types.cpp:30
bool is_type
Definition: symbol.h:63
const typet & subtype() const
Definition: type.h:33
bool get_inlined() const
Definition: std_types.h:915
const irep_idt & get_identifier() const
Definition: std_types.h:840
std::set< cpp_idt * > id_sett
Definition: cpp_scope.h:28
const irept & find(const irep_namet &name) const
Definition: irep.cpp:285
bool is_inline() const
const typet & return_type() const
Definition: std_types.h:895
bool is_macro
Definition: symbol.h:63
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See namespace_baset::lookup().
Definition: namespace.cpp:136
void combine_types(const source_locationt &source_location, const typet &decl_type, symbolt &symbol)
void set(const irep_namet &name, const irep_idt &value)
Definition: irep.h:286
void lookup_identifier(const irep_idt &identifier, cpp_idt::id_classt id_class, id_sett &id_set)
Definition: cpp_scope.cpp:172
void handle_initializer(symbolt &symbol, cpp_declaratort &declarator)
cpp_scopet & resolve_scope(const cpp_namet &cpp_name, irep_idt &base_name, cpp_template_args_non_tct &template_args)
bool is_lvalue
Definition: symbol.h:68
#define forall_irep(it, irep)
Definition: irep.h:62
cpp_scopest cpp_scopes