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 {
31 }
32 
34  const typet &declaration_type,
35  const cpp_storage_spect &storage_spec,
36  const cpp_member_spect &member_spec,
37  cpp_declaratort &declarator)
38 {
39  assert(declaration_type.is_not_nil());
40 
41  if(declaration_type.id()=="cpp-cast-operator")
42  {
43  typet type;
44  type.swap(declarator.name().get_sub().back());
45  declarator.type().subtype()=type;
46  std::string tmp;
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  cpp_typecheck.typecheck_type(final_type);
72  }
73 
74  is_code=is_code_type(final_type);
75 
76  // global-scope arrays must have fixed size
77  if(scope->is_global_scope())
79 
81 
82  // first see if it is a member
84  {
85  // it's a member! it must be declared already
86 
87  typet &method_qualifier=
88  static_cast<typet &>(declarator.method_qualifier());
89 
90  // adjust template type
91  if(final_type.id()==ID_template)
92  {
93  assert(0);
94  typet tmp;
95  tmp.swap(final_type.subtype());
96  final_type.swap(tmp);
97  }
98 
99  // try static first
100  symbol_tablet::symbolst::iterator c_it=
102 
103  if(c_it==cpp_typecheck.symbol_table.symbols.end())
104  {
105  // adjust type if it's a non-static member function
106  if(final_type.id()==ID_code)
108  scope->identifier, final_type, method_qualifier);
109 
111 
112  // try again
114 
115  if(c_it==cpp_typecheck.symbol_table.symbols.end())
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  assert(c_it!=cpp_typecheck.symbol_table.symbols.end());
128 
129  symbolt &symbol=c_it->second;
130 
131  combine_types(declarator.name().source_location(), final_type, symbol);
132  enforce_rules(symbol);
133 
134  // If it is a constructor, we take care of the
135  // object initialization
136  if(final_type.get(ID_return_type)==ID_constructor)
137  {
138  const cpp_namet &name=declarator.name();
139 
140  exprt symbol_expr=
142  name,
145 
146  if(symbol_expr.id()!=ID_type ||
147  symbol_expr.type().id()!=ID_symbol)
148  {
150  cpp_typecheck.error() << "error: expected type"
151  << messaget::eom;
152  throw 0;
153  }
154 
155  irep_idt identifier=symbol_expr.type().get(ID_identifier);
156  const symbolt &symb=cpp_typecheck.lookup(identifier);
157  const typet &type = symb.type;
158  assert(type.id()==ID_struct);
159 
160  if(declarator.find(ID_member_initializers).is_nil())
161  declarator.set(ID_member_initializers, ID_member_initializers);
162 
164  type.find(ID_bases),
165  to_struct_type(type).components(),
166  declarator.member_initializers());
167 
169  to_struct_type(type),
170  declarator.member_initializers());
171  }
172 
173  if(!storage_spec.is_extern())
174  symbol.is_extern=false;
175 
176  // initializer?
177  handle_initializer(symbol, declarator);
178 
179  return symbol;
180  }
181  else
182  {
183  // no, it's no way a method
184 
185  // we won't allow the constructor/destructor type
186  if(final_type.id()==ID_code &&
187  to_code_type(final_type).return_type().id()==ID_constructor)
188  {
190  cpp_typecheck.error() << "function must have return type"
191  << messaget::eom;
192  throw 0;
193  }
194 
195  // already there?
196  symbol_tablet::symbolst::iterator c_it=
198 
199  if(c_it==cpp_typecheck.symbol_table.symbols.end())
200  return convert_new_symbol(storage_spec, member_spec, declarator);
201 
202  symbolt &symbol=c_it->second;
203 
204  if(!storage_spec.is_extern())
205  symbol.is_extern = false;
206 
207  if(declarator.get_bool("#template_case"))
208  return symbol;
209 
210  combine_types(declarator.name().source_location(), final_type, symbol);
211  enforce_rules(symbol);
212 
213  // initializer?
214  handle_initializer(symbol, declarator);
215 
216  if(symbol.type.id()=="cpp-template-type")
217  {
219 
222 
223  if(id_set.empty())
224  {
225  cpp_idt &identifier=
228  }
229  }
230 
231  return symbol;
232  }
233 }
234 
236  const source_locationt &source_location,
237  const typet &decl_type,
238  symbolt &symbol)
239 {
240  if(symbol.type.id()==decl_type.id() &&
241  decl_type.id()==ID_code)
242  {
243  // functions need special treatment due
244  // to argument names, default values, and inlined-ness
245  const code_typet &decl_code_type=to_code_type(decl_type);
246  code_typet &symbol_code_type=to_code_type(symbol.type);
247 
248  if(decl_code_type.get_inlined())
249  symbol_code_type.set_inlined(true);
250 
251  if(decl_code_type.return_type()==symbol_code_type.return_type() &&
252  decl_code_type.parameters().size()==symbol_code_type.parameters().size())
253  {
254  for(unsigned i=0; i<decl_code_type.parameters().size(); i++)
255  {
256  const code_typet::parametert &decl_parameter=
257  decl_code_type.parameters()[i];
258  code_typet::parametert &symbol_parameter=
259  symbol_code_type.parameters()[i];
260 
261  // first check type
262  if(decl_parameter.type()!=symbol_parameter.type())
263  {
264  // The 'this' parameter of virtual functions mismatches
265  if(i!=0 || !symbol_code_type.get_bool("#is_virtual"))
266  {
267  cpp_typecheck.error().source_location=source_location;
268  cpp_typecheck.error() << "symbol `" << symbol.display_name()
269  << "': parameter " << (i+1)
270  << " type mismatch\n"
271  << "previous type: "
273  symbol_parameter.type())
274  << "\nnew type: "
276  decl_parameter.type())
277  << messaget::eom;
278  throw 0;
279  }
280  }
281 
282  if(symbol.value.is_nil())
283  {
284  symbol_parameter.set_base_name(decl_parameter.get_base_name());
285  symbol_parameter.set_identifier(decl_parameter.get_identifier());
286  symbol_parameter.add_source_location()=
287  decl_parameter.source_location();
288  }
289  }
290 
291  // ok
292  return;
293  }
294  }
295  else if(symbol.type==decl_type)
296  return; // ok
297  else if(symbol.type.id()==ID_array &&
298  symbol.type.find(ID_size).is_nil() &&
299  decl_type.id()==ID_array &&
300  symbol.type.subtype()==decl_type.subtype())
301  {
302  symbol.type = decl_type;
303  return; // ok
304  }
305 
306  cpp_typecheck.error().source_location=source_location;
307  cpp_typecheck.error() << "symbol `" << symbol.display_name()
308  << "' already declared with different type:\n"
309  << "original: "
310  << cpp_typecheck.to_string(symbol.type)
311  << "\n new: "
313  << messaget::eom;
314  throw 0;
315 }
316 
318 {
319  // enforce rules for operator overloading
321 
322  // enforce rules about main()
323  main_function_rules(symbol);
324 }
325 
327  symbolt &symbol,
328  cpp_declaratort &declarator)
329 {
330  exprt &value=declarator.value();
331 
332  // moves member initializers into 'value'
334  declarator.member_initializers(),
335  symbol.type,
336  value);
337 
338  // any initializer to be done?
339  if(value.is_nil())
340  return;
341 
342  if(symbol.is_extern)
343  {
344  // the symbol is really located here
345  symbol.is_extern=false;
346  }
347 
348  if(symbol.value.is_nil())
349  {
350  // no initial value yet
351  symbol.value.swap(value);
352 
353  if(is_code && declarator.type().id()!=ID_template)
355 
356  if(!is_code)
358  }
359  else
360  {
361  #if 0
362  cpp_typecheck.error().source_location=declarator.name());
363 
364  if(is_code)
365  cpp_typecheck.str << "body of function `"
366  << symbol.display_name()
367  << "' has already been defined";
368  else
369  cpp_typecheck.str << "symbol `"
370  << symbol.display_name()
371  << "' already has an initializer";
372 
373  throw 0;
374  #endif
375  }
376 }
377 
379 {
380  std::string identifier=id2string(base_name);
381 
382  // main is always "C" linkage, as a matter of principle
383  if(is_code &&
384  base_name==ID_main &&
385  scope->prefix=="")
386  {
387  linkage_spec=ID_C;
388  }
389 
390  if(is_code)
391  {
392  if(linkage_spec==ID_C)
393  {
394  // fine as is
395  }
396  else if(linkage_spec==ID_auto ||
397  linkage_spec==ID_cpp)
398  {
399  // Is there already an `extern "C"' function with the same name
400  // and the same signature?
401  symbol_tablet::symbolst::const_iterator
402  c_it=cpp_typecheck.symbol_table.symbols.find(identifier);
403 
404  if(c_it!=cpp_typecheck.symbol_table.symbols.end() &&
405  c_it->second.type.id()==ID_code &&
407  cpp_typecheck.function_identifier(c_it->second.type))
408  {
409  // leave as is, no decoration
410  }
411  else
412  {
413  // add C++ decoration
415  }
416  }
417  }
418 
420  scope->prefix+
421  identifier;
422 }
423 
425  const cpp_storage_spect &storage_spec,
426  const cpp_member_spect &member_spec,
427  cpp_declaratort &declarator)
428 {
429  irep_idt pretty_name=get_pretty_name();
430 
431  symbolt symbol;
432 
433  symbol.name=final_identifier;
434  symbol.base_name=base_name;
435  symbol.value=declarator.value();
436  symbol.location=declarator.name().source_location();
437  symbol.mode=linkage_spec==ID_auto?ID_cpp:linkage_spec;
438  symbol.module=cpp_typecheck.module;
439  symbol.type=final_type;
440  symbol.is_type=is_typedef;
442  symbol.pretty_name=pretty_name;
443 
444  // Constant? These are propagated.
445  if(symbol.type.get_bool(ID_C_constant) &&
446  symbol.value.is_not_nil())
447  symbol.is_macro=true;
448 
449  if(member_spec.is_inline())
450  symbol.type.set(ID_C_inlined, true);
451 
452  if(!symbol.is_type)
453  {
454  if(is_code)
455  {
456  // it is a function
457  if(storage_spec.is_static())
458  symbol.is_file_local=true;
459  }
460  else
461  {
462  // it is a variable
463  symbol.is_state_var=true;
464  symbol.is_lvalue = !is_reference(symbol.type) &&
465  !(symbol.type.get_bool(ID_C_constant) &&
466  is_number(symbol.type) &&
467  symbol.value.id() == ID_constant);
468 
470  {
471  symbol.is_static_lifetime=true;
472 
473  if(storage_spec.is_extern())
474  symbol.is_extern=true;
475  }
476  else
477  {
478  if(storage_spec.is_static())
479  {
480  symbol.is_static_lifetime=true;
481  symbol.is_file_local=true;
482  }
483  else if(storage_spec.is_extern())
484  {
485  cpp_typecheck.error().source_location=storage_spec.location();
486  cpp_typecheck.error() << "external storage not permitted here"
487  << messaget::eom;
488  throw 0;
489  }
490  }
491  }
492  }
493 
494  if(symbol.is_static_lifetime)
495  cpp_typecheck.dynamic_initializations.push_back(symbol.name);
496 
497  // move early, it must be visible before doing any value
498  symbolt *new_symbol;
499 
500  if(cpp_typecheck.symbol_table.move(symbol, new_symbol))
501  {
504  << "cpp_typecheckt::convert_declarator: symbol_table.move() failed"
505  << messaget::eom;
506  throw 0;
507  }
508 
509  if(!is_code)
510  {
512 
515 
516  for(cpp_scopest::id_sett::const_iterator
517  id_it=id_set.begin();
518  id_it!=id_set.end();
519  id_it++)
520  {
521  const cpp_idt &id=**id_it;
522  // the name is already in the scope
523  // this is ok if they belong to different categories
524 
525  if(!id.is_class() && !id.is_enum())
526  {
528  cpp_typecheck.error() << "`" << base_name
529  << "' already in scope"
530  << messaget::eom;
531  throw 0;
532  }
533  }
534  }
535 
536  // put into scope
537  cpp_idt &identifier=
539 
540  if(is_template)
542  else if(is_template_parameter)
544  else if(is_typedef)
546  else
548 
549  // do the value
550  if(!new_symbol->is_type)
551  {
552  if(is_code && declarator.type().id()!=ID_template)
553  cpp_typecheck.add_method_body(new_symbol);
554 
555  if(!is_code)
556  cpp_typecheck.convert_initializer(*new_symbol);
557  }
558 
559  enforce_rules(*new_symbol);
560 
561  return *new_symbol;
562 }
563 
565 {
566  if(is_code)
567  {
568  const irept::subt &parameters=
569  final_type.find(ID_parameters).get_sub();
570 
571  std::string result=scope->prefix+id2string(base_name)+"(";
572 
573  forall_irep(it, parameters)
574  {
575  const typet &parameter_type=((exprt &)*it).type();
576 
577  if(it!=parameters.begin())
578  result+=", ";
579 
580  result+=cpp_typecheck.to_string(parameter_type);
581  }
582 
583  result+=')';
584 
585  return result;
586  }
587 
588  return scope->prefix+id2string(base_name);
589 }
590 
592  const symbolt &symbol)
593 {
594 }
595 
597  const symbolt &symbol)
598 {
599  if(symbol.name==ID_main)
600  {
601  if(symbol.type.id()!=ID_code)
602  {
604  cpp_typecheck.error() << "main must be function" << messaget::eom;
605  throw 0;
606  }
607 
608  const typet &return_type=
609  to_code_type(symbol.type).return_type();
610 
611  if(return_type!=signed_int_type())
612  {
613  // Too many embedded compilers ignore this rule.
614  #if 0
616  throw "main must return int";
617  #endif
618  }
619  }
620 }
C++ Language Type Checking.
The type of an expression.
Definition: type.h:20
irep_idt name
The unique identifier.
Definition: symbol.h:46
void main_function_rules(const symbolt &symbol)
void check_fixed_size_array(typet &type)
check that an array has fixed size
virtual bool lookup(const irep_idt &name, const symbolt *&symbol) const
Definition: namespace.cpp:139
void typecheck_type(typet &type)
Base type of functions.
Definition: std_types.h:734
bool is_nil() const
Definition: irep.h:103
const std::string & id2string(const irep_idt &d)
Definition: irep.h:44
bool is_not_nil() const
Definition: irep.h:104
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
std::vector< irept > subt
Definition: irep.h:91
irep_idt mode
Language mode.
Definition: symbol.h:55
bool is_code_type(const typet &type) const
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:40
const componentst & components() const
Definition: std_types.h:242
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:49
irep_idt pretty_name
Language-specific display name.
Definition: symbol.h:58
typet & type()
Definition: expr.h:60
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:33
static mstreamt & eom(mstreamt &m)
Definition: message.h:193
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:70
subt & get_sub()
Definition: irep.h:245
void set_base_name(const irep_idt &name)
Definition: std_types.h:777
symbol_tablet & symbol_table
std::string prefix
Definition: cpp_id.h:80
void add_method_body(symbolt *_method_symbol)
const irep_idt & id() const
Definition: irep.h:189
const source_locationt & source_location() const
Definition: cpp_name.h:72
const irep_idt & get_base_name() const
Definition: std_types.h:787
void set_inlined(bool value)
Definition: std_types.h:856
symbolst symbols
Definition: symbol_table.h:57
source_locationt & location()
bool is_extern() const
C++ Language Module.
source_locationt source_location
Definition: message.h:175
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
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:87
C++ Language Type Checking.
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
bool move(symbolt &symbol, symbolt *&new_symbol)
Move a symbol into the symbol table.
cpp_declarator_convertert(class cpp_typecheckt &_cpp_typecheck)
const struct_typet & to_struct_type(const typet &type)
Cast a generic typet to a struct_typet.
Definition: std_types.h:317
bool is_global_scope() const
Definition: cpp_scope.h:78
const irep_idt & display_name() const
Definition: symbol.h:60
bool is_extern
Definition: symbol.h:71
irep_idt function_identifier(const typet &type)
for function overloading
typet type
Type of symbol.
Definition: symbol.h:37
source_locationt location
Source code location of definition of symbol.
Definition: symbol.h:43
void set_identifier(const irep_idt &identifier)
Definition: std_types.h:772
API to type classes.
bool is_number(const typet &type)
Definition: type.cpp:24
Base class for all expressions.
Definition: expr.h:46
bool is_state_var
Definition: symbol.h:66
void operator_overloading_rules(const symbolt &symbol)
const parameterst & parameters() const
Definition: std_types.h:841
irep_idt base_name
Base (non-scoped) name.
Definition: symbol.h:52
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:142
bool is_file_local
Definition: symbol.h:71
virtual std::string to_string(const typet &type)
const irep_idt module
const code_typet & to_code_type(const typet &type)
Cast a generic typet to a code_typet.
Definition: std_types.h:884
dynamic_initializationst dynamic_initializations
void swap(irept &irep)
Definition: irep.h:231
mstreamt & error()
Definition: message.h:223
source_locationt & add_source_location()
Definition: expr.h:147
cpp_namet & name()
Definition: cpp_id.h:28
signedbv_typet signed_int_type()
Definition: c_types.cpp:29
bool is_type
Definition: symbol.h:66
const typet & subtype() const
Definition: type.h:31
bool get_inlined() const
Definition: std_types.h:851
const irep_idt & get_identifier() const
Definition: std_types.h:782
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:831
bool is_macro
Definition: symbol.h:66
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:214
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:71
#define forall_irep(it, irep)
Definition: irep.h:62
cpp_scopest cpp_scopes