[PATCH 9/9] C++ compile support

Keith Seitz
2018-08-10T23:32:03Z

This patch adds *basic* support for C++ to the compile feature. It does
most simple type conversions, including everything that C compile does and
your basic "with-classes" type of C++.

I've written a new compile-support.exp support file which adds a new test
facility for automating and simplifying "compile print" vs "compile code"
testing. See testsuite/lib/compile-support.exp and CompileExpression
for more on that. The tests use this facility extensively.

This initial support has several glaring omissions:
- No template support at all
I have follow-on patches for this, but they add much complexity
to this "basic" support. Consequently, they will be submitted separately.
- Cannot print functions
The code template needs tweaking, and I simply haven't gotten to it yet.
- So-called "special function" support is not included
Using constructors, destructors, operators, etc will not work. I have
follow-on patches for that, but they require some work because of the
recent churn in symbol searching.
- There are several test suite references to "compile/1234" bugs.
I will file bugs and update the test suite's bug references before pushing
these patches.

The test suite started as a copy of the original C-language support, but
I have written tests to exercise the basic functionality of the plug-in.

Debug options have been expanded a bit. I've added options for outputting
debug messages for the oracle and C++ type-conversion. These are the
"debug compile-oracle" and "debug compile-cplus-types" options.

gdb/ChangeLog:

* Makefile.in (SUBDIR_GCC_COMPILE_SRCS): Add compile-cplus-support.c,
compile-cplus-symbols.c, and compile-cplus-types.c.
(HFILES_NO_SRCDIR): Add gcc-cp-plugin.h.
* c-lang.c (cplus_language_defn): Set C++ compile functions.
* c-lang.h (cplus_get_compile_context, cplus_compute_program):
Declare.
* compile/compile-c-support.c: Include compile-cplus.h.
(load_libcompile): Templatize.
(get_compile_context): "New" function.
(c_get_compile_context): Use get_compile_context.
(cplus_get_compile_context): New function.
(cplus_push_user_expression, cplus_pop_user_expression)
(cplus_add_code_header, cplus_add_input, cplus_compile_program)
(cplus_compute_program): Define new structs/functions.
* compile/compile-cplus-support.c: New file.
* compile/compile-cplus-symmbols.c: New file.
* compile/compile-cplus-types.c: New file.
* compile/compile-cplus.h: New file.
* compile/compile-internal.h (debug_compile_oracle, GCC_TYPE_NONE):
Declare.
* compile/compile-object-load.c (get_out_value_type): Use
strncmp_iw when comparing symbol names.
(compile_object_load): Add mst_bss and mst_data.
* compile/compile.c (_initialize_compile): Remove
-Wno-implicit-function-declaration from `compile_args'.
* compile/gcc-cp-plugin.h: New file.
* NEWS: Mention C++ compile support and new debug options.

gdb/testsuite/ChangeLog:

* gdb.compile/compile-cplus-anonymous.cc: New file.
* gdb.compile/compile-cplus-anonymous.exp: New file.
* gdb.compile/compile-cplus-array-decay.cc: New file.
* gdb.compile/compile-cplus-array-decay.exp: New file.
* gdb.compile/compile-cplus-inherit.cc: New file.
* gdb.compile/compile-cplus-inherit.exp: New file.
* gdb.compile/compile-cplus-member.cc: New file.
* gdb.compile/compile-cplus-member.exp: New file.
* gdb.compile/compile-cplus-method.cc: New file.
* gdb.compile/compile-cplus-method.exp: New file.
* gdb.compile/compile-cplus-mod.c: "New" file.
* gdb.compile/compile-cplus-namespace.cc: New file.
* gdb.compile/compile-cplus-namespace.exp: New file.
* gdb.compile/compile-cplus-nested.cc: New file.
* gdb.compile/compile-cplus-nested.exp: New file.
* gdb.compile/compile-cplus-print.c: "New" file.
* gdb.compile/compile-cplus-print.exp: "New" file.
* gdb.compile/compile-cplus-virtual.cc: New file.
* gdb.compile/compile-cplus-virtual.exp: New file.
* gdb.compile/compile-cplus.c: "New" file.
* gdb.compile/compile-cplus.exp: "New" file.
* lib/compile-support.exp: New file.

doc/ChangeLog:

* gdb.texinfo (Compiling and injecting code in GDB): Document
set/show "compile-oracle" and "compile-cplus-types" commands.
---
gdb/ChangeLog | 30 +
gdb/Makefile.in | 5 +
gdb/NEWS | 14 +
gdb/c-lang.c | 4 +-
gdb/c-lang.h | 19 +
gdb/compile/compile-c-support.c | 205 ++-
gdb/compile/compile-cplus-support.c | 30 +
gdb/compile/compile-cplus-symbols.c | 511 +++++++
gdb/compile/compile-cplus-types.c | 1430 ++++++++++++++++++++
gdb/compile/compile-cplus.h | 207 +++
gdb/compile/compile-internal.h | 8 +
gdb/compile/compile-object-load.c | 7 +-
gdb/compile/compile.c | 1 -
gdb/compile/gcc-cp-plugin.h | 85 ++
gdb/doc/ChangeLog | 5 +
gdb/doc/gdb.texinfo | 20 +
gdb/testsuite/ChangeLog | 25 +
.../gdb.compile/compile-cplus-anonymous.cc | 76 ++
.../gdb.compile/compile-cplus-anonymous.exp | 64 +
.../gdb.compile/compile-cplus-array-decay.cc | 31 +
.../gdb.compile/compile-cplus-array-decay.exp | 50 +
gdb/testsuite/gdb.compile/compile-cplus-inherit.cc | 58 +
.../gdb.compile/compile-cplus-inherit.exp | 53 +
gdb/testsuite/gdb.compile/compile-cplus-member.cc | 83 ++
gdb/testsuite/gdb.compile/compile-cplus-member.exp | 77 ++
gdb/testsuite/gdb.compile/compile-cplus-method.cc | 91 ++
gdb/testsuite/gdb.compile/compile-cplus-method.exp | 67 +
gdb/testsuite/gdb.compile/compile-cplus-mod.c | 28 +
.../gdb.compile/compile-cplus-namespace.cc | 52 +
.../gdb.compile/compile-cplus-namespace.exp | 51 +
gdb/testsuite/gdb.compile/compile-cplus-nested.cc | 58 +
gdb/testsuite/gdb.compile/compile-cplus-nested.exp | 53 +
gdb/testsuite/gdb.compile/compile-cplus-print.c | 32 +
gdb/testsuite/gdb.compile/compile-cplus-print.exp | 81 ++
gdb/testsuite/gdb.compile/compile-cplus-virtual.cc | 54 +
.../gdb.compile/compile-cplus-virtual.exp | 71 +
gdb/testsuite/gdb.compile/compile-cplus.c | 241 ++++
gdb/testsuite/gdb.compile/compile-cplus.exp | 341 +++++
gdb/testsuite/lib/compile-support.exp | 227 ++++
39 files changed, 4515 insertions(+), 30 deletions(-)
create mode 100644 gdb/compile/compile-cplus-support.c
create mode 100644 gdb/compile/compile-cplus-symbols.c
create mode 100644 gdb/compile/compile-cplus-types.c
create mode 100644 gdb/compile/compile-cplus.h
create mode 100644 gdb/compile/gcc-cp-plugin.h
create mode 100644 gdb/testsuite/gdb.compile/compile-cplus-anonymous.cc
create mode 100644 gdb/testsuite/gdb.compile/compile-cplus-anonymous.exp
create mode 100644 gdb/testsuite/gdb.compile/compile-cplus-array-decay.cc
create mode 100644 gdb/testsuite/gdb.compile/compile-cplus-array-decay.exp
create mode 100644 gdb/testsuite/gdb.compile/compile-cplus-inherit.cc
create mode 100644 gdb/testsuite/gdb.compile/compile-cplus-inherit.exp
create mode 100644 gdb/testsuite/gdb.compile/compile-cplus-member.cc
create mode 100644 gdb/testsuite/gdb.compile/compile-cplus-member.exp
create mode 100644 gdb/testsuite/gdb.compile/compile-cplus-method.cc
create mode 100644 gdb/testsuite/gdb.compile/compile-cplus-method.exp
create mode 100644 gdb/testsuite/gdb.compile/compile-cplus-mod.c
create mode 100644 gdb/testsuite/gdb.compile/compile-cplus-namespace.cc
create mode 100644 gdb/testsuite/gdb.compile/compile-cplus-namespace.exp
create mode 100644 gdb/testsuite/gdb.compile/compile-cplus-nested.cc
create mode 100644 gdb/testsuite/gdb.compile/compile-cplus-nested.exp
create mode 100644 gdb/testsuite/gdb.compile/compile-cplus-print.c
create mode 100644 gdb/testsuite/gdb.compile/compile-cplus-print.exp
create mode 100644 gdb/testsuite/gdb.compile/compile-cplus-virtual.cc
create mode 100644 gdb/testsuite/gdb.compile/compile-cplus-virtual.exp
create mode 100644 gdb/testsuite/gdb.compile/compile-cplus.c
create mode 100644 gdb/testsuite/gdb.compile/compile-cplus.exp
create mode 100644 gdb/testsuite/lib/compile-support.exp

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index e12c54983c..c03dbbfec4 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,35 @@
YYYY-MM-DD Keith Seitz <keiths@redhat.com>

+ * Makefile.in (SUBDIR_GCC_COMPILE_SRCS): Add compile-cplus-support.c,
+ compile-cplus-symbols.c, and compile-cplus-types.c.
+ (HFILES_NO_SRCDIR): Add gcc-cp-plugin.h.
+ * c-lang.c (cplus_language_defn): Set C++ compile functions.
+ * c-lang.h (cplus_get_compile_context, cplus_compute_program):
+ Declare.
+ * compile/compile-c-support.c: Include compile-cplus.h.
+ (load_libcompile): Templatize.
+ (get_compile_context): "New" function.
+ (c_get_compile_context): Use get_compile_context.
+ (cplus_get_compile_context): New function.
+ (cplus_push_user_expression, cplus_pop_user_expression)
+ (cplus_add_code_header, cplus_add_input, cplus_compile_program)
+ (cplus_compute_program): Define new structs/functions.
+ * compile/compile-cplus-support.c: New file.
+ * compile/compile-cplus-symmbols.c: New file.
+ * compile/compile-cplus-types.c: New file.
+ * compile/compile-cplus.h: New file.
+ * compile/compile-internal.h (debug_compile_oracle, GCC_TYPE_NONE):
+ Declare.
+ * compile/compile-object-load.c (get_out_value_type): Use
+ strncmp_iw when comparing symbol names.
+ (compile_object_load): Add mst_bss and mst_data.
+ * compile/compile.c (_initialize_compile): Remove
+ -Wno-implicit-function-declaration from `compile_args'.
+ * compile/gcc-cp-plugin.h: New file.
+ * NEWS: Mention C++ compile support and new debug options.
+
+YYYY-MM-DD Keith Seitz <keiths@redhat.com>
+
* linespec.c (collect_info::add_symbol): Make virtual.
(struct symbol_searcher_collect_info): New struct.
(symbol_searcher::find_all_symbols): New method.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 118c3c8062..9163e04d14 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -317,6 +317,9 @@ SUBDIR_GCC_COMPILE_SRCS = \
compile/compile-c-support.c \
compile/compile-c-symbols.c \
compile/compile-c-types.c \
+ compile/compile-cplus-support.c \
+ compile/compile-cplus-symbols.c \
+ compile/compile-cplus-types.c \
compile/compile-loc2c.c \
compile/compile-object-load.c \
compile/compile-object-run.c
@@ -1461,10 +1464,12 @@ HFILES_NO_SRCDIR = \
common/xml-utils.h \
compile/compile.h \
compile/compile-c.h \
+ compile/compile-cplus.h \
compile/compile-internal.h \
compile/compile-object-load.h \
compile/compile-object-run.h \
compile/gcc-c-plugin.h \
+ compile/gcc-cp-plugin.h \
config/nm-linux.h \
config/nm-nto.h \
config/djgpp/langinfo.h \
diff --git a/gdb/NEWS b/gdb/NEWS
index f275031345..cfc7789a9f 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,10 @@

*** Changes since GDB 8.2

+* GDB now has experimental support for the compilation and injection of
+ C++ source code into the inferior. This feature requires the GCC C++
+ plug-in available since GCC 7.1.
+
* GDB and GDBserver now support IPv6 connections. IPv6 addresses
can be passed using the '[ADDRESS]:PORT' notation, or the regular
'ADDRESS:PORT' method.
@@ -12,6 +16,16 @@

* New commands

+set debug compile-oracle
+show debug compile-oracle
+ Control the display of debug output about symbol requests from
+ the compiler plug-in.
+
+set debug compile-cplus-types
+show debug compile-cplus-types
+ Control the display of debug output about C++ type conversion
+ in the compile feature.
+
frame apply [all | COUNT | -COUNT | level LEVEL...] [FLAG]... COMMAND
Apply a command to some frames.
FLAG arguments allow to control what output to produce and how to handle
diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index 5ad580182c..6bae4c18ec 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -1017,8 +1017,8 @@ extern const struct language_defn cplus_language_defn =
iterate_over_symbols,
cp_search_name_hash,
&cplus_varobj_ops,
- NULL,
- NULL,
+ cplus_get_compile_context,
+ cplus_compute_program,
LANG_MAGIC
};

diff --git a/gdb/c-lang.h b/gdb/c-lang.h
index b7bf08992b..9719ad50aa 100644
--- a/gdb/c-lang.h
+++ b/gdb/c-lang.h
@@ -160,6 +160,14 @@ extern int c_textual_element_type (struct type *, char);

extern compile_instance *c_get_compile_context (void);

+/* Create a new instance of the C++ compiler and return it. The new
+ compiler is owned by the caller and must be freed using the destroy
+ method. This function never returns NULL, but rather throws an
+ exception on failure. This is suitable for use as the
+ la_get_compile_instance language method. */
+
+extern compile_instance *cplus_get_compile_context (void);
+
/* This takes the user-supplied text and returns a new bit of code to
compile.

@@ -172,4 +180,15 @@ extern std::string c_compute_program (compile_instance *inst,
const struct block *expr_block,
CORE_ADDR expr_pc);

+/* This takes the user-supplied text and returns a new bit of code to compile.
+
+ This is used as the la_compute_program language method; see that
+ for a description of the arguments. */
+
+extern std::string cplus_compute_program (compile_instance *inst,
+ const char *input,
+ struct gdbarch *gdbarch,
+ const struct block *expr_block,
+ CORE_ADDR expr_pc);
+
#endif /* !defined (C_LANG_H) */
diff --git a/gdb/compile/compile-c-support.c b/gdb/compile/compile-c-support.c
index e8993aa5eb..4c7893cf06 100644
--- a/gdb/compile/compile-c-support.c
+++ b/gdb/compile/compile-c-support.c
@@ -1,4 +1,4 @@
-/* C language support for compilation.
+/* C/C++ language support for compilation.

Copyright (C) 2014-2018 Free Software Foundation, Inc.

@@ -20,6 +20,7 @@
#include "defs.h"
#include "compile-internal.h"
#include "compile-c.h"
+#include "compile-cplus.h"
#include "compile.h"
#include "gdb-dlfcn.h"
#include "c-lang.h"
@@ -67,25 +68,22 @@ c_get_range_decl_name (const struct dynamic_prop *prop)

\f

-/* Helper function for c_get_compile_context. Open the GCC front-end
- shared library and return the symbol specified by the current
- GCC_C_FE_CONTEXT. */
+/* Load the plug-in library FE_LIBCC and return the initialization function
+ FE_CONTEXT. */

-static gcc_c_fe_context_function *
-load_libcc (void)
+template <typename FUNCTYPE>
+FUNCTYPE *
+load_libcompile (const char *fe_libcc, const char *fe_context)
{
- gcc_c_fe_context_function *func;
+ FUNCTYPE *func;

- /* gdb_dlopen will call error () on an error, so no need to check
- value. */
- gdb_dlhandle_up handle = gdb_dlopen (STRINGIFY (GCC_C_FE_LIBCC));
- func = (gcc_c_fe_context_function *) gdb_dlsym (handle,
- STRINGIFY (GCC_C_FE_CONTEXT));
+ /* gdb_dlopen will call error () on an error, so no need to check
+ value. */
+ gdb_dlhandle_up handle = gdb_dlopen (fe_libcc);
+ func = (FUNCTYPE *) gdb_dlsym (handle, fe_context);

if (func == NULL)
- error (_("could not find symbol %s in library %s"),
- STRINGIFY (GCC_C_FE_CONTEXT),
- STRINGIFY (GCC_C_FE_LIBCC));
+ error (_("could not find symbol %s in library %s"), fe_context, fe_libcc);

/* Leave the library open. */
handle.release ();
@@ -93,28 +91,57 @@ load_libcc (void)
}

/* Return the compile instance associated with the current context.
- This function calls the symbol returned from the load_libcc
- function. This will provide the gcc_c_context. */
+ This function calls the symbol returned from the load_libcompile
+ function. FE_LIBCC is the library to load. BASE_VERSION is the
+ base compile plug-in version we support. API_VERSION is the
+ API version supported. */

+template <typename INSTTYPE, typename FUNCTYPE, typename CTXTYPE,
+ typename BASE_VERSION_TYPE, typename API_VERSION_TYPE>
compile_instance *
-c_get_compile_context (void)
+get_compile_context (const char *fe_libcc, const char *fe_context,
+ BASE_VERSION_TYPE base_version,
+ API_VERSION_TYPE api_version)
{
- static gcc_c_fe_context_function *func;
-
- struct gcc_c_context *context;
+ static FUNCTYPE *func;
+ static CTXTYPE *context;

if (func == NULL)
{
- func = load_libcc ();
+ func = load_libcompile<FUNCTYPE> (fe_libcc, fe_context);
gdb_assert (func != NULL);
}

- context = (*func) (GCC_FE_VERSION_0, GCC_C_FE_VERSION_0);
+ context = (*func) (base_version, api_version);
if (context == NULL)
error (_("The loaded version of GCC does not support the required version "
"of the API."));

- return new compile_c_instance (context);
+ return new INSTTYPE (context);
+}
+
+/* A C-language implementation of get_compile_context. */
+
+compile_instance *
+c_get_compile_context (void)
+{
+ return get_compile_context
+ <compile_c_instance, gcc_c_fe_context_function, gcc_c_context,
+ gcc_base_api_version, gcc_c_api_version>
+ (STRINGIFY (GCC_C_FE_LIBCC), STRINGIFY (GCC_C_FE_CONTEXT),
+ GCC_FE_VERSION_0, GCC_C_FE_VERSION_0);
+}
+
+/* A C++-language implementation of get_compile_context. */
+
+compile_instance *
+cplus_get_compile_context (void)
+{
+ return get_compile_context
+ <compile_cplus_instance, gcc_cp_fe_context_function, gcc_cp_context,
+ gcc_base_api_version, gcc_cp_api_version>
+ (STRINGIFY (GCC_CP_FE_LIBCC), STRINGIFY (GCC_CP_FE_CONTEXT),
+ GCC_FE_VERSION_0, GCC_CP_FE_VERSION_0);
}

\f
@@ -384,6 +411,113 @@ struct c_add_input
}
};

