aboutsummaryrefslogtreecommitdiff
path: root/gdb/compile/compile-cplus-templates.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/compile/compile-cplus-templates.c')
-rw-r--r--gdb/compile/compile-cplus-templates.c1448
1 files changed, 1448 insertions, 0 deletions
diff --git a/gdb/compile/compile-cplus-templates.c b/gdb/compile/compile-cplus-templates.c
new file mode 100644
index 00000000000..4b2bf46baae
--- /dev/null
+++ b/gdb/compile/compile-cplus-templates.c
@@ -0,0 +1,1448 @@
+/* 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 <http://www.gnu.org/licenses/>. */
+
+#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 <algorithm>
+
+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<demangle_parse_info> 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 <parameter list>(argument list), with
+ generic template parameters instead of any instanced type.
+
+ For example, both "void foo<int> (int)" and "void foo<A> (A)" will
+ return "T foo<typename T>(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<demangle_parse_info> 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<demangle_parse_info> 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<parameters> */
+ 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<template_parameter_modifier> &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 <template_parameter_modifier> &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<template_parameter_modifier> 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);
+
+ back_to = make_cleanup (xfree, ret);
+ fprintf_unfiltered (stream, "%s::", ret);
+ do_cleanups (back_to);
+
+ /* 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<template_parameter_modifier> &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<template_parameter_modifier> 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<demangle_parse_info> 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);
+}