This is the mail archive of the gdb-cvs@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[binutils-gdb] C++ compile support


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=078a020797210f4d8f9491bbfe16ec31e9efb652

commit 078a020797210f4d8f9491bbfe16ec31e9efb652
Author: Keith Seitz <keiths@redhat.com>
Date:   Wed Aug 29 15:12:24 2018 -0700

    C++ compile support
    
    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.
    
    I've added a new option for outputting debug messages for C++ type-conversion
    ("debug compile-cplus-types").
    
    gdb/ChangeLog:
    
    	* Makefile.in (SUBDIR_GCC_COMPILE_SRCS): Add 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-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.

Diff:
---
 gdb/ChangeLog                                      |   29 +
 gdb/Makefile.in                                    |    4 +
 gdb/NEWS                                           |   14 +
 gdb/c-lang.c                                       |    4 +-
 gdb/c-lang.h                                       |   19 +
 gdb/compile/compile-c-support.c                    |  205 ++-
 gdb/compile/compile-cplus-symbols.c                |  493 +++++++
 gdb/compile/compile-cplus-types.c                  | 1427 ++++++++++++++++++++
 gdb/compile/compile-cplus.h                        |  205 +++
 gdb/compile/compile-internal.h                     |    4 +
 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                                |   10 +
 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 |   76 ++
 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  |   79 ++
 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        |  347 +++++
 gdb/testsuite/lib/compile-support.exp              |  227 ++++
 38 files changed, 4449 insertions(+), 30 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index d82257e..43e22e2 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,34 @@
 2018-08-29  Keith Seitz  <keiths@redhat.com>
 
+	* Makefile.in (SUBDIR_GCC_COMPILE_SRCS): Add 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-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.
+
+2018-08-29  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 542170f..438379e 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -317,6 +317,8 @@ SUBDIR_GCC_COMPILE_SRCS = \
 	compile/compile-c-support.c \
 	compile/compile-c-symbols.c \
 	compile/compile-c-types.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
@@ -1464,10 +1466,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 0ad8ae5..75436b0 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,14 @@
 
 *** Changes since GDB 8.2
 
+* GDB now has experimental support for the compilation and injection of
+  C++ source code into the inferior.  This beta release does not include
+  support for several language features, such as templates, constructors,
+  and operators.
+
+  This feature requires GCC 7.1 or higher built with libcp1.so
+  (the C++ plug-in).
+
 * GDB and GDBserver now support IPv6 connections.  IPv6 addresses
   can be passed using the '[ADDRESS]:PORT' notation, or the regular
   'ADDRESS:PORT' method.
@@ -15,6 +23,12 @@
 
 * New commands
 
+set debug compile-cplus-types
+show debug compile-cplus-types
+  Control the display of debug output about type conversion in the
+  C++ compile feature.  Commands have no effect while compiliong
+  for other languages.
+
 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 5ad5801..6bae4c1 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 b7bf089..ae17abd 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 ();
