bool tan_parseoptionst::from_file(const std::string &filename) { std::ifstream infile(filename.c_str()); if(!infile) { error(std::string("Error opening file `")+filename+"'."); return true; } status(std::string("Loading `")+filename+"' ..."); if(read_goto_binary(filename, context, goto_functions, get_message_handler())) { error(std::string("Error reading file `")+filename+"'."); return true; } if(cmdline.isset("show-program")) { goto_functions.output(namespacet(context), std::cout); return true; } return false; }
std::string from_type(const typet &type) { symbol_tablet symbol_table; return from_type(namespacet(symbol_table), "", type); }
std::string from_expr(const exprt &expr) { symbol_tablet symbol_table; return from_expr(namespacet(symbol_table), "", expr); }
clang_c_adjust::clang_c_adjust(contextt &_context) : context(_context), ns(namespacet(context)) { }
void cpp_typecheckt::do_virtual_table(const symbolt &symbol) { assert(symbol.type.id()==ID_struct); // builds virtual-table value maps: (class x virtual_name x value) std::map<irep_idt, std::map<irep_idt,exprt> > vt_value_maps; const struct_typet &struct_type = to_struct_type(symbol.type); for(unsigned i = 0; i < struct_type.components().size(); i++) { const struct_typet::componentt& compo = struct_type.components()[i]; if(!compo.get_bool("is_virtual")) continue; const code_typet& code_type = to_code_type(compo.type()); assert(code_type.arguments().size() > 0); const pointer_typet& pointer_type = static_cast<const pointer_typet&>(code_type.arguments()[0].type()); irep_idt class_id = pointer_type.subtype().get("identifier"); std::map<irep_idt,exprt>& value_map = vt_value_maps[class_id]; exprt e = symbol_exprt(compo.get_name(),code_type); if(compo.get_bool("is_pure_virtual")) { pointer_typet pointer_type(code_type); e = gen_zero(pointer_type); assert(e.is_not_nil()); value_map[compo.get("virtual_name")] = e; } else { address_of_exprt address(e); value_map[compo.get("virtual_name")] = address; } } // create virtual-table symbol variables for(std::map<irep_idt, std::map<irep_idt,exprt> >::const_iterator cit = vt_value_maps.begin(); cit != vt_value_maps.end(); cit++) { const std::map<irep_idt,exprt>& value_map = cit->second; const symbolt& late_cast_symb = namespacet(symbol_table).lookup(cit->first); const symbolt& vt_symb_type = namespacet(symbol_table).lookup("virtual_table::"+id2string(late_cast_symb.name)); symbolt vt_symb_var; vt_symb_var.name= id2string(vt_symb_type.name) + "@"+ id2string(symbol.name); vt_symb_var.base_name= id2string(vt_symb_type.base_name) + "@" + id2string(symbol.base_name); vt_symb_var.mode=ID_cpp; vt_symb_var.module=module; vt_symb_var.location=vt_symb_type.location; vt_symb_var.type = symbol_typet(vt_symb_type.name); vt_symb_var.is_lvalue = true; vt_symb_var.is_static_lifetime = true; // do the values const struct_typet &vt_type = to_struct_type(vt_symb_type.type); exprt values(ID_struct, symbol_typet(vt_symb_type.name)); for(unsigned i=0; i < vt_type.components().size(); i++) { const struct_typet::componentt& compo = vt_type.components()[i]; std::map<irep_idt,exprt>::const_iterator cit2 = value_map.find( compo.get("base_name")); assert(cit2 != value_map.end()); const exprt& value = cit2->second; assert(value.type() == compo.type()); values.operands().push_back(value); } vt_symb_var.value = values; bool failed = symbol_table.move(vt_symb_var); assert(!failed); } }
std::string cegis_operand_array_name(const symbol_tablet &st, const typet &type) { std::string result(VARIABLE_ARRAY_PREFIX); return result+=type2c(type, namespacet(st)); }
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); }