+/* C++-language policy to emit a push user expression pragma into
+ BUF. */
+
+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. */
+
+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. */
+
+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:
+ fputs_unfiltered (
+ "#include <cstring>\n"
+ "#include <bits/move.h>\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."));
+ }
+ }
+};
+
+/* 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_VALUE_SCOPE:
+ case COMPILE_I_PRINT_ADDRESS_SCOPE:
+ fprintf_unfiltered
+ (buf,
+ /* "auto" strips ref- and cv- qualifiers, so we need to also strip
+ those from COMPILE_I_EXPR_PTR_TYPE. */
+ "auto " COMPILE_I_EXPR_VAL " = %s;\n"
+ "typedef "
+ "std::add_pointer<std::remove_cv<decltype (%s)>::type>::type "
+ " __gdb_expr_ptr;\n"
+ "__gdb_expr_ptr " COMPILE_I_EXPR_PTR_TYPE ";\n"
+ "std::memcpy (" COMPILE_I_PRINT_OUT_ARG ", %s ("
+ COMPILE_I_EXPR_VAL "),\n"
+ "\tsizeof (*" COMPILE_I_EXPR_PTR_TYPE "));\n"
+ ,input, input,
+ (type == COMPILE_I_PRINT_ADDRESS_SCOPE
+ ? "__builtin_addressof" : ""));
+ 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
@@ -513,13 +647,18 @@ private:
struct gdbarch *m_arch;
};

-/* Type used for C program computations. */
+/* The types used for C and C++ program computations. */

typedef compile_program<compile_c_instance,
c_push_user_expression, pop_user_expression_nop,
c_add_code_header, c_add_code_footer,
c_add_input> c_compile_program;

+typedef compile_program<compile_cplus_instance,
+ cplus_push_user_expression, cplus_pop_user_expression,
+ cplus_add_code_header, c_add_code_footer,
+ cplus_add_input> cplus_compile_program;
+
/* The la_compute_program method for C. */

