cprover
cpp_declarator_converter.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: C++ Language Type Checking
4
5Author: Daniel Kroening, kroening@cs.cmu.edu
6
7\*******************************************************************/
8
11
13
14#include <util/c_types.h>
17#include <util/std_types.h>
18
19#include "cpp_type2name.h"
20#include "cpp_typecheck.h"
21#include "cpp_typecheck_fargs.h"
22
24 class cpp_typecheckt &_cpp_typecheck):
25 is_typedef(false),
26 is_template(false),
27 is_template_parameter(false),
28 is_friend(false),
29 linkage_spec(_cpp_typecheck.current_linkage_spec),
30 cpp_typecheck(_cpp_typecheck),
31 is_code(false)
32{
33}
34
36 const typet &declaration_type,
37 const cpp_storage_spect &storage_spec,
38 const cpp_member_spect &member_spec,
39 cpp_declaratort &declarator)
40{
41 assert(declaration_type.is_not_nil());
42
43 if(declaration_type.id()=="cpp-cast-operator")
44 {
45 typet type;
46 type.swap(declarator.name().get_sub().back());
47 declarator.type().subtype()=type;
49 cpp_namet::namet name("(" + 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_storage_spect final_storage_spec = storage_spec;
58 final_storage_spec |= cpp_storage_spect(final_type);
59
60 cpp_template_args_non_tct template_args;
61
62 // run resolver on scope
63 {
65
66 cpp_typecheck_resolvet cpp_typecheck_resolve(cpp_typecheck);
67
68 cpp_typecheck_resolve.resolve_scope(
69 declarator.name(), base_name, template_args);
70
71 cpp_scopet *friend_scope = nullptr;
72
73 if(is_friend)
74 {
75 friend_scope = &cpp_typecheck.cpp_scopes.current_scope();
76 save_scope.restore();
77 }
78
80
81 // check the declarator-part of the type, in the current scope
82 if(declarator.value().is_nil() || !cpp_typecheck.has_auto(final_type))
84
85 if(friend_scope)
86 scope = friend_scope;
87 }
88
90
91 // global-scope arrays must have fixed size
94
96
97 if(is_typedef)
98 final_type.set(ID_C_typedef, final_identifier);
99
100 // first see if it is a member
102 {
103 // it's a member! it must be declared already, unless it's a friend
104
105 typet &method_qualifier=
106 static_cast<typet &>(declarator.method_qualifier());
107
108 // adjust template type
109 if(final_type.id()==ID_template)
110 {
112 typet tmp;
113 tmp.swap(final_type.subtype());
114 final_type.swap(tmp);
115 }
116
117 // try static first
118 auto maybe_symbol=
120
121 if(!maybe_symbol)
122 {
123 // adjust type if it's a non-static member function
124 if(final_type.id()==ID_code)
125 {
128
132 method_qualifier);
133 }
134
136
137 // try again
139 if(!maybe_symbol && is_friend)
140 {
141 symbolt &friend_symbol =
142 convert_new_symbol(final_storage_spec, member_spec, declarator);
143 // mark it as weak so that the full declaration can replace the symbol
144 friend_symbol.is_weak = true;
145 return friend_symbol;
146 }
147 else if(!maybe_symbol)
148 {
150 declarator.name().source_location();
152 << "member '" << base_name << "' not found in scope '"
153 << scope->identifier << "'" << messaget::eom;
154 throw 0;
155 }
156 }
157
158 symbolt &symbol=*maybe_symbol;
159
160 combine_types(declarator.name().source_location(), final_type, symbol);
161 enforce_rules(symbol);
162
163 // If it is a constructor, we take care of the
164 // object initialization
165 if(to_code_type(final_type).return_type().id() == ID_constructor)
166 {
167 const cpp_namet &name=declarator.name();
168
169 exprt symbol_expr=
171 name,
174
175 if(symbol_expr.id() != ID_type)
176 {
178 cpp_typecheck.error() << "error: expected type"
179 << 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_tablet::symbolst::const_iterator
418 c_it=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;
446
447 symbol.name=final_identifier;
448 symbol.base_name=base_name;
449 symbol.value=declarator.value();
450 symbol.location=declarator.name().source_location();
451 symbol.is_extern = storage_spec.is_extern();
452 symbol.is_parameter = declarator.get_is_parameter();
453 symbol.is_weak = storage_spec.is_weak();
454 symbol.mode=linkage_spec==ID_auto?ID_cpp:linkage_spec;
456 symbol.type=final_type;
457 symbol.is_type=is_typedef;
459 symbol.pretty_name=pretty_name;
460
461 if(is_code && !symbol.is_type)
462 {
463 // it is a function
464 symbol.is_static_lifetime = false;
465 symbol.is_thread_local = false;
466
467 symbol.is_file_local = storage_spec.is_static();
468
469 if(member_spec.is_inline())
470 to_code_type(symbol.type).set_inlined(true);
471
472 if(symbol.value.is_nil())
473 {
474 // we don't need the identifiers
475 for(auto &parameter : to_code_type(symbol.type).parameters())
476 parameter.set_identifier(irep_idt());
477 }
478 }
479 else
480 {
481 symbol.is_lvalue =
482 !is_reference(symbol.type) &&
483 !(symbol.type.get_bool(ID_C_constant) && is_number(symbol.type) &&
484 symbol.value.id() == ID_constant);
485
486 symbol.is_static_lifetime =
487 !symbol.is_macro && !symbol.is_type &&
489 storage_spec.is_static());
490
491 symbol.is_thread_local =
492 (!symbol.is_static_lifetime && !storage_spec.is_extern()) ||
493 storage_spec.is_thread_local();
494
495 symbol.is_file_local =
496 symbol.is_macro ||
498 !storage_spec.is_extern()) ||
500 storage_spec.is_static()) ||
501 symbol.is_parameter;
502 }
503
504 if(symbol.is_static_lifetime)
506
507 // move early, it must be visible before doing any value
508 symbolt *new_symbol;
509
510 if(cpp_typecheck.symbol_table.move(symbol, new_symbol))
511 {
514 << "cpp_typecheckt::convert_declarator: symbol_table.move() failed"
515 << messaget::eom;
516 throw 0;
517 }
518
519 if(!is_code)
520 {
521 const auto id_set = cpp_typecheck.cpp_scopes.current_scope().lookup(
523
524 for(const auto &id_ptr : id_set)
525 {
526 const cpp_idt &id = *id_ptr;
527 // the name is already in the scope
528 // this is ok if they belong to different categories
529
530 if(!id.is_class() && !id.is_enum())
531 {
534 << "'" << base_name << "' already in scope" << messaget::eom;
535 throw 0;
536 }
537 }
538 }
539
540 // put into scope
541 cpp_idt &identifier=
543
544 if(is_template)
546 else if(is_template_parameter)
548 else if(is_typedef)
550 else
552
553 // do the value
554 if(!new_symbol->is_type)
555 {
556 if(is_code && declarator.type().id()!=ID_template)
557 cpp_typecheck.add_method_body(new_symbol);
558
559 if(!is_code)
561 }
562
563 enforce_rules(*new_symbol);
564
565 return *new_symbol;
566}
567
569{
570 if(is_code)
571 {
572 const irept::subt &parameters=
573 final_type.find(ID_parameters).get_sub();
574
575 std::string result=scope->prefix+id2string(base_name)+"(";
576
577 for(auto it = parameters.begin(); it != parameters.end(); ++it)
578 {
579 const typet &parameter_type = ((exprt &)*it).type();
580
581 if(it!=parameters.begin())
582 result+=", ";
583
584 result+=cpp_typecheck.to_string(parameter_type);
585 }
586
587 result+=')';
588
589 return result;
590 }
591
593}
594
596 const symbolt &)
597{
598}
599
601 const symbolt &symbol)
602{
603 if(symbol.name==ID_main)
604 {
605 if(symbol.type.id()!=ID_code)
606 {
608 cpp_typecheck.error() << "main must be function" << messaget::eom;
609 throw 0;
610 }
611
612 const typet &return_type=
613 to_code_type(symbol.type).return_type();
614
615 if(return_type!=signed_int_type())
616 {
617 // Too many embedded compilers ignore this rule.
618 #if 0
620 throw "main must return int";
621 #endif
622 }
623 }
624}
signedbv_typet signed_int_type()
Definition: c_types.cpp:40
const exprt & size() const
Definition: std_types.h:790
const typet & element_type() const
The type of the elements of the array.
Definition: std_types.h:777
symbol_tablet & symbol_table
const irep_idt module
const irep_idt & get_base_name() const
Definition: std_types.h:595
void set_base_name(const irep_idt &name)
Definition: std_types.h:585
void set_identifier(const irep_idt &identifier)
Definition: std_types.h:580
Base type of functions.
Definition: std_types.h:539
void set_inlined(bool value)
Definition: std_types.h:670
bool get_inlined() const
Definition: std_types.h:665
const parameterst & parameters() const
Definition: std_types.h:655
const typet & return_type() const
Definition: std_types.h:645
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()
typet merge_type(const typet &declaration_type) const
cpp_namet & name()
irept & method_qualifier()
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_idt & put_into_scope(const symbolt &symbol, cpp_scopet &scope, bool is_friend=false)
Definition: cpp_scopes.cpp:24
cpp_scopet & current_scope()
Definition: cpp_scopes.h:32
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:83
cpp_scopest cpp_scopes
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:37
Base class for all expressions.
Definition: expr.h:54
typet & type()
Return the type of the expression.
Definition: expr.h:82
const source_locationt & source_location() const
Definition: expr.h:230
source_locationt & add_source_location()
Definition: expr.h:235
bool get_bool(const irep_idt &name) const
Definition: irep.cpp:58
const irept & find(const irep_idt &name) const
Definition: irep.cpp:106
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:45
void set(const irep_idt &name, const irep_idt &value)
Definition: irep.h:420
bool is_not_nil() const
Definition: irep.h:380
subt & get_sub()
Definition: irep.h:456
void swap(irept &irep)
Definition: irep.h:442
const irep_idt & id() const
Definition: irep.h:396
bool is_nil() const
Definition: irep.h:376
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:138
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
const symbolst & symbols
Read-only field, used to look up symbols given their names.
virtual symbolt * get_writeable(const irep_idt &name) override
Find a symbol in the symbol table for read-write access.
Definition: symbol_table.h:90
virtual bool move(symbolt &symbol, symbolt *&new_symbol) override
Move a symbol into the symbol table.
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:66
bool is_macro
Definition: symbol.h:61
bool is_file_local
Definition: symbol.h:66
irep_idt module
Name of module the symbol belongs to.
Definition: symbol.h:43
bool is_static_lifetime
Definition: symbol.h:65
bool is_parameter
Definition: symbol.h:67
bool is_thread_local
Definition: symbol.h:65
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:67
irep_idt name
The unique identifier.
Definition: symbol.h:40
irep_idt pretty_name
Language-specific display name.
Definition: symbol.h:52
const irep_idt & display_name() const
Return language specific display name if present.
Definition: symbol.h:55
bool is_lvalue
Definition: symbol.h:66
exprt value
Initial value of symbol.
Definition: symbol.h:34
irep_idt mode
Language mode.
Definition: symbol.h:49
The type of an expression, extends irept.
Definition: type.h:29
const typet & subtype() const
Definition: type.h:48
C++ Language Type Checking.
std::string cpp_type2name(const typet &type)
C++ Language Module.
bool cpp_typecheck(cpp_parse_treet &cpp_parse_tree, symbol_tablet &symbol_table, const std::string &module, message_handlert &message_handler)
C++ Language Type Checking.
C++ Language Type Checking.
dstringt irep_idt
Definition: irep.h:37
const std::string & id2string(const irep_idt &d)
Definition: irep.h:47
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:137
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:503
Pre-defined types.
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition: std_types.h:744
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition: std_types.h:308
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:832