+
 /* 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 e8993aa..5c700bb 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)
 
 
 
-/* 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 ()
+{
+  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 ()
+{
+  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);
 }
 
 
@@ -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-symbols.c b/gdb/compile/compile-cplus-symbols.c
new file mode 100644
index 0000000..0f849fe
--- /dev/null
+++ b/gdb/compile/compile-cplus-symbols.c
@@ -0,0 +1,493 @@
+/* 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"
+
+/* 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 = compile_cplus_instance::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 (compile_debug)
+    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 ())
+	{
+	  /* Don't convert the symbol found above, if any, twice!  */
+	  if (it.symbol != sym.symbol)
+	    {
+	      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 (compile_debug)
+    {
+      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 (compile_debug)
+    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 (compile_debug)
+    {
+      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;
+}
diff --git a/gdb/compile/compile-cplus-types.c b/gdb/compile/compile-cplus-types.c
new file mode 100644
index 0000000..9425fc6
--- /dev/null
+++ b/gdb/compile/compile-cplus-types.c
@@ -0,0 +1,1427 @@
+/* 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>
+compile_cplus_instance::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)
+    {
+      const char *symbol = (comp.bsymbol.symbol != nullptr
+			    ? SYMBOL_NATURAL_NAME (comp.bsymbol.symbol)
+			    : "<none>");
+
+      printf_unfiltered ("\tname = %s, symbol = %s\n", comp.name.c_str (),
+			 symbol);
+    }
+}
+
+/* See description in compile-cplus.h.  */
+
+compile_scope
+type_name_to_scope (const char *type_name, const struct block *block)
+{
+  compile_scope scope;
+
+  if (type_name == nullptr)
+    {
+      /* An anonymous type.  We cannot really do much here.  We simply cannot
+	 look up anonymous types easily/at all.  */
+      return scope;
+    }
+
+  const char *p = type_name;
+  std::string lookup_name;
+
+  while (*p != '\0')
+    {
+      /* Create a string token of the first component of TYPE_NAME.  */
+      int len = cp_find_first_component (p);
+      std::string s (p, len);
+
+      /* Advance past the last token.  */
+      p += len;
+
+      /* Look up the symbol and decide when to stop.  */
+      if (!lookup_name.empty ())
+	lookup_name += "::";
+      lookup_name += s;
+
+      /* Look up the resulting name.  */
+      struct block_symbol bsymbol
+	= lookup_symbol (lookup_name.c_str (), block, 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)).get (),
+		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
+    = compile_cplus_instance::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
+	= compile_cplus_instance::decl_name (TYPE_FN_FIELDLIST_NAME (type, i));
+
+      /* Loop through the fieldlist, adding decls to the compiler's
+	 representation of the class.  */
+      for (int j = 0; j < TYPE_FN_FIELDLIST_LENGTH (type, i); ++j)
+	{
+	  /* Skip artificial methods.  */
+	  if (TYPE_FN_FIELD_ARTIFICIAL (methods, j))
+	    continue;
+
+	  gcc_cp_symbol_kind_flags sym_kind = GCC_CP_SYMBOL_FUNCTION;
+	  gcc_type method_type;
+	  struct block_symbol sym
+	    = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (methods, j),
+			     instance->block (), 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
+    = compile_cplus_instance::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
+    = compile_cplus_instance::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
+	= compile_cplus_instance::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
+    = compile_cplus_instance::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 %d"),
+				 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;
+}
+
+void
+compile_cplus_instance::gcc_cplus_enter_scope
+ (void *datum, struct gcc_cp_context *gcc_context)
+{
+}
+
+void
+compile_cplus_instance::gcc_cplus_leave_scope
+  (void *datum, struct gcc_cp_context *gcc_context)
+{
+}
+
+
+
+/* Plug-in forwards.  */
+
+/* C++ plug-in wrapper.  */
+
+/* A result printer for plug-in calls that return a gcc_type or
+   gcc_decl.  */
+
+static void
+compile_cplus_debug_output_1 (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 ()
+{
+  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 0000000..7baa57d
--- /dev/null
+++ b/gdb/compile/compile-cplus.h
@@ -0,0 +1,205 @@
+/* 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;
+
+/* 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);
+
+  /* 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.  */
+  static gdb::unique_xmalloc_ptr<char> decl_name (const char *natural);
+
+private:
+
+  /* Callbacks suitable for use as the GCC C++ enter/leave scope requests.  */
+  static gcc_cp_enter_leave_user_expr_scope_function gcc_cplus_enter_scope;
+  static gcc_cp_enter_leave_user_expr_scope_function gcc_cplus_leave_scope;
+
+  /* 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;
+};
+
+/* 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 c8d2d2f..a6e7330 100644
--- a/gdb/compile/compile-internal.h
+++ b/gdb/compile/compile-internal.h
@@ -164,6 +164,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 a83f95d..873750b 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 20d81cb..6d51006 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 0000000..1b72726
--- /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 c637d39..58e01e4 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,8 @@
+2018-08-29  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-22  Jan Vrany  <jan.vrany@fit.cvut.cz>
 
 	* gdb.texinfo (The -stack-list-frames Command): Update description
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 5068c0a..f2d1155 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18689,6 +18689,16 @@ 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-cplus-types}
+@item set debug compile-cplus-types
+@cindex compile C@t{++} type conversion
+Turns on or off the display of C@t{++} type conversion debugging information.
+The default is off.
+
+@item show debug compile-cplus-types
+Displays the current state of displaying debugging information for
+C@t{++} type conversion.
 @end table
 
 @subsection Compilation options for the @code{compile} command
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 5145fd6..0164558 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,28 @@
+2018-08-29  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-16  Gary Benson <gbenson@redhat.com>
 
 	PR gdb/13000:
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 0000000..95c4430
--- /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 () : 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 ()
+{
+  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 0000000..ebfb941
--- /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/23588 *-*-*"
+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 0000000..da51a65
--- /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 0000000..fb3e63f
--- /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 0000000..1d93f9c
--- /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 ()
+{
+  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 0000000..1978cb5
--- /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 0000000..d742318
--- /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);
+
[...]

[diff truncated at 100000 bytes]


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]