std::string
@@ -534,3 +673,19 @@ c_compute_program (compile_instance *inst,

return program.compute (input, expr_block, expr_pc);
}
+
+/* The la_compute_program method for C++. */
+
+std::string
+cplus_compute_program (compile_instance *inst,
+ const char *input,
+ struct gdbarch *gdbarch,
+ const struct block *expr_block,
+ CORE_ADDR expr_pc)
+{
+ compile_cplus_instance *cplus_inst
+ = static_cast<compile_cplus_instance *> (inst);
+ cplus_compile_program program (cplus_inst, gdbarch);
+
+ return program.compute (input, expr_block, expr_pc);
+}
diff --git a/gdb/compile/compile-cplus-support.c b/gdb/compile/compile-cplus-support.c
new file mode 100644
index 0000000000..42fc7692c4
--- /dev/null
+++ b/gdb/compile/compile-cplus-support.c
@@ -0,0 +1,30 @@
+/* C++ language support for compilation.
+
+ Copyright (C) 2015-2018 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 "gcc-cp-interface.h"
+
+void
+gcc_cplus_enter_scope (void *datum, struct gcc_cp_context *gcc_context)
+{
+}
+
+void
+gcc_cplus_leave_scope (void *datum, struct gcc_cp_context *gcc_context)
+{
+}
diff --git a/gdb/compile/compile-cplus-symbols.c b/gdb/compile/compile-cplus-symbols.c
new file mode 100644
index 0000000000..8e7be596d3
--- /dev/null
+++ b/gdb/compile/compile-cplus-symbols.c
@@ -0,0 +1,511 @@
+/* Convert symbols from GDB to GCC
+
+ Copyright (C) 2014-2018 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 "gdb_assert.h"
+#include "symtab.h"
+#include "parser-defs.h"
+#include "block.h"
+#include "objfiles.h"
+#include "compile.h"
+#include "value.h"
+#include "exceptions.h"
+#include "gdbtypes.h"
+#include "dwarf2loc.h"
+#include "cp-support.h"
+#include "gdbcmd.h"
+#include "compile-c.h"
+
+/* See description in compile-internal.h. */
+
+int debug_compile_oracle = 0;
+
+/* Convert a given symbol, SYM, to the compiler's representation.
+ INSTANCE is the compiler instance. IS_GLOBAL is true if the
+ symbol came from the global scope. IS_LOCAL is true if the symbol
+ came from a local scope. (Note that the two are not strictly
+ inverses because the symbol might have come from the static
+ scope.) */
+
+static void
+convert_one_symbol (compile_cplus_instance *instance,
+ struct block_symbol sym, bool is_global, bool is_local)
+{
+ /* Squash compiler warning. */
+ gcc_type sym_type = 0;
+ const char *filename = symbol_symtab (sym.symbol)->filename;
+ unsigned short line = SYMBOL_LINE (sym.symbol);
+
+ instance->error_symbol_once (sym.symbol);
+
+ if (SYMBOL_CLASS (sym.symbol) == LOC_LABEL)
+ sym_type = 0;
+ else
+ sym_type = instance->convert_type (SYMBOL_TYPE (sym.symbol));
+
+ if (SYMBOL_DOMAIN (sym.symbol) == STRUCT_DOMAIN)
+ {
+ /* Nothing to do. */
+ }
+ else
+ {
+ /* Squash compiler warning. */
+ gcc_cp_symbol_kind_flags kind = GCC_CP_FLAG_BASE;
+ CORE_ADDR addr = 0;
+ std::string name;
+ gdb::unique_xmalloc_ptr<char> symbol_name;
+
+ switch (SYMBOL_CLASS (sym.symbol))
+ {
+ case LOC_TYPEDEF:
+ if (TYPE_CODE (SYMBOL_TYPE (sym.symbol)) == TYPE_CODE_TYPEDEF)
+ kind = GCC_CP_SYMBOL_TYPEDEF;
+ else if (TYPE_CODE (SYMBOL_TYPE (sym.symbol)) == TYPE_CODE_NAMESPACE)
+ return;
+ break;
+
+ case LOC_LABEL:
+ kind = GCC_CP_SYMBOL_LABEL;
+ addr = SYMBOL_VALUE_ADDRESS (sym.symbol);
+ break;
+
+ case LOC_BLOCK:
+ {
+ kind = GCC_CP_SYMBOL_FUNCTION;
+ addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym.symbol));
+ if (is_global && TYPE_GNU_IFUNC (SYMBOL_TYPE (sym.symbol)))
+ addr = gnu_ifunc_resolve_addr (target_gdbarch (), addr);
+ }
+ break;
+
+ case LOC_CONST:
+ if (TYPE_CODE (SYMBOL_TYPE (sym.symbol)) == TYPE_CODE_ENUM)
+ {
+ /* Already handled by convert_enum. */
+ return;
+ }
+ instance->plugin ().build_constant
+ (sym_type, SYMBOL_NATURAL_NAME (sym.symbol),
+ SYMBOL_VALUE (sym.symbol), filename, line);
+ return;
+
+ case LOC_CONST_BYTES:
+ error (_("Unsupported LOC_CONST_BYTES for symbol \"%s\"."),
+ SYMBOL_PRINT_NAME (sym.symbol));
+
+ case LOC_UNDEF:
+ internal_error (__FILE__, __LINE__, _("LOC_UNDEF found for \"%s\"."),
+ SYMBOL_PRINT_NAME (sym.symbol));
+
+ case LOC_COMMON_BLOCK:
+ error (_("Fortran common block is unsupported for compilation "
+ "evaluaton of symbol \"%s\"."),
+ SYMBOL_PRINT_NAME (sym.symbol));
+
+ case LOC_OPTIMIZED_OUT:
+ error (_("Symbol \"%s\" cannot be used for compilation evaluation "
+ "as it is optimized out."),
+ SYMBOL_PRINT_NAME (sym.symbol));
+
+ case LOC_COMPUTED:
+ if (is_local)
+ goto substitution;
+ /* Probably TLS here. */
+ warning (_("Symbol \"%s\" is thread-local and currently can only "
+ "be referenced from the current thread in "
+ "compiled code."),
+ SYMBOL_PRINT_NAME (sym.symbol));
+ /* FALLTHROUGH */
+ case LOC_UNRESOLVED:
+ /* 'symbol_name' cannot be used here as that one is used only for
+ local variables from compile_dwarf_expr_to_c.
+ Global variables can be accessed by GCC only by their address, not
+ by their name. */
+ {
+ struct value *val;
+ struct frame_info *frame = nullptr;
+
+ if (symbol_read_needs_frame (sym.symbol))
+ {
+ frame = get_selected_frame (nullptr);
+ if (frame == nullptr)
+ error (_("Symbol \"%s\" cannot be used because "
+ "there is no selected frame"),
+ SYMBOL_PRINT_NAME (sym.symbol));
+ }
+
+ val = read_var_value (sym.symbol, sym.block, frame);
+ if (VALUE_LVAL (val) != lval_memory)
+ error (_("Symbol \"%s\" cannot be used for compilation "
+ "evaluation as its address has not been found."),
+ SYMBOL_PRINT_NAME (sym.symbol));
+
+ kind = GCC_CP_SYMBOL_VARIABLE;
+ addr = value_address (val);
+ }
+ break;
+
+
+ case LOC_REGISTER:
+ case LOC_ARG:
+ case LOC_REF_ARG:
+ case LOC_REGPARM_ADDR:
+ case LOC_LOCAL:
+ substitution:
+ kind = GCC_CP_SYMBOL_VARIABLE;
+ symbol_name = c_symbol_substitution_name (sym.symbol);
+ break;
+
+ case LOC_STATIC:
+ kind = GCC_CP_SYMBOL_VARIABLE;
+ addr = SYMBOL_VALUE_ADDRESS (sym.symbol);
+ break;
+
+ case LOC_FINAL_VALUE:
+ default:
+ gdb_assert_not_reached ("Unreachable case in convert_one_symbol.");
+ }
+
+ /* Don't emit local variable decls for a raw expression. */
+ if (instance->scope () != COMPILE_I_RAW_SCOPE || symbol_name == nullptr)
+ {
+ compile_scope scope;
+
+ /* For non-local symbols, create/push a new scope so that the
+ symbol is properly scoped to the plug-in. */
+ if (!is_local)
+ {
+ scope
+ = instance->new_scope (SYMBOL_NATURAL_NAME (sym.symbol),
+ SYMBOL_TYPE (sym.symbol));
+ if (scope.nested_type () != GCC_TYPE_NONE)
+ {
+ /* We found a symbol for this type that was defined inside
+ some other symbol, e.g., a class tyepdef defined. */
+ return;
+ }
+
+ instance->enter_scope (scope);
+ }
+
+ /* Get the `raw' name of the symbol. */
+ if (name.empty () && SYMBOL_NATURAL_NAME (sym.symbol) != nullptr)
+ name = decl_name (SYMBOL_NATURAL_NAME (sym.symbol)).get ();
+
+ /* Define the decl. */
+ instance->plugin ().build_decl
+ ("variable", name.c_str (), kind, sym_type,
+ symbol_name.get (), addr, filename, line);
+
+ /* Pop scope for non-local symbols. */
+ if (!is_local)
+ instance->leave_scope ();
+ }
+ }
+}
+
+/* Convert a full symbol to its gcc form. CONTEXT is the compiler to
+ use, IDENTIFIER is the name of the symbol, SYM is the symbol
+ itself, and DOMAIN is the domain which was searched. */
+
+static void
+convert_symbol_sym (compile_cplus_instance *instance,
+ const char *identifier, struct block_symbol sym,
+ domain_enum domain)
+{
+ /* If we found a symbol and it is not in the static or global
+ scope, then we should first convert any static or global scope
+ symbol of the same name. This lets this unusual case work:
+
+ int x; // Global.
+ int func(void)
+ {
+ int x;
+ // At this spot, evaluate "extern int x; x"
+ }
+ */
+
+ const struct block *static_block = block_static_block (sym.block);
+ /* STATIC_BLOCK is NULL if FOUND_BLOCK is the global block. */
+ bool is_local_symbol = (sym.block != static_block && static_block != nullptr);
+ if (is_local_symbol)
+ {
+ struct block_symbol global_sym;
+
+ global_sym = lookup_symbol (identifier, nullptr, domain, nullptr);
+ /* If the outer symbol is in the static block, we ignore it, as
+ it cannot be referenced. */
+ if (global_sym.symbol != nullptr
+ && global_sym.block != block_static_block (global_sym.block))
+ {
+ if (compile_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "gcc_convert_symbol \"%s\": global symbol\n",
+ identifier);
+ convert_one_symbol (instance, global_sym, true, false);
+ }
+ }
+
+ if (compile_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "gcc_convert_symbol \"%s\": local symbol\n",
+ identifier);
+ convert_one_symbol (instance, sym, false, is_local_symbol);
+}
+
+/* Convert a minimal symbol to its gcc form. CONTEXT is the compiler
+ to use and BMSYM is the minimal symbol to convert. */
+
+static void
+convert_symbol_bmsym (compile_cplus_instance *instance,
+ struct bound_minimal_symbol bmsym)
+{
+ struct minimal_symbol *msym = bmsym.minsym;
+ struct objfile *objfile = bmsym.objfile;
+ struct type *type;
+ gcc_cp_symbol_kind_flags kind;
+ gcc_type sym_type;
+ CORE_ADDR addr;
+
+ addr = MSYMBOL_VALUE_ADDRESS (objfile, msym);
+
+ /* Conversion copied from write_exp_msymbol. */
+ switch (MSYMBOL_TYPE (msym))
+ {
+ case mst_text:
+ case mst_file_text:
+ case mst_solib_trampoline:
+ type = objfile_type (objfile)->nodebug_text_symbol;
+ kind = GCC_CP_SYMBOL_FUNCTION;
+ break;
+
+ case mst_text_gnu_ifunc:
+ /* nodebug_text_gnu_ifunc_symbol would cause:
+ function return type cannot be function */
+ type = objfile_type (objfile)->nodebug_text_symbol;
+ kind = GCC_CP_SYMBOL_FUNCTION;
+ addr = gnu_ifunc_resolve_addr (target_gdbarch (), addr);
+ break;
+
+ case mst_data:
+ case mst_file_data:
+ case mst_bss:
+ case mst_file_bss:
+ type = objfile_type (objfile)->nodebug_data_symbol;
+ kind = GCC_CP_SYMBOL_VARIABLE;
+ break;
+
+ case mst_slot_got_plt:
+ type = objfile_type (objfile)->nodebug_got_plt_symbol;
+ kind = GCC_CP_SYMBOL_FUNCTION;
+ break;
+
+ default:
+ type = objfile_type (objfile)->nodebug_unknown_symbol;
+ kind = GCC_CP_SYMBOL_VARIABLE;
+ break;
+ }
+
+ sym_type = instance->convert_type (type);
+ instance->plugin ().push_namespace ("");
+ instance->plugin ().build_decl
+ ("minsym", MSYMBOL_NATURAL_NAME (msym), kind, sym_type, nullptr, addr,
+ nullptr, 0);
+ instance->plugin ().pop_binding_level ("");
+}
+
+/* See compile-cplus.h. */
+
+void
+gcc_cplus_convert_symbol (void *datum,
+ struct gcc_cp_context *gcc_context,
+ enum gcc_cp_oracle_request request ATTRIBUTE_UNUSED,
+ const char *identifier)
+{
+ if (debug_compile_oracle)
+ fprintf_unfiltered (gdb_stdlog,
+ "got oracle request for \"%s\"\n", identifier);
+
+ bool found = false;
+ compile_cplus_instance *instance = (compile_cplus_instance *) datum;
+
+ TRY
+ {
+ /* Symbol searching is a three part process unfortunately. */
+
+ /* First do a "standard" lookup, converting any found symbols.
+ This will find variables in the current scope. */
+
+ struct block_symbol sym
+ = lookup_symbol (identifier, instance->block (), VAR_DOMAIN, nullptr);
+
+ if (sym.symbol != nullptr)
+ {
+ found = true;
+ convert_symbol_sym (instance, identifier, sym, VAR_DOMAIN);
+ }
+
+ /* Then use linespec.c's multi-symbol search. This should find
+ all non-variable symbols for which we have debug info. */
+
+ symbol_searcher searcher;
+ searcher.find_all_symbols (identifier, current_language,
+ ALL_DOMAIN, nullptr, nullptr);
+
+ /* Convert any found symbols. */
+ for (const auto &it : searcher.matching_symbols ())
+ {
+ found = true;
+ convert_symbol_sym (instance, identifier, it,
+ SYMBOL_DOMAIN (it.symbol));
+ }
+
+ /* Finally, if no symbols have been found, fall back to minsyms. */
+ if (!found)
+ {
+ for (const auto &it : searcher.matching_msymbols ())
+ {
+ found = true;
+ convert_symbol_bmsym (instance, it);
+ }
+ }
+ }
+ CATCH (e, RETURN_MASK_ALL)
+ {
+ /* We can't allow exceptions to escape out of this callback. Safest
+ is to simply emit a gcc error. */
+ instance->plugin ().error (e.message);
+ }
+ END_CATCH
+
+ if (compile_debug && !found)
+ fprintf_unfiltered (gdb_stdlog,
+ "gcc_convert_symbol \"%s\": lookup_symbol failed\n",
+ identifier);
+
+ if (debug_compile_oracle)
+ {
+ if (found)
+ fprintf_unfiltered (gdb_stdlog, "found type for %s\n", identifier);
+ else
+ {
+ fprintf_unfiltered (gdb_stdlog, "did not find type for %s\n",
+ identifier);
+ }
+ }
+
+ return;
+}
+
+/* See compile-cplus.h. */
+
+gcc_address
+gcc_cplus_symbol_address (void *datum, struct gcc_cp_context *gcc_context,
+ const char *identifier)
+{
+ compile_cplus_instance *instance = (compile_cplus_instance *) datum;
+ gcc_address result = 0;
+ int found = 0;
+
+ if (debug_compile_oracle)
+ fprintf_unfiltered (gdb_stdlog,
+ "got oracle request for address of %s\n", identifier);
+
+ /* We can't allow exceptions to escape out of this callback. Safest
+ is to simply emit a gcc error. */
+ TRY
+ {
+ struct symbol *sym
+ = lookup_symbol (identifier, nullptr, VAR_DOMAIN, nullptr).symbol;
+
+ if (sym != nullptr && SYMBOL_CLASS (sym) == LOC_BLOCK)
+ {
+ if (compile_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "gcc_symbol_address \"%s\": full symbol\n",
+ identifier);
+ result = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
+ if (TYPE_GNU_IFUNC (SYMBOL_TYPE (sym)))
+ result = gnu_ifunc_resolve_addr (target_gdbarch (), result);
+ found = 1;
+ }
+ else
+ {
+ struct bound_minimal_symbol msym;
+
+ msym = lookup_bound_minimal_symbol (identifier);
+ if (msym.minsym != nullptr)
+ {
+ if (compile_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "gcc_symbol_address \"%s\": minimal "
+ "symbol\n",
+ identifier);
+ result = BMSYMBOL_VALUE_ADDRESS (msym);
+ if (MSYMBOL_TYPE (msym.minsym) == mst_text_gnu_ifunc)
+ result = gnu_ifunc_resolve_addr (target_gdbarch (), result);
+ found = 1;
+ }
+ }
+ }
+
+ CATCH (e, RETURN_MASK_ERROR)
+ {
+ instance->plugin ().error (e.message);
+ }
+ END_CATCH
+
+ if (compile_debug && !found)
+ fprintf_unfiltered (gdb_stdlog,
+ "gcc_symbol_address \"%s\": failed\n",
+ identifier);
+
+ if (debug_compile_oracle)
+ {
+ if (found)
+ fprintf_unfiltered (gdb_stdlog, "found address for %s!\n", identifier);
+ else
+ fprintf_unfiltered (gdb_stdlog,
+ "did not find address for %s\n", identifier);
+ }
+
+ return result;
+}
+
+\f
+
+void _initialize_compile_cplus_symbols (void);
+
+void
+_initialize_compile_cplus_symbols (void)
+{
+ add_setshow_boolean_cmd ("compile-oracle", no_class,
+ &debug_compile_oracle, _("\
+Set debugging of compiler plug-in oracle requests."), _("\
+Show debugging of compiler plug-in oracle requests."), _("\
+When enabled debugging messages are printed for compiler plug-in\n\
+oracle requests."),
+ nullptr,
+ nullptr,
+ &setdebuglist,
+ &showdebuglist);
+}
diff --git a/gdb/compile/compile-cplus-types.c b/gdb/compile/compile-cplus-types.c
new file mode 100644
index 0000000000..3e197834fc
--- /dev/null
+++ b/gdb/compile/compile-cplus-types.c
@@ -0,0 +1,1430 @@
+/* Convert types from GDB to GCC
+
+ Copyright (C) 2014-2018 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 "common/preprocessor.h"
+#include "gdbtypes.h"
+#include "compile-internal.h"
+#include "compile-cplus.h"
+#include "gdb_assert.h"
+#include "symtab.h"
+#include "source.h"
+#include "cp-support.h"
+#include "cp-abi.h"
+#include "symtab.h"
+#include "objfiles.h"
+#include "block.h"
+#include "gdbcmd.h"
+#include "c-lang.h"
+#include "compile-c.h" /* Included for c_get_range_decl_name
+ et al. */
+#include <algorithm>
+
+/* Default compile flags for C++. */
+
+const char *compile_cplus_instance::m_default_cflags = "-std=gnu++11";
+
+/* Flag to enable internal debugging. */
+
+static int debug_compile_cplus_types = 0;
+
+/* Flag to enable internal scope switching debugging. */
+
+static int debug_compile_cplus_scopes = 0;
+
+/* Forward declarations. */
+
+static gcc_type compile_cplus_convert_func (compile_cplus_instance *instance,
+ struct type *type,
+ bool strip_artificial);
+
+/* See description in compile-cplus.h. */
+
+gdb::unique_xmalloc_ptr<char>
+decl_name (const char *natural)
+{
+ if (natural == nullptr)
+ return nullptr;
+
+ char *name = cp_func_name (natural);
+ if (name != nullptr)
+ return gdb::unique_xmalloc_ptr<char> (name);
+
+ return gdb::unique_xmalloc_ptr<char> (xstrdup (natural));
+}
+
+/* Get the access flag for the NUM'th field of TYPE. */
+
+static enum gcc_cp_symbol_kind
+get_field_access_flag (const struct type *type, int num)
+{
+ if (TYPE_FIELD_PROTECTED (type, num))
+ return GCC_CP_ACCESS_PROTECTED;
+ else if (TYPE_FIELD_PRIVATE (type, num))
+ return GCC_CP_ACCESS_PRIVATE;
+
+ /* GDB assumes everything else is public. */
+ return GCC_CP_ACCESS_PUBLIC;
+}
+
+/* Get the access flag for the NUM'th method of TYPE's FNI'th
+ fieldlist. */
+
+enum gcc_cp_symbol_kind
+get_method_access_flag (const struct type *type, int fni, int num)
+{
+ gdb_assert (TYPE_CODE (type) == TYPE_CODE_STRUCT);
+
+ /* If this type was not declared a class, everything is public. */
+ if (!TYPE_DECLARED_CLASS (type))
+ return GCC_CP_ACCESS_PUBLIC;
+
+ /* Otherwise, read accessibility from the fn_field. */
+ const struct fn_field *methods = TYPE_FN_FIELDLIST1 (type, fni);
+ if (TYPE_FN_FIELD_PROTECTED (methods, num))
+ return GCC_CP_ACCESS_PROTECTED;
+ else if (TYPE_FN_FIELD_PRIVATE (methods, num))
+ return GCC_CP_ACCESS_PRIVATE;
+ else
+ return GCC_CP_ACCESS_PUBLIC;
+}
+
+/* A useful debugging function to output the scope SCOPE to stdout. */
+
+static void __attribute__ ((used))
+debug_print_scope (const compile_scope &scope)
+{
+ for (const auto &comp: scope)
+ {
+ std::string symbol = (comp.bsymbol.symbol != nullptr
+ ? SYMBOL_NATURAL_NAME (comp.bsymbol.symbol)
+ : "<none>");
+
+ printf_unfiltered ("\tname = %s, symbol = %s\n", comp.name.c_str (),
+ symbol.c_str ());
+ }
+}
+
+/* Utility function to convert CODE into a string. */
+
+static const char *
+type_code_to_string (enum type_code code)
+{
+ const char * const s[] =
+ {"BISTRING (deprecated)", "UNDEF (not used)",
+ "PTR", "ARRAY", "STRUCT", "UNION", "ENUM",
+ "FLAGS", "FUNC", "INT", "FLT", "VOID",
+ "SET", "RANGE", "STRING", "ERROR", "METHOD",
+ "METHODPTR", "MEMBERPTR", "REF", "RVALUE_REF", "CHAR", "BOOL",
+ "COMPLEX", "TYPEDEF", "NAMESPACE", "DECFLOAT", "MODULE",
+ "INTERNAL_FUNCTION", "XMETHOD"};
+
+ return s[code + 1];
+}
+
+/* See description in compile-cplus.h. */
+
+compile_scope
+type_name_to_scope (const char *type_name, const struct block *block)
+{
+ compile_scope scope;
+
+ if (type_name == nullptr)
+ {
+ /* An anonymous type. We cannot really do much here. We simply cannot
+ look up anonymous types easily/at all. */
+ return scope;
+ }
+
+ const char *p = type_name;
+ std::string lookup_name;
+
+ while (*p != '\0')
+ {
+ /* Create a string token of the first component of TYPE_NAME. */
+ int len = cp_find_first_component (p);
+ std::string s (p, len);
+
+ /* Advance past the last token. */
+ p += len;
+
+ /* Look up the symbol and decide when to stop. */
+ if (!lookup_name.empty ())
+ lookup_name += "::";
+ lookup_name += s;
+
+ /* Look up the resulting name. */
+ struct block_symbol bsymbol
+ = lookup_symbol (lookup_name.c_str (), block, VAR_DOMAIN, nullptr);
+
+ if (bsymbol.symbol != nullptr)
+ {
+ scope_component comp = {s, bsymbol};
+
+ scope.push_back (comp);
+
+ if (TYPE_CODE (SYMBOL_TYPE (bsymbol.symbol)) != TYPE_CODE_NAMESPACE)
+ {
+ /* We're done. */
+ break;
+ }
+ }
+
+ if (*p == ':')
+ {
+ ++p;
+ if (*p == ':')
+ ++p;
+ else
+ {
+ /* This shouldn't happen since we are not attempting to
+ loop over user input. This name is generated by GDB
+ from debug info. */
+ internal_error (__FILE__, __LINE__,
+ _("malformed TYPE_NAME during parsing"));
+ }
+ }
+ }
+
+ return scope;
+}
+
+/* Compare two scope_components for equality. These are equal if the names
+ of the two components' are the same. */
+
+bool
+operator== (const scope_component &lhs, const scope_component &rhs)
+{
+ return lhs.name == rhs.name;
+}
+
+/* Compare two scope_components for inequality. These are not equal if
+ the two components' names are not equal. */
+
+bool
+operator!= (const scope_component &lhs, const scope_component &rhs)
+{
+ return lhs.name != rhs.name;
+}
+
+/* Compare two compile_scopes for equality. These are equal if they are both
+ contain the same number of components and each component is equal. */
+
+bool
+operator== (const compile_scope &lhs, const compile_scope &rhs)
+{
+ if (lhs.size () != rhs.size ())
+ return false;
+
+ for (int i = 0; i < lhs.size (); ++i)
+ {
+ if (lhs[i] != rhs[i])
+ return false;
+ }
+
+ return true;
+}
+
+/* Compare two compile_scopes for inequality. These are inequal if they
+ contain unequal number of elements or if any of the components are not
+ the same. */
+
+bool
+operator!= (const compile_scope &lhs, const compile_scope &rhs)
+{
+ if (lhs.size () != rhs.size ())
+ return true;
+
+ for (int i = 0; i < lhs.size (); ++i)
+ {
+ if (lhs[i] != rhs[i])
+ return true;
+ }
+
+ return false;
+}
+
+/* See description in compile-cplus.h. */
+
+void
+compile_cplus_instance::enter_scope (compile_scope &new_scope)
+{
+ bool must_push = m_scopes.empty () || m_scopes.back () != new_scope;
+
+ new_scope.m_pushed = must_push;
+
+ /* Save the new scope. */
+ m_scopes.push_back (new_scope);
+
+ if (must_push)
+ {
+ if (debug_compile_cplus_scopes)
+ fprintf_unfiltered (gdb_stdlog, "entering new scope %p\n", new_scope);
+
+ /* Push the global namespace. */
+ plugin ().push_namespace ("");
+
+ /* Push all other namespaces. Note that we do not push the last
+ scope_component -- that's the actual type we are converting. */
+ std::for_each
+ (new_scope.begin (), new_scope.end () - 1,
+ [this] (const scope_component &comp)
+ {
+ gdb_assert (TYPE_CODE (SYMBOL_TYPE (comp.bsymbol.symbol))
+ == TYPE_CODE_NAMESPACE);
+
+ const char *ns = (comp.name == CP_ANONYMOUS_NAMESPACE_STR ? nullptr
+ : comp.name.c_str ());
+
+ this->plugin ().push_namespace (ns);
+ });
+ }
+ else
+ {
+ if (debug_compile_cplus_scopes)
+ {
+ fprintf_unfiltered (gdb_stdlog, "staying in current scope -- "
+ "scopes are identical\n");
+ }
+ }
+}
+
+/* See description in compile-cplus.h. */
+
+void
+compile_cplus_instance::leave_scope ()
+{
+ /* Get the current scope and remove it from the internal list of
+ scopes. */
+ compile_scope current = m_scopes.back ();
+
+ m_scopes.pop_back ();
+
+ if (current.m_pushed)
+ {
+ if (debug_compile_cplus_scopes)
+ fprintf_unfiltered (gdb_stdlog, "leaving scope %p\n", current);
+
+ /* Pop namespaces. */
+ std::for_each
+ (current.begin (),current.end () - 1,
+ [this] (const scope_component &comp) {
+ gdb_assert (TYPE_CODE (SYMBOL_TYPE (comp.bsymbol.symbol))
+ == TYPE_CODE_NAMESPACE);
+ this->plugin ().pop_binding_level (comp.name.c_str ());
+ });
+
+ /* Pop global namespace. */
+ plugin ().pop_binding_level ("");
+ }
+ else
+ {
+ if (debug_compile_cplus_scopes)
+ fprintf_unfiltered (gdb_stdlog,
+ "identical scopes -- not leaving scope\n");
+ }
+}
+
+/* See description in compile-cplus.h. */
+
+compile_scope
+compile_cplus_instance::new_scope (const char *type_name, struct type *type)
+{
+ /* Break the type name into components. If TYPE was defined in some
+ superclass, we do not process TYPE but process the enclosing type
+ instead. */
+ compile_scope scope = type_name_to_scope (type_name, block ());
+
+ if (!scope.empty ())
+ {
+ /* Get the name of the last component, which should be the
+ unqualified name of the type to process. */
+ scope_component &comp = scope.back ();
+
+ if (!types_equal (type, SYMBOL_TYPE (comp.bsymbol.symbol))
+ && (m_scopes.empty ()
+ || (m_scopes.back ().back ().bsymbol.symbol
+ != comp.bsymbol.symbol)))
+ {
+ /* The type is defined inside another class(es). Convert that
+ type instead of defining this type. */
+ convert_type (SYMBOL_TYPE (comp.bsymbol.symbol));
+
+ /* If the original type (passed in to us) is defined in a nested
+ class, the previous call will give us that type's gcc_type.
+ Upper layers are expecting to get the original type's
+ gcc_type! */
+ get_cached_type (type, scope.m_nested_type);
+ return scope;
+ }
+ }
+ else
+ {
+ if (TYPE_NAME (type) == nullptr)
+ {
+ /* Anonymous type */
+
+ /* We don't have a qualified name for this to look up, but
+ we need a scope. We have to assume, then, that it is the same
+ as the current scope, if any. */
+ if (!m_scopes.empty ())
+ {
+ scope = m_scopes.back ();
+ scope.m_pushed = false;
+ }
+ else
+ scope.push_back (scope_component ());
+ }
+ else
+ {
+ scope_component comp
+ = {
+ decl_name (TYPE_NAME (type)).release (),
+ lookup_symbol (TYPE_NAME (type), block (), VAR_DOMAIN, nullptr)
+ };
+ scope.push_back (comp);
+ }
+ }
+
+ /* There must be at least one component in the compile_scope. */
+ gdb_assert (scope.size () > 0);
+ return scope;
+}
+
+/* See description in compile-cplus.h. */
+
+gcc_type
+compile_cplus_instance::convert_reference_base
+ (gcc_type base, enum gcc_cp_ref_qualifiers rquals)
+{
+ return this->plugin ().build_reference_type (base, rquals);
+}
+
+/* Convert a reference type to its gcc representation. */
+
+static gcc_type
+compile_cplus_convert_reference (compile_cplus_instance *instance,
+ struct type *type)
+{
+ gcc_type target = instance->convert_type (TYPE_TARGET_TYPE (type));
+
+ enum gcc_cp_ref_qualifiers quals = GCC_CP_REF_QUAL_NONE;
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_REF:
+ quals = GCC_CP_REF_QUAL_LVALUE;
+ break;
+ case TYPE_CODE_RVALUE_REF:
+ quals = GCC_CP_REF_QUAL_RVALUE;
+ break;
+ default:
+ gdb_assert_not_reached ("unexpected type code for reference type");
+ }
+
+ return instance->convert_reference_base (target, quals);
+}
+
+/* See description in compile-cplus.h. */
+
+gcc_type
+compile_cplus_instance::convert_pointer_base(gcc_type target)
+{
+ return plugin ().build_pointer_type (target);
+}
+
+/* Convert a pointer type to its gcc representation. */
+
+static gcc_type
+compile_cplus_convert_pointer (compile_cplus_instance *instance,
+ struct type *type)
+{
+ gcc_type target = instance->convert_type (TYPE_TARGET_TYPE (type));
+
+ return instance->convert_pointer_base (target);
+}
+
+/* Convert an array type to its gcc representation. */
+
+static gcc_type
+compile_cplus_convert_array (compile_cplus_instance *instance,
+ struct type *type)
+{
+ struct type *range = TYPE_INDEX_TYPE (type);
+ gcc_type element_type = instance->convert_type (TYPE_TARGET_TYPE (type));
+
+ if (TYPE_LOW_BOUND_KIND (range) != PROP_CONST)
+ {
+ const char *s = _("array type with non-constant"
+ " lower bound is not supported");
+
+ return instance->plugin ().error (s);
+ }
+
+ if (TYPE_LOW_BOUND (range) != 0)
+ {
+ const char *s = _("cannot convert array type with "
+ "non-zero lower bound to C");
+
+ return instance->plugin ().error (s);
+ }
+
+ if (TYPE_HIGH_BOUND_KIND (range) == PROP_LOCEXPR
+ || TYPE_HIGH_BOUND_KIND (range) == PROP_LOCLIST)
+ {
+ if (TYPE_VECTOR (type))
+ {
+ const char *s = _("variably-sized vector type is not supported");
+
+ return instance->plugin ().error (s);
+ }
+
+ std::string upper_bound
+ = c_get_range_decl_name (&TYPE_RANGE_DATA (range)->high);
+ return instance->plugin ().build_vla_array_type (element_type,
+ upper_bound.c_str ());
+ }
+ else
+ {
+ LONGEST low_bound, high_bound, count;
+
+ if (get_array_bounds (type, &low_bound, &high_bound) == 0)
+ count = -1;
+ else
+ {
+ gdb_assert (low_bound == 0); /* Ensured above. */
+ count = high_bound + 1;
+ }
+
+ if (TYPE_VECTOR (type))
+ return instance->plugin ().build_vector_type (element_type, count);
+
+ return instance->plugin ().build_array_type (element_type, count);
+ }
+}
+
+/* Convert a typedef of TYPE. If not GCC_CP_ACCESS_NONE, NESTED_ACCESS
+ will define the accessibility of the typedef definition in its
+ containing class. */
+
+static gcc_type
+compile_cplus_convert_typedef (compile_cplus_instance *instance,
+ struct type *type,
+ enum gcc_cp_symbol_kind nested_access)
+{
+ compile_scope scope = instance->new_scope (TYPE_NAME (type), type);
+
+ if (scope.nested_type () != GCC_TYPE_NONE)
+ return scope.nested_type ();
+
+ gdb::unique_xmalloc_ptr<char> name = decl_name (TYPE_NAME (type));
+
+ /* Make sure the scope for this type has been pushed. */
+ instance->enter_scope (scope);
+
+ /* Convert the typedef's real type. */
+ gcc_type typedef_type = instance->convert_type (check_typedef (type));
+
+ instance->plugin ().build_decl ("typedef", name.get (),
+ GCC_CP_SYMBOL_TYPEDEF | nested_access,
+ typedef_type, 0, 0, nullptr, 0);
+
+ /* Completed this scope. */
+ instance->leave_scope ();
+ return typedef_type;
+}
+
+/* Convert types defined in TYPE. */
+
+static void
+compile_cplus_convert_type_defns (compile_cplus_instance *instance,
+ struct type *type)
+{
+ int i;
+ enum gcc_cp_symbol_kind accessibility;
+
+ /* Convert typedefs. */
+ for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (type); ++i)
+ {
+ if (TYPE_TYPEDEF_FIELD_PROTECTED (type, i))
+ accessibility = GCC_CP_ACCESS_PROTECTED;
+ else if (TYPE_TYPEDEF_FIELD_PRIVATE (type, i))
+ accessibility = GCC_CP_ACCESS_PRIVATE;
+ else
+ accessibility = GCC_CP_ACCESS_PUBLIC;
+ instance->convert_type (TYPE_TYPEDEF_FIELD_TYPE (type, i), accessibility);
+ }
+
+ /* Convert nested types. */
+ for (i = 0; i < TYPE_NESTED_TYPES_COUNT (type); ++i)
+ {
+ if (TYPE_NESTED_TYPES_FIELD_PROTECTED (type, i))
+ accessibility = GCC_CP_ACCESS_PROTECTED;
+ else if (TYPE_NESTED_TYPES_FIELD_PRIVATE (type, i))
+ accessibility = GCC_CP_ACCESS_PRIVATE;
+ else
+ accessibility = GCC_CP_ACCESS_PUBLIC;
+ instance->convert_type (TYPE_NESTED_TYPES_FIELD_TYPE (type, i),
+ accessibility);
+ }
+}
+
+/* Convert data members defined in TYPE, which should be struct/class/union
+ with gcc_type COMP_TYPE. */
+
+static void
+compile_cplus_convert_struct_or_union_members
+ (compile_cplus_instance *instance, struct type *type, gcc_type comp_type)
+{
+ for (int i = TYPE_N_BASECLASSES (type); i < TYPE_NFIELDS (type); ++i)
+ {
+ const char *field_name = TYPE_FIELD_NAME (type, i);
+
+ if (TYPE_FIELD_IGNORE (type, i)
+ || TYPE_FIELD_ARTIFICIAL (type, i))
+ continue;
+
+ /* GDB records unnamed/anonymous fields with empty string names. */
+ if (*field_name == '\0')
+ field_name = nullptr;
+
+ gcc_type field_type
+ = instance->convert_type (TYPE_FIELD_TYPE (type, i));
+
+ if (field_is_static (&TYPE_FIELD (type, i)))
+ {
+ CORE_ADDR physaddr;
+
+ switch (TYPE_FIELD_LOC_KIND (type, i))
+ {
+ case FIELD_LOC_KIND_PHYSADDR:
+ {
+ physaddr = TYPE_FIELD_STATIC_PHYSADDR (type, i);
+
+ instance->plugin ().build_decl
+ ("field physaddr", field_name,
+ (GCC_CP_SYMBOL_VARIABLE | get_field_access_flag (type, i)),
+ field_type, nullptr, physaddr, nullptr, 0);
+ }
+ break;
+
+ case FIELD_LOC_KIND_PHYSNAME:
+ {
+ const char *physname = TYPE_FIELD_STATIC_PHYSNAME (type, i);
+ struct block_symbol sym
+ = lookup_symbol (physname, instance->block (),
+ VAR_DOMAIN, nullptr);
+
+ if (sym.symbol == nullptr)
+ {
+ /* We didn't actually find the symbol. There's little
+ we can do but ignore this member. */
+ continue;
+ }
+ const char *filename = symbol_symtab (sym.symbol)->filename;
+ unsigned int line = SYMBOL_LINE (sym.symbol);
+
+ physaddr = SYMBOL_VALUE_ADDRESS (sym.symbol);
+ instance->plugin ().build_decl
+ ("field physname", field_name,
+ (GCC_CP_SYMBOL_VARIABLE| get_field_access_flag (type, i)),
+ field_type, nullptr, physaddr, filename, line);
+ }
+ break;
+
+ default:
+ gdb_assert_not_reached
+ ("unexpected static field location kind");
+ }
+ }
+ else
+ {
+ unsigned long bitsize = TYPE_FIELD_BITSIZE (type, i);
+ enum gcc_cp_symbol_kind field_flags = GCC_CP_SYMBOL_FIELD
+ | get_field_access_flag (type, i);
+
+ if (bitsize == 0)
+ bitsize = 8 * TYPE_LENGTH (TYPE_FIELD_TYPE (type, i));
+
+ instance->plugin ().build_field
+ (field_name, field_type, field_flags, bitsize,
+ TYPE_FIELD_BITPOS (type, i));
+ }
+ }
+}
+
+/* Convert a method type to its gcc representation. */
+
+static gcc_type
+compile_cplus_convert_method (compile_cplus_instance *instance,
+ struct type *parent_type,
+ struct type *method_type)
+{
+ /* Get the actual function type of the method, the corresponding class's
+ type and corresponding qualifier flags. */
+ gcc_type func_type = compile_cplus_convert_func (instance, method_type, true);
+ gcc_type class_type = instance->convert_type (parent_type);
+ gcc_cp_qualifiers_flags quals = (enum gcc_cp_qualifiers) 0;
+
+ if (TYPE_CONST (method_type))
+ quals |= GCC_CP_QUALIFIER_CONST;
+ if (TYPE_VOLATILE (method_type))
+ quals |= GCC_CP_QUALIFIER_VOLATILE;
+ if (TYPE_RESTRICT (method_type))
+ quals |= GCC_CP_QUALIFIER_RESTRICT;
+
+ /* Not yet implemented. */
+ gcc_cp_ref_qualifiers_flags rquals = GCC_CP_REF_QUAL_NONE;
+
+ return instance->plugin ().build_method_type
+ (class_type, func_type, quals, rquals);
+}
+
+/* Convert a member or method pointer represented by TYPE. */
+
+static gcc_type
+compile_cplus_convert_memberptr (compile_cplus_instance *instance,
+ struct type *type)
+{
+ struct type *containing_class = TYPE_SELF_TYPE (type);
+
+ if (containing_class == nullptr)
+ return GCC_TYPE_NONE;
+
+ gcc_type class_type = instance->convert_type (containing_class);
+ gcc_type member_type
+ = instance->convert_type (TYPE_TARGET_TYPE (type));
+
+ return instance->plugin ().build_pointer_to_member_type
+ (class_type, member_type);
+}
+
+/* Convert all methods defined in TYPE, which should be a class/struct/union
+ with gcc_type CLASS_TYPE. */
+
+static void
+compile_cplus_convert_struct_or_union_methods (compile_cplus_instance *instance,
+ struct type *type,
+ gcc_type class_type)
+{
+ for (int i = 0; i < TYPE_NFN_FIELDS (type); ++i)
+ {
+ struct fn_field *methods = TYPE_FN_FIELDLIST1 (type, i);
+ gdb::unique_xmalloc_ptr<char> overloaded_name
+ = decl_name (TYPE_FN_FIELDLIST_NAME (type, i));
+
+ /* Loop through the fieldlist, adding decls to the compiler's
+ representation of the class. */
+ for (int j = 0; j < TYPE_FN_FIELDLIST_LENGTH (type, i); ++j)
+ {
+ /* Skip artificial methods. */
+ if (TYPE_FN_FIELD_ARTIFICIAL (methods, j))
+ continue;
+
+ gcc_cp_symbol_kind_flags sym_kind = GCC_CP_SYMBOL_FUNCTION;
+ gcc_type method_type;
+ struct block_symbol sym
+ = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (methods, j),
+ instance->block (), VAR_DOMAIN, nullptr);
+
+ if (sym.symbol == nullptr)
+ {
+ if (TYPE_FN_FIELD_VIRTUAL_P (methods, j))
+ {
+ /* This is beyond hacky, and is really only a workaround for
+ detecting pure virtual methods. */
+ method_type = compile_cplus_convert_method
+ (instance, type, TYPE_FN_FIELD_TYPE (methods, j));
+
+ instance->plugin ().build_decl
+ ("pure virtual method", overloaded_name.get (),
+ (sym_kind
+ | get_method_access_flag (type, i, j)
+ | GCC_CP_FLAG_VIRTUAL_FUNCTION
+ | GCC_CP_FLAG_PURE_VIRTUAL_FUNCTION),
+ method_type, nullptr, 0, nullptr, 0);
+ continue;
+ }
+
+ /* This can happen if we have a DW_AT_declaration DIE
+ for the method, but no "definition"-type DIE (with
+ DW_AT_specification referencing the decl DIE), i.e.,
+ the compiler has probably optimized the method away.
+
+ In this case, all we can hope to do is issue a warning
+ to the user letting him know. If the user has not actually
+ requested using this method, things should still work. */
+ warning (_("Method %s appears to be optimized out.\n"
+ "All references to this method will be undefined."),
+ TYPE_FN_FIELD_PHYSNAME (methods, j));
+ continue;
+ }
+
+ const char *filename = symbol_symtab (sym.symbol)->filename;
+ unsigned int line = SYMBOL_LINE (sym.symbol);
+ CORE_ADDR address = BLOCK_START (SYMBOL_BLOCK_VALUE (sym.symbol));
+ const char *kind;
+
+ if (TYPE_FN_FIELD_STATIC_P (methods, j))
+ {
+ kind = "static method";
+ method_type = compile_cplus_convert_func
+ (instance, TYPE_FN_FIELD_TYPE (methods, j), true);
+ }
+ else
+ {
+ kind = "method";
+ method_type = (compile_cplus_convert_method
+ (instance, type, TYPE_FN_FIELD_TYPE (methods, j)));
+ }
+
+ if (TYPE_FN_FIELD_VIRTUAL_P (methods, j))
+ sym_kind |= GCC_CP_FLAG_VIRTUAL_FUNCTION;
+
+ instance->plugin ().build_decl
+ (kind, overloaded_name.get (),
+ sym_kind | get_method_access_flag (type, i, j),
+ method_type, nullptr, address, filename, line);
+ }
+ }
+}
+
+/* Convert a struct or union type to its gcc representation. If this type
+ was defined in another type, NESTED_ACCESS should indicate the
+ accessibility of this type. */
+
+static gcc_type
+compile_cplus_convert_struct_or_union (compile_cplus_instance *instance,
+ struct type *type,
+ enum gcc_cp_symbol_kind nested_access)
+{
+ const char *filename = nullptr;
+ unsigned short line = 0;
+
+ /* Get the decl name of this type. */
+ gdb::unique_xmalloc_ptr<char> name = decl_name (TYPE_NAME (type));
+
+ /* Create a new scope for TYPE. */
+ compile_scope scope = instance->new_scope (TYPE_NAME (type), type);
+
+ if (scope.nested_type () != GCC_TYPE_NONE)
+ {
+ /* The type requested was actually defined inside another type,
+ such as a nested class definition. Return that type. */
+ return scope.nested_type ();
+ }
+
+ /* Push all scopes. */
+ instance->enter_scope (scope);
+
+ /* First we create the resulting type and enter it into our hash
+ table. This lets recursive types work. */
+
+ gcc_decl resuld;
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
+ {
+ const char *what = TYPE_DECLARED_CLASS (type) ? "struct" : "class";
+
+ resuld = instance->plugin ().build_decl
+ (what, name.get (), (GCC_CP_SYMBOL_CLASS | nested_access
+ | (TYPE_DECLARED_CLASS (type)
+ ? GCC_CP_FLAG_CLASS_NOFLAG
+ : GCC_CP_FLAG_CLASS_IS_STRUCT)),
+ 0, nullptr, 0, filename, line);
+ }
+ else
+ {
+ gdb_assert (TYPE_CODE (type) == TYPE_CODE_UNION);
+ resuld = instance->plugin ().build_decl
+ ("union", name.get (), GCC_CP_SYMBOL_UNION | nested_access,
+ 0, nullptr, 0, filename, line);
+ }
+
+ gcc_type result;
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
+ {
+ struct gcc_vbase_array bases;
+ int num_baseclasses = TYPE_N_BASECLASSES (type);
+
+ memset (&bases, 0, sizeof (bases));
+
+ if (num_baseclasses > 0)
+ {
+ bases.elements = XNEWVEC (gcc_type, num_baseclasses);
+ bases.flags = XNEWVEC (enum gcc_cp_symbol_kind, num_baseclasses);
+ bases.n_elements = num_baseclasses;
+ for (int i = 0; i < num_baseclasses; ++i)
+ {
+ struct type *base_type = TYPE_BASECLASS (type, i);
+
+ bases.flags[i] = GCC_CP_SYMBOL_BASECLASS
+ | get_field_access_flag (type, i)
+ | (BASETYPE_VIA_VIRTUAL (type, i)
+ ? GCC_CP_FLAG_BASECLASS_VIRTUAL
+ : GCC_CP_FLAG_BASECLASS_NOFLAG);
+ bases.elements[i] = instance->convert_type (base_type);
+ }
+ }
+
+ result = instance->plugin ().start_class_type
+ (name.get (), resuld, &bases, filename, line);
+ xfree (bases.flags);
+ xfree (bases.elements);
+ }
+ else
+ {
+ gdb_assert (TYPE_CODE (type) == TYPE_CODE_UNION);
+ result = instance->plugin ().start_class_type
+ (name.get (), resuld, nullptr, filename, line);
+ }
+
+ instance->insert_type (type, result);
+
+ /* Add definitions. */
+ compile_cplus_convert_type_defns (instance, type);
+
+ /* Add methods. */
+ compile_cplus_convert_struct_or_union_methods (instance, type, result);
+
+ /* Add members. */
+ compile_cplus_convert_struct_or_union_members (instance, type, result);
+
+ /* All finished. */
+ instance->plugin ().finish_class_type (name.get (), TYPE_LENGTH (type));
+
+ /* Pop all scopes. */
+ instance->leave_scope ();
+ return result;
+}
+
+/* Convert an enum type to its gcc representation. If this type
+ was defined in another type, NESTED_ACCESS should indicate the
+ accessibility of this type.*/
+
+static gcc_type
+compile_cplus_convert_enum (compile_cplus_instance *instance, struct type *type,
+ enum gcc_cp_symbol_kind nested_access)
+{
+ int scoped_enum_p = FALSE;
+
+ /* Create a new scope for this type. */
+ compile_scope scope = instance->new_scope (TYPE_NAME (type), type);
+
+ if (scope.nested_type () != GCC_TYPE_NONE)
+ {
+ /* The type requested was actually defined inside another type,
+ such as a nested class definition. Return that type. */
+ return scope.nested_type ();
+ }
+
+ gdb::unique_xmalloc_ptr<char> name = decl_name (TYPE_NAME (type));
+
+ /* Push all scopes. */
+ instance->enter_scope (scope);
+
+ gcc_type int_type
+ = instance->plugin ().get_int_type (TYPE_UNSIGNED (type),
+ TYPE_LENGTH (type), nullptr);
+ gcc_type result
+ = instance->plugin ().start_enum_type (name.get (), int_type,
+ GCC_CP_SYMBOL_ENUM | nested_access
+ | (scoped_enum_p
+ ? GCC_CP_FLAG_ENUM_SCOPED
+ : GCC_CP_FLAG_ENUM_NOFLAG),
+ nullptr, 0);
+ for (int i = 0; i < TYPE_NFIELDS (type); ++i)
+ {
+ gdb::unique_xmalloc_ptr<char> fname
+ = decl_name (TYPE_FIELD_NAME (type, i));
+
+ if (TYPE_FIELD_LOC_KIND (type, i) != FIELD_LOC_KIND_ENUMVAL
+ || fname == nullptr)
+ continue;
+
+ instance->plugin ().build_enum_constant (result, fname.get (),
+ TYPE_FIELD_ENUMVAL (type, i));
+ }
+
+ /* Finish enum definition and pop scopes. */
+ instance->plugin ().finish_enum_type (result);
+ instance->leave_scope ();
+ return result;
+}
+
+/* Convert a function type to its gcc representation. This function does
+ not deal with function templates. */
+
+static gcc_type
+compile_cplus_convert_func (compile_cplus_instance *instance,
+ struct type *type, bool strip_artificial)
+{
+ int is_varargs = TYPE_VARARGS (type);
+ struct type *target_type = TYPE_TARGET_TYPE (type);
+
+ /* Functions with no debug info have no return type. Ideally we'd
+ want to fallback to the type of the cast just before the
+ function, like GDB's built-in expression parser, but we don't
+ have access to that type here. For now, fallback to int, like
+ GDB's parser used to do. */
+ if (target_type == nullptr)
+ {
+ if (TYPE_OBJFILE_OWNED (type))
+ target_type = objfile_type (TYPE_OWNER (type).objfile)->builtin_int;
+ else
+ target_type = builtin_type (TYPE_OWNER (type).gdbarch)->builtin_int;
+ warning (_("function has unknown return type; assuming int"));
+ }
+
+ /* This approach means we can't make self-referential function
+ types. Those are impossible in C, though. */
+ gcc_type return_type = instance->convert_type (target_type);
+
+ struct gcc_type_array array =
+ { TYPE_NFIELDS (type), XNEWVEC (gcc_type, TYPE_NFIELDS (type)) };
+ int artificials = 0;
+ for (int i = 0; i < TYPE_NFIELDS (type); ++i)
+ {
+ if (strip_artificial && TYPE_FIELD_ARTIFICIAL (type, i))
+ {
+ --array.n_elements;
+ ++artificials;
+ }
+ else
+ {
+ array.elements[i - artificials]
+ = instance->convert_type (TYPE_FIELD_TYPE (type, i));
+ }
+ }
+
+ /* We omit setting the argument types to `void' to be a little flexible
+ with some minsyms like printf (compile-cplus.exp has examples). */
+ gcc_type result = instance->plugin ().build_function_type
+ (return_type, &array, is_varargs);
+ xfree (array.elements);
+ return result;
+}
+
+/* Convert an integer type to its gcc representation. */
+
+static gcc_type
+compile_cplus_convert_int (compile_cplus_instance *instance, struct type *type)
+{
+ if (TYPE_NOSIGN (type))
+ {
+ gdb_assert (TYPE_LENGTH (type) == 1);
+ return instance->plugin ().get_char_type ();
+ }
+
+ return instance->plugin ().get_int_type
+ (TYPE_UNSIGNED (type), TYPE_LENGTH (type), TYPE_NAME (type));
+}
+
+/* Convert a floating-point type to its gcc representation. */
+
+static gcc_type
+compile_cplus_convert_float (compile_cplus_instance *instance,
+ struct type *type)
+{
+ return instance->plugin ().get_float_type
+ (TYPE_LENGTH (type), TYPE_NAME (type));
+}
+
+/* Convert the 'void' type to its gcc representation. */
+
+static gcc_type
+compile_cplus_convert_void (compile_cplus_instance *instance, struct type *type)
+{
+ return instance->plugin ().get_void_type ();
+}
+
+/* Convert a boolean type to its gcc representation. */
+
+static gcc_type
+compile_cplus_convert_bool (compile_cplus_instance *instance, struct type *type)
+{
+ return instance->plugin ().get_bool_type ();
+}
+
+/* See description in compile-cplus.h. */
+
+gcc_type
+compile_cplus_instance::convert_qualified_base (gcc_type base,
+ gcc_cp_qualifiers_flags quals)
+{
+ gcc_type result = base;
+
+ if (quals != GCC_CP_REF_QUAL_NONE)
+ result = plugin ().build_qualified_type (base, quals);
+
+ return result;
+}
+
+/* See description in compile-cplus.h. */
+
+static gcc_type
+compile_cplus_convert_qualified (compile_cplus_instance *instance,
+ struct type *type)
+{
+ struct type *unqual = make_unqualified_type (type);
+ gcc_cp_qualifiers_flags quals = (enum gcc_cp_qualifiers) 0;
+ gcc_type unqual_converted = instance->convert_type (unqual);
+
+ if (TYPE_CONST (type))
+ quals |= GCC_CP_QUALIFIER_CONST;
+ if (TYPE_VOLATILE (type))
+ quals |= GCC_CP_QUALIFIER_VOLATILE;
+ if (TYPE_RESTRICT (type))
+ quals |= GCC_CP_QUALIFIER_RESTRICT;
+
+ return instance->convert_qualified_base (unqual_converted, quals);
+}
+
+/* Convert a complex type to its gcc representation. */
+
+static gcc_type
+compile_cplus_convert_complex (compile_cplus_instance *instance,
+ struct type *type)
+{
+ gcc_type base = instance->convert_type (TYPE_TARGET_TYPE (type));
+
+ return instance->plugin ().build_complex_type (base);
+}
+
+/* Convert a namespace of TYPE. */
+
+static gcc_type
+compile_cplus_convert_namespace (compile_cplus_instance *instance,
+ struct type *type)
+{
+ compile_scope scope = instance->new_scope (TYPE_NAME (type), type);
+ gdb::unique_xmalloc_ptr<char> name = decl_name (TYPE_NAME (type));
+
+ /* Push scope. */
+ instance->enter_scope (scope);
+
+ /* Convert this namespace. */
+ instance->plugin ().push_namespace (name.get ());
+ instance->plugin ().pop_binding_level (name.get ());
+
+ /* Pop scope. */
+ instance->leave_scope ();
+
+ /* Namespaces are non-cacheable types. */
+ return GCC_TYPE_NONE;
+}
+
+/* A helper function which knows how to convert most types from their
+ gdb representation to the corresponding gcc form. This examines
+ the TYPE and dispatches to the appropriate conversion function. It
+ returns the gcc type.
+
+ If the type was defined in another type, NESTED_ACCESS should indicate the
+ accessibility of this type. */
+
+static gcc_type
+convert_type_cplus_basic (compile_cplus_instance *instance,
+ struct type *type,
+ enum gcc_cp_symbol_kind nested_access)
+{
+ /* If we are converting a qualified type, first convert the
+ unqualified type and then apply the qualifiers. */
+ if ((TYPE_INSTANCE_FLAGS (type) & (TYPE_INSTANCE_FLAG_CONST
+ | TYPE_INSTANCE_FLAG_VOLATILE
+ | TYPE_INSTANCE_FLAG_RESTRICT)) != 0)
+ return compile_cplus_convert_qualified (instance, type);
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_REF:
+ case TYPE_CODE_RVALUE_REF:
+ return compile_cplus_convert_reference (instance, type);
+
+ case TYPE_CODE_PTR:
+ return compile_cplus_convert_pointer (instance, type);
+
+ case TYPE_CODE_ARRAY:
+ return compile_cplus_convert_array (instance, type);
+
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ return
+ compile_cplus_convert_struct_or_union (instance, type, nested_access);
+
+ case TYPE_CODE_ENUM:
+ return compile_cplus_convert_enum (instance, type, nested_access);
+
+ case TYPE_CODE_FUNC:
+ return compile_cplus_convert_func (instance, type, false);
+
+ case TYPE_CODE_METHOD:
+ return
+ compile_cplus_convert_method (instance, TYPE_SELF_TYPE (type), type);
+
+ case TYPE_CODE_MEMBERPTR:
+ case TYPE_CODE_METHODPTR:
+ return compile_cplus_convert_memberptr (instance, type);
+ break;
+
+ case TYPE_CODE_INT:
+ return compile_cplus_convert_int (instance, type);
+
+ case TYPE_CODE_FLT:
+ return compile_cplus_convert_float (instance, type);
+
+ case TYPE_CODE_VOID:
+ return compile_cplus_convert_void (instance, type);
+
+ case TYPE_CODE_BOOL:
+ return compile_cplus_convert_bool (instance, type);
+
+ case TYPE_CODE_COMPLEX:
+ return compile_cplus_convert_complex (instance, type);
+
+ case TYPE_CODE_NAMESPACE:
+ return compile_cplus_convert_namespace (instance, type);
+
+ case TYPE_CODE_TYPEDEF:
+ return compile_cplus_convert_typedef (instance, type, nested_access);
+
+ default:
+ break;
+ }
+
+ std::string s = string_printf (_("unhandled TYPE_CODE_%s"),
+ type_code_to_string (TYPE_CODE (type)));
+
+ return instance->plugin ().error (s.c_str ());
+}
+
+gcc_type
+compile_cplus_instance::convert_type (struct type *type,
+ enum gcc_cp_symbol_kind nested_access)
+{
+ /* Check if TYPE has already been converted. */
+ gcc_type result;
+ if (get_cached_type (type, result))
+ return result;
+
+ /* It is the first time this type has been seen -- convert it
+ and cache it, if appropriate.. */
+ result = convert_type_cplus_basic (this, type, nested_access);
+ if (result != GCC_TYPE_NONE)
+ insert_type (type, result);
+ return result;
+}
+
+\f
+
+/* Plug-in forwards. */
+
+/* C++ plug-in wrapper. */
+
+/* A result printer for plug-in calls that return a gcc_type or
+ gcc_decl. */
+
+static void
+compile_cplus_debug_output_1 (gcc_type arg)
+{
+ fprintf_unfiltered (gdb_stdlog, "%lld", arg);
+}
+
+static void
+compile_cplus_debug_output_1 (const char *arg)
+{
+ if (arg == nullptr)
+ fputs_unfiltered ("NULL", gdb_stdlog);
+ else
+ fputs_unfiltered (arg, gdb_stdlog);
+}
+
+static void
+compile_cplus_debug_output ()
+{
+}
+
+template <typename T>
+static void
+compile_cplus_debug_output_1 (const T *arg)
+{
+}
+
+template <typename T, typename... Targs>
+static void
+compile_cplus_debug_output (T arg, Targs... Args)
+{
+ compile_cplus_debug_output_1 (arg);
+ fputc_unfiltered (' ', gdb_stdlog);
+ compile_cplus_debug_output (Args...);
+}
+
+#define FORWARD(OP,...) m_context->cp_ops->OP(m_context, ##__VA_ARGS__)
+#define OUTPUT_DEBUG_RESULT(R) \
+ if (debug_compile_cplus_types) \
+ { \
+ fputs_unfiltered (": ", gdb_stdlog); \
+ compile_cplus_debug_output (R); \
+ fputc_unfiltered ('\n', gdb_stdlog); \
+ } \
+
+#define GCC_METHOD0(R, N) \
+ R gcc_cp_plugin::N () const \
+ { \
+ if (debug_compile_cplus_types) \
+ compile_cplus_debug_output (STRINGIFY (N)); \
+ auto result = FORWARD (N); \
+ OUTPUT_DEBUG_RESULT (result); \
+ return result; \
+ }
+#define GCC_METHOD1(R, N, A) \
+ R gcc_cp_plugin::N (A a) const \
+ { \
+ if (debug_compile_cplus_types) \
+ compile_cplus_debug_output (STRINGIFY (N), a); \
+ auto result = FORWARD (N, a); \
+ OUTPUT_DEBUG_RESULT (result); \
+ return result; \
+ }
+#define GCC_METHOD2(R, N, A, B) \
+ R gcc_cp_plugin::N (A a, B b) const \
+ { \
+ if (debug_compile_cplus_types) \
+ compile_cplus_debug_output (STRINGIFY (N), a, b); \
+ auto result = FORWARD (N, a, b); \
+ OUTPUT_DEBUG_RESULT (result); \
+ return result; \
+ }
+#define GCC_METHOD3(R, N, A, B, C) \
+ R gcc_cp_plugin::N (A a, B b, C c) const \
+ { \
+ if (debug_compile_cplus_types) \
+ compile_cplus_debug_output (STRINGIFY (N), a, b, c); \
+ auto result = FORWARD (N, a, b, c); \
+ OUTPUT_DEBUG_RESULT (result); \
+ return result; \
+ }
+#define GCC_METHOD4(R, N, A, B, C, D) \
+ R gcc_cp_plugin::N (A a, B b, C c, D d) const \
+ { \
+ if (debug_compile_cplus_types) \
+ compile_cplus_debug_output (STRINGIFY (N), a, b, c, d); \
+ auto result = FORWARD (N, a, b, c, d); \
+ OUTPUT_DEBUG_RESULT (result); \
+ return result; \
+ }
+#define GCC_METHOD5(R, N, A, B, C, D, E) \
+ R gcc_cp_plugin::N (A a, B b, C c, D d, E e) const \
+ { \
+ if (debug_compile_cplus_types) \
+ compile_cplus_debug_output (STRINGIFY (N), a, b, c, d, e); \
+ auto result = FORWARD (N, a, b, c, d, e); \
+ OUTPUT_DEBUG_RESULT (result); \
+ return result; \
+ }
+#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \
+ R gcc_cp_plugin::N (A a, B b, C c, D d, E e, F f, G g) const \
+ { \
+ if (debug_compile_cplus_types) \
+ compile_cplus_debug_output (STRINGIFY (N), a, b, c, d, e, f, g); \
+ auto result = FORWARD (N, a, b, c, d, e, f, g); \
+ OUTPUT_DEBUG_RESULT (result); \
+ return result; \
+ }
+
+#include "gcc-cp-fe.def"
+
+#undef GCC_METHOD0
+#undef GCC_METHOD1
+#undef GCC_METHOD2
+#undef GCC_METHOD3
+#undef GCC_METHOD4
+#undef GCC_METHOD5
+#undef GCC_METHOD7
+#undef FORWARD
+#undef OUTPUT_DEBUG_RESULT
+
+gcc_expr
+gcc_cp_plugin::build_decl (const char *debug_decltype, const char *name,
+ enum gcc_cp_symbol_kind sym_kind, gcc_type sym_type,
+ const char *substitution_name, gcc_address address,
+ const char *filename, unsigned int line_number)
+{
+ if (debug_compile_cplus_types)
+ fprintf_unfiltered (gdb_stdlog, "<%s> ", debug_decltype);
+
+ return build_decl (name, sym_kind, sym_type, substitution_name,
+ address, filename, line_number);
+}
+
+gcc_type
+gcc_cp_plugin::start_class_type (const char *debug_name, gcc_decl typedecl,
+ const struct gcc_vbase_array *base_classes,
+ const char *filename, unsigned int line_number)
+{
+ if (debug_compile_cplus_types)
+ fprintf_unfiltered (gdb_stdlog, "<%s> ", debug_name);
+
+ return start_class_type (typedecl, base_classes, filename, line_number);
+}
+
+int
+gcc_cp_plugin::finish_class_type (const char *debug_name,
+ unsigned long size_in_bytes)
+{
+ if (debug_compile_cplus_types)
+ fprintf_unfiltered (gdb_stdlog, "<%s> ", debug_name);
+
+ return finish_class_type (size_in_bytes);
+}
+
+int
+gcc_cp_plugin::pop_binding_level (const char *debug_name)
+{
+ if (debug_compile_cplus_types)
+ fprintf_unfiltered (gdb_stdlog, "<%s> ", debug_name);
+
+ return pop_binding_level ();
+}
+
+void _initialize_compile_cplus_types (void);
+
+void
+_initialize_compile_cplus_types (void)
+{
+ add_setshow_boolean_cmd ("compile-cplus-types", no_class,
+ &debug_compile_cplus_types, _("\
+Set debugging of C++ compile type conversion."), _("\
+Show debugging of C++ compile type conversion."), _("\
+When enabled debugging messages are printed during C++ type conversion for\n\
+the compile commands."),
+ nullptr,
+ nullptr,
+ &setdebuglist,
+ &showdebuglist);
+
+ add_setshow_boolean_cmd ("compile-cplus-scopes", no_class,
+ &debug_compile_cplus_scopes, _("\
+Set debugging of C++ compile scopes."), _("\
+Show debugging of C++ compile scopes."), _("\
+When enabled debugging messages are printed about definition scopes during\n\
+C++ type conversion for the compile commands."),
+ nullptr,
+ nullptr,
+ &setdebuglist,
+ &showdebuglist);
+}
diff --git a/gdb/compile/compile-cplus.h b/gdb/compile/compile-cplus.h
new file mode 100644
index 0000000000..0f246af310
--- /dev/null
+++ b/gdb/compile/compile-cplus.h
@@ -0,0 +1,207 @@
+/* Header file for GDB compile C++ language support.
+ Copyright (C) 2016-2018 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 <http://www.gnu.org/licenses/>. */
+
+#ifndef GDB_COMPILE_CPLUS_H
+#define GDB_COMPILE_CPLUS_H
+
+#include "common/enum-flags.h"
+#include "gcc-cp-plugin.h"
+
+struct type;
+struct block;
+
+/* enum-flags wrapper */
+DEF_ENUM_FLAGS_TYPE (enum gcc_cp_qualifiers, gcc_cp_qualifiers_flags);
+DEF_ENUM_FLAGS_TYPE (enum gcc_cp_ref_qualifiers, gcc_cp_ref_qualifiers_flags);
+DEF_ENUM_FLAGS_TYPE (enum gcc_cp_symbol_kind, gcc_cp_symbol_kind_flags);
+
+class compile_cplus_instance;
+
+/* A single component of a type's scope. Type names are broken into
+ "components," a series of unqualified names comprising the type name,
+ e.g., "namespace1", "namespace2", "myclass". */
+
+struct scope_component
+{
+ /* The unqualified name of this scope. */
+ std::string name;
+
+ /* The block symbol for this type/scope. */
+ struct block_symbol bsymbol;
+};
+
+/* Comparison operators for scope_components. */
+
+bool operator== (const scope_component &lhs, const scope_component &rhs);
+bool operator!= (const scope_component &lhs, const scope_component &rhs);
+
+
+/* A single compiler scope used to define a type.
+
+ A compile_scope is a list of scope_components, where all leading
+ scope_components are namespaces, followed by a single non-namespace
+ type component (the actual type we are converting). */
+
+class compile_scope : private std::vector<scope_component>
+{
+public:
+
+ using std::vector<scope_component>::push_back;
+ using std::vector<scope_component>::pop_back;
+ using std::vector<scope_component>::back;
+ using std::vector<scope_component>::empty;
+ using std::vector<scope_component>::size;
+ using std::vector<scope_component>::begin;
+ using std::vector<scope_component>::end;
+ using std::vector<scope_component>::operator[];
+
+ compile_scope ()
+ : m_nested_type (GCC_TYPE_NONE), m_pushed (false)
+ {
+ }
+
+ /* Return the gcc_type of the type if it is a nested definition.
+ Returns GCC_TYPE_NONE if this type was not nested. */
+ gcc_type nested_type ()
+ {
+ return m_nested_type;
+ }
+
+private:
+
+ /* compile_cplus_instance is a friend class so that it can set the
+ following private members when compile_scopes are created. */
+ friend compile_cplus_instance;
+
+ /* If the type was actually a nested type, this will hold that nested
+ type after the scope is pushed. */
+ gcc_type m_nested_type;
+
+ /* If true, this scope was pushed to the compiler and all namespaces
+ must be popped when leaving the scope. */
+ bool m_pushed;
+};
+
+/* Comparison operators for compile_scopes. */
+
+bool operator== (const compile_scope &lhs, const compile_scope &rhs);
+bool operator!= (const compile_scope &lhs, const compile_scope &rhs);
+
+/* Convert TYPENAME into a vector of namespace and top-most/super
+ composite scopes.
+
+ For example, for the input "Namespace::classB::classInner", the
+ resultant vector will contain the tokens "Namespace" and
+ "classB". */
+
+compile_scope type_name_to_scope (const char *type_name,
+ const struct block *block);
+
+/* A callback suitable for use as the GCC C++ symbol oracle. */
+
+extern gcc_cp_oracle_function gcc_cplus_convert_symbol;
+
+/* A callback suitable for use as the GCC C++ address oracle. */
+
+extern gcc_cp_symbol_address_function gcc_cplus_symbol_address;
+
+/* Callbacks suitable for use as the GCC C++ enter/leave scope requests. */
+
+extern gcc_cp_enter_leave_user_expr_scope_function gcc_cplus_enter_scope;
+extern gcc_cp_enter_leave_user_expr_scope_function gcc_cplus_leave_scope;
+
+/* A subclass of compile_instance that is specific to the C++ front
+ end. */
+
+class compile_cplus_instance : public compile_instance
+{
+public:
+
+ explicit compile_cplus_instance (struct gcc_cp_context *gcc_cp)
+ : compile_instance (&gcc_cp->base, m_default_cflags),
+ m_plugin (gcc_cp)
+ {
+ m_plugin.set_callbacks (gcc_cplus_convert_symbol,
+ gcc_cplus_symbol_address,
+ gcc_cplus_enter_scope, gcc_cplus_leave_scope,
+ this);
+ }
+
+ /* Convert a gdb type, TYPE, to a GCC type.
+
+ If this type was defined in another type, NESTED_ACCESS should indicate
+ the accessibility of this type (or GCC_CP_ACCESS_NONE if not a nested
+ type). GCC_CP_ACCESS_NONE is the default nested access.
+
+ The new GCC type is returned. */
+ gcc_type convert_type
+ (struct type *type,
+ enum gcc_cp_symbol_kind nested_access = GCC_CP_ACCESS_NONE);
+
+ /* Return a handle for the GCC plug-in. */
+ gcc_cp_plugin &plugin () { return m_plugin; }
+
+ /* Factory method to create a new scope based on TYPE with name TYPE_NAME.
+ [TYPE_NAME could be TYPE_NAME or SYMBOL_NATURAL_NAME.]
+
+ If TYPE is a nested or local definition, nested_type () will return
+ the gcc_type of the conversion.
+
+ Otherwise, nested_type () is GCC_TYPE_NONE. */
+ compile_scope new_scope (const char *type_name, struct type *type);
+
+ /* Enter the given NEW_SCOPE. */
+ void enter_scope (compile_scope &scope);
+
+ /* Leave the current scope. */
+ void leave_scope ();
+
+ /* Add the qualifiers given by QUALS to BASE. */
+ gcc_type convert_qualified_base (gcc_type base,
+ gcc_cp_qualifiers_flags quals);
+
+ /* Convert TARGET into a pointer type. */
+ gcc_type convert_pointer_base (gcc_type target);
+
+ /* Convert BASE into a reference type. RQUALS describes the reference. */
+ gcc_type convert_reference_base (gcc_type base,
+ enum gcc_cp_ref_qualifiers rquals);
+
+private:
+
+ /* Default compiler flags for C++. */
+ static const char *m_default_cflags;
+
+ /* The GCC plug-in. */
+ gcc_cp_plugin m_plugin;
+
+ /* A list of scopes we are processing. */
+ std::vector<compile_scope> m_scopes;
+};
+
+/* Return the declaration name of the symbol named NATURAL.
+ This returns a name with no function arguments or template parameters,
+ suitable for passing to the compiler plug-in. */
+
+gdb::unique_xmalloc_ptr<char> decl_name (const char *natural);
+
+/* Get the access flag for the NUM'th method of TYPE's FNI'th
+ fieldlist. */
+
+enum gcc_cp_symbol_kind get_method_access_flag (const struct type *type,
+ int fni, int num);
+
+#endif /* GDB_COMPILE_CPLUS_H */
diff --git a/gdb/compile/compile-internal.h b/gdb/compile/compile-internal.h
index c8d2d2f427..483a0d5f7f 100644
--- a/gdb/compile/compile-internal.h
+++ b/gdb/compile/compile-internal.h
@@ -23,6 +23,10 @@

