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("#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("#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 && declarator.type().id()!=ID_template)
351 
352  if(!is_code)
354  }
355  else
356  {
357  #if 0
358  cpp_typecheck.error().source_location=declarator.name());
359 
360  if(is_code)
361  cpp_typecheck.str << "body of function `"
362  << symbol.display_name()
363  << "' has already been defined";
364  else
365  cpp_typecheck.str << "symbol `"
366  << symbol.display_name()
367  << "' already has an initializer";
368 
369  throw 0;
370  #endif
371  }
372 }
373 
375 {
376  std::string identifier=id2string(base_name);
377 
378  // main is always "C" linkage, as a matter of principle
379  if(is_code &&
380  base_name==ID_main &&
381  scope->prefix=="")
382  {
383  linkage_spec=ID_C;
384  }
385 
386  if(is_code)
387  {
388  if(linkage_spec==ID_C)
389  {
390  // fine as is
391  }
392  else if(linkage_spec==ID_auto ||
393  linkage_spec==ID_cpp)
394  {
395  // Is there already an `extern "C"' function with the same name
396  // and the same signature?
397  symbol_tablet::symbolst::const_iterator
398  c_it=cpp_typecheck.symbol_table.symbols.find(identifier);
399 
400  if(c_it!=cpp_typecheck.symbol_table.symbols.end() &&
401  c_it->second.type.id()==ID_code &&
403  cpp_typecheck.function_identifier(c_it->second.type))
404  {
405  // leave as is, no decoration
406  }
407  else
408  {
409  // add C++ decoration
411  }
412  }
413  }
414 
416  scope->prefix+
417  identifier;
418 }
419 
421  const cpp_storage_spect &storage_spec,
422  const cpp_member_spect &member_spec,
423  cpp_declaratort &declarator)
424 {
425  irep_idt pretty_name=get_pretty_name();
426 
427  symbolt symbol;
428 
429  symbol.name=final_identifier;
430  symbol.base_name=base_name;
431  symbol.value=declarator.value();
432  symbol.location=declarator.name().source_location();
433  symbol.mode=linkage_spec==ID_auto?ID_cpp:linkage_spec;
434  symbol.module=cpp_typecheck.module;
435  symbol.type=final_type;
436  symbol.is_type=is_typedef;
438  symbol.pretty_name=pretty_name;
439 
440  // Constant? These are propagated.
441  if(symbol.type.get_bool(ID_C_constant) &&
442  symbol.value.is_not_nil())
443  symbol.is_macro=true;
444 
445  if(member_spec.is_inline())
446  symbol.type.set(ID_C_inlined, true);
447 
448  if(!symbol.is_type)
449  {
450  if(is_code)
451  {
452  // it is a function
453  if(storage_spec.is_static())
454  symbol.is_file_local=true;
455  }
456  else
457  {
458  // it is a variable
459  symbol.is_state_var=true;
460  symbol.is_lvalue = !is_reference(symbol.type) &&
461  !(symbol.type.get_bool(ID_C_constant) &&
462  is_number(symbol.type) &&
463  symbol.value.id() == ID_constant);
464 
466  {
467  symbol.is_static_lifetime=true;
468 
469  if(storage_spec.is_extern())
470  symbol.is_extern=true;
471  }
472  else
473  {
474  if(storage_spec.is_static())
475  {
476  symbol.is_static_lifetime=true;
477  symbol.is_file_local=true;
478  }
479  else if(storage_spec.is_extern())
480  {
481  cpp_typecheck.error().source_location=storage_spec.location();
482  cpp_typecheck.error() << "external storage not permitted here"
483  << messaget::eom;
484  throw 0;
485  }
486  }
487  }
488  }
489 
490  if(symbol.is_static_lifetime)
491  cpp_typecheck.dynamic_initializations.push_back(symbol.name);
492 
493  // move early, it must be visible before doing any value
494  symbolt *new_symbol;
495 
496  if(cpp_typecheck.symbol_table.move(symbol, new_symbol))
497  {
500  << "cpp_typecheckt::convert_declarator: symbol_table.move() failed"
501  << messaget::eom;
502  throw 0;
503  }
504 
505  if(!is_code)
506  {
508 
511 
512  for(cpp_scopest::id_sett::const_iterator
513  id_it=id_set.begin();
514  id_it!=id_set.end();
515  id_it++)
516  {
517  const cpp_idt &id=**id_it;
518  // the name is already in the scope
519  // this is ok if they belong to different categories
520 
521  if(!id.is_class() && !id.is_enum())
522  {
524  cpp_typecheck.error() << "`" << base_name
525  << "' already in scope"
526  << messaget::eom;
527  throw 0;
528  }
529  }
530  }
531 
532  // put into scope
533  cpp_idt &identifier=
535 
536  if(is_template)
538  else if(is_template_parameter)
540  else if(is_typedef)
542  else
544 
545  // do the value
546  if(!new_symbol->is_type)
547  {
548  if(is_code && declarator.type().id()!=ID_template)
549  cpp_typecheck.add_method_body(new_symbol);
550 
551  if(!is_code)
552  cpp_typecheck.convert_initializer(*new_symbol);
553  }
554 
555  enforce_rules(*new_symbol);
556 
557  return *new_symbol;
558 }
559 
561 {
562  if(is_code)
563  {
564  const irept::subt &parameters=
565  final_type.find(ID_parameters).get_sub();
566 
567  std::string result=scope->prefix+id2string(base_name)+"(";
568 
569  forall_irep(it, parameters)
570  {
571  const typet &parameter_type=((exprt &)*it).type();
572 
573  if(it!=parameters.begin())
574  result+=", ";
575 
576  result+=cpp_typecheck.to_string(parameter_type);
577  }
578 
579  result+=')';
580 
581  return result;
582  }
583 
584  return scope->prefix+id2string(base_name);
585 }
586 
588  const symbolt &symbol)
589 {
590 }
591 
593  const symbolt &symbol)
594 {
595  if(symbol.name==ID_main)
596  {
597  if(symbol.type.id()!=ID_code)
598  {
600  cpp_typecheck.error() << "main must be function" << messaget::eom;
601  throw 0;
602  }
603 
604  const typet &return_type=
605  to_code_type(symbol.type).return_type();
606 
607  if(return_type!=signed_int_type())
608  {
609  // Too many embedded compilers ignore this rule.
610  #if 0
612  throw "main must return int";
613  #endif
614  }
615  }
616 }
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:102
const std::string & id2string(const irep_idt &d)
Definition: irep.h:43
bool is_not_nil() const
Definition: irep.h:103
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:90
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:987
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:245
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:189
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:86
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
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:250
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:231
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:130
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:68
#define forall_irep(it, irep)
Definition: irep.h:61
cpp_scopest cpp_scopes