See More

/*******************************************************************\ Module: C++ Language Type Conversion Author: Daniel Kroening, [email protected] \*******************************************************************/ /// \file /// C++ Language Type Conversion #include "cpp_convert_type.h" #include #include #include #include #include #include #include "cpp_declaration.h" #include "cpp_name.h" class cpp_convert_typet : public ansi_c_convert_typet { public: // The following types exist in C11 and later, but are implemented as // typedefs. In C++, they are keywords and thus required explicit handling in // here. std::size_t wchar_t_count, char16_t_count, char32_t_count; void write(typet &type) override; cpp_convert_typet(message_handlert &message_handler, const typet &type) : ansi_c_convert_typet(message_handler), wchar_t_count(0), char16_t_count(0), char32_t_count(0) { source_location = type.source_location(); read_rec(type); } protected: void read_rec(const typet &type) override; void read_function_type(const typet &type); void read_template(const typet &type); }; void cpp_convert_typet::read_rec(const typet &type) { #if 0 std::cout << "cpp_convert_typet::read_rec: " << type.pretty() << '\n'; #endif if(type.id() == ID_gcc_float80) ++gcc_float64x_cnt; else if(type.id()==ID_wchar_t) ++wchar_t_count; else if(type.id()==ID_char16_t) ++char16_t_count; else if(type.id()==ID_char32_t) ++char32_t_count; else if(type.id()==ID_constexpr) c_qualifiers.is_constant = true; else if(type.id()==ID_function_type) { read_function_type(type); } else if(type.id()==ID_identifier) { // from parameters } else if(type.id()==ID_cpp_name) { // from typedefs other.push_back(type); } else if(type.id()==ID_array) { other.push_back(type); cpp_convert_plain_type( to_array_type(other.back()).element_type(), message_handler); } else if(type.id()==ID_template) { read_template(type); } else if(type.id()==ID_frontend_pointer) { // add width and turn into ID_pointer pointer_typet tmp( to_type_with_subtype(type).subtype(), config.ansi_c.pointer_width); tmp.add_source_location()=type.source_location(); if(type.get_bool(ID_C_reference)) tmp.set(ID_C_reference, true); if(type.get_bool(ID_C_rvalue_reference)) tmp.set(ID_C_rvalue_reference, true); const irep_idt typedef_identifier = type.get(ID_C_typedef); if(!typedef_identifier.empty()) tmp.set(ID_C_typedef, typedef_identifier); other.push_back(tmp); } else if(type.id()==ID_pointer) { // ignore, we unfortunately convert multiple times other.push_back(type); } else if(type.id() == ID_frontend_vector) vector_size = static_cast(type.find(ID_size)); else { ansi_c_convert_typet::read_rec(type); } } void cpp_convert_typet::read_template(const typet &type) { other.push_back(type); typet &t=other.back(); cpp_convert_plain_type(to_type_with_subtype(t).subtype(), message_handler); irept &arguments=t.add(ID_arguments); for(auto &argument : arguments.get_sub()) { exprt &decl = static_cast(argument); // may be type or expression bool is_type=decl.get_bool(ID_is_type); if(is_type) { } else { cpp_convert_plain_type(decl.type(), message_handler); } // TODO: initializer } } void cpp_convert_typet::read_function_type(const typet &type) { other.push_back(type); other.back().id(ID_code); code_typet &t = to_code_type(other.back()); // change subtype to return_type typet &return_type = t.return_type(); return_type.swap(to_type_with_subtype(t).subtype()); t.remove_subtype(); if(return_type.is_not_nil()) cpp_convert_plain_type(return_type, message_handler); // take care of parameter types code_typet::parameterst &parameters = t.parameters(); // see if we have an ellipsis if(!parameters.empty() && parameters.back().id() == ID_ellipsis) { t.make_ellipsis(); parameters.pop_back(); } for(auto &parameter_expr : parameters) { if(parameter_expr.id()==ID_cpp_declaration) { cpp_declarationt &declaration=to_cpp_declaration(parameter_expr); source_locationt type_location=declaration.type().source_location(); cpp_convert_plain_type(declaration.type(), message_handler); DATA_INVARIANT( declaration.declarators().size() == 1, "there should be only one declarator"); cpp_declaratort &declarator= declaration.declarators().front(); // do we have a declarator? if(declarator.is_nil()) { parameter_expr = code_typet::parametert(declaration.type()); parameter_expr.add_source_location()=type_location; } else { const cpp_namet &cpp_name=declarator.name(); typet final_type=declarator.merge_type(declaration.type()); // see if it's an array type if(final_type.id()==ID_array) { // turn into pointer type final_type = pointer_type(to_array_type(final_type).element_type()); } code_typet::parametert new_parameter(final_type); if(cpp_name.is_nil()) { new_parameter.add_source_location()=type_location; } else if(cpp_name.is_simple_name()) { irep_idt base_name=cpp_name.get_base_name(); CHECK_RETURN(!base_name.empty()); new_parameter.set_identifier(base_name); new_parameter.set_base_name(base_name); new_parameter.add_source_location()=cpp_name.source_location(); } else { throw "expected simple name as parameter"; } if(declarator.value().is_not_nil()) new_parameter.default_value().swap(declarator.value()); parameter_expr.swap(new_parameter); } } else if(parameter_expr.id()==ID_ellipsis) { throw "ellipsis only allowed as last parameter"; } else UNREACHABLE; } // if we just have one parameter of type void, remove it if(parameters.size() == 1 && parameters.front().type().id() == ID_empty) parameters.clear(); } void cpp_convert_typet::write(typet &type) { if(!other.empty()) { if(wchar_t_count || char16_t_count || char32_t_count) { messaget log{message_handler}; log.error().source_location = source_location; log.error() << "illegal type modifier for defined type" << messaget::eom; throw 0; } ansi_c_convert_typet::write(type); } else if(c_bool_cnt) { if( signed_cnt || unsigned_cnt || int_cnt || short_cnt || char_cnt || wchar_t_count || proper_bool_cnt || char16_t_count || char32_t_count || int8_cnt || int16_cnt || int32_cnt || int64_cnt || gcc_int128_cnt || ptr32_cnt || ptr64_cnt) { throw "illegal type modifier for C++ bool"; } ansi_c_convert_typet::write(type); } else if(wchar_t_count) { // This is a distinct type, and can't be made signed/unsigned. // This is tolerated by most compilers, however. if( int_cnt || short_cnt || char_cnt || long_cnt || char16_t_count || char32_t_count || int8_cnt || int16_cnt || int32_cnt || int64_cnt || ptr32_cnt || ptr64_cnt) { throw "illegal type modifier for wchar_t"; } type=wchar_t_type(); ansi_c_convert_typet::build_type_with_subtype(type); ansi_c_convert_typet::set_attributes(type); } else if(char16_t_count) { // This is a distinct type, and can't be made signed/unsigned. if( int_cnt || short_cnt || char_cnt || long_cnt || char32_t_count || int8_cnt || int16_cnt || int32_cnt || int64_cnt || ptr32_cnt || ptr64_cnt || signed_cnt || unsigned_cnt) { throw "illegal type modifier for char16_t"; } type=char16_t_type(); ansi_c_convert_typet::build_type_with_subtype(type); ansi_c_convert_typet::set_attributes(type); } else if(char32_t_count) { // This is a distinct type, and can't be made signed/unsigned. if(int_cnt || short_cnt || char_cnt || long_cnt || int8_cnt || int16_cnt || int32_cnt || int64_cnt || ptr32_cnt || ptr64_cnt || signed_cnt || unsigned_cnt) { throw "illegal type modifier for char32_t"; } type=char32_t_type(); ansi_c_convert_typet::build_type_with_subtype(type); ansi_c_convert_typet::set_attributes(type); } else { ansi_c_convert_typet::write(type); } } void cpp_convert_plain_type(typet &type, message_handlert &message_handler) { if( type.id() == ID_cpp_name || type.id() == ID_struct || type.id() == ID_union || type.id() == ID_array || type.id() == ID_code || type.id() == ID_unsignedbv || type.id() == ID_signedbv || type.id() == ID_bool || type.id() == ID_floatbv || type.id() == ID_empty || type.id() == ID_constructor || type.id() == ID_destructor || type.id() == ID_c_enum) { } else if(type.id() == ID_c_bool) { type.set(ID_width, config.ansi_c.bool_width); } else { cpp_convert_typet cpp_convert_type(message_handler, type); cpp_convert_type.write(type); } } void cpp_convert_auto( typet &dest, const typet &src, message_handlert &message_handler) { if(dest.id() != ID_merged_type && dest.has_subtype()) { cpp_convert_auto( to_type_with_subtype(dest).subtype(), src, message_handler); return; } cpp_convert_typet cpp_convert_type(message_handler, dest); for(auto &t : cpp_convert_type.other) if(t.id() == ID_auto) t = src; cpp_convert_type.write(dest); }