|  | /* Convert types from GDB to GCC | 
|  |  | 
|  | Copyright (C) 2014-2024 Free Software Foundation, Inc. | 
|  |  | 
|  | This file is part of GDB. | 
|  |  | 
|  | This program is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 3 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
|  |  | 
|  |  | 
|  | #include "gdbsupport/preprocessor.h" | 
|  | #include "gdbtypes.h" | 
|  | #include "compile-internal.h" | 
|  | #include "compile-cplus.h" | 
|  | #include "gdbsupport/gdb_assert.h" | 
|  | #include "symtab.h" | 
|  | #include "source.h" | 
|  | #include "cp-support.h" | 
|  | #include "cp-abi.h" | 
|  | #include "objfiles.h" | 
|  | #include "block.h" | 
|  | #include "cli/cli-cmds.h" | 
|  | #include "c-lang.h" | 
|  | #include "compile-c.h" | 
|  | #include <algorithm> | 
|  |  | 
|  | /* Default compile flags for C++.  */ | 
|  |  | 
|  | const char *compile_cplus_instance::m_default_cflags = "-std=gnu++11"; | 
|  |  | 
|  | /* Flag to enable internal debugging.  */ | 
|  |  | 
|  | static bool debug_compile_cplus_types = false; | 
|  |  | 
|  | /* Flag to enable internal scope switching debugging.  */ | 
|  |  | 
|  | static bool debug_compile_cplus_scopes = false; | 
|  |  | 
|  | /* Forward declarations.  */ | 
|  |  | 
|  | static gcc_type compile_cplus_convert_func (compile_cplus_instance *instance, | 
|  | struct type *type, | 
|  | bool strip_artificial); | 
|  |  | 
|  | /* See description in compile-cplus.h.  */ | 
|  |  | 
|  | gdb::unique_xmalloc_ptr<char> | 
|  | compile_cplus_instance::decl_name (const char *natural) | 
|  | { | 
|  | if (natural == nullptr) | 
|  | return nullptr; | 
|  |  | 
|  | gdb::unique_xmalloc_ptr<char> name = cp_func_name (natural); | 
|  | if (name != nullptr) | 
|  | return name; | 
|  |  | 
|  | return make_unique_xstrdup (natural); | 
|  | } | 
|  |  | 
|  | /* Get the access flag for the NUM'th field of TYPE.  */ | 
|  |  | 
|  | static enum gcc_cp_symbol_kind | 
|  | get_field_access_flag (const struct type *type, int num) | 
|  | { | 
|  | field &fld = type->field (num); | 
|  | if (fld.is_protected ()) | 
|  | return GCC_CP_ACCESS_PROTECTED; | 
|  | else if (fld.is_private ()) | 
|  | return GCC_CP_ACCESS_PRIVATE; | 
|  |  | 
|  | /* GDB assumes everything else is public.  */ | 
|  | return GCC_CP_ACCESS_PUBLIC; | 
|  | } | 
|  |  | 
|  | /* Get the access flag for the NUM'th method of TYPE's FNI'th | 
|  | fieldlist.  */ | 
|  |  | 
|  | enum gcc_cp_symbol_kind | 
|  | get_method_access_flag (const struct type *type, int fni, int num) | 
|  | { | 
|  | gdb_assert (type->code () == TYPE_CODE_STRUCT); | 
|  |  | 
|  | /* If this type was not declared a class, everything is public.  */ | 
|  | if (!type->is_declared_class ()) | 
|  | return GCC_CP_ACCESS_PUBLIC; | 
|  |  | 
|  | /* Otherwise, read accessibility from the fn_field.  */ | 
|  | const struct fn_field *methods = TYPE_FN_FIELDLIST1 (type, fni); | 
|  | if (TYPE_FN_FIELD_PROTECTED (methods, num)) | 
|  | return GCC_CP_ACCESS_PROTECTED; | 
|  | else if (TYPE_FN_FIELD_PRIVATE (methods, num)) | 
|  | return GCC_CP_ACCESS_PRIVATE; | 
|  | else | 
|  | return GCC_CP_ACCESS_PUBLIC; | 
|  | } | 
|  |  | 
|  | /* A useful debugging function to output the scope SCOPE to stdout.  */ | 
|  |  | 
|  | static void __attribute__ ((used)) | 
|  | debug_print_scope (const compile_scope &scope) | 
|  | { | 
|  | for (const auto &comp: scope) | 
|  | { | 
|  | const char *symbol = (comp.bsymbol.symbol != nullptr | 
|  | ? comp.bsymbol.symbol->natural_name () | 
|  | : "<none>"); | 
|  |  | 
|  | printf_unfiltered ("\tname = %s, symbol = %s\n", comp.name.c_str (), | 
|  | symbol); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* See description in compile-cplus.h.  */ | 
|  |  | 
|  | compile_scope | 
|  | type_name_to_scope (const char *type_name, const struct block *block) | 
|  | { | 
|  | compile_scope scope; | 
|  |  | 
|  | if (type_name == nullptr) | 
|  | { | 
|  | /* An anonymous type.  We cannot really do much here.  We simply cannot | 
|  | look up anonymous types easily/at all.  */ | 
|  | return scope; | 
|  | } | 
|  |  | 
|  | const char *p = type_name; | 
|  | std::string lookup_name; | 
|  |  | 
|  | while (*p != '\0') | 
|  | { | 
|  | /* Create a string token of the first component of TYPE_NAME.  */ | 
|  | int len = cp_find_first_component (p); | 
|  | std::string s (p, len); | 
|  |  | 
|  | /* Advance past the last token.  */ | 
|  | p += len; | 
|  |  | 
|  | /* Look up the symbol and decide when to stop.  */ | 
|  | if (!lookup_name.empty ()) | 
|  | lookup_name += "::"; | 
|  | lookup_name += s; | 
|  |  | 
|  | /* Look up the resulting name.  */ | 
|  | struct block_symbol bsymbol | 
|  | = lookup_symbol (lookup_name.c_str (), block, SEARCH_VFT, nullptr); | 
|  |  | 
|  | if (bsymbol.symbol != nullptr) | 
|  | { | 
|  | scope_component comp = {s, bsymbol}; | 
|  |  | 
|  | scope.push_back (comp); | 
|  |  | 
|  | if (bsymbol.symbol->type ()->code () != TYPE_CODE_NAMESPACE) | 
|  | { | 
|  | /* We're done.  */ | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (*p == ':') | 
|  | { | 
|  | ++p; | 
|  | if (*p == ':') | 
|  | ++p; | 
|  | else | 
|  | { | 
|  | /* This shouldn't happen since we are not attempting to | 
|  | loop over user input.  This name is generated by GDB | 
|  | from debug info.  */ | 
|  | internal_error (_("malformed TYPE_NAME during parsing")); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return scope; | 
|  | } | 
|  |  | 
|  | /* Compare two scope_components for equality.  These are equal if the names | 
|  | of the two components' are the same.  */ | 
|  |  | 
|  | bool | 
|  | operator== (const scope_component &lhs, const scope_component &rhs) | 
|  | { | 
|  | return lhs.name == rhs.name; | 
|  | } | 
|  |  | 
|  | /* Compare two scope_components for inequality.  These are not equal if | 
|  | the two components' names are not equal.  */ | 
|  |  | 
|  | bool | 
|  | operator!= (const scope_component &lhs, const scope_component &rhs) | 
|  | { | 
|  | return lhs.name != rhs.name; | 
|  | } | 
|  |  | 
|  | /* Compare two compile_scopes for equality.  These are equal if they are both | 
|  | contain the same number of components and each component is equal.  */ | 
|  |  | 
|  | bool | 
|  | operator== (const compile_scope &lhs, const compile_scope &rhs) | 
|  | { | 
|  | if (lhs.size () != rhs.size ()) | 
|  | return false; | 
|  |  | 
|  | for (int i = 0; i < lhs.size (); ++i) | 
|  | { | 
|  | if (lhs[i] != rhs[i]) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* Compare two compile_scopes for inequality.  These are inequal if they | 
|  | contain unequal number of elements or if any of the components are not | 
|  | the same.  */ | 
|  |  | 
|  | bool | 
|  | operator!= (const compile_scope &lhs, const compile_scope &rhs) | 
|  | { | 
|  | if (lhs.size () != rhs.size ()) | 
|  | return true; | 
|  |  | 
|  | for (int i = 0; i < lhs.size (); ++i) | 
|  | { | 
|  | if (lhs[i] != rhs[i]) | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /* See description in compile-cplus.h.  */ | 
|  |  | 
|  | void | 
|  | compile_cplus_instance::enter_scope (compile_scope &&new_scope) | 
|  | { | 
|  | bool must_push = m_scopes.empty () || m_scopes.back () != new_scope; | 
|  |  | 
|  | new_scope.m_pushed = must_push; | 
|  |  | 
|  | /* Save the new scope.  */ | 
|  | m_scopes.push_back (std::move (new_scope)); | 
|  |  | 
|  | if (must_push) | 
|  | { | 
|  | if (debug_compile_cplus_scopes) | 
|  | { | 
|  | gdb_printf (gdb_stdlog, "entering new scope %s\n", | 
|  | host_address_to_string (&m_scopes.back ())); | 
|  | } | 
|  |  | 
|  | /* Push the global namespace. */ | 
|  | plugin ().push_namespace (""); | 
|  |  | 
|  | /* Push all other namespaces.  Note that we do not push the last | 
|  | scope_component -- that's the actual type we are converting.  */ | 
|  | std::for_each | 
|  | (m_scopes.back ().begin (), m_scopes.back ().end () - 1, | 
|  | [this] (const scope_component &comp) | 
|  | { | 
|  | gdb_assert (comp.bsymbol.symbol->type ()->code () | 
|  | == TYPE_CODE_NAMESPACE); | 
|  |  | 
|  | const char *ns = (comp.name == CP_ANONYMOUS_NAMESPACE_STR ? nullptr | 
|  | : comp.name.c_str ()); | 
|  |  | 
|  | this->plugin ().push_namespace (ns); | 
|  | }); | 
|  | } | 
|  | else | 
|  | { | 
|  | if (debug_compile_cplus_scopes) | 
|  | { | 
|  | gdb_printf (gdb_stdlog, "staying in current scope -- " | 
|  | "scopes are identical\n"); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* See description in compile-cplus.h.  */ | 
|  |  | 
|  | void | 
|  | compile_cplus_instance::leave_scope () | 
|  | { | 
|  | /* Get the current scope and remove it from the internal list of | 
|  | scopes.  */ | 
|  | compile_scope current = m_scopes.back (); | 
|  |  | 
|  | m_scopes.pop_back (); | 
|  |  | 
|  | if (current.m_pushed) | 
|  | { | 
|  | if (debug_compile_cplus_scopes) | 
|  | { | 
|  | gdb_printf (gdb_stdlog, "leaving scope %s\n", | 
|  | host_address_to_string (¤t)); | 
|  | } | 
|  |  | 
|  | /* Pop namespaces.  */ | 
|  | std::for_each | 
|  | (current.begin (),current.end () - 1, | 
|  | [this] (const scope_component &comp) { | 
|  | gdb_assert (comp.bsymbol.symbol->type ()->code () | 
|  | == TYPE_CODE_NAMESPACE); | 
|  | this->plugin ().pop_binding_level (comp.name.c_str ()); | 
|  | }); | 
|  |  | 
|  | /* Pop global namespace.  */ | 
|  | plugin ().pop_binding_level (""); | 
|  | } | 
|  | else | 
|  | { | 
|  | if (debug_compile_cplus_scopes) | 
|  | gdb_printf (gdb_stdlog, | 
|  | "identical scopes -- not leaving scope\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* See description in compile-cplus.h.  */ | 
|  |  | 
|  | compile_scope | 
|  | compile_cplus_instance::new_scope (const char *type_name, struct type *type) | 
|  | { | 
|  | /* Break the type name into components.  If TYPE was defined in some | 
|  | superclass, we do not process TYPE but process the enclosing type | 
|  | instead.  */ | 
|  | compile_scope scope = type_name_to_scope (type_name, block ()); | 
|  |  | 
|  | if (!scope.empty ()) | 
|  | { | 
|  | /* Get the name of the last component, which should be the | 
|  | unqualified name of the type to process.  */ | 
|  | scope_component &comp = scope.back (); | 
|  |  | 
|  | if (!types_equal (type, comp.bsymbol.symbol->type ()) | 
|  | && (m_scopes.empty () | 
|  | || (m_scopes.back ().back ().bsymbol.symbol | 
|  | != comp.bsymbol.symbol))) | 
|  | { | 
|  | /* The type is defined inside another class(es).  Convert that | 
|  | type instead of defining this type.  */ | 
|  | convert_type (comp.bsymbol.symbol->type ()); | 
|  |  | 
|  | /* If the original type (passed in to us) is defined in a nested | 
|  | class, the previous call will give us that type's gcc_type. | 
|  | Upper layers are expecting to get the original type's | 
|  | gcc_type!  */ | 
|  | get_cached_type (type, &scope.m_nested_type); | 
|  | return scope; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if (type->name () == nullptr) | 
|  | { | 
|  | /* Anonymous type  */ | 
|  |  | 
|  | /* We don't have a qualified name for this to look up, but | 
|  | we need a scope.  We have to assume, then, that it is the same | 
|  | as the current scope, if any.  */ | 
|  | if (!m_scopes.empty ()) | 
|  | { | 
|  | scope = m_scopes.back (); | 
|  | scope.m_pushed = false; | 
|  | } | 
|  | else | 
|  | scope.push_back (scope_component ()); | 
|  | } | 
|  | else | 
|  | { | 
|  | scope_component comp | 
|  | = { | 
|  | decl_name (type->name ()).get (), | 
|  | lookup_symbol (type->name (), block (), SEARCH_VFT, nullptr) | 
|  | }; | 
|  | scope.push_back (comp); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* There must be at least one component in the compile_scope.  */ | 
|  | gdb_assert (scope.size () > 0); | 
|  | return scope; | 
|  | } | 
|  |  | 
|  | /* See description in compile-cplus.h.  */ | 
|  |  | 
|  | gcc_type | 
|  | compile_cplus_instance::convert_reference_base | 
|  | (gcc_type base, enum gcc_cp_ref_qualifiers rquals) | 
|  | { | 
|  | return this->plugin ().build_reference_type (base, rquals); | 
|  | } | 
|  |  | 
|  | /* Convert a reference type to its gcc representation.  */ | 
|  |  | 
|  | static gcc_type | 
|  | compile_cplus_convert_reference (compile_cplus_instance *instance, | 
|  | struct type *type) | 
|  | { | 
|  | gcc_type target = instance->convert_type (type->target_type ()); | 
|  |  | 
|  | enum gcc_cp_ref_qualifiers quals = GCC_CP_REF_QUAL_NONE; | 
|  | switch (type->code ()) | 
|  | { | 
|  | case TYPE_CODE_REF: | 
|  | quals = GCC_CP_REF_QUAL_LVALUE; | 
|  | break; | 
|  | case TYPE_CODE_RVALUE_REF: | 
|  | quals = GCC_CP_REF_QUAL_RVALUE; | 
|  | break; | 
|  | default: | 
|  | gdb_assert_not_reached ("unexpected type code for reference type"); | 
|  | } | 
|  |  | 
|  | return instance->convert_reference_base (target, quals); | 
|  | } | 
|  |  | 
|  | /* See description in compile-cplus.h.  */ | 
|  |  | 
|  | gcc_type | 
|  | compile_cplus_instance::convert_pointer_base(gcc_type target) | 
|  | { | 
|  | return plugin ().build_pointer_type (target); | 
|  | } | 
|  |  | 
|  | /* Convert a pointer type to its gcc representation.  */ | 
|  |  | 
|  | static gcc_type | 
|  | compile_cplus_convert_pointer (compile_cplus_instance *instance, | 
|  | struct type *type) | 
|  | { | 
|  | gcc_type target = instance->convert_type (type->target_type ()); | 
|  |  | 
|  | return instance->convert_pointer_base (target); | 
|  | } | 
|  |  | 
|  | /* Convert an array type to its gcc representation.  */ | 
|  |  | 
|  | static gcc_type | 
|  | compile_cplus_convert_array (compile_cplus_instance *instance, | 
|  | struct type *type) | 
|  | { | 
|  | struct type *range = type->index_type (); | 
|  | gcc_type element_type = instance->convert_type (type->target_type ()); | 
|  |  | 
|  | if (!range->bounds ()->low.is_constant ()) | 
|  | { | 
|  | const char *s = _("array type with non-constant" | 
|  | " lower bound is not supported"); | 
|  |  | 
|  | return instance->plugin ().error (s); | 
|  | } | 
|  |  | 
|  | if (range->bounds ()->low.const_val () != 0) | 
|  | { | 
|  | const char *s = _("cannot convert array type with " | 
|  | "non-zero lower bound to C"); | 
|  |  | 
|  | return instance->plugin ().error (s); | 
|  | } | 
|  |  | 
|  | if (range->bounds ()->high.kind () == PROP_LOCEXPR | 
|  | || range->bounds ()->high.kind () == PROP_LOCLIST) | 
|  | { | 
|  | if (type->is_vector ()) | 
|  | { | 
|  | const char *s = _("variably-sized vector type is not supported"); | 
|  |  | 
|  | return instance->plugin ().error (s); | 
|  | } | 
|  |  | 
|  | std::string upper_bound | 
|  | = c_get_range_decl_name (&range->bounds ()->high); | 
|  | return instance->plugin ().build_vla_array_type (element_type, | 
|  | upper_bound.c_str ()); | 
|  | } | 
|  | else | 
|  | { | 
|  | LONGEST low_bound, high_bound, count; | 
|  |  | 
|  | if (!get_array_bounds (type, &low_bound, &high_bound)) | 
|  | count = -1; | 
|  | else | 
|  | { | 
|  | gdb_assert (low_bound == 0); /* Ensured above.  */ | 
|  | count = high_bound + 1; | 
|  | } | 
|  |  | 
|  | if (type->is_vector ()) | 
|  | return instance->plugin ().build_vector_type (element_type, count); | 
|  |  | 
|  | return instance->plugin ().build_array_type (element_type, count); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Convert a typedef of TYPE.  If not GCC_CP_ACCESS_NONE, NESTED_ACCESS | 
|  | will define the accessibility of the typedef definition in its | 
|  | containing class.  */ | 
|  |  | 
|  | static gcc_type | 
|  | compile_cplus_convert_typedef (compile_cplus_instance *instance, | 
|  | struct type *type, | 
|  | enum gcc_cp_symbol_kind nested_access) | 
|  | { | 
|  | compile_scope scope = instance->new_scope (type->name (), type); | 
|  |  | 
|  | if (scope.nested_type () != GCC_TYPE_NONE) | 
|  | return scope.nested_type (); | 
|  |  | 
|  | gdb::unique_xmalloc_ptr<char> name | 
|  | = compile_cplus_instance::decl_name (type->name ()); | 
|  |  | 
|  | /* Make sure the scope for this type has been pushed.  */ | 
|  | instance->enter_scope (std::move (scope)); | 
|  |  | 
|  | /* Convert the typedef's real type.  */ | 
|  | gcc_type typedef_type = instance->convert_type (check_typedef (type)); | 
|  |  | 
|  | instance->plugin ().build_decl ("typedef", name.get (), | 
|  | GCC_CP_SYMBOL_TYPEDEF | nested_access, | 
|  | typedef_type, 0, 0, nullptr, 0); | 
|  |  | 
|  | /* Completed this scope.  */ | 
|  | instance->leave_scope (); | 
|  | return typedef_type; | 
|  | } | 
|  |  | 
|  | /* Convert types defined in TYPE.  */ | 
|  |  | 
|  | static void | 
|  | compile_cplus_convert_type_defns (compile_cplus_instance *instance, | 
|  | struct type *type) | 
|  | { | 
|  | int i; | 
|  | enum gcc_cp_symbol_kind accessibility; | 
|  |  | 
|  | /* Convert typedefs.  */ | 
|  | for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (type); ++i) | 
|  | { | 
|  | if (TYPE_TYPEDEF_FIELD_PROTECTED (type, i)) | 
|  | accessibility = GCC_CP_ACCESS_PROTECTED; | 
|  | else if (TYPE_TYPEDEF_FIELD_PRIVATE (type, i)) | 
|  | accessibility = GCC_CP_ACCESS_PRIVATE; | 
|  | else | 
|  | accessibility = GCC_CP_ACCESS_PUBLIC; | 
|  | instance->convert_type (TYPE_TYPEDEF_FIELD_TYPE (type, i), accessibility); | 
|  | } | 
|  |  | 
|  | /* Convert nested types.  */ | 
|  | for (i = 0; i < TYPE_NESTED_TYPES_COUNT (type); ++i) | 
|  | { | 
|  | if (TYPE_NESTED_TYPES_FIELD_PROTECTED (type, i)) | 
|  | accessibility = GCC_CP_ACCESS_PROTECTED; | 
|  | else if (TYPE_NESTED_TYPES_FIELD_PRIVATE (type, i)) | 
|  | accessibility = GCC_CP_ACCESS_PRIVATE; | 
|  | else | 
|  | accessibility = GCC_CP_ACCESS_PUBLIC; | 
|  | instance->convert_type (TYPE_NESTED_TYPES_FIELD_TYPE (type, i), | 
|  | accessibility); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Convert data members defined in TYPE, which should be struct/class/union | 
|  | with gcc_type COMP_TYPE.  */ | 
|  |  | 
|  | static void | 
|  | compile_cplus_convert_struct_or_union_members | 
|  | (compile_cplus_instance *instance, struct type *type, gcc_type comp_type) | 
|  | { | 
|  | for (int i = TYPE_N_BASECLASSES (type); i < type->num_fields (); ++i) | 
|  | { | 
|  | const char *field_name = type->field (i).name (); | 
|  |  | 
|  | if (type->field (i).is_ignored () | 
|  | || type->field (i).is_artificial ()) | 
|  | continue; | 
|  |  | 
|  | /* GDB records unnamed/anonymous fields with empty string names.  */ | 
|  | if (*field_name == '\0') | 
|  | field_name = nullptr; | 
|  |  | 
|  | gcc_type field_type | 
|  | = instance->convert_type (type->field (i).type ()); | 
|  |  | 
|  | if (type->field (i).is_static ()) | 
|  | { | 
|  | CORE_ADDR physaddr; | 
|  |  | 
|  | switch (type->field (i).loc_kind ()) | 
|  | { | 
|  | case FIELD_LOC_KIND_PHYSADDR: | 
|  | { | 
|  | physaddr = type->field (i).loc_physaddr (); | 
|  |  | 
|  | instance->plugin ().build_decl | 
|  | ("field physaddr", field_name, | 
|  | (GCC_CP_SYMBOL_VARIABLE | get_field_access_flag (type, i)), | 
|  | field_type, nullptr, physaddr, nullptr, 0); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case FIELD_LOC_KIND_PHYSNAME: | 
|  | { | 
|  | const char *physname = type->field (i).loc_physname (); | 
|  | struct block_symbol sym | 
|  | = lookup_symbol (physname, instance->block (), | 
|  | SEARCH_VFT, nullptr); | 
|  |  | 
|  | if (sym.symbol == nullptr) | 
|  | { | 
|  | /* We didn't actually find the symbol.  There's little | 
|  | we can do but ignore this member.  */ | 
|  | continue; | 
|  | } | 
|  | const char *filename = sym.symbol->symtab ()->filename; | 
|  | unsigned int line = sym.symbol->line (); | 
|  |  | 
|  | physaddr = sym.symbol->value_address (); | 
|  | instance->plugin ().build_decl | 
|  | ("field physname", field_name, | 
|  | (GCC_CP_SYMBOL_VARIABLE| get_field_access_flag (type, i)), | 
|  | field_type, nullptr, physaddr, filename, line); | 
|  | } | 
|  | break; | 
|  |  | 
|  | default: | 
|  | gdb_assert_not_reached | 
|  | ("unexpected static field location kind"); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | unsigned long bitsize = type->field (i).bitsize (); | 
|  | enum gcc_cp_symbol_kind field_flags = GCC_CP_SYMBOL_FIELD | 
|  | | get_field_access_flag (type, i); | 
|  |  | 
|  | if (bitsize == 0) | 
|  | bitsize = 8 * type->field (i).type ()->length (); | 
|  |  | 
|  | instance->plugin ().build_field | 
|  | (field_name, field_type, field_flags, bitsize, | 
|  | type->field (i).loc_bitpos ()); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Convert a method type to its gcc representation.  */ | 
|  |  | 
|  | static gcc_type | 
|  | compile_cplus_convert_method (compile_cplus_instance *instance, | 
|  | struct type *parent_type, | 
|  | struct type *method_type) | 
|  | { | 
|  | /* Get the actual function type of the method, the corresponding class's | 
|  | type and corresponding qualifier flags.  */ | 
|  | gcc_type func_type = compile_cplus_convert_func (instance, method_type, true); | 
|  | gcc_type class_type = instance->convert_type (parent_type); | 
|  | gcc_cp_qualifiers_flags quals = 0; | 
|  |  | 
|  | if (TYPE_CONST (method_type)) | 
|  | quals |= GCC_CP_QUALIFIER_CONST; | 
|  | if (TYPE_VOLATILE (method_type)) | 
|  | quals |= GCC_CP_QUALIFIER_VOLATILE; | 
|  | if (TYPE_RESTRICT (method_type)) | 
|  | quals |= GCC_CP_QUALIFIER_RESTRICT; | 
|  |  | 
|  | /* Not yet implemented.  */ | 
|  | gcc_cp_ref_qualifiers_flags rquals = GCC_CP_REF_QUAL_NONE; | 
|  |  | 
|  | return instance->plugin ().build_method_type | 
|  | (class_type, func_type, quals.raw (), rquals.raw ()); | 
|  | } | 
|  |  | 
|  | /* Convert a member or method pointer represented by TYPE.  */ | 
|  |  | 
|  | static gcc_type | 
|  | compile_cplus_convert_memberptr (compile_cplus_instance *instance, | 
|  | struct type *type) | 
|  | { | 
|  | struct type *containing_class = TYPE_SELF_TYPE (type); | 
|  |  | 
|  | if (containing_class == nullptr) | 
|  | return GCC_TYPE_NONE; | 
|  |  | 
|  | gcc_type class_type = instance->convert_type (containing_class); | 
|  | gcc_type member_type | 
|  | = instance->convert_type (type->target_type ()); | 
|  |  | 
|  | return instance->plugin ().build_pointer_to_member_type | 
|  | (class_type, member_type); | 
|  | } | 
|  |  | 
|  | /* Convert all methods defined in TYPE, which should be a class/struct/union | 
|  | with gcc_type CLASS_TYPE.  */ | 
|  |  | 
|  | static void | 
|  | compile_cplus_convert_struct_or_union_methods (compile_cplus_instance *instance, | 
|  | struct type *type, | 
|  | gcc_type class_type) | 
|  | { | 
|  | for (int i = 0; i < TYPE_NFN_FIELDS (type); ++i) | 
|  | { | 
|  | struct fn_field *methods = TYPE_FN_FIELDLIST1 (type, i); | 
|  | gdb::unique_xmalloc_ptr<char> overloaded_name | 
|  | = compile_cplus_instance::decl_name (TYPE_FN_FIELDLIST_NAME (type, i)); | 
|  |  | 
|  | /* Loop through the fieldlist, adding decls to the compiler's | 
|  | representation of the class.  */ | 
|  | for (int j = 0; j < TYPE_FN_FIELDLIST_LENGTH (type, i); ++j) | 
|  | { | 
|  | /* Skip artificial methods.  */ | 
|  | if (TYPE_FN_FIELD_ARTIFICIAL (methods, j)) | 
|  | continue; | 
|  |  | 
|  | gcc_cp_symbol_kind_flags sym_kind = GCC_CP_SYMBOL_FUNCTION; | 
|  | gcc_type method_type; | 
|  | struct block_symbol sym | 
|  | = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (methods, j), | 
|  | instance->block (), SEARCH_VFT, nullptr); | 
|  |  | 
|  | if (sym.symbol == nullptr) | 
|  | { | 
|  | if (TYPE_FN_FIELD_VIRTUAL_P (methods, j)) | 
|  | { | 
|  | /* This is beyond hacky, and is really only a workaround for | 
|  | detecting pure virtual methods.  */ | 
|  | method_type = compile_cplus_convert_method | 
|  | (instance, type, TYPE_FN_FIELD_TYPE (methods, j)); | 
|  |  | 
|  | instance->plugin ().build_decl | 
|  | ("pure virtual method", overloaded_name.get (), | 
|  | (sym_kind | 
|  | | get_method_access_flag (type, i, j) | 
|  | | GCC_CP_FLAG_VIRTUAL_FUNCTION | 
|  | | GCC_CP_FLAG_PURE_VIRTUAL_FUNCTION).raw (), | 
|  | method_type, nullptr, 0, nullptr, 0); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | /* This can happen if we have a DW_AT_declaration DIE | 
|  | for the method, but no "definition"-type DIE (with | 
|  | DW_AT_specification referencing the decl DIE), i.e., | 
|  | the compiler has probably optimized the method away. | 
|  |  | 
|  | In this case, all we can hope to do is issue a warning | 
|  | to the user letting him know.  If the user has not actually | 
|  | requested using this method, things should still work.  */ | 
|  | warning (_("Method %s appears to be optimized out.\n" | 
|  | "All references to this method will be undefined."), | 
|  | TYPE_FN_FIELD_PHYSNAME (methods, j)); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | const char *filename = sym.symbol->symtab ()->filename; | 
|  | unsigned int line = sym.symbol->line (); | 
|  | CORE_ADDR address = sym.symbol->value_block()->start (); | 
|  | const char *kind; | 
|  |  | 
|  | if (TYPE_FN_FIELD_STATIC_P (methods, j)) | 
|  | { | 
|  | kind = "static method"; | 
|  | method_type = compile_cplus_convert_func | 
|  | (instance, TYPE_FN_FIELD_TYPE (methods, j), true); | 
|  | } | 
|  | else | 
|  | { | 
|  | kind = "method"; | 
|  | method_type = (compile_cplus_convert_method | 
|  | (instance, type, TYPE_FN_FIELD_TYPE (methods, j))); | 
|  | } | 
|  |  | 
|  | if (TYPE_FN_FIELD_VIRTUAL_P (methods, j)) | 
|  | sym_kind |= GCC_CP_FLAG_VIRTUAL_FUNCTION; | 
|  |  | 
|  | instance->plugin ().build_decl | 
|  | (kind, overloaded_name.get (), | 
|  | (sym_kind | get_method_access_flag (type, i, j)).raw (), | 
|  | method_type, nullptr, address, filename, line); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Convert a struct or union type to its gcc representation.  If this type | 
|  | was defined in another type, NESTED_ACCESS should indicate the | 
|  | accessibility of this type.  */ | 
|  |  | 
|  | static gcc_type | 
|  | compile_cplus_convert_struct_or_union (compile_cplus_instance *instance, | 
|  | struct type *type, | 
|  | enum gcc_cp_symbol_kind nested_access) | 
|  | { | 
|  | const char *filename = nullptr; | 
|  | unsigned int line = 0; | 
|  |  | 
|  | /* Get the decl name of this type.  */ | 
|  | gdb::unique_xmalloc_ptr<char> name | 
|  | = compile_cplus_instance::decl_name (type->name ()); | 
|  |  | 
|  | /* Create a new scope for TYPE.  */ | 
|  | compile_scope scope = instance->new_scope (type->name (), type); | 
|  |  | 
|  | if (scope.nested_type () != GCC_TYPE_NONE) | 
|  | { | 
|  | /* The type requested was actually defined inside another type, | 
|  | such as a nested class definition.  Return that type.  */ | 
|  | return scope.nested_type (); | 
|  | } | 
|  |  | 
|  | /* Push all scopes.  */ | 
|  | instance->enter_scope (std::move (scope)); | 
|  |  | 
|  | /* First we create the resulting type and enter it into our hash | 
|  | table.  This lets recursive types work.  */ | 
|  |  | 
|  | gcc_decl resuld; | 
|  | if (type->code () == TYPE_CODE_STRUCT) | 
|  | { | 
|  | const char *what = type->is_declared_class () ? "class" : "struct"; | 
|  |  | 
|  | resuld = instance->plugin ().build_decl | 
|  | (what, name.get (), (GCC_CP_SYMBOL_CLASS | nested_access | 
|  | | (type->is_declared_class () | 
|  | ? GCC_CP_FLAG_CLASS_NOFLAG | 
|  | : GCC_CP_FLAG_CLASS_IS_STRUCT)), | 
|  | 0, nullptr, 0, filename, line); | 
|  | } | 
|  | else | 
|  | { | 
|  | gdb_assert (type->code () == TYPE_CODE_UNION); | 
|  | resuld = instance->plugin ().build_decl | 
|  | ("union", name.get (), GCC_CP_SYMBOL_UNION | nested_access, | 
|  | 0, nullptr, 0, filename, line); | 
|  | } | 
|  |  | 
|  | gcc_type result; | 
|  | if (type->code () == TYPE_CODE_STRUCT) | 
|  | { | 
|  | int num_baseclasses = TYPE_N_BASECLASSES (type); | 
|  | std::vector<gcc_type> elements (num_baseclasses); | 
|  | std::vector<enum gcc_cp_symbol_kind> flags (num_baseclasses); | 
|  |  | 
|  | struct gcc_vbase_array bases {}; | 
|  | bases.elements = elements.data (); | 
|  | bases.flags = flags.data (); | 
|  | bases.n_elements = num_baseclasses; | 
|  |  | 
|  | for (int i = 0; i < num_baseclasses; ++i) | 
|  | { | 
|  | struct type *base_type = TYPE_BASECLASS (type, i); | 
|  |  | 
|  | bases.flags[i] = (GCC_CP_SYMBOL_BASECLASS | 
|  | | get_field_access_flag (type, i) | 
|  | | (BASETYPE_VIA_VIRTUAL (type, i) | 
|  | ? GCC_CP_FLAG_BASECLASS_VIRTUAL | 
|  | : GCC_CP_FLAG_BASECLASS_NOFLAG)); | 
|  | bases.elements[i] = instance->convert_type (base_type); | 
|  | } | 
|  |  | 
|  | result = instance->plugin ().start_class_type | 
|  | (name.get (), resuld, &bases, filename, line); | 
|  | } | 
|  | else | 
|  | { | 
|  | gdb_assert (type->code () == TYPE_CODE_UNION); | 
|  | result = instance->plugin ().start_class_type | 
|  | (name.get (), resuld, nullptr, filename, line); | 
|  | } | 
|  |  | 
|  | instance->insert_type (type, result); | 
|  |  | 
|  | /* Add definitions.  */ | 
|  | compile_cplus_convert_type_defns (instance, type); | 
|  |  | 
|  | /* Add methods.  */ | 
|  | compile_cplus_convert_struct_or_union_methods (instance, type, result); | 
|  |  | 
|  | /* Add members.  */ | 
|  | compile_cplus_convert_struct_or_union_members (instance, type, result); | 
|  |  | 
|  | /* All finished.  */ | 
|  | instance->plugin ().finish_class_type (name.get (), type->length ()); | 
|  |  | 
|  | /* Pop all scopes.  */ | 
|  | instance->leave_scope (); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* Convert an enum type to its gcc representation.  If this type | 
|  | was defined in another type, NESTED_ACCESS should indicate the | 
|  | accessibility of this type.*/ | 
|  |  | 
|  | static gcc_type | 
|  | compile_cplus_convert_enum (compile_cplus_instance *instance, struct type *type, | 
|  | enum gcc_cp_symbol_kind nested_access) | 
|  | { | 
|  | bool scoped_enum_p = false; | 
|  |  | 
|  | /* Create a new scope for this type.  */ | 
|  | compile_scope scope = instance->new_scope (type->name (), type); | 
|  |  | 
|  | if (scope.nested_type () != GCC_TYPE_NONE) | 
|  | { | 
|  | /* The type requested was actually defined inside another type, | 
|  | such as a nested class definition.  Return that type.  */ | 
|  | return scope.nested_type (); | 
|  | } | 
|  |  | 
|  | gdb::unique_xmalloc_ptr<char> name | 
|  | = compile_cplus_instance::decl_name (type->name ()); | 
|  |  | 
|  | /* Push all scopes.  */ | 
|  | instance->enter_scope (std::move (scope)); | 
|  |  | 
|  | gcc_type int_type | 
|  | = instance->plugin ().get_int_type (type->is_unsigned (), | 
|  | type->length (), nullptr); | 
|  | gcc_type result | 
|  | = instance->plugin ().start_enum_type (name.get (), int_type, | 
|  | GCC_CP_SYMBOL_ENUM | nested_access | 
|  | | (scoped_enum_p | 
|  | ? GCC_CP_FLAG_ENUM_SCOPED | 
|  | : GCC_CP_FLAG_ENUM_NOFLAG), | 
|  | nullptr, 0); | 
|  | for (int i = 0; i < type->num_fields (); ++i) | 
|  | { | 
|  | gdb::unique_xmalloc_ptr<char> fname | 
|  | = compile_cplus_instance::decl_name (type->field (i).name ()); | 
|  |  | 
|  | if (type->field (i).loc_kind () != FIELD_LOC_KIND_ENUMVAL | 
|  | || fname == nullptr) | 
|  | continue; | 
|  |  | 
|  | instance->plugin ().build_enum_constant (result, fname.get (), | 
|  | type->field (i).loc_enumval ()); | 
|  | } | 
|  |  | 
|  | /* Finish enum definition and pop scopes.  */ | 
|  | instance->plugin ().finish_enum_type (result); | 
|  | instance->leave_scope (); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* Convert a function type to its gcc representation.  This function does | 
|  | not deal with function templates.  */ | 
|  |  | 
|  | static gcc_type | 
|  | compile_cplus_convert_func (compile_cplus_instance *instance, | 
|  | struct type *type, bool strip_artificial) | 
|  | { | 
|  | int is_varargs = type->has_varargs (); | 
|  | struct type *target_type = type->target_type (); | 
|  |  | 
|  | /* Functions with no debug info have no return type.  Ideally we'd | 
|  | want to fallback to the type of the cast just before the | 
|  | function, like GDB's built-in expression parser, but we don't | 
|  | have access to that type here.  For now, fallback to int, like | 
|  | GDB's parser used to do.  */ | 
|  | if (target_type == nullptr) | 
|  | { | 
|  | target_type = builtin_type (type->arch ())->builtin_int; | 
|  | warning (_("function has unknown return type; assuming int")); | 
|  | } | 
|  |  | 
|  | /* This approach means we can't make self-referential function | 
|  | types.  Those are impossible in C, though.  */ | 
|  | gcc_type return_type = instance->convert_type (target_type); | 
|  |  | 
|  | std::vector<gcc_type> elements (type->num_fields ()); | 
|  | struct gcc_type_array array = { (int) type->num_fields (), elements.data () }; | 
|  | int artificials = 0; | 
|  | for (int i = 0; i < type->num_fields (); ++i) | 
|  | { | 
|  | if (strip_artificial && type->field (i).is_artificial ()) | 
|  | { | 
|  | --array.n_elements; | 
|  | ++artificials; | 
|  | } | 
|  | else | 
|  | { | 
|  | array.elements[i - artificials] | 
|  | = instance->convert_type (type->field (i).type ()); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* We omit setting the argument types to `void' to be a little flexible | 
|  | with some minsyms like printf (compile-cplus.exp has examples).  */ | 
|  | gcc_type result = instance->plugin ().build_function_type | 
|  | (return_type, &array, is_varargs); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* Convert an integer type to its gcc representation.  */ | 
|  |  | 
|  | static gcc_type | 
|  | compile_cplus_convert_int (compile_cplus_instance *instance, struct type *type) | 
|  | { | 
|  | if (type->has_no_signedness ()) | 
|  | { | 
|  | gdb_assert (type->length () == 1); | 
|  | return instance->plugin ().get_char_type (); | 
|  | } | 
|  |  | 
|  | return instance->plugin ().get_int_type | 
|  | (type->is_unsigned (), type->length (), type->name ()); | 
|  | } | 
|  |  | 
|  | /* Convert a floating-point type to its gcc representation.  */ | 
|  |  | 
|  | static gcc_type | 
|  | compile_cplus_convert_float (compile_cplus_instance *instance, | 
|  | struct type *type) | 
|  | { | 
|  | return instance->plugin ().get_float_type | 
|  | (type->length (), type->name ()); | 
|  | } | 
|  |  | 
|  | /* Convert the 'void' type to its gcc representation.  */ | 
|  |  | 
|  | static gcc_type | 
|  | compile_cplus_convert_void (compile_cplus_instance *instance, struct type *type) | 
|  | { | 
|  | return instance->plugin ().get_void_type (); | 
|  | } | 
|  |  | 
|  | /* Convert a boolean type to its gcc representation.  */ | 
|  |  | 
|  | static gcc_type | 
|  | compile_cplus_convert_bool (compile_cplus_instance *instance, struct type *type) | 
|  | { | 
|  | return instance->plugin ().get_bool_type (); | 
|  | } | 
|  |  | 
|  | /* See description in compile-cplus.h.  */ | 
|  |  | 
|  | gcc_type | 
|  | compile_cplus_instance::convert_qualified_base (gcc_type base, | 
|  | gcc_cp_qualifiers_flags quals) | 
|  | { | 
|  | gcc_type result = base; | 
|  |  | 
|  | if (quals != 0) | 
|  | result = plugin ().build_qualified_type (base, quals.raw ()); | 
|  |  | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* See description in compile-cplus.h.  */ | 
|  |  | 
|  | static gcc_type | 
|  | compile_cplus_convert_qualified (compile_cplus_instance *instance, | 
|  | struct type *type) | 
|  | { | 
|  | struct type *unqual = make_unqualified_type (type); | 
|  | gcc_cp_qualifiers_flags quals = (enum gcc_cp_qualifiers) 0; | 
|  | gcc_type unqual_converted = instance->convert_type (unqual); | 
|  |  | 
|  | if (TYPE_CONST (type)) | 
|  | quals |= GCC_CP_QUALIFIER_CONST; | 
|  | if (TYPE_VOLATILE (type)) | 
|  | quals |= GCC_CP_QUALIFIER_VOLATILE; | 
|  | if (TYPE_RESTRICT (type)) | 
|  | quals |= GCC_CP_QUALIFIER_RESTRICT; | 
|  |  | 
|  | return instance->convert_qualified_base (unqual_converted, quals); | 
|  | } | 
|  |  | 
|  | /* Convert a complex type to its gcc representation.  */ | 
|  |  | 
|  | static gcc_type | 
|  | compile_cplus_convert_complex (compile_cplus_instance *instance, | 
|  | struct type *type) | 
|  | { | 
|  | gcc_type base = instance->convert_type (type->target_type ()); | 
|  |  | 
|  | return instance->plugin ().build_complex_type (base); | 
|  | } | 
|  |  | 
|  | /* Convert a namespace of TYPE.  */ | 
|  |  | 
|  | static gcc_type | 
|  | compile_cplus_convert_namespace (compile_cplus_instance *instance, | 
|  | struct type *type) | 
|  | { | 
|  | compile_scope scope = instance->new_scope (type->name (), type); | 
|  | gdb::unique_xmalloc_ptr<char> name | 
|  | = compile_cplus_instance::decl_name (type->name ()); | 
|  |  | 
|  | /* Push scope.  */ | 
|  | instance->enter_scope (std::move (scope)); | 
|  |  | 
|  | /* Convert this namespace.  */ | 
|  | instance->plugin ().push_namespace (name.get ()); | 
|  | instance->plugin ().pop_binding_level (name.get ()); | 
|  |  | 
|  | /* Pop scope.  */ | 
|  | instance->leave_scope (); | 
|  |  | 
|  | /* Namespaces are non-cacheable types.  */ | 
|  | return GCC_TYPE_NONE; | 
|  | } | 
|  |  | 
|  | /* A helper function which knows how to convert most types from their | 
|  | gdb representation to the corresponding gcc form.  This examines | 
|  | the TYPE and dispatches to the appropriate conversion function.  It | 
|  | returns the gcc type. | 
|  |  | 
|  | If the type was defined in another type, NESTED_ACCESS should indicate the | 
|  | accessibility of this type.  */ | 
|  |  | 
|  | static gcc_type | 
|  | convert_type_cplus_basic (compile_cplus_instance *instance, | 
|  | struct type *type, | 
|  | enum gcc_cp_symbol_kind nested_access) | 
|  | { | 
|  | /* If we are converting a qualified type, first convert the | 
|  | unqualified type and then apply the qualifiers.  */ | 
|  | if ((type->instance_flags () & (TYPE_INSTANCE_FLAG_CONST | 
|  | | TYPE_INSTANCE_FLAG_VOLATILE | 
|  | | TYPE_INSTANCE_FLAG_RESTRICT)) != 0) | 
|  | return compile_cplus_convert_qualified (instance, type); | 
|  |  | 
|  | switch (type->code ()) | 
|  | { | 
|  | case TYPE_CODE_REF: | 
|  | case TYPE_CODE_RVALUE_REF: | 
|  | return compile_cplus_convert_reference (instance, type); | 
|  |  | 
|  | case TYPE_CODE_PTR: | 
|  | return compile_cplus_convert_pointer (instance, type); | 
|  |  | 
|  | case TYPE_CODE_ARRAY: | 
|  | return compile_cplus_convert_array (instance, type); | 
|  |  | 
|  | case TYPE_CODE_STRUCT: | 
|  | case TYPE_CODE_UNION: | 
|  | return | 
|  | compile_cplus_convert_struct_or_union (instance, type, nested_access); | 
|  |  | 
|  | case TYPE_CODE_ENUM: | 
|  | return compile_cplus_convert_enum (instance, type, nested_access); | 
|  |  | 
|  | case TYPE_CODE_FUNC: | 
|  | return compile_cplus_convert_func (instance, type, false); | 
|  |  | 
|  | case TYPE_CODE_METHOD: | 
|  | return | 
|  | compile_cplus_convert_method (instance, TYPE_SELF_TYPE (type), type); | 
|  |  | 
|  | case TYPE_CODE_MEMBERPTR: | 
|  | case TYPE_CODE_METHODPTR: | 
|  | return compile_cplus_convert_memberptr (instance, type); | 
|  | break; | 
|  |  | 
|  | case TYPE_CODE_INT: | 
|  | return compile_cplus_convert_int (instance, type); | 
|  |  | 
|  | case TYPE_CODE_FLT: | 
|  | return compile_cplus_convert_float (instance, type); | 
|  |  | 
|  | case TYPE_CODE_VOID: | 
|  | return compile_cplus_convert_void (instance, type); | 
|  |  | 
|  | case TYPE_CODE_BOOL: | 
|  | return compile_cplus_convert_bool (instance, type); | 
|  |  | 
|  | case TYPE_CODE_COMPLEX: | 
|  | return compile_cplus_convert_complex (instance, type); | 
|  |  | 
|  | case TYPE_CODE_NAMESPACE: | 
|  | return compile_cplus_convert_namespace (instance, type); | 
|  |  | 
|  | case TYPE_CODE_TYPEDEF: | 
|  | return compile_cplus_convert_typedef (instance, type, nested_access); | 
|  |  | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | std::string s = string_printf (_("unhandled TYPE_CODE %d"), | 
|  | type->code ()); | 
|  |  | 
|  | return instance->plugin ().error (s.c_str ()); | 
|  | } | 
|  |  | 
|  | gcc_type | 
|  | compile_cplus_instance::convert_type (struct type *type, | 
|  | enum gcc_cp_symbol_kind nested_access) | 
|  | { | 
|  | /* Check if TYPE has already been converted.  */ | 
|  | gcc_type result; | 
|  | if (get_cached_type (type, &result)) | 
|  | return result; | 
|  |  | 
|  | /* It is the first time this type has been seen -- convert it | 
|  | and cache it, if appropriate..  */ | 
|  | result = convert_type_cplus_basic (this, type, nested_access); | 
|  | if (result != GCC_TYPE_NONE) | 
|  | insert_type (type, result); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | void | 
|  | compile_cplus_instance::gcc_cplus_enter_scope | 
|  | (void *datum, struct gcc_cp_context *gcc_context) | 
|  | { | 
|  | } | 
|  |  | 
|  | void | 
|  | compile_cplus_instance::gcc_cplus_leave_scope | 
|  | (void *datum, struct gcc_cp_context *gcc_context) | 
|  | { | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | /* Plug-in forwards.  */ | 
|  |  | 
|  | /* C++ plug-in wrapper.  */ | 
|  |  | 
|  | /* A result printer for plug-in calls that return a gcc_type or | 
|  | gcc_decl.  */ | 
|  |  | 
|  | static void | 
|  | compile_cplus_debug_output_1 (ULONGEST arg) | 
|  | { | 
|  | gdb_printf (gdb_stdlog, "%s", pulongest (arg)); | 
|  | } | 
|  |  | 
|  | static void | 
|  | compile_cplus_debug_output_1 (const char *arg) | 
|  | { | 
|  | if (arg == nullptr) | 
|  | gdb_puts ("NULL", gdb_stdlog); | 
|  | else | 
|  | gdb_puts (arg, gdb_stdlog); | 
|  | } | 
|  |  | 
|  | static void | 
|  | compile_cplus_debug_output () | 
|  | { | 
|  | } | 
|  |  | 
|  | template <typename T> | 
|  | static void | 
|  | compile_cplus_debug_output_1 (const T *arg) | 
|  | { | 
|  | } | 
|  |  | 
|  | template <typename T, typename... Targs> | 
|  | static void | 
|  | compile_cplus_debug_output (T arg, Targs... Args) | 
|  | { | 
|  | compile_cplus_debug_output_1 (arg); | 
|  | gdb_putc (' ', gdb_stdlog); | 
|  | compile_cplus_debug_output (Args...); | 
|  | } | 
|  |  | 
|  | #define FORWARD(OP,...) m_context->cp_ops->OP(m_context, ##__VA_ARGS__) | 
|  | #define OUTPUT_DEBUG_RESULT(R)			  \ | 
|  | if (debug_compile_cplus_types)		  \ | 
|  | {						  \ | 
|  | gdb_puts (": ", gdb_stdlog);		  \ | 
|  | compile_cplus_debug_output (R);		  \ | 
|  | gdb_putc ('\n', gdb_stdlog);		  \ | 
|  | }						  \ | 
|  |  | 
|  | #define GCC_METHOD0(R, N)			  \ | 
|  | R gcc_cp_plugin::N () const			  \ | 
|  | {						  \ | 
|  | if (debug_compile_cplus_types)		  \ | 
|  | compile_cplus_debug_output (STRINGIFY (N)); \ | 
|  | auto result = FORWARD (N);			  \ | 
|  | OUTPUT_DEBUG_RESULT (result);		  \ | 
|  | return result;				  \ | 
|  | } | 
|  | #define GCC_METHOD1(R, N, A)				\ | 
|  | R gcc_cp_plugin::N (A a) const			\ | 
|  | {							\ | 
|  | if (debug_compile_cplus_types)			\ | 
|  | compile_cplus_debug_output (STRINGIFY (N), a);	\ | 
|  | auto result = FORWARD (N, a);			\ | 
|  | OUTPUT_DEBUG_RESULT (result);			\ | 
|  | return result;					\ | 
|  | } | 
|  | #define GCC_METHOD2(R, N, A, B)				\ | 
|  | R gcc_cp_plugin::N (A a, B b) const			\ | 
|  | {							\ | 
|  | if (debug_compile_cplus_types)			\ | 
|  | compile_cplus_debug_output (STRINGIFY (N), a, b);	\ | 
|  | auto result = FORWARD (N, a, b);			\ | 
|  | OUTPUT_DEBUG_RESULT (result);			\ | 
|  | return result;					\ | 
|  | } | 
|  | #define GCC_METHOD3(R, N, A, B, C) \ | 
|  | R gcc_cp_plugin::N (A a, B b, C c) const			\ | 
|  | {								\ | 
|  | if (debug_compile_cplus_types)				\ | 
|  | compile_cplus_debug_output (STRINGIFY (N), a, b, c);	\ | 
|  | auto result = FORWARD (N, a, b, c);				\ | 
|  | OUTPUT_DEBUG_RESULT (result);				\ | 
|  | return result;						\ | 
|  | } | 
|  | #define GCC_METHOD4(R, N, A, B, C, D)				\ | 
|  | R gcc_cp_plugin::N (A a, B b, C c, D d) const			\ | 
|  | {								\ | 
|  | if (debug_compile_cplus_types)				\ | 
|  | compile_cplus_debug_output (STRINGIFY (N), a, b, c, d);	\ | 
|  | auto result = FORWARD (N, a, b, c, d);			\ | 
|  | OUTPUT_DEBUG_RESULT (result);				\ | 
|  | return result;						\ | 
|  | } | 
|  | #define GCC_METHOD5(R, N, A, B, C, D, E)				\ | 
|  | R gcc_cp_plugin::N (A a, B b, C c, D d, E e) const			\ | 
|  | {									\ | 
|  | if (debug_compile_cplus_types)					\ | 
|  | compile_cplus_debug_output (STRINGIFY (N), a, b, c, d, e);	\ | 
|  | auto result = FORWARD (N, a, b, c, d, e);				\ | 
|  | OUTPUT_DEBUG_RESULT (result);					\ | 
|  | return result;							\ | 
|  | } | 
|  | #define GCC_METHOD7(R, N, A, B, C, D, E, F, G)				\ | 
|  | R gcc_cp_plugin::N (A a, B b, C c, D d, E e, F f, G g) const		\ | 
|  | {									\ | 
|  | if (debug_compile_cplus_types)					\ | 
|  | compile_cplus_debug_output (STRINGIFY (N), a, b, c, d, e, f, g);	\ | 
|  | auto result = FORWARD (N, a, b, c, d, e, f, g);			\ | 
|  | OUTPUT_DEBUG_RESULT (result);					\ | 
|  | return result;							\ | 
|  | } | 
|  |  | 
|  | #include "gcc-cp-fe.def" | 
|  |  | 
|  | #undef GCC_METHOD0 | 
|  | #undef GCC_METHOD1 | 
|  | #undef GCC_METHOD2 | 
|  | #undef GCC_METHOD3 | 
|  | #undef GCC_METHOD4 | 
|  | #undef GCC_METHOD5 | 
|  | #undef GCC_METHOD7 | 
|  | #undef FORWARD | 
|  | #undef OUTPUT_DEBUG_RESULT | 
|  |  | 
|  | gcc_expr | 
|  | gcc_cp_plugin::build_decl (const char *debug_decltype, const char *name, | 
|  | enum gcc_cp_symbol_kind sym_kind, gcc_type sym_type, | 
|  | const char *substitution_name, gcc_address address, | 
|  | const char *filename, unsigned int line_number) | 
|  | { | 
|  | if (debug_compile_cplus_types) | 
|  | gdb_printf (gdb_stdlog, "<%s> ", debug_decltype); | 
|  |  | 
|  | return build_decl (name, sym_kind, sym_type, substitution_name, | 
|  | address, filename, line_number); | 
|  | } | 
|  |  | 
|  | gcc_type | 
|  | gcc_cp_plugin::start_class_type (const char *debug_name, gcc_decl typedecl, | 
|  | const struct gcc_vbase_array *base_classes, | 
|  | const char *filename, unsigned int line_number) | 
|  | { | 
|  | if (debug_compile_cplus_types) | 
|  | gdb_printf (gdb_stdlog, "<%s> ", debug_name); | 
|  |  | 
|  | return start_class_type (typedecl, base_classes, filename, line_number); | 
|  | } | 
|  |  | 
|  | int | 
|  | gcc_cp_plugin::finish_class_type (const char *debug_name, | 
|  | unsigned long size_in_bytes) | 
|  | { | 
|  | if (debug_compile_cplus_types) | 
|  | gdb_printf (gdb_stdlog, "<%s> ", debug_name); | 
|  |  | 
|  | return finish_class_type (size_in_bytes); | 
|  | } | 
|  |  | 
|  | int | 
|  | gcc_cp_plugin::pop_binding_level (const char *debug_name) | 
|  | { | 
|  | if (debug_compile_cplus_types) | 
|  | gdb_printf (gdb_stdlog, "<%s> ", debug_name); | 
|  |  | 
|  | return pop_binding_level (); | 
|  | } | 
|  |  | 
|  | void _initialize_compile_cplus_types (); | 
|  | void | 
|  | _initialize_compile_cplus_types () | 
|  | { | 
|  | add_setshow_boolean_cmd ("compile-cplus-types", no_class, | 
|  | &debug_compile_cplus_types, _("\ | 
|  | Set debugging of C++ compile type conversion."), _("\ | 
|  | Show debugging of C++ compile type conversion."), _("\ | 
|  | When enabled debugging messages are printed during C++ type conversion for\n\ | 
|  | the compile commands."), | 
|  | nullptr, | 
|  | nullptr, | 
|  | &setdebuglist, | 
|  | &showdebuglist); | 
|  |  | 
|  | add_setshow_boolean_cmd ("compile-cplus-scopes", no_class, | 
|  | &debug_compile_cplus_scopes, _("\ | 
|  | Set debugging of C++ compile scopes."), _("\ | 
|  | Show debugging of C++ compile scopes."), _("\ | 
|  | When enabled debugging messages are printed about definition scopes during\n\ | 
|  | C++ type conversion for the compile commands."), | 
|  | nullptr, | 
|  | nullptr, | 
|  | &setdebuglist, | 
|  | &showdebuglist); | 
|  | } |