cprover
Loading...
Searching...
No Matches
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>
19
20#include "cpp_type2name.h"
21#include "cpp_typecheck.h"
22#include "cpp_typecheck_fargs.h"
23
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),
32 is_code(false)
33{
34}
35
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;
49 cpp_typecheck.typecheck_type(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);
57
60
62
63 // run resolver on scope
64 {
66
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
80 scope=&cpp_typecheck.cpp_scopes.current_scope();
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))
84 cpp_typecheck.typecheck_type(final_type);
85
86 if(friend_scope)
88 }
89
91
92 // global-scope arrays must have fixed size
94 cpp_typecheck.check_fixed_size_array(final_type);
95
97
98 if(is_typedef)
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
111 {
113 typet tmp;
116 }
117
118 // try static first
119 auto maybe_symbol=
120 cpp_typecheck.symbol_table.get_writeable(final_identifier);
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 {
128 cpp_typecheck.cpp_scopes.go_to(*scope);
129
130 cpp_typecheck.add_this_to_method_type(
133 method_qualifier);
134 }
135
137
138 // try again
139 maybe_symbol=cpp_typecheck.symbol_table.get_writeable(final_identifier);
140 if(!maybe_symbol && is_friend)
141 {
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 {
150 cpp_typecheck.error().source_location=
151 declarator.name().source_location();
152 cpp_typecheck.error()
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=
171 cpp_typecheck.resolve(
172 name,
175
176 if(symbol_expr.id() != ID_type)
177 {
178 cpp_typecheck.error().source_location=name.source_location();
179 cpp_typecheck.error() << "error: expected type"
180 << messaget::eom;
181 throw 0;
182 }
183
184 irep_idt identifier=symbol_expr.type().get(ID_identifier);
185 const symbolt &symb=cpp_typecheck.lookup(identifier);
186 const struct_typet &type = to_struct_type(symb.type);
187
188 if(declarator.find(ID_member_initializers).is_nil())
190
191 cpp_typecheck.check_member_initializers(
192 type.bases(), type.components(), declarator.member_initializers());
193
194 cpp_typecheck.full_member_initialization(
195 type, declarator.member_initializers());
196 }
197
198 if(!final_storage_spec.is_extern())
199 symbol.is_extern=false;
200
201 // initializer?
202 handle_initializer(symbol, declarator);
203
204 return symbol;
205 }
206 else
207 {
208 // no, it's no way a method
209
210 // we won't allow the constructor/destructor type
211 if(final_type.id()==ID_code &&
212 to_code_type(final_type).return_type().id()==ID_constructor)
213 {
214 cpp_typecheck.error().source_location=declarator.name().source_location();
215 cpp_typecheck.error() << "function must have return type"
216 << messaget::eom;
217 throw 0;
218 }
219
220 // already there?
221 const auto maybe_symbol=
222 cpp_typecheck.symbol_table.get_writeable(final_identifier);
223 if(!maybe_symbol)
224 return convert_new_symbol(final_storage_spec, member_spec, declarator);
225 symbolt &symbol=*maybe_symbol;
226
227 if(!final_storage_spec.is_extern())
228 symbol.is_extern = false;
229
230 if(declarator.get_bool(ID_C_template_case))
231 return symbol;
232
233 combine_types(declarator.name().source_location(), final_type, symbol);
234 enforce_rules(symbol);
235
236 // initializer?
237 handle_initializer(symbol, declarator);
238
239 if(symbol.type.id()=="cpp-template-type")
240 {
241 const auto id_set = scope->lookup_identifier(
243
244 if(id_set.empty())
245 {
246 cpp_idt &identifier=
247 cpp_typecheck.cpp_scopes.put_into_scope(symbol, *scope);
249 }
250 }
251
252 return symbol;
253 }
254}
255
257 const source_locationt &source_location,
258 const typet &decl_type,
259 symbolt &symbol)
260{
261 if(symbol.type.id()==decl_type.id() &&
262 decl_type.id()==ID_code)
263 {
264 // functions need special treatment due
265 // to argument names, default values, and inlined-ness
268
269 if(decl_code_type.get_inlined())
270 symbol_code_type.set_inlined(true);
271
272 if(decl_code_type.return_type()==symbol_code_type.return_type() &&
273 decl_code_type.parameters().size()==symbol_code_type.parameters().size())
274 {
275 for(std::size_t i=0; i<decl_code_type.parameters().size(); i++)
276 {
278 decl_code_type.parameters()[i];
280 symbol_code_type.parameters()[i];
281
282 // first check type
283 if(decl_parameter.type()!=symbol_parameter.type())
284 {
285 // The 'this' parameter of virtual functions mismatches
286 if(i != 0 || !symbol_code_type.get_bool(ID_C_is_virtual))
287 {
288 cpp_typecheck.error().source_location=source_location;
289 cpp_typecheck.error()
290 << "symbol '" << symbol.display_name() << "': parameter "
291 << (i + 1) << " type mismatch\n"
292 << "previous type: "
293 << cpp_typecheck.to_string(symbol_parameter.type())
294 << "\nnew type: "
295 << cpp_typecheck.to_string(decl_parameter.type())
296 << messaget::eom;
297 throw 0;
298 }
299 }
300
301 if(symbol.value.is_nil())
302 {
303 symbol_parameter.set_base_name(decl_parameter.get_base_name());
304 // set an empty identifier when no body is available
305 symbol_parameter.set_identifier(irep_idt());
306 symbol_parameter.add_source_location()=
307 decl_parameter.source_location();
308 }
309 }
310
311 // ok
312 return;
313 }
314 }
315 else if(symbol.type==decl_type)
316 return; // ok
317 else if(
318 symbol.type.id() == ID_array &&
319 to_array_type(symbol.type).size().is_nil() && decl_type.id() == ID_array &&
320 to_array_type(symbol.type).element_type() ==
321 to_array_type(decl_type).element_type())
322 {
323 symbol.type = decl_type;
324 return; // ok
325 }
326
327 cpp_typecheck.error().source_location=source_location;
328 cpp_typecheck.error() << "symbol '" << symbol.display_name()
329 << "' already declared with different type:\n"
330 << "original: " << cpp_typecheck.to_string(symbol.type)
331 << "\n new: " << cpp_typecheck.to_string(final_type)
332 << messaget::eom;
333 throw 0;
334}
335
337{
338 // enforce rules for operator overloading
340
341 // enforce rules about main()
342 main_function_rules(symbol);
343}
344
346 symbolt &symbol,
347 cpp_declaratort &declarator)
348{
349 exprt &value=declarator.value();
350
351 // moves member initializers into 'value' - only methods have these
352 if(symbol.type.id() == ID_code)
353 cpp_typecheck.move_member_initializers(
354 declarator.member_initializers(), to_code_type(symbol.type), value);
355
356 // any initializer to be done?
357 if(value.is_nil())
358 return;
359
360 if(symbol.is_extern)
361 {
362 // the symbol is really located here
363 symbol.is_extern=false;
364 }
365
366 if(symbol.value.is_nil())
367 {
368 // no initial value yet
369 symbol.value.swap(value);
370
371 if(!is_code)
372 cpp_typecheck.convert_initializer(symbol);
373 }
374 else
375 {
376#if 0
377 cpp_typecheck.error().source_location=source_location;
378
379 if(is_code)
380 {
381 cpp_typecheck.error() << "body of function '"
382 << symbol.display_name()
383 << "' has already been defined" << messaget::eom;
384 }
385 else
386 {
387 cpp_typecheck.error() << "symbol '"
388 << symbol.display_name()
389 << "' already has an initializer" << messaget::eom;
390 }
391
392 throw 0;
393#endif
394 }
395}
396
398{
399 std::string identifier=id2string(base_name);
400
401 // main is always "C" linkage, as a matter of principle
402 if(is_code && base_name == ID_main && scope->prefix.empty())
403 {
405 }
406
407 if(is_code)
408 {
409 if(linkage_spec==ID_C)
410 {
411 // fine as is
412 }
413 else if(linkage_spec==ID_auto ||
415 {
416 // Is there already an `extern "C"' function with the same name
417 // and the same signature?
418 symbol_table_baset::symbolst::const_iterator c_it =
419 cpp_typecheck.symbol_table.symbols.find(identifier);
420
421 if(c_it!=cpp_typecheck.symbol_table.symbols.end() &&
422 c_it->second.type.id()==ID_code &&
423 cpp_typecheck.function_identifier(final_type)==
424 cpp_typecheck.function_identifier(c_it->second.type))
425 {
426 // leave as is, no decoration
427 }
428 else
429 {
430 // add C++ decoration
431 identifier+=id2string(cpp_typecheck.function_identifier(final_type));
432 }
433 }
434 }
435
436 final_identifier = scope->prefix + identifier;
437}
438
440 const cpp_storage_spect &storage_spec,
441 const cpp_member_spect &member_spec,
442 cpp_declaratort &declarator)
443{
444 irep_idt pretty_name=get_pretty_name();
445
446 symbolt symbol{
450 symbol.base_name=base_name;
451 symbol.value=declarator.value();
452 symbol.location=declarator.name().source_location();
453 symbol.is_extern = storage_spec.is_extern();
454 symbol.is_parameter = declarator.get_is_parameter();
455 symbol.is_weak = storage_spec.is_weak();
456 symbol.module=cpp_typecheck.module;
457 symbol.is_type=is_typedef;
458 symbol.is_macro=is_typedef && !is_template_parameter;
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 = !is_reference(symbol.type) &&
482 !(symbol.type.get_bool(ID_C_constant) &&
483 is_number(symbol.type) && symbol.value.is_constant());
484
485 symbol.is_static_lifetime =
486 !symbol.is_macro && !symbol.is_type &&
487 (cpp_typecheck.cpp_scopes.current_scope().is_global_scope() ||
488 storage_spec.is_static());
489
490 symbol.is_thread_local =
491 (!symbol.is_static_lifetime && !storage_spec.is_extern()) ||
492 storage_spec.is_thread_local();
493
494 symbol.is_file_local =
495 symbol.is_macro ||
496 (!cpp_typecheck.cpp_scopes.current_scope().is_global_scope() &&
497 !storage_spec.is_extern()) ||
498 (cpp_typecheck.cpp_scopes.current_scope().is_global_scope() &&
499 storage_spec.is_static()) ||
500 symbol.is_parameter;
501 }
502
503 if(symbol.is_static_lifetime)
504 cpp_typecheck.dynamic_initializations.push_back(symbol.name);
505
506 // move early, it must be visible before doing any value
507 symbolt *new_symbol;
508
509 if(cpp_typecheck.symbol_table.move(symbol, new_symbol))
510 {
511 cpp_typecheck.error().source_location=symbol.location;
512 cpp_typecheck.error()
513 << "cpp_typecheckt::convert_declarator: symbol_table.move() failed"
514 << messaget::eom;
515 throw 0;
516 }
517
518 if(!is_code)
519 {
520 const auto id_set = cpp_typecheck.cpp_scopes.current_scope().lookup(
522
523 for(const auto &id_ptr : id_set)
524 {
525 const cpp_idt &id = *id_ptr;
526 // the name is already in the scope
527 // this is ok if they belong to different categories
528
529 if(!id.is_class() && !id.is_enum())
530 {
531 cpp_typecheck.error().source_location=new_symbol->location;
532 cpp_typecheck.error()
533 << "'" << base_name << "' already in scope" << messaget::eom;
534 throw 0;
535 }
536 }
537 }
538
539 // put into scope
540 cpp_idt &identifier=
541 cpp_typecheck.cpp_scopes.put_into_scope(*new_symbol, *scope, is_friend);
542
543 if(is_template)
545 else if(is_template_parameter)
547 else if(is_typedef)
549 else
551
552 // do the value
553 if(!new_symbol->is_type)
554 {
555 if(is_code && declarator.type().id()!=ID_template)
556 cpp_typecheck.add_method_body(new_symbol);
557
558 if(!is_code)
559 cpp_typecheck.convert_initializer(*new_symbol);
560 }
561
562 enforce_rules(*new_symbol);
563
564 return *new_symbol;
565}
566
568{
569 if(is_code)
570 {
571 const irept::subt &parameters=
572 final_type.find(ID_parameters).get_sub();
573
574 std::string result=scope->prefix+id2string(base_name)+"(";
575
576 for(auto it = parameters.begin(); it != parameters.end(); ++it)
577 {
578 const typet &parameter_type = ((exprt &)*it).type();
579
580 if(it!=parameters.begin())
581 result+=", ";
582
583 result+=cpp_typecheck.to_string(parameter_type);
584 }
585
586 result+=')';
587
588 return result;
589 }
590
592}
593
598
600 const symbolt &symbol)
601{
602 if(symbol.name==ID_main)
603 {
604 if(symbol.type.id()!=ID_code)
605 {
606 cpp_typecheck.error().source_location=symbol.location;
607 cpp_typecheck.error() << "main must be function" << messaget::eom;
608 throw 0;
609 }
610
611 const typet &return_type=
612 to_code_type(symbol.type).return_type();
613
614 if(return_type!=signed_int_type())
615 {
616 // Too many embedded compilers ignore this rule.
617 #if 0
618 cpp_typecheck.error().source_location=symbol.location;
619 throw "main must return int";
620 #endif
621 }
622 }
623}
signedbv_typet signed_int_type()
Definition c_types.cpp:27
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:563
Base type of functions.
Definition std_types.h:539
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
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
bool is_global_scope() const
Definition cpp_scope.h:82
id_sett lookup_identifier(const irep_idt &id, cpp_idt::id_classt identifier_class)
bool is_static() const
bool is_thread_local() const
bool is_extern() const
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition dstring.h:39
Base class for all expressions.
Definition expr.h:56
typet & type()
Return the type of the expression.
Definition expr.h:84
bool get_bool(const irep_idt &name) const
Definition irep.cpp:57
const irept & find(const irep_idt &name) const
Definition irep.cpp:101
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: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
static eomt eom
Definition message.h:297
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
Symbol table entry.
Definition symbol.h:28
bool is_extern
Definition symbol.h:74
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
irep_idt name
The unique identifier.
Definition symbol.h:40
const irep_idt & display_name() const
Return language specific display name if present.
Definition symbol.h:55
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: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.
#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 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:844
Author: Diffblue Ltd.
dstringt irep_idt