void cpp_typecheckt::static_initialization() { code_blockt block_sini; // Static Initialization Block code_blockt block_dini; // Dynamic Initialization Block disable_access_control = true; // first do zero initialization context.foreach_operand([this, &block_sini](const symbolt &s) { if(!s.static_lifetime || s.mode != current_mode) return; // it has a non-code initializer already? if(s.value.is_not_nil() && s.value.id() != "code") return; // it's a declaration only if(s.is_extern) return; if(!s.lvalue) return; zero_initializer( cpp_symbol_expr(s), s.type, s.location, block_sini.operands()); }); while(!dinis.empty()) { symbolt &symbol = *context.find_symbol(dinis.front()); dinis.pop_front(); if(symbol.is_extern) continue; if(symbol.mode != current_mode) continue; assert(symbol.static_lifetime); assert(!symbol.is_type); assert(symbol.type.id() != "code"); exprt symexpr = cpp_symbol_expr(symbol); if(symbol.value.is_not_nil()) { if(!cpp_is_pod(symbol.type)) { block_dini.move_to_operands(symbol.value); } else { exprt symbexpr("symbol", symbol.type); symbexpr.identifier(symbol.name); codet code; code.set_statement("assign"); code.copy_to_operands(symbexpr, symbol.value); code.location() = symbol.location; if(symbol.value.id() == "constant") block_sini.move_to_operands(code); else block_dini.move_to_operands(code); } // Make it nil because we do not want // global_init to try to initialize the // object symbol.value.make_nil(); } else { exprt::operandst ops; codet call = cpp_constructor(locationt(), symexpr, ops); if(call.is_not_nil()) block_dini.move_to_operands(call); } } block_sini.move_to_operands(block_dini); // Create the initialization procedure symbolt init_symbol; init_symbol.name = "#ini#" + id2string(module); init_symbol.base_name = "#ini#" + id2string(module); init_symbol.value.swap(block_sini); init_symbol.mode = current_mode; init_symbol.module = module; init_symbol.type = code_typet(); init_symbol.type.add("return_type") = typet("empty"); init_symbol.type.set("initialization", true); init_symbol.is_type = false; init_symbol.is_macro = false; context.move(init_symbol); disable_access_control = false; }
bool cpp_typecheckt::cpp_is_pod(const typet &type) const { if(type.id()==ID_struct) { // Not allowed in PODs: // * Non-PODs // * Constructors/Destructors // * virtuals // * private/protected, unless static // * overloading assignment operator // * Base classes const struct_typet &struct_type=to_struct_type(type); if(!type.find(ID_bases).get_sub().empty()) return false; const struct_typet::componentst &components= struct_type.components(); for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { if(it->get_bool(ID_is_type)) continue; if(it->get_base_name()=="operator=") return false; if(it->get_bool(ID_is_virtual)) return false; const typet &sub_type=it->type(); if(sub_type.id()==ID_code) { if(it->get_bool(ID_is_virtual)) return false; const typet &return_type=to_code_type(sub_type).return_type(); if(return_type.id()==ID_constructor || return_type.id()==ID_destructor) return false; } else if(it->get(ID_access)!=ID_public && !it->get_bool(ID_is_static)) return false; if(!cpp_is_pod(sub_type)) return false; } return true; } else if(type.id()==ID_array) { return cpp_is_pod(type.subtype()); } else if(type.id()==ID_pointer) { if(is_reference(type)) // references are not PODs return false; // but pointers are PODs! return true; } else if(type.id()==ID_symbol) { const symbolt &symb=lookup(type.get(ID_identifier)); assert(symb.is_type); return cpp_is_pod(symb.type); } // everything else is POD return true; }
codet cpp_typecheckt::cpp_constructor( const source_locationt &source_location, const exprt &object, const exprt::operandst &operands) { exprt object_tc=object; typecheck_expr(object_tc); elaborate_class_template(object_tc.type()); typet tmp_type(object_tc.type()); follow_symbol(tmp_type); assert(!is_reference(tmp_type)); if(tmp_type.id()==ID_array) { // We allow only one operand and it must be tagged with '#array_ini'. // Note that the operand is an array that is used for copy-initialization. // In the general case, a program is not allow to use this form of // construct. This way of initializing an array is used internaly only. // The purpose of the tag #arra_ini is to rule out ill-formed // programs. if(!operands.empty() && !operands.front().get_bool("#array_ini")) { error().source_location=source_location; error() << "bad array initializer" << eom; throw 0; } assert(operands.empty() || operands.size()==1); if(operands.empty() && cpp_is_pod(tmp_type)) { codet nil; nil.make_nil(); return nil; } const exprt &size_expr= to_array_type(tmp_type).size(); if(size_expr.id()=="infinity") { // don't initialize codet nil; nil.make_nil(); return nil; } exprt tmp_size=size_expr; make_constant_index(tmp_size); mp_integer s; if(to_integer(tmp_size, s)) { error().source_location=source_location; error() << "array size `" << to_string(size_expr) << "' is not a constant" << eom; throw 0; } /*if(cpp_is_pod(tmp_type)) { code_expressiont new_code; exprt op_tc=operands.front(); typecheck_expr(op_tc); // Override constantness object_tc.type().set("#constant", false); object_tc.set("#lvalue", true); side_effect_exprt assign("assign"); assign.add_source_location()=source_location; assign.copy_to_operands(object_tc, op_tc); typecheck_side_effect_assignment(assign); new_code.expression()=assign; return new_code; } else*/ { codet new_code(ID_block); // for each element of the array, call the default constructor for(mp_integer i=0; i < s; ++i) { exprt::operandst tmp_operands; exprt constant=from_integer(i, index_type()); constant.add_source_location()=source_location; exprt index(ID_index); index.copy_to_operands(object); index.copy_to_operands(constant); index.add_source_location()=source_location; if(!operands.empty()) { exprt operand(ID_index); operand.copy_to_operands(operands.front()); operand.copy_to_operands(constant); operand.add_source_location()=source_location; tmp_operands.push_back(operand); } exprt i_code = cpp_constructor(source_location, index, tmp_operands); if(i_code.is_nil()) { new_code.is_nil(); break; } new_code.move_to_operands(i_code); } return new_code; } } else if(cpp_is_pod(tmp_type)) { code_expressiont new_code; exprt::operandst operands_tc=operands; for(exprt::operandst::iterator it=operands_tc.begin(); it!=operands_tc.end(); it++) { typecheck_expr(*it); add_implicit_dereference(*it); } if(operands_tc.empty()) { // a POD is NOT initialized new_code.make_nil(); } else if(operands_tc.size()==1) { // Override constantness object_tc.type().set(ID_C_constant, false); object_tc.set(ID_C_lvalue, true); side_effect_exprt assign(ID_assign); assign.add_source_location()=source_location; assign.copy_to_operands(object_tc, operands_tc.front()); typecheck_side_effect_assignment(assign); new_code.expression()=assign; } else { error().source_location=source_location; error() << "initialization of POD requires one argument, " "but got " << operands.size() << eom; throw 0; } return new_code; } else if(tmp_type.id()==ID_union) { assert(0); // Todo: union } else if(tmp_type.id()==ID_struct) { exprt::operandst operands_tc=operands; for(exprt::operandst::iterator it=operands_tc.begin(); it!=operands_tc.end(); it++) { typecheck_expr(*it); add_implicit_dereference(*it); } const struct_typet &struct_type= to_struct_type(tmp_type); // set most-derived bits codet block(ID_block); for(std::size_t i=0; i < struct_type.components().size(); i++) { const irept &component=struct_type.components()[i]; if(component.get(ID_base_name)!="@most_derived") continue; exprt member(ID_member, bool_typet()); member.set(ID_component_name, component.get(ID_name)); member.copy_to_operands(object_tc); member.add_source_location()=source_location; member.set(ID_C_lvalue, object_tc.get_bool(ID_C_lvalue)); exprt val=false_exprt(); if(!component.get_bool("from_base")) val=true_exprt(); side_effect_exprt assign(ID_assign); assign.add_source_location()=source_location; assign.move_to_operands(member, val); typecheck_side_effect_assignment(assign); code_expressiont code_exp; code_exp.expression()=assign; block.move_to_operands(code_exp); } // enter struct scope cpp_save_scopet save_scope(cpp_scopes); cpp_scopes.set_scope(struct_type.get(ID_name)); // find name of constructor const struct_typet::componentst &components= struct_type.components(); irep_idt constructor_name; for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { const typet &type=it->type(); if(!it->get_bool(ID_from_base) && type.id()==ID_code && type.find(ID_return_type).id()==ID_constructor) { constructor_name=it->get(ID_base_name); break; } } // there is always a constructor for non-PODs assert(constructor_name!=""); irept cpp_name(ID_cpp_name); cpp_name.get_sub().push_back(irept(ID_name)); cpp_name.get_sub().back().set(ID_identifier, constructor_name); cpp_name.get_sub().back().set(ID_C_source_location, source_location); side_effect_expr_function_callt function_call; function_call.add_source_location()=source_location; function_call.function().swap(static_cast<exprt&>(cpp_name)); function_call.arguments().reserve(operands_tc.size()); for(exprt::operandst::iterator it=operands_tc.begin(); it!=operands_tc.end(); it++) function_call.op1().copy_to_operands(*it); typecheck_side_effect_function_call(function_call); assert(function_call.get(ID_statement)==ID_temporary_object); exprt &initializer = static_cast<exprt &>(function_call.add(ID_initializer)); assert(initializer.id()==ID_code && initializer.get(ID_statement)==ID_expression); side_effect_expr_function_callt &func_ini= to_side_effect_expr_function_call(initializer.op0()); exprt &tmp_this=func_ini.arguments().front(); assert(tmp_this.id()==ID_address_of && tmp_this.op0().id()=="new_object"); exprt address_of(ID_address_of, typet(ID_pointer)); address_of.type().subtype()=object_tc.type(); address_of.copy_to_operands(object_tc); tmp_this.swap(address_of); if(block.operands().empty()) return to_code(initializer); else { block.move_to_operands(initializer); return block; } } else assert(false); codet nil; nil.make_nil(); return nil; }
void cpp_typecheckt::convert_anonymous_union( cpp_declarationt &declaration, codet &code) { codet new_code(ID_decl_block); new_code.reserve_operands(declaration.declarators().size()); // unnamed object std::string identifier="#anon_union"+i2string(anon_counter++); irept name(ID_name); name.set(ID_identifier, identifier); name.set(ID_C_source_location, declaration.source_location()); cpp_namet cpp_name; cpp_name.move_to_sub(name); cpp_declaratort declarator; declarator.name()=cpp_name; cpp_declarator_convertert cpp_declarator_converter(*this); const symbolt &symbol= cpp_declarator_converter.convert(declaration, declarator); if(!cpp_is_pod(declaration.type())) { error().source_location=follow(declaration.type()).source_location(); error() << "anonymous union is not POD" << eom; throw 0; } codet decl_statement(ID_decl); decl_statement.reserve_operands(2); decl_statement.copy_to_operands(cpp_symbol_expr(symbol)); new_code.move_to_operands(decl_statement); // do scoping symbolt union_symbol=symbol_table.symbols[follow(symbol.type).get(ID_name)]; const irept::subt &components=union_symbol.type.add(ID_components).get_sub(); forall_irep(it, components) { if(it->find(ID_type).id()==ID_code) { error().source_location=union_symbol.type.source_location(); error() << "anonymous union `" << union_symbol.base_name << "' shall not have function members" << eom; throw 0; } const irep_idt &base_name=it->get(ID_base_name); if(cpp_scopes.current_scope().contains(base_name)) { error().source_location=union_symbol.type.source_location(); error() << "identifier `" << base_name << "' already in scope" << eom; throw 0; } cpp_idt &id=cpp_scopes.current_scope().insert(base_name); id.id_class = cpp_idt::SYMBOL; id.identifier=it->get(ID_name); id.class_identifier=union_symbol.name; id.is_member=true; } symbol_table.symbols[union_symbol.name].type.set( "#unnamed_object", symbol.base_name); code.swap(new_code); }
void cpp_typecheckt::typecheck_compound_declarator( const symbolt &symbol, const cpp_declarationt &declaration, cpp_declaratort &declarator, struct_typet::componentst &components, const irep_idt &access, bool is_static, bool is_typedef, bool is_mutable) { bool is_cast_operator= declaration.type().id()=="cpp-cast-operator"; if(is_cast_operator) { assert(declarator.name().get_sub().size()==2 && declarator.name().get_sub().front().id()==ID_operator); typet type=static_cast<typet &>(declarator.name().get_sub()[1]); declarator.type().subtype()=type; irept name(ID_name); name.set(ID_identifier, "("+cpp_type2name(type)+")"); declarator.name().get_sub().back().swap(name); } typet final_type= declarator.merge_type(declaration.type()); // this triggers template elaboration elaborate_class_template(final_type); typecheck_type(final_type); cpp_namet cpp_name; cpp_name.swap(declarator.name()); irep_idt base_name; if(cpp_name.is_nil()) { // Yes, there can be members without name. base_name=irep_idt(); } else if(cpp_name.is_simple_name()) { base_name=cpp_name.get_base_name(); } else { err_location(cpp_name.location()); str << "declarator in compound needs to be simple name"; throw 0; } bool is_method=!is_typedef && final_type.id()==ID_code; bool is_constructor=declaration.is_constructor(); bool is_destructor=declaration.is_destructor(); bool is_virtual=declaration.member_spec().is_virtual(); bool is_explicit=declaration.member_spec().is_explicit(); bool is_inline=declaration.member_spec().is_inline(); final_type.set(ID_C_member_name, symbol.name); // first do some sanity checks if(is_virtual && !is_method) { err_location(cpp_name.location()); str << "only methods can be virtual"; throw 0; } if(is_inline && !is_method) { err_location(cpp_name.location()); str << "only methods can be inlined"; throw 0; } if(is_virtual && is_static) { err_location(cpp_name.location()); str << "static methods cannot be virtual"; throw 0; } if(is_cast_operator && is_static) { err_location(cpp_name.location()); str << "cast operators cannot be static`"; throw 0; } if(is_constructor && is_virtual) { err_location(cpp_name.location()); str << "constructors cannot be virtual"; throw 0; } if(!is_constructor && is_explicit) { err_location(cpp_name.location()); str << "only constructors can be explicit"; throw 0; } if(is_constructor && base_name!=id2string(symbol.base_name)) { err_location(cpp_name.location()); str << "member function must return a value or void"; throw 0; } if(is_destructor && base_name!="~"+id2string(symbol.base_name)) { err_location(cpp_name.location()); str << "destructor with wrong name"; throw 0; } // now do actual work struct_typet::componentt component; irep_idt identifier= language_prefix+ cpp_scopes.current_scope().prefix+ id2string(base_name); component.set(ID_name, identifier); component.type()=final_type; component.set(ID_access, access); component.set(ID_base_name, base_name); component.set(ID_pretty_name, base_name); component.location()=cpp_name.location(); if(cpp_name.is_operator()) { component.set("is_operator", true); component.type().set("#is_operator", true); } if(is_cast_operator) component.set("is_cast_operator", true); if(declaration.member_spec().is_explicit()) component.set("is_explicit", true); typet &method_qualifier= (typet &)declarator.add("method_qualifier"); if(is_static) { component.set(ID_is_static, true); component.type().set("#is_static", true); } if(is_typedef) component.set("is_type", true); if(is_mutable) component.set("is_mutable", true); exprt &value=declarator.value(); irept &initializers=declarator.member_initializers(); if(is_method) { component.set(ID_is_inline, declaration.member_spec().is_inline()); // the 'virtual' name of the function std::string virtual_name= component.get_string(ID_base_name)+ id2string( function_identifier(static_cast<const typet &>(component.find(ID_type)))); if(method_qualifier.id()==ID_const) virtual_name += "$const"; if(component.type().get(ID_return_type) == ID_destructor) virtual_name= "@dtor"; // The method may be virtual implicitly. std::set<irep_idt> virtual_bases; for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { if(it->get_bool("is_virtual")) { if(it->get("virtual_name")==virtual_name) { is_virtual=true; const code_typet& code_type = to_code_type(it->type()); assert(code_type.arguments().size()>0); const typet& pointer_type = code_type.arguments()[0].type(); assert(pointer_type.id() == ID_pointer); virtual_bases.insert(pointer_type.subtype().get(ID_identifier)); } } } if(!is_virtual) { typecheck_member_function( symbol.name, component, initializers, method_qualifier, value); if(!value.is_nil() && !is_static) { err_location(cpp_name.location()); str << "no initialization allowed here"; throw 0; } } else // virtual { component.type().set("#is_virtual", true); component.type().set("#virtual_name",virtual_name); // Check if it is a pure virtual method if(is_virtual) { if(value.is_not_nil() && value.id() == ID_constant) { mp_integer i; to_integer(value, i); if(i!=0) { err_location(declarator.name().location()); str << "expected 0 to mark pure virtual method, got " << i; } component.set("is_pure_virtual", true); value.make_nil(); } } typecheck_member_function( symbol.name, component, initializers, method_qualifier, value); // get the virtual-table symbol type irep_idt vt_name = "virtual_table::"+symbol.name.as_string(); contextt::symbolst::iterator vtit = context.symbols.find(vt_name); if(vtit == context.symbols.end()) { // first time: create a virtual-table symbol type symbolt vt_symb_type; vt_symb_type.name= vt_name; vt_symb_type.base_name="virtual_table::"+symbol.base_name.as_string(); vt_symb_type.pretty_name = vt_symb_type.base_name; vt_symb_type.mode=ID_cpp; vt_symb_type.module=module; vt_symb_type.location=symbol.location; vt_symb_type.type = struct_typet(); vt_symb_type.type.set(ID_name, vt_symb_type.name); vt_symb_type.is_type = true; bool failed = context.move(vt_symb_type); assert(!failed); vtit = context.symbols.find(vt_name); // add a virtual-table pointer struct_typet::componentt compo; compo.type() = pointer_typet(symbol_typet(vt_name)); compo.set_name(symbol.name.as_string() +"::@vtable_pointer"); compo.set(ID_base_name, "@vtable_pointer"); compo.set(ID_pretty_name, symbol.base_name.as_string() +"@vtable_pointer"); compo.set("is_vtptr", true); compo.set(ID_access, ID_public); components.push_back(compo); put_compound_into_scope(compo); } assert(vtit->second.type.id()==ID_struct); struct_typet &virtual_table= to_struct_type(vtit->second.type); component.set("virtual_name", virtual_name); component.set("is_virtual", is_virtual); // add an entry to the virtual table struct_typet::componentt vt_entry; vt_entry.type() = pointer_typet(component.type()); vt_entry.set_name(vtit->first.as_string()+"::"+virtual_name); vt_entry.set(ID_base_name, virtual_name); vt_entry.set(ID_pretty_name, virtual_name); vt_entry.set(ID_access, ID_public); vt_entry.location() = symbol.location; virtual_table.components().push_back(vt_entry); // take care of overloading while(!virtual_bases.empty()) { irep_idt virtual_base = *virtual_bases.begin(); // a new function that does 'late casting' of the 'this' parameter symbolt func_symb; func_symb.name=component.get_name().as_string() + "::" +virtual_base.as_string(); func_symb.base_name=component.get(ID_base_name); func_symb.pretty_name = component.get(ID_base_name); func_symb.mode=ID_cpp; func_symb.module=module; func_symb.location=component.location(); func_symb.type=component.type(); // change the type of the 'this' pointer code_typet& code_type = to_code_type(func_symb.type); code_typet::argumentt& arg= code_type.arguments().front(); arg.type().subtype().set(ID_identifier, virtual_base); // create symbols for the arguments code_typet::argumentst& args = code_type.arguments(); for(unsigned i=0; i<args.size(); i++) { code_typet::argumentt& arg = args[i]; irep_idt base_name = arg.get_base_name(); if(base_name==irep_idt()) base_name="arg"+i2string(i); symbolt arg_symb; arg_symb.name = func_symb.name.as_string() + "::"+ base_name.as_string(); arg_symb.base_name = base_name; arg_symb.pretty_name = base_name; arg_symb.mode=ID_cpp; arg_symb.location=func_symb.location; arg_symb.type = arg.type(); arg.set(ID_C_identifier, arg_symb.name); // add the argument to the symbol table bool failed = context.move(arg_symb); assert(!failed); } // do the body of the function typecast_exprt late_cast(to_code_type(component.type()).arguments()[0].type()); late_cast.op0()= symbol_expr(namespacet(context).lookup( args[0].get(ID_C_identifier))); if(code_type.return_type().id()!=ID_empty && code_type.return_type().id()!=ID_destructor) { side_effect_expr_function_callt expr_call; expr_call.function() = symbol_exprt(component.get_name(),component.type()); expr_call.type() = to_code_type(component.type()).return_type(); expr_call.arguments().reserve(args.size()); expr_call.arguments().push_back(late_cast); for(unsigned i=1; i < args.size(); i++) { expr_call.arguments().push_back( symbol_expr(namespacet(context).lookup( args[i].get(ID_C_identifier)))); } code_returnt code_return; code_return.return_value() = expr_call; func_symb.value = code_return; } else { code_function_callt code_func; code_func.function() = symbol_exprt(component.get_name(),component.type()); code_func.arguments().reserve(args.size()); code_func.arguments().push_back(late_cast); for(unsigned i=1; i < args.size(); i++) { code_func.arguments().push_back( symbol_expr(namespacet(context).lookup( args[i].get(ID_C_identifier)))); } func_symb.value = code_func; } // add this new function to the list of components struct_typet::componentt new_compo = component; new_compo.type() = func_symb.type; new_compo.set_name(func_symb.name); components.push_back(new_compo); // add the function to the symbol table { bool failed = context.move(func_symb); assert(!failed); } // next base virtual_bases.erase(virtual_bases.begin()); } } } if(is_static && !is_method) // static non-method member { // add as global variable to context symbolt static_symbol; static_symbol.mode=symbol.mode; static_symbol.name=identifier; static_symbol.type=component.type(); static_symbol.base_name=component.get(ID_base_name); static_symbol.lvalue=true; static_symbol.static_lifetime=true; static_symbol.location=cpp_name.location(); static_symbol.is_extern=true; // TODO: not sure about this: should be defined separately! dynamic_initializations.push_back(static_symbol.name); symbolt *new_symbol; if(context.move(static_symbol, new_symbol)) { err_location(cpp_name.location()); str << "redeclaration of static member `" << static_symbol.base_name.as_string() << "'"; throw 0; } if(value.is_not_nil()) { if(cpp_is_pod(new_symbol->type)) { new_symbol->value.swap(value); c_typecheck_baset::do_initializer(*new_symbol); // these are macros if they are PODs and come with a (constant) value if(new_symbol->type.get_bool(ID_C_constant)) { simplify(new_symbol->value, *this); new_symbol->is_macro=true; } } else { symbol_exprt symexpr; symexpr.set_identifier(new_symbol->name); exprt::operandst ops; ops.push_back(value); codet defcode = cpp_constructor(locationt(), symexpr, ops); new_symbol->value.swap(defcode); } } } // array members must have fixed size check_fixed_size_array(component.type()); put_compound_into_scope(component); components.push_back(component); }