From: Keith Seitz Date: Wed, 8 Feb 2017 22:43:57 +0000 (-0800) Subject: Update with 'origin/master'. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=588e429077dfcd18f9bb42a13a3687ef890fd01d;p=thirdparty%2Fbinutils-gdb.git Update with 'origin/master'. Problems: gdb/c-exp.y gdb/compile/compile-c-support.c gdb/compile/compile-c-symbols.c gdb/compile/compile-internal.h gdb/compile/compile-loc2c.c gdb/dwarf2read.c --- 588e429077dfcd18f9bb42a13a3687ef890fd01d diff --cc gdb/c-exp.y index 9d1eb782486,2753c6ec5d1..e89a600ed15 --- a/gdb/c-exp.y +++ b/gdb/c-exp.y @@@ -1555,19 -1555,11 +1555,21 @@@ oper: OPERATOR NE | OPERATOR OBJC_LBRAC ']' { $$ = operator_stoken ("[]"); } | OPERATOR conversion_type_id - { struct ui_file *buf = mem_fileopen (); + { string_file buf; - c_print_type ($2, NULL, buf, -1, 0, + c_print_type ($2, NULL, &buf, -1, 0, &type_print_raw_options); - std::string name = " " + ui_file_as_string (buf); - ui_file_delete (buf); - $$ = operator_stoken (buf.c_str ()); + + /* This also needs canonicalization. */ - std::string canon - = cp_canonicalize_string (name.c_str ()); - if (!canon.empty ()) - name = " " + canon; - $$ = operator_stoken (name.c_str ()); ++ const char *name = buf.c_str (); ++ std::string canon = cp_canonicalize_string (name); ++ if (canon.empty ()) ++ canon = name; ++ ++ /* We need a space between "operator" and the ++ canonicalized type name. */ ++ canon.insert (0, " "); ++ $$ = operator_stoken (canon.c_str ()); } ; diff --cc gdb/compile/compile-c-support.c index 3a3ed45d7e3,7ad0a872f23..e823d3d7b58 --- a/gdb/compile/compile-c-support.c +++ b/gdb/compile/compile-c-support.c @@@ -281,420 -318,114 +281,412 @@@ generate_register_struct (struct ui_fil fputs_unfiltered ("};\n\n", stream); } -/* Take the source code provided by the user with the 'compile' - command, and compute the additional wrapping, macro, variable and - register operations needed. INPUT is the source code derived from - the 'compile' command, GDBARCH is the architecture to use when - computing above, EXPR_BLOCK denotes the block relevant contextually - to the inferior when the expression was created, and EXPR_PC - indicates the value of $PC. */ +/* C-language policy to emit a push user expression pragma into BUF. */ -std::string -c_compute_program (struct compile_instance *inst, - const char *input, - struct gdbarch *gdbarch, - const struct block *expr_block, - CORE_ADDR expr_pc) +struct c_push_user_expression { - struct compile_c_instance *context = (struct compile_c_instance *) inst; + void push_user_expression (struct ui_file *buf) + { + fputs_unfiltered ("#pragma GCC user_expression\n", buf); + } +}; - string_file buf; - string_file var_stream; +/* C-language policy to emit a pop user expression pragma into BUF. + For C, this is a nop. */ - write_macro_definitions (expr_block, expr_pc, &buf); +struct pop_user_expression_nop +{ + void pop_user_expression (struct ui_file *buf) + { + /* Nothing to do. */ + } +}; + +/* C-language policy to construct a code header for a block of code. + Takes a scope TYPE argument which selects the correct header to + insert into BUF. */ - /* Do not generate local variable information for "raw" - compilations. In this case we aren't emitting our own function - and the user's code may only refer to globals. */ - if (inst->scope != COMPILE_I_RAW_SCOPE) - { - unsigned char *registers_used; - int i; +struct c_add_code_header +{ + void add_code_header (enum compile_i_scope_types type, struct ui_file *buf) + { + switch (type) + { + case COMPILE_I_SIMPLE_SCOPE: + fputs_unfiltered ("void " + GCC_FE_WRAPPER_FUNCTION + " (struct " + COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG + " *" + COMPILE_I_SIMPLE_REGISTER_ARG_NAME + ") {\n", + buf); + break; + + case COMPILE_I_PRINT_ADDRESS_SCOPE: + case COMPILE_I_PRINT_VALUE_SCOPE: + /* is needed for a memcpy call below. */ + fputs_unfiltered ("#include \n" + "void " + GCC_FE_WRAPPER_FUNCTION + " (struct " + COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG + " *" + COMPILE_I_SIMPLE_REGISTER_ARG_NAME + ", " + COMPILE_I_PRINT_OUT_ARG_TYPE + " " + COMPILE_I_PRINT_OUT_ARG + ") {\n", + buf); + break; + + case COMPILE_I_RAW_SCOPE: + break; + + default: + gdb_assert_not_reached (_("Unknown compiler scope reached.")); + } + } +}; - /* Generate the code to compute variable locations, but do it - before generating the function header, so we can define the - register struct before the function body. This requires a - temporary stream. */ - registers_used = generate_c_for_variable_locations (context, - var_stream, gdbarch, - expr_block, expr_pc); - make_cleanup (xfree, registers_used); - - buf.puts ("typedef unsigned int" - " __attribute__ ((__mode__(__pointer__)))" - " __gdb_uintptr;\n"); - buf.puts ("typedef int" - " __attribute__ ((__mode__(__pointer__)))" - " __gdb_intptr;\n"); - - /* Iterate all log2 sizes in bytes supported by c_get_mode_for_size. */ - for (i = 0; i < 4; ++i) - { - const char *mode = c_get_mode_for_size (1 << i); +/* C-language policy to construct a code footer for a block of code. + Takes a scope TYPE which selects the correct footer to insert into BUF. */ - gdb_assert (mode != NULL); - buf.printf ("typedef int" - " __attribute__ ((__mode__(__%s__)))" - " __gdb_int_%s;\n", - mode, mode); - } +struct c_add_code_footer +{ + void add_code_footer (enum compile_i_scope_types type, struct ui_file *buf) + { + switch (type) + { + case COMPILE_I_SIMPLE_SCOPE: + case COMPILE_I_PRINT_ADDRESS_SCOPE: + case COMPILE_I_PRINT_VALUE_SCOPE: + fputs_unfiltered ("}\n", buf); + break; - generate_register_struct (&buf, gdbarch, registers_used); - } + case COMPILE_I_RAW_SCOPE: + break; - add_code_header (inst->scope, &buf); + default: + gdb_assert_not_reached (_("Unknown compiler scope reached.")); + } + } +}; - if (inst->scope == COMPILE_I_SIMPLE_SCOPE - || inst->scope == COMPILE_I_PRINT_ADDRESS_SCOPE - || inst->scope == COMPILE_I_PRINT_VALUE_SCOPE) - { - buf.write (var_stream.c_str (), var_stream.size ()); - buf.puts ("#pragma GCC user_expression\n"); - } +/* C-language policy to emit the user code snippet INPUT into BUF based on the + scope TYPE. */ + +struct c_add_input +{ + void add_input (enum compile_i_scope_types type, const char *input, + struct ui_file *buf) + { + switch (type) + { + case COMPILE_I_PRINT_ADDRESS_SCOPE: + case COMPILE_I_PRINT_VALUE_SCOPE: + fprintf_unfiltered (buf, + "__auto_type " COMPILE_I_EXPR_VAL " = %s;\n" + "typeof (%s) *" COMPILE_I_EXPR_PTR_TYPE ";\n" + "memcpy (" COMPILE_I_PRINT_OUT_ARG ", %s" + COMPILE_I_EXPR_VAL ",\n" + "sizeof (*" COMPILE_I_EXPR_PTR_TYPE "));\n" + , input, input, + (type == COMPILE_I_PRINT_ADDRESS_SCOPE + ? "&" : "")); + break; + + default: + fputs_unfiltered (input, buf); + break; + } + fputs_unfiltered ("\n", buf); + } +}; + +/* C++-language policy to emit a push user expression pragma into + BUF. */ - /* The user expression has to be in its own scope, so that "extern" - works properly. Otherwise gcc thinks that the "extern" - declaration is in the same scope as the declaration provided by - gdb. */ - if (inst->scope != COMPILE_I_RAW_SCOPE) - buf.puts ("{\n"); +struct cplus_push_user_expression +{ + void push_user_expression (struct ui_file *buf) + { + fputs_unfiltered ("#pragma GCC push_user_expression\n", buf); + } +}; + +/* C++-language policy to emit a pop user expression pragma into BUF. */ - buf.puts ("#line 1 \"gdb command line\"\n"); +struct cplus_pop_user_expression +{ + void pop_user_expression (struct ui_file *buf) + { + fputs_unfiltered ("#pragma GCC pop_user_expression\n", buf); + } +}; + +/* C++-language policy to construct a code header for a block of code. + Takes a scope TYPE argument which selects the correct header to + insert into BUF. */ - switch (inst->scope) +struct cplus_add_code_header +{ + void add_code_header (enum compile_i_scope_types type, struct ui_file *buf) + { + switch (type) { + case COMPILE_I_SIMPLE_SCOPE: + fputs_unfiltered ("void " + GCC_FE_WRAPPER_FUNCTION + " (struct " + COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG + " *" + COMPILE_I_SIMPLE_REGISTER_ARG_NAME + ") {\n", + buf); + break; + case COMPILE_I_PRINT_ADDRESS_SCOPE: case COMPILE_I_PRINT_VALUE_SCOPE: - buf.printf ( -"__auto_type " COMPILE_I_EXPR_VAL " = %s;\n" -"typeof (%s) *" COMPILE_I_EXPR_PTR_TYPE ";\n" -"memcpy (" COMPILE_I_PRINT_OUT_ARG ", %s" COMPILE_I_EXPR_VAL ",\n" - "sizeof (*" COMPILE_I_EXPR_PTR_TYPE "));\n" - , input, input, - (inst->scope == COMPILE_I_PRINT_ADDRESS_SCOPE - ? "&" : "")); + fputs_unfiltered ( + "#include \n" + "#include \n" + "void " + GCC_FE_WRAPPER_FUNCTION + " (struct " + COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG + " *" + COMPILE_I_SIMPLE_REGISTER_ARG_NAME + ", " + COMPILE_I_PRINT_OUT_ARG_TYPE + " " + COMPILE_I_PRINT_OUT_ARG + ") {\n", + buf); break; - default: - buf.puts (input); + + case COMPILE_I_RAW_SCOPE: break; + + default: + gdb_assert_not_reached (_("Unknown compiler scope reached.")); } + } +}; + +/* C++-language policy to emit the user code snippet INPUT into BUF based on + the scope TYPE. */ + +struct cplus_add_input +{ + void add_input (enum compile_i_scope_types type, const char *input, + struct ui_file *buf) + { + switch (type) + { + case COMPILE_I_PRINT_ADDRESS_SCOPE: + case COMPILE_I_PRINT_VALUE_SCOPE: + fprintf_unfiltered + (buf, + "auto " COMPILE_I_EXPR_VAL " = %s;\n" + "decltype ( %s ) *" COMPILE_I_EXPR_PTR_TYPE ";\n" + "std::memcpy (" COMPILE_I_PRINT_OUT_ARG ", %s (" + COMPILE_I_EXPR_VAL "),\n" + "sizeof (decltype(%s)));\n" + ,input, input, + (type == COMPILE_I_PRINT_ADDRESS_SCOPE + ? "std::__addressof" : ""), input); + break; + + default: + fputs_unfiltered (input, buf); + break; + } + fputs_unfiltered ("\n", buf); + } +}; + +/* A host class representing a compile program. + + CompileInstanceType is the type of the compile_instance for the + langauge. + + PushUserExpressionPolicy and PopUserExpressionPolicy are used to + push and pop user expression pragmas to the compile plug-in. + + AddCodeHeaderPolicy and AddCodeFooterPolicy are used to add the appropriate + code header and footer, respectively. + + AddInputPolicy adds the actual user code. */ + +template +class compile_program + : private PushUserExpressionPolicy, private PopUserExpressionPolicy, + private AddCodeHeaderPolicy, private AddCodeFooterPolicy, + private AddInputPolicy +{ + using PushUserExpressionPolicy::push_user_expression; + using PopUserExpressionPolicy::pop_user_expression; + using AddCodeHeaderPolicy::add_code_header; + using AddCodeFooterPolicy::add_code_footer; + using AddInputPolicy::add_input; + +public: + + /* Construct a compile_program using the compiler instance INST + using the architecture given by GDBARCH. */ + + compile_program (CompileInstanceType *inst, struct gdbarch *gdbarch) + : m_instance (inst), m_arch (gdbarch) + { + } + + /* Take the source code provided by the user with the 'compile' + command and compute the additional wrapping, macro, variable and + register operations needed. INPUT is the source code derived from + the 'compile' command, EXPR_BLOCK denotes the block relevant contextually + to the inferior when the expression was created, and EXPR_PC + indicates the value of $PC. + + Returns the text of the program to compile. This must be free'd by + the caller. */ + + std::string compute (const char *input, const struct block *expr_block, + CORE_ADDR expr_pc) + { - struct ui_file *var_stream = NULL; - struct ui_file *buf = mem_fileopen (); - struct cleanup *cleanup = make_cleanup_ui_file_delete (buf); ++ string_file var_stream; ++ string_file buf; + + /* Do not generate local variable information for "raw" + compilations. In this case we aren't emitting our own function + and the user's code may only refer to globals. */ + if (m_instance->scope () != COMPILE_I_RAW_SCOPE) + { + /* Generate the code to compute variable locations, but do it + before generating the function header, so we can define the + register struct before the function body. This requires a + temporary stream. */ - var_stream = mem_fileopen (); - make_cleanup_ui_file_delete (var_stream); + unsigned char *registers_used + = generate_c_for_variable_locations (m_instance, var_stream, m_arch, + expr_block, expr_pc); + make_cleanup (xfree, registers_used); + - fputs_unfiltered ("typedef unsigned int" - " __attribute__ ((__mode__(__pointer__)))" - " __gdb_uintptr;\n", - buf); - fputs_unfiltered ("typedef int" - " __attribute__ ((__mode__(__pointer__)))" - " __gdb_intptr;\n", - buf); ++ buf.puts ("typedef unsigned int" ++ " __attribute__ ((__mode__(__pointer__)))" ++ " __gdb_uintptr;\n"); ++ buf.puts ("typedef int" ++ " __attribute__ ((__mode__(__pointer__)))" ++ " __gdb_intptr;\n"); + + /* Iterate all log2 sizes in bytes supported by c_get_mode_for_size. */ + for (int i = 0; i < 4; ++i) + { + const char *mode = c_get_mode_for_size (1 << i); + + gdb_assert (mode != NULL); - fprintf_unfiltered (buf, - "typedef int" - " __attribute__ ((__mode__(__%s__)))" - " __gdb_int_%s;\n", - mode, mode); ++ buf.printf ("typedef int" ++ " __attribute__ ((__mode__(__%s__)))" ++ " __gdb_int_%s;\n", ++ mode, mode); + } + - generate_register_struct (buf, m_arch, registers_used); ++ generate_register_struct (&buf, m_arch, registers_used); + } + - add_code_header (m_instance->scope (), buf); ++ add_code_header (m_instance->scope (), &buf); + + if (m_instance->scope () == COMPILE_I_SIMPLE_SCOPE + || m_instance->scope () == COMPILE_I_PRINT_ADDRESS_SCOPE + || m_instance->scope () == COMPILE_I_PRINT_VALUE_SCOPE) + { - ui_file_put (var_stream, ui_file_write_for_put, buf); - push_user_expression (buf); ++ buf.write (var_stream.c_str (), var_stream.size ()); ++ push_user_expression (&buf); + } + - write_macro_definitions (expr_block, expr_pc, buf); ++ write_macro_definitions (expr_block, expr_pc, &buf); + + /* The user expression has to be in its own scope, so that "extern" + works properly. Otherwise gcc thinks that the "extern" + declaration is in the same scope as the declaration provided by + gdb. */ + if (m_instance->scope () != COMPILE_I_RAW_SCOPE) - fputs_unfiltered ("{\n", buf); ++ buf.puts ("{\n"); + - fputs_unfiltered ("#line 1 \"gdb command line\"\n", buf); ++ buf.puts ("#line 1 \"gdb command line\"\n"); + - add_input (m_instance->scope (), input, buf); ++ add_input (m_instance->scope (), input, &buf); + + /* For larger user expressions the automatic semicolons may be + confusing. */ + if (strchr (input, '\n') == NULL) - fputs_unfiltered (";\n", buf); ++ buf.puts (";\n"); - buf.puts ("\n"); + if (m_instance->scope () != COMPILE_I_RAW_SCOPE) - fputs_unfiltered ("}\n", buf); ++ buf.puts ("}\n"); - /* For larger user expressions the automatic semicolons may be - confusing. */ - if (strchr (input, '\n') == NULL) - buf.puts (";\n"); + if (m_instance->scope () == COMPILE_I_SIMPLE_SCOPE + || m_instance->scope () == COMPILE_I_PRINT_ADDRESS_SCOPE + || m_instance->scope () == COMPILE_I_PRINT_VALUE_SCOPE) - pop_user_expression (buf); ++ pop_user_expression (&buf); + - add_code_footer (m_instance->scope (), buf); - std::string code = ui_file_as_string (buf); - do_cleanups (cleanup); - return code; ++ add_code_footer (m_instance->scope (), &buf); ++ return std::move (buf.string ()); + } + +private: + + /* The compile instance to be used for compilation and + type-conversion. */ + CompileInstanceType *m_instance; + + /* The architecture to be used. */ + struct gdbarch *m_arch; +}; + +/* The types used for C and C++ program computations. */ + +typedef compile_program c_compile_program; + +typedef compile_program cplus_compile_program; + +/* The la_compute_program method for C. */ + +std::string +c_compute_program (struct compile_instance *inst, + const char *input, + struct gdbarch *gdbarch, + const struct block *expr_block, + CORE_ADDR expr_pc) +{ + compile_c_instance *c_inst = static_cast (inst); + c_compile_program program (c_inst, gdbarch); + + return program.compute (input, expr_block, expr_pc); +} + +/* The la_compute_program method for C++. */ + +std::string +cplus_compute_program (struct compile_instance *inst, + const char *input, + struct gdbarch *gdbarch, + const struct block *expr_block, + CORE_ADDR expr_pc) +{ + using namespace compile; - if (inst->scope != COMPILE_I_RAW_SCOPE) - buf.puts ("}\n"); + compile_cplus_instance *cplus_inst + = static_cast (inst); + cplus_compile_program program (cplus_inst, gdbarch); - add_code_footer (inst->scope, &buf); - return std::move (buf.string ()); + return program.compute (input, expr_block, expr_pc); } diff --cc gdb/compile/compile-c-symbols.c index 49f22b237a7,9282cfc0251..9c0a918c89e --- a/gdb/compile/compile-c-symbols.c +++ b/gdb/compile/compile-c-symbols.c @@@ -485,8 -583,8 +485,8 @@@ symbol_seen (htab_t hashtab, struct sym /* Generate C code to compute the length of a VLA. */ static void - generate_vla_size (struct compile_instance *compiler, - struct ui_file *stream, -generate_vla_size (struct compile_c_instance *compiler, ++generate_vla_size (compile_instance *compiler, + string_file &stream, struct gdbarch *gdbarch, unsigned char *registers_used, CORE_ADDR pc, @@@ -541,8 -639,8 +541,8 @@@ /* Generate C code to compute the address of SYM. */ static void - generate_c_for_for_one_variable (struct compile_instance *compiler, - struct ui_file *stream, -generate_c_for_for_one_variable (struct compile_c_instance *compiler, ++generate_c_for_for_one_variable (compile_instance *compiler, + string_file &stream, struct gdbarch *gdbarch, unsigned char *registers_used, CORE_ADDR pc, @@@ -610,11 -714,11 +609,11 @@@ END_CATCH } --/* See compile-internal.h. */ ++/* See compile-c.h. */ unsigned char * - generate_c_for_variable_locations (struct compile_instance *compiler, - struct ui_file *stream, -generate_c_for_variable_locations (struct compile_c_instance *compiler, ++generate_c_for_variable_locations (compile_instance *compiler, + string_file &stream, struct gdbarch *gdbarch, const struct block *block, CORE_ADDR pc) diff --cc gdb/compile/compile-c.h index 7161c603a9b,00000000000..a7024116757 mode 100644,000000..100644 --- a/gdb/compile/compile-c.h +++ b/gdb/compile/compile-c.h @@@ -1,176 -1,0 +1,176 @@@ +/* Header file for GDB compile C-language support. + Copyright (C) 2014-2017 Free Software Foundation, Inc. + + 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 . */ + +#ifndef GDB_COMPILE_C_H +#define GDB_COMPILE_C_H + +#include "common/enum-flags.h" + +/* enum-flags wrapper. */ +DEF_ENUM_FLAGS_TYPE (enum gcc_qualifiers, gcc_qualifiers_flags); + +/* A callback suitable for use as the GCC C symbol oracle. */ + +extern gcc_c_oracle_function gcc_convert_symbol; + +/* A callback suitable for use as the GCC C address oracle. */ + +extern gcc_c_symbol_address_function gcc_symbol_address; + +/* A subclass of compile_instance that is specific to the C front + end. */ + +class compile_c_instance + : public compile_instance +{ + public: + + compile_c_instance (struct gcc_base_context *base, const char *options) + : compile_instance (base, options) + { + } + + explicit compile_c_instance (struct gcc_c_context *gcc_c) + : compile_instance (&gcc_c->base, + "-std=gnu11" + /* Otherwise the .o file may need + "_Unwind_Resume" and + "__gcc_personality_v0". */ + " -fno-exceptions" + " -Wno-implicit-function-declaration"), + m_context (gcc_c) + { + m_context->c_ops->set_callbacks (m_context, gcc_convert_symbol, + gcc_symbol_address, this); + } + + ~compile_c_instance () + { + m_gcc_fe->ops->destroy (m_gcc_fe); + } + + /* Convert a gdb type, TYPE, to a GCC type. + + The new GCC type is returned. */ + + gcc_type convert_type (struct type *type); + + /* Plug-in forwards */ + + unsigned int c_version () const; + + bool tagbind (const char *name, gcc_type tagged_type, const char *filename, + unsigned int line_number); + + bool build_constant (gcc_type type, const char *name, unsigned long value, + const char *filename, unsigned int line_number); + + gcc_decl build_decl (const char *name, enum gcc_c_symbol_kind sym_kind, + gcc_type sym_type, const char *substitution_name, + gcc_address address, const char *filename, + unsigned int line_number); + + bool bind (gcc_decl decl, bool is_global); + + gcc_type error (const char *message); + + gcc_type build_pointer_type (gcc_type base_type); + + gcc_type build_vla_array_type (gcc_type element_type, + const char *upper_bound_name); + + gcc_type build_vector_type (gcc_type element_type, int num_elements); + + gcc_type build_array_type (gcc_type element_type, int num_elements); + + gcc_type build_record_type (); + + gcc_type build_union_type (); + + bool build_add_field (gcc_type record_or_union_type, const char *field_name, + gcc_type field_type, unsigned long bitsize, + unsigned long bitpos); + + bool finish_record_or_union (gcc_type record_or_union_type, + unsigned long size_in_bytes); + + gcc_type int_type (bool is_unsigned, unsigned long size_in_bytes, + const char *builtin_name); + + gcc_type int_type (bool is_unsigned, unsigned long size_in_bytes); + + gcc_type build_enum_type (gcc_type underlying_int_type); + + bool build_add_enum_constant (gcc_type enum_type, const char *name, + unsigned long value); + + bool finish_enum_type (gcc_type enum_type); + + gcc_type build_function_type (gcc_type return_value, + const struct gcc_type_array *argument_types, + bool is_varargs); + + gcc_type char_type (); + + gcc_type float_type (unsigned long size_in_bytes, const char *builtin_name); + + gcc_type float_type (unsigned long size_in_bytes); + + gcc_type void_type (); + + gcc_type bool_type (); + + gcc_type build_qualified_type (gcc_type unqualified_type, + enum gcc_qualifiers qualifiers); + + gcc_type build_complex_type (gcc_type element_type); + +private: + + /* The GCC C context. */ + struct gcc_c_context *m_context; +}; + +/* Emit code to compute the address for all the local variables in + scope at PC in BLOCK. Returns a malloc'd vector, indexed by gdb + register number, where each element indicates if the corresponding + register is needed to compute a local variable. */ + +extern unsigned char *generate_c_for_variable_locations - (struct compile_instance *compiler, - struct ui_file *stream, ++ (compile_instance *compiler, ++ string_file &stream, + struct gdbarch *gdbarch, + const struct block *block, + CORE_ADDR pc); + +/* Get the GCC mode attribute value for a given type size. */ + +extern const char *c_get_mode_for_size (int size); + +/* Given a dynamic property, return an xmallocd name that is used to + represent its size. The result must be freed by the caller. The + contents of the resulting string will be the same each time for + each call with the same argument. */ + +struct dynamic_prop; +extern char *c_get_range_decl_name (const struct dynamic_prop *prop); + +/* Compute the name of the pointer representing a local symbol's + address. */ + +extern char *c_symbol_substitution_name (struct symbol *sym); + +#endif /* GDB_COMPILE_C_H */ diff --cc gdb/compile/compile-cplus-templates.c index 683fe78952f,00000000000..d4a1d37c5b2 mode 100644,000000..100644 --- a/gdb/compile/compile-cplus-templates.c +++ b/gdb/compile/compile-cplus-templates.c @@@ -1,1478 -1,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 . */ + +#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 - (struct ui_file *stream, const struct template_argument_info *arg_info); ++ (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)". ++ return "T foo(T)". */ + - The return result should be freed. */ - - static char * ++static std::string +function_template_decl (const struct template_symbol *tsymbol, + const struct demangle_parse_info *info) +{ - struct demangle_component *ret_comp; - struct ui_file *stream; - long length; - struct cleanup *back_to; - struct block_symbol symbol; - char *str = NULL; - + gdb_assert (info != NULL); + - stream = mem_fileopen (); - back_to = make_cleanup_ui_file_delete (stream); ++ string_file stream; ++ struct demangle_component *ret_comp = info->tree; + - 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, ++ c_print_type (return_type, "", &stream, -1, 0, + &type_print_raw_options); + } + else - print_template_type (d_left (ret_comp), tsymbol, stream); - fputc_unfiltered (' ', stream); ++ 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); ++ print_conversion_node (info->tree, tsymbol, &stream); + else + { - fputs_unfiltered (tsymbol->search_name, stream); - if (tsymbol->search_name[strlen (tsymbol->search_name) - 1] - == '<') - fputc_unfiltered (' ', stream); ++ stream.puts (tsymbol->search_name); ++ if (tsymbol->search_name[strlen (tsymbol->search_name) - 1] == '<') ++ stream.putc (' '); + } + + /* Print out template (generic) arguments. */ - fputc_unfiltered ('<', stream); - print_template_parameter_list (stream, tsymbol->template_arguments); - fputc_unfiltered ('>', stream); ++ stream.putc ('<'); ++ print_template_parameter_list (tsymbol->template_arguments, &stream); ++ stream.putc ('>'); + + /* Print out function arguments. */ - fputc_unfiltered ('(', stream); - print_function_template_arglist (ret_comp, tsymbol, stream); - fputc_unfiltered (')', stream); ++ stream.putc ('('); ++ print_function_template_arglist (ret_comp, tsymbol, &stream); ++ stream.putc (')'); + } + - /* !!keiths: Convert this to use ui_file_string when that becomes - available. */ - str = ui_file_xstrdup (stream, &length); - do_cleanups (back_to); - return str; ++ 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. */ - char *generic_c = function_template_decl (tsymbol, info); - std::string generic (generic_c); - xfree (generic_c); - return 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) +{ - struct ui_file *stream = mem_fileopen (); - struct cleanup *back_to = make_cleanup_ui_file_delete (stream); ++ string_file stream; + + /* Format: class|struct|union namespaces::NAME */ + if (TYPE_CODE (type) == TYPE_CODE_STRUCT) + { + if (TYPE_DECLARED_CLASS (type)) - fputs_unfiltered ("class ", stream); ++ stream.puts ("class "); + else - fputs_unfiltered ("struct ", stream); ++ stream.puts ("struct "); + } + else + { + gdb_assert (TYPE_CODE (type) == TYPE_CODE_UNION); - fputs_unfiltered ("union ", stream); ++ 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) - { - fputs_unfiltered (comp.name.c_str (), stream); - fputs_unfiltered ("::", stream); - } ++ stream.printf ("%s::", comp.name.c_str ()); + }); + - fputs_unfiltered (name.c_str (), stream); - fputc_unfiltered ('<', stream); - print_template_parameter_list (stream, TYPE_TEMPLATE_ARGUMENT_INFO (type)); - fputc_unfiltered ('>', stream); - - long length; - char *generic = ui_file_xstrdup (stream, &length); ++ stream.printf ("%s<", name.c_str ()); ++ print_template_parameter_list (TYPE_TEMPLATE_ARGUMENT_INFO (type), &stream); ++ stream.putc ('>'); + - make_cleanup (xfree, generic); - std::string string_generic (generic); - do_cleanups (back_to); - return string_generic; ++ 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 (struct ui_file *stream, - const struct template_argument_info *arg_info) ++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 &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); - char *str = function_template_decl (tsymbol, info.get ()); ++ std::string str = function_template_decl (tsymbol, info.get ()); + - make_cleanup (xfree, str); - fprintf_filtered (gdb_stdout, "%s\n", str); ++ 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/dwarf2read.c index 9f8ef405ec0,774ed730757..48acc968156 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@@ -8428,33 -8409,6 +8428,22 @@@ die_needs_namespace (struct die_info *d } } - /* Retrieve the last character from a mem_file. */ - - static void - do_ui_file_peek_last (void *object, const char *buffer, long length) - { - char *last_char_p = (char *) object; - - if (length > 0) - *last_char_p = buffer[length - 1]; - } - +/* Return the DIE's linkage name attribute, either DW_AT_linkage_name + or DW_AT_MIPS_linkage_name. Returns NULL if the attribute is not + defined for the given DIE. */ + +static const char * +dw2_linkage_name (struct die_info *die, struct dwarf2_cu *cu) +{ + const char *linkage_name; + + linkage_name = dwarf2_string_attr (die, DW_AT_linkage_name, cu); + if (linkage_name == NULL) + linkage_name = dwarf2_string_attr (die, DW_AT_MIPS_linkage_name, cu); + + return linkage_name; +} + /* Compute the fully qualified name of DIE in CU. If PHYSNAME is nonzero, compute the physname for the object, which include a method's: - formal parameters (C++),