extern int compile_debug;

+/* Flag to enable internal debugging for oracle requests. */
+
+extern int debug_compile_oracle;
+
struct block;

/* An object that maps a gdb type to a gcc type. */
@@ -164,6 +168,10 @@ protected:
#define COMPILE_I_EXPR_VAL "__gdb_expr_val"
#define COMPILE_I_EXPR_PTR_TYPE "__gdb_expr_ptr_type"

+/* A "type" to indicate a NULL type. */
+
+const gcc_type GCC_TYPE_NONE = (gcc_type) -1;
+
/* Call gdbarch_register_name (GDBARCH, REGNUM) and convert its result
to a form suitable for the compiler source. The register names
should not clash with inferior defined macros. */
diff --git a/gdb/compile/compile-object-load.c b/gdb/compile/compile-object-load.c
index a83f95dda9..873750b944 100644
--- a/gdb/compile/compile-object-load.c
+++ b/gdb/compile/compile-object-load.c
@@ -459,7 +459,8 @@ get_out_value_type (struct symbol *func_sym, struct objfile *objfile,
if (function != NULL
&& (BLOCK_SUPERBLOCK (function_block)
== BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK))
- && (strcmp (SYMBOL_LINKAGE_NAME (function), GCC_FE_WRAPPER_FUNCTION)
+ && (strcmp_iw (SYMBOL_LINKAGE_NAME (function),
+ GCC_FE_WRAPPER_FUNCTION)
== 0))
break;
}
@@ -478,7 +479,7 @@ get_out_value_type (struct symbol *func_sym, struct objfile *objfile,
gdb_ptr_type = check_typedef (gdb_ptr_type);
if (TYPE_CODE (gdb_ptr_type) != TYPE_CODE_PTR)
error (_("Type of \"%s\" is not a pointer"), COMPILE_I_EXPR_PTR_TYPE);
- gdb_type_from_ptr = TYPE_TARGET_TYPE (gdb_ptr_type);
+ gdb_type_from_ptr = check_typedef (TYPE_TARGET_TYPE (gdb_ptr_type));

if (types_deeply_equal (gdb_type, gdb_type_from_ptr))
{
@@ -741,6 +742,8 @@ compile_object_load (const compile_file_names &file_names,
? mst_unknown : MSYMBOL_TYPE (bmsym.minsym))
{
case mst_text:
+ case mst_bss:
+ case mst_data:
sym->value = BMSYMBOL_VALUE_ADDRESS (bmsym);
if (compile_debug)
fprintf_unfiltered (gdb_stdlog,
diff --git a/gdb/compile/compile.c b/gdb/compile/compile.c
index 31ae5970b9..efa4e8d0fa 100644
--- a/gdb/compile/compile.c
+++ b/gdb/compile/compile.c
@@ -995,7 +995,6 @@ String quoting is parsed like in shell, for example:\n\
" -fPIE"
/* We want warnings, except for some commonly happening for GDB commands. */
" -Wall "
- " -Wno-implicit-function-declaration"
" -Wno-unused-but-set-variable"
" -Wno-unused-variable"
/* Override CU's possible -fstack-protector-strong. */
diff --git a/gdb/compile/gcc-cp-plugin.h b/gdb/compile/gcc-cp-plugin.h
new file mode 100644
index 0000000000..1b72726a67
--- /dev/null
+++ b/gdb/compile/gcc-cp-plugin.h
@@ -0,0 +1,85 @@
+/* GCC C++ plug-in wrapper for GDB.
+
+ Copyright (C) 2018 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/>. */
+
+/* A class representing the GCC C++ plug-in. */
+
+#include "gcc-cp-interface.h"
+
+class gcc_cp_plugin
+{
+public:
+
+ explicit gcc_cp_plugin (struct gcc_cp_context *gcc_cp)
+ : m_context (gcc_cp)
+ {
+ }
+
+ /* Set the oracle callbacks to be used by the compiler plug-in. */
+ void set_callbacks (gcc_cp_oracle_function *binding_oracle,
+ gcc_cp_symbol_address_function *address_oracle,
+ gcc_cp_enter_leave_user_expr_scope_function *enter_scope,
+ gcc_cp_enter_leave_user_expr_scope_function *leave_scope,
+ void *datum)
+ {
+ m_context->cp_ops->set_callbacks (m_context, binding_oracle,
+ address_oracle, enter_scope, leave_scope,
+ datum);
+ }
+
+ /* Returns the interface version of the compiler plug-in. */
+ int version () const { return m_context->cp_ops->cp_version; }
+
+#define GCC_METHOD0(R, N) R N () const;
+#define GCC_METHOD1(R, N, A) R N (A) const;
+#define GCC_METHOD2(R, N, A, B) R N (A, B) const;
+#define GCC_METHOD3(R, N, A, B, C) R N (A, B, C) const;
+#define GCC_METHOD4(R, N, A, B, C, D) R N (A, B, C, D) const;
+#define GCC_METHOD5(R, N, A, B, C, D, E) R N (A, B, C, D, E) const;
+#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) R N (A, B, C, D, E, F, G) const;
+
+#include "gcc-cp-fe.def"
+
+#undef GCC_METHOD0
+#undef GCC_METHOD1
+#undef GCC_METHOD2
+#undef GCC_METHOD3
+#undef GCC_METHOD4
+#undef GCC_METHOD5
+#undef GCC_METHOD7
+
+ /* Special overloads of plug-in methods with added debugging information. */
+
+ gcc_expr build_decl (const char *debug_decltype, const char *name,
+ enum gcc_cp_symbol_kind sym_kind, gcc_type sym_type,
+ const char *substitution_name, gcc_address address,
+ const char *filename, unsigned int line_number);
+
+ gcc_type start_class_type (const char *debug_name, gcc_decl typedecl,
+ const struct gcc_vbase_array *base_classes,
+ const char *filename, unsigned int line_number);
+
+ int finish_class_type (const char *debug_name, unsigned long size_in_bytes);
+
+ int pop_binding_level (const char *debug_name);
+
+private:
+
+ /* The GCC C++ context. */
+ struct gcc_cp_context *m_context;
+};
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index ceb4043e32..f8fcd33481 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,8 @@
+YYYY-MM-DD Keith Seitz <keiths@redhat.com>
+
+ * gdb.texinfo (Compiling and injecting code in GDB): Document
+ set/show "compile-oracle" and "compile-cplus-types" commands.
+
2018-08-07 Simon Marchi <simon.marchi@ericsson.com>

* gdb.texinfo (Index Files Speed Up GDB): Add section about
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index b931834400..c17c19caa2 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18689,6 +18689,26 @@ injecting the code. The default is off.
@item show debug compile
Displays the current state of displaying @value{GDBN} process of
compiling and injecting the code.
+
+@anchor{set debug compile-oracle}
+@item set debug compile-oracle
+@cindex compile oracle debugging info
+Turns on or off display of symbol requests from the compiler plug-in
+(the ``oracle''). The default is off.
+
+@item show debug compile-oracle
+Displays the current state of displaying symbol requests made by the
+compiler plug-in.
+
+@anchor{set debug compile-cplus-types}
+@item set debug compile-cplus-types
+@cindex compile C++ type conversion
+Turns on or off the display of C++ type conversion debugging information.
+The default is off.
+
+@item show debug compile-cplus-types
+Displays the current state of displaying debugging information for
+C++ type conversion.
@end table

@subsection Compilation options for the @code{compile} command
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index bd3c3bfec5..050e406349 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,28 @@
+YYYY-MM-DD Keith Seitz <keiths@redhat.com>
+
+ * gdb.compile/compile-cplus-anonymous.cc: New file.
+ * gdb.compile/compile-cplus-anonymous.exp: New file.
+ * gdb.compile/compile-cplus-array-decay.cc: New file.
+ * gdb.compile/compile-cplus-array-decay.exp: New file.
+ * gdb.compile/compile-cplus-inherit.cc: New file.
+ * gdb.compile/compile-cplus-inherit.exp: New file.
+ * gdb.compile/compile-cplus-member.cc: New file.
+ * gdb.compile/compile-cplus-member.exp: New file.
+ * gdb.compile/compile-cplus-method.cc: New file.
+ * gdb.compile/compile-cplus-method.exp: New file.
+ * gdb.compile/compile-cplus-mod.c: "New" file.
+ * gdb.compile/compile-cplus-namespace.cc: New file.
+ * gdb.compile/compile-cplus-namespace.exp: New file.
+ * gdb.compile/compile-cplus-nested.cc: New file.
+ * gdb.compile/compile-cplus-nested.exp: New file.
+ * gdb.compile/compile-cplus-print.c: "New" file.
+ * gdb.compile/compile-cplus-print.exp: "New" file.
+ * gdb.compile/compile-cplus-virtual.cc: New file.
+ * gdb.compile/compile-cplus-virtual.exp: New file.
+ * gdb.compile/compile-cplus.c: "New" file.
+ * gdb.compile/compile-cplus.exp: "New" file.
+ * lib/compile-support.exp: New file.
+
2018-08-09 Andrew Burgess <andrew.burgess@embecosm.com>

* gdb.base/vla-optimized-out.exp: Add new test.
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-anonymous.cc b/gdb/testsuite/gdb.compile/compile-cplus-anonymous.cc
new file mode 100644
index 0000000000..4c6673249e
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-anonymous.cc
@@ -0,0 +1,76 @@
+/* Copyright 2015-2018 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 <http://www.gnu.org/licenses/>. */
+
+namespace {
+ static enum {ABC = 1, DEF, GHI, JKL} anon_e = GHI;
+ static union
+ {
+ char aa;
+ int bb;
+ float ff;
+ double dd;
+ void *pp;
+ } anon_u = { 'a' };
+
+ static struct
+ {
+ char *ptr;
+ int len;
+ struct
+ {
+ unsigned MAGIC;
+ };
+ union
+ {
+ int ua;
+ char *ub;
+ };
+ } anon_s = {"abracadabra", 11, 0xdead, 0xbeef};
+
+ struct A
+ {
+ A (void) : e (AA)
+ {
+ this->u.b = 0;
+ this->s.ptr = "hello";
+ this->s.len = 5;
+ }
+
+ enum {AA = 10, BB, CC, DD} e;
+ union
+ {
+ char a;
+ int b;
+ float f;
+ double d;
+ void *p;
+ } u;
+ struct
+ {
+ char *ptr;
+ int len;
+ } s;
+ };
+};
+
+int
+main (void)
+{
+ A a;
+ int var = 1234;
+
+ return a.u.b + a.s.len + static_cast<int> (a.e)
+ + static_cast<int> (anon_e) + anon_u.bb + anon_s.len; // break here
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-anonymous.exp b/gdb/testsuite/gdb.compile/compile-cplus-anonymous.exp
new file mode 100644
index 0000000000..0aa3290557
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-anonymous.exp
@@ -0,0 +1,64 @@
+# Copyright 2015-2018 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 <http://www.gnu.org/licenses/>.
+
+# Anonymous type conversion tests for GDB's C++ compile feature.
+
+load_lib compile-support.exp
+
+standard_testfile .cc
+
+if {[skip_cplus_tests]} {
+ untested "skipping C++ tests"
+ return
+}
+
+if {[prepare_for_testing $testfile $testfile $srcfile \
+ {debug nowarnings c++}]} {
+ return -1
+}
+
+if {![runto_main]} {
+ untested "could not run to main"
+ return -1
+}
+
+if {[skip_compile_feature_tests]} {
+ untested \
+ "compile command not supported (could not find libcc1 shared library?)"
+ return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+# Reminder, "var" is an integer; all these types get converted to `int'.
+CompileExpression::new "var"
+CompileExpression::test "anon_e" {(3|GHI)}
+CompileExpression::test "anon_u.aa" {97( 'a')?}
+CompileExpression::test "a.u.b" 0
+CompileExpression::test "a.s.len" 5
+CompileExpression::test "a.e" {(10|A::AA)}
+CompileExpression::test "(*a.s.ptr != 'h')" (0|false)
+CompileExpression::test "A::BB" {(11|A::BB)}
+CompileExpression::test "ABC" {(1|ABC)}
+CompileExpression::test "DEF" {(2|DEF)}
+CompileExpression::test "GHI" {(3|GHI)}
+CompileExpression::test "JKL" {(4|JKL)}
+
+set k "compile/1234 *-*-*"
+CompileExpression::test "anon_s.len" 11 -kfail $k
+CompileExpression::test "anon_s.MAGIC" "57005" -kfail $k
+CompileExpression::test "anon_s.ua" "48879" -kfail $k
+CompileExpression::test "(*anon_s.ptr == 'a')" (1|true) -kfail $k
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-array-decay.cc b/gdb/testsuite/gdb.compile/compile-cplus-array-decay.cc
new file mode 100644
index 0000000000..da51a65654
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-array-decay.cc
@@ -0,0 +1,31 @@
+/* Copyright 2017-2018 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 <http://www.gnu.org/licenses/>. */
+
+static const char *g_string_initializer = "hello";
+
+int
+main ()
+{
+ int integers[10];
+ const char *strings[10];
+
+ for (auto &i : integers)
+ i = 0;
+
+ for (auto &i : strings)
+ i = g_string_initializer;
+
+ return 0; // break here
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-array-decay.exp b/gdb/testsuite/gdb.compile/compile-cplus-array-decay.exp
new file mode 100644
index 0000000000..fb3e63fd91
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-array-decay.exp
@@ -0,0 +1,50 @@
+# Copyright 2017-2018 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 <http://www.gnu.org/licenses/>.
+
+# Test whether GDB's C++ compile feature is decaying arrays into pointers.
+
+load_lib compile-support.exp
+
+standard_testfile .cc
+
+if {[skip_cplus_tests]} {
+ untested "skipping C++ tests"
+ return
+}
+
+if {[prepare_for_testing $testfile $testfile $srcfile \
+ {debug nowarnings c++}]} {
+ return -1
+}
+
+if {![runto_main]} {
+ untested "could not run to main"
+ return -1
+}
+
+if {[skip_compile_feature_tests]} {
+ untested \
+ "compile command not supported (could not find libcc1 shared library?)"
+ return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+gdb_test "compile print integers" " = \\{0, 0, 0, 0, 0, 0, 0, 0, 0, 0\\}"
+
+gdb_test "compile print strings" " = \\{$hex \"hello\", $hex \"hello\",\
+ $hex \"hello\", $hex \"hello\", $hex \"hello\", $hex \"hello\",\
+ $hex \"hello\", $hex \"hello\", $hex \"hello\", $hex \"hello\"\\}"
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-inherit.cc b/gdb/testsuite/gdb.compile/compile-cplus-inherit.cc
new file mode 100644
index 0000000000..de81d1a182
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-inherit.cc
@@ -0,0 +1,58 @@
+/* Copyright 2015-2018 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 <http://www.gnu.org/licenses/>. */
+
+struct A
+{
+ A () : a_ (1) {}
+ int do_it (int amount) { return a_ + amount; }
+
+ int a_;
+};
+
+struct B
+{
+ B () : b_ (2) {}
+ int do_it (int amount) { return b_ - amount; }
+
+ int b_;
+};
+
+struct C
+{
+ C () : c_ (3) {}
+ int do_it (int amount) { return c_ * amount; }
+
+ int c_;
+};
+
+struct D : public A, B, C
+{
+ D () : d_ (4) {}
+
+ int d_;
+};
+
+int
+main (void)
+{
+ D d;
+ int var = 1234;
+
+ var = d.A::do_it (1)
+ + d.B::do_it (2)
+ + d.C::do_it (3); // break here
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-inherit.exp b/gdb/testsuite/gdb.compile/compile-cplus-inherit.exp
new file mode 100644
index 0000000000..1978cb556a
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-inherit.exp
@@ -0,0 +1,53 @@
+# Copyright 2015-2018 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 <http://www.gnu.org/licenses/>.
+
+# Inheritance tests for GDB's C++ compile feature.
+
+load_lib compile-support.exp
+
+standard_testfile .cc
+
+if {[skip_cplus_tests]} {
+ untested "skipping C++ tests"
+ return
+}
+
+if {[prepare_for_testing $testfile $testfile $srcfile \
+ {debug nowarnings c++}]} {
+ return -1
+}
+
+if {![runto_main]} {
+ untested "could not run to main"
+ return -1
+}
+
+if {[skip_compile_feature_tests]} {
+ untested \
+ "compile command not supported (could not find libcc1 shared library?)"
+ return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+CompileExpression::new "var"
+CompileExpression::test "d.a_" 1
+CompileExpression::test "d.b_" 2
+CompileExpression::test "d.c_" 3
+CompileExpression::test "d.d_" 4
+CompileExpression::test "d.A::do_it (1)" 2
+CompileExpression::test "d.B::do_it (1)" 1
+CompileExpression::test "d.C::do_it (1)" 3
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-member.cc b/gdb/testsuite/gdb.compile/compile-cplus-member.cc
new file mode 100644
index 0000000000..428e3aab56
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-member.cc
@@ -0,0 +1,83 @@
+/* Copyright 2015-2018 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 <http://www.gnu.org/licenses/>. */
+
+class A;
+static int get_values (const A& a);
+
+enum myenum {E_A = 10, E_B, E_C, E_D, E_E};
+
+namespace N {
+ typedef enum {NA = 20, NB, NC, ND} ANON_NE;
+}
+
+namespace {
+ typedef enum {AA = 40, AB, AC, AD} ANON_E;
+}
+
+ANON_E g_e = AC;
+
+class A
+{
+public:
+ typedef int ATYPE;
+
+ A(void) : public_ (1), protected_ (N::NB), private_ (3) {}
+ ATYPE public_;
+ static const myenum s_public_;
+ friend ATYPE get_values (const A&);
+
+protected:
+ N::ANON_NE protected_;
+ static N::ANON_NE s_protected_;
+
+private:
+ ATYPE private_;
+ static myenum s_private_;
+};
+
+const myenum A::s_public_ = E_A;
+N::ANON_NE A::s_protected_ = N::NA;
+myenum A::s_private_ = E_C;
+
+static A::ATYPE
+get_values (const A& a)
+{
+ A::ATYPE val;
+
+ val = a.public_ + a.private_; // 1 + 3
+ if (a.protected_ == N::NB) // + 21
+ val += 21;
+ if (a.s_public_ == E_A) // +10
+ val += 10;
+ if (a.s_protected_ == N::NA) // +20
+ val += 20;
+ if (a.s_private_ == E_C) // +30
+ val += 30;
+ if (g_e == AC) // +40
+ val += 40;
+ return val; // = 125
+}
+
+typedef int A::*PMI;
+
+int
+main (void)
+{
+ A a;
+ int var = 1234;
+ PMI pmi = &A::public_;
+
+ return a.*pmi + get_values (a); // break here
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-member.exp b/gdb/testsuite/gdb.compile/compile-cplus-member.exp
new file mode 100644
index 0000000000..525ba43c00
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-member.exp
@@ -0,0 +1,77 @@
+# Copyright 2015-2018 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 <http://www.gnu.org/licenses/>.
+
+# Member tests for GDB's C++ compile feature.
+
+load_lib compile-support.exp
+
+standard_testfile .cc
+
+if {[skip_cplus_tests]} {
+ untested "skipping C++ tests"
+ return
+}
+
+if {[prepare_for_testing $testfile $testfile $srcfile \
+ {debug nowarnings c++}]} {
+ return -1
+}
+
+if {![runto_main]} {
+ untested "could not run to main"
+ return -1
+}
+
+if {[skip_compile_feature_tests]} {
+ untested \
+ "compile command not supported (could not find libcc1 shared library?)"
+ return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+CompileExpression::new "var"
+CompileExpression::test "a.public_" 1
+CompileExpression::test "a.protected_" {(21|N::NB)}
+CompileExpression::test "a.private_" 3
+CompileExpression::test "A::s_public_" {(10|E_A)}
+CompileExpression::test "A::s_protected_" {(20|N::NA)}
+CompileExpression::test "A::s_private_" {(12|E_C)}
+CompileExpression::test "A::ATYPE i = 10; var = i;" 10 -explicit
+CompileExpression::test "get_values (a)" 125
+CompileExpression::test "myenum me = E_B; var = me;" 11 -explicit
+CompileExpression::test "A::s_protected_ = N::NB; var = A::s_protected_;" \
+ 21 -explicit
+CompileExpression::test "A::s_private_ = E_B; var = A::s_private_;" 11 -explicit
+CompileExpression::test "N::ANON_NE ae = N::ND; var = ae;" 23 -explicit
+CompileExpression::test {a.*pmi} 1
+CompileExpression::test {a.public_ = 2; var = a.*pmi; a.public_ = 1} 2 -explicit
+CompileExpression::test "g_e" {(42|AC)}
+
+# Test some compilation failures
+set failed {\r\nCompilation failed\.}
+# !!keiths: This should actually really work...
+gdb_test "compile code a.s_public_ = E_B" \
+ ".*assignment of read-only variable 'A::s_public_'$failed"
+
+gdb_test "compile code get_values ()" \
+ ".*too few arguments to function.*$failed"
+
+gdb_test "compile code ATYPE i;" \
+ ".*.ATYPE. was not declared in this scope$failed"
+
+gdb_test "compile code N::ANON_NE nse = E_A" \
+ ".*cannot convert.*$failed"
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-method.cc b/gdb/testsuite/gdb.compile/compile-cplus-method.cc
new file mode 100644
index 0000000000..b5470e06b6
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-method.cc
@@ -0,0 +1,91 @@
+/* Copyright 2015-2018 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 <http://www.gnu.org/licenses/>. */
+
+class A;
+static int get_value (const A* a);
+
+class A
+{
+public:
+ typedef int ATYPE;
+
+ A (void) : a_ (21) {}
+ ATYPE get_var (void) { return a_; }
+ ATYPE get_var (unsigned long a) { return 100; }
+ ATYPE get_var (ATYPE a) { return 101; }
+ ATYPE get_var (float a) { return 102; }
+ ATYPE get_var (void *a) { return 103;}
+ ATYPE get_var (A& lr) { return 104; }
+ ATYPE get_var (A const& lr) { return 105; }
+
+ ATYPE get_var1 (int n) { return a_ << n; }
+ ATYPE get_var2 (int incr, unsigned n) { return (a_ + incr) << n; }
+
+ static ATYPE get_1 (int a) { return a + 1; }
+ static ATYPE get_2 (int a, int b) { return a + b + 2; }
+
+ friend ATYPE get_value (const A*);
+
+private:
+ ATYPE a_;
+};
+
+static A::ATYPE
+get_value (A::ATYPE a)
+{
+ return a;
+}
+
+static A::ATYPE
+get_value (const A* a)
+{
+ return a->a_;
+}
+
+static A::ATYPE
+get_value (void)
+{
+ return 200;
+}
+
+typedef int (A::*PMF) (A::ATYPE);
+
+int
+main (void)
+{
+ A *a = new A ();
+ int var = 1234;
+ float f = 1.23;
+ unsigned long ul = 0xdeadbeef;
+ A const* ac = a;
+
+ PMF pmf = &A::get_var;
+ PMF *pmf_p = &pmf;
+
+ var -= a->get_var (); // break here
+ var -= a->get_var (1);
+ var -= a->get_var (ul);
+ var -= a->get_var (f);
+ var -= a->get_var (a);
+ var -= a->get_var (*a);
+ var -= a->get_var (*ac);
+ var -= a->get_var1 (1);
+ var -= a->get_var2 (1, 2);
+ var += (a->*pmf) (1);
+ var -= (a->**pmf_p) (1);
+
+ return var - A::get_1 (1) + A::get_2 (1, 2) + get_value ()
+ + get_value (get_value ()) + get_value (a);
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-method.exp b/gdb/testsuite/gdb.compile/compile-cplus-method.exp
new file mode 100644
index 0000000000..3a5bb82850
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-method.exp
@@ -0,0 +1,67 @@
+# Copyright 2015-2018 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 <http://www.gnu.org/licenses/>.
+
+# Method tests for GDB's C++ compile feature.
+
+load_lib compile-support.exp
+
+standard_testfile .cc
+
+if {[skip_cplus_tests]} {
+ untested "skipping C++ tests"
+ return
+}
+
+if {[prepare_for_testing $testfile $testfile $srcfile \
+ {debug nowarnings c++}]} {
+ return -1
+}
+
+if {![runto_main]} {
+ untested "could not run to main"
+ return -1
+}
+
+if {[skip_compile_feature_tests]} {
+ untested \
+ "compile command not supported (could not find libcc1 shared library?)"
+ return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+CompileExpression::new "var"
+CompileExpression::test "a->get_var ()" 21
+CompileExpression::test "a->get_var (static_cast<unsigned long> (1))" 100
+CompileExpression::test "a->get_var (static_cast<int> (1))" 101
+CompileExpression::test "a->get_var (static_cast<float> (1))" 102
+CompileExpression::test "a->get_var (static_cast<void *> (a))" 103
+CompileExpression::test "a->get_var (*a)" 104
+CompileExpression::test "a->get_var (*ac)" 105
+CompileExpression::test "a->get_var1 (1)" 42
+CompileExpression::test "a->get_var2 (1, 2)" 88
+CompileExpression::test "A::get_1 (1)" 2
+CompileExpression::test "A::get_2 (1, 2)" 5
+CompileExpression::test "A::get_1 (a->get_var ())" 22
+CompileExpression::test "a->get_var1 (a->get_var () - 16)" 672
+CompileExpression::test "a->get_var2 (a->get_var (), A::get_1 (2))" 336
+CompileExpression::test "get_value ()" 200
+CompileExpression::test "get_value (a)" 21
+CompileExpression::test "get_value (get_value ())" 200
+CompileExpression::test {(a->*pmf) (1)} 101
+CompileExpression::test \
+ {pmf = &A::get_var1; var = (a->*pmf) (2); pmf = &A::get_var} 84 -explicit
+CompileExpression::test {(a->**pmf_p) (1)} 101
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-mod.c b/gdb/testsuite/gdb.compile/compile-cplus-mod.c
new file mode 100644
index 0000000000..56a135ba8c
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-mod.c
@@ -0,0 +1,28 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2014-2018 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 <http://www.gnu.org/licenses/>. */
+
+extern "C" void
+_gdb_expr (void)
+{
+ // Make 'globalvar' lookup working.
+#pragma GCC push_user_expression
+
+ globalvar = 3;
+ globalvar += 4;
+
+#pragma GCC pop_user_expression
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-namespace.cc b/gdb/testsuite/gdb.compile/compile-cplus-namespace.cc
new file mode 100644
index 0000000000..1f8dc96cd9
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-namespace.cc
@@ -0,0 +1,52 @@
+/* Copyright 2015-2018 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 <http://www.gnu.org/licenses/>. */
+
+namespace N1
+{
+ namespace N2
+ {
+ namespace N3
+ {
+ namespace N4
+ {
+ static int n4static = 400;
+
+ struct S4
+ {
+ static int s4static;
+ int s4int_;
+ S4 (void) : s4int_ (4) {};
+ ~S4 (void) { --s4static; }
+
+ int get_var (void) { return s4int_; }
+ static int get_svar (void) { return s4static; }
+ };
+ int S4::s4static = 40;
+ }
+ }
+ }
+}
+
+int
+main (void)
+{
+ using namespace N1::N2::N3::N4;
+
+ S4 s4;
+ int var = 1234;
+
+ var += s4.s4int_; /* break here */
+ return S4::get_svar () - 10 * s4.get_var ();
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-namespace.exp b/gdb/testsuite/gdb.compile/compile-cplus-namespace.exp
new file mode 100644
index 0000000000..768a707b93
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-namespace.exp
@@ -0,0 +1,51 @@
+# Copyright 2015-2018 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 <http://www.gnu.org/licenses/>.
+
+# Namespace tests for GDB's C++ compile feature.
+
+load_lib compile-support.exp
+
+standard_testfile .cc
+
+if {[skip_cplus_tests]} {
+ untested "skipping C++ tests"
+ return
+}
+
+if {[prepare_for_testing $testfile $testfile $srcfile \
+ {debug nowarnings c++}]} {
+ return -1
+}
+
+if {![runto_main]} {
+ untested "could not run to main"
+ return -1
+}
+
+if {[skip_compile_feature_tests]} {
+ untested \
+ "compile command not supported (could not find libcc1 shared library?)"
+ return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+CompileExpression::new "var"
+CompileExpression::test "N1::N2::N3::N4::n4static" 400
+CompileExpression::test "N1::N2::N3::N4::S4::s4static" 40
+CompileExpression::test "s4.s4int_" 4
+CompileExpression::test "N1::N2::N3::N4::S4::get_svar ()" 40
+CompileExpression::test "s4.get_var ()" 4
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-nested.cc b/gdb/testsuite/gdb.compile/compile-cplus-nested.cc
new file mode 100644
index 0000000000..5d35cf9c51
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-nested.cc
@@ -0,0 +1,58 @@
+/* Copyright 2015-2018 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 <http://www.gnu.org/licenses/>. */
+
+class A
+{
+public:
+ A (void) : a_ (1) {}
+ int get (void);
+
+protected:
+ int a_;
+
+private:
+ /* It is important to not /not/ use the nested class definition in A.
+ This exercises a different path through the code. */
+ struct Inner1
+ {
+ int a_;
+ Inner1 (void) : a_ (2) {}
+
+ struct Inner2
+ {
+ int a_;
+ Inner2 (void) : a_ (3) {}
+ };
+ };
+};
+
+int
+A::get (void)
+{
+ A::Inner1 i1;
+ A::Inner1::Inner2 i2;
+
+ return i1.a_ + i2.a_; // break here
+}
+
+int var = 1234;
+
+int
+main (void)
+{
+ A a;
+
+ return a.get ();
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-nested.exp b/gdb/testsuite/gdb.compile/compile-cplus-nested.exp
new file mode 100644
index 0000000000..3b5ba20b28
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-nested.exp
@@ -0,0 +1,53 @@
+# Copyright 2015-2018 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 <http://www.gnu.org/licenses/>.
+
+# Nested type tests for GDB's C++ compile feature.
+
+load_lib compile-support.exp
+
+standard_testfile .cc
+
+if {[skip_cplus_tests]} {
+ untested "skipping C++ tests"
+ return
+}
+
+if {[prepare_for_testing $testfile $testfile $srcfile \
+ {debug nowarnings c++}]} {
+ return -1
+}
+
+if {![runto_main]} {
+ untested "could not run to main"
+ return -1
+}
+
+if {[skip_compile_feature_tests]} {
+ untested \
+ "compile command not supported (could not find libcc1 shared library?)"
+ return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+CompileExpression::new "var"
+CompileExpression::test "i1.a_" 2
+CompileExpression::test "i2.a_" 3
+CompileExpression::test "A::Inner1 *i1p = &i1; var = i1p->a_;" 2 -explicit
+CompileExpression::test "A::Inner1::Inner2 *i2p = &i2; var = i2p->a_;" 3 \
+ -explicit
+CompileExpression::test "A::Inner1 &r1 = i1; var = r1.a_;" 2 -explicit
+CompileExpression::test "A::Inner1::Inner2 &r2 = i2; var = r2.a_;" 3 -explicit
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-print.c b/gdb/testsuite/gdb.compile/compile-cplus-print.c
new file mode 100644
index 0000000000..9e6575da66
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-print.c
@@ -0,0 +1,32 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2015-2018 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 <http://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+
+int varint = 10;
+int vararray[] = { 1, 2, 3, 4, 5 };
+int *vararrayp = vararray;
+struct object
+{
+ int field;
+} varobject = { 1 };
+
+int
+main (void)
+{
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-print.exp b/gdb/testsuite/gdb.compile/compile-cplus-print.exp
new file mode 100644
index 0000000000..b554c7ddb3
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-print.exp
@@ -0,0 +1,81 @@
+# Copyright 2015-2018 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 <http://www.gnu.org/licenses/>.
+
+load_lib compile-support.exp
+
+standard_testfile
+
+get_compiler_info
+set options {}
+if [test_compiler_info gcc*] {
+ lappend options additional_flags=-g3
+ lappend options additional_flags=-std=gnu++11
+ lappend options c++
+}
+
+set srcfilesoptions [list ${srcfile} ${options}]
+
+if { [eval build_executable_from_specs ${testfile}.exp $testfile {$options} ${srcfilesoptions}] } {
+ return -1
+}
+
+clean_restart ${testfile}
+
+if {[skip_compile_feature_tests]} {
+ untested "compile command not supported (could not find libcc1 shared library?)"
+ return -1
+}
+
+gdb_test_no_output "set language c++" \
+ "Set language to C++"
+
+if ![runto_main] {
+ return -1
+}
+
+gdb_test "compile print varint" " = 10"
+gdb_test "compile print vararray" " = \\{1, 2, 3, 4, 5\\}"
+gdb_test "compile print main" " = \\{int \\(void\\)\\} 0x\[0-9a-f\]+"
+
+set test "compile print *vararray@3"
+gdb_test_multiple $test $test {
+ -re " = \\{1, 2, 3\\}\r\n$gdb_prompt $" {
+ pass $test
+ }
+ -re "warning: .*All references to this method will be undefined\.\r\n" {
+ exp_continue
+ }
+ -re ": error: stray '@' in program\r\n.*\r\n$gdb_prompt $" {
+ kfail compile/18489 "$test"
+ }
+}
+
+set test "compile print *vararrayp@3"
+gdb_test_multiple $test $test {
+ -re " = \\{1, 2, 3\\}\r\n$gdb_prompt $" {
+ pass $test
+ }
+ -re "warning: .*All references to this method will be undefined\.\r\n" {
+ exp_continue
+ }
+ -re ": error: stray '@' in program\r\n.*\r\n$gdb_prompt $" {
+ kfail compile/18489 "$test"
+ }
+}
+
+gdb_test "compile print/x 256" " = 0x100"
+gdb_test {print $} " = 256"
+
+gdb_test "compile print varobject" { = {field = 1}}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-virtual.cc b/gdb/testsuite/gdb.compile/compile-cplus-virtual.cc
new file mode 100644
index 0000000000..5083726303
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-virtual.cc
@@ -0,0 +1,54 @@
+/* Copyright 2015-2018 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 <http://www.gnu.org/licenses/>. */
+
+struct A
+{
+ virtual int doit (void) { return 1; }
+ virtual int doit3 (void) { return -3; }
+ virtual int doit2 (void) = 0;
+};
+
+struct B : virtual A
+{
+ int doit (void) { return 2; }
+ int doit2 (void) { return 22; }
+};
+
+struct C : virtual A
+{
+ int doit (void) { return 3; }
+ int doit2 (void) { return 33; }
+};
+
+struct D : B, C
+{
+ int doit (void) { return 4; }
+ int doit2 (void) { return 44; }
+};
+
+int
+main (void)
+{
+ int var = 1234;
+ B b;
+ C c;
+ D d;
+ A *ap = &d;
+
+ var = (b.doit () + c.doit () + d.doit () + d.doit3 ()
+ + ap->doit () + ap->doit2 ()); // break here
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-virtual.exp b/gdb/testsuite/gdb.compile/compile-cplus-virtual.exp
new file mode 100644
index 0000000000..696cc03304
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-virtual.exp
@@ -0,0 +1,71 @@
+# Copyright 2015-2018 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 <http://www.gnu.org/licenses/>.
+
+# Virtual method/inheritance tests for GDB's C++ compile feature.
+
+load_lib compile-support.exp
+
+standard_testfile .cc
+
+if {[skip_cplus_tests]} {
+ untested "skipping C++ tests"
+ return
+}
+
+if {[prepare_for_testing $testfile $testfile $srcfile \
+ {debug nowarnings c++}]} {
+ return -1
+}
+
+if {![runto_main]} {
+ untested "could not run to main"
+ return -1
+}
+
+if {[skip_compile_feature_tests]} {
+ untested \
+ "compile command not supported (could not find libcc1 shared library?)"
+ return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+CompileExpression::new "var"
+CompileExpression::test "b.doit ()" 2
+CompileExpression::test "c.doit ()" 3
+CompileExpression::test "d.doit ()" 4
+CompileExpression::test "ap->doit ()" 4
+CompileExpression::test "b.doit2 ()" 22
+CompileExpression::test "c.doit2 ()" 33
+CompileExpression::test "d.doit2 ()" 44
+CompileExpression::test "ap->doit2 ()" 44
+CompileExpression::test "b.doit3 ()" -3
+CompileExpression::test "c.doit3 ()" -3
+CompileExpression::test "d.doit3 ()" -3
+
+# These two tests are "disabled". They represent new/future features.
+# CompileExpression::test \
+ [concat "struct ABC {int doit2(void) { return 3333; }} abc;" \
+ "var = abc.doit2()"] \
+ 3333 -explicit
+# CompileExpression::test \
+ [concat "struct ABC : A {int doit2(void) { return 4444; }} abc;" \
+ "var = abc.doit2()"] \
+ 4444 -explicit
+
+# Test some error conditions
+gdb_test "compile code A a;" \
+ ".*cannot declare variable .a. to be of abstract type.*Compilation failed."
diff --git a/gdb/testsuite/gdb.compile/compile-cplus.c b/gdb/testsuite/gdb.compile/compile-cplus.c
new file mode 100644
index 0000000000..ab14514894
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus.c
@@ -0,0 +1,241 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2014-2018 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 <http://www.gnu.org/licenses/>. */
+
+#include <stdbool.h>
+#include <iostream>
+
+#define SOME_MACRO 23
+#define ARG_MACRO(X, Y) ((X) + (Y) - 1)
+
+
+enum enum_type {
+ ONE = 1,
+ TWO = 2
+};
+
+typedef int v4 __attribute__ ((vector_size (16)));
+
+union union_type;
+
+struct struct_type {
+ char charfield;
+ unsigned char ucharfield;
+ short shortfield;
+ unsigned short ushortfield;
+ int intfield;
+ unsigned int uintfield;
+ unsigned int bitfield : 3;
+ long longfield;
+ unsigned long ulongfield;
+ enum enum_type enumfield;
+ float floatfield;
+ double doublefield;
+ const union union_type *ptrfield;
+ struct struct_type *selffield;
+ int arrayfield[5];
+ _Complex double complexfield;
+ _Bool boolfield;
+ v4 vectorfield;
+};
+
+typedef int inttypedef;
+
+union union_type {
+ int intfield;
+ inttypedef typedeffield;
+};
+
+/* volatile provides some coverage of the conversion code. */
+volatile struct struct_type struct_object;
+
+union union_type union_object;
+
+
+enum ulonger_enum_type {
+ REALLY_MINUS_1 = -1UL,
+};
+
+enum ulonger_enum_type ulonger;
+
+enum longer_enum_type {
+ MINUS_1 = -1,
+ FORCE_TO_LONG = 1L << ((8 * sizeof (long)) - 2)
+};
+
+enum longer_enum_type longer;
+
+int globalvar = 10;
+
+static void
+func_static (int addend)
+{
+ globalvar += addend;
+}
+
+void
+func_global (int subtrahend)
+{
+ globalvar -= subtrahend;
+}
+
+void
+no_args_or_locals (void)
+{
+ /* no_args_or_locals breakpoint */
+}
+
+int *intptr;
+int globalshadow = 10;
+static int staticshadow = 20;
+int externed = 7;
+
+class Base
+{
+ virtual int pure_virt () = 0;
+ public:
+ int return_value () {return a;}
+ private:
+ int a = 1;
+ int b = 2;
+};
+
+class Base2
+{
+ virtual int non_pure () {return 84;}
+ public:
+ int return_value () {return b;}
+ private:
+ int a = 3;
+ int b = 4;
+};
+
+class Base3
+{
+ public:
+ int return_value () {return b;}
+ private:
+ int b = 5;
+};
+
+
+class Multiple : public Base, public Base2
+{
+ int pure_virt ()
+ {
+ int a = Base::return_value ();
+ return a + 42;
+ }
+};
+//struct foo { foo(); virtual ~foo(); }; struct bar : virtual foo { bar(); ~bar(); }; struct baz : bar {}; bar::bar() {} bar::~bar() {} bar t; baz u;
+struct VirtualOnly
+{
+ VirtualOnly();
+ virtual ~VirtualOnly()=0;
+};
+
+VirtualOnly::VirtualOnly ()
+{
+}
+
+VirtualOnly::~VirtualOnly ()
+{
+}
+
+struct VirtualBase : virtual VirtualOnly
+{
+ int z = 22;
+ VirtualBase (void);
+ ~VirtualBase (void);
+};
+
+struct VirtualBase2 : VirtualBase {};
+
+VirtualBase::VirtualBase (void)
+{
+ z = 24;
+}
+
+VirtualBase::~VirtualBase (void)
+{
+ z = 22;
+}
+
+class Foo
+{
+ int var;
+ static const int public_static_var = 12;
+
+ private:
+ int private_var = 0;
+ int private_method (void);
+
+ public:
+ int public_var = 0;
+ int public_method (void);
+ void set_private_var (int);
+};
+
+void Foo::set_private_var (int i)
+{
+ private_var = i;
+}
+
+int Foo::private_method (void)
+{
+ return private_var;
+}
+
+int Foo::public_method (void)
+{
+ return public_var;
+}
+
+int
+main (void)
+{
+ int localvar = 50;
+ int shadowed = 51;
+ int bound = 3;
+ int unresolved = 10;
+ int globalshadow = 100;
+ int staticshadow = 200;
+ int externed = 9;
+ int f = 0;
+ int var = 0;
+ Foo foovar;
+ Multiple *multivar = new Multiple;
+ VirtualBase vbase;
+ VirtualBase2 vbase2;
+ static int static_local = 77000;
+
+ foovar.public_var = 42;
+ foovar.set_private_var (42);
+ multivar->Base2::return_value();
+ {
+ int another_local = 7;
+ int shadowed = 52;
+ extern int unresolved;
+ extern int externed;
+
+ int vla[bound];
+
+ func_static (0); /* break-here */
+ no_args_or_locals ();
+ }
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus.exp b/gdb/testsuite/gdb.compile/compile-cplus.exp
new file mode 100644
index 0000000000..cb8d9cbdfd
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus.exp
@@ -0,0 +1,341 @@
+# Copyright 2014-2018 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 <http://www.gnu.org/licenses/>.
+
+load_lib compile-support.exp
+
+standard_testfile .c compile-shlib.c compile-constvar.S compile-nodebug.c
+
+get_compiler_info
+set options {}
+if [test_compiler_info gcc*] {
+ lappend options additional_flags=-g3
+ lappend options additional_flags=-std=gnu++11
+ lappend options c++
+}
+
+if { ![istarget x86_64-*-* ] || ![is_lp64_target] } {
+ verbose "Skipping x86_64 LOC_CONST test."
+ set srcfile3 ""
+}
+
+set srcfilesoptions [list ${srcfile} ${options}]
+if { $srcfile3 != "" } {
+ lappend srcfilesoptions $srcfile3 ${options}
+}
+lappend srcfilesoptions $srcfile4 "nodebug c++"
+if { [eval build_executable_from_specs ${testfile}.exp $testfile {$options} ${srcfilesoptions}] } {
+ return -1
+}
+
+clean_restart ${testfile}
+
+#
+# FIXME: Right now, for C++ we just duplicate the C tests, but force
+# the language to C++
+#
+gdb_test_no_output "set language c++" \
+ "Set language to C++"
+
+if ![runto_main] {
+ return -1
+}
+
+if {[skip_compile_feature_tests]} {
+ untested "compile command not supported (could not find libcc1 shared library?)"
+ return -1
+}
+
+#
+# Test delimiter for code, and arguments.
+#
+
+
+gdb_test_no_output "compile code globalvar = SOME_MACRO;" \
+ "set variable from macro"
+gdb_test "p globalvar" " = 23" "expect 23"
+
+gdb_test_no_output "compile code globalvar = ARG_MACRO(0, 0);" \
+ "set variable from function-like macro"
+gdb_test "p globalvar" " = -1" "expect -1"
+
+gdb_test_no_output "compile code globalvar = 42;" "set variable"
+gdb_test "p globalvar" " = 42" "expect 42"
+
+gdb_test_no_output "compile code globalvar *= 2;" "modify variable"
+gdb_test "p globalvar" " = 84" "expect 84"
+
+gdb_test_no_output "compile file -r ${srcdir}/${subdir}/${testfile}-mod.c" \
+ "use external source file"
+gdb_test "p globalvar" " = 7" "expect 7"
+
+gdb_test_no_output "compile code func_static (2);" "call static function"
+gdb_test "p globalvar" " = 9" "expect 9"
+gdb_test_no_output "compile code func_global (1);" "call global function"
+gdb_test "p globalvar" " = 8" "expect 8"
+
+gdb_test_no_output \
+ "compile code globalvar = (sizeof (ulonger) == sizeof (long))" \
+ "compute size of ulonger"
+gdb_test "p globalvar" " = 1" "check size of ulonger"
+gdb_test_no_output \
+ "compile code globalvar = (sizeof (longer) == sizeof (long))" \
+ "compute size of longer"
+gdb_test "p globalvar" " = 1" "check size of longer"
+gdb_test_no_output "compile code globalvar = MINUS_1"
+gdb_test "p globalvar" " = -1" "check MINUS_1"
+
+gdb_test_no_output "compile code globalvar = static_local"
+gdb_test "p globalvar" " = 77000" "check static_local"
+
+gdb_test_no_output \
+ "compile code static int staticvar = 5; intptr = &staticvar" \
+ "do not keep jit in memory"
+gdb_test "p *intptr" "Cannot access memory at address 0x\[0-9a-f\]+" \
+ "expect 5"
+
+gdb_test "compile code func_doesnotexist ();" "error: \'func_doesnotexist\' was not declared in this scope.*"
+
+gdb_test "compile code *(volatile int *) 0 = 0;" \
+ "The program being debugged was signaled while in a function called from GDB\\.\r\nGDB remains in the frame where the signal was received\\.\r\n.*" \
+ "compile code segfault first"
+gdb_test "bt" \
+ "\r\n#0 \[^\r\n\]* in _gdb_expr \[^\r\n\]*\r\n#1 <function called from gdb>\r\n.*"
+
+set test "p/x \$pc"
+set infcall_pc 0
+gdb_test_multiple $test $test {
+ -re " = (0x\[0-9a-f\]+)\r\n$gdb_prompt $" {
+ set infcall_pc $expect_out(1,string)
+ pass $test
+ }
+}
+
+gdb_test "info sym $infcall_pc" "\r\n_gdb_expr.*" "info sym found"
+gdb_test "return" "\r\n#0 main .*" "return" \
+ "Make _gdb_expr\\(__gdb_regs\\*\\) return now\\? \\(y or n\\) " "y"
+gdb_test "info sym $infcall_pc" "\r\nNo symbol matches .*" "info sym not found"
+
+gdb_test_no_output "set unwindonsignal on"
+gdb_test "compile code *(volatile int *) 0 = 0;" \
+ "The program being debugged was signaled while in a function called from GDB\\.\r\nGDB has restored the context to what it was before the call\\.\r\n.*" \
+ "compile code segfault second"
+
+gdb_breakpoint [gdb_get_line_number "break-here"]
+gdb_continue_to_breakpoint "break-here" ".* break-here .*"
+
+# C++ Specific tests.
+## Public methods and members
+
+gdb_test "print foovar.public_var" "42" \
+ "Test compile code foovar.public_var = 42 setting."
+gdb_test_no_output "compile code foovar.public_var = 43;" \
+ "set foobar.public_var to 43"
+gdb_test "print foovar.public_var" "43" \
+ "Test compile code foovar.public_var = 43 setting."
+gdb_test "print foovar.public_method ()" "43" \
+ "Test compile code foovar.public_method = 43 setting."
+
+## Private methods and members
+gdb_test_no_output "compile code foovar.set_private_var (84);" \
+ "Call class function to set private_var"
+gdb_test "print foovar.private_var" "84" \
+ "Test compile code foovar.set_private_var = 84 setting."
+gdb_test_no_output "compile code foovar.private_var = 85" \
+ "Directly set a private member in GDB compile5"
+gdb_test "print foovar.private_var" "85" \
+ "Test compile code foovar.set_private_var = 85 setting."
+
+## Simple inheritance
+CompileExpression::new "var"
+CompileExpression::test "class Baz: public Foo {public: int z = 12;}; Baz bazvar; bazvar.z = 24; var = bazvar.z" 24 -explicit
+## Multiple inheritance
+CompileExpression::test "class MI: public Base, public Base2 {int pure_virt () {return 42;}}; MI MIVar; var = MIVar.pure_virt();" 42 -explicit
+CompileExpression::test "class MI: public Base, public Base2 {int pure_virt () {return Base::return_value() + 42;}}; MI MIVar; var = MIVar.pure_virt();" 43 -explicit
+CompileExpression::test "class Base3 {public: int z = 99;}; class MI: public Base, public Base3 {int pure_virt () {return Base3::z + 42;}}; MI MIVar; var = MIVar.pure_virt();" 141 -explicit
+
+gdb_test "p localvar" " = 50" "expect localvar 50"
+
+gdb_test_no_output "compile code localvar = 12;" "set localvar"
+gdb_test "p localvar" " = 12" "expect 12"
+
+gdb_test_no_output "compile code localvar *= 2;" "modify localvar"
+gdb_test "p localvar" " = 24" "expect 24"
+
+gdb_test_no_output "compile code localvar = shadowed" \
+ "test shadowing"
+gdb_test "p localvar" " = 52" "expect 52"
+
+gdb_test_no_output "compile code localvar = externed"
+gdb_test "p localvar" " = 7" "test extern in inner scope"
+
+gdb_test_no_output "compile code vla\[2\] = 7"
+gdb_test "p vla\[2\]" " = 7"
+gdb_test_no_output \
+ "compile code localvar = (sizeof (vla) == bound * sizeof (vla\[0\]))"
+gdb_test "p localvar" " = 1"
+
+#
+# Test setting fields and also many different types.
+#
+
+gdb_test_no_output "compile code struct_object.selffield = (struct_type*)&struct_object"
+gdb_test "print struct_object.selffield == &struct_object" " = true"
+
+gdb_test_no_output "compile code struct_object.charfield = 1"
+gdb_test "print struct_object.charfield" " = 1 '\\\\001'"
+gdb_test_no_output "compile code struct_object.ucharfield = 1"
+gdb_test "print struct_object.ucharfield" " = 1 '\\\\001'"
+
+foreach {field value} {
+ shortfield -5
+ ushortfield 5
+ intfield -7
+ uintfield 7
+ bitfield 2
+ longfield -9
+ ulongfield 9
+ enumfield ONE
+ floatfield 1
+ doublefield 2
+} {
+ gdb_test_no_output "compile code struct_object.$field = $value"
+ gdb_test "print struct_object.$field" " = $value"
+}
+
+gdb_test_no_output "compile code struct_object.arrayfield\[2\] = 7"
+gdb_test "print struct_object.arrayfield" \
+ " = \\{0, 0, 7, 0, 0\\}"
+
+gdb_test_no_output "compile code struct_object.complexfield = 7 + 5i"
+gdb_test "print struct_object.complexfield" " = 7 \\+ 5 \\* I"
+
+gdb_test_no_output "compile code struct_object.boolfield = 1"
+gdb_test "print struct_object.boolfield" " = true"
+
+gdb_test_no_output "compile code struct_object.vectorfield\[2\] = 7"
+gdb_test "print struct_object.vectorfield" \
+ " = \\{0, 0, 7, 0\\}"
+
+gdb_test_no_output "compile code union_object.typedeffield = 7"
+gdb_test "print union_object.typedeffield" " = 7"
+gdb_test "print union_object.intfield" " = 7"
+
+
+# LOC_UNRESOLVED tests.
+
+gdb_test "print unresolved" " = 20"
+gdb_test "compile code globalvar = unresolved;"
+gdb_test "print globalvar" " = 20" "print unresolved value"
+
+# Test shadowing with global and static variables.
+
+gdb_test_no_output "compile code globalshadow += 1;"
+gdb_test "print globalshadow" " = 101"
+gdb_test_no_output "compile code extern int globalshadow; globalshadow += 5;"
+gdb_test "print 'compile-cplus.c'::globalshadow" " = 15"
+gdb_test "print globalshadow" " = 101" "print globalshadow second time"
+gdb_test_no_output "compile code staticshadow += 2;"
+gdb_test "print staticshadow" " = 202"
+# "extern int staticshadow;" cannot access static variable.
+
+# Raw code cannot refer to locals.
+# As it references global variable we need the #pragma.
+# For #pragma we need multiline input.
+gdb_test_multiple "compile code -r" "compile code -r multiline 1" { -re "\r\n>$" {} }
+gdb_test_multiple "void _gdb_expr(void) {" "compile code -r multiline 2" { -re "\r\n>$" {} }
+gdb_test_multiple "#pragma GCC push_user_expression" "compile code -r multiline 3" { -re "\r\n>$" {} }
+gdb_test_multiple " globalshadow = 77000;" "compile code -r multiline 4" { -re "\r\n>$" {} }
+gdb_test_multiple "#pragma GCC pop_user_expression" "compile code -r multiline 5" { -re "\r\n>$" {} }
+gdb_test_multiple "}" "compile code -r multiline 6" { -re "\r\n>$" {} }
+gdb_test_no_output "end" "compile code -r multiline 7"
+gdb_test "print 'compile-cplus.c'::globalshadow" " = 77000" \
+ "check globalshadow with -r"
+
+# Test GOT vs. resolving jit function pointers.
+
+gdb_test_no_output "compile -raw -- extern \"C\" void abort(); int func(){return 21;} void _gdb_expr(){int (*funcp)()=func; if (funcp()!=21) abort();}" \
+ "pointer to jit function"
+
+#
+# Test the case where the registers structure would not normally have
+# any fields.
+#
+
+gdb_breakpoint [gdb_get_line_number "no_args_or_locals breakpoint"]
+gdb_continue_to_breakpoint "no_args_or_locals"
+
+gdb_test_no_output "compile code globalvar = 77;" "set variable to 77"
+gdb_test "p globalvar" " = 77" "expect 77"
+
+
+# Test reference to minimal_symbol, not (full) symbol.
+
+gdb_test_no_output "compile code globalvar = func_nodebug (75);" \
+ "call func_nodebug"
+gdb_test "p globalvar" " = -75" "expect -75"
+gdb_test_no_output \
+ "compile code int (*funcp) (int) = (int(*)(int))func_nodebug; globalvar = funcp (76);" \
+ "call func_nodebug indirectly"
+gdb_test "p globalvar" " = -76" "expect -76"
+
+
+# Test compiled module memory protection.
+
+gdb_test_no_output "set debug compile on"
+gdb_test "compile code static const int readonly = 1; *(int *) &readonly = 2;" \
+ "The program being debugged was signaled while in a function called from GDB\\.\r\nGDB has restored the context to what it was before the call\\.\r\n.*"
+gdb_test_no_output "set debug compile off"
+
+
+#
+# Some simple coverage tests.
+#
+
+gdb_test "show debug compile" "Compile debugging is .*"
+gdb_test "show compile-args" \
+ "Compile command command-line arguments are .*"
+gdb_test "compile code -z" "Unknown argument.*"
+
+gdb_test "set lang rust" \
+ "Warning: the current language does not match this frame."
+gdb_test "compile code globalvar" "No compiler support for language rust\."
+gdb_test_no_output "set lang auto"
+
+gdb_test_no_output "compile code union union_type newdecl_u"
+gdb_test_no_output "compile code struct struct_type newdecl_s"
+gdb_test_no_output "compile code inttypedef newdecl_i"
+
+gdb_test "compile file" \
+ "You must provide a filename for this command.*" \
+ "Test compile file without a filename"
+gdb_test "compile file -r" \
+ "You must provide a filename with the raw option set.*" \
+ "Test compile file and raw option without a filename"
+gdb_test "compile file -z" \
+ "Unknown argument.*" \
+ "Test compile file with unknown argument"
+
+
+# LOC_CONST tests.
+
+if { $srcfile3 != "" } {
+ gdb_test "p constvar" " = 3"
+ gdb_test "info addr constvar" {Symbol "constvar" is constant\.}
+
+ gdb_test "compile code globalvar = constvar;"
+ gdb_test "print globalvar" " = 3" "print constvar value"
+} else {
+ untested "print constvar value"
+}
diff --git a/gdb/testsuite/lib/compile-support.exp b/gdb/testsuite/lib/compile-support.exp
new file mode 100644
index 0000000000..b784c3549b
--- /dev/null
+++ b/gdb/testsuite/lib/compile-support.exp
@@ -0,0 +1,227 @@
+# Copyright 2015-2018 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 <http://www.gnu.org/licenses/>.
+
+# Generic/oft used support routines for testing GDB's compile feature.
+
+# Return 1 if we should skip tests of the "compile" feature.
+# This must be invoked after the inferior has been started.
+
+proc skip_compile_feature_tests {} {
+ global gdb_prompt
+
+ set result 0
+ gdb_test_multiple "compile code -- ;" "check for working compile command" {
+ "Could not load libcc1.*\r\n$gdb_prompt $" {
+ set result 1
+ }
+ -re "Command not supported on this host\\..*\r\n$gdb_prompt $" {
+ set result 1
+ }
+ -re "\r\n$gdb_prompt $" {
+ }
+ }
+ return $result
+}
+
+# This namespace provides some convenience functions for running
+# "compile code" and "compile print" tests.
+#
+# Exported functions are defined inline below.
+#
+# General usage:
+#
+# Start a new session, noting that the variable "var" will be used for
+# "compile code" expressions. This variable /must/ exist in the stopped
+# location.
+#
+# CompileExpression::new "var"
+#
+# Test the implicit expression "foo;" with result/value 3.
+# CompileExpression::test "foo" 3
+# ---> Runs the following tests (name of tests ignored for illustration)
+# gdb_test_no_output "compile code var = foo"
+# gdb_test "p var" "= 3"
+# gdb_test "compile print foo;" "= 3"
+#
+# Test the explicit expression "a = function (3); var = a;" with the result 21.
+# CompileExpression::test "a = function (3); var = a;" 21 -explicit
+# ---> Runs the following tests (name of tests ignored for illustration)
+# gdb_test_no_output "compile code a = function (3); var = a;"
+# gdb_test "p var" "= 21"
+#
+# Additional option flags may be passed to test to control the behavior
+# of the test harness:
+#
+# Pass -explicit to specify that the test uses an explicit expression,
+# one which sets the value of the variable (see above). Only the code test
+# will be run.
+#
+# Pass -value and/or -print to indicate that the value and/or print steps
+# will optionally fail. Specify "xfail" or "kfail" to indicate how
+# particular step will fail. These may be followed by any accepted DejaGNU
+# parameters such as architecture and bug#. [See examples below.]
+#
+# To specify that the compile (and consequently print and value tests) is
+# expected to kfail/xfail, use -kfail or -xfail with any appropriate
+# DejaGNU parameters. Both options override -print and -value.
+# [-xfail is given precedence over -kfail should both be given.]
+#
+# -value is used when a "code" test is run, specifying that the "compile
+# code" and "print VAR" steps will fail in the prescribed manner.
+# [If the print step generates a PASS, the test is considered invalidly
+# written. VAR's value should /always/ be invalidated before a test is
+# run.]
+#
+# -print is used to specify that an expression will fail in the prescribed
+# manner when "print" test is executed.
+#
+# Pass "-name NAME" to set an optional test name. If not specified,
+# the harness will use test names such as "compile code EXPR" and
+# "result of compile code EXPR".
+#
+# Pass "-noprint" or "-nocode" to suppress print or code tests, respectively,
+# This is useful when the expression being tested modifies the object
+# being tested, e.g., "a++".
+#
+# These options must be passed LAST to CompileExpression::test.
+#
+# Examples:
+#
+# Both "code" and "print" tests are expected to xfail:
+# CompileExpression add_imp "foo" 3 -compile {xfail *-*-*} -print {xfail *-*-*}
+#
+# The "print $VARIABLE" portion of the "code" test is expected to kfail
+# (the actual "compile code" GDB command will succeed), but the "print"
+# test should pass:
+# CompileExpression add_imp "foo" 3 -value {kfail *-*-* gdb/1234}
+
+namespace eval ::CompileExpression {
+
+ # The variable name to check testing results. This variable
+ # must be in scope when tests are run.
+ variable varName_ {}
+
+ # Start a new expression list. VARNAME is the name of the variable
+ # that will be printed to check if the result of the test was
+ # successful.
+ proc new {varname} {
+ variable varName_
+
+ set varName_ $varname
+ }
+
+ # Test an expression.
+ #
+ # See the preamble for a list of valid optional arguments.
+ #
+ # Implicit expressions will be sent to GDB in the form
+ # "$varName = $EXP". "p $varName" will be used to decide the pass
+ # or fail status of the test.
+ #
+ # Explicit expressions will be sent to GDB as-is and tested using only
+ # "compile code". The expression should set the value of the variable
+ # $varName, which is then printed to determine whether the test passed
+ # or failed.
+ #
+ # Unlike explicit expressions, implicit expressions are tested with both
+ # "compile print" and "compile code".
+
+ proc test {exp result args} {
+ parse_args {{value {"" ""}} {print {"" ""}} {name ""}
+ {noprint} {nocode} {explicit} {xfail {"" ""}} {kfail {"" ""}}}
+
+ if {[lindex $xfail 0] != ""} {
+ set l "xfail $xfail"
+ } elseif {[lindex $kfail 0] != ""} {
+ set l "kfail $kfail"
+ } else {
+ set l ""
+ set compile {"" ""}
+ }
+ if {$l != ""} {
+ set compile $l
+ set print $l
+ set value $l
+ }
+
+ if {!$nocode} {
+ do_test_ code $exp $result $explicit $name \
+ [list $compile $value $print]
+ }
+ if {!$noprint} {
+ do_test_ print $exp $result $explicit $name \
+ [list $compile $value $print]
+ }
+ }
+
+ # Run a compile test for CMD ("print" or "code").
+
+ proc do_test_ {cmd exp result is_explicit tst fail_list} {
+ variable varName_
+
+ if {![string match $cmd "code"]
+ && ![string match $cmd "print"]} {
+ error "invalid command, $cmd; should be \"print\" or \"compile\""
+ }
+
+ # Get expected result of test. Will be "" if test is
+ # expected to PASS.
+ lassign $fail_list fail_compile fail_value fail_print
+
+ # Set a test name if one hasn't been provided.
+ if {$tst == ""} {
+ set tst "compile $cmd $exp"
+ }
+
+ if {[string match $cmd "print"]} {
+ if {!$is_explicit} {
+ eval setup_failures_ $fail_print
+ gdb_test "compile print $exp" $result $tst
+ }
+ } else {
+ if {$is_explicit} {
+ set command "compile code $exp"
+ } else {
+ set command "compile code $varName_ = $exp"
+ }
+ eval setup_failures_ $fail_compile
+ gdb_test_no_output $command $tst
+ eval setup_failures_ $fail_value
+ gdb_test "p $varName_" "= $result" "result of $tst"
+ }
+ }
+
+ # A convenience proc used to set up xfail and kfail tests.
+ # HOW is either xfail or kfail (case is ignored). ARGS is any
+ # optional architecture, bug number, or other string to pass to
+ # respective DejaGNU setup_$how routines.
+
+ proc setup_failures_ {how args} {
+ switch -nocase $how {
+ xfail {
+ eval setup_xfail $args
+ }
+
+ kfail {
+ eval setup_kfail $args
+ }
+
+ default {
+ # Do nothing. Either the test is expected to PASS
+ # or we have an unhandled failure mode.
+ }
+ }
+ }
+}
--
2.13.6