From: Keith Seitz Date: Thu, 17 Aug 2017 20:58:01 +0000 (-0700) Subject: Update w/HEAD X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fheads%2Fusers%2Fpmuldoon%2Fc%2B%2Bcompile;p=thirdparty%2Fbinutils-gdb.git Update w/HEAD Problems: gdb/compile/compile.c gdb/cp-support.c gdb/cp-support.h gdb/gdbtypes.h gdb/language.c gdb/linespec.c --- b5f28d7abc02ca509e389fa932d725cf111e4b40 diff --cc gdb/c-lang.c index 3628ebed33d,f86e26ed5f7..a65002cabce --- a/gdb/c-lang.c +++ b/gdb/c-lang.c @@@ -34,12 -34,7 +34,10 @@@ #include "gdb_obstack.h" #include #include "gdbcore.h" +#include "symtab.h" +#include "block.h" +#include "linespec.h" /* for find_toplevel_char */ - extern void _initialize_c_language (void); - /* Given a C string type, STR_TYPE, return the corresponding target character set name. */ diff --cc gdb/compile/compile-cplus-templates.c index 4b2bf46baae,00000000000..b3d07946d47 mode 100644,000000..100644 --- a/gdb/compile/compile-cplus-templates.c +++ b/gdb/compile/compile-cplus-templates.c @@@ -1,1448 -1,0 +1,1446 @@@ +/* Template support for compile. + + Copyright (C) 2016, 2017 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 . */ + +#include "defs.h" +#include "compile-internal.h" +#include "compile-cplus.h" +#include "cp-support.h" +#include "demangle.h" +#include "typeprint.h" +#include "c-lang.h" +#include "gdbcmd.h" + +#include + +using namespace compile; + +/* Modifiers for abstract template parameters when used in template function + declarations, including CV and ref qualifiers and pointer and reference + type modifiers, e.g., const T*. */ + +enum template_parameter_type_modifier +{ + /*/ The abstract parameter type is not qualified at all. */ + PARAMETER_NONE, + + /* The abstract parameter type was declared `const', const T. */ + PARAMETER_CONST, + + /* The abstract parameter type was declared `volatile', volatile T. */ + PARAMETER_VOLATILE, + + /* The abstract parameter type was declared `restrict', restrict T. */ + PARAMETER_RESTRICT, + + /* The abstract parameter type was declared as a pointer, T*. */ + PARAMETER_POINTER, + + /* The abstract parameter type was declared as a reference, T&. */ + PARAMETER_LVALUE_REFERENCE, + + /* The abstract parameter type was declared as rvalue reference, + T&&. */ + PARAMETER_RVALUE_REFERENCE +}; +typedef enum template_parameter_type_modifier template_parameter_modifier; + +/* Forward declarations. */ + +static void print_template_parameter_list + (const struct template_argument_info *arg_info, struct ui_file *stream); + +static void print_template_type (const struct demangle_component *comp, + const struct template_symbol *tsymbol, + struct ui_file *stream); + +static void print_conversion_node (const struct demangle_component *comp, + const struct template_symbol *tsymbol, + struct ui_file *stream); + +static void print_function_template_arglist + (const struct demangle_component *comp, + const struct template_symbol *tsymbol, struct ui_file *stream); + +/* See description in compile-cplus-templates.h. */ + +function_template_defn::function_template_defn + (std::string generic, std::unique_ptr info, + const struct template_symbol *tsymbol, struct type *parent_type, + int fidx, int midx) + : template_defn (compile::decl_name (tsymbol->search_name), generic, + tsymbol->template_arguments->n_arguments), + m_tsymbol (tsymbol), m_parent_type (parent_type), + m_fidx (fidx), m_midx (midx), + m_demangle_info (std::move (info)) +{ +} + +/* Return a string representing the template declaration for TSYMBOL. + All template symbols deriving from the same source declaration should + yield the same string representation. + + This string representation is of the generic form + RETURN_TYPE QUALIFIED_NAME (argument list), with + generic template parameters instead of any instanced type. + + For example, both "void foo (int)" and "void foo (A)" will + return "T foo(T)". */ + +static std::string +function_template_decl (const struct template_symbol *tsymbol, + const struct demangle_parse_info *info) +{ + gdb_assert (info != NULL); + + string_file stream; + struct demangle_component *ret_comp = info->tree; + + if (ret_comp != NULL) + { + if (ret_comp->type == DEMANGLE_COMPONENT_TYPED_NAME) + ret_comp = d_right (ret_comp); + + /* Print out the return type to the stream (if there is one). */ + if (d_left (ret_comp) != NULL) + { + if (tsymbol->template_return_index == -1) + { + struct type *return_type + = TYPE_TARGET_TYPE (SYMBOL_TYPE (&tsymbol->base)); + + c_print_type (return_type, "", &stream, -1, 0, + &type_print_raw_options); + } + else + print_template_type (d_left (ret_comp), tsymbol, &stream); + stream.putc (' '); + } + + /* Print the name of the template. */ + if (tsymbol->conversion_operator_index != -1) + print_conversion_node (info->tree, tsymbol, &stream); + else + { + stream.puts (tsymbol->search_name); + if (tsymbol->search_name[strlen (tsymbol->search_name) - 1] == '<') + stream.putc (' '); + } + + /* Print out template (generic) arguments. */ + stream.putc ('<'); + print_template_parameter_list (tsymbol->template_arguments, &stream); + stream.putc ('>'); + + /* Print out function arguments. */ + stream.putc ('('); + print_function_template_arglist (ret_comp, tsymbol, &stream); + stream.putc (')'); + } + + return std::move (stream.string ()); +} + +/* Compute the generic used by the given function template + definition. */ + +static std::string +compute_function_template_generic (struct template_symbol *tsymbol, + const demangle_parse_info *info) +{ + gdb_assert (info->tree != NULL); + + /* Ensure template arguments have been decoded. */ + cp_decode_template_type_indices (tsymbol, info); + + /* Output the template generic. */ + return function_template_decl (tsymbol, info); +} + +/* See description in compile-cplus.h. */ + +void +compile_cplus_instance::maybe_define_new_function_template + (const struct symbol *sym, struct type *parent_type, int f_idx, + int m_idx) + +{ + if (sym != NULL && SYMBOL_IS_CPLUS_TEMPLATE_FUNCTION (sym)) + { + struct template_symbol *tsym = (struct template_symbol *) sym; + + if (tsym->linkage_name == NULL) + return; + + std::unique_ptr info + = cp_mangled_name_to_comp (tsym->linkage_name, DMGL_ANSI | DMGL_PARAMS); + + std::string generic + = compute_function_template_generic (tsym, info.get ()); + function_template_defn_map_t::iterator pos + = m_function_template_defns->find (generic); + + function_template_defn *defn; + + if (pos == m_function_template_defns->end ()) + { + /* Create the new template definition and insert it into + the cache. */ + defn = new function_template_defn (generic, std::move (info), tsym, + parent_type, f_idx, m_idx); + m_function_template_defns->insert (std::make_pair (generic, defn)); + } + else + { + /* Or use the existing definition. */ + defn = pos->second.get (); + } + + /* Loop over the template arguments, noting any default values. */ + for (unsigned int i = 0; i < tsym->template_arguments->n_arguments; ++i) + { + if (defn->default_argument (i) == NULL + && tsym->template_arguments->default_arguments[i] != NULL) + { + struct symbol *def + = tsym->template_arguments->default_arguments[i]; + defn->set_default_argument (i, def); + + /* We don't want to define them here because it could start + emitting template definitions before we're even done + collecting the default values. [Easy to demonstrate if the + default value is a class.] */ + } + } + } +} + +/* See description in compile-cplus-templates.h. */ + +void +compile::define_templates (compile_cplus_instance *instance, + VEC (block_symbol_d) *symbols) +{ + int i; + struct block_symbol *elt; + + /* We need to do this in two passes. On the first pass, we collect + the list of "unique" template definitions we need (using the template + hashing function) and we collect the list of default values for the + template (which can only be done after we have a list of all templates). + On the second pass, we iterate over the list of templates we need to + define, enumerating those definitions (with default values) to the + compiler plug-in. */ + + for (i = 0; VEC_iterate (block_symbol_d, symbols, i, elt); ++i) + instance->maybe_define_new_function_template (elt->symbol, NULL, -1, -1); + + /* From here on out, we MUST have all types declared or defined, + otherwise GCC will give us "definition of TYPE in template parameter + list." */ + /* Create any new template definitions we encountered. */ + instance->emit_function_template_decls (); + instance->emit_class_template_decls (); +} + +/* See description in compile-cplus-templates.h. */ + +function_template_defn * +compile_cplus_instance::find_function_template_defn + (struct template_symbol *tsym) +{ + if (tsym->linkage_name == NULL) + return NULL; + + std::unique_ptr info + = cp_mangled_name_to_comp (tsym->linkage_name, DMGL_ANSI | DMGL_PARAMS); + + std::string generic = compute_function_template_generic (tsym, info.get ()); + function_template_defn_map_t::iterator pos + = m_function_template_defns->find (generic); + + if (pos != m_function_template_defns->end ()) + return pos->second.get (); + + return NULL; +} + +/* Compute the generic used by the given function template + definition. */ + +static std::string +compute_class_template_generic (std::string name, struct type *type) +{ + string_file stream; + + /* Format: class|struct|union namespaces::NAME */ + if (TYPE_CODE (type) == TYPE_CODE_STRUCT) + { + if (TYPE_DECLARED_CLASS (type)) + stream.puts ("class "); + else + stream.puts ("struct "); + } + else + { + gdb_assert (TYPE_CODE (type) == TYPE_CODE_UNION); + stream.puts ("union "); + } + + /* Print all namespaces. Note that we do not push the last + scope_component -- that's the actual type we are defining. */ + + compile::compile_scope scope = type_name_to_scope (TYPE_NAME (type), NULL); + std::for_each (scope.begin (), scope.end () - 1, [&] (const auto &comp) + { + gdb_assert (TYPE_CODE (SYMBOL_TYPE (comp.bsymbol.symbol)) + == TYPE_CODE_NAMESPACE); + + if (comp.name != CP_ANONYMOUS_NAMESPACE_STR) + stream.printf ("%s::", comp.name.c_str ()); + }); + + stream.printf ("%s<", name.c_str ()); + print_template_parameter_list (TYPE_TEMPLATE_ARGUMENT_INFO (type), &stream); + stream.putc ('>'); + + return std::move (stream.string ()); +} + +/* See description in compile-cplus-templates.h. */ + +class_template_defn * +compile_cplus_instance::find_class_template_defn (struct type *type) +{ + /* There are no template definitions associated with anonymous types or + types without template arguments. */ + if (TYPE_NAME (type) == NULL || TYPE_TEMPLATE_ARGUMENT_INFO (type) == NULL) + return NULL; + + char *name = decl_name (TYPE_NAME (type)); + struct cleanup *back_to = make_cleanup (xfree, name); + + std::string generic (compute_class_template_generic (name, type)); + class_template_defn_map_t::iterator pos + = m_class_template_defns->find (generic); + if (pos != m_class_template_defns->end ()) + { + /* A template generic for this was already defined. */ + do_cleanups (back_to); + return pos->second.get (); + } + + /* No generic for this template was found. */ + do_cleanups (back_to); + return NULL; +} + +/* A class providing printing for a single parameter type modifier. */ + +class one_template_type_modifier_printer +{ +public: + /* Construct a new printer which outputs to STREAM. */ + explicit one_template_type_modifier_printer (struct ui_file *stream) + : m_stream (stream) + { + } + + /* Unary function to output the modifier. */ + void operator() (template_parameter_modifier modifier) + { + switch (modifier) + { + case PARAMETER_NONE: + break; + + case PARAMETER_CONST: + fputs_unfiltered (" const", m_stream); + break; + + case PARAMETER_VOLATILE: + fputs_unfiltered (" volatile", m_stream); + break; + + case PARAMETER_RESTRICT: + fputs_unfiltered (" restrict", m_stream); + break; + + case PARAMETER_POINTER: + fputs_unfiltered ("*", m_stream); + break; + + case PARAMETER_LVALUE_REFERENCE: + fputc_unfiltered ('&', m_stream); + break; + + case PARAMETER_RVALUE_REFERENCE: + fputs_unfiltered ("&&", m_stream); + + default: + gdb_assert_not_reached ("unknown template parameter modifier"); + } + } + +private: + /* The stream to which to print the modifier. */ + struct ui_file *m_stream; +}; + +/* Print the type modifiers MODIFIERS to STREAM. */ + +static void +print_template_type_modifiers + (const std::vector &modifiers, + struct ui_file *stream) +{ + one_template_type_modifier_printer printer (stream); + + for (auto &item : modifiers) + printer (item); +} + +/* Get the abstract template type described by COMP, returning any + type modifiers in MODIFIERS. */ + +static const struct demangle_component * +get_template_type (const struct demangle_component *comp, + std::vector &modifiers) +{ + bool done = 0; + + /* This is probably a little too simplistic... */ + while (!done) + { + switch (comp->type) + { + case DEMANGLE_COMPONENT_POINTER: + modifiers.insert (modifiers.begin (), PARAMETER_POINTER); + comp = d_left (comp); + break; + + case DEMANGLE_COMPONENT_REFERENCE: + modifiers.insert (modifiers.begin (), PARAMETER_LVALUE_REFERENCE); + comp = d_left (comp); + break; + + case DEMANGLE_COMPONENT_CONST: + modifiers.insert (modifiers.begin (), PARAMETER_CONST); + comp = d_left (comp); + break; + + case DEMANGLE_COMPONENT_RESTRICT: + modifiers.insert (modifiers.begin (), PARAMETER_RESTRICT); + comp = d_left (comp); + break; + + case DEMANGLE_COMPONENT_VOLATILE: + modifiers.insert (modifiers.begin (), PARAMETER_VOLATILE); + comp = d_left (comp); + break; + + case DEMANGLE_COMPONENT_TEMPLATE_PARAM: + default: + done = true; + break; + } + } + + return comp; +} + +/* Print the generic parameter type given by COMP from the template symbol + TSYMBOL to STREAM. This function prints the generic template parameter + type, not the instanced type, e.g., "const T&". */ + +static void +print_template_type (const struct demangle_component *comp, + const struct template_symbol *tsymbol, + struct ui_file *stream) +{ + /* Get the template parameter and modifiers. */ + std::vector modifiers; + comp = get_template_type (comp, modifiers); + + /* This had better be a template parameter! */ + gdb_assert (comp->type == DEMANGLE_COMPONENT_TEMPLATE_PARAM); + + /* Using the parameter's index, get the parameter's symbol and print it + with modifiers. */ + long idx = comp->u.s_number.number; + struct symbol *sym = tsymbol->template_arguments->arguments[idx]; + + fputs_unfiltered (SYMBOL_NATURAL_NAME (sym), stream); + print_template_type_modifiers (modifiers, stream); +} + +/* Print the template parameter list of a type/symbol to STREAM. */ + +static void +print_template_parameter_list (const struct template_argument_info *arg_info, + struct ui_file *stream) +{ + for (int i = 0; i < arg_info->n_arguments; ++i) + { + if (i != 0) + fputs_unfiltered (", ", stream); + + switch (arg_info->argument_kinds[i]) + { + case type_parameter: + fprintf_unfiltered (stream, "typename %s", + SYMBOL_NATURAL_NAME (arg_info->arguments[i])); + break; + + case value_parameter: + c_print_type (SYMBOL_TYPE (arg_info->arguments[i]), "", stream, -1, 0, + &type_print_raw_options); + fprintf_unfiltered (stream, " %s", + SYMBOL_NATURAL_NAME (arg_info->arguments[i])); + break; + + case template_parameter: + break; + + case variadic_parameter: + break; + + default: + gdb_assert_not_reached ("unexpected template parameter kind"); + } + } +} + +/* Print out the generic template function argument list of the template + symbol TSYMBOL to STREAM. COMP represents the FUNCTION_TYPE of the + demangle tree for TSYMBOL. */ + +static void +print_function_template_arglist (const struct demangle_component *comp, + const struct template_symbol *tsymbol, + struct ui_file *stream) +{ + int i, artificials; + struct type *ttype = SYMBOL_TYPE (&tsymbol->base); + + for (i = 0, artificials = 0; i < TYPE_NFIELDS (ttype); ++i) + { + int tidx; + + if (TYPE_FIELD_ARTIFICIAL (ttype, i)) + { + ++artificials; + continue; + } + + if ((i - artificials) > 0) + fputs_unfiltered (", ", stream); + + tidx = tsymbol->template_argument_indices[i - artificials]; + if (tidx == -1) + { + /* A concrete type was used to define this argument. */ + c_print_type (TYPE_FIELD_TYPE (ttype, i), "", stream, -1, 0, + &type_print_raw_options); + continue; + } + + /* The type of this argument was specified by a template parameter, + possibly with added CV and ref qualifiers. */ + + /* Get the next ARGLIST node and print it. */ + comp = d_right (comp); + gdb_assert (comp != NULL); + gdb_assert (comp->type == DEMANGLE_COMPONENT_ARGLIST); + print_template_type (d_left (comp), tsymbol, stream); + } +} + +/* Print the conversion operator in COMP for the template symbol TSYMBOL + to STREAM. */ + +static void +print_conversion_node (const struct demangle_component *comp, + const struct template_symbol *tsymbol, + struct ui_file *stream) +{ + while (1) + { + switch (comp->type) + { + case DEMANGLE_COMPONENT_TYPED_NAME: + case DEMANGLE_COMPONENT_TEMPLATE: + comp = d_left (comp); + break; + + case DEMANGLE_COMPONENT_QUAL_NAME: + { + /* Print out the qualified name. */ - struct cleanup *back_to; - char *ret = cp_comp_to_string (d_left (comp), 10); ++ gdb::unique_xmalloc_ptr ret ++ = cp_comp_to_string (d_left (comp), 10); + - back_to = make_cleanup (xfree, ret); - fprintf_unfiltered (stream, "%s::", ret); - do_cleanups (back_to); ++ fprintf_unfiltered (stream, "%s::", ret.get ()); + + /* Follow the rest of the name. */ + comp = d_right (comp); + } + break; + + case DEMANGLE_COMPONENT_CONVERSION: + fputs_unfiltered ("operator ", stream); + print_template_type (d_left (comp), tsymbol, stream); + return; + + default: + return; + } + } +} + +/* See description in compile-cplus-templates.h. */ + +void +compile_cplus_instance::maybe_define_new_class_template + (struct type *type, const char *decl_name) +{ + if (TYPE_N_TEMPLATE_ARGUMENTS (type) == 0 || decl_name == NULL) + return; + + std::string generic (compute_class_template_generic (decl_name, type)); + class_template_defn_map_t::iterator pos + = m_class_template_defns->find (generic); + + class_template_defn *defn = NULL; + + if (pos == m_class_template_defns->end ()) + { + /* Insert the new template definition into the cache. */ + defn = new class_template_defn (decl_name, generic, type); + m_class_template_defns->insert (std::make_pair (generic, defn)); + } + else + { + /* If there is an existing definition, use that definition. */ + defn = pos->second.get (); + } + + /* Loop over the template arguments, noting any default values. */ + for (unsigned int i = 0; i < TYPE_N_TEMPLATE_ARGUMENTS (type); ++i) + { + if (defn->default_argument (i) == NULL + && TYPE_TEMPLATE_DEFAULT_ARGUMENT (type, i) != NULL) + { + defn->set_default_argument (i, + TYPE_TEMPLATE_DEFAULT_ARGUMENT (type, i)); + + /* We don't want to define them here because it could start + emitting template definitions before we're even done + collecting the default values. [Easy to demonstrate if the + default value is a class.] */ + } + } +} + +/* See description in compile-cplus-templates.h. */ + +void +compile::scan_type_for_function_templates (compile_cplus_instance *instance, + struct type *type) +{ + for (int i = 0; i < TYPE_NFN_FIELDS (type); ++i) + { + struct fn_field *methods = TYPE_FN_FIELDLIST1 (type, i); + + for (int j = 0; j < TYPE_FN_FIELDLIST_LENGTH (type, i); ++j) + { + struct block_symbol sym + = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (methods, j), + instance->block (), VAR_DOMAIN, NULL); + + instance->maybe_define_new_function_template (sym.symbol, type, i, j); + } + } +} + +/* Helper function to define and return the `value' of TYPE of the template + parameter ARG in compile INSTANCE. */ + +static gcc_expr +get_template_argument_value (compile_cplus_instance *instance, + gcc_type type, struct symbol *arg) +{ + gcc_expr value = 0; + + switch (SYMBOL_CLASS (arg)) + { + /* !!keiths: More (incomplete) fun. */ + case LOC_CONST: + value = instance->build_literal_expr (type, SYMBOL_VALUE (arg)); + break; + + case LOC_COMPUTED: + { + struct value *val; + struct frame_info *frame = NULL; + + /* !!keiths: I don't think this can happen, but I've been + wrong before. */ + if (symbol_read_needs_frame (arg)) + { + frame = get_selected_frame (NULL); + gdb_assert (frame != NULL); + } + val = read_var_value (arg, instance->block (), frame); + + /* !!keiths: This is a hack, but I don't want to write + yet another linkage name translation function. At least + not just yet. */ + value = instance->build_literal_expr (type, value_address (val)); + } + break; + + default: + gdb_assert_not_reached + ("unhandled template value argument symbol class"); + } + + return value; +} + +/* Enumerate the template parameters of the generic form of the template + definition DEFN into DEST. */ + +static void +define_template_parameters_generic + (compile_cplus_instance *instance, template_defn *defn, + const struct template_argument_info *arg_info, + const char *filename, int line) +{ + for (int i = 0; i < arg_info->n_arguments; ++i) + { + const char *id = SYMBOL_NATURAL_NAME (arg_info->arguments[i]); + + switch (arg_info->argument_kinds[i]) + { + case type_parameter: + { + /* GDB doesn't support variadic templates yet. */ + int is_pack = 0; + gcc_type default_type = 0; + + if (defn->default_argument (i) != NULL) + { + struct type *type = SYMBOL_TYPE (defn->default_argument (i)); + + /* This type must previously have been converted, + or GCC will error with "definition of TYPE inside + template parameter list." */ + default_type = instance->convert_type (type); + } + + gcc_type abstract_type + = instance->build_type_template_parameter (id, is_pack, + default_type, filename, line); + defn->set_parameter_abstract_type (i, abstract_type); + } + break; + + case value_parameter: + { + gcc_expr default_value = 0; + struct type *ptype = SYMBOL_TYPE (arg_info->arguments[i]); + + /* Get the argument's type. This type must also have been + previously defined (or declared) to prevent errors. */ + gcc_type abstract_type = instance->convert_type (ptype); + defn->set_parameter_abstract_type (i, abstract_type); + + if (defn->default_argument (i) != NULL) + { + default_value + = get_template_argument_value (instance, abstract_type, + defn->default_argument (i)); + } + + instance->build_value_template_parameter (abstract_type, id, + default_value, + filename, line); + } + break; + + case template_parameter: + /* GDB doesn't support template-template parameters. */ + break; + + case variadic_parameter: + /* GDB doesn't support variadic templates. */ + break; + + default: + gdb_assert_not_reached ("unexpected template parameter kind"); + } + } +} + +/* Populate the `kinds' member of DEST from ARG_INFO. */ + +static void +enumerate_template_parameter_kinds + (compile_cplus_instance *instance, struct gcc_cp_template_args *dest, + const struct template_argument_info *arg_info) +{ + for (int i = 0; i < arg_info->n_arguments; ++i) + { + switch (arg_info->argument_kinds[i]) + { + case type_parameter: + dest->kinds[i] = GCC_CP_TPARG_CLASS; + break; + case value_parameter: + dest->kinds[i] = GCC_CP_TPARG_VALUE; + break; + case template_parameter: + dest->kinds[i] = GCC_CP_TPARG_TEMPL; + break; + case variadic_parameter: + dest->kinds[i] = GCC_CP_TPARG_PACK; + break; + default: + gdb_assert_not_reached ("unexpected template parameter kind"); + } + } +} + +/* See description in compile-cplus-templates.h. */ + +void +compile_cplus_instance::enumerate_template_arguments + (struct gcc_cp_template_args *dest, const template_defn *defn, + const struct template_argument_info *arg_info) +{ + /* Fill in the parameter kinds. */ + enumerate_template_parameter_kinds (this, dest, arg_info); + + /* Loop over the arguments, converting parameter types, values, etc + into DEST. */ + for (int i = 0; i < arg_info->n_arguments; ++i) + { + switch (arg_info->argument_kinds[i]) + { + case type_parameter: + { + gcc_type type + = convert_type (SYMBOL_TYPE (arg_info->arguments[i])); + + dest->elements[i].type = type; + } + break; + + case value_parameter: + { + gcc_type type = defn->parameter_abstract_type (i); + + dest->elements[i].value + = get_template_argument_value (this, type, + arg_info->arguments[i]); + } + break; + + case template_parameter: + break; + + case variadic_parameter: + break; + + default: + gdb_assert_not_reached ("unexpected template parameter kind"); + } + } +} + +/* Define the type for all default template parameters for the template + arguments given by ARGUMENTS. */ + +static void +define_default_template_parameter_types + (compile_cplus_instance *instance, template_defn *defn, + const struct template_argument_info *arg_info) +{ + for (int i = 0; i < arg_info->n_arguments; ++i) + { + if (defn->default_argument (i) != NULL) + { + switch (arg_info->argument_kinds[i]) + { + case type_parameter: + case value_parameter: + instance->convert_type (SYMBOL_TYPE (defn->default_argument (i))); + break; + + case template_parameter: + case variadic_parameter: + default: + gdb_assert (_("unexpected template parameter kind")); + } + } + } +} + +/* A class to add type modifiers to a given compiler type. */ + +class template_parameter_type_modifier_adder +{ +public: + template_parameter_type_modifier_adder + (compile_cplus_instance *instance, gcc_type the_type) + : m_instance (instance), m_flags (0), m_type (the_type) + { + } + + void operator() (template_parameter_modifier modifier) + { + switch (modifier) + { + case PARAMETER_NONE: + break; + + case PARAMETER_CONST: + m_flags |= GCC_CP_QUALIFIER_CONST; + break; + + case PARAMETER_VOLATILE: + m_flags |= GCC_CP_QUALIFIER_VOLATILE; + break; + + case PARAMETER_RESTRICT: + m_flags |= GCC_CP_QUALIFIER_RESTRICT; + break; + + case PARAMETER_POINTER: + m_type = convert_qualified_base (m_instance, m_type, m_flags); + m_type = convert_pointer_base (m_instance, m_type); + m_flags = (enum gcc_cp_qualifiers) 0; + break; + + case PARAMETER_LVALUE_REFERENCE: + m_type = convert_qualified_base (m_instance, m_type, m_flags); + m_type = convert_pointer_base (m_instance, m_type); + m_flags = (enum gcc_cp_qualifiers) 0; + break; + + case PARAMETER_RVALUE_REFERENCE: + m_type = convert_qualified_base (m_instance, m_type, m_flags); + m_type = convert_reference_base (m_instance, m_type); + m_flags = (enum gcc_cp_qualifiers) 0; + break; + + default: + gdb_assert_not_reached ("unknown template parameter modifier"); + } + } + + /* Returns the modified type. */ + + gcc_type type () const + { + return m_type; + } + +private: + /* The compiler instance into which to define the new type(s). */ + compile_cplus_instance *m_instance; + + /* The qualifier flags. */ + gcc_cp_qualifiers_flags m_flags; + + /* The type we are modifying. */ + gcc_type m_type; +}; + +/* Add the modifiers given by MODIFIERS to TYPE. */ + +static gcc_type +add_template_type_modifiers + (compile_cplus_instance *instance, gcc_type type, + const std::vector &modifiers) +{ + template_parameter_type_modifier_adder adder (instance, type); + + for (auto &item : modifiers) + adder (item); + return adder.type (); +} + +/* Add the type modifiers described in COMP to BASE_TYPE. */ + +static gcc_type +add_type_modifiers (compile_cplus_instance *instance, + gcc_type base_type, + const struct demangle_component *comp) +{ + std::vector modifiers; + + get_template_type (comp, modifiers); + + gcc_type result + = add_template_type_modifiers (instance, base_type, modifiers); + + return result; +} + +/* A struct to define (to the plug-in) and fill-in the + function template definition based on the template instance in SLOT. + CALL_DATA should be the compiler instance to use. */ + +class function_template_definer +{ + public: + + function_template_definer (compile_cplus_instance *instance) + : m_instance (instance) + { + } + + void operator() (function_template_defn *defn) + { + if (defn->defined ()) + { + /* This template has already been defined. Keep looking for more + undefined templates. */ + return; + } + + /* Ensure this is one-time operation. */ + defn->set_defined (true); + + struct fn_field *method_field; + struct type *method_type; + const struct template_symbol *tsym = defn->template_symbol (); + if (defn->parent_type () != NULL + && defn->fidx () != -1 && defn->midx () != -1) + { + struct fn_field *methods + = TYPE_FN_FIELDLIST1 (defn->parent_type (), defn->fidx ()); + + method_field = &methods[defn->midx ()]; + method_type = method_field->type; + } + else + { + method_field = NULL; + method_type = SYMBOL_TYPE (&tsym->base); + } + + bool ignore; + char *special_name = NULL; + const char *id = defn->decl_name (); + gdb_assert (!strchr (id, ':')); + const char *name = maybe_canonicalize_special_function (id, + method_field, + method_type, + &special_name, + &ignore); + + /* Ignore any "ignore" -- we need the template defined even if + this specific instance shouldn't emit a template. */ + struct cleanup *back_to = make_cleanup (null_cleanup, NULL); + + if (special_name != NULL) + { + make_cleanup (xfree, special_name); + name = special_name; + } + + gcc_cp_symbol_kind_flags sym_kind = GCC_CP_SYMBOL_FUNCTION; + + if (name != id) + sym_kind |= GCC_CP_FLAG_SPECIAL_FUNCTION; + + /* Define any default value types. */ + define_default_template_parameter_types (m_instance, defn, + tsym->template_arguments); + + /* Assess the processing context. */ + gcc_type result; + compile_scope scope + = m_instance->new_scope (SYMBOL_NATURAL_NAME (&tsym->base), + SYMBOL_TYPE (&tsym->base)); + + if (scope.nested_type () != GCC_TYPE_NONE) + { + do_cleanups (back_to); + /* new_scope returned the type of the actual template instance from + which we're constructing the template definition. It is already + defined. */ + return; + } + + /* Start the new template declaration. */ + m_instance->enter_scope (scope); + m_instance->start_template_decl (defn->generic ().c_str ()); + + /* Get the parameters' generic kinds and types. */ + define_template_parameters_generic (m_instance, defn, + tsym->template_arguments, + symbol_symtab (&tsym->base)->filename, + SYMBOL_LINE (&tsym->base)); + + /* Find the function node describing this template function. */ + gdb_assert (defn->demangle_info ()->tree->type + == DEMANGLE_COMPONENT_TYPED_NAME); + struct demangle_component *comp = d_right (defn->demangle_info ()->tree); + + gdb_assert (comp->type == DEMANGLE_COMPONENT_FUNCTION_TYPE); + + /* The return type is either a concrete type (TYPE_TARGET_TYPE) + or a template parameter. */ + gcc_type return_type; + + if (tsym->template_return_index != -1) + { + gcc_type param_type + = defn->parameter_abstract_type (tsym->template_return_index); + + return_type + = add_type_modifiers (m_instance, param_type, d_left (comp)); + } + else if (tsym->conversion_operator_index != -1) + { + bool done = false; + gcc_type param_type + = defn->parameter_abstract_type (tsym->conversion_operator_index); + + /* Conversion operators do not have a return type or arguments, + so we need to use the CONVERSION node in the left/name sub-tree + of the demangle tree. */ + + comp = d_left (defn->demangle_info ()->tree); + while (!done) + { + switch (comp->type) + { + case DEMANGLE_COMPONENT_TEMPLATE: + comp = d_left (comp); + break; + + case DEMANGLE_COMPONENT_QUAL_NAME: + comp = d_right (comp); + break; + + case DEMANGLE_COMPONENT_CONVERSION: + default: + done = true; + break; + } + } + + /* We had better have found a CONVERSION node if + tsym->conversion_operator_index was set! */ + gdb_assert (comp->type == DEMANGLE_COMPONENT_CONVERSION); + return_type = add_type_modifiers (m_instance, param_type, + d_left (comp)); + } + else + { + struct type *temp = TYPE_TARGET_TYPE (SYMBOL_TYPE (&tsym->base)); + + return_type = m_instance->convert_type (temp); + } + + /* Get the parameters' definitions, and put them into ARRAY. */ + struct type *templ_type = SYMBOL_TYPE (&tsym->base); + int is_varargs = is_varargs_p (templ_type); + struct gcc_type_array array; + + array.n_elements = TYPE_NFIELDS (templ_type); + array.elements = XNEWVEC (gcc_type, TYPE_NFIELDS (templ_type)); + make_cleanup (xfree, array.elements); + + int artificials = 0; + + /* d_right (info->tree) is FUNCTION_TYPE (assert above). */ + comp = d_right (d_right (defn->demangle_info ()->tree)); + gdb_assert (comp != NULL && comp->type == DEMANGLE_COMPONENT_ARGLIST); + + for (int i = 0; i < TYPE_NFIELDS (templ_type); ++i) + { + if (TYPE_FIELD_ARTIFICIAL (templ_type, i)) + { + --array.n_elements; + ++artificials; + } + else + { + int tidx = tsym->template_argument_indices[i - artificials]; + struct type *arg_type = TYPE_FIELD_TYPE (templ_type, i); + + if (tidx == -1) + { + /* The parameter's type is a concrete type. */ + array.elements[i - artificials] + = m_instance->convert_type (arg_type); + } + else + { + /* The parameter's type is a template parameter. */ + gcc_type result = defn->parameter_abstract_type (tidx); + + array.elements[i - artificials] + = add_type_modifiers (m_instance, result, d_left (comp)); + } + + /* Move to the next ARGLIST node. */ + comp = d_right (comp); + } + } + + gcc_type func_type = m_instance->build_function_type (return_type, &array, + is_varargs); + + /* If we have a method, create its type and set additional symbol flags + for the compiler. */ + if (defn->parent_type () != NULL + && defn->fidx () != -1 && defn->midx () != -1) + { + gcc_type class_type; + struct fn_field *methods + = TYPE_FN_FIELDLIST1 (defn->parent_type (), defn->fidx ()); + + /* Get the defining class's type. This should already be in the + cache. */ + class_type = m_instance->convert_type (defn->parent_type ()); + + /* Add any virtuality flags. */ + if (TYPE_FN_FIELD_VIRTUAL_P (methods, defn->midx ())) + { + sym_kind |= GCC_CP_FLAG_VIRTUAL_FUNCTION; + + /* Unfortunate to have to do a symbol lookup, but this is the only + way to know if we have a pure virtual method. */ + struct block_symbol sym + = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (methods, defn->midx ()), + m_instance->block (), VAR_DOMAIN, NULL); + if (sym.symbol == NULL) + { + /* !!keiths: The pure virtual hack. See + ccp_convert_struct_or_union_methods for more. */ + sym_kind |= GCC_CP_FLAG_PURE_VIRTUAL_FUNCTION; + } + } + + /* Add access flags. */ + sym_kind |= get_method_access_flag (defn->parent_type (), + defn->fidx (), defn->midx ()); + + /* Create the method type. */ + if (!TYPE_FN_FIELD_STATIC_P (methods, defn->midx ())) + { + gcc_cp_qualifiers_flags quals; + gcc_cp_ref_qualifiers_flags rquals; + + quals = (enum gcc_cp_qualifiers) 0; /* !!keiths FIXME */ + rquals = GCC_CP_REF_QUAL_NONE; /* !!keiths FIXME */ + func_type + = m_instance->build_method_type (class_type, func_type, quals, + rquals); + } + } + + /* Finally, define the new generic template declaration. */ + gcc_decl decl + = m_instance->build_decl ("function template", name, sym_kind, + func_type, 0, 0, + symbol_symtab (&(tsym->base))->filename, + SYMBOL_LINE (&(tsym->base))); + defn->set_decl (decl); + + m_instance->leave_scope (); + do_cleanups (back_to); + } + + private: + + /* The compiler instance to use. */ + compile_cplus_instance *m_instance; +}; + +/* See description in compile-cplus-templates.h. */ + +void +compile_cplus_instance::emit_function_template_decls () +{ + function_template_definer definer (this); + + for (auto &item : *m_function_template_defns) + definer (item.second.get ()); +} + +/* A class to define and fill-in class template definitions. */ + +class class_template_definer +{ + public: + + class_template_definer (compile_cplus_instance *instance) + : m_instance (instance) + { + } + + void operator() (class_template_defn *defn) + { + if (defn->defined ()) + { + /* This template has already been defined. Keep looking for more + undefined templates. */ + return; + } + + /* Make sure this is only done once! */ + defn->set_defined (true); + + /* Define any default value types. */ + const struct template_argument_info *arg_info + = TYPE_TEMPLATE_ARGUMENT_INFO (defn->type ()); + + define_default_template_parameter_types (m_instance, defn, arg_info); + + /* Create/push new scope. */ + compile_scope scope + = m_instance->new_scope (TYPE_NAME (defn->type ()), defn->type ()); + + if (scope.nested_type () != GCC_TYPE_NONE) + { + /* new_processing_context returned the type of the actual template + instance from which we're constructing the template definition. + It is already defined. */ + return; + } + m_instance->enter_scope (scope); + + /* Start a new template list for this template. */ + m_instance->start_template_decl (defn->generic ().c_str ()); + + /* Get the parameters' generic kinds and types. */ + define_template_parameters_generic (m_instance, defn, arg_info, + /* filename */ NULL, /* + !!keiths FIXME */ + /* line */ 0 + /* !!keiths FIXME */ + ); + + + /* Define the new generic template declaration. */ + if (TYPE_CODE (defn->type ()) == TYPE_CODE_STRUCT) + { + gcc_decl decl + = m_instance->build_decl ("class template", defn->decl_name (), + GCC_CP_SYMBOL_CLASS /* | nested_access? */ + | (TYPE_DECLARED_CLASS (defn->type ()) + ? GCC_CP_FLAG_CLASS_NOFLAG + : GCC_CP_FLAG_CLASS_IS_STRUCT), + 0, NULL, 0, /*filename*/ NULL, /*line*/ 0); + + defn->set_decl (decl); + } + else + { + gdb_assert (TYPE_CODE (defn->type ()) == TYPE_CODE_UNION); + gcc_decl decl + = m_instance->build_decl ("union template", defn->decl_name (), + GCC_CP_SYMBOL_UNION /* | nested_access? */, + 0, NULL, 0, /*fileanme*/NULL, /*line*/0); + + defn->set_decl (decl); + } + + m_instance->leave_scope (); + } + + private: + + /* The compiler instance to use. */ + compile_cplus_instance *m_instance; +}; + +/* See description in compile-cplus-templates.h. */ + +void +compile_cplus_instance::emit_class_template_decls () +{ + class_template_definer definer (this); + + for (auto &item : *m_class_template_defns) + definer (item.second.get ()); +} + +/* A command to test function_template_decl. */ + +static void +print_template_defn_command (char *arg, int from_tty) +{ + + char *demangled_name + = gdb_demangle (arg, DMGL_ANSI | DMGL_PARAMS | DMGL_RET_DROP); + + if (demangled_name == NULL) + { + fprintf_filtered (gdb_stderr, _("could not demangle \"%s\"\n"), arg); + return; + } + + struct cleanup *back_to = make_cleanup (xfree, demangled_name); + struct block_symbol symbol + = lookup_symbol (demangled_name, NULL, VAR_DOMAIN, NULL); + + if (symbol.symbol == NULL) + { + fprintf_filtered (gdb_stderr, _("could not find symbol for \"%s\"\n"), + arg); + do_cleanups (back_to); + return; + } + + if (!SYMBOL_IS_CPLUS_TEMPLATE_FUNCTION (symbol.symbol)) + { + fprintf_filtered (gdb_stderr, _("symbol \"%s\" does not represent a" + " template function\n"), arg); + do_cleanups (back_to); + return; + } + + struct template_symbol *tsymbol = (struct template_symbol *) symbol.symbol; + + cp_decode_template_type_indices (tsymbol, NULL); + + std::unique_ptr info + = cp_mangled_name_to_comp (arg, DMGL_ANSI | DMGL_PARAMS); + std::string str = function_template_decl (tsymbol, info.get ()); + + fprintf_filtered (gdb_stdout, "%s\n", str.c_str ()); + do_cleanups (back_to); +} + +void _initialize_compile_cplus_templates (); + +void +_initialize_compile_cplus_templates () +{ + add_cmd ("tdef", class_maintenance, print_template_defn_command, + _("Print the template generic for the given linkage name."), + &maint_cplus_cmd_list); +} diff --cc gdb/compile/compile.c index 74ffa64432b,bca7b57ea2e..7c8fe15c678 --- a/gdb/compile/compile.c +++ b/gdb/compile/compile.c @@@ -451,22 -426,11 +455,12 @@@ get_args (const compile::compile_instan static void cleanup_compile_instance (void *arg) { - struct compile_instance *inst = (struct compile_instance *) arg; + compile::compile_instance *inst + = static_cast (arg); - inst->destroy (inst); + delete inst; } - /* A cleanup function to unlink a file. */ - - static void - cleanup_unlink_file (void *arg) - { - const char *filename = (const char *) arg; - - unlink (filename); - } - /* A helper function suitable for use as the "print_callback" in the compiler object. */ @@@ -484,8 -448,8 +478,8 @@@ static compile_file_name compile_to_object (struct command_line *cmd, const char *cmd_string, enum compile_i_scope_types scope) { - struct compile_instance *compiler; + compile::compile_instance *compiler; - struct cleanup *cleanup, *inner_cleanup; + struct cleanup *cleanup; const struct block *expr_block; CORE_ADDR trash_pc, expr_pc; int argc; @@@ -569,12 -519,10 +563,12 @@@ /* Set compiler command-line arguments. */ get_args (compiler, gdbarch, &argc, &argv); - make_cleanup_freeargv (argv); + gdb_argv argv_holder (argv); - error_message = compiler->fe->ops->set_arguments (compiler->fe, triplet_rx, - argc, argv); + if (compiler->version ()>= GCC_FE_VERSION_1) + error_message = compiler->set_arguments (argc, argv); + else + error_message = compiler->set_arguments (triplet_rx, argc, argv); if (error_message != NULL) { make_cleanup (xfree, error_message); diff --cc gdb/cp-support.c index 26af2bc1013,8bcbe657a4e..cc5c5e71859 --- a/gdb/cp-support.c +++ b/gdb/cp-support.c @@@ -816,53 -832,9 +825,52 @@@ cp_func_name (const char *full_name if (ret_comp != NULL) ret = cp_comp_to_string (ret_comp, 10); - return ret; + return ret.release (); } +/* See description in cp-support.h. */ + +char * +cp_strip_template_parameters (const char *linkage_or_phys_name) +{ + /* We do not turn the linkage name into demangle components since we cannot + walk the tree in any usable way when dealing with conversion operators. + Instead we use a heuristic approach that works for all cases. */ + char *stripped = NULL; + const char *name; + + char *demangled_name = gdb_demangle (linkage_or_phys_name, DMGL_ANSI); + if (demangled_name != NULL) + name = demangled_name; + else + name = linkage_or_phys_name; + + /* Only attempt to strip this if it looks like a template. */ + if (strchr (name, '<') != NULL && strchr (name, '>') != NULL) + { + const char *p; + size_t len = strlen (name) - 1; + + /* This is evil, but since we cannot use demangler trees, we have + no choice but to do textual searches. It is simply easiest to + do this backwards. */ + + /* Since we are searching backwards, we need only find the opening + '<' from the end of the string (at the "top level"). */ + p = find_toplevel_char_r (name, len, '<'); + if (p != NULL) + { + /* Remove any trailing whitespace. */ + while (p > name && (ISSPACE (*(p - 1)))) + --p; + stripped = savestring (name, p - name); + } + } + + xfree (demangled_name); + return stripped; +} + /* DEMANGLED_NAME is the name of a function, including parameters and (optionally) a return type. Return the name of the function without parameters or return type, or NULL if we can not parse the name. */ diff --cc gdb/cp-support.h index 85d6461eef6,9210165cd14..1a4dd776d3a --- a/gdb/cp-support.h +++ b/gdb/cp-support.h @@@ -152,19 -150,8 +160,19 @@@ struct type *cp_find_type_baseclass_by_ extern std::unique_ptr cp_demangled_name_to_comp (const char *demangled_name, const char **errmsg); +/* Convert a mangled name to a demangle_component tree. OPTIONS will be + passed to the demangler. */ + +extern std::unique_ptr + cp_mangled_name_to_comp (const char *mangled_name, int options); + +/* Convenience macros to move through the demangle tree. */ + +#define d_left(dc) (dc)->u.s_binary.left +#define d_right(dc) (dc)->u.s_binary.right + - extern char *cp_comp_to_string (struct demangle_component *result, - int estimated_len); + extern gdb::unique_xmalloc_ptr cp_comp_to_string + (struct demangle_component *result, int estimated_len); extern void cp_merge_demangle_parse_infos (struct demangle_parse_info *, struct demangle_component *, diff --cc gdb/gdbtypes.h index a38c2dc4955,d2018a81080..60b67700814 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@@ -855,14 -835,8 +848,9 @@@ struct fn_fiel unsigned int is_const:1; unsigned int is_volatile:1; ++ unsigned int is_public:1; unsigned int is_private:1; unsigned int is_protected:1; - unsigned int is_public:1; - unsigned int is_abstract:1; - unsigned int is_static:1; - unsigned int is_final:1; - unsigned int is_synchronized:1; - unsigned int is_native:1; unsigned int is_artificial:1; /* * A stub method only has some fields valid (but they are enough @@@ -874,18 -848,9 +862,19 @@@ unsigned int is_constructor : 1; + /* * True if this function is a destructor, false otherwise. */ + + unsigned int is_destructor : 1; + + /* * True if this function is aliased to an existing fn_field, + false otherwise. These functions should be skipped during symbol + lookups or type printing. */ ++ + unsigned int is_alias : 1; + /* * Unused. */ - unsigned int dummy:1; - unsigned int dummy:9; ++ unsigned int dummy:6; /* * Index into that baseclass's virtual function table, minus 2; else if static: VOFFSET_STATIC; else: 0. */ @@@ -1473,17 -1392,9 +1462,12 @@@ extern void set_type_vptr_basetype (str #define TYPE_FN_FIELD_VOLATILE(thisfn, n) ((thisfn)[n].is_volatile) #define TYPE_FN_FIELD_PRIVATE(thisfn, n) ((thisfn)[n].is_private) #define TYPE_FN_FIELD_PROTECTED(thisfn, n) ((thisfn)[n].is_protected) +#define TYPE_FN_FIELD_PUBLIC(thisfn, n) ((thisfn)[n].is_public) - #define TYPE_FN_FIELD_STATIC(thisfn, n) ((thisfn)[n].is_static) - #define TYPE_FN_FIELD_FINAL(thisfn, n) ((thisfn)[n].is_final) - #define TYPE_FN_FIELD_SYNCHRONIZED(thisfn, n) ((thisfn)[n].is_synchronized) - #define TYPE_FN_FIELD_NATIVE(thisfn, n) ((thisfn)[n].is_native) #define TYPE_FN_FIELD_ARTIFICIAL(thisfn, n) ((thisfn)[n].is_artificial) - #define TYPE_FN_FIELD_ABSTRACT(thisfn, n) ((thisfn)[n].is_abstract) #define TYPE_FN_FIELD_STUB(thisfn, n) ((thisfn)[n].is_stub) #define TYPE_FN_FIELD_CONSTRUCTOR(thisfn, n) ((thisfn)[n].is_constructor) +#define TYPE_FN_FIELD_DESTRUCTOR(thisfn, n) ((thisfn)[n].is_destructor) +#define TYPE_FN_FIELD_ALIAS(thisfn, n) ((thisfn)[n].is_alias) #define TYPE_FN_FIELD_FCONTEXT(thisfn, n) ((thisfn)[n].fcontext) #define TYPE_FN_FIELD_VOFFSET(thisfn, n) ((thisfn)[n].voffset-2) #define TYPE_FN_FIELD_VIRTUAL_P(thisfn, n) ((thisfn)[n].voffset > 1) diff --cc gdb/go-lang.c index f38e8454a50,60bb3c55472..9448f2c88fb --- a/gdb/go-lang.c +++ b/gdb/go-lang.c @@@ -606,9 -606,8 +606,9 @@@ extern const struct language_defn go_la default_pass_by_reference, c_get_string, c_watch_location_expression, - NULL, + NULL, /* la_get_symbol_name_cmp */ iterate_over_symbols, + default_compute_string_hash, &default_varobj_ops, NULL, NULL, diff --cc gdb/language.c index 844ed7ed6c5,073039e3266..2cce56be548 --- a/gdb/language.c +++ b/gdb/language.c @@@ -44,7 -44,7 +44,8 @@@ #include "cp-support.h" #include "frame.h" #include "c-lang.h" +#include "dictionary.h" /* for dict_hash */ + #include extern void _initialize_language (void); diff --cc gdb/linespec.c index 807770662ea,136cb6553fc..cd440bf2896 --- a/gdb/linespec.c +++ b/gdb/linespec.c @@@ -285,11 -348,11 +340,12 @@@ static struct symtabs_and_lines decode_ static VEC (symtab_ptr) *symtabs_from_filename (const char *, struct program_space *pspace); -static VEC (symbolp) *find_label_symbols (struct linespec_state *self, - VEC (symbolp) *function_symbols, - VEC (symbolp) **label_funcs_ret, - const char *name, - bool completion_mode = false); +static VEC (block_symbol_d) *find_label_symbols + (struct linespec_state *self, + VEC (block_symbol_d) *function_symbols, + VEC (block_symbol_d) **label_funcs_ret, - const char *name); ++ const char *name, ++ bool completion_mode = false); static void find_linespec_symbols (struct linespec_state *self, VEC (symtab_ptr) *file_symtabs, @@@ -1989,18 -2404,21 +2301,22 @@@ convert_linespec_to_sals (struct linesp return sals; } - /* Convert the explicit location EXPLICIT_LOC into SaLs. */ + /* Build RESULT from the explicit location components SOURCE_FILENAME, + FUNCTION_NAME, LABEL_NAME and LINE_OFFSET. */ - static struct symtabs_and_lines - convert_explicit_location_to_sals (struct linespec_state *self, - linespec_p result, - const struct explicit_location *explicit_loc) + static void + convert_explicit_location_to_linespec (struct linespec_state *self, + linespec_p result, + const char *source_filename, + const char *function_name, + const char *label_name, + struct line_offset line_offset) { - VEC (symbolp) *symbols, *labels; + VEC (block_symbol_d) *labels; + VEC (block_symbol_d) *symbols; VEC (bound_minimal_symbol_d) *minimal_symbols; - if (explicit_loc->source_filename != NULL) + if (source_filename != NULL) { TRY { @@@ -2388,6 -2855,344 +2753,344 @@@ linespec_lex_to_end (char **stringp do_cleanups (cleanup); } + /* See linespec.h. */ + + void + linespec_complete_function (completion_tracker &tracker, + const char *function, + const char *source_filename) + { + complete_symbol_mode mode = complete_symbol_mode::LINESPEC; + + if (source_filename != NULL) + { + collect_file_symbol_completion_matches (tracker, mode, + function, function, + source_filename); + } + else + collect_symbol_completion_matches (tracker, mode, function, function); + } + + /* Helper for complete_linespec to simplify it. SOURCE_FILENAME is + only meaningful if COMPONENT is FUNCTION. */ + + static void + complete_linespec_component (linespec_parser *parser, + completion_tracker &tracker, + const char *text, + linespec_complete_what component, + const char *source_filename) + { + if (component == linespec_complete_what::KEYWORD) + { + complete_on_enum (tracker, linespec_keywords, text, text); + } + else if (component == linespec_complete_what::EXPRESSION) + { + const char *word + = advance_to_expression_complete_word_point (tracker, text); + complete_expression (tracker, text, word); + } + else if (component == linespec_complete_what::FUNCTION) + { + completion_list fn_list; + + linespec_complete_function (tracker, text, source_filename); + if (source_filename == NULL) + { + /* Haven't seen a source component, like in "b + file.c:function[TAB]". Maybe this wasn't a function, but + a filename instead, like "b file.[TAB]". */ + fn_list = complete_source_filenames (text); + } + + /* If we only have a single filename completion, append a ':' for + the user, since that's the only thing that can usefully follow + the filename. */ + if (fn_list.size () == 1 && !tracker.have_completions ()) + { + char *fn = fn_list[0].release (); + + /* If we also need to append a quote char, it needs to be + appended before the ':'. Append it now, and make ':' the + new "quote" char. */ + if (tracker.quote_char ()) + { + char quote_char_str[2] = { tracker.quote_char () }; + + fn = reconcat (fn, fn, quote_char_str, (char *) NULL); + tracker.set_quote_char (':'); + } + else + fn = reconcat (fn, fn, ":", (char *) NULL); + fn_list[0].reset (fn); + + /* Tell readline to skip appending a space. */ + tracker.set_suppress_append_ws (true); + } + tracker.add_completions (std::move (fn_list)); + } + } + + /* Helper for linespec_complete_label. Find labels that match + LABEL_NAME in the function symbols listed in the PARSER, and add + them to the tracker. */ + + static void + complete_label (completion_tracker &tracker, + linespec_parser *parser, + const char *label_name) + { - VEC (symbolp) *label_function_symbols = NULL; - VEC (symbolp) *labels ++ VEC (block_symbol_d) *label_function_symbols = NULL; ++ VEC (block_symbol_d) *labels + = find_label_symbols (PARSER_STATE (parser), + PARSER_RESULT (parser)->function_symbols, + &label_function_symbols, + label_name, true); + - symbol *label; ++ struct block_symbol *label; + for (int ix = 0; - VEC_iterate (symbolp, labels, ix, label); ++ix) ++ VEC_iterate (block_symbol_d, labels, ix, label); ++ix) + { - char *match = xstrdup (SYMBOL_SEARCH_NAME (label)); ++ char *match = xstrdup (SYMBOL_SEARCH_NAME (label->symbol)); + tracker.add_completion (gdb::unique_xmalloc_ptr (match)); + } - VEC_free (symbolp, labels); ++ VEC_free (block_symbol_d, labels); + } + + /* See linespec.h. */ + + void + linespec_complete_label (completion_tracker &tracker, + const struct language_defn *language, + const char *source_filename, + const char *function_name, + const char *label_name) + { + linespec_parser parser; + struct cleanup *cleanup; + + linespec_parser_new (&parser, 0, language, NULL, NULL, 0, NULL); + cleanup = make_cleanup (linespec_parser_delete, &parser); + + line_offset unknown_offset = { 0, LINE_OFFSET_UNKNOWN }; + + TRY + { + convert_explicit_location_to_linespec (PARSER_STATE (&parser), + PARSER_RESULT (&parser), + source_filename, + function_name, + NULL, unknown_offset); + } + CATCH (ex, RETURN_MASK_ERROR) + { + do_cleanups (cleanup); + return; + } + END_CATCH + + complete_label (tracker, &parser, label_name); + + do_cleanups (cleanup); + } + + /* See description in linespec.h. */ + + void + linespec_complete (completion_tracker &tracker, const char *text) + { + linespec_parser parser; + struct cleanup *cleanup; + const char *orig = text; + + linespec_parser_new (&parser, 0, current_language, NULL, NULL, 0, NULL); + cleanup = make_cleanup (linespec_parser_delete, &parser); + parser.lexer.saved_arg = text; + PARSER_STREAM (&parser) = text; + + parser.completion_tracker = &tracker; + PARSER_STATE (&parser)->is_linespec = 1; + + /* Parse as much as possible. parser.completion_word will hold + furthest completion point we managed to parse to. */ + TRY + { + parse_linespec (&parser, text); + } + CATCH (except, RETURN_MASK_ERROR) + { + } + END_CATCH + + if (parser.completion_quote_char != '\0' + && parser.completion_quote_end != NULL + && parser.completion_quote_end[1] == '\0') + { + /* If completing a quoted string with the cursor right at + terminating quote char, complete the completion word without + interpretation, so that readline advances the cursor one + whitespace past the quote, even if there's no match. This + makes these cases behave the same: + + before: "b function()" + after: "b function() " + + before: "b 'function()'" + after: "b 'function()' " + + and trusts the user in this case: + + before: "b 'not_loaded_function_yet()'" + after: "b 'not_loaded_function_yet()' " + */ + parser.complete_what = linespec_complete_what::NOTHING; + parser.completion_quote_char = '\0'; + + gdb::unique_xmalloc_ptr text_copy + (xstrdup (parser.completion_word)); + tracker.add_completion (std::move (text_copy)); + } + + tracker.set_quote_char (parser.completion_quote_char); + + if (parser.complete_what == linespec_complete_what::LABEL) + { + parser.complete_what = linespec_complete_what::NOTHING; + + const char *func_name = PARSER_EXPLICIT (&parser)->function_name; + - VEC (symbolp) *function_symbols; ++ VEC (block_symbol_d) *function_symbols; + VEC (bound_minimal_symbol_d) *minimal_symbols; + find_linespec_symbols (PARSER_STATE (&parser), + PARSER_RESULT (&parser)->file_symtabs, + func_name, + &function_symbols, &minimal_symbols); + + PARSER_RESULT (&parser)->function_symbols = function_symbols; + PARSER_RESULT (&parser)->minimal_symbols = minimal_symbols; + + complete_label (tracker, &parser, parser.completion_word); + } + else if (parser.complete_what == linespec_complete_what::FUNCTION) + { + /* While parsing/lexing, we didn't know whether the completion + word completes to a unique function/source name already or + not. + + E.g.: + "b function() " + may need to complete either to: + "b function() const" + or to: + "b function() if/thread/task" + + Or, this: + "b foo t" + may need to complete either to: + "b foo template_fun()" + with "foo" being the template function's return type, or to: + "b foo thread/task" + + Or, this: + "b file" + may need to complete either to a source file name: + "b file.c" + or this, also a filename, but a unique completion: + "b file.c:" + or to a function name: + "b file_function" + + Address that by completing assuming source or function, and + seeing if we find a completion that matches exactly the + completion word. If so, then it must be a function (see note + below) and we advance the completion word to the end of input + and switch to KEYWORD completion mode. + + Note: if we find a unique completion for a source filename, + then it won't match the completion word, because the LCD will + contain a trailing ':'. And if we're completing at or after + the ':', then complete_linespec_component won't try to + complete on source filenames. */ + + const char *text = parser.completion_word; + const char *word = parser.completion_word; + + complete_linespec_component (&parser, tracker, + parser.completion_word, + linespec_complete_what::FUNCTION, + PARSER_EXPLICIT (&parser)->source_filename); + + parser.complete_what = linespec_complete_what::NOTHING; + + if (tracker.quote_char ()) + { + /* The function/file name was not close-quoted, so this + can't be a keyword. Note: complete_linespec_component + may have swapped the original quote char for ':' when we + get here, but that still indicates the same. */ + } + else if (!tracker.have_completions ()) + { + size_t key_start; + size_t wordlen = strlen (parser.completion_word); + + key_start + = string_find_incomplete_keyword_at_end (linespec_keywords, + parser.completion_word, + wordlen); + + if (key_start != -1 + || (wordlen > 0 + && parser.completion_word[wordlen - 1] == ' ')) + { + parser.completion_word += key_start; + parser.complete_what = linespec_complete_what::KEYWORD; + } + } + else if (tracker.completes_to_completion_word (word)) + { + /* Skip the function and complete on keywords. */ + parser.completion_word += strlen (word); + parser.complete_what = linespec_complete_what::KEYWORD; + tracker.discard_completions (); + } + } + + tracker.advance_custom_word_point_by (parser.completion_word - orig); + + complete_linespec_component (&parser, tracker, + parser.completion_word, + parser.complete_what, + PARSER_EXPLICIT (&parser)->source_filename); + + /* If we're past the "filename:function:label:offset" linespec, and + didn't find any match, then assume the user might want to create + a pending breakpoint anyway and offer the keyword + completions. */ + if (!parser.completion_quote_char + && (parser.complete_what == linespec_complete_what::FUNCTION + || parser.complete_what == linespec_complete_what::LABEL + || parser.complete_what == linespec_complete_what::NOTHING) + && !tracker.have_completions ()) + { + const char *end + = parser.completion_word + strlen (parser.completion_word); + + if (end > orig && end[-1] == ' ') + { + tracker.advance_custom_word_point_by (end - parser.completion_word); + + complete_linespec_component (&parser, tracker, end, + linespec_complete_what::KEYWORD, + NULL); + } + } + + do_cleanups (cleanup); + } + /* A helper function for decode_line_full and decode_line_1 to turn LOCATION into symtabs_and_lines. */ @@@ -3374,24 -4108,72 +4077,79 @@@ find_linespec_symbols (struct linespec_ } } - /* Return all labels named NAME in FUNCTION_SYMBOLS. Return the - actual function symbol in which the label was found in LABEL_FUNC_RET. */ + /* Helper for find_label_symbols. Find all labels that match name + NAME in BLOCK. Return all labels that match in FUNCTION_SYMBOLS. + Return the actual function symbol in which the label was found in + LABEL_FUNC_RET. If COMPLETION_MODE is true, then NAME is + interpreted as a label name prefix. Otherwise, only a label named + exactly NAME match. */ + + static void + find_label_symbols_in_block (const struct block *block, + const char *name, struct symbol *fn_sym, + bool completion_mode, - VEC (symbolp) **result, - VEC (symbolp) **label_funcs_ret) ++ VEC (block_symbol_d) **result, ++ VEC (block_symbol_d) **label_funcs_ret) + { + if (completion_mode) + { + struct block_iterator iter; + struct symbol *sym; + size_t name_len = strlen (name); + + int (*cmp) (const char *, const char *, size_t); + cmp = case_sensitivity == case_sensitive_on ? strncmp : strncasecmp; + + ALL_BLOCK_SYMBOLS (block, iter, sym) + { + if (symbol_matches_domain (SYMBOL_LANGUAGE (sym), + SYMBOL_DOMAIN (sym), LABEL_DOMAIN) + && cmp (SYMBOL_SEARCH_NAME (sym), name, name_len) == 0) + { - VEC_safe_push (symbolp, *result, sym); - VEC_safe_push (symbolp, *label_funcs_ret, fn_sym); ++ struct block_symbol label_bsym = {sym, block}; ++ struct block_symbol fn_bsym = {fn_sym, block}; ++ ++ VEC_safe_push (block_symbol_d, *result, &label_bsym); ++ VEC_safe_push (block_symbol_d, *label_funcs_ret, &fn_bsym); + } + } + } + else + { - struct symbol *sym = lookup_symbol (name, block, LABEL_DOMAIN, 0).symbol; ++ struct block_symbol label_sym ++ = lookup_symbol (name, block, LABEL_DOMAIN, 0); + - if (sym != NULL) ++ if (label_sym.symbol != NULL) + { - VEC_safe_push (symbolp, *result, sym); - VEC_safe_push (symbolp, *label_funcs_ret, fn_sym); ++ struct block_symbol fn_bsym = {fn_sym, block}; ++ ++ VEC_safe_push (block_symbol_d, *result, &label_sym); ++ VEC_safe_push (block_symbol_d, *label_funcs_ret, &fn_bsym); + } + } + } + + /* Return all labels that match name NAME in FUNCTION_SYMBOLS. Return + the actual function symbol in which the label was found in + LABEL_FUNC_RET. If COMPLETION_MODE is true, then NAME is + interpreted as a label name prefix. Otherwise, only labels named + exactly NAME match. */ -static VEC (symbolp) * +static VEC (block_symbol_d) * find_label_symbols (struct linespec_state *self, - VEC (symbolp) *function_symbols, - VEC (symbolp) **label_funcs_ret, const char *name, + VEC (block_symbol_d) *function_symbols, - VEC (block_symbol_d) **label_funcs_ret, const char *name) ++ VEC (block_symbol_d) **label_funcs_ret, const char *name, + bool completion_mode) { int ix; const struct block *block; - - struct symbol *sym; + struct symbol *fn_sym; - VEC (symbolp) *result = NULL; + VEC (block_symbol_d) *result = NULL; if (function_symbols == NULL) { - struct block_symbol block_sym; + struct block_symbol fn_block_sym; + set_current_program_space (self->program_space); block = get_current_search_block (); @@@ -3414,23 -4190,14 +4166,18 @@@ } else { + struct block_symbol *elt; + for (ix = 0; - VEC_iterate (symbolp, function_symbols, ix, fn_sym); ++ix) + VEC_iterate (block_symbol_d, function_symbols, ix, elt); ++ix) { - struct symbol *fn_sym = elt->symbol; - struct block_symbol block_sym; ++ fn_sym = elt->symbol; + set_current_program_space (SYMTAB_PSPACE (symbol_symtab (fn_sym))); block = SYMBOL_BLOCK_VALUE (fn_sym); - block_sym = lookup_symbol (name, block, LABEL_DOMAIN, 0); - if (block_sym.symbol != NULL) - { - VEC_safe_push (block_symbol_d, result, &block_sym); - VEC_safe_push (block_symbol_d, *label_funcs_ret, elt); - } + find_label_symbols_in_block (block, name, fn_sym, completion_mode, + &result, label_funcs_ret); } } diff --cc gdb/utils.c index c110ef4c6c1,96ae709fb23..c00bfd4fbf1 --- a/gdb/utils.c +++ b/gdb/utils.c @@@ -66,6 -66,6 +66,7 @@@ #include "interps.h" #include "gdb_regex.h" #include "job-control.h" ++#include "cp-support.h" #if !HAVE_DECL_MALLOC extern PTR malloc (); /* ARI: PTR */ @@@ -3339,98 -3277,6 +3278,139 @@@ strip_leading_path_elements (const cha return p; } +/* See description in utils.h. */ + +const char * +find_toplevel_char (const char *s, char c) +{ + int quoted = 0; /* zero if we're not in quotes; + '"' if we're in a double-quoted string; + '\'' if we're in a single-quoted string. */ + int depth = 0; /* Number of unclosed parens we've seen. */ + const char *scan; + + for (scan = s; *scan; scan++) + { + if (quoted) + { + if (*scan == quoted) + quoted = 0; + else if (*scan == '\\' && *(scan + 1)) + scan++; + } + else if (*scan == c && ! quoted && depth == 0) + return scan; + else if (*scan == '"' || *scan == '\'') + quoted = *scan; + else if (*scan == '(' || *scan == '<') + depth++; + else if ((*scan == ')' || *scan == '>') && depth > 0) + depth--; ++ else if (*scan == 'o' && !quoted && depth == 0) ++ { ++ /* Handle C++ operator names. */ ++ if (strncmp (scan, CP_OPERATOR_STR, CP_OPERATOR_LEN) == 0) ++ { ++ scan += CP_OPERATOR_LEN; ++ if (*scan == c) ++ return scan; ++ while (isspace (*scan)) ++ { ++ ++scan; ++ if (*scan == c) ++ return scan; ++ } ++ if (*scan == '\0') ++ break; ++ ++ switch (*scan) ++ { ++ /* Skip over one less than the appropriate number of ++ characters: the for loop will skip over the last ++ one. */ ++ case '<': ++ if (scan[1] == '<') ++ { ++ scan++; ++ if (*scan == c) ++ return scan; ++ } ++ break; ++ case '>': ++ if (scan[1] == '>') ++ { ++ scan++; ++ if (*scan == c) ++ return scan; ++ } ++ break; ++ } ++ } ++ } + } + + return 0; +} + +/* See description in utils.h. */ + +const char * +find_toplevel_char_r (const char *s, size_t len, char c) +{ + int quoted = 0; + int depth = 0; + const char *scan; + + for (scan = s + len; scan >= s; --scan) + { + if (quoted) + { + if (*scan == quoted) + quoted = 0; + } + else if (*scan == ')' || *scan == '>') + ++depth; + else if ((*scan == '(' || *scan == '<') && depth > 0) + --depth; + + if (*scan == c && !quoted && depth == 0) + return scan; + else if ((*scan == '"' || *scan == '\'') + && scan > s && *(scan - 1) != '\\') + quoted = *scan; + } + + return NULL; +} + +/* See description in utils.h. */ + +const char * +find_toplevel_string (const char *haystack, const char *needle) +{ + const char *s = haystack; + + do + { + s = find_toplevel_char (s, *needle); + + if (s != NULL) + { + /* Found first char in HAYSTACK; check rest of string. */ + if (startswith (s, needle)) + return s; + + /* Didn't find it; loop over HAYSTACK, looking for the next + instance of the first character of NEEDLE. */ + ++s; + } + } + while (s != NULL && *s != '\0'); + + /* NEEDLE was not found in HAYSTACK. */ + return NULL; +} + /* Provide a prototype to silence -Wmissing-prototypes. */ extern initialize_file_ftype _initialize_utils;