]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Compile C++ feature. users/keiths/c++compile-submit
authorKeith Seitz <keiths@redhat.com>
Fri, 17 Feb 2017 21:50:40 +0000 (13:50 -0800)
committerKeith Seitz <keiths@redhat.com>
Tue, 21 Feb 2017 21:33:46 +0000 (13:33 -0800)
41 files changed:
gdb/Makefile.in
gdb/c-lang.c
gdb/c-lang.h
gdb/compile/compile-c-support.c
gdb/compile/compile-cplus-support.c [new file with mode: 0644]
gdb/compile/compile-cplus-symbols.c [new file with mode: 0644]
gdb/compile/compile-cplus-templates.c [new file with mode: 0644]
gdb/compile/compile-cplus-templates.h [new file with mode: 0644]
gdb/compile/compile-cplus-types.c [new file with mode: 0644]
gdb/compile/compile-cplus.h [new file with mode: 0644]
gdb/compile/compile-internal.h
gdb/compile/compile-object-load.c
gdb/compile/compile.c
gdb/testsuite/gdb.compile/compile-cplus-mod.c [new file with mode: 0644]
gdb/testsuite/gdb.compile/compile-cplus-print.c [new file with mode: 0644]
gdb/testsuite/gdb.compile/compile-cplus-print.exp [new file with mode: 0644]
gdb/testsuite/gdb.compile/compile-cplus.c [new file with mode: 0644]
gdb/testsuite/gdb.compile/compile-cplus.exp [new file with mode: 0644]
gdb/testsuite/gdb.compile/cp-namespace-template.cc [new file with mode: 0644]
gdb/testsuite/gdb.compile/cp-namespace-template.exp [new file with mode: 0644]
gdb/testsuite/gdb.compile/cp-simple-anonymous.cc [new file with mode: 0644]
gdb/testsuite/gdb.compile/cp-simple-anonymous.exp [new file with mode: 0644]
gdb/testsuite/gdb.compile/cp-simple-inherit.cc [new file with mode: 0644]
gdb/testsuite/gdb.compile/cp-simple-inherit.exp [new file with mode: 0644]
gdb/testsuite/gdb.compile/cp-simple-member.cc [new file with mode: 0644]
gdb/testsuite/gdb.compile/cp-simple-member.exp [new file with mode: 0644]
gdb/testsuite/gdb.compile/cp-simple-method.cc [new file with mode: 0644]
gdb/testsuite/gdb.compile/cp-simple-method.exp [new file with mode: 0644]
gdb/testsuite/gdb.compile/cp-simple-nested.cc [new file with mode: 0644]
gdb/testsuite/gdb.compile/cp-simple-nested.exp [new file with mode: 0644]
gdb/testsuite/gdb.compile/cp-simple-ns.cc [new file with mode: 0644]
gdb/testsuite/gdb.compile/cp-simple-ns.exp [new file with mode: 0644]
gdb/testsuite/gdb.compile/cp-simple-template.cc [new file with mode: 0644]
gdb/testsuite/gdb.compile/cp-simple-template.exp [new file with mode: 0644]
gdb/testsuite/gdb.compile/cp-simple-virtual.cc [new file with mode: 0644]
gdb/testsuite/gdb.compile/cp-simple-virtual.exp [new file with mode: 0644]
gdb/testsuite/gdb.compile/cp-special-function.cc [new file with mode: 0644]
gdb/testsuite/gdb.compile/cp-special-function.exp [new file with mode: 0644]
gdb/testsuite/lib/compile-support.exp [new file with mode: 0644]
include/gcc-cp-fe.def [new file with mode: 0644]
include/gcc-cp-interface.h [new file with mode: 0644]

index 43253d3dc15d1f2114694bc38514abf2a800899b..3686fb60fe63d162c51242717bd8ff5d9146bbcb 100644 (file)
@@ -354,6 +354,10 @@ SUBDIR_GCC_COMPILE_OBS = \
        compile-c-support.o \
        compile-c-symbols.o \
        compile-c-types.o \
+       compile-cplus-support.o \
+       compile-cplus-symbols.o \
+       compile-cplus-templates.o \
+       compile-cplus-types.o \
        compile-loc2c.o \
        compile-object-load.o \
        compile-object-run.o
@@ -363,6 +367,10 @@ SUBDIR_GCC_COMPILE_SRCS = \
        compile/compile-c-support.c \
        compile/compile-c-symbols.c \
        compile/compile-c-types.c \
+       compile/compile-cplus-support.c \
+       compile/compile-cplus-symbols.c \
+       compile/compile-cplus-templates.c \
+       compile/compile-cplus-types.c \
        compile/compile-loc2c.c \
        compile/compile-object-load.c \
        compile/compile-object-load.h \
index a61540d272fbf12bb45580f62b7826b2c877af2d..1d69338f5aacbb9a01ce273bc15f4f770fd51568 100644 (file)
@@ -1068,8 +1068,8 @@ const struct language_defn cplus_language_defn =
   iterate_over_symbols,
   cplus_compute_string_hash,
   &cplus_varobj_ops,
-  NULL,
-  NULL,
+  cplus_get_compile_context,
+  cplus_compute_program,
   LANG_MAGIC
 };
 
index 58a81b01fce8acf294dd44f3393b940375ea583a..6fdcaa4f90b2b180f8eb538342b94f9940a360e3 100644 (file)
@@ -152,6 +152,14 @@ extern int c_textual_element_type (struct type *, char);
 
 extern compile::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::compile_instance *cplus_get_compile_context (void);
+
 /* This takes the user-supplied text and returns a new bit of code to
    compile.
 
@@ -164,4 +172,15 @@ extern std::string c_compute_program (compile::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::compile_instance *inst,
+                                         const char *input,
+                                         struct gdbarch *gdbarch,
+                                         const struct block *expr_block,
+                                         CORE_ADDR expr_pc);
+
 #endif /* !defined (C_LANG_H) */
index ead2bddf210616111784b38c83a7d896ce4ece9f..02421f054d59ae184be0c3ef0dd6b3dac2f0c4ad 100644 (file)
@@ -1,4 +1,4 @@
-/* C language support for compilation.
+/* C/C++ language support for compilation.
 
    Copyright (C) 2014-2017 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"
@@ -130,6 +131,20 @@ c_get_compile_context (void)
      GCC_FE_VERSION_0, GCC_C_FE_VERSION_0);
 }
 
+/* A C++-language implementation of get_compile_context.  */
+
+compile::compile_instance *
+cplus_get_compile_context (void)
+{
+  using namespace compile;
+
+  return get_compile_context
+    <compile_cplus_instance, gcc_cp_fe_context_function, gcc_cp_context,
+     gcc_base_api_version, gcc_cp_api_version>
+    (STRINGIFY (GCC_CP_FE_LIBCC), STRINGIFY (GCC_CP_FE_CONTEXT),
+     GCC_FE_VERSION_0, GCC_CP_FE_VERSION_0);
+}
+
 \f
 
 /* Write one macro definition.  */
@@ -392,6 +407,108 @@ 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_ADDRESS_SCOPE:
+      case COMPILE_I_PRINT_VALUE_SCOPE:
+       fprintf_unfiltered
+         (buf,
+          "auto " COMPILE_I_EXPR_VAL " = %s;\n"
+          "decltype ( %s ) *" COMPILE_I_EXPR_PTR_TYPE ";\n"
+          "std::memcpy (" COMPILE_I_PRINT_OUT_ARG ", %s ("
+          COMPILE_I_EXPR_VAL "),\n"
+          "sizeof (decltype(%s)));\n"
+          ,input, input,
+          (type == COMPILE_I_PRINT_ADDRESS_SCOPE
+           ? "std::__addressof" : ""), input);
+       break;
+
+      default:
+       fputs_unfiltered (input, buf);
+       break;
+      }
+    fputs_unfiltered ("\n", buf);
+  }
+};
+
 /* A host class representing a compile program.
 
    CompileInstanceType is the type of the compile_instance for the
@@ -531,13 +648,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::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::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
@@ -554,3 +676,21 @@ c_compute_program (compile::compile_instance *inst,
 
   return program.compute (input, expr_block, expr_pc);
 }
+
+/* The la_compute_program method for C++.  */
+
+std::string
+cplus_compute_program (compile::compile_instance *inst,
+                      const char *input,
+                      struct gdbarch *gdbarch,
+                      const struct block *expr_block,
+                      CORE_ADDR expr_pc)
+{
+  using namespace compile;
+
+  compile_cplus_instance *cplus_inst
+    = static_cast<compile_cplus_instance *> (inst);
+  cplus_compile_program program (cplus_inst, gdbarch);
+
+  return program.compute (input, expr_block, expr_pc);
+}
diff --git a/gdb/compile/compile-cplus-support.c b/gdb/compile/compile-cplus-support.c
new file mode 100644 (file)
index 0000000..063476d
--- /dev/null
@@ -0,0 +1,33 @@
+/* C language support for compilation.
+
+   Copyright (C) 2015, 2016 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "gcc-cp-interface.h"
+
+void
+gcc_cplus_enter_scope (void *datum, struct gcc_cp_context *gcc_context)
+{
+  /* FIXME: enter the scope in which the user expression is supposed
+     to be parsed.  -lxo  */
+}
+
+void
+gcc_cplus_leave_scope (void *datum, struct gcc_cp_context *gcc_context)
+{
+  /* FIXME: leave the scopes entered by gcc_cplus_enter_scope.  -lxo  */
+}
diff --git a/gdb/compile/compile-cplus-symbols.c b/gdb/compile/compile-cplus-symbols.c
new file mode 100644 (file)
index 0000000..cbd4cda
--- /dev/null
@@ -0,0 +1,705 @@
+/* Convert symbols from GDB to GCC
+
+   Copyright (C) 2014-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+#include "defs.h"
+#include "compile-internal.h"
+#include "compile-cplus.h"
+#include "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" /* !!keiths FIXME for c_get_range_decl_name  */
+
+\f
+
+using namespace compile;
+
+/* See description in compile-internal.h.  */
+
+int debug_compile_oracle = 0;
+
+/* Convert a given symbol, SYM, to the compiler's representation.
+   CONTEXT 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 if (!SYMBOL_IS_CPLUS_TEMPLATE_FUNCTION (sym.symbol))
+    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;
+      char *symbol_name = NULL;
+
+      /* Add a null cleanup for templates.  !!keiths: remove!  */
+      struct cleanup *back_to
+       = make_cleanup (free_current_contents, &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)
+           {
+             do_cleanups (back_to);
+             return;
+           }
+         break;
+
+       case LOC_LABEL:
+         kind = GCC_CP_SYMBOL_LABEL;
+         addr = SYMBOL_VALUE_ADDRESS (sym.symbol);
+         break;
+
+       case LOC_BLOCK:
+         {
+           bool ignore;
+           char *special_name;
+           const char *func_name;
+
+           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);
+
+           special_name = NULL;
+           func_name = maybe_canonicalize_special_function
+             (SYMBOL_LINKAGE_NAME (sym.symbol), NULL,
+              SYMBOL_TYPE (sym.symbol), &special_name, &ignore);
+           if (special_name != NULL)
+             {
+               kind |= GCC_CP_FLAG_SPECIAL_FUNCTION;
+               name = special_name;
+               xfree (special_name);
+             }
+           else if (func_name != SYMBOL_NATURAL_NAME (sym.symbol))
+             {
+               kind |= GCC_CP_FLAG_SPECIAL_FUNCTION;
+               name = func_name;
+             }
+           else if (ignore)
+             {
+               /* !!keiths: I don't think we can get here, can we?  */
+               gdb_assert_not_reached ("told to ignore method!");
+             }
+         }
+         break;
+
+       case LOC_CONST:
+         if (TYPE_CODE (SYMBOL_TYPE (sym.symbol)) == TYPE_CODE_ENUM)
+           {
+             /* Already handled by convert_enum.  */
+             do_cleanups (back_to);
+             return;
+           }
+         instance->build_constant (sym_type, SYMBOL_NATURAL_NAME (sym.symbol),
+                                   SYMBOL_VALUE (sym.symbol), filename, line);
+         do_cleanups (back_to);
+         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 = NULL;
+
+           if (symbol_read_needs_frame (sym.symbol))
+             {
+               frame = get_selected_frame (NULL);
+               if (frame == NULL)
+                 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 == NULL)
+       {
+         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.
+                    Don't return anything in that case because that really
+                    confuses users.  */
+                 do_cleanups (back_to);
+                 return;
+               }
+
+             instance->enter_scope (scope);
+           }
+
+         /* Get the `raw' name of the symbol.  */
+         if (name.empty () && SYMBOL_NATURAL_NAME (sym.symbol) != NULL)
+           {
+             char *str = cp_func_name (SYMBOL_NATURAL_NAME (sym.symbol));
+
+             name = str;
+             xfree (str);
+           }
+
+         /* Define the decl.  */
+         if (SYMBOL_IS_CPLUS_TEMPLATE_FUNCTION (sym.symbol))
+           {
+             struct template_symbol *tsymbol
+               = (struct template_symbol *) sym.symbol;
+
+             instance->build_function_template_specialization (tsymbol, addr,
+                                                               filename, line);
+           }
+         else
+           {
+             instance->build_decl ("variable", name.c_str (), kind, sym_type,
+                                   symbol_name, addr, filename, line);
+           }
+
+         /* Pop scope for non-local symbols.  */
+         if (!is_local)
+           instance->leave_scope ();
+       }
+
+      /* Free any allocated memory.  */
+      do_cleanups (back_to);
+    }
+}
+
+/* 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 != NULL);
+  if (is_local_symbol)
+    {
+      struct block_symbol global_sym;
+
+      global_sym = lookup_symbol (identifier, NULL, domain, NULL);
+      /* If the outer symbol is in the static block, we ignore it, as
+        it cannot be referenced.  */
+      if (global_sym.symbol != NULL
+         && global_sym.block != block_static_block (global_sym.block))
+       {
+         if (compile_debug)
+           fprintf_unfiltered (gdb_stdout,
+                               "gcc_convert_symbol \"%s\": global symbol\n",
+                               identifier);
+         convert_one_symbol (instance, global_sym, true, false);
+       }
+    }
+
+  if (compile_debug)
+    fprintf_unfiltered (gdb_stdout,
+                       "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->push_namespace ("");
+  /* FIXME: push (and, after the call, pop) any other namespaces, if
+     any, and drop the above when defining a class member.  drop any
+     namespace and class names from before the symbol name, and any
+     function signatures from after it.  -lxo  */
+  /* !!keiths: I don't see how we could do this.  We have NO debug
+     information for the symbol.  While we have access to the demangled
+     name, we still don't know what A::B::C::D::E::F means without debug
+     info, no?  */
+  instance->build_decl ("minsym", MSYMBOL_NATURAL_NAME (msym), kind, sym_type,
+                       NULL, addr, NULL, 0);
+  instance->pop_binding_level ("");
+}
+
+/* Do a regular expression search of the symbol table for any symbol
+   named NAME in the given DOMAIN.  Warning: This is INCREDIBLY slow.  */
+
+static int
+regexp_search_symbols (compile_cplus_instance *instance,
+                     const char *name, domain_enum domain)
+{
+  char *regexp;
+  enum search_domain search_domain;
+  struct symbol_search *symbols, *p;
+  struct cleanup *cleanup;
+  int found = 0;
+
+  switch (domain)
+    {
+    case STRUCT_DOMAIN:
+      search_domain = TYPES_DOMAIN;
+      break;
+    case VAR_DOMAIN:
+      /* !!keiths: We really don't want to search functions.  The search
+        will return all kinds of stuff that we don't really want, such as
+        every operator+ defined in every class.  */
+      return 0;
+      /* !!keiths; fscked up.  We need to search through functions
+        when GCC_CP_ORACLE_SYMBOL (= VAR_DOMAIN).  */
+      /* !!keiths; I hope we don't have to search even more domains!  */
+      search_domain = FUNCTIONS_DOMAIN;
+      break;
+    default:
+      /* This will cause search_symbols to assert.  */
+      search_domain = ALL_DOMAIN;
+      break;
+    }
+
+  symbols = NULL;
+  cleanup = make_cleanup_free_search_symbols (&symbols);
+
+  regexp = xstrprintf ("\\(\\(::\\)\\|^\\)%s\\($\\|<\\)", name);
+  make_cleanup (xfree, regexp);
+  search_symbols (regexp, search_domain, 0, NULL, &symbols);
+
+  for (p = symbols; p != NULL; p = p->next)
+    {
+      if (p->symbol != NULL)
+       {
+         struct block_symbol sym;
+
+         sym.symbol = p->symbol;
+         sym.block = SYMBOL_BLOCK_VALUE (p->symbol);
+         convert_symbol_sym (instance, name, sym, domain);
+         found = 1;
+       }
+      /* !!keiths: Ignore minsyms?  */
+    }
+
+  do_cleanups (cleanup);
+  return found;
+}
+
+/* See compile-cplus.h.  */
+
+void
+gcc_cplus_convert_symbol (void *datum,
+                         struct gcc_cp_context *gcc_context,
+                         enum gcc_cp_oracle_request request,
+                         const char *identifier)
+{
+  compile_cplus_instance *instance
+    = (compile_cplus_instance *) datum;
+  int found = 0;
+  struct search_multiple_result search_result;
+  struct cleanup *cleanups;
+  /* !!keiths create htab for template definitions */
+
+  switch (request)
+    {
+    case GCC_CP_ORACLE_IDENTIFIER:
+      /* FIXME: This used to be separate SYMBOL and TAG.  Check for
+        simplification opportunities below.  -lxo  */
+      break;
+    default:
+      gdb_assert_not_reached ("Unrecognized oracle request.");
+    }
+
+  /* We can't allow exceptions to escape out of this callback.  Safest
+     is to simply emit a gcc error.  */
+  if (debug_compile_oracle)
+    {
+      printf ("got oracle request for \"%s\"\n", identifier);
+    }
+
+  memset (&search_result, 0, sizeof (search_result));
+  cleanups = make_cleanup (search_multiple_result_cleanup, &search_result);
+  TRY
+    {
+      int ix;
+
+      /* !!keiths: Symbol lookup is out of control.  Here's the current
+        process, screaming for a custom symbol table search:
+
+        1. If looking up a symbol in VAR_DOMAIN (basically anything but
+        a type), use linespec.c's (new) multi-symbol search.  This will
+        allow overloads of functions (not methods) to be converted.
+
+        2. If a symbol is not found, do a "standard" lookup.  This will
+        find variables in the current scope.
+
+        3. If a symbol is still not found, try a regexp search.  This
+        allows namespace-y stuff to work (cp-simple-ns.exp). This is currently
+        only used for STRUCT_DOMAIN lookups.
+
+        4. Finally, if all else fails, fall back to minsyms.  */
+
+      if (1)
+       {
+         search_result = search_symbols_multiple (identifier,
+                                                  current_language,
+                                                  VAR_DOMAIN, NULL, NULL);
+         if (!VEC_empty (block_symbol_d, search_result.symbols))
+           {
+             struct block_symbol *elt;
+
+             /* Define any template generics from the found symbols.  */
+             define_templates (instance, search_result.symbols);
+
+             /* Convert each found symbol.  */
+             for (ix = 0;
+                  VEC_iterate (block_symbol_d, search_result.symbols, ix, elt);
+                  ++ix)
+               {
+                 convert_symbol_sym (instance, identifier, *elt, VAR_DOMAIN);
+               }
+             found = 1;
+           }
+       }
+
+      if (!found)
+       {
+         struct block_symbol sym
+           = lookup_symbol (identifier, instance->block (), VAR_DOMAIN, NULL);
+
+         if (sym.symbol != NULL)
+           {
+             convert_symbol_sym (instance, identifier, sym, VAR_DOMAIN);
+             found = 1;
+           }
+       }
+
+      if (1)
+       {
+         struct block_symbol sym
+           = lookup_symbol (identifier, instance->block (), STRUCT_DOMAIN,
+                            NULL);
+
+         if (sym.symbol != NULL)
+           {
+             convert_symbol_sym (instance, identifier, sym, STRUCT_DOMAIN);
+             found = 1;
+           }
+       }
+
+      if (!found)
+       {
+         /* Try a regexp search of the program's symbols.  */
+         found = regexp_search_symbols (instance, identifier, VAR_DOMAIN)
+           + regexp_search_symbols (instance, identifier, STRUCT_DOMAIN);
+
+         /* One last attempt: fall back to minsyms.  */
+         if (!found && !VEC_empty (bound_minimal_symbol_d,
+                                   search_result.minimal_symbols))
+           {
+             struct bound_minimal_symbol *elt;
+
+             for (ix = 0;
+                  VEC_iterate (bound_minimal_symbol_d,
+                               search_result.minimal_symbols, ix, elt);
+                  ++ix)
+               {
+                 convert_symbol_bmsym (instance, *elt);
+               }
+             found = 1;
+           }
+       }
+    }
+  CATCH (e, RETURN_MASK_ALL)
+    {
+      instance->error (e.message);
+    }
+  END_CATCH
+
+  if (compile_debug && !found)
+    fprintf_unfiltered (gdb_stdout,
+                       "gcc_convert_symbol \"%s\": lookup_symbol failed\n",
+                       identifier);
+
+  if (debug_compile_oracle)
+    {
+      if (found)
+       printf_unfiltered ("found type for %s!\n", identifier);
+      else
+       printf_unfiltered ("did not find type for %s\n", identifier);
+    }
+
+  do_cleanups (cleanups);
+  return;
+}
+
+/* See compile-cplus.h.  */
+
+gcc_address
+gcc_cplus_symbol_address (void *datum, struct gcc_cp_context *gcc_context,
+                         const char *identifier)
+{
+  compile_cplus_instance *instance
+    = (compile_cplus_instance *) datum;
+  gcc_address result = 0;
+  int found = 0;
+
+  if (debug_compile_oracle)
+    printf_unfiltered ("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;
+
+      /* FIXME: We used to only need global functions here, but we may
+        now be asked for other symbols.  IDENTIFIER is a mangled
+        name.  -lxo */
+      sym = lookup_symbol (identifier, NULL, VAR_DOMAIN, NULL).symbol;
+      if (sym != NULL && SYMBOL_CLASS (sym) == LOC_BLOCK)
+       {
+         if (compile_debug)
+           fprintf_unfiltered (gdb_stdout,
+                               "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 != NULL)
+           {
+             if (compile_debug)
+               fprintf_unfiltered (gdb_stdout,
+                                   "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->error (e.message);
+    }
+  END_CATCH
+
+  if (compile_debug && !found)
+    fprintf_unfiltered (gdb_stdout,
+                       "gcc_symbol_address \"%s\": failed\n",
+                       identifier);
+
+  if (debug_compile_oracle)
+    {
+      if (found)
+       printf_unfiltered ("found address for %s!\n", identifier);
+      else
+       printf_unfiltered ("did not find address for %s\n", identifier);
+    }
+
+  return result;
+}
+
+\f
+
+void _initialize_compile_cplus_symbols (void);
+
+void
+_initialize_compile_cplus_symbols (void)
+{
+  add_setshow_boolean_cmd ("compile-oracle", no_class,
+                          &debug_compile_oracle, _("\
+Set debugging of compiler plug-in oracle requests."), _("\
+Show debugging of compiler plug-in oracle requests."), _("\
+When enabled debugging messages are printed for compiler plug-in\n\
+oracle requests."),
+                          NULL,
+                          NULL,
+                          &setdebuglist,
+                          &showdebuglist);
+}
diff --git a/gdb/compile/compile-cplus-templates.c b/gdb/compile/compile-cplus-templates.c
new file mode 100644 (file)
index 0000000..4b2bf46
--- /dev/null
@@ -0,0 +1,1448 @@
+/* Template support for compile.
+
+   Copyright (C) 2016, 2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "compile-internal.h"
+#include "compile-cplus.h"
+#include "cp-support.h"
+#include "demangle.h"
+#include "typeprint.h"
+#include "c-lang.h"
+#include "gdbcmd.h"
+
+#include <algorithm>
+
+using namespace compile;
+
+/* Modifiers for abstract template parameters when used in template function
+   declarations, including CV and ref qualifiers and pointer and reference
+   type modifiers, e.g., const T*.  */
+
+enum template_parameter_type_modifier
+{
+  /*/ The abstract parameter type is not qualified at all.  */
+  PARAMETER_NONE,
+
+  /* The abstract parameter type was declared `const', const T.  */
+  PARAMETER_CONST,
+
+  /* The abstract parameter type was declared `volatile', volatile T.  */
+  PARAMETER_VOLATILE,
+
+  /* The abstract parameter type was declared `restrict', restrict T.  */
+  PARAMETER_RESTRICT,
+
+  /* The abstract parameter type was declared as a pointer, T*.  */
+  PARAMETER_POINTER,
+
+  /* The abstract parameter type was declared as a reference, T&.  */
+  PARAMETER_LVALUE_REFERENCE,
+
+  /* The abstract parameter type was declared as rvalue reference,
+     T&&.  */
+  PARAMETER_RVALUE_REFERENCE
+};
+typedef enum template_parameter_type_modifier template_parameter_modifier;
+
+/* Forward declarations.  */
+
+static void print_template_parameter_list
+  (const struct template_argument_info *arg_info, struct ui_file *stream);
+
+static void print_template_type (const struct demangle_component *comp,
+                                const struct template_symbol *tsymbol,
+                                struct ui_file *stream);
+
+static void print_conversion_node (const struct demangle_component *comp,
+                                  const struct template_symbol *tsymbol,
+                                  struct ui_file *stream);
+
+static void print_function_template_arglist
+  (const struct demangle_component *comp,
+   const struct template_symbol *tsymbol, struct ui_file *stream);
+
+/* See description in compile-cplus-templates.h.  */
+
+function_template_defn::function_template_defn
+  (std::string generic, std::unique_ptr<demangle_parse_info> info,
+   const struct template_symbol *tsymbol, struct type *parent_type,
+   int fidx, int midx)
+  : template_defn (compile::decl_name (tsymbol->search_name), generic,
+                  tsymbol->template_arguments->n_arguments),
+    m_tsymbol (tsymbol), m_parent_type (parent_type),
+    m_fidx (fidx), m_midx (midx),
+    m_demangle_info (std::move (info))
+{
+}
+
+/* Return a string representing the template declaration for TSYMBOL.
+   All template symbols deriving from the same source declaration should
+   yield the same string representation.
+
+   This string representation is of the generic form
+   RETURN_TYPE QUALIFIED_NAME <parameter list>(argument list), with
+   generic template parameters instead of any instanced type.
+
+   For example, both "void foo<int> (int)" and "void foo<A> (A)" will
+   return "T foo<typename T>(T)".  */
+
+static std::string
+function_template_decl (const struct template_symbol *tsymbol,
+                       const struct demangle_parse_info *info)
+{
+  gdb_assert (info != NULL);
+
+  string_file stream;
+  struct demangle_component *ret_comp = info->tree;
+
+  if (ret_comp != NULL)
+    {
+      if (ret_comp->type == DEMANGLE_COMPONENT_TYPED_NAME)
+       ret_comp = d_right (ret_comp);
+
+      /* Print out the return type to the stream (if there is one).  */
+      if (d_left (ret_comp) != NULL)
+       {
+         if (tsymbol->template_return_index == -1)
+           {
+             struct type *return_type
+               = TYPE_TARGET_TYPE (SYMBOL_TYPE (&tsymbol->base));
+
+             c_print_type (return_type, "", &stream, -1, 0,
+                           &type_print_raw_options);
+           }
+         else
+           print_template_type (d_left (ret_comp), tsymbol, &stream);
+         stream.putc (' ');
+       }
+
+      /* Print the name of the template.  */
+      if (tsymbol->conversion_operator_index != -1)
+       print_conversion_node (info->tree, tsymbol, &stream);
+      else
+       {
+         stream.puts (tsymbol->search_name);
+         if (tsymbol->search_name[strlen (tsymbol->search_name) - 1] == '<')
+           stream.putc (' ');
+       }
+
+      /* Print out template (generic) arguments.  */
+      stream.putc ('<');
+      print_template_parameter_list (tsymbol->template_arguments, &stream);
+      stream.putc ('>');
+
+      /* Print out function arguments.  */
+      stream.putc ('(');
+      print_function_template_arglist (ret_comp, tsymbol, &stream);
+      stream.putc (')');
+    }
+
+  return std::move (stream.string ());
+}
+
+/* Compute the generic used by the given function template
+   definition.  */
+
+static std::string
+compute_function_template_generic (struct template_symbol *tsymbol,
+                                  const demangle_parse_info *info)
+{
+  gdb_assert (info->tree != NULL);
+
+  /* Ensure template arguments have been decoded.  */
+  cp_decode_template_type_indices (tsymbol, info);
+
+  /* Output the template generic.  */
+  return function_template_decl (tsymbol, info);
+}
+
+/* See description in compile-cplus.h.  */
+
+void
+compile_cplus_instance::maybe_define_new_function_template
+  (const struct symbol *sym, struct type *parent_type, int f_idx,
+   int m_idx)
+
+{
+  if (sym != NULL && SYMBOL_IS_CPLUS_TEMPLATE_FUNCTION (sym))
+    {
+      struct template_symbol *tsym = (struct template_symbol *) sym;
+
+      if (tsym->linkage_name == NULL)
+       return;
+
+      std::unique_ptr<demangle_parse_info> info
+       = cp_mangled_name_to_comp (tsym->linkage_name, DMGL_ANSI | DMGL_PARAMS);
+
+      std::string generic
+       = compute_function_template_generic (tsym, info.get ());
+      function_template_defn_map_t::iterator pos
+       = m_function_template_defns->find (generic);
+
+      function_template_defn *defn;
+
+      if (pos == m_function_template_defns->end ())
+       {
+         /* Create the new template definition and insert it into
+            the cache.  */
+         defn = new function_template_defn (generic, std::move (info), tsym,
+                                            parent_type, f_idx, m_idx);
+         m_function_template_defns->insert (std::make_pair (generic, defn));
+       }
+      else
+       {
+         /* Or use the existing definition.  */
+         defn = pos->second.get ();
+       }
+
+      /* Loop over the template arguments, noting any default values.  */
+      for (unsigned int i = 0; i < tsym->template_arguments->n_arguments; ++i)
+       {
+         if (defn->default_argument (i) == NULL
+             && tsym->template_arguments->default_arguments[i] != NULL)
+           {
+             struct symbol *def
+               = tsym->template_arguments->default_arguments[i];
+             defn->set_default_argument (i, def);
+
+             /* We don't want to define them here because it could start
+                emitting template definitions before we're even done
+                collecting the default values.  [Easy to demonstrate if the
+                default value is a class.]  */
+           }
+       }
+    }
+}
+
+/* See description in compile-cplus-templates.h.  */
+
+void
+compile::define_templates (compile_cplus_instance *instance,
+                          VEC (block_symbol_d) *symbols)
+{
+  int i;
+  struct block_symbol *elt;
+
+  /* We need to do this in two passes.  On the first pass, we collect
+     the list of "unique" template definitions we need (using the template
+     hashing function) and we collect the list of default values for the
+     template (which can only be done after we have a list of all templates).
+     On the second pass, we iterate over the list of templates we need to
+     define, enumerating those definitions (with default values) to the
+     compiler plug-in.  */
+
+  for (i = 0; VEC_iterate (block_symbol_d, symbols, i, elt); ++i)
+    instance->maybe_define_new_function_template (elt->symbol, NULL, -1, -1);
+
+  /* From here on out, we MUST have all types declared or defined,
+     otherwise GCC will give us "definition of TYPE in template parameter
+     list."  */
+  /* Create any new template definitions we encountered.  */
+  instance->emit_function_template_decls ();
+  instance->emit_class_template_decls ();
+}
+
+/* See description in compile-cplus-templates.h.  */
+
+function_template_defn *
+compile_cplus_instance::find_function_template_defn
+  (struct template_symbol *tsym)
+{
+  if (tsym->linkage_name == NULL)
+    return NULL;
+
+  std::unique_ptr<demangle_parse_info> info
+    = cp_mangled_name_to_comp (tsym->linkage_name, DMGL_ANSI | DMGL_PARAMS);
+
+  std::string generic = compute_function_template_generic (tsym, info.get ());
+  function_template_defn_map_t::iterator pos
+    = m_function_template_defns->find (generic);
+
+  if (pos != m_function_template_defns->end ())
+    return pos->second.get ();
+
+  return NULL;
+}
+
+/* Compute the generic used by the given function template
+   definition.  */
+
+static std::string
+compute_class_template_generic (std::string name, struct type *type)
+{
+  string_file stream;
+
+  /* Format: class|struct|union namespaces::NAME<parameters>  */
+  if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
+    {
+      if (TYPE_DECLARED_CLASS (type))
+       stream.puts ("class ");
+      else
+       stream.puts ("struct ");
+    }
+  else
+    {
+      gdb_assert (TYPE_CODE (type) == TYPE_CODE_UNION);
+      stream.puts ("union ");
+    }
+
+  /* Print all namespaces.  Note that we do not push the last
+     scope_component -- that's the actual type we are defining.  */
+
+  compile::compile_scope scope = type_name_to_scope (TYPE_NAME (type), NULL);
+  std::for_each (scope.begin (), scope.end () - 1, [&] (const auto &comp)
+     {
+       gdb_assert (TYPE_CODE (SYMBOL_TYPE (comp.bsymbol.symbol))
+                  == TYPE_CODE_NAMESPACE);
+
+       if (comp.name != CP_ANONYMOUS_NAMESPACE_STR)
+        stream.printf ("%s::", comp.name.c_str ());
+     });
+
+  stream.printf ("%s<", name.c_str ());
+  print_template_parameter_list (TYPE_TEMPLATE_ARGUMENT_INFO (type), &stream);
+  stream.putc ('>');
+
+  return std::move (stream.string ());
+}
+
+/* See description in compile-cplus-templates.h.  */
+
+class_template_defn *
+compile_cplus_instance::find_class_template_defn (struct type *type)
+{
+  /* There are no template definitions associated with anonymous types or
+     types without template arguments.  */
+  if (TYPE_NAME (type) == NULL || TYPE_TEMPLATE_ARGUMENT_INFO (type) == NULL)
+    return NULL;
+
+  char *name = decl_name (TYPE_NAME (type));
+  struct cleanup *back_to = make_cleanup (xfree, name);
+
+  std::string generic (compute_class_template_generic (name, type));
+  class_template_defn_map_t::iterator pos
+    = m_class_template_defns->find (generic);
+  if (pos != m_class_template_defns->end ())
+    {
+      /* A template generic for this was already defined.  */
+      do_cleanups (back_to);
+      return pos->second.get ();
+    }
+
+  /* No generic for this template was found.  */
+  do_cleanups (back_to);
+  return NULL;
+}
+
+/* A class providing printing for a single parameter type modifier.  */
+
+class one_template_type_modifier_printer
+{
+public:
+  /* Construct a new printer which outputs to STREAM.  */
+  explicit one_template_type_modifier_printer (struct ui_file *stream)
+    : m_stream (stream)
+  {
+  }
+
+  /* Unary function to output the modifier.  */
+  void operator() (template_parameter_modifier modifier)
+  {
+    switch (modifier)
+      {
+      case PARAMETER_NONE:
+       break;
+
+      case PARAMETER_CONST:
+       fputs_unfiltered (" const", m_stream);
+       break;
+
+      case PARAMETER_VOLATILE:
+       fputs_unfiltered (" volatile", m_stream);
+       break;
+
+      case PARAMETER_RESTRICT:
+       fputs_unfiltered (" restrict", m_stream);
+       break;
+
+      case PARAMETER_POINTER:
+       fputs_unfiltered ("*", m_stream);
+       break;
+
+      case PARAMETER_LVALUE_REFERENCE:
+       fputc_unfiltered ('&', m_stream);
+       break;
+
+      case PARAMETER_RVALUE_REFERENCE:
+       fputs_unfiltered ("&&", m_stream);
+
+      default:
+       gdb_assert_not_reached ("unknown template parameter modifier");
+      }
+  }
+
+private:
+  /* The stream to which to print the modifier.  */
+  struct ui_file *m_stream;
+};
+
+/* Print the type modifiers MODIFIERS to STREAM.  */
+
+static void
+print_template_type_modifiers
+  (const std::vector<template_parameter_modifier> &modifiers,
+   struct ui_file *stream)
+{
+  one_template_type_modifier_printer printer (stream);
+
+  for (auto &item : modifiers)
+    printer (item);
+}
+
+/* Get the abstract template type described by COMP, returning any
+   type modifiers in MODIFIERS.  */
+
+static const struct demangle_component *
+get_template_type (const struct demangle_component *comp,
+                  std::vector <template_parameter_modifier> &modifiers)
+{
+  bool done = 0;
+
+  /* This is probably a little too simplistic...  */
+  while (!done)
+    {
+      switch (comp->type)
+       {
+       case DEMANGLE_COMPONENT_POINTER:
+         modifiers.insert (modifiers.begin (), PARAMETER_POINTER);
+         comp = d_left (comp);
+         break;
+
+       case DEMANGLE_COMPONENT_REFERENCE:
+         modifiers.insert (modifiers.begin (), PARAMETER_LVALUE_REFERENCE);
+         comp = d_left (comp);
+         break;
+
+       case DEMANGLE_COMPONENT_CONST:
+         modifiers.insert (modifiers.begin (), PARAMETER_CONST);
+         comp = d_left (comp);
+         break;
+
+       case DEMANGLE_COMPONENT_RESTRICT:
+         modifiers.insert (modifiers.begin (), PARAMETER_RESTRICT);
+         comp = d_left (comp);
+         break;
+
+       case DEMANGLE_COMPONENT_VOLATILE:
+         modifiers.insert (modifiers.begin (), PARAMETER_VOLATILE);
+         comp = d_left (comp);
+         break;
+
+       case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
+       default:
+         done = true;
+         break;
+       }
+    }
+
+  return comp;
+}
+
+/* Print the generic parameter type given by COMP from the template symbol
+   TSYMBOL to STREAM.  This function prints the generic template parameter
+   type, not the instanced type, e.g., "const T&".  */
+
+static void
+print_template_type (const struct demangle_component *comp,
+                    const struct template_symbol *tsymbol,
+                    struct ui_file *stream)
+{
+  /* Get the template parameter and modifiers.  */
+  std::vector<template_parameter_modifier> modifiers;
+  comp = get_template_type (comp, modifiers);
+
+  /* This had better be a template parameter!  */
+  gdb_assert (comp->type == DEMANGLE_COMPONENT_TEMPLATE_PARAM);
+
+  /* Using the parameter's index, get the parameter's symbol and print it
+     with modifiers.  */
+  long idx = comp->u.s_number.number;
+  struct symbol *sym = tsymbol->template_arguments->arguments[idx];
+
+  fputs_unfiltered (SYMBOL_NATURAL_NAME (sym), stream);
+  print_template_type_modifiers (modifiers, stream);
+}
+
+/* Print the template parameter list of a type/symbol to STREAM.  */
+
+static void
+print_template_parameter_list (const struct template_argument_info *arg_info,
+                              struct ui_file *stream)
+{
+  for (int i = 0; i < arg_info->n_arguments; ++i)
+    {
+      if (i != 0)
+       fputs_unfiltered (", ", stream);
+
+      switch (arg_info->argument_kinds[i])
+       {
+       case type_parameter:
+         fprintf_unfiltered (stream, "typename %s",
+                             SYMBOL_NATURAL_NAME (arg_info->arguments[i]));
+         break;
+
+       case value_parameter:
+         c_print_type (SYMBOL_TYPE (arg_info->arguments[i]), "", stream, -1, 0,
+                       &type_print_raw_options);
+         fprintf_unfiltered (stream, " %s",
+                             SYMBOL_NATURAL_NAME (arg_info->arguments[i]));
+         break;
+
+       case template_parameter:
+         break;
+
+       case variadic_parameter:
+         break;
+
+       default:
+         gdb_assert_not_reached ("unexpected template parameter kind");
+       }
+    }
+}
+
+/* Print out the generic template function argument list of the template
+   symbol TSYMBOL to STREAM.  COMP represents the FUNCTION_TYPE of the
+   demangle tree for TSYMBOL.  */
+
+static void
+print_function_template_arglist (const struct demangle_component *comp,
+                                const struct template_symbol *tsymbol,
+                                struct ui_file *stream)
+{
+  int i, artificials;
+  struct type *ttype = SYMBOL_TYPE (&tsymbol->base);
+
+  for (i = 0, artificials = 0; i < TYPE_NFIELDS (ttype); ++i)
+    {
+      int tidx;
+
+      if (TYPE_FIELD_ARTIFICIAL (ttype, i))
+       {
+         ++artificials;
+         continue;
+       }
+
+      if ((i - artificials) > 0)
+       fputs_unfiltered (", ", stream);
+
+      tidx = tsymbol->template_argument_indices[i - artificials];
+      if (tidx == -1)
+       {
+         /* A concrete type was used to define this argument.  */
+         c_print_type (TYPE_FIELD_TYPE (ttype, i), "", stream, -1, 0,
+                       &type_print_raw_options);
+         continue;
+       }
+
+      /* The type of this argument was specified by a template parameter,
+        possibly with added CV and ref qualifiers.  */
+
+      /* Get the next ARGLIST node and print it.  */
+      comp = d_right (comp);
+      gdb_assert (comp != NULL);
+      gdb_assert (comp->type == DEMANGLE_COMPONENT_ARGLIST);
+      print_template_type (d_left (comp), tsymbol, stream);
+    }
+}
+
+/* Print the conversion operator in COMP for the template symbol TSYMBOL
+   to STREAM.  */
+
+static void
+print_conversion_node (const struct demangle_component *comp,
+                      const struct template_symbol *tsymbol,
+                      struct ui_file *stream)
+{
+  while (1)
+    {
+      switch (comp->type)
+       {
+       case DEMANGLE_COMPONENT_TYPED_NAME:
+       case DEMANGLE_COMPONENT_TEMPLATE:
+         comp = d_left (comp);
+         break;
+
+       case DEMANGLE_COMPONENT_QUAL_NAME:
+         {
+           /* Print out the qualified name.  */
+           struct cleanup *back_to;
+           char *ret = cp_comp_to_string (d_left (comp), 10);
+
+           back_to = make_cleanup (xfree, ret);
+           fprintf_unfiltered (stream, "%s::", ret);
+           do_cleanups (back_to);
+
+           /* Follow the rest of the name.  */
+           comp = d_right (comp);
+         }
+         break;
+
+       case DEMANGLE_COMPONENT_CONVERSION:
+         fputs_unfiltered ("operator ", stream);
+         print_template_type (d_left (comp), tsymbol, stream);
+         return;
+
+       default:
+         return;
+       }
+    }
+}
+
+/* See description in compile-cplus-templates.h.  */
+
+void
+compile_cplus_instance::maybe_define_new_class_template
+  (struct type *type, const char *decl_name)
+{
+  if (TYPE_N_TEMPLATE_ARGUMENTS (type) == 0 || decl_name == NULL)
+    return;
+
+  std::string generic (compute_class_template_generic (decl_name, type));
+  class_template_defn_map_t::iterator pos
+    = m_class_template_defns->find (generic);
+
+  class_template_defn *defn = NULL;
+
+  if (pos == m_class_template_defns->end ())
+    {
+      /* Insert the new template definition into the cache.  */
+      defn = new class_template_defn (decl_name, generic, type);
+      m_class_template_defns->insert (std::make_pair (generic, defn));
+    }
+  else
+    {
+      /* If there is an existing definition, use that definition.  */
+      defn = pos->second.get ();
+    }
+
+  /* Loop over the template arguments, noting any default values.  */
+  for (unsigned int i = 0; i < TYPE_N_TEMPLATE_ARGUMENTS (type); ++i)
+    {
+      if (defn->default_argument (i) == NULL
+         && TYPE_TEMPLATE_DEFAULT_ARGUMENT (type, i) != NULL)
+       {
+         defn->set_default_argument (i,
+                                     TYPE_TEMPLATE_DEFAULT_ARGUMENT (type, i));
+
+         /* We don't want to define them here because it could start
+            emitting template definitions before we're even done
+            collecting the default values.  [Easy to demonstrate if the
+            default value is a class.]  */
+       }
+    }
+}
+
+/* See description in compile-cplus-templates.h.  */
+
+void
+compile::scan_type_for_function_templates (compile_cplus_instance *instance,
+                                          struct type *type)
+{
+  for (int i = 0; i < TYPE_NFN_FIELDS (type); ++i)
+    {
+      struct fn_field *methods = TYPE_FN_FIELDLIST1 (type, i);
+
+      for (int j = 0; j < TYPE_FN_FIELDLIST_LENGTH (type, i); ++j)
+       {
+         struct block_symbol sym
+           = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (methods, j),
+                            instance->block (), VAR_DOMAIN, NULL);
+
+         instance->maybe_define_new_function_template (sym.symbol, type, i, j);
+       }
+    }
+}
+
+/* Helper function to define and return the `value' of TYPE of the template
+   parameter ARG in compile INSTANCE.  */
+
+static gcc_expr
+get_template_argument_value (compile_cplus_instance *instance,
+                            gcc_type type, struct symbol *arg)
+{
+  gcc_expr value = 0;
+
+  switch (SYMBOL_CLASS (arg))
+    {
+      /* !!keiths: More (incomplete) fun.  */
+    case LOC_CONST:
+      value = instance->build_literal_expr (type, SYMBOL_VALUE (arg));
+      break;
+
+    case LOC_COMPUTED:
+      {
+       struct value *val;
+       struct frame_info *frame = NULL;
+
+       /* !!keiths: I don't think this can happen, but I've been
+          wrong before.  */
+       if (symbol_read_needs_frame (arg))
+         {
+           frame = get_selected_frame (NULL);
+           gdb_assert (frame != NULL);
+         }
+       val = read_var_value (arg, instance->block (), frame);
+
+       /* !!keiths: This is a hack, but I don't want to write
+          yet another linkage name translation function.  At least
+          not just yet.  */
+       value = instance->build_literal_expr (type, value_address (val));
+      }
+      break;
+
+    default:
+      gdb_assert_not_reached
+       ("unhandled template value argument symbol class");
+    }
+
+  return value;
+}
+
+/* Enumerate the template parameters of the generic form of the template
+   definition DEFN into DEST.  */
+
+static void
+define_template_parameters_generic
+  (compile_cplus_instance *instance, template_defn *defn,
+   const struct template_argument_info *arg_info,
+   const char *filename, int line)
+{
+  for (int i = 0; i < arg_info->n_arguments; ++i)
+    {
+      const char *id = SYMBOL_NATURAL_NAME (arg_info->arguments[i]);
+
+      switch (arg_info->argument_kinds[i])
+       {
+       case type_parameter:
+         {
+           /* GDB doesn't support variadic templates yet.  */
+           int is_pack = 0;
+           gcc_type default_type = 0;
+
+           if (defn->default_argument (i) != NULL)
+             {
+               struct type *type = SYMBOL_TYPE (defn->default_argument (i));
+
+               /* This type must previously have been converted,
+                  or GCC will error with "definition of TYPE inside
+                  template parameter list."  */
+               default_type = instance->convert_type (type);
+             }
+
+           gcc_type abstract_type
+             = instance->build_type_template_parameter (id, is_pack,
+                       default_type, filename, line);
+           defn->set_parameter_abstract_type (i, abstract_type);
+         }
+         break;
+
+       case value_parameter:
+         {
+           gcc_expr default_value = 0;
+           struct type *ptype = SYMBOL_TYPE (arg_info->arguments[i]);
+
+           /* Get the argument's type.  This type must also have been
+            previously defined (or declared) to prevent errors.  */
+           gcc_type abstract_type = instance->convert_type (ptype);
+           defn->set_parameter_abstract_type (i, abstract_type);
+
+           if (defn->default_argument (i) != NULL)
+             {
+               default_value
+                 = get_template_argument_value (instance, abstract_type,
+                                                defn->default_argument (i));
+             }
+
+           instance->build_value_template_parameter (abstract_type, id,
+                                                     default_value,
+                                                     filename, line);
+         }
+         break;
+
+       case template_parameter:
+         /* GDB doesn't support template-template parameters.  */
+         break;
+
+       case variadic_parameter:
+         /* GDB doesn't support variadic templates.  */
+         break;
+
+       default:
+         gdb_assert_not_reached ("unexpected template parameter kind");
+       }
+    }
+}
+
+/* Populate the `kinds' member of DEST from ARG_INFO.  */
+
+static void
+enumerate_template_parameter_kinds
+  (compile_cplus_instance *instance, struct gcc_cp_template_args *dest,
+   const struct template_argument_info *arg_info)
+{
+  for (int i = 0; i < arg_info->n_arguments; ++i)
+    {
+      switch (arg_info->argument_kinds[i])
+       {
+       case type_parameter:
+         dest->kinds[i] = GCC_CP_TPARG_CLASS;
+         break;
+       case value_parameter:
+         dest->kinds[i] = GCC_CP_TPARG_VALUE;
+         break;
+       case template_parameter:
+         dest->kinds[i] = GCC_CP_TPARG_TEMPL;
+         break;
+       case variadic_parameter:
+         dest->kinds[i] = GCC_CP_TPARG_PACK;
+         break;
+       default:
+         gdb_assert_not_reached ("unexpected template parameter kind");
+       }
+    }
+}
+
+/* See description in compile-cplus-templates.h.  */
+
+void
+compile_cplus_instance::enumerate_template_arguments
+  (struct gcc_cp_template_args *dest, const template_defn *defn,
+   const struct template_argument_info *arg_info)
+{
+  /* Fill in the parameter kinds.  */
+  enumerate_template_parameter_kinds (this, dest, arg_info);
+
+  /* Loop over the arguments, converting parameter types, values, etc
+     into DEST.  */
+  for (int i = 0; i < arg_info->n_arguments; ++i)
+    {
+      switch (arg_info->argument_kinds[i])
+       {
+       case type_parameter:
+         {
+           gcc_type type
+             = convert_type (SYMBOL_TYPE (arg_info->arguments[i]));
+
+           dest->elements[i].type = type;
+         }
+         break;
+
+       case value_parameter:
+         {
+           gcc_type type = defn->parameter_abstract_type (i);
+
+           dest->elements[i].value
+             = get_template_argument_value (this, type,
+                                            arg_info->arguments[i]);
+         }
+         break;
+
+       case template_parameter:
+         break;
+
+       case variadic_parameter:
+         break;
+
+       default:
+         gdb_assert_not_reached ("unexpected template parameter kind");
+       }
+    }
+}
+
+/* Define the type for all default template parameters for the template
+   arguments given by ARGUMENTS.  */
+
+static void
+define_default_template_parameter_types
+  (compile_cplus_instance *instance, template_defn *defn,
+   const struct template_argument_info *arg_info)
+{
+  for (int i = 0; i < arg_info->n_arguments; ++i)
+    {
+      if (defn->default_argument (i) != NULL)
+       {
+         switch (arg_info->argument_kinds[i])
+           {
+           case type_parameter:
+           case value_parameter:
+             instance->convert_type (SYMBOL_TYPE (defn->default_argument (i)));
+             break;
+
+           case template_parameter:
+           case variadic_parameter:
+           default:
+             gdb_assert (_("unexpected template parameter kind"));
+           }
+       }
+    }
+}
+
+/* A class to add type modifiers to a given compiler type.  */
+
+class template_parameter_type_modifier_adder
+{
+public:
+  template_parameter_type_modifier_adder
+    (compile_cplus_instance *instance, gcc_type the_type)
+      : m_instance (instance), m_flags (0), m_type (the_type)
+  {
+  }
+
+  void operator() (template_parameter_modifier modifier)
+  {
+    switch (modifier)
+      {
+      case PARAMETER_NONE:
+       break;
+
+      case PARAMETER_CONST:
+       m_flags |= GCC_CP_QUALIFIER_CONST;
+       break;
+
+      case PARAMETER_VOLATILE:
+       m_flags |= GCC_CP_QUALIFIER_VOLATILE;
+       break;
+
+      case PARAMETER_RESTRICT:
+       m_flags |= GCC_CP_QUALIFIER_RESTRICT;
+       break;
+
+      case PARAMETER_POINTER:
+       m_type = convert_qualified_base (m_instance, m_type, m_flags);
+       m_type = convert_pointer_base (m_instance, m_type);
+       m_flags = (enum gcc_cp_qualifiers) 0;
+       break;
+
+      case PARAMETER_LVALUE_REFERENCE:
+       m_type = convert_qualified_base (m_instance, m_type, m_flags);
+       m_type = convert_pointer_base (m_instance, m_type);
+       m_flags = (enum gcc_cp_qualifiers) 0;
+       break;
+
+      case PARAMETER_RVALUE_REFERENCE:
+       m_type = convert_qualified_base (m_instance, m_type, m_flags);
+       m_type = convert_reference_base (m_instance, m_type);
+       m_flags = (enum gcc_cp_qualifiers) 0;
+       break;
+
+      default:
+       gdb_assert_not_reached ("unknown template parameter modifier");
+      }
+  }
+
+  /* Returns the modified type.  */
+
+  gcc_type type () const
+  {
+    return m_type;
+  }
+
+private:
+  /* The compiler instance into which to define the new type(s).  */
+  compile_cplus_instance *m_instance;
+
+  /* The qualifier flags.  */
+  gcc_cp_qualifiers_flags m_flags;
+
+  /* The type we are modifying.  */
+  gcc_type m_type;
+};
+
+/* Add the modifiers given by MODIFIERS to TYPE.  */
+
+static gcc_type
+add_template_type_modifiers
+  (compile_cplus_instance *instance, gcc_type type,
+   const std::vector<template_parameter_modifier> &modifiers)
+{
+  template_parameter_type_modifier_adder adder (instance, type);
+
+  for (auto &item : modifiers)
+    adder (item);
+  return adder.type ();
+}
+
+/* Add the type modifiers described in COMP to BASE_TYPE.  */
+
+static gcc_type
+add_type_modifiers (compile_cplus_instance *instance,
+                   gcc_type base_type,
+                   const struct demangle_component *comp)
+{
+  std::vector<template_parameter_modifier> modifiers;
+
+  get_template_type (comp, modifiers);
+
+  gcc_type result
+    = add_template_type_modifiers (instance, base_type, modifiers);
+
+  return result;
+}
+
+/* A struct to define (to the plug-in) and fill-in the
+   function template definition based on the template instance in SLOT.
+   CALL_DATA should be the compiler instance to use.  */
+
+class function_template_definer
+{
+ public:
+
+  function_template_definer (compile_cplus_instance *instance)
+    : m_instance (instance)
+  {
+  }
+
+  void operator() (function_template_defn *defn)
+  {
+    if (defn->defined ())
+      {
+       /* This template has already been defined.  Keep looking for more
+          undefined templates.  */
+       return;
+      }
+
+    /* Ensure this is one-time operation.  */
+    defn->set_defined (true);
+
+    struct fn_field *method_field;
+    struct type *method_type;
+    const struct template_symbol *tsym = defn->template_symbol ();
+    if (defn->parent_type () != NULL
+       && defn->fidx () != -1 && defn->midx () != -1)
+      {
+       struct fn_field *methods
+         = TYPE_FN_FIELDLIST1 (defn->parent_type (), defn->fidx ());
+
+       method_field = &methods[defn->midx ()];
+       method_type = method_field->type;
+      }
+    else
+      {
+       method_field = NULL;
+       method_type = SYMBOL_TYPE (&tsym->base);
+      }
+
+    bool ignore;
+    char *special_name = NULL;
+    const char *id = defn->decl_name ();
+    gdb_assert (!strchr (id, ':'));
+    const char *name = maybe_canonicalize_special_function (id,
+                                                           method_field,
+                                                           method_type,
+                                                           &special_name,
+                                                           &ignore);
+
+    /* Ignore any "ignore" -- we need the template defined even if
+       this specific instance shouldn't emit a template.  */
+    struct cleanup *back_to = make_cleanup (null_cleanup, NULL);
+
+    if (special_name != NULL)
+      {
+       make_cleanup (xfree, special_name);
+       name = special_name;
+      }
+
+    gcc_cp_symbol_kind_flags sym_kind = GCC_CP_SYMBOL_FUNCTION;
+
+    if (name != id)
+      sym_kind |= GCC_CP_FLAG_SPECIAL_FUNCTION;
+
+    /* Define any default value types.  */
+    define_default_template_parameter_types (m_instance, defn,
+                                            tsym->template_arguments);
+
+    /* Assess the processing context.  */
+    gcc_type result;
+    compile_scope scope
+      = m_instance->new_scope (SYMBOL_NATURAL_NAME (&tsym->base),
+                              SYMBOL_TYPE (&tsym->base));
+
+    if (scope.nested_type () != GCC_TYPE_NONE)
+      {
+       do_cleanups (back_to);
+       /* new_scope returned the type of the actual template instance from
+          which we're constructing the template definition.  It is already
+          defined.  */
+       return;
+      }
+
+    /* Start the new template declaration.  */
+    m_instance->enter_scope (scope);
+    m_instance->start_template_decl (defn->generic ().c_str ());
+
+    /* Get the parameters' generic kinds and types.  */
+    define_template_parameters_generic (m_instance, defn,
+                                       tsym->template_arguments,
+                                       symbol_symtab (&tsym->base)->filename,
+                                       SYMBOL_LINE (&tsym->base));
+
+    /* Find the function node describing this template function.  */
+    gdb_assert (defn->demangle_info ()->tree->type
+               == DEMANGLE_COMPONENT_TYPED_NAME);
+    struct demangle_component *comp = d_right (defn->demangle_info ()->tree);
+
+    gdb_assert (comp->type == DEMANGLE_COMPONENT_FUNCTION_TYPE);
+
+    /* The return type is either a concrete type (TYPE_TARGET_TYPE)
+       or a template parameter.  */
+    gcc_type return_type;
+
+    if (tsym->template_return_index != -1)
+      {
+       gcc_type param_type
+         = defn->parameter_abstract_type (tsym->template_return_index);
+
+       return_type
+         = add_type_modifiers (m_instance, param_type, d_left (comp));
+      }
+    else if (tsym->conversion_operator_index != -1)
+      {
+       bool done = false;
+       gcc_type param_type
+         = defn->parameter_abstract_type (tsym->conversion_operator_index);
+
+       /* Conversion operators do not have a return type or arguments,
+          so we need to use the CONVERSION node in the left/name sub-tree
+          of the demangle tree.  */
+
+       comp = d_left (defn->demangle_info ()->tree);
+       while (!done)
+         {
+           switch (comp->type)
+             {
+             case DEMANGLE_COMPONENT_TEMPLATE:
+               comp = d_left (comp);
+               break;
+
+             case DEMANGLE_COMPONENT_QUAL_NAME:
+               comp = d_right (comp);
+               break;
+
+             case DEMANGLE_COMPONENT_CONVERSION:
+             default:
+               done = true;
+               break;
+             }
+         }
+
+       /* We had better have found a CONVERSION node if
+          tsym->conversion_operator_index was set!  */
+       gdb_assert (comp->type == DEMANGLE_COMPONENT_CONVERSION);
+       return_type = add_type_modifiers (m_instance, param_type,
+                                         d_left (comp));
+      }
+    else
+      {
+       struct type *temp = TYPE_TARGET_TYPE (SYMBOL_TYPE (&tsym->base));
+
+       return_type = m_instance->convert_type (temp);
+      }
+
+    /* Get the parameters' definitions, and put them into ARRAY.  */
+    struct type *templ_type = SYMBOL_TYPE (&tsym->base);
+    int is_varargs = is_varargs_p (templ_type);
+    struct gcc_type_array array;
+
+    array.n_elements = TYPE_NFIELDS (templ_type);
+    array.elements = XNEWVEC (gcc_type, TYPE_NFIELDS (templ_type));
+    make_cleanup (xfree, array.elements);
+
+    int artificials = 0;
+
+    /* d_right (info->tree) is FUNCTION_TYPE (assert above).  */
+    comp = d_right (d_right (defn->demangle_info ()->tree));
+    gdb_assert (comp != NULL && comp->type == DEMANGLE_COMPONENT_ARGLIST);
+
+    for (int i = 0; i < TYPE_NFIELDS (templ_type); ++i)
+      {
+       if (TYPE_FIELD_ARTIFICIAL (templ_type, i))
+         {
+           --array.n_elements;
+           ++artificials;
+         }
+       else
+         {
+           int tidx = tsym->template_argument_indices[i - artificials];
+           struct type *arg_type = TYPE_FIELD_TYPE (templ_type, i);
+
+           if (tidx == -1)
+             {
+               /* The parameter's type is a concrete type.  */
+               array.elements[i - artificials]
+                 = m_instance->convert_type (arg_type);
+             }
+           else
+             {
+               /* The parameter's type is a template parameter.  */
+               gcc_type result = defn->parameter_abstract_type (tidx);
+
+               array.elements[i - artificials]
+                 = add_type_modifiers (m_instance, result, d_left (comp));
+             }
+
+           /* Move to the next ARGLIST node.  */
+           comp = d_right (comp);
+         }
+      }
+
+    gcc_type func_type = m_instance->build_function_type (return_type, &array,
+                                                         is_varargs);
+
+    /* If we have a method, create its type and set additional symbol flags
+       for the compiler.  */
+    if (defn->parent_type () != NULL
+       && defn->fidx () != -1 && defn->midx () != -1)
+      {
+       gcc_type class_type;
+       struct fn_field *methods
+         = TYPE_FN_FIELDLIST1 (defn->parent_type (), defn->fidx ());
+
+       /* Get the defining class's type.  This should already be in the
+          cache.  */
+       class_type = m_instance->convert_type (defn->parent_type ());
+
+       /* Add any virtuality flags.  */
+       if (TYPE_FN_FIELD_VIRTUAL_P (methods, defn->midx ()))
+         {
+           sym_kind |= GCC_CP_FLAG_VIRTUAL_FUNCTION;
+
+           /* Unfortunate to have to do a symbol lookup, but this is the only
+              way to know if we have a pure virtual method.  */
+           struct block_symbol sym
+             = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (methods, defn->midx ()),
+                              m_instance->block (), VAR_DOMAIN, NULL);
+           if (sym.symbol == NULL)
+             {
+               /* !!keiths: The pure virtual hack.  See
+                  ccp_convert_struct_or_union_methods for more.  */
+               sym_kind |= GCC_CP_FLAG_PURE_VIRTUAL_FUNCTION;
+             }
+         }
+
+       /* Add access flags.  */
+       sym_kind |= get_method_access_flag (defn->parent_type (),
+                                           defn->fidx (), defn->midx ());
+
+       /* Create the method type.  */
+       if (!TYPE_FN_FIELD_STATIC_P (methods, defn->midx ()))
+         {
+           gcc_cp_qualifiers_flags quals;
+           gcc_cp_ref_qualifiers_flags rquals;
+
+           quals = (enum gcc_cp_qualifiers) 0; /* !!keiths FIXME  */
+           rquals = GCC_CP_REF_QUAL_NONE; /* !!keiths FIXME  */
+           func_type
+             = m_instance->build_method_type (class_type, func_type, quals,
+                                              rquals);
+         }
+      }
+
+    /* Finally, define the new generic template declaration.  */
+    gcc_decl decl
+      = m_instance->build_decl ("function template", name, sym_kind,
+                               func_type, 0, 0,
+                               symbol_symtab (&(tsym->base))->filename,
+                               SYMBOL_LINE (&(tsym->base)));
+    defn->set_decl (decl);
+
+    m_instance->leave_scope ();
+    do_cleanups (back_to);
+  }
+
+ private:
+
+  /* The compiler instance to use.  */
+  compile_cplus_instance *m_instance;
+};
+
+/* See description in compile-cplus-templates.h.  */
+
+void
+compile_cplus_instance::emit_function_template_decls ()
+{
+  function_template_definer definer (this);
+
+  for (auto &item : *m_function_template_defns)
+    definer (item.second.get ());
+}
+
+/* A class to define and fill-in class template definitions.  */
+
+class class_template_definer
+{
+ public:
+
+  class_template_definer (compile_cplus_instance *instance)
+    : m_instance (instance)
+  {
+  }
+
+  void operator() (class_template_defn *defn)
+  {
+    if (defn->defined ())
+      {
+       /* This template has already been defined.  Keep looking for more
+          undefined templates.  */
+       return;
+      }
+
+    /* Make sure this is only done once!  */
+    defn->set_defined (true);
+
+    /* Define any default value types.  */
+    const struct template_argument_info *arg_info
+      = TYPE_TEMPLATE_ARGUMENT_INFO (defn->type ());
+
+    define_default_template_parameter_types (m_instance, defn, arg_info);
+
+    /* Create/push new scope.  */
+    compile_scope scope
+      = m_instance->new_scope (TYPE_NAME (defn->type ()), defn->type ());
+
+    if (scope.nested_type () != GCC_TYPE_NONE)
+      {
+       /* new_processing_context returned the type of the actual template
+          instance from which we're constructing the template definition.
+          It is already defined.  */
+       return;
+      }
+    m_instance->enter_scope (scope);
+
+    /* Start a new template list for this template.  */
+    m_instance->start_template_decl (defn->generic ().c_str ());
+
+    /* Get the parameters' generic kinds and types.  */
+    define_template_parameters_generic (m_instance, defn, arg_info,
+                                       /* filename */ NULL, /*
+                                          !!keiths FIXME  */
+                                       /* line */ 0
+                                       /* !!keiths FIXME  */
+                                       );
+
+
+    /* Define the new generic template declaration.  */
+    if (TYPE_CODE (defn->type ()) == TYPE_CODE_STRUCT)
+      {
+       gcc_decl decl
+         = m_instance->build_decl ("class template", defn->decl_name (),
+                                   GCC_CP_SYMBOL_CLASS /* | nested_access? */
+                                   | (TYPE_DECLARED_CLASS (defn->type ())
+                                      ? GCC_CP_FLAG_CLASS_NOFLAG
+                                      : GCC_CP_FLAG_CLASS_IS_STRUCT),
+                                 0, NULL, 0, /*filename*/ NULL, /*line*/ 0);
+
+       defn->set_decl (decl);
+       }
+    else
+      {
+       gdb_assert (TYPE_CODE (defn->type ()) == TYPE_CODE_UNION);
+       gcc_decl decl
+         = m_instance->build_decl ("union template", defn->decl_name (),
+                                   GCC_CP_SYMBOL_UNION /* | nested_access? */,
+                                   0, NULL, 0, /*fileanme*/NULL, /*line*/0);
+
+       defn->set_decl (decl);
+      }
+
+    m_instance->leave_scope ();
+  }
+
+ private:
+
+  /* The compiler instance to use.  */
+  compile_cplus_instance *m_instance;
+};
+
+/* See description in compile-cplus-templates.h.  */
+
+void
+compile_cplus_instance::emit_class_template_decls ()
+{
+  class_template_definer definer (this);
+
+  for (auto &item : *m_class_template_defns)
+    definer (item.second.get ());
+}
+
+/* A command to test function_template_decl.  */
+
+static void
+print_template_defn_command (char *arg, int from_tty)
+{
+
+  char *demangled_name
+    = gdb_demangle (arg, DMGL_ANSI | DMGL_PARAMS | DMGL_RET_DROP);
+
+  if (demangled_name == NULL)
+    {
+      fprintf_filtered (gdb_stderr, _("could not demangle \"%s\"\n"), arg);
+      return;
+    }
+
+  struct cleanup *back_to = make_cleanup (xfree, demangled_name);
+  struct block_symbol symbol
+    = lookup_symbol (demangled_name, NULL, VAR_DOMAIN, NULL);
+
+  if (symbol.symbol == NULL)
+    {
+      fprintf_filtered (gdb_stderr, _("could not find symbol for \"%s\"\n"),
+                       arg);
+      do_cleanups (back_to);
+      return;
+    }
+
+  if (!SYMBOL_IS_CPLUS_TEMPLATE_FUNCTION (symbol.symbol))
+    {
+      fprintf_filtered (gdb_stderr, _("symbol \"%s\" does not represent a"
+                                     " template function\n"), arg);
+      do_cleanups (back_to);
+      return;
+    }
+
+  struct template_symbol *tsymbol = (struct template_symbol *) symbol.symbol;
+
+  cp_decode_template_type_indices (tsymbol, NULL);
+
+  std::unique_ptr<demangle_parse_info> info
+    = cp_mangled_name_to_comp (arg, DMGL_ANSI | DMGL_PARAMS);
+  std::string str = function_template_decl (tsymbol, info.get ());
+
+  fprintf_filtered (gdb_stdout, "%s\n", str.c_str ());
+  do_cleanups (back_to);
+}
+
+void _initialize_compile_cplus_templates ();
+
+void
+_initialize_compile_cplus_templates ()
+{
+  add_cmd ("tdef", class_maintenance, print_template_defn_command,
+          _("Print the template generic for the given linkage name."),
+          &maint_cplus_cmd_list);
+}
diff --git a/gdb/compile/compile-cplus-templates.h b/gdb/compile/compile-cplus-templates.h
new file mode 100644 (file)
index 0000000..56290b4
--- /dev/null
@@ -0,0 +1,319 @@
+/* Template support for compile.
+
+   Copyright (C) 2016, 2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef COMPILE_CPLUS_TEMPLATES_H
+#define COMPILE_CPLUS_TEMPLATES_H
+#include "gdbtypes.h"
+#include "cp-support.h"
+
+#include <string>
+#include <vector>
+#include <unordered_map>
+#include <memory>
+
+struct symbol;
+struct gcc_cp_template_args;
+struct template_symbol;
+
+namespace compile
+{
+  class function_template_defn;
+  class class_template_defn;
+  class compile_cplus_instance;
+
+  /* Types used for tracking template definitions.  */
+  typedef std::unique_ptr<function_template_defn> function_template_defn_up;
+  typedef std::unique_ptr<class_template_defn> class_template_defn_up;
+  typedef std::pair<std::string, function_template_defn_up>
+    function_template_map_item_t;
+  typedef std::unordered_map<std::string, function_template_defn_up>
+    function_template_defn_map_t;
+  typedef std::pair<std::string, class_template_defn_up>
+    class_template_map_item_t;
+  typedef std::unordered_map<std::string, class_template_defn_up>
+    class_template_defn_map_t;
+
+  /* A base class holding data common to all template definitions.  */
+
+  class template_defn
+  {
+  public:
+
+    /* Return the declaration name of this definition.  */
+
+    const char *
+    decl_name () const
+    {
+      return m_decl_name.c_str ();
+    }
+
+    /* Return the compiler plug-in's decl for this definition.  */
+
+    gcc_decl
+    decl () const
+    {
+      return m_decl;
+    }
+
+    /* Set the compiler plug-in's decl for this definition.  */
+
+    void
+    set_decl (gcc_decl decl)
+    {
+      m_decl = decl;
+    }
+
+    /* Return the generic string for this template definition.  */
+
+    const std::string
+    generic (void) const
+    {
+      return m_generic;
+    }
+
+    /* Return the compiler plug-in's abstract type for the IDX'th
+       template parameter.  */
+
+    gcc_type
+    parameter_abstract_type (unsigned int idx) const
+    {
+      return m_abstract_types[idx];
+    }
+
+    /* Set the IDX'th template parameter's abstract type.  */
+
+    void
+    set_parameter_abstract_type (unsigned int idx, gcc_type type)
+    {
+      m_abstract_types[idx] = type;
+    }
+
+    /* Has this template already been defined in the compiler plug-in?  */
+
+    bool
+    defined (void) const
+    {
+      return m_defined;
+    }
+
+    /* Mark this definition as defined in the compiler plug-in.  */
+
+    void
+    set_defined (bool val)
+    {
+      m_defined = val;
+    }
+
+    /* Return the ARG_NUM'th template parameter's default value
+       or NULL if none was set (or known).  */
+
+    struct symbol *
+    default_argument (unsigned int arg_num) const
+    {
+      return m_default_arguments[arg_num];
+    }
+
+    /* Record the value of the ARG_NUM'th template parameter.  */
+
+    void
+    set_default_argument (unsigned int arg_num, struct symbol *value)
+    {
+      m_default_arguments[arg_num] = value;
+    }
+
+  protected:
+
+    /* Protected constructor so that no one instantiates this
+       type directly.
+
+       DECL_NAME is the declaration name of this template, i.e., it's
+       name with no template parameters.  GENERIC is the computed generic
+       template definition.  N_PARAMETERS specifies how many template
+       parameters this template has.  */
+
+    template_defn (std::string decl_name, std::string generic,
+                  unsigned int n_parameters)
+      : m_decl_name (decl_name), m_generic (generic),
+       m_abstract_types (n_parameters), m_decl (0),
+       m_default_arguments (n_parameters), m_defined (false)
+    {
+    }
+
+  private:
+
+    /* The declaration name of the template, excluding any
+       parameters.  */
+    std::string m_decl_name;
+
+    /* A string representation of the generic template definition.  */
+    std::string m_generic;
+
+    /* The abstract template parameter types.  */
+    std::vector<gcc_type> m_abstract_types;
+
+    /* The decl associated with this template definition.  */
+    gcc_decl m_decl;
+
+    /* A list of default values for the parameters of this template.  */
+    std::vector<struct symbol *> m_default_arguments;
+
+    /* Has this template already been defined?  This is a necessary evil
+       since we have to traverse over all hash table entries.  */
+    bool m_defined;
+  };
+
+  /* A function template definition.  */
+
+  class function_template_defn
+    : public template_defn
+  {
+  public:
+
+    /* Construct a new function template definition with the generic
+       string representation GENERIC and demangle INFO, based on the
+       concrete instance given by template symbol TSYMBOL.
+
+       If this definition is a method template, PARENT_TYPE is the type
+       of the closing class and FIDX and MIDX are the fieldlist and
+       method indices, respectively, which describe this method.
+
+       If this definition is not a method template, PARENT_TYPE is NULL
+       and FIDX/MIDX are both -1.  */
+
+    function_template_defn (std::string generic,
+                           std::unique_ptr<demangle_parse_info> info,
+                           const struct template_symbol *tsymbol,
+                           struct type *parent_type, int fidx, int midx);
+
+    /* Return the demangle information for this template.  */
+
+    const demangle_parse_info *demangle_info (void) const
+    {
+      return m_demangle_info.get ();
+    }
+
+    /* Return the concrete instance used to define this template.  */
+
+    const struct template_symbol *template_symbol (void) const
+    {
+      return m_tsymbol;
+    }
+
+    /* For method templates, return the type of the enclosing parent type,
+       or NULL for non-method templates.  */
+
+    struct type *parent_type (void) const
+    {
+      return m_parent_type;
+    }
+
+    /* For method templates, return the field list index in PARENT_TYPE
+       which describes this method.  Return -1 otherwise.  */
+
+    int fidx (void) const
+    {
+      return m_fidx;
+    }
+
+    /* For method templates, return the index of this method into the
+       field list (given by fidx()).  Return -1 otherwise.  */
+
+    int midx (void) const
+    {
+      return m_midx;
+    }
+
+  private:
+
+    /* The template symbol used to create this template definition.
+       NOTE: Any given template_defn could be associated with any number
+       of template instances in the program.
+
+       This field is not const since we will be lazily computing template
+       parameter indices for the function's argument and return types.  */
+
+    const struct template_symbol *m_tsymbol;
+
+    /* The parent type or NULL if this does not represent a method.  */
+
+    struct type *m_parent_type;
+
+    /* The fieldlist and method indices for the method or -1 if this template
+       definition does not represent a method.  */
+
+    int m_fidx;
+    int m_midx;
+
+    /* Demangle tree for the template defining this generic.  */
+    std::unique_ptr<demangle_parse_info> m_demangle_info;
+  };
+
+  /* A class template definition.  */
+
+  class class_template_defn
+    : public template_defn
+  {
+  public:
+
+    /* A unary function to delete map items.  */
+
+    static void destroy (class_template_map_item_t p);
+
+    /* Construct a new class template definition with the generic
+       string representation GENERIC based on the concrete instance
+       TYPE.  */
+
+    class_template_defn (std::string decl_name, std::string generic,
+                        struct type *type)
+      : template_defn (decl_name, generic, TYPE_N_TEMPLATE_ARGUMENTS (type)),
+       m_type (type)
+    {
+    }
+
+    /* Return concrete instance that this template definition was
+       based on.  */
+
+    struct type *type (void) const
+    {
+      return m_type;
+    }
+
+  private:
+
+    /* The type used to create this template definition.
+       NOTE: Any given template_defn could be associated with any number
+       of template instances in the program.  */
+    struct type *m_type;
+  };
+
+  /* Loop over SYMBOLS, defining any generic template definitions for
+     any template symbols in the list.  */
+
+  void define_templates (compile_cplus_instance *instance,
+                        VEC (block_symbol_d) *symbols);
+
+
+  /* Scan TYPE for any new function templates.
+     Does not actually emit definitions for any new templates until
+     emit_function_template_decls is called.  */
+
+  void scan_type_for_function_templates (compile_cplus_instance *instance,
+                                        struct type *type);
+};
+#endif /* COMPILE_CPLUS_TEMPLATES_H  */
diff --git a/gdb/compile/compile-cplus-types.c b/gdb/compile/compile-cplus-types.c
new file mode 100644 (file)
index 0000000..5265524
--- /dev/null
@@ -0,0 +1,2273 @@
+/* Convert types from GDB to GCC
+
+   Copyright (C) 2014-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+#include "defs.h"
+#include "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>
+
+using namespace compile;
+
+/* Define to enable debugging for ctor/dtor definitions during
+   type conversion.  */
+
+#define DEBUG_XTOR 0
+
+/* A "type" to indicate that convert_type should not attempt to
+   cache its resultant type.  This is used, for example, when defining
+   namespaces for the oracle.  */
+
+#define DONT_CACHE_TYPE ((gcc_type) 0)
+
+/* 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 ccp_convert_func (compile_cplus_instance *instance,
+                                 struct type *type, int strip_artificial);
+
+/* See description in compile-cplus.h.  */
+
+char *
+compile::decl_name (const char *natural)
+{
+  char *name = NULL;
+
+  if (natural != NULL)
+    {
+      char *stripped;
+
+      /* !!keiths: FIXME: Write a new parser func to do this?  */
+      name = cp_func_name (natural);
+      if (name == NULL)
+       {
+         stripped = cp_strip_template_parameters (natural);
+         if (stripped != NULL)
+           return stripped;
+
+         name = xstrdup (natural);
+       }
+      else
+       {
+         stripped = cp_strip_template_parameters (name);
+         if (stripped != NULL)
+           {
+             xfree (name);
+             return stripped;
+           }
+       }
+    }
+
+  return name;
+}
+
+/* See description in compile-cplus.h.  */
+
+int
+compile::is_varargs_p (const struct type *type)
+{
+  /* !!keiths: This doesn't always work, unfortunately.  When we have a
+     pure virtual method, TYPE_PROTOTYPED == 0.
+     But this *may* be needed for several gdb.compile tests.  Or at least
+     indicate other unresolved bugs in this file or elsewhere in gdb.  */
+  return TYPE_VARARGS (type) /*|| !TYPE_PROTOTYPED (type)*/;
+}
+
+/* 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
+compile::get_method_access_flag (const struct type *type, int fni, int num)
+{
+  const struct fn_field *methods;
+
+  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.  */
+  methods = TYPE_FN_FIELDLIST1 (type, fni);
+  if (TYPE_FN_FIELD_PUBLIC (methods, num))
+    return GCC_CP_ACCESS_PUBLIC;
+  else 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;
+
+  gdb_assert_not_reached ("unhandled method access specifier");
+}
+
+/* A useful debugging function to output the scope SCOPE
+   to stdout.  */
+
+static void __attribute__ ((used))
+debug_print_scope (const compile_scope &scope)
+{
+  int i;
+
+  for (const auto &comp: scope)
+    {
+      std::string symbol = (comp.bsymbol.symbol != NULL
+                           ? SYMBOL_NATURAL_NAME (comp.bsymbol.symbol)
+                           : "<none>");
+
+      printf ("\tname = %s, symbol = %s\n", comp.name.c_str (),
+             symbol.c_str ());
+    }
+}
+
+/* Utility function to convert CODE into a string.  */
+
+static const char *
+type_code_to_string (enum type_code code)
+{
+  const char * const s[] =
+    {"BISTRING (deprecated)", "UNDEF (not used)",
+      "PTR", "ARRAY", "STRUCT", "UNION", "ENUM",
+      "FLAGS", "FUNC", "INT", "FLT", "VOID",
+      "SET", "RANGE", "STRING", "ERROR", "METHOD",
+      "METHODPTR", "MEMBERPTR", "REF", "CHAR", "BOOL",
+      "COMPLEX", "TYPEDEF", "NAMESPACE", "DECFLOAT", "MODULE",
+     "INTERNAL_FUNCTION", "XMETHOD"};
+
+  return s[code + 1];
+}
+
+/* See description in compile-cplus.h.  */
+
+compile_scope
+compile::type_name_to_scope (const char *type_name, const struct block *block)
+{
+  compile_scope scope;
+
+  if (type_name == NULL)
+    {
+      /* 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 (1)
+    {
+      /* 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, NULL);
+
+      if (bsymbol.symbol != NULL)
+       {
+         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"));
+           }
+       }
+      if (p[0] == '\0')
+       break;
+    }
+
+  return scope;
+}
+
+/* Compare two scope_components for equality.  These are equal if the names
+   of the two components' are the same.  */
+
+bool
+compile::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
+compile::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
+compile::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
+compile::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)
+       printf_unfiltered ("entering new scope %p\n", new_scope);
+
+      /* Push the global namespace. */
+      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 auto &comp)
+        {
+         gdb_assert (TYPE_CODE (SYMBOL_TYPE (comp.bsymbol.symbol))
+                     == TYPE_CODE_NAMESPACE);
+
+         const char *ns = (comp.name == CP_ANONYMOUS_NAMESPACE_STR ? NULL
+                           : comp.name.c_str ());
+
+         this->push_namespace (ns);
+        });
+    }
+  else
+    {
+      if (debug_compile_cplus_scopes)
+       {
+         printf_unfiltered
+           ("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)
+       printf_unfiltered ("leaving scope %p\n", current);
+
+      /* Pop namespaces.  Do not push the last scope_component -- that's
+        the type we are converting, not a namespace.  */
+      std::for_each
+       (current.begin (),current.end () - 1, [this] (const auto &comp) {
+         gdb_assert (TYPE_CODE (SYMBOL_TYPE (comp.bsymbol.symbol))
+                     == TYPE_CODE_NAMESPACE);
+         this->pop_binding_level (comp.name.c_str ());
+       });
+
+      /* Pop global namespace.  */
+      pop_binding_level ("");
+    }
+  else
+    {
+      if (debug_compile_cplus_scopes)
+       printf_unfiltered ("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!  */
+         type_map_t::iterator pos = m_type_map.find (type);
+
+         gdb_assert (pos != m_type_map.end ());
+         scope.m_nested_type = pos->second;
+         return scope;
+       }
+    }
+  else
+    {
+      if (TYPE_NAME (type) == NULL)
+       {
+         /* 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;
+
+         comp.bsymbol
+           = lookup_symbol (TYPE_NAME (type), block (), VAR_DOMAIN, NULL);
+
+         char *name = cp_func_name (TYPE_NAME (type));
+
+         comp.name = name;
+         xfree (name);
+         scope.push_back (comp);
+       }
+    }
+
+  /* Ensure least one component in the scope.  */
+  gdb_assert (scope.size () > 0);
+  return scope;
+}
+
+/* !!keiths: not RVALUE REFERENCES!  */
+
+gcc_type
+compile::convert_reference_base (compile_cplus_instance *instance,
+                                gcc_type base)
+{
+  return instance->build_reference_type (base, GCC_CP_REF_QUAL_LVALUE);
+}
+
+/* Convert a reference type to its gcc representation.  */
+
+static gcc_type
+ccp_convert_reference (compile_cplus_instance *instance,
+                      struct type *type)
+{
+  gcc_type target = instance->convert_type (TYPE_TARGET_TYPE (type));
+
+  /* !!keiths: GDB does not currently do anything with rvalue references.
+     [Except set the type code to TYPE_CODE_ERROR!  */
+  return convert_reference_base (instance, target);
+}
+
+/* See description in compile-cplus.h.  */
+
+gcc_type
+compile::convert_pointer_base (compile_cplus_instance *instance,
+                              gcc_type target)
+{
+  return instance->build_pointer_type (target);
+}
+
+/* Convert a pointer type to its gcc representation.  */
+
+static gcc_type
+ccp_convert_pointer (compile_cplus_instance *instance,
+                    struct type *type)
+{
+  gcc_type target = instance->convert_type (TYPE_TARGET_TYPE (type));
+
+  return convert_pointer_base (instance, target);
+}
+
+/* Convert an array type to its gcc representation.  */
+
+static gcc_type
+ccp_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->error (s);
+    }
+
+  if (TYPE_LOW_BOUND (range) != 0)
+    {
+      const char *s = _("cannot convert array type with "
+                       "non-zero lower bound to C");
+
+      return instance->error (s);
+    }
+
+  if (TYPE_HIGH_BOUND_KIND (range) == PROP_LOCEXPR
+      || TYPE_HIGH_BOUND_KIND (range) == PROP_LOCLIST)
+    {
+      gcc_type result;
+      char *upper_bound;
+
+      if (TYPE_VECTOR (type))
+       {
+         const char *s = _("variably-sized vector type is not supported");
+
+         return instance->error (s);
+       }
+
+      upper_bound = c_get_range_decl_name (&TYPE_RANGE_DATA (range)->high);
+      result = instance->build_vla_array_type (element_type, upper_bound);
+      xfree (upper_bound);
+      return result;
+    }
+  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->build_vector_type (element_type, count);
+
+      return instance->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
+ccp_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 ();
+
+  char *name = NULL;
+  struct cleanup *cleanups = make_cleanup (free_current_contents, &name);
+
+  if (TYPE_NAME (type) != NULL)
+    name = cp_func_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->build_decl ("typedef", name,
+                       GCC_CP_SYMBOL_TYPEDEF | nested_access,
+                       typedef_type,
+                       0, 0,
+                       /* !!keiths: Wow. More of this!  */
+                       NULL, 0);
+
+  /* Completed this scope.  */
+  instance->leave_scope ();
+  do_cleanups (cleanups);
+  return typedef_type;
+}
+
+/* Convert types defined in TYPE.  */
+
+static void
+ccp_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_PUBLIC (type, i))
+       accessibility = GCC_CP_ACCESS_PUBLIC;
+      else 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
+       gdb_assert_not_reached ("unknown accessibility");
+      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_PUBLIC (type, i))
+       accessibility = GCC_CP_ACCESS_PUBLIC;
+      else 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
+       gdb_assert_not_reached ("unknown accessibility");
+      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
+ccp_convert_struct_or_union_members (compile_cplus_instance *instance,
+                                    struct type *type, gcc_type comp_type)
+{
+  int i;
+
+  for (i = TYPE_N_BASECLASSES (type); i < TYPE_NFIELDS (type); ++i)
+    {
+      CORE_ADDR physaddr;
+      gcc_type field_type;
+      const char *field_name = TYPE_FIELD_NAME (type, i);
+
+      if (TYPE_FIELD_IGNORE (type, i)
+         || TYPE_FIELD_ARTIFICIAL (type, i))
+       continue;
+
+      field_type
+       = instance->convert_type (TYPE_FIELD_TYPE (type, i));
+
+      if (field_is_static (&TYPE_FIELD (type, i)))
+       {
+         switch (TYPE_FIELD_LOC_KIND (type, i))
+           {
+           case FIELD_LOC_KIND_PHYSADDR:
+             {
+               physaddr = TYPE_FIELD_STATIC_PHYSADDR (type, i);
+
+               instance->build_decl ("field physaddr", field_name,
+                                     (GCC_CP_SYMBOL_VARIABLE
+                                      | get_field_access_flag (type, i)),
+                                     field_type, NULL, physaddr,
+                                     NULL, 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,
+                                  NULL);
+               const char *filename;
+               unsigned int line;
+
+               if (sym.symbol == NULL)
+                 {
+                   /* We didn't actually find the symbol.  There's little
+                      we can do but ignore this member.  */
+                   continue;
+                 }
+               filename = symbol_symtab (sym.symbol)->filename;
+               line = SYMBOL_LINE (sym.symbol);
+               physaddr = SYMBOL_VALUE_ADDRESS (sym.symbol);
+               instance->build_decl ("field physname", field_name,
+                                     (GCC_CP_SYMBOL_VARIABLE
+                                      | get_field_access_flag (type, i)),
+                                     field_type, NULL, 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)
+         /* FIXME:
+           | (field-is-mutable-p (type, i)
+              ? GCC_CP_FLAG_FIELD_MUTABLE
+              : GCC_CP_FLAG_FIELD_NOFLAG)
+            -lxo */
+           ;
+
+         if (bitsize == 0)
+           bitsize = 8 * TYPE_LENGTH (TYPE_FIELD_TYPE (type, i));
+
+         /* FIXME: We have to save the returned decl somewhere, so
+            that we can refer to it in expressions, in context for
+            lambdas, etc.  */
+         instance->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
+ccp_convert_method (compile_cplus_instance *instance,
+                   struct type *parent_type, struct type *method_type)
+{
+  gcc_type result, func_type, class_type;
+  gcc_cp_qualifiers_flags quals;
+  gcc_cp_ref_qualifiers_flags rquals;
+
+  /* Get the actual (proto)type of the method, as a function.  */
+  func_type = ccp_convert_func (instance, method_type, 1);
+
+  class_type = instance->convert_type (parent_type);
+  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;
+  rquals = GCC_CP_REF_QUAL_NONE;
+  /* !!keiths FIXME  */
+  result = instance->build_method_type (class_type, func_type, quals, rquals);
+  return result;
+}
+
+/* Convert a member or method pointer represented by TYPE.  */
+
+static gcc_type
+ccp_convert_memberptr (compile_cplus_instance *instance, struct type *type)
+{
+  struct type *containing_class = TYPE_SELF_TYPE (type);
+
+  if (containing_class == NULL)
+    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->build_pointer_to_member_type (class_type, member_type);
+}
+
+#define OPHASH1(A) ((uint32_t) A << 16)
+#define OPHASH2(A,B) OPHASH1(A) | (uint32_t) B << 8
+#define OPHASH3(A,B,C) OPHASH2(A,B) | (uint32_t) C
+
+/* Compute a one, two, or three letter hash for the operator given by
+   OP.  Returns the computed hash or zero for (some) conversion operators.  */
+
+static uint32_t
+operator_hash (const char *op)
+{
+  const char *p = op;
+  uint32_t hash = 0;
+  int len = 0;
+
+  while (p[0] != '\0' && (p[0] != '(' || p[1] == ')'))
+    {
+      ++len;
+      ++p;
+    }
+
+  switch (len)
+    {
+    case 1:
+      hash = OPHASH1(op[0]);
+      break;
+    case 2:
+     hash = OPHASH2(op[0], op[1]);
+     break;
+    case 3:
+      /* This will also hash "operator int", but the plug-in does not
+        recognize OPHASH3('i', 'n', 't'), so we still end up in the code
+        to do a conversion operator in the caller.  */
+      hash = OPHASH3(op[0], op[1], op[2]);
+      break;
+    default:
+      break;
+    }
+
+  return hash;
+}
+
+/* Returns non-zero iff TYPE represents a binary method.  */
+
+static int
+is_binary_method (const struct type *type)
+{
+  int i, len;
+
+  for (i = 0, len = 0; i < TYPE_NFIELDS (type); ++i)
+    {
+      if (!TYPE_FIELD_ARTIFICIAL (type, i))
+       ++len;
+    }
+
+ return len > 1;
+}
+
+/* See compile-cplus.h.  */
+
+const char *
+compile::maybe_canonicalize_special_function
+  (const char *field_name, const struct fn_field *method_field,
+   const struct type *method_type, char **outname, bool *ignore)
+{
+  /* We assume that no method is to be ignored.  */
+  *ignore = false;
+
+  /* We only consider ctors and dtors if METHOD_FIELD is non-NULL.  */
+  if (method_field != NULL)
+    {
+      if (method_field->is_constructor)
+       {
+#if DEBUG_XTOR
+         printf ("*** CONSTRUCTOR %s: ", field_name);
+#endif
+#if CAUSES_ICE
+         switch (method_field->cdtor_type.ctor_kind)
+           {
+           case complete_object_ctor:
+#if DEBUG_XTOR
+             printf ("complete_object_ctor (C1)\n");
+#endif
+             return "C1";
+
+           case base_object_ctor:
+#if DEBUG_XTOR
+             printf ("base_object_ctor (C2)\n");
+#endif
+             return "C2";
+
+           case complete_object_allocating_ctor:
+             *ignore = true;
+#if DEBUG_XTOR
+             printf ("complete_object_allocating_ctor -- ignored\n");
+#endif
+             return field_name; /* C?  */
+
+           case unified_ctor:
+#if DEBUG_XTOR
+             printf ("unified_ctor (C4) -- ignored\n");
+#endif
+             *ignore = true;
+             return field_name; /* C4  */
+
+           case object_ctor_group:
+#if DEBUG_XTOR
+             printf ("object_ctor_group -- ignored\n");
+#endif
+             *ignore = true;
+             return field_name; /* C?  */
+
+           case not_ctor:
+#if DEBUG_XTOR
+             printf ("unknown_ctr -- ignored\n");
+#endif
+             *ignore = true;
+             return field_name; /* unknown  */
+
+           default:
+             gdb_assert_not_reached ("unknown constructor kind");
+           }
+#else
+#if DEBUG_XTOR
+         printf ("DISABLED -- ignored\n");
+#endif
+         *ignore = true;
+#endif /* CAUSES_ICE  */
+       }
+      else  if (method_field->is_destructor)
+       {
+#if DEBUG_XTOR
+         printf ("*** DESTRUCTOR %s: ", field_name);
+#endif
+         switch (method_field->cdtor_type.dtor_kind)
+           {
+           case deleting_dtor:
+#if DEBUG_XTOR
+             printf ("deleting_dtor (D0)\n");
+#endif
+             return "D0";
+
+           case complete_object_dtor:
+#if DEBUG_XTOR
+             printf ("complete_object_dtor (D1)\n");
+#endif
+             return "D1";
+
+           case base_object_dtor:
+#if DEBUG_XTOR
+             printf ("base_object_dtor (D2)\n");
+#endif
+             return "D2";
+
+           case unified_dtor:
+#if DEBUG_XTOR
+             printf ("unified_dtor (D4) -- ignored\n");
+#endif
+             *ignore = true;
+             return field_name; /* D4  */
+
+           case object_dtor_group:
+#if DEBUG_XTOR
+             printf ("object_dtor_group (D?) -- ignored\n");
+#endif
+             *ignore = true;
+             return field_name; /* D?  */
+
+           case not_dtor:
+#if DEBUG_XTOR
+             printf ("not_dtor -- ignored\n");
+#endif
+             *ignore = true;
+             return field_name; /* unknown  */
+
+           default:
+             gdb_assert_not_reached ("unknown destructor kind");
+           }
+       }
+    }
+
+  if (!is_operator_name (field_name))
+    return field_name;
+
+  /* Skip over "operator".  */
+  field_name += sizeof ("operator") - 1;
+
+  if (strncmp (field_name, "new", sizeof ("new") - 1) == 0)
+    {
+      field_name += 3;
+      if (*field_name == '\0')
+       return "nw";
+      else if (*field_name == '[')
+       return "na";
+    }
+  else if (strncmp (field_name, "delete", sizeof ("delete") - 1) == 0)
+    {
+      if (*field_name == '\0')
+       return "dl";
+      else if (*field_name == '[')
+       return "da";
+    }
+  else if (field_name[0] == '\"' && field_name[1] == '\"')
+    {
+      const char *end;
+      size_t len;
+
+      /* Skip over \"\" -- the plug-in doesn't want it.  */
+      field_name += 2;
+
+      /* Skip any whitespace that may have been introduced during
+        canonicalization.  */
+      field_name = skip_spaces_const (field_name);
+
+      /* Find the opening '(', if any.  */
+      end = strchr (field_name, '(');
+      if (end == NULL)
+       end = field_name + strlen (field_name);
+
+      /* Size of buffer: 'li', 'i', sizeof operator name, '\0'  */
+      len = 2 + end - field_name + 1;
+      *outname = (char *) xmalloc (len);
+      strcpy (*outname, "li");
+      strncat (*outname, field_name, end - field_name);
+      (*outname)[len-1] = '\0';
+      return "li";
+    }
+
+  switch (operator_hash (field_name))
+    {
+    case OPHASH1 ('+'):
+      if (is_binary_method (method_type))
+       return "pl";
+      else
+       return "ps";
+      break;
+
+    case OPHASH1 ('-'):
+      if (is_binary_method (method_type))
+       return "mi";
+      else
+       return "ng";
+      break;
+    case OPHASH1 ('&'):
+      if (is_binary_method (method_type))
+       return "an";
+      else
+       return "ad";
+      break;
+
+    case OPHASH1 ('*'):
+      if (is_binary_method (method_type))
+       return "ml";
+      else
+       return "de";
+      break;
+
+    case OPHASH1 ('~'):
+      return "co";
+    case OPHASH1 ('/'):
+      return "dv";
+    case OPHASH1 ('%'):
+      return "rm";
+    case OPHASH1 ('|'):
+      return "or";
+    case OPHASH1 ('^'):
+      return "eo";
+    case OPHASH1 ('='):
+      return "aS";
+    case OPHASH2 ('+', '='):
+      return "pL";
+    case OPHASH2 ('-', '='):
+      return "mI";
+    case OPHASH2 ('*', '='):
+      return "mL";
+    case OPHASH2 ('/', '='):
+      return "dV";
+    case OPHASH2 ('%', '='):
+      return "rM";
+    case OPHASH2 ('&', '='):
+      return "aN";
+    case OPHASH2 ('|', '='):
+      return "oR";
+    case OPHASH2 ('^', '='):
+      return "eO";
+    case OPHASH2 ('<', '<'):
+      return "ls";
+    case OPHASH2 ('>', '>'):
+      return "rs";
+    case OPHASH3 ('<', '<', '='):
+      return "lS";
+    case OPHASH3 ('>', '>', '='):
+      return "rS";
+    case OPHASH2 ('=', '='):
+      return "eq";
+    case OPHASH2 ('!', '='):
+      return "ne";
+    case OPHASH1 ('<'):
+      return "lt";
+    case OPHASH1 ('>'):
+      return "gt";
+    case OPHASH2 ('<', '='):
+      return "le";
+    case OPHASH2 ('>', '='):
+      return "ge";
+    case OPHASH1 ('!'):
+      return "nt";
+    case OPHASH2 ('&', '&'):
+      return "aa";
+    case OPHASH2 ('|', '|'):
+      return "oo";
+    case OPHASH2 ('+', '+'):
+      return "pp";
+    case OPHASH2 ('-', '-'):
+      return "mm";
+    case OPHASH1 (','):
+      return "cm";
+    case OPHASH3 ('-', '>', '*'):
+      return "pm";
+    case OPHASH2 ('-', '>'):
+      return "pt";
+    case OPHASH2 ('(', ')'):
+      return "cl";
+    case OPHASH2 ('[', ']'):
+      return "ix";
+    case OPHASH1 ('?'):
+      return "qu";
+
+    default:
+      /* Conversion operators: Full name is not needed.  */
+      return "cv";
+    }
+}
+
+/* Convert all methods defined in TYPE, which should be a class/struct/union
+   with gcc_type CLASS_TYPE.  */
+
+static void
+ccp_convert_struct_or_union_methods (compile_cplus_instance *instance,
+                                    struct type *type, gcc_type class_type)
+{
+  int i;
+
+  /* First things first: If this class had any template methods, emit them so
+     that the compiler knows about them.  */
+  instance->emit_function_template_decls ();
+
+
+  /* Now define the actual methods/template specializations.  */
+  for (i = 0; i < TYPE_NFN_FIELDS (type); ++i)
+    {
+      int j;
+      struct fn_field *methods = TYPE_FN_FIELDLIST1 (type, i);
+      char *overloaded_name
+       = decl_name (TYPE_FN_FIELDLIST_NAME (type, i));
+      struct cleanup *outer = make_cleanup (xfree, overloaded_name);
+
+      /* Loop through the fieldlist, adding decls to the compiler's
+        representation of the class.  */
+      for (j = 0; j < TYPE_FN_FIELDLIST_LENGTH (type, i); ++j)
+       {
+         CORE_ADDR address;
+         gcc_type method_type;
+         struct block_symbol sym;
+         const char *filename;
+         unsigned int line;
+         const char *kind;
+         gcc_cp_symbol_kind_flags sym_kind = GCC_CP_SYMBOL_FUNCTION;
+         const char *name;
+         char *special_name;
+         struct cleanup *back_to;
+         bool ignore;
+         struct template_symbol *tsym = NULL;
+
+         /* Skip artificial methods.  */
+         if (TYPE_FN_FIELD_ARTIFICIAL (methods, j))
+           continue;
+
+         special_name = NULL;
+         name = maybe_canonicalize_special_function (overloaded_name,
+                                                     &methods[j],
+                                                     methods[j].type,
+                                                     &special_name,
+                                                     &ignore);
+         if (ignore)
+           continue;
+
+         back_to = make_cleanup (null_cleanup, NULL);
+
+         if (special_name != NULL)
+           {
+             make_cleanup (xfree, special_name);
+             name = special_name;
+           }
+
+         if (name != overloaded_name)
+           {
+             sym_kind |= GCC_CP_FLAG_SPECIAL_FUNCTION;
+           }
+         sym = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (methods, j),
+                              instance->block (), VAR_DOMAIN, NULL);
+
+         if (sym.symbol == NULL)
+           {
+             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
+                   = ccp_convert_method (instance, type,
+                                         TYPE_FN_FIELD_TYPE (methods, j));
+
+                 instance->build_decl ("pure virtual method", name,
+                                       (sym_kind
+                                        | get_method_access_flag (type, i, j)
+                                        | GCC_CP_FLAG_VIRTUAL_FUNCTION
+                                        | GCC_CP_FLAG_PURE_VIRTUAL_FUNCTION),
+                                       method_type, NULL, 0,
+                                       NULL /* FIXME: filename  */,
+                                       0 /* FIXME: line number  */);
+                 do_cleanups (back_to);
+                 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));
+             do_cleanups (back_to);
+             continue;
+           }
+
+         filename = symbol_symtab (sym.symbol)->filename;
+         line = SYMBOL_LINE (sym.symbol);
+         address = BLOCK_START (SYMBOL_BLOCK_VALUE (sym.symbol));
+
+         /* Short-circuit for method templates.  */
+         if (SYMBOL_IS_CPLUS_TEMPLATE_FUNCTION (sym.symbol))
+           {
+             struct template_symbol *tsymbol
+               = (struct template_symbol *) sym.symbol;
+
+             instance->build_function_template_specialization (tsymbol,
+                                                               address,
+                                                               filename, line);
+             do_cleanups (back_to);
+             continue;
+           }
+
+         if (TYPE_FN_FIELD_STATIC_P (methods, j))
+           {
+             kind = "static method";
+             method_type = ccp_convert_func (instance,
+                                             TYPE_FN_FIELD_TYPE (methods, j),
+                                             1);
+           }
+         else
+           {
+             kind = "method";
+             method_type
+               = ccp_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;
+
+         /* FIXME: for cdtors, we must call build_decl with a zero
+            address, if we haven't created the base declaration
+            yet, and then define_cdtor_clone with the address of
+            each clone.  When we leave the address out, GCC uses
+            the address oracle.  -lxo  */
+         if ((sym_kind & GCC_CP_FLAG_SPECIAL_FUNCTION)
+             && (name[0] == 'C' || name[0] == 'D'))
+           {
+             address = 0;
+             /* FIXME: We should declare only one cdtor for each
+                clone set with "C" or "D" as the name, with address
+                zero, then define each address with
+                define_cdtor_clone.  Until this is implemented,
+                declare only one of these, and let the address oracle
+                take care of the addresses.  -lxo */
+             if (name[1] != '2' && name[1] != '4')
+               {
+                 do_cleanups (back_to);
+                 continue;
+               }
+           }
+
+         instance->build_decl (kind, name,
+                               sym_kind | get_method_access_flag (type, i, j),
+                               method_type, NULL, address, filename, line);
+         do_cleanups (back_to);
+       }
+
+      do_cleanups (outer);
+    }
+}
+
+/* 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
+ccp_convert_struct_or_union (compile_cplus_instance *instance,
+                            struct type *type,
+                            enum gcc_cp_symbol_kind nested_access)
+{
+  const char *filename = NULL;  /* !!keiths: FIXME  */
+  unsigned short line = 0;
+  char *name = NULL;
+  struct cleanup *back_to = make_cleanup (free_current_contents, &name);
+
+  /* Get the decl name of this type.  */
+  if (TYPE_NAME (type) != NULL)
+      name = decl_name (TYPE_NAME (type));
+
+  /* First things first: If this type has any templates in it, make sure
+     that we collect default arguments and get those types defined BEFORE
+     this type is defined.  */
+  scan_type_for_function_templates (instance, type);
+
+  /* If this is a new template class, make sure the generic has been seen
+     and defined.  */
+  instance->maybe_define_new_class_template (type, name);
+  instance->emit_class_template_decls ();
+
+  /* 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; /* FIXME: yeah, it's a terrible pun.  Please make
+                     it go once we separate declaration from
+                     definition (see below).  -lxo */
+  if (TYPE_N_TEMPLATE_ARGUMENTS (type))
+    {
+      resuld = instance->build_class_template_specialization (type,
+                                                             filename, line);
+    }
+  else if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
+    {
+      const char *what = TYPE_DECLARED_CLASS (type) ? "struct" : "class";
+
+      resuld = instance->build_decl (what, name,
+                                    GCC_CP_SYMBOL_CLASS | nested_access
+                                    | (TYPE_DECLARED_CLASS (type)
+                                       ? GCC_CP_FLAG_CLASS_NOFLAG
+                                       : GCC_CP_FLAG_CLASS_IS_STRUCT),
+                                    0, NULL, 0, filename, line);
+    }
+  else
+    {
+      gdb_assert (TYPE_CODE (type) == TYPE_CODE_UNION);
+      resuld = instance->build_decl ("union", name,
+                                    GCC_CP_SYMBOL_UNION | nested_access,
+                                    0, NULL, 0, filename, line);
+    }
+
+  /* FIXME: we should be able to pop the scope at this point, rather
+     than at the end, and we ought to delay the rest of this function
+     to the point in which we need the class or union to be a complete
+     type, otherwise some well-formed C++ types cannot be represented.
+     -lxo */
+
+  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->start_class_type (name, resuld, &bases,
+                                          filename, line);
+      xfree (bases.flags);
+      xfree (bases.elements);
+    }
+  else
+    {
+      gdb_assert (TYPE_CODE (type) == TYPE_CODE_UNION);
+      result
+       = instance->start_class_type (name, resuld, NULL, filename, line);
+    }
+
+  instance->insert_type (type, result);
+
+  /* Add definitions.  */
+  ccp_convert_type_defns (instance, type);
+
+  /* Add methods.  */
+  ccp_convert_struct_or_union_methods (instance, type, result);
+
+  /* Add members.  */
+  ccp_convert_struct_or_union_members (instance, type, result);
+
+  /* All finished.  */
+  instance->finish_class_type (name, TYPE_LENGTH (type));
+
+  /* Pop all scopes.  */
+  instance->leave_scope ();
+  do_cleanups (back_to);
+  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
+ccp_convert_enum (compile_cplus_instance *instance, struct type *type,
+                 enum gcc_cp_symbol_kind nested_access)
+{
+  int i;
+  gcc_type int_type;
+  const char *filename = NULL;
+  unsigned short line = 0;
+  /* !!keiths: This does not appear to work. GCC complains about
+     being unable to convert enum values from '(MyEnum)0' to 'int'.  */
+  int scoped_enum_p = /*TYPE_DECLARED_CLASS (type) ? TRUE :*/ 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 ();
+    }
+
+  char *name = NULL;
+  struct cleanup *cleanups = make_cleanup (free_current_contents, &name);
+
+  if (TYPE_NAME (type) != NULL)
+    name = cp_func_name (TYPE_NAME (type));
+
+  /* Push all scopes.  */
+  instance->enter_scope (scope);
+
+  int_type = instance->get_int_type (TYPE_UNSIGNED (type),
+                                    TYPE_LENGTH (type), NULL);
+  gcc_type result
+    = instance->start_enum_type (name, int_type,
+                                GCC_CP_SYMBOL_ENUM | nested_access
+                                | (scoped_enum_p
+                                   ? GCC_CP_FLAG_ENUM_SCOPED
+                                   : GCC_CP_FLAG_ENUM_NOFLAG),
+                                filename, line);
+  for (i = 0; i < TYPE_NFIELDS (type); ++i)
+    {
+      char *fname = cp_func_name (TYPE_FIELD_NAME (type, i));
+
+      if (TYPE_FIELD_LOC_KIND (type, i) != FIELD_LOC_KIND_ENUMVAL
+         || fname == NULL)
+       {
+         xfree (fname);
+         continue;
+       }
+
+      instance->build_enum_constant (result, fname,
+                                    TYPE_FIELD_ENUMVAL (type, i));
+      xfree (fname);
+    }
+
+  instance->finish_enum_type (result);
+
+  /* Pop all scopes.  */
+  instance->leave_scope ();
+  do_cleanups (cleanups);
+  return result;
+}
+
+/* Convert a function type to its gcc representation.  This function does
+   not deal with function templates.  */
+
+static gcc_type
+ccp_convert_func (compile_cplus_instance *instance, struct type *type,
+                 int strip_artificial)
+{
+  int i, artificials;
+  gcc_type result, return_type;
+  struct gcc_type_array array;
+  int is_varargs = is_varargs_p (type);
+
+  /* This approach means we can't make self-referential function
+     types.  Those are impossible in C, though.  */
+  return_type = instance->convert_type (TYPE_TARGET_TYPE (type));
+
+  array.n_elements = TYPE_NFIELDS (type);
+  array.elements = XNEWVEC (gcc_type, TYPE_NFIELDS (type));
+  artificials = 0;
+  for (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));
+       }
+    }
+
+  /* FIXME: add default args, exception specs and, once support is
+     added, attributes.  -lxo */
+
+  /* We omit setting the argument types to `void' to be a little flexible
+     with some minsyms like printf (compile-cplus.exp has examples).  */
+  result = instance->build_function_type (return_type, &array, is_varargs);
+  xfree (array.elements);
+
+  return result;
+}
+
+/* Convert an integer type to its gcc representation.  */
+
+static gcc_type
+ccp_convert_int (compile_cplus_instance *instance, struct type *type)
+{
+  if (TYPE_NOSIGN (type))
+    {
+      gdb_assert (TYPE_LENGTH (type) == 1);
+      return instance->get_char_type ();
+    }
+
+  return instance->get_int_type (TYPE_UNSIGNED (type), TYPE_LENGTH (type),
+                                TYPE_NAME (type));
+}
+
+/* Convert a floating-point type to its gcc representation.  */
+
+static gcc_type
+ccp_convert_float (compile_cplus_instance *instance, struct type *type)
+{
+  return instance->get_float_type (TYPE_LENGTH (type), TYPE_NAME (type));
+}
+
+/* Convert the 'void' type to its gcc representation.  */
+
+static gcc_type
+ccp_convert_void (compile_cplus_instance *instance, struct type *type)
+{
+  return instance->get_void_type ();
+}
+
+/* Convert a boolean type to its gcc representation.  */
+
+static gcc_type
+ccp_convert_bool (compile_cplus_instance *instance, struct type *type)
+{
+  return instance->get_bool_type ();
+}
+
+/* See description in compile-cplus.h.  */
+
+gcc_type
+compile::convert_qualified_base (compile_cplus_instance *instance,
+                                gcc_type base,
+                                gcc_cp_qualifiers_flags quals)
+{
+  gcc_type result = base;
+
+  if (quals != 0)
+    result = instance->build_qualified_type (base, quals);
+
+  return result;
+}
+
+/* Convert a qualified type to its gcc representation.  */
+
+static gcc_type
+ccp_convert_qualified (compile_cplus_instance *instance,
+                      struct type *type)
+{
+  struct type *unqual = make_unqualified_type (type);
+  gcc_type unqual_converted;
+  gcc_cp_qualifiers_flags quals = (enum gcc_cp_qualifiers) 0;
+  gcc_type result;
+
+  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 convert_qualified_base (instance, unqual_converted, quals);
+}
+
+/* Convert a complex type to its gcc representation.  */
+
+static gcc_type
+ccp_convert_complex (compile_cplus_instance *instance,
+                    struct type *type)
+{
+  gcc_type base = instance->convert_type (TYPE_TARGET_TYPE (type));
+
+  return instance->build_complex_type (base);
+}
+
+/* Convert a namespace of TYPE.  */
+
+static gcc_type
+ccp_convert_namespace (compile_cplus_instance *instance,
+                      struct type *type)
+{
+  compile_scope scope = instance->new_scope (TYPE_NAME (type), type);
+
+
+  char *name = NULL;
+  struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
+  if (TYPE_NAME (type) != NULL)
+    {
+      name = cp_func_name (TYPE_NAME (type));
+      make_cleanup (xfree, name);
+    }
+  else
+    name = "";
+
+  /* Push scope.  */
+  instance->enter_scope (scope);
+
+  /* Convert this namespace.  */
+  instance->push_namespace (name);
+  instance->pop_binding_level (name);
+
+  /* Pop scope.  */
+  instance->leave_scope ();
+  do_cleanups (cleanups);
+
+  /* Namespaces are non-cacheable types.  */
+  return DONT_CACHE_TYPE;
+}
+
+/* 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)
+{
+  /* Reference types seem to always have a const qualifier, but we
+     don't want that to be propagated to the GCC type, because GCC
+     doesn't like the reference types themselves to be qualified.  */
+  if (TYPE_CODE (type) == TYPE_CODE_REF)
+    return ccp_convert_reference (instance, type);
+
+  /* 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 ccp_convert_qualified (instance, type);
+
+  switch (TYPE_CODE (type))
+    {
+#if 0
+    case TYPE_CODE_REF:
+      return ccp_convert_reference (instance, type);
+#endif
+
+    case TYPE_CODE_PTR:
+      return ccp_convert_pointer (instance, type);
+
+    case TYPE_CODE_ARRAY:
+      return ccp_convert_array (instance, type);
+
+    case TYPE_CODE_STRUCT:
+    case TYPE_CODE_UNION:
+      return ccp_convert_struct_or_union (instance, type, nested_access);
+
+    case TYPE_CODE_ENUM:
+      return ccp_convert_enum (instance, type, nested_access);
+
+    case TYPE_CODE_FUNC:
+      return ccp_convert_func (instance, type, 0);
+
+    case TYPE_CODE_METHOD:
+      return ccp_convert_method (instance, TYPE_SELF_TYPE (type), type);
+
+    case TYPE_CODE_MEMBERPTR:
+    case TYPE_CODE_METHODPTR:
+      return ccp_convert_memberptr (instance, type);
+      break;
+
+    case TYPE_CODE_INT:
+      return ccp_convert_int (instance, type);
+
+    case TYPE_CODE_FLT:
+      return ccp_convert_float (instance, type);
+
+    case TYPE_CODE_VOID:
+      return ccp_convert_void (instance, type);
+
+    case TYPE_CODE_BOOL:
+      return ccp_convert_bool (instance, type);
+
+    case TYPE_CODE_COMPLEX:
+      return ccp_convert_complex (instance, type);
+
+    case TYPE_CODE_NAMESPACE:
+      return ccp_convert_namespace (instance, type);
+
+    case TYPE_CODE_TYPEDEF:
+      return ccp_convert_typedef (instance, type, nested_access);
+    }
+
+  {
+    char *s = xstrprintf (_("unhandled TYPE_CODE_%s"),
+                         type_code_to_string (TYPE_CODE (type)));
+
+    return instance->error (s);
+    xfree (s);
+  }
+}
+
+gcc_type
+compile_cplus_instance::convert_type (struct type *type,
+                                     enum gcc_cp_symbol_kind nested_access)
+{
+  type_map_t::iterator pos = m_type_map.find (type);
+  if (pos != m_type_map.end ())
+    return pos->second;
+
+  gcc_type result = convert_type_cplus_basic (this, type, nested_access);
+  if (result != DONT_CACHE_TYPE)
+    insert_type (type, result);
+  return result;
+}
+
+\f
+
+/* Default compile flags for C++.  */
+
+const char *compile_cplus_instance::m_default_cflags = "-std=gnu++11";
+
+/* See compile-cplus.h.  */
+
+compile_cplus_instance::compile_cplus_instance (struct gcc_cp_context *gcc_fe)
+  : compile_instance (&gcc_fe->base, m_default_cflags),
+    m_context (gcc_fe),
+    m_function_template_defns (new function_template_defn_map_t ()),
+    m_class_template_defns (new class_template_defn_map_t ())
+{
+  gcc_fe->cp_ops->set_callbacks (gcc_fe, gcc_cplus_convert_symbol,
+                                gcc_cplus_symbol_address,
+                                gcc_cplus_enter_scope,
+                                gcc_cplus_leave_scope,
+                                this);
+}
+
+/* Plug-in forwards.  */
+
+/* A result printer for plug-in calls that return a boolean result.  */
+
+static void
+ccp_output_result (int result)
+{
+  printf_unfiltered ("%s\n", result ? "true" : "false");
+}
+
+/* A result printer for plug-in calls that return a gcc_type or
+   gcc_decl.  */
+
+static void
+ccp_output_result (gcc_type result)
+{
+  printf_unfiltered ("%lld\n", result);
+}
+
+#define STR(x) #x
+#define STRINGIFY(x) STR(x)
+
+#define DECLARE_FORWARD(OP,...)                                                \
+  auto forward = [&] (const char *fmt, ...)                            \
+  {                                                                    \
+    if (debug_compile_cplus_types)                                     \
+      {                                                                        \
+       std::string format (STRINGIFY (OP));                            \
+                                                                       \
+       format += " ";                                                  \
+       format += fmt;                                                  \
+       format += ": ";                                                 \
+                                                                       \
+       va_list args;                                                   \
+                                                                       \
+       va_start (args, fmt);                                           \
+       vprintf_unfiltered (format.c_str (), args);                     \
+       va_end (args);                                                  \
+      }                                                                        \
+                                                                       \
+    auto result = m_context->cp_ops->OP (m_context, ##__VA_ARGS__);    \
+                                                                       \
+    if (debug_compile_cplus_types)                                     \
+      ccp_output_result (result);                                      \
+                                                                       \
+    return result;                                                     \
+  };
+
+/* See description in gcc-cp-fe.def.  */
+
+bool
+compile_cplus_instance::build_constant (gcc_type type, const char *name,
+                                       unsigned long value,
+                                       const char *filename,
+                                       unsigned int line_number)
+{
+  DECLARE_FORWARD (build_constant, type, name, value, filename, line_number);
+
+  return forward ("\"%s\"", name);
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_decl
+compile_cplus_instance::build_function_template_specialization
+  (struct template_symbol *concrete, gcc_address address,
+   const char *filename, unsigned int line_number)
+{
+  function_template_defn *defn
+    = find_function_template_defn (concrete);
+
+  /* A generic should already have been defined at this point.  */
+  gdb_assert (defn != NULL);
+
+  struct gcc_cp_template_args targs;
+
+  targs.n_elements = concrete->template_arguments->n_arguments;
+  targs.kinds = XNEWVEC (char, targs.n_elements);
+
+  struct cleanup *back_to = make_cleanup (xfree, targs.kinds);
+
+  targs.elements = XNEWVEC (gcc_cp_template_arg, targs.n_elements);
+  make_cleanup (xfree, targs.elements);
+  enumerate_template_arguments (&targs, defn, concrete->template_arguments);
+
+  DECLARE_FORWARD (build_function_template_specialization, defn->decl (),
+                  &targs, address, filename, line_number);
+
+  gcc_decl result = forward ("%s", SYMBOL_NATURAL_NAME (&concrete->base));
+  do_cleanups (back_to);
+  return result;
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_decl
+compile_cplus_instance::build_class_template_specialization
+  (struct type *concrete, const char *filename, unsigned int line_number)
+{
+  class_template_defn *defn
+    = find_class_template_defn (concrete);
+
+  /* A generic should have already been defined at this point.  */
+  gdb_assert (defn != NULL);
+
+  struct gcc_cp_template_args targs;
+
+  targs.n_elements = TYPE_N_TEMPLATE_ARGUMENTS (concrete);
+  targs.kinds = XNEWVEC (char, targs.n_elements);
+
+  struct cleanup *back_to = make_cleanup (xfree, targs.kinds);
+
+  targs.elements = XNEWVEC (gcc_cp_template_arg, targs.n_elements);
+  make_cleanup (xfree, targs.elements);
+  enumerate_template_arguments (&targs, defn,
+                               TYPE_TEMPLATE_ARGUMENT_INFO (concrete));
+
+  DECLARE_FORWARD (build_class_template_specialization, defn->decl (), &targs,
+                  filename, line_number);
+
+  gcc_decl result
+    = forward ("%s for template decl %lld\n", TYPE_NAME (concrete),
+              defn->decl ());
+  do_cleanups (back_to);
+  return result;
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_decl
+compile_cplus_instance::build_decl (const char *decl_type,
+                                   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)
+{
+  DECLARE_FORWARD (build_decl, name, sym_kind, sym_type,
+                  substitution_name, address, filename, line_number);
+
+  return forward ("%s %s %d %s", decl_type, name, (int) sym_kind,
+                 substitution_name);
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+bool
+compile_cplus_instance::push_namespace (const char *name)
+{
+  DECLARE_FORWARD (push_namespace, name);
+
+  return forward ("\"%s\"", name);
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+bool
+compile_cplus_instance::pop_binding_level (const char *opt_name)
+{
+  DECLARE_FORWARD (pop_binding_level);
+
+  return forward ("\"%s\"", opt_name);
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_type
+compile_cplus_instance::error (const char *message)
+{
+  DECLARE_FORWARD (error, message);
+
+  return forward ("%s", message);
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+
+gcc_type
+compile_cplus_instance::build_reference_type (gcc_type base_type,
+                                             enum gcc_cp_ref_qualifiers rquals)
+{
+  DECLARE_FORWARD (build_reference_type, base_type, rquals);
+
+  return forward ("");
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_type
+compile_cplus_instance::build_pointer_type (gcc_type base_type)
+{
+  DECLARE_FORWARD (build_pointer_type, base_type);
+
+  return forward ("");
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_type
+compile_cplus_instance::build_vla_array_type (gcc_type element_type,
+                                             const char *upper_bound_name)
+{
+  DECLARE_FORWARD (build_vla_array_type, element_type, upper_bound_name);
+
+  return forward ("");
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_type
+compile_cplus_instance::build_vector_type (gcc_type element_type,
+                                          int num_elements)
+{
+  DECLARE_FORWARD (build_vector_type, element_type, num_elements);
+
+  return forward ("");
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_type
+compile_cplus_instance::build_array_type (gcc_type element_type,
+                                         int num_elements)
+{
+  DECLARE_FORWARD (build_array_type, element_type, num_elements);
+
+  return forward ("");
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_decl
+compile_cplus_instance::build_field (const char *field_name,
+                                    gcc_type field_type,
+                                    enum gcc_cp_symbol_kind field_flags,
+                                    unsigned long bitsize,
+                                    unsigned long bitpos)
+{
+  DECLARE_FORWARD (build_field, field_name, field_type, field_flags,
+                  bitsize, bitpos);
+
+  return forward ("%s %lld", field_name, field_type);
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_type
+compile_cplus_instance::build_method_type (gcc_type class_type,
+                                          gcc_type func_type,
+                                          enum gcc_cp_qualifiers quals,
+                                          enum gcc_cp_ref_qualifiers rquals)
+{
+  DECLARE_FORWARD (build_method_type, class_type, func_type, quals, rquals);
+
+  return forward ("");
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_type
+compile_cplus_instance::start_class_type
+  (const char *name, gcc_decl typedecl,
+   const struct gcc_vbase_array *base_classes,
+   const char *filename, unsigned int line_number)
+{
+  DECLARE_FORWARD (start_class_type, typedecl, base_classes,
+                  filename, line_number);
+
+  return forward ("%s", name);
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+bool
+compile_cplus_instance::finish_class_type (const char *name,
+                                          unsigned long size_in_bytes)
+{
+  DECLARE_FORWARD (finish_class_type, size_in_bytes);
+
+  return forward ("%s (%ld)", name, size_in_bytes);
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_type
+compile_cplus_instance::get_int_type (bool is_unsigned,
+                                     unsigned long size_in_bytes,
+                                     const char *builtin_name)
+{
+  DECLARE_FORWARD (get_int_type, is_unsigned, size_in_bytes, builtin_name);
+
+  return forward ("%d %ld %s", is_unsigned, size_in_bytes, builtin_name);
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_type
+compile_cplus_instance::start_enum_type (const char *name,
+                                        gcc_type underlying_int_type,
+                                        enum gcc_cp_symbol_kind flags,
+                                        const char *filename,
+                                        unsigned int line_number)
+{
+  DECLARE_FORWARD (start_enum_type, name, underlying_int_type,
+                  flags, filename, line_number);
+
+  return forward ("%s", name);
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_decl
+compile_cplus_instance::build_enum_constant (gcc_type enum_type,
+                                            const char *name,
+                                            unsigned long value)
+{
+  DECLARE_FORWARD (build_enum_constant, enum_type, name, value);
+
+  return forward ("%s = %ld", name, value);
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+bool
+compile_cplus_instance::finish_enum_type (gcc_type enum_type)
+{
+  DECLARE_FORWARD (finish_enum_type, enum_type);
+
+  return forward ("");
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_type
+compile_cplus_instance::build_function_type
+  (gcc_type return_type, const struct gcc_type_array *argument_types,
+   bool is_varargs)
+{
+  DECLARE_FORWARD (build_function_type, return_type, argument_types,
+                  is_varargs);
+
+  return forward ("%lld %d", return_type, is_varargs);
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_type
+compile_cplus_instance::get_char_type ()
+{
+  DECLARE_FORWARD (get_char_type);
+
+  return forward ("");
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_type
+compile_cplus_instance::get_float_type (unsigned long size_in_bytes,
+                                       const char *builtin_name)
+{
+  DECLARE_FORWARD (get_float_type, size_in_bytes, builtin_name);
+
+  return forward  ("%ld %s", size_in_bytes, builtin_name);
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_type
+compile_cplus_instance::get_void_type ()
+{
+  DECLARE_FORWARD (get_void_type);
+
+  return forward ("");
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_type
+compile_cplus_instance::get_bool_type ()
+{
+  DECLARE_FORWARD (get_bool_type);
+
+  return forward ("");
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_type
+compile_cplus_instance::build_qualified_type (gcc_type unqualified_type,
+                                             enum gcc_cp_qualifiers qualifiers)
+{
+  DECLARE_FORWARD (build_qualified_type, unqualified_type, qualifiers);
+
+  return forward ("");
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_type
+compile_cplus_instance::build_complex_type (gcc_type element_type)
+{
+  DECLARE_FORWARD (build_complex_type, element_type);
+
+  return forward ("%lld", element_type);
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_expr
+compile_cplus_instance::build_literal_expr (gcc_type type, unsigned long value)
+{
+  DECLARE_FORWARD (build_literal_expr, type, value);
+
+  return forward ("%lld %ld", type, value);
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_type
+compile_cplus_instance::build_type_template_parameter (const char *id,
+                                                      bool pack_p,
+                                                      gcc_type default_type,
+                                                      const char *filename,
+                                                      unsigned int line_number)
+{
+  DECLARE_FORWARD (build_type_template_parameter, id, pack_p,
+                  default_type, filename, line_number);
+
+  return forward ("%s %d %lld %s %d", id, pack_p, default_type,
+                 filename, line_number);
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_decl
+compile_cplus_instance::build_value_template_parameter
+  (gcc_type type, const char *id, gcc_expr default_value,
+   const char *filename, unsigned int line_number)
+{
+  DECLARE_FORWARD (build_value_template_parameter, type, id,
+                  default_value, filename, line_number);
+
+  return forward ("%lld %s %lld %s %d", type, id, default_value,
+                 filename, line_number);
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+bool
+compile_cplus_instance::start_template_decl (const char *generic)
+{
+  DECLARE_FORWARD (start_template_decl);
+
+  return forward ("for generic %s\n", generic);
+}
+
+/* See description in gcc-cp-fe.def.  */
+
+gcc_type
+compile_cplus_instance::build_pointer_to_member_type (gcc_type class_type,
+                                                     gcc_type member_type)
+{
+  DECLARE_FORWARD (build_pointer_to_member_type, class_type, member_type);
+
+  return forward ("%lld %lld", class_type, member_type);
+}
+
+#undef DECLARE_FORWARD
+
+void _initialize_compile_cplus_types (void);
+
+void
+_initialize_compile_cplus_types (void)
+{
+  add_setshow_boolean_cmd ("compile-cplus-types", no_class,
+                            &debug_compile_cplus_types, _("\
+Set debugging of C++ compile type conversion."), _("\
+Show debugging of C++ compile type conversion."), _("\
+When enabled debugging messages are printed during C++ type conversion for\n\
+the compile commands."),
+                            NULL,
+                            NULL,
+                            &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."),
+                            NULL,
+                            NULL,
+                            &setdebuglist,
+                            &showdebuglist);
+}
diff --git a/gdb/compile/compile-cplus.h b/gdb/compile/compile-cplus.h
new file mode 100644 (file)
index 0000000..2ab31fe
--- /dev/null
@@ -0,0 +1,399 @@
+/* Header file for GDB compile C++ language support.
+   Copyright (C) 2016, 2017 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef GDB_COMPILE_CPLUS_H
+#define GDB_COMPILE_CPLUS_H
+
+#include "gcc-cp-interface.h"
+#include "common/enum-flags.h"
+#include "compile-cplus-templates.h"
+
+#include <string>
+#include <memory>
+
+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);
+
+namespace compile
+{
+  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 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_fe);
+
+    /* If SYM is a template symbol whose generic we have not yet declared,
+       add it to INSTANCE's list of template definitions and scan for default
+       values.  */
+
+    void maybe_define_new_function_template (const struct symbol *sym,
+                                            struct type *parent_type,
+                                            int f_idx, int m_idx);
+
+    /* If TYPE (with declaration name DECL_NAME) represents a concrete instance
+       of a new class template, note the new template definition.  */
+
+    void maybe_define_new_class_template (struct type *type,
+                                         const char *decl_name);
+
+    /* Find the generic template definition for TSYM or NULL if none was
+       found.  */
+
+    function_template_defn *find_function_template_defn
+      (struct template_symbol *tsym);
+
+    /* Search for an existing class template definition based on TYPE.
+       Returns NULL if no template based on TYPE is known.  */
+
+    class_template_defn *find_class_template_defn (struct type *type);
+
+    /* Emit any new function template definitions to the compiler
+       plug-in.  */
+
+    void emit_function_template_decls ();
+
+    /* Emit any new class template definitions to the compiler
+       plug-in.  */
+
+    void emit_class_template_decls ();
+
+    /* 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);
+
+    /* 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 ();
+
+    /* Plug-in forwards  */
+
+    gcc_type get_bool_type ();
+
+    gcc_decl build_enum_constant (gcc_type enum_type, const char *name,
+                                 unsigned long value);
+
+    gcc_type build_array_type (gcc_type element_type, int num_elements);
+
+    bool build_constant (gcc_type type, const char *name, unsigned long value,
+                        const char *filename, unsigned int line_number);
+
+    gcc_type build_complex_type (gcc_type element_type);
+
+    gcc_type build_function_type (gcc_type return_type,
+                                 const struct gcc_type_array *argument_types,
+                                 bool is_varargs);
+
+    gcc_type build_method_type (gcc_type class_type, gcc_type func_type,
+                               enum gcc_cp_qualifiers quals,
+                               enum gcc_cp_ref_qualifiers rquals);
+
+    gcc_type build_qualified_type (gcc_type unqualified_type,
+                                  enum gcc_cp_qualifiers qualifiers);
+
+    gcc_type build_pointer_to_member_type (gcc_type class_type,
+                                          gcc_type member_type);
+
+    gcc_type build_pointer_type (gcc_type base_type);
+
+    gcc_type build_reference_type (gcc_type base_type,
+                                  enum gcc_cp_ref_qualifiers rquals);
+
+    gcc_type build_vla_array_type (gcc_type element_type,
+                                  const char *upper_bound_name);
+
+    gcc_type build_vector_type (gcc_type element_type, int num_elements);
+
+    gcc_type get_char_type ();
+
+    gcc_type error (const char *message);
+
+    bool finish_enum_type (gcc_type enum_type);
+
+    /* NAME is for debugging only.  */
+
+    bool finish_class_type (const char *name, unsigned long size_in_bytes);
+
+    gcc_type get_float_type (unsigned long size_in_bytes,
+                            const char *builtin_name);
+
+    gcc_type get_int_type (bool is_unsigned, unsigned long size_in_bytes,
+                      const char *builtin_name);
+
+    gcc_expr build_literal_expr (gcc_type type, unsigned long value);
+
+    /* DECL_DESC is for debugging only.  */
+
+    gcc_decl build_decl (const char *decl_desc, 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_decl build_field (const char *field_name, gcc_type field_type,
+                         enum gcc_cp_symbol_kind field_flags,
+                         unsigned long bitsize, unsigned long bitpos);
+
+    gcc_type build_type_template_parameter (const char *id, bool pack_p,
+                                           gcc_type default_type,
+                                           const char *filename,
+                                           unsigned int line_number);
+
+    gcc_decl build_value_template_parameter (gcc_type type, const char *id,
+                                            gcc_expr default_value,
+                                            const char *filename,
+                                            unsigned int line_number);
+
+    /* NAME is for debugging only.  */
+
+    bool pop_binding_level (const char *name);
+
+    bool push_namespace (const char *name);
+
+    gcc_decl build_class_template_specialization (struct type *concrete,
+                                                 const char *filename,
+                                                 unsigned int line_number);
+
+    gcc_decl build_function_template_specialization
+      (struct template_symbol *concrete, gcc_address address,
+       const char *filename, unsigned int line_number);
+
+    /* NAME is for debugging only.  */
+
+    gcc_type start_class_type (const char *name, gcc_decl typedecl,
+                              const struct gcc_vbase_array *base_classes,
+                              const char *filename,
+                              unsigned int line_number);
+
+    gcc_type start_enum_type (const char *name,
+                             gcc_type underlying_int_type,
+                             enum gcc_cp_symbol_kind flags,
+                             const char *filename,
+                             unsigned int line_number);
+
+    /* GENERIC is for debugging only.  */
+
+    bool start_template_decl (const char *generic);
+
+    gcc_type get_void_type ();
+
+
+  private:
+
+    /* Default compiler flags for C++.  */
+    static const char *m_default_cflags;
+
+    /* Enumerate the template arguments of template DEFN into DEST.  */
+
+    void enumerate_template_arguments
+      (struct gcc_cp_template_args *dest, const template_defn *defn,
+       const struct template_argument_info *arg_info);
+
+    /* The C++ compile plug-in context.  */
+    struct gcc_cp_context *m_context;
+
+    /* A cache of function template definitions.  */
+    std::unique_ptr<function_template_defn_map_t> m_function_template_defns;
+
+    /* A cache of class template definitions.  */
+    std::unique_ptr<class_template_defn_map_t> m_class_template_defns;
+
+    /* A list of scopes we are processing.  */
+    std::vector<compile_scope> m_scopes;
+  };
+
+  /* Return the declaration name of the natural name NATURAL.
+     This returns a name with no function arguments or template parameters.
+     The result must be freed by the caller.  */
+
+  char *decl_name (const char *natural);
+
+  /* Add the qualifiers given by QUALS to BASE.  */
+
+  gcc_type convert_qualified_base (compile_cplus_instance *instance,
+                                  gcc_type base,
+                                  gcc_cp_qualifiers_flags quals);
+
+  /* Convert TARGET into a pointer type in the given compiler
+     INSTANCE.  */
+
+  gcc_type convert_pointer_base (compile_cplus_instance *instance,
+                                gcc_type target);
+
+  /* Convert BASE into a reference type in the given compile
+     INSTANCE.  */
+
+  gcc_type convert_reference_base (compile_cplus_instance *instance,
+                                  gcc_type base);
+
+  /* Returns non-zero if the given TYPE represents a varargs function,
+     zero otherwise.  */
+
+  int is_varargs_p (const struct type *type);
+
+  /* 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);
+
+/* Maybe canonicalize FIELD_NAME with function field METHOD_FIELD (may
+   be NULL for non-constructors) and METHOD_TYPE (may not be NULL).
+
+   If the field is not represented by one of the plug-in's "special functions,"
+   (operators, ctors, dtors), return FIELD_NAME.
+
+   Otherwise return the unique plug-in identifier for the function.
+
+   If memory was allocated for the name (required by some function types),
+   it *OUTNAME will be set and should be used over the return value.  It
+   must subsequently be freed by the caller.
+
+   If the given method should be ignored (not defined to the plug-in),
+   IGNORE will be true.  */
+
+  const char *maybe_canonicalize_special_function
+    (const char *field_name, const struct fn_field *method_field,
+     const struct type *method_type, char **outname, bool *ignore);
+};
+
+/* A callback suitable for use as the GCC C++ symbol oracle.  */
+
+extern gcc_cp_oracle_function gcc_cplus_convert_symbol;
+
+/* A callback suitable for use as the GCC C++ address oracle.  */
+
+extern gcc_cp_symbol_address_function gcc_cplus_symbol_address;
+
+/* Callbacks suitable for use as the GCC C++ enter/leave scope requests.  */
+
+extern gcc_cp_enter_leave_user_expr_scope_function gcc_cplus_enter_scope;
+extern gcc_cp_enter_leave_user_expr_scope_function gcc_cplus_leave_scope;
+
+#endif /* GDB_COMPILE_CPLUS_H  */
index 292282e65501bd2bd907fd9864765c339104d894..71522827c685b0f3330da8e937d6e6f7140e7015 100644 (file)
 
 extern int compile_debug;
 
+/* Flag to enable internal debugging for oracle requests.  */
+
+extern int debug_compile_oracle;
+
 struct block;
 
 namespace compile
index 473e664abadc17c6ac72c3973f9ed2b25997d3dc..8dbc7547afa133ba7eee51427c32c8cc4d951f6a 100644 (file)
@@ -460,7 +460,7 @@ 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;
     }
@@ -742,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,
index b9a3d3419f939d115a21d40c00ee8c77e96db8fb..a0a5d73de87c3b7f5437324f8dffa91a89ff44ae 100644 (file)
@@ -917,7 +917,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/testsuite/gdb.compile/compile-cplus-mod.c b/gdb/testsuite/gdb.compile/compile-cplus-mod.c
new file mode 100644 (file)
index 0000000..8b7c755
--- /dev/null
@@ -0,0 +1,28 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2014-2015 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+extern "C" void
+_gdb_expr (void)
+{
+  // Make 'globalvar' lookup working.
+#pragma GCC push_user_expression
+
+  globalvar = 3;
+  globalvar += 4;
+
+#pragma GCC pop_user_expression
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-print.c b/gdb/testsuite/gdb.compile/compile-cplus-print.c
new file mode 100644 (file)
index 0000000..2635d16
--- /dev/null
@@ -0,0 +1,32 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2015-2016 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+
+int varint = 10;
+int vararray[] = { 1, 2, 3, 4, 5 };
+int *vararrayp = vararray;
+struct object
+{
+  int field;
+} varobject = { 1 };
+
+int
+main (void)
+{
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-print.exp b/gdb/testsuite/gdb.compile/compile-cplus-print.exp
new file mode 100644 (file)
index 0000000..cb453a4
--- /dev/null
@@ -0,0 +1,75 @@
+# Copyright 2015-2016 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+load_lib compile-support.exp
+
+standard_testfile
+
+get_compiler_info
+set options {}
+if [test_compiler_info gcc*] {
+    lappend options additional_flags=-g3
+    lappend options additional_flags=-std=gnu++11
+    lappend options c++
+}
+
+set srcfilesoptions [list ${srcfile} ${options}]
+
+if { [eval build_executable_from_specs ${testfile}.exp $testfile {$options} ${srcfilesoptions}] } {
+    return -1
+}
+
+clean_restart ${testfile}
+
+if {[skip_compile_feature_tests]} {
+    untested "compile command not supported (could not find libcc1 shared library?)"
+    return -1
+}
+
+gdb_test_no_output "set language c++" \
+    "Set language to C++"
+
+if ![runto_main] {
+    return -1
+}
+
+gdb_test "compile print varint" " = 10"
+gdb_test "compile print vararray" " = \\{1, 2, 3, 4, 5\\}"
+gdb_test "compile print main" " = \\{int \\(void\\)\\} 0x\[0-9a-f\]+"
+
+set test "compile print *vararray@3"
+gdb_test_multiple $test $test {
+    -re " = \\{1, 2, 3\\}\r\n$gdb_prompt $" {
+       pass $test
+    }
+    -re ": error: stray '@' in program\r\n.*\r\n$gdb_prompt $" {
+       kfail compile/18489 "$test"
+    }
+}
+
+set test "compile print *vararrayp@3"
+gdb_test_multiple $test $test {
+    -re " = \\{1, 2, 3\\}\r\n$gdb_prompt $" {
+       pass $test
+    }
+    -re ": error: stray '@' in program\r\n.*\r\n$gdb_prompt $" {
+       kfail compile/18489 "$test"
+    }
+}
+
+gdb_test "compile print/x 256" " = 0x100"
+gdb_test {print $} " = 256"
+
+gdb_test "compile print varobject" { = {field = 1}}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus.c b/gdb/testsuite/gdb.compile/compile-cplus.c
new file mode 100644 (file)
index 0000000..3ba46ce
--- /dev/null
@@ -0,0 +1,241 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2014-2017 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdbool.h>
+#include <iostream>
+
+#define SOME_MACRO 23
+#define ARG_MACRO(X, Y) ((X) + (Y) - 1)
+
+
+enum enum_type {
+  ONE = 1,
+  TWO = 2
+};
+
+typedef int v4 __attribute__ ((vector_size (16)));
+
+union union_type;
+
+struct struct_type {
+  char charfield;
+  unsigned char ucharfield;
+  short shortfield;
+  unsigned short ushortfield;
+  int intfield;
+  unsigned int uintfield;
+  unsigned int bitfield : 3;
+  long longfield;
+  unsigned long ulongfield;
+  enum enum_type enumfield;
+  float floatfield;
+  double doublefield;
+  const union union_type *ptrfield;
+  struct struct_type *selffield;
+  int arrayfield[5];
+  _Complex double complexfield;
+  _Bool boolfield;
+  v4 vectorfield;
+};
+
+typedef int inttypedef;
+
+union union_type {
+  int intfield;
+  inttypedef typedeffield;
+};
+
+/* volatile provides some coverage of the conversion code.  */
+volatile struct struct_type struct_object;
+
+union union_type union_object;
+
+
+enum ulonger_enum_type {
+  REALLY_MINUS_1 = -1UL,
+};
+
+enum ulonger_enum_type ulonger;
+
+enum longer_enum_type {
+  MINUS_1 = -1,
+  FORCE_TO_LONG = 1L << ((8 * sizeof (long)) - 2)
+};
+
+enum longer_enum_type longer;
+
+int globalvar = 10;
+
+static void
+func_static (int addend)
+{
+  globalvar += addend;
+}
+
+void
+func_global (int subtrahend)
+{
+  globalvar -= subtrahend;
+}
+
+void
+no_args_or_locals (void)
+{
+  /* no_args_or_locals breakpoint */
+}
+
+int *intptr;
+int globalshadow = 10;
+static int staticshadow = 20;
+int externed = 7;
+
+class Base
+{
+  virtual int pure_virt () = 0;
+ public:
+  int return_value () {return a;}
+ private:
+  int a = 1;
+  int b = 2;
+};
+
+class Base2
+{
+  virtual int non_pure () {return 84;}
+ public:
+  int return_value () {return b;}
+ private:
+  int a = 3;
+  int b = 4;
+};
+
+class Base3
+{
+ public:
+  int return_value () {return b;}
+ private:
+  int b = 5;
+};
+
+
+class Multiple : public Base, public Base2
+{
+  int pure_virt ()
+  {
+    int a = Base::return_value ();
+    return a + 42;
+  }
+};
+//struct foo { foo(); virtual ~foo(); }; struct bar : virtual foo { bar(); ~bar(); }; struct baz : bar {}; bar::bar() {} bar::~bar() {} bar t; baz u;
+struct VirtualOnly
+{
+  VirtualOnly();
+  virtual ~VirtualOnly()=0;
+};
+
+VirtualOnly::VirtualOnly ()
+{
+}
+
+VirtualOnly::~VirtualOnly ()
+{
+}
+
+struct VirtualBase : virtual VirtualOnly
+{
+  int z = 22;
+  VirtualBase (void);
+  ~VirtualBase (void);
+};
+
+struct VirtualBase2 : VirtualBase {};
+
+VirtualBase::VirtualBase (void)
+{
+  z = 24;
+}
+
+VirtualBase::~VirtualBase (void)
+{
+  z = 22;
+}
+
+class Foo
+{
+  int var;
+  static const int public_static_var = 12;
+
+ private:
+  int private_var = 0;
+  int private_method (void);
+
+ public:
+  int public_var = 0;
+  int public_method (void);
+  void set_private_var (int);
+};
+
+void Foo::set_private_var (int i)
+{
+  private_var = i;
+}
+
+int Foo::private_method (void)
+{
+  return private_var;
+}
+
+int Foo::public_method (void)
+{
+  return public_var;
+}
+
+int
+main (void)
+{
+  int localvar = 50;
+  int shadowed = 51;
+  int bound = 3;
+  int unresolved = 10;
+  int globalshadow = 100;
+  int staticshadow = 200;
+  int externed = 9;
+  int f = 0;
+  int var = 0;
+  Foo foovar;
+  Multiple *multivar = new Multiple;
+  VirtualBase vbase;
+  VirtualBase2 vbase2;
+  static int static_local = 77000;
+
+  foovar.public_var = 42;
+  foovar.set_private_var (42);
+  multivar->Base2::return_value();
+  {
+    int another_local = 7;
+    int shadowed = 52;
+    extern int unresolved;
+    extern int externed;
+
+    int vla[bound];
+
+    func_static (0); /* break-here */
+    no_args_or_locals ();
+  }
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus.exp b/gdb/testsuite/gdb.compile/compile-cplus.exp
new file mode 100644 (file)
index 0000000..04849ba
--- /dev/null
@@ -0,0 +1,341 @@
+# Copyright 2014-2017 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+load_lib compile-support.exp
+
+standard_testfile .c compile-shlib.c compile-constvar.S compile-nodebug.c
+
+get_compiler_info
+set options {}
+if [test_compiler_info gcc*] {
+    lappend options additional_flags=-g3
+    lappend options additional_flags=-std=gnu++11
+    lappend options c++
+}
+
+if { ![istarget x86_64-*-* ] || ![is_lp64_target] } {
+    verbose "Skipping x86_64 LOC_CONST test."
+    set srcfile3 ""
+}
+
+set srcfilesoptions [list ${srcfile} ${options}]
+if { $srcfile3 != "" } {
+    lappend srcfilesoptions $srcfile3 ${options}
+}
+lappend srcfilesoptions $srcfile4 "nodebug c++"
+if { [eval build_executable_from_specs ${testfile}.exp $testfile {$options} ${srcfilesoptions}] } {
+    return -1
+}
+
+clean_restart ${testfile}
+
+#
+# FIXME: Right now, for C++ we just duplicate the C tests, but force
+# the language to  C++
+#
+gdb_test_no_output "set language c++" \
+    "Set language to C++"
+
+if ![runto_main] {
+    return -1
+}
+
+if {[skip_compile_feature_tests]} {
+    untested "compile command not supported (could not find libcc1 shared library?)"
+    return -1
+}
+
+#
+# Test delimiter for code, and arguments.
+#
+
+
+gdb_test_no_output "compile code globalvar = SOME_MACRO;" \
+    "set variable from macro"
+gdb_test "p globalvar" " = 23" "expect 23"
+
+gdb_test_no_output "compile code globalvar = ARG_MACRO(0, 0);" \
+    "set variable from function-like macro"
+gdb_test "p globalvar" " = -1" "expect -1"
+
+gdb_test_no_output "compile code globalvar = 42;" "set variable"
+gdb_test "p globalvar" " = 42" "expect 42"
+
+gdb_test_no_output "compile code globalvar *= 2;" "modify variable"
+gdb_test "p globalvar" " = 84" "expect 84"
+
+gdb_test_no_output "compile file -r ${srcdir}/${subdir}/${testfile}-mod.c" \
+    "use external source file"
+gdb_test "p globalvar" " = 7" "expect 7"
+
+gdb_test_no_output "compile code func_static (2);" "call static function"
+gdb_test "p globalvar" " = 9" "expect 9"
+gdb_test_no_output "compile code func_global (1);" "call global function"
+gdb_test "p globalvar" " = 8" "expect 8"
+
+gdb_test_no_output \
+    "compile code globalvar = (sizeof (ulonger) == sizeof (long))" \
+    "compute size of ulonger"
+gdb_test "p globalvar" " = 1" "check size of ulonger"
+gdb_test_no_output \
+    "compile code globalvar = (sizeof (longer) == sizeof (long))" \
+    "compute size of longer"
+gdb_test "p globalvar" " = 1" "check size of longer"
+gdb_test_no_output "compile code globalvar = MINUS_1"
+gdb_test "p globalvar" " = -1" "check MINUS_1"
+
+gdb_test_no_output "compile code globalvar = static_local"
+gdb_test "p globalvar" " = 77000" "check static_local"
+
+gdb_test_no_output \
+    "compile code static int staticvar = 5; intptr = &staticvar" \
+    "do not keep jit in memory"
+gdb_test "p *intptr" "Cannot access memory at address 0x\[0-9a-f\]+" \
+    "expect 5"
+
+gdb_test "compile code func_doesnotexist ();" "error: \'func_doesnotexist\' was not declared in this scope.*"
+
+gdb_test "compile code *(volatile int *) 0 = 0;" \
+    "The program being debugged was signaled while in a function called from GDB\\.\r\nGDB remains in the frame where the signal was received\\.\r\n.*" \
+    "compile code segfault first"
+gdb_test "bt" \
+    "\r\n#0  \[^\r\n\]* in _gdb_expr \[^\r\n\]*\r\n#1  <function called from gdb>\r\n.*"
+
+set test "p/x \$pc"
+set infcall_pc 0
+gdb_test_multiple $test $test {
+    -re " = (0x\[0-9a-f\]+)\r\n$gdb_prompt $" {
+       set infcall_pc $expect_out(1,string)
+       pass $test
+    }
+}
+
+gdb_test "info sym $infcall_pc" "\r\n_gdb_expr.*" "info sym found"
+gdb_test "return" "\r\n#0  main .*" "return" \
+        "Make _gdb_expr\\(__gdb_regs\\*\\) return now\\? \\(y or n\\) " "y"
+gdb_test "info sym $infcall_pc" "\r\nNo symbol matches .*" "info sym not found"
+
+gdb_test_no_output "set unwindonsignal on"
+gdb_test "compile code *(volatile int *) 0 = 0;" \
+    "The program being debugged was signaled while in a function called from GDB\\.\r\nGDB has restored the context to what it was before the call\\.\r\n.*" \
+    "compile code segfault second"
+
+gdb_breakpoint [gdb_get_line_number "break-here"]
+gdb_continue_to_breakpoint "break-here" ".* break-here .*"
+
+# C++ Specific tests.
+## Public methods and members
+
+gdb_test "print foovar.public_var" "42" \
+    "Test compile code foovar.public_var = 42 setting."
+gdb_test_no_output "compile code foovar.public_var = 43;" \
+    "set foobar.public_var to 43"
+gdb_test "print foovar.public_var" "43" \
+    "Test compile code foovar.public_var = 43 setting."
+gdb_test "print foovar.public_method ()" "43" \
+    "Test compile code foovar.public_method  = 43 setting."
+
+## Private methods and members
+gdb_test_no_output "compile code foovar.set_private_var (84);" \
+    "Call class function to set private_var"
+gdb_test "print foovar.private_var" "84" \
+    "Test compile code foovar.set_private_var = 84 setting."
+gdb_test_no_output "compile code foovar.private_var = 85"  \
+    "Directly set a private member in GDB compile5"
+gdb_test "print foovar.private_var" "85" \
+    "Test compile code foovar.set_private_var = 85 setting."
+
+## Simple inheritance
+CompileExpression::new "var"
+CompileExpression::test "class Baz: public Foo {public: int z = 12;}; Baz bazvar; bazvar.z = 24; var = bazvar.z" 24 -explicit
+## Multiple inheritance
+CompileExpression::test "class MI: public Base, public Base2 {int pure_virt () {return 42;}}; MI MIVar; var = MIVar.pure_virt();" 42 -explicit
+CompileExpression::test "class MI: public Base, public Base2 {int pure_virt () {return Base::return_value() + 42;}}; MI MIVar; var =  MIVar.pure_virt();" 43 -explicit
+CompileExpression::test "class Base3 {public: int z = 99;}; class MI: public Base, public Base3 {int pure_virt () {return Base3::z + 42;}}; MI MIVar; var = MIVar.pure_virt();" 141 -explicit
+
+gdb_test "p localvar" " = 50" "expect localvar 50"
+
+gdb_test_no_output "compile code localvar = 12;" "set localvar"
+gdb_test "p localvar" " = 12" "expect 12"
+
+gdb_test_no_output "compile code localvar *= 2;" "modify localvar"
+gdb_test "p localvar" " = 24" "expect 24"
+
+gdb_test_no_output "compile code localvar = shadowed" \
+    "test shadowing"
+gdb_test "p localvar" " = 52" "expect 52"
+
+gdb_test_no_output "compile code localvar = externed"
+gdb_test "p localvar" " = 7" "test extern in inner scope"
+
+gdb_test_no_output "compile code vla\[2\] = 7"
+gdb_test "p vla\[2\]" " = 7"
+gdb_test_no_output \
+    "compile code localvar = (sizeof (vla) == bound * sizeof (vla\[0\]))"
+gdb_test "p localvar" " = 1"
+
+#
+# Test setting fields and also many different types.
+#
+
+gdb_test_no_output "compile code struct_object.selffield = (struct_type*)&struct_object"
+gdb_test "print struct_object.selffield == &struct_object" " = true"
+
+gdb_test_no_output "compile code struct_object.charfield = 1"
+gdb_test "print struct_object.charfield" " = 1 '\\\\001'"
+gdb_test_no_output "compile code struct_object.ucharfield = 1"
+gdb_test "print struct_object.ucharfield" " = 1 '\\\\001'"
+
+foreach {field value} {
+    shortfield -5
+    ushortfield 5
+    intfield -7
+    uintfield 7
+    bitfield 2
+    longfield -9
+    ulongfield 9
+    enumfield ONE
+    floatfield 1
+    doublefield 2
+} {
+    gdb_test_no_output "compile code struct_object.$field = $value"
+    gdb_test "print struct_object.$field" " = $value"
+}
+
+gdb_test_no_output "compile code struct_object.arrayfield\[2\] = 7"
+gdb_test "print struct_object.arrayfield" \
+    " = \\{0, 0, 7, 0, 0\\}"
+
+gdb_test_no_output "compile code struct_object.complexfield = 7 + 5i"
+gdb_test "print struct_object.complexfield" " = 7 \\+ 5 \\* I"
+
+gdb_test_no_output "compile code struct_object.boolfield = 1"
+gdb_test "print struct_object.boolfield" " = true"
+
+gdb_test_no_output "compile code struct_object.vectorfield\[2\] = 7"
+gdb_test "print struct_object.vectorfield" \
+    " = \\{0, 0, 7, 0\\}"
+
+gdb_test_no_output "compile code union_object.typedeffield = 7"
+gdb_test "print union_object.typedeffield" " = 7"
+gdb_test "print union_object.intfield" " = 7"
+
+
+# LOC_UNRESOLVED tests.
+
+gdb_test "print unresolved" " = 20"
+gdb_test "compile code globalvar = unresolved;"
+gdb_test "print globalvar" " = 20" "print unresolved value"
+
+# Test shadowing with global and static variables.
+
+gdb_test_no_output "compile code globalshadow += 1;"
+gdb_test "print globalshadow" " = 101"
+gdb_test_no_output "compile code extern int globalshadow; globalshadow += 5;"
+gdb_test "print 'compile-cplus.c'::globalshadow" " = 15"
+gdb_test "print globalshadow" " = 101" "print globalshadow second time"
+gdb_test_no_output "compile code staticshadow += 2;"
+gdb_test "print staticshadow" " = 202"
+# "extern int staticshadow;" cannot access static variable.
+
+# Raw code cannot refer to locals.
+# As it references global variable we need the #pragma.
+# For #pragma we need multiline input.
+gdb_test_multiple "compile code -r" "compile code -r multiline 1" { -re "\r\n>$" {} }
+gdb_test_multiple "void _gdb_expr(void) {" "compile code -r multiline 2" { -re "\r\n>$" {} }
+gdb_test_multiple "#pragma GCC push_user_expression" "compile code -r multiline 3" { -re "\r\n>$" {} }
+gdb_test_multiple "  globalshadow = 77000;" "compile code -r multiline 4" { -re "\r\n>$" {} }
+gdb_test_multiple "#pragma GCC pop_user_expression" "compile code -r multiline 5" { -re "\r\n>$" {} }
+gdb_test_multiple "}" "compile code -r multiline 6" { -re "\r\n>$" {} }
+gdb_test_no_output "end" "compile code -r multiline 7"
+gdb_test "print 'compile-cplus.c'::globalshadow" " = 77000" \
+    "check globalshadow with -r"
+
+# Test GOT vs. resolving jit function pointers.
+
+gdb_test_no_output "compile -raw -- extern \"C\" void abort(); int func(){return 21;} void _gdb_expr(){int (*funcp)()=func; if (funcp()!=21) abort();}" \
+    "pointer to jit function"
+
+#
+# Test the case where the registers structure would not normally have
+# any fields.
+#
+
+gdb_breakpoint [gdb_get_line_number "no_args_or_locals breakpoint"]
+gdb_continue_to_breakpoint "no_args_or_locals"
+
+gdb_test_no_output "compile code globalvar = 77;" "set variable to 77"
+gdb_test "p globalvar" " = 77" "expect 77"
+
+
+# Test reference to minimal_symbol, not (full) symbol.
+
+gdb_test_no_output "compile code globalvar = func_nodebug (75);" \
+    "call func_nodebug"
+gdb_test "p globalvar" " = -75" "expect -75"
+gdb_test_no_output \
+  "compile code int (*funcp) (int) = (int(*)(int))func_nodebug; globalvar = funcp (76);" \
+  "call func_nodebug indirectly"
+gdb_test "p globalvar" " = -76" "expect -76"
+
+
+# Test compiled module memory protection.
+
+gdb_test_no_output "set debug compile on"
+gdb_test "compile code static const int readonly = 1; *(int *) &readonly = 2;" \
+    "The program being debugged was signaled while in a function called from GDB\\.\r\nGDB has restored the context to what it was before the call\\.\r\n.*"
+gdb_test_no_output "set debug compile off"
+
+
+#
+# Some simple coverage tests.
+#
+
+gdb_test "show debug compile" "Compile debugging is .*"
+gdb_test "show compile-args" \
+    "Compile command command-line arguments are .*"
+gdb_test "compile code -z" "Unknown argument.*"
+
+gdb_test "set lang rust" \
+    "Warning: the current language does not match this frame."
+gdb_test "compile code globalvar" "No compiler support for language rust\."
+gdb_test_no_output "set lang auto"
+
+gdb_test_no_output "compile code union union_type newdecl_u"
+gdb_test_no_output "compile code struct struct_type newdecl_s"
+gdb_test_no_output "compile code inttypedef newdecl_i"
+
+gdb_test "compile file" \
+    "You must provide a filename for this command.*" \
+    "Test compile file without a filename"
+gdb_test "compile file -r" \
+    "You must provide a filename with the raw option set.*" \
+    "Test compile file and raw option without a filename"
+gdb_test "compile file -z" \
+    "Unknown argument.*" \
+    "Test compile file with unknown argument"
+
+
+# LOC_CONST tests.
+
+if { $srcfile3 != "" } {
+    gdb_test "p constvar" " = 3"
+    gdb_test "info addr constvar" {Symbol "constvar" is constant\.}
+
+    gdb_test "compile code globalvar = constvar;"
+    gdb_test "print globalvar" " = 3" "print constvar value"
+} else {
+    untested "print constvar value"
+}
diff --git a/gdb/testsuite/gdb.compile/cp-namespace-template.cc b/gdb/testsuite/gdb.compile/cp-namespace-template.cc
new file mode 100644 (file)
index 0000000..18bbab4
--- /dev/null
@@ -0,0 +1,138 @@
+/* Copyright 2016-2017 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+namespace N1
+{
+  namespace N2
+  {
+    template <typename T, int V>
+    T mytemplate (int a)
+    {
+      return static_cast<T> (a) + V;
+    }
+
+    template <typename T, int V>
+    T mytemplate (void)
+    {
+      return -V;
+    }
+
+    template <int V = 100>
+    int mytemplate (void)
+    {
+      return V;
+    }
+
+    struct A
+    {
+      A (int val) : value (val) { }
+      operator int () const { return value; }
+
+      template <typename T = A>
+      T tempmethod (void)
+      {
+       return value;
+      }
+
+      template <typename T = A, int V = -1>
+      static T stempmethod (void)
+      {
+       return V;
+      }
+
+      template <typename T = A, int V = -2>
+      static T stempmethod (T arg)
+      {
+       return arg + V;
+      }
+
+      int value;
+    };
+
+    template<>
+    int
+    A::tempmethod (void)
+    {
+      return -value;
+    }
+
+    // A handful of operator templates
+    struct O
+    {
+      O (int v) : v_ (v) { }
+
+      template <typename T>
+      operator T (void) { return -v_; }
+
+      template <typename T>
+      O operator+ (T val)
+      {
+       return v_ + val;
+      }
+
+      int v_;
+    };
+
+    // A simple class template
+    template <typename T1 = O, typename T2 = int, int V = 3>
+    class classt
+    {
+    public:
+      classt (T1 v) : val1_ (v), val2_ (107) { }
+      T1 get1 (void) const { return val1_; }
+      T2 get2 (void) const { return val2_; }
+      int get3 (void) const { return V; }
+
+    private:
+      T1 val1_;
+      T2 val2_;
+    };
+  };
+};
+
+int
+main (void)
+{
+  using namespace N1::N2;
+
+  A a (20);
+  O o (30);
+  int var = 0xdeadbeef;
+  int i = 1;
+  const int j = 1;
+  int* pi = &i;
+  int const* const cpci = &j;
+  int *const cpi = &i;
+
+  int o_val = o + 30;
+
+  classt<> cddd (o);
+  classt<int> cdd (100);
+  classt<int, char> cd (101);
+  classt<int, char, 12> c (102);
+  int cvals = cddd.get1 () + cddd.get2 () + cddd.get3 ();
+  cvals += cdd.get1 () + cdd.get2 () + cdd.get3 ();
+  cvals += cd.get1 () + cd.get2 () + cd.get3 ();
+  cvals += c.get1 () + c.get2 () + c.get3 ();
+
+  return mytemplate<int, 1> (0)
+    + mytemplate<int, 1> ()
+    + mytemplate<0> ()
+    + mytemplate ()
+    + a.tempmethod ()
+    + a.tempmethod<int> ()
+    + A::stempmethod ()
+    + A::stempmethod (0); // break here
+}
diff --git a/gdb/testsuite/gdb.compile/cp-namespace-template.exp b/gdb/testsuite/gdb.compile/cp-namespace-template.exp
new file mode 100644 (file)
index 0000000..19eabe9
--- /dev/null
@@ -0,0 +1,67 @@
+# Copyright 2016-2017 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Namespace-qualified template tests.
+
+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]} {
+    return -1
+}
+
+if {[skip_compile_feature_tests]} {
+    untested \
+       "compile command not supported (could not find libcc1 shared library?)"
+    return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+CompileExpression::new "var"
+CompileExpression::test "N1::N2::mytemplate<int, 1> ()" -1
+CompileExpression::test "N1::N2::mytemplate<int, 1> (1)" 2
+CompileExpression::test "N1::N2::mytemplate<0> ()" 0
+CompileExpression::test "N1::N2::mytemplate ()" 100
+CompileExpression::test "a.tempmethod ()" {(20|{value = 20})} \
+    -print {xfail *-*-* gcc/debug/49348} \
+    -value {xfail *-*-* gcc/debug/49348}
+CompileExpression::test "a.tempmethod<N1::N2::A> ()" {(20|{value = 20})}
+CompileExpression::test "a.tempmethod<int> ()" -20
+CompileExpression::test "o + 3" {(-33|{v_ = 33})}
+CompileExpression::test "cddd.get1 ()" {(-30|{v_ = 30})}
+CompileExpression::test "cddd.get2 ()" 107
+CompileExpression::test "cddd.get3 ()" 3
+CompileExpression::test "cdd.get1 ()" 100
+CompileExpression::test "cdd.get2 ()" 107
+CompileExpression::test "cdd.get3 ()" 3
+CompileExpression::test "cd.get1 ()" 101
+CompileExpression::test "cd.get2 ()" {107( 'k')?}
+CompileExpression::test "cd.get3 ()" 3
+CompileExpression::test "c.get1 ()" 102
+CompileExpression::test "c.get2 ()" {107( 'k')?}
+CompileExpression::test "c.get3 ()" 12
diff --git a/gdb/testsuite/gdb.compile/cp-simple-anonymous.cc b/gdb/testsuite/gdb.compile/cp-simple-anonymous.cc
new file mode 100644 (file)
index 0000000..19b9fc8
--- /dev/null
@@ -0,0 +1,65 @@
+/* Copyright 2015 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 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;
+} anon_s = {"abracadabra", 11};
+
+struct A
+{
+  A (void) : e (AA)
+  {
+    this->u.b = 0;
+    this->s.ptr = "hello";
+    this->s.len = 5;
+  }
+
+  enum {AA = 10, BB, CC, DD} e;
+  union
+  {
+    char a;
+    int b;
+    float f;
+    double d;
+    void *p;
+  } u;
+  struct
+  {
+    char *ptr;
+    int len;
+  } s;
+};
+
+int
+main (void)
+{
+  A a;
+  int var = 1234;
+
+  return a.u.b + a.s.len + static_cast<int> (a.e)
+    + static_cast<int> (anon_e) + anon_u.bb + anon_s.len; // break here
+}
diff --git a/gdb/testsuite/gdb.compile/cp-simple-anonymous.exp b/gdb/testsuite/gdb.compile/cp-simple-anonymous.exp
new file mode 100644 (file)
index 0000000..094c07b
--- /dev/null
@@ -0,0 +1,55 @@
+# Copyright 2015-2016 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/>.
+
+# (Very) simple method tests.
+
+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]} {
+    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 "anon_s.len" 11
+CompileExpression::test "a.u.b" 0
+CompileExpression::test "a.s.len" 5
+CompileExpression::test "a.e" {(10|A::AA)}
+CompileExpression::test "(*anon_s.ptr == 'a')" (1|true)
+CompileExpression::test "(*a.s.ptr != 'h')" (0|false)
+CompileExpression::test "A::BB" {(11|A::BB)}
diff --git a/gdb/testsuite/gdb.compile/cp-simple-inherit.cc b/gdb/testsuite/gdb.compile/cp-simple-inherit.cc
new file mode 100644 (file)
index 0000000..3e445df
--- /dev/null
@@ -0,0 +1,58 @@
+/* Copyright 2015 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+struct A
+{
+  A () : a_ (1) {}
+  int do_it (int amount) { return a_ + amount; }
+
+  int a_;
+};
+
+struct B
+{
+  B () : b_ (2) {}
+  int do_it (int amount) { return b_ - amount; }
+
+  int b_;
+};
+
+struct C
+{
+  C () : c_ (3) {}
+  int do_it (int amount) { return c_ * amount; }
+
+  int c_;
+};
+
+struct D : public A, B, C
+{
+  D () : d_ (4) {}
+
+  int d_;
+};
+
+int
+main (void)
+{
+  D d;
+  int var = 1234;
+
+  var = d.A::do_it (1)
+    + d.B::do_it (2)
+    + d.C::do_it (3);          // break here
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.compile/cp-simple-inherit.exp b/gdb/testsuite/gdb.compile/cp-simple-inherit.exp
new file mode 100644 (file)
index 0000000..64c8906
--- /dev/null
@@ -0,0 +1,52 @@
+# Copyright 2015, 2016, 2017 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# (Very) simple inheritance tests.
+
+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]} {
+    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/cp-simple-member.cc b/gdb/testsuite/gdb.compile/cp-simple-member.cc
new file mode 100644 (file)
index 0000000..9278088
--- /dev/null
@@ -0,0 +1,83 @@
+/* Copyright 2015 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+class A;
+static int get_values (const A& a);
+
+enum myenum {E_A = 10, E_B, E_C, E_D, E_E};
+
+#if WE_DONT_LIKE_THIS
+// Yet? GCC outputs DW_AT_linkage_name="<anon>"
+// This *really* messes things up.
+namespace {
+  typedef enum {AA = 20, AB, AC, AD} ANON_E;
+}
+#endif
+
+namespace N {
+  typedef enum {AA = 20, AB, AC, AD} ANON_E;
+}
+
+class A
+{
+public:
+  typedef int ATYPE;
+
+  A(void) : public_ (1), protected_ (N::AB), private_ (3) {}
+  ATYPE public_;
+  static const myenum s_public_;
+  friend ATYPE get_values (const A&);
+
+protected:
+  N::ANON_E protected_;
+  static N::ANON_E s_protected_;
+
+private:
+  ATYPE private_;
+  static myenum s_private_;
+};
+
+const myenum A::s_public_ = E_A;
+N::ANON_E A::s_protected_ = N::AA;
+myenum A::s_private_ = E_C;
+
+static A::ATYPE
+get_values (const A& a)
+{
+  A::ATYPE val;
+
+  val = a.public_ + a.private_;        // 1 + 3
+  if (a.protected_ == N::AB)   // + 21
+    val += 21;
+  if (a.s_public_ == E_A)      // +10
+    val += 10;
+  if (a.s_protected_ == N::AA) // +20
+    val += 20;
+  if (a.s_private_ == E_C)     // +30
+    val += 30;
+  return val;                  // = 85
+}
+
+typedef int A::*PMI;
+
+int
+main (void)
+{
+  A a;
+  int var = 1234;
+  PMI pmi = &A::public_;
+
+  return a.*pmi + get_values (a);              // break here
+}
diff --git a/gdb/testsuite/gdb.compile/cp-simple-member.exp b/gdb/testsuite/gdb.compile/cp-simple-member.exp
new file mode 100644 (file)
index 0000000..c9320d7
--- /dev/null
@@ -0,0 +1,76 @@
+# Copyright 2015-2016 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/>.
+
+# (Very) simple method tests.
+
+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]} {
+    return -1
+}
+
+if {[skip_compile_feature_tests]} {
+    untested \
+       "compile command not supported (could not find libcc1 shared library?)"
+    return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+CompileExpression::new "var"
+CompileExpression::test "a.public_" 1
+CompileExpression::test "a.protected_" {(21|N::AB)}
+CompileExpression::test "a.private_" 3
+CompileExpression::test "A::s_public_" {(10|E_A)}
+CompileExpression::test "A::s_protected_" {(20|N::AA)}
+CompileExpression::test "A::s_private_" {(12|E_C)}
+CompileExpression::test "A::ATYPE i = 10; var = i;" 10 -explicit
+CompileExpression::test "get_values (a)" 85
+CompileExpression::test "myenum me = E_B; var = me;" 11 -explicit
+CompileExpression::test "A::s_protected_ = N::AB; var = A::s_protected_;" \
+    21 -explicit
+CompileExpression::test "A::s_private_ = E_B; var = A::s_private_;" 11 -explicit
+CompileExpression::test "N::ANON_E ae = N::AD; var = ae;" 23 -explicit
+CompileExpression::test {a.*pmi} 1
+CompileExpression::test {a.public_ = 2; var = a.*pmi; a.public_ = 1} 2 -explicit
+
+# Test some compilation failures
+set failed {\r\nCompilation failed\.}
+# !!keiths: This should actually really work...
+gdb_test "compile code a.s_public_ = E_B" \
+    ".*assignment of read-only variable 'A::s_public_'$failed"
+
+gdb_test "compile code get_values ()" \
+    ".*too few arguments to function.*$failed"
+
+gdb_test "compile code ATYPE i;" \
+    ".*.ATYPE. was not declared in this scope$failed"
+
+# !!keiths; The "to ..." part depends on how we name anonymous types.
+gdb_test "compile code N::ANON_E nse = E_A" \
+    ".*cannot convert .myenum. to .N::anonymous enum.*$failed"
diff --git a/gdb/testsuite/gdb.compile/cp-simple-method.cc b/gdb/testsuite/gdb.compile/cp-simple-method.cc
new file mode 100644 (file)
index 0000000..c3c9969
--- /dev/null
@@ -0,0 +1,91 @@
+/* Copyright 2015, 2016 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+class A;
+static int get_value (const A* a);
+
+class A
+{
+public:
+  typedef int ATYPE;
+
+  A (void) : a_ (21) {}
+  ATYPE get_var (void) { return a_; }
+  ATYPE get_var (unsigned long a) { return 100; }
+  ATYPE get_var (ATYPE a) { return 101; }
+  ATYPE get_var (float a) { return 102; }
+  ATYPE get_var (void *a) { return 103;}
+  ATYPE get_var (A& lr) { return 104; }
+  ATYPE get_var (A const& lr) { return 105; }
+
+  ATYPE get_var1 (int n) { return a_ << n; }
+  ATYPE get_var2 (int incr, unsigned n) { return (a_ + incr) << n; }
+
+  static ATYPE get_1 (int a) { return a + 1; }
+  static ATYPE get_2 (int a, int b) { return a + b + 2; }
+
+  friend ATYPE get_value (const A*);
+
+private:
+  ATYPE a_;
+};
+
+static A::ATYPE
+get_value (A::ATYPE a)
+{
+  return a;
+}
+
+static A::ATYPE
+get_value (const A* a)
+{
+  return a->a_;
+}
+
+static A::ATYPE
+get_value (void)
+{
+  return 200;
+}
+
+typedef int (A::*PMF) (A::ATYPE);
+
+int
+main (void)
+{
+  A *a = new A ();
+  int var = 1234;
+  float f = 1.23;
+  unsigned long ul = 0xdeadbeef;
+  A const* ac = a;
+
+  PMF pmf = &A::get_var;
+  PMF *pmf_p = &pmf;
+
+  var -= a->get_var ();                // break here
+  var -= a->get_var (1);
+  var -= a->get_var (ul);
+  var -= a->get_var (f);
+  var -= a->get_var (a);
+  var -= a->get_var (*a);
+  var -= a->get_var (*ac);
+  var -= a->get_var1 (1);
+  var -= a->get_var2 (1, 2);
+  var += (a->*pmf) (1);
+  var -= (a->**pmf_p) (1);
+
+  return var - A::get_1 (1) + A::get_2 (1, 2) + get_value ()
+    + get_value (get_value ()) + get_value (a);
+}
diff --git a/gdb/testsuite/gdb.compile/cp-simple-method.exp b/gdb/testsuite/gdb.compile/cp-simple-method.exp
new file mode 100644 (file)
index 0000000..ebb1273
--- /dev/null
@@ -0,0 +1,66 @@
+# Copyright 2015-2017 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# (Very) simple method tests.
+
+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]} {
+    return -1
+}
+
+if {[skip_compile_feature_tests]} {
+    untested \
+       "compile command not supported (could not find libcc1 shared library?)"
+    return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+CompileExpression::new "var"
+CompileExpression::test "a->get_var ()" 21
+CompileExpression::test "a->get_var (static_cast<unsigned long> (1))" 100
+CompileExpression::test "a->get_var (static_cast<int> (1))" 101
+CompileExpression::test "a->get_var (static_cast<float> (1))" 102
+CompileExpression::test "a->get_var (static_cast<void *> (a))" 103
+CompileExpression::test "a->get_var (*a)" 104
+CompileExpression::test "a->get_var (*ac)" 105
+CompileExpression::test "a->get_var1 (1)" 42
+CompileExpression::test "a->get_var2 (1, 2)" 88
+CompileExpression::test "A::get_1 (1)" 2
+CompileExpression::test "A::get_2 (1, 2)" 5
+CompileExpression::test "A::get_1 (a->get_var ())" 22
+CompileExpression::test "a->get_var1 (a->get_var () - 16)" 672
+CompileExpression::test "a->get_var2 (a->get_var (), A::get_1 (2))" 336
+CompileExpression::test "get_value ()" 200
+CompileExpression::test "get_value (a)" 21
+CompileExpression::test "get_value (get_value ())" 200
+CompileExpression::test {(a->*pmf) (1)} 101
+CompileExpression::test \
+    {pmf = &A::get_var1; var = (a->*pmf) (2); pmf = &A::get_var} 84 -explicit
+CompileExpression::test {(a->**pmf_p) (1)} 101
diff --git a/gdb/testsuite/gdb.compile/cp-simple-nested.cc b/gdb/testsuite/gdb.compile/cp-simple-nested.cc
new file mode 100644 (file)
index 0000000..50db34f
--- /dev/null
@@ -0,0 +1,58 @@
+/* Copyright 2015-2016 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+class A
+{
+public:
+  A (void) : a_ (1) {}
+  int get (void);
+
+protected:
+  int a_;
+
+private:
+  /* It is important to not /not/ use the nested class definition in A.
+     This exercises a different path through the code.  */
+  struct Inner1
+  {
+    int a_;
+    Inner1 (void) : a_ (2) {}
+
+    struct Inner2
+    {
+      int a_;
+      Inner2 (void) : a_ (3) {}
+    };
+  };
+};
+
+int
+A::get (void)
+{
+  A::Inner1 i1;
+  A::Inner1::Inner2 i2;
+
+  return i1.a_ + i2.a_; // break here
+}
+
+int var = 1234;
+
+int
+main (void)
+{
+  A a;
+
+  return a.get ();
+}
diff --git a/gdb/testsuite/gdb.compile/cp-simple-nested.exp b/gdb/testsuite/gdb.compile/cp-simple-nested.exp
new file mode 100644 (file)
index 0000000..be36197
--- /dev/null
@@ -0,0 +1,52 @@
+# Copyright 2015-2016 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/>.
+
+# (Very) simple virtual method/inheritance tests.
+
+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]} {
+    return -1
+}
+
+if {[skip_compile_feature_tests]} {
+    untested \
+       "compile command not supported (could not find libcc1 shared library?)"
+    return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+CompileExpression::new "var"
+CompileExpression::test "i1.a_" 2
+CompileExpression::test "i2.a_" 3
+CompileExpression::test "A::Inner1 *i1p = &i1; var = i1p->a_;" 2 -explicit
+CompileExpression::test "A::Inner1::Inner2 *i2p = &i2; var = i2p->a_;" 3 \
+    -explicit
+CompileExpression::test "A::Inner1 &r1 = i1; var = r1.a_;" 2 -explicit
+CompileExpression::test "A::Inner1::Inner2 &r2 = i2; var = r2.a_;" 3 -explicit
diff --git a/gdb/testsuite/gdb.compile/cp-simple-ns.cc b/gdb/testsuite/gdb.compile/cp-simple-ns.cc
new file mode 100644 (file)
index 0000000..56923ed
--- /dev/null
@@ -0,0 +1,37 @@
+namespace N1
+{
+  namespace N2
+  {
+    namespace N3
+    {
+      namespace N4
+      {
+        static int n4static = 400;
+
+        struct S4
+        {
+          static int s4static;
+          int s4int_;
+          S4 (void) : s4int_ (4) {};
+          ~S4 (void) { --s4static; }
+
+         int get_var (void) { return s4int_; }
+         static int get_svar (void) { return s4static; }
+        };
+        int S4::s4static = 40;
+      }
+    }
+  }
+}
+
+int
+main (void)
+{
+  using namespace N1::N2::N3::N4;
+
+  S4 s;
+  int var = 1234;
+
+  var += s.s4int_; /* break here */
+  return S4::get_svar () - 10 * s.get_var ();
+}
diff --git a/gdb/testsuite/gdb.compile/cp-simple-ns.exp b/gdb/testsuite/gdb.compile/cp-simple-ns.exp
new file mode 100644 (file)
index 0000000..5d51a3d
--- /dev/null
@@ -0,0 +1,48 @@
+# Copyright 2015, 2016, 2017 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+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]} {
+    return -1
+}
+
+if {[skip_compile_feature_tests]} {
+    untested \
+       "compile command not supported (could not find libcc1 shared library?)"
+    return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+CompileExpression::new "var"
+CompileExpression::test "N1::N2::N3::N4::n4static" 400
+CompileExpression::test "N1::N2::N3::N4::S4::s4static" 40
+CompileExpression::test "s.s4int_" 4
+CompileExpression::test "N1::N2::N3::N4::S4::get_svar ()" 40
+CompileExpression::test "s.get_var ()" 4
diff --git a/gdb/testsuite/gdb.compile/cp-simple-template.cc b/gdb/testsuite/gdb.compile/cp-simple-template.cc
new file mode 100644 (file)
index 0000000..ec46694
--- /dev/null
@@ -0,0 +1,180 @@
+/* Copyright 2016 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/>.  */
+
+// NOTE: We cannot currently use namespaces until namespace-qualified
+// symbol lookups are fixed in gdb
+
+template <typename T, int V>
+T mytemplate (int a)
+{
+  return static_cast<T> (a) + V;
+}
+
+template <typename T, int V>
+T mytemplate (void)
+{
+  return -V;
+}
+
+template <int V = 100>
+int mytemplate (void)
+{
+  return V;
+}
+
+struct A
+{
+  A (int val) : value (val) { }
+  operator int () const { return value; }
+
+  template <typename T = A>
+  T tempmethod (void)
+  {
+    return value;
+  }
+
+  template <typename T = A, int V = -1>
+  static T stempmethod (void)
+  {
+    return V;
+  }
+
+  template <typename T = A, int V = -2>
+  static T stempmethod (T arg)
+  {
+    return arg + V;
+  }
+
+  int value;
+};
+
+template<>
+int
+A::tempmethod (void)
+{
+  return -value;
+}
+
+template <typename T>
+T deduct (T a)
+{
+  return a;
+}
+
+extern char const g_str[] = "hello";
+
+template <typename T>
+int mod_test (T a) { return 1; }
+
+template <typename T>
+int mod_test (T* const a) { return 2; }
+
+template <typename T>
+int mod_test (T const* const a) { return 3; }
+
+#if 0
+/* This chaining of defaults has no good representation in the debug info.
+   For each instance where T2 defaulted to T1, we will have as many
+   default values in the debug info for T2, one for each such instance.  */
+template <typename T1 = int, typename T2 = T1, typename T3 = T2,
+         int V1 = 10, int V2 = 20, const char* V3 = g_str>
+T1 defaultvals (void)
+{
+  return static_cast<T1> (V1);
+}
+#else
+template <typename T = A, int V = 10, const char* S = g_str>
+T defaultvals (void)
+{
+  return static_cast<T> (V);
+}
+#endif
+
+// A handful of operator templates
+struct O
+{
+  O (int v) : v_ (v) { }
+
+  template <typename T>
+  operator T (void) { return -v_; }
+
+  template <typename T>
+  O operator+ (T val)
+  {
+    return v_ + val;
+  }
+
+  int v_;
+};
+
+template <typename T>
+const T** ret_test (void) { return 0; }
+
+template <typename T>
+T const* const* ret2_test (void) { return 0; }
+
+// Some simple class templates
+template <typename T1 = O, typename T2 = int, int V = 3>
+class classt
+{
+public:
+  classt (T1 v) : val1_ (v), val2_ (107) { }
+  T1 get1 (void) const { return val1_; }
+  T2 get2 (void) const { return val2_; }
+  int get3 (void) const { return V; }
+
+private:
+  T1 val1_;
+  T2 val2_;
+};
+
+int
+main (void)
+{
+  A a (20);
+  O o (30);
+  int var = 0xdeadbeef;
+  int i = 1;
+  const int j = 1;
+  int* pi = &i;
+  int const* const cpci = &j;
+  int *const cpi = &i;
+
+  int o_val = o + 30;
+  int mod_value = mod_test (i) + mod_test (cpci) + mod_test (cpi);
+  const char** cp = ret_test<char> ();
+  char const* const* ccp = ret2_test<char> ();
+
+  classt<> cddd (o);
+  classt<int> cdd (100);
+  classt<int, char> cd (101);
+  classt<int, char, 12> c (102);
+  int cvals = cddd.get1 () + cddd.get2 () + cddd.get3 ();
+  cvals += cdd.get1 () + cdd.get2 () + cdd.get3 ();
+  cvals += cd.get1 () + cd.get2 () + cd.get3 ();
+  cvals += c.get1 () + c.get2 () + c.get3 ();
+
+  return mytemplate<int, 1> (0)
+    + mytemplate<int, 1> ()
+    + mytemplate<0> ()
+    + mytemplate ()
+    + a.tempmethod ()
+    + a.tempmethod<int> ()
+    + A::stempmethod ()
+    + A::stempmethod (0)
+    + defaultvals ()
+    + defaultvals<int, 20> ()
+    + deduct (0); // break here
+}
diff --git a/gdb/testsuite/gdb.compile/cp-simple-template.exp b/gdb/testsuite/gdb.compile/cp-simple-template.exp
new file mode 100644 (file)
index 0000000..7261eed
--- /dev/null
@@ -0,0 +1,79 @@
+# Copyright 2016 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/>.
+
+# (Very) simple template tests.
+
+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]} {
+    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 "mytemplate<int, 1> ()" -1
+CompileExpression::test "mytemplate<int, 1> (1)" 2
+CompileExpression::test "mytemplate<0> ()" 0
+CompileExpression::test "mytemplate ()" 100
+CompileExpression::test "a.tempmethod ()" {(20|{value = 20})} \
+    -print {xfail *-*-* gcc/debug/49348} \
+    -value {xfail *-*-* gcc/debug/49348}
+CompileExpression::test "a.tempmethod<A> ()" {(20|{value = 20})}
+CompileExpression::test "a.tempmethod<int> ()" -20
+CompileExpression::test "defaultvals ()" {(10|{value = 10})}
+CompileExpression::test "defaultvals<int, 20> ()" 20
+CompileExpression::test "deduct (1234)" 1234
+CompileExpression::test "o + 3" {(-33|{v_ = 33})}
+CompileExpression::test "mod_test (i)" 1
+CompileExpression::test "mod_test (cpi)" 2
+CompileExpression::test "mod_test (cpci)" 3
+CompileExpression::test "cddd.get1 ()" {(-30|{v_ = 30})}
+CompileExpression::test "cddd.get2 ()" 107
+CompileExpression::test "cddd.get3 ()" 3
+CompileExpression::test "cdd.get1 ()" 100
+CompileExpression::test "cdd.get2 ()" 107
+CompileExpression::test "cdd.get3 ()" 3
+CompileExpression::test "cd.get1 ()" 101
+CompileExpression::test "cd.get2 ()" {107( 'k')?}
+CompileExpression::test "cd.get3 ()" 3
+CompileExpression::test "c.get1 ()" 102
+CompileExpression::test "c.get2 ()" {107( 'k')?}
+CompileExpression::test "c.get3 ()" 12
+
+# Some explicit tests that don't fit neatly into CompileExpression (yet)
+gdb_test "compile print ret_test<char>()" \
+    [string_to_regexp {= (const char **) 0x0}]
+gdb_test "compile print ret2_test<char>()" \
+    [string_to_regexp {= (const char * const *) 0x0}]
diff --git a/gdb/testsuite/gdb.compile/cp-simple-virtual.cc b/gdb/testsuite/gdb.compile/cp-simple-virtual.cc
new file mode 100644 (file)
index 0000000..f778d70
--- /dev/null
@@ -0,0 +1,65 @@
+/* Copyright 2015 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+struct A
+{
+  virtual int doit (void) { return 1; }
+  virtual int doit3 (void) { return -3; }
+  virtual int doit2 (void) = 0;
+};
+
+struct B : virtual A
+{
+  int doit (void) { return 2; }
+  int doit2 (void) { return 22; }
+};
+
+struct C : virtual A
+{
+  int doit (void) { return 3; }
+  int doit2 (void) { return 33; }
+};
+
+struct D : B, C
+{
+  int doit (void) { return 4; }
+  int doit2 (void) { return 44; }
+};
+
+int
+main (void)
+{
+  int var = 1234;
+  B b;
+  C c;
+  D d;
+  A *ap = &d;
+
+  struct Foo
+  {
+    int doit (void) { return 1111; }
+  } foo;
+
+  struct Bar : A
+  {
+    int doit2 (void) { return 2222; }
+  } bar;
+
+  var = (b.doit () + c.doit () + d.doit () + d.doit3 ()
+        + ap->doit () + ap->doit2 () + foo.doit ()
+        + bar.doit2 ());       // break here
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.compile/cp-simple-virtual.exp b/gdb/testsuite/gdb.compile/cp-simple-virtual.exp
new file mode 100644 (file)
index 0000000..44bb3dd
--- /dev/null
@@ -0,0 +1,72 @@
+# Copyright 2015, 2016 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/>.
+
+# (Very) simple virtual method/inheritance tests.
+
+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]} {
+    return -1
+}
+
+if {[skip_compile_feature_tests]} {
+    untested \
+       "compile command not supported (could not find libcc1 shared library?)"
+    return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+CompileExpression::new "var"
+CompileExpression::test "b.doit ()" 2
+CompileExpression::test "c.doit ()" 3
+CompileExpression::test "d.doit ()" 4
+CompileExpression::test "ap->doit ()" 4
+CompileExpression::test "b.doit2 ()" 22
+CompileExpression::test "c.doit2 ()" 33
+CompileExpression::test "d.doit2 ()" 44
+CompileExpression::test "ap->doit2 ()" 44
+CompileExpression::test "b.doit3 ()" -3
+CompileExpression::test "c.doit3 ()" -3
+CompileExpression::test "d.doit3 ()" -3
+CompileExpression::test "foo.doit ()" 1111
+CompileExpression::test "bar.doit2 ()" 2222
+
+# These two tests are "disabled".  They represent new/future features.
+# CompileExpression::test \
+    [concat "struct ABC {int doit2(void) { return 3333; }} abc;" \
+        "var = abc.doit2()"] \
+    3333 -explicit
+# CompileExpression::test \
+    [concat "struct ABC : A {int doit2(void) { return 4444; }} abc;" \
+        "var = abc.doit2()"] \
+    4444 -explicit
+
+# Test some error conditions
+gdb_test "compile code A a;" \
+    ".*cannot declare variable .a. to be of abstract type.*Compilation failed."
diff --git a/gdb/testsuite/gdb.compile/cp-special-function.cc b/gdb/testsuite/gdb.compile/cp-special-function.cc
new file mode 100644 (file)
index 0000000..6bb5ea5
--- /dev/null
@@ -0,0 +1,661 @@
+/* Copyright 2015 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <cstddef>
+
+class MyInteger;
+static MyInteger *global_integer;
+
+class MyInteger
+{
+public:
+  MyInteger (int val) : pub_var (0), int_ (val) {}
+  int get (void) const { return int_; }
+
+  /* Don't assume that these operators do exactly what you
+     think they will -- especially the unary versions of +,-,*,&.  */
+
+  friend MyInteger operator+ (const MyInteger& i);
+  friend int operator+ (const MyInteger& i1, const MyInteger& i2);
+  friend int operator+ (const MyInteger& i1, int i2);
+  friend int operator+ (int i1, const MyInteger& i2);
+
+  friend MyInteger operator- (const MyInteger& i);
+  friend int operator- (const MyInteger& i1, const MyInteger& i2);
+  friend int operator- (const MyInteger& i1, int i2);
+  friend int operator- (int i1, const MyInteger& i2);
+
+  friend MyInteger operator& (const MyInteger& i);
+  friend int operator& (const MyInteger& i1, const MyInteger& i2);
+  friend int operator& (const MyInteger& i1, int i2);
+  friend int operator& (int i1, const MyInteger& i2);
+
+  friend MyInteger operator* (const MyInteger& i);
+  friend int operator* (const MyInteger& i1, const MyInteger& i2);
+  friend int operator* (const MyInteger& i1, int i2);
+  friend int operator* (int i1, const MyInteger& i2);
+
+  friend MyInteger operator~ (const MyInteger& i);
+
+  friend int operator/ (const MyInteger& i1, const MyInteger& i2);
+  friend int operator/ (const MyInteger& i1, int i2);
+  friend int operator/ (int i1, const MyInteger& i2);
+
+  friend int operator% (const MyInteger& i1, const MyInteger& i2);
+  friend int operator% (const MyInteger& i1, int i2);
+  friend int operator% (int i1, const MyInteger& i2);
+
+  friend int operator| (const MyInteger& i1, const MyInteger& i2);
+  friend int operator| (const MyInteger& i1, int i2);
+  friend int operator| (int i1, const MyInteger& i2);
+
+  friend int operator^ (const MyInteger& i1, const MyInteger& i2);
+  friend int operator^ (const MyInteger& i1, int i2);
+  friend int operator^ (int i1, const MyInteger& i2);
+
+  void operator= (const MyInteger& i) { int_ = i.int_; }
+  void operator= (int i) { int_ = i; }
+
+  void operator+= (const MyInteger& i) { int_ += i.int_; }
+  void operator+= (int i) { int_ += i; }
+
+  void operator-= (const MyInteger& i) { int_ -= i.int_; }
+  void operator-= (int i) { int_ -= i; }
+
+  void operator*= (const MyInteger& i) { int_ *= i.int_; }
+  void operator*= (int i) { int_ *= i; }
+
+  void operator/= (const MyInteger& i) { int_ /= i.int_; }
+  void operator/= (int i) { int_ /= i; }
+
+  void operator%= (const MyInteger& i) { int_ %= i.int_; }
+  void operator%= (int i) { int_ %= i; }
+
+  void operator&= (const MyInteger& i) { int_ &= i.int_; }
+  void operator&= (int i) { int_ &= i; }
+
+  void operator|= (const MyInteger& i) { int_ |= i.int_; }
+  void operator|= (int i) { int_ |= i; }
+
+  void operator^= (const MyInteger& i) { int_ ^= i.int_; }
+  void operator^= (int i) { int_ ^= i; }
+
+  friend int operator<< (const MyInteger& i1, const MyInteger& i2);
+  friend int operator<< (const MyInteger& i1, int i2);
+  friend int operator<< (int i1, const MyInteger& i2);
+
+  friend int operator>> (const MyInteger& i1, const MyInteger& i2);
+  friend int operator>> (const MyInteger& i1, int i2);
+  friend int operator>> (int i1, const MyInteger& i2);
+
+  void operator<<= (const MyInteger& i) { int_ <<= i.int_; }
+  void operator<<= (int i) { int_ <<= i; }
+
+  void operator>>= (const MyInteger& i) { int_ >>= i.int_; }
+  void operator>>= (int i) { int_ >>= i; }
+
+  friend bool operator== (const MyInteger& i1, const MyInteger& i2);
+  friend bool operator== (const MyInteger& i1, int i2);
+  friend bool operator== (int i1, const MyInteger& i2);
+
+  friend bool operator!= (const MyInteger& i1, const MyInteger& i2);
+  friend bool operator!= (const MyInteger& i1, int i2);
+  friend bool operator!= (int i1, const MyInteger& i2);
+
+  friend bool operator< (const MyInteger& i1, const MyInteger& i2);
+  friend bool operator< (const MyInteger& i1, int i2);
+  friend bool operator< (int i1, const MyInteger& i2);
+
+  friend bool operator> (const MyInteger& i1, const MyInteger& i2);
+  friend bool operator> (const MyInteger& i1, int i2);
+  friend bool operator> (int i1, const MyInteger& i2);
+
+  friend bool operator<= (const MyInteger& i1, const MyInteger& i2);
+  friend bool operator<= (const MyInteger& i1, int i2);
+  friend bool operator<= (int i1, const MyInteger& i2);
+
+  friend bool operator>= (const MyInteger& i1, const MyInteger& i2);
+  friend bool operator>= (const MyInteger& i1, int i2);
+  friend bool operator>= (int i1, const MyInteger& i2);
+
+  friend int operator! (const MyInteger& i);
+
+  friend bool operator&& (const MyInteger& i1, const MyInteger& i2);
+  friend bool operator&& (const MyInteger& i1, int i2);
+  friend bool operator&& (int i1, const MyInteger& i2);
+
+  friend bool operator|| (const MyInteger& i1, const MyInteger& i2);
+  friend bool operator|| (const MyInteger& i1, int i2);
+  friend bool operator|| (int i1, const MyInteger& i2);
+
+  MyInteger& operator++ (void) { ++int_; return *this; }
+  MyInteger operator++ (int dummy)
+  {
+    MyInteger tmp (int_);
+    operator++ ();
+    return tmp;
+  }
+
+  MyInteger& operator-- (void) { --int_; return *this; }
+  MyInteger operator-- (int dummy)
+  {
+    MyInteger tmp (int_);
+    operator-- ();
+    return tmp;
+  }
+
+  friend MyInteger& operator, (MyInteger& i1, MyInteger& i2);
+
+  friend int operator->* (const MyInteger& i1, int i2);
+  friend int operator->* (const MyInteger& i1, const MyInteger& i2);
+
+  MyInteger* operator-> (void) { return global_integer; }
+
+  int operator() (void) { return -int_; }
+  int operator() (const MyInteger& i) { return int_ + i; }
+  int operator() (int i) { return int_ + i; }
+
+  int operator[] (const MyInteger& i) { return int_ - i; }
+  int operator[] (int i) { return int_ - i; }
+
+#if 1
+  static void* operator new (std::size_t sz);
+#endif
+
+  operator int() const { return -int_; }
+  operator char() const { return int_ & 0xff; }
+
+public:
+  int pub_var;
+private:
+  int int_;
+};
+
+MyInteger
+operator+ (const MyInteger& i)
+{
+  return MyInteger (i + 10);
+}
+
+int
+operator+ (const MyInteger& i1, const MyInteger& i2)
+{
+  return i1.int_ + i2.int_;
+}
+
+int
+operator+ (const MyInteger& i1, int i2)
+{
+  return i1.int_ + i2;
+}
+
+int
+operator+ (int i1, const MyInteger&  i2)
+{
+  return operator+ (i2, i1);
+}
+
+MyInteger
+operator- (const MyInteger& i)
+{
+  return MyInteger (i + 20);
+}
+
+int
+operator- (const MyInteger& i1, const MyInteger& i2)
+{
+  return i1.int_ - i2.int_;
+}
+
+int
+operator- (const MyInteger& i1, int i2)
+{
+  return i1.int_ - i2;
+}
+
+int
+operator- (int i1, const MyInteger&  i2)
+{
+  return i1 - i2.int_;
+}
+
+MyInteger
+operator& (const MyInteger& i)
+{
+  return MyInteger (i + 30);
+}
+
+int
+operator& (const MyInteger& i1, const MyInteger& i2)
+{
+  return i1.int_ & i2.int_;
+}
+
+int
+operator& (const MyInteger& i1, int i2)
+{
+  return i1.int_ & i2;
+}
+
+int
+operator& (int i1, const MyInteger&  i2)
+{
+  return operator& (i2, i1);
+}
+
+MyInteger
+operator* (const MyInteger& i)
+{
+  return MyInteger (i + 40);
+}
+
+int
+operator* (const MyInteger& i1, const MyInteger& i2)
+{
+  return i1.int_ * i2.int_;
+}
+
+int
+operator* (const MyInteger& i1, int i2)
+{
+  return i1.int_ * i2;
+}
+
+int
+operator* (int i1, const MyInteger&  i2)
+{
+  return operator* (i2, i1);
+}
+
+MyInteger
+operator~ (const MyInteger& i)
+{
+  return MyInteger (~i.int_);
+}
+
+int
+operator/ (const MyInteger& i1, const MyInteger& i2)
+{
+  return i1.int_ / i2.int_;
+}
+
+int
+operator/ (const MyInteger& i1, int i2)
+{
+  return i1.int_ / i2;
+}
+
+int
+operator/ (int i1, const MyInteger& i2)
+{
+  return i1 / i2.int_;
+}
+
+int
+operator% (const MyInteger& i1, const MyInteger& i2)
+{
+  return i1.int_ % i2.int_;
+}
+
+int
+operator% (const MyInteger& i1, int i2)
+{
+  return i1.int_ % i2;
+}
+
+int
+operator% (int i1, const MyInteger& i2)
+{
+  return i1 % i2.int_;
+}
+
+int
+operator| (const MyInteger& i1, const MyInteger& i2)
+{
+  return i1.int_ | i2.int_;
+}
+
+int
+operator| (const MyInteger& i1, int i2)
+{
+  return i1.int_ | i2;
+}
+
+int
+operator| (int i1, const MyInteger& i2)
+{
+  return i1 | i2.int_;
+}
+
+int
+operator^ (const MyInteger& i1, const MyInteger& i2)
+{
+  return i1.int_ ^ i2.int_;
+}
+
+int
+operator^ (const MyInteger& i1, int i2)
+{
+  return i1.int_ ^ i2;
+}
+
+int
+operator^ (int i1, const MyInteger& i2)
+{
+  return i1 ^ i2.int_;
+}
+
+int
+operator<< (const MyInteger& i1, const MyInteger& i2)
+{
+  return i1.int_ << i2.int_;
+}
+
+int
+operator<< (const MyInteger& i1, int i2)
+{
+  return i1.int_ << i2;
+}
+
+int
+operator<< (int i1, const MyInteger& i2)
+{
+  return i1 << i2.int_;
+}
+
+int
+operator>> (const MyInteger& i1, const MyInteger& i2)
+{
+  return i1.int_ >> i2.int_;
+}
+
+int
+operator>> (const MyInteger& i1, int i2)
+{
+  return i1.int_ >> i2;
+}
+
+int
+operator>> (int i1, const MyInteger& i2)
+{
+  return i1 >> i2.int_;
+}
+
+bool
+operator== (const MyInteger& i1, const MyInteger& i2)
+{
+  return i1.int_ == i2.int_;
+}
+
+bool
+operator== (const MyInteger& i1, int i2)
+{
+  return i1.int_ == i2;
+}
+
+bool
+operator== (int i1, const MyInteger& i2)
+{
+  return operator== (i2, i1);
+}
+
+bool
+operator!= (const MyInteger& i1, const MyInteger& i2)
+{
+  return i1.int_ != i2.int_;
+}
+
+bool
+operator!= (const MyInteger& i1, int i2)
+{
+  return i1.int_ != i2;
+}
+
+bool
+operator!= (int i1, const MyInteger& i2)
+{
+  return operator!= (i2, i1);
+}
+
+bool
+operator< (const MyInteger& i1, const MyInteger& i2)
+{
+  return i1.int_ < i2.int_;
+}
+
+bool
+operator< (const MyInteger& i1, int i2)
+{
+  return i1.int_ < i2;
+}
+
+bool
+operator< (int i1, const MyInteger& i2)
+{
+  return i1 < i2.int_;
+}
+
+bool
+operator> (const MyInteger& i1, const MyInteger& i2)
+{
+  return i1.int_ > i2.int_;
+}
+
+bool
+operator> (const MyInteger& i1, int i2)
+{
+  return i1.int_ > i2;
+}
+
+bool
+operator> (int i1, const MyInteger& i2)
+{
+  return i1 > i2.int_;
+}
+
+bool
+operator<= (const MyInteger& i1, const MyInteger& i2)
+{
+  return i1.int_ <= i2.int_;
+}
+
+bool
+operator<= (const MyInteger& i1, int i2)
+{
+  return i1.int_ <= i2;
+}
+
+bool
+operator<= (int i1, const MyInteger& i2)
+{
+  return i1 <= i2.int_;
+}
+
+bool
+operator>= (const MyInteger& i1, const MyInteger& i2)
+{
+  return i1.int_ >= i2.int_;
+}
+
+bool
+operator>= (const MyInteger& i1, int i2)
+{
+  return i1.int_ >= i2;
+}
+
+bool
+operator>= (int i1, const MyInteger& i2)
+{
+  return i1 >= i2.int_;
+}
+
+int
+operator! (const MyInteger& i)
+{
+  return !(i.int_);
+}
+
+bool
+operator&& (const MyInteger& i1, const MyInteger& i2)
+{
+  return i1.int_ && i2.int_;
+}
+
+bool
+operator&& (const MyInteger& i1, int i2)
+{
+  return i1.int_ && i2;
+}
+
+bool
+operator&& (int i1, const MyInteger& i2)
+{
+  return operator&& (i2, i1);
+}
+
+bool
+operator|| (const MyInteger& i1, const MyInteger& i2)
+{
+  return i1.int_ || i2.int_;
+}
+
+bool
+operator|| (const MyInteger& i1, int i2)
+{
+  return i1.int_ || i2;
+}
+
+bool
+operator|| (int i1, const MyInteger& i2)
+{
+  return operator|| (i2, i1);
+}
+
+MyInteger&
+operator, (MyInteger& i1, MyInteger& i2)
+{
+  return i1;
+}
+
+int
+operator->* (const MyInteger& i1, int i2)
+{
+  return i1 + i2;
+}
+
+int
+operator->* (const MyInteger& i1, const MyInteger& i2)
+{
+  return i1 + i2;
+}
+
+int
+operator"" _MI (unsigned long long i)
+{
+  return 100;
+}
+
+int
+operator"" _MI (char c)
+{
+  return 200;
+}
+
+int
+operator"" _MI (const char *str, std::size_t len)
+{
+  return 300;
+}
+
+#if 1
+static void*
+MyInteger::operator new (std::size_t sz)
+{
+  void* p =  ::operator new (sz);
+  MyInteger* obj = static_cast<MyInteger*> (p);
+
+  obj->pub_var = 1234;
+  return p;
+}
+#endif
+
+int
+main (void)
+{
+  char ch;
+  int var;
+  MyInteger a (1), b (2), c (-3), d (0);
+
+  global_integer = new MyInteger (21);
+  global_integer->pub_var = -21;
+  ch = *global_integer;
+  d = a;
+  d = 0;
+  d += a;
+  d += 1;
+  d -= a;
+  d -= 1;
+  d *= 1;
+  d *= d;
+  d = 2;
+  d /= 1;
+  d /= d;
+  d %= 2;
+  d %= a;
+  d = 2;
+  d &= 1;
+  d &= a;
+  d |= 2;
+  d |= a;
+  d ^= 1;
+  d ^= b;
+  d <<= 2;
+  d <<= a;
+  d >>= 2;
+  d >>= a;
+  d++;
+  ++d;
+  d--;
+  --d;
+  d = 1234;
+  var = d;
+  return +c + a + b + 3 + a.get ()
+    - a - 2 - a - b + (-c)
+    + a & b + a & 1
+    * a * b * 2 * c
+    + ~c
+    + a / 1 + b / a + 1 / a
+    + a % b + a % 1 + 2 % b
+    + 1|b + a|2 + a|b
+    + 1^a + b^2 + a^b
+    + 1 << a + a << 1 + a << a
+    + 10 >> a + b >> 1 + b >> a
+    + a == 1 + a == b + 1 == a
+    + a != 1 + a != b + 1 != a
+    + (a < 1) + (a < b) + (2 < a)
+    + (a > 1) + (a > b) + (2 > a)
+    + (a <= 1) + (a <= b) + (2 <= a)
+    + (a >= 1) + (a >= b) + (2 >= a)
+    + (!a)
+    + (a && 0) + (a && b) + (1 && a)
+    + (a || 0) + (a || b) + (1 || a)
+    + (a,b)
+    + a->*1 + a->*b
+    + a->pub_var
+    + a () + a (a) + a (2)
+    + a [1] + b [a]
+    + 'a'_MI + 1234_MI + "hello"_MI
+    ; // break here
+}
diff --git a/gdb/testsuite/gdb.compile/cp-special-function.exp b/gdb/testsuite/gdb.compile/cp-special-function.exp
new file mode 100644 (file)
index 0000000..fcbbfce
--- /dev/null
@@ -0,0 +1,260 @@
+# Copyright 2015, 2016 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/>.
+
+# (Very) simple method tests.
+
+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++ additional_flags=-std=c++11}]} {
+    return -1
+}
+
+if {![runto_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 "a + 1" 2
+CompileExpression::test "a + b" 3
+CompileExpression::test "a + b + 3" 6
+CompileExpression::test "1 + a + a" 3
+CompileExpression::test "1 + b + 1" 4
+CompileExpression::test "(+a).get ()" 11
+CompileExpression::test "(+c).get ()" 7
+CompileExpression::test "a + (+c).get ()" 8
+
+CompileExpression::test "a - 2" -1
+CompileExpression::test "a - b" -1
+CompileExpression::test "a - b - 3" -4
+CompileExpression::test "2 - a - a" 0
+CompileExpression::test "2 - b - 2" -2
+CompileExpression::test "(-a).get ()" 21
+CompileExpression::test "(-c).get ()" 17
+CompileExpression::test "a - (-c).get ()" -16
+
+CompileExpression::test "a & 3" 1
+CompileExpression::test "a & b" 0
+CompileExpression::test "a & b & 3" 0
+CompileExpression::test "3 & a & a" 1
+CompileExpression::test "3 & b & 3" 2
+CompileExpression::test "(&a).get ()" 31
+CompileExpression::test "(&c).get ()" 27
+CompileExpression::test "a & (&c).get ()" 1
+
+CompileExpression::test "a * 4" 4
+CompileExpression::test "a * b" 2
+CompileExpression::test "a * b * 4" 8
+CompileExpression::test "4 * a * a" 4
+CompileExpression::test "4 * b * 4" 32
+CompileExpression::test "(*a).get ()" 41
+CompileExpression::test "(*c).get ()" 37
+CompileExpression::test "a * (*c).get ()" 37
+
+CompileExpression::test "(~a).get ()" -2
+CompileExpression::test "(~b).get ()" -3
+CompileExpression::test "(~c).get ()" 2
+
+CompileExpression::test "a / 1" 1
+CompileExpression::test "10 / b" 5
+CompileExpression::test "b / a" 2
+CompileExpression::test "-3 / c / 1 / a" 1
+
+CompileExpression::test "a % 1" 0
+CompileExpression::test "5 % c" 2
+CompileExpression::test "a % c" 1
+CompileExpression::test "-2 % c % b % 1" 0
+
+CompileExpression::test "a | 1" 1
+CompileExpression::test "1 | b" 3
+CompileExpression::test "b | c" -1
+CompileExpression::test "1 | a | b | 4" 7
+
+CompileExpression::test "a ^ 1" 0
+CompileExpression::test "1 ^ b" 3
+CompileExpression::test "b ^ c" -1
+CompileExpression::test "1 ^ a ^ b ^ 4" 6
+
+# !!keiths: I don't know why this is failing...
+CompileExpression::test "d = b; var = d.get ();" 2 -explicit
+CompileExpression::test "d = 21; var = d.get ();" 21 -explicit
+CompileExpression::test "d = 0; var = d.get ();" 0 -explicit
+
+CompileExpression::test "d.int_ = 1; var = d.get ()" 1 -explicit
+CompileExpression::test "d += a; var = d.get ();" 2 -explicit
+CompileExpression::test "d += 2; var = d.get ();" 4 -explicit
+
+CompileExpression::test "d.int_ = 2; var = d.get ()" 2 -explicit
+CompileExpression::test "d -= a; var = d.get ();" 1 -explicit
+CompileExpression::test "d -= 2; var = d.get ();" -1 -explicit
+
+CompileExpression::test "d.int_ = 3; var = d.get ()" 3 -explicit
+CompileExpression::test "d *= 2; var = d.get ()" 6 -explicit
+CompileExpression::test  "d *= d; var = d.get ()" 36 -explicit
+
+CompileExpression::test "d.int_ = 6; var = d.get ()" 6 -explicit
+CompileExpression::test "d /= 2; var = d.get ()" 3 -explicit
+CompileExpression::test  "d /= d; var = d.get ()" 1 -explicit
+
+CompileExpression::test "d.int_ = 4; var = d.get ()" 4 -explicit
+CompileExpression::test "d %= 3; var = d.get ()" 1 -explicit
+CompileExpression::test  "d %= d; var = d.get ()" 0 -explicit
+
+CompileExpression::test "d.int_ = 5; var = d.get ()" 5 -explicit
+CompileExpression::test "d &= 4; var = d.get ()" 4 -explicit
+CompileExpression::test  "d &= a; var = d.get ()" 0 -explicit
+
+CompileExpression::test "d.int_ = 8; var = d.get ()" 8 -explicit
+CompileExpression::test "d |= a; var = d.get ()" 9 -explicit
+CompileExpression::test  "d |= 16; var = d.get ()" 25 -explicit
+
+CompileExpression::test "d.int_ = 9; var = d.get ()" 9 -explicit
+CompileExpression::test "d ^= 2; var = d.get ()" 11 -explicit
+CompileExpression::test  "d ^= d; var = d.get ()" 0 -explicit
+
+CompileExpression::test "d.int_ = 10; var = d.get ()" 10 -explicit
+CompileExpression::test "d << 2" 40
+CompileExpression::test "d << a" 20
+CompileExpression::test "1 << b" 4
+
+CompileExpression::test "d.int_ = 12; var = d.get ()" 12 -explicit
+CompileExpression::test "d >> 2" 3
+CompileExpression::test "d >> a" 6
+CompileExpression::test "10 >> a" 5
+
+CompileExpression::test "d.int_ = 13; var = d.get ()" 13 -explicit
+CompileExpression::test "d <<= 2; var = d.get ()" 52 -explicit
+CompileExpression::test  "d <<= a; var = d.get ()" 104 -explicit
+
+CompileExpression::test "d.int_ = 14; var = d.get ()" 14 -explicit
+CompileExpression::test "d >>= 2; var = d.get ()" 3 -explicit
+CompileExpression::test  "d >>= a; var = d.get ()" 1 -explicit
+
+CompileExpression::test "d.int_ = 1013; var = d.get ()" 1013 -explicit
+CompileExpression::test "d == 2" {(0|false)}
+CompileExpression::test "d == d" {(1|true)}
+CompileExpression::test "1 == d" {(0|false)}
+
+CompileExpression::test "d.int_ = 1014; var = d.get ()" 1014 -explicit
+CompileExpression::test "d != 2" {(1|true)}
+CompileExpression::test "d != d" {(0|false)}
+CompileExpression::test "1014 == d" {(1|true)}
+
+CompileExpression::test "d.int_ = 15; var = d.get ()" 15 -explicit
+CompileExpression::test "d < 2" {(0|false)}
+CompileExpression::test "a < d" {(1|true)}
+CompileExpression::test "16 < d" {(0|false)}
+
+CompileExpression::test "d.int_ = 16; var = d.get ()" 16 -explicit
+CompileExpression::test "d > 2" {(1|true)}
+CompileExpression::test "d < a" {(0|false)}
+CompileExpression::test "15 < d" {(1|true)}
+
+CompileExpression::test "d.int_ = 17; var = d.get ()" 17 -explicit
+CompileExpression::test "d <= 2" {(0|false)}
+CompileExpression::test "a <= d" {(1|true)}
+CompileExpression::test "18 <= d" {(0|false)}
+
+CompileExpression::test "d.int_ = 18; var = d.get ()" 18 -explicit
+CompileExpression::test "d >= 2" {(1|true)}
+CompileExpression::test "d <= a" {(0|false)}
+CompileExpression::test "15 <= d" {(1|true)}
+
+CompileExpression::test "d.int_ = 19; var = d.get ()" 19 -explicit
+CompileExpression::test "!d" {(0|false)}
+
+CompileExpression::test "d.int_ = 20; var = d.get ()" 20 -explicit
+CompileExpression::test "d && 0" {(0|false)}
+CompileExpression::test "d && a" {(1|true)}
+CompileExpression::test "0 && d" {(0|false)}
+
+CompileExpression::test "d.int_ = 21; var = d.get ()" 21 -explicit
+CompileExpression::test "d || 0" {(1|true)}
+CompileExpression::test "d || a" {(1|true)}
+CompileExpression::test "0 || d" {(1|true)}
+
+CompileExpression::test "d.int_ = 22; var = d.get ()" 22 -explicit
+CompileExpression::test "(d++).get ()" 22 -noprint
+CompileExpression::test "(d++).get ()" 23 -nocode
+CompileExpression::test "d.get ()" 24 -name "get value of post-incr d"
+CompileExpression::test "(++d).get ()" 25 -noprint
+CompileExpression::test "(++d).get ()" 26 -nocode
+
+CompileExpression::test "d.int_ = 23; var = d.get ()" 23 -explicit
+CompileExpression::test "(d--).get ()" 23 -noprint
+CompileExpression::test "(d--).get ()" 22 -nocode
+CompileExpression::test "d.get ()" 21 -name "get value of post-decr d"
+CompileExpression::test "(--d).get ()" 20 -noprint
+CompileExpression::test "(--d).get ()" 19 -nocode
+
+CompileExpression::test "d.int_ = 24; var = d.get ()" 24 -explicit
+CompileExpression::test "(a,d).get ()" 1
+CompileExpression::test "(d,a).get ()" 24
+
+CompileExpression::test "d.int_ = 25; var = d.get ()" 25 -explicit
+CompileExpression::test "d->*3" 28
+CompileExpression::test "d->*b" 27 "d->*b 1"
+
+CompileExpression::test "d.int_ = 26; var = d.get ()" 26 -explicit
+CompileExpression::test "d->*4" 30
+CompileExpression::test "d->*b" 28 "d->*b 2"
+
+CompileExpression::test "d.pub_var = 1; var = d.pub_var" 1 -explicit
+CompileExpression::test "d->pub_var" -21
+
+# "'d' cannot be used as function"
+ CompileExpression::test "d.int_ = 27; var = d.get ()" 27 -explicit
+ CompileExpression::test "d ()" -27
+ CompileExpression::test "d (3)" 30
+ CompileExpression::test "a (b)" 3
+
+CompileExpression::test "d.int_ = 28; var = d.get ()" 28 -explicit
+CompileExpression::test "d\[10\]" 18
+CompileExpression::test "d\[b\]" 26
+
+# "unable to find XYZ literal operator 'operator""_MI'"
+ CompileExpression::test "10_MI" 100
+ CompileExpression::test "'c'_MI" 200
+ CompileExpression::test "\"foo\"_MI" 300
+
+# crash
+ CompileExpression::test \
+    "MyInteger *myint_ptr = new MyInteger (1); var = myint_ptr->pub_var" \
+    1234 -explicit
+
+CompileExpression::test "d.int_ = 29; var = d.int_" 29 -explicit
+CompileExpression::test "ch = d; var = ch;" 29 -explicit
+CompileExpression::test "char a_char = d; var = a_char - 9" 20 -explicit
+
+CompileExpression::test "d.int_ = 30; var = d.int_" 30 -explicit
+CompileExpression::test "d" {(-30|{pub_var = 1, int_ = 30})}
+CompileExpression::test "int integer = d; var = integer - 10" -40 -explicit
diff --git a/gdb/testsuite/lib/compile-support.exp b/gdb/testsuite/lib/compile-support.exp
new file mode 100644 (file)
index 0000000..935ea55
--- /dev/null
@@ -0,0 +1,208 @@
+# Copyright 2015, 2016 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Generic/oft used support routines for testing GDB's compile feature.
+
+# Return 1 if we should skip tests of the "compile" feature.
+# This must be invoked after the inferior has been started.
+
+proc skip_compile_feature_tests {} {
+    global gdb_prompt
+
+    set result 0
+    gdb_test_multiple "compile code -- ;" "check for working compile command" {
+       "Could not load libcc1.*\r\n$gdb_prompt $" {
+           set result 1
+       }
+       -re "Command not supported on this host\\..*\r\n$gdb_prompt $" {
+           set result 1
+       }
+       -re "\r\n$gdb_prompt $" {
+       }
+    }
+    return $result
+}
+
+# This namespace provides some convenience functions for running
+# "compile code" and "compile print" tests.
+#
+# Exported functions are defined inline below.
+#
+# General usage:
+#
+# Start a new session, noting that the variable "var" will be used for
+# "compile code" expressions.
+# CompileExpression::new "var"
+#
+# Test the implicit expression "foo;" with result/value 3.
+# CompileExpression::test "foo;" 3
+# ---> Runs the following tests (name of tests ignored for illustration)
+#    gdb_test_no_output "compile code var = foo;"
+#    gdb_test "p var" "= 3"
+#    gdb_test "compile print foo;" "= 3"
+#
+# Test the explicit expression "a = function (3); var = a;" with the result 21.
+# CompileExpression::test "a = function (3); var = a;" 21 -explicit
+# ---> Runs the following tests (name of tests ignored for illustration)
+#    gdb_test_no_output "compile code a = function (3); var = a;"
+#    gdb_test "p var" "= 21"
+#
+# Additional option flags may be passed to test to control the behavior
+# of the test harness:
+#
+# Pass -explicit to specify that the test uses an explicit expression,
+# one which sets the value of the variable (see above).  Only the code test
+# will be run.
+#
+# Otherwise, all expressions are considered implicit.
+#
+# Pass -value, -compile, and/or -print to indicate that the value,
+# compile, or print steps will optionally fail. Specify "xfail" or
+# "kfail" to indicate how each particular step will fail.  These may be
+# followed by any accepted DejaGNU parameters such as architecture and
+# bug#.
+#
+# -compile and -value are used when a "code" test is run, the former
+# specifying that the "compile code" command (to GDB) will fail or pass
+# in the prescribed manner.  -value indicates that the "print $VARIABLE"
+# command (to GDB) will fail in the prescribed manner.
+#
+# -print is used to specify that an expression will fail in the presribed
+# manner when "print" test is executed.
+#
+# Pass "-name NAME" to set an optional test name.  If not specified,
+# the harness will use test names such as "compile code EXPR" and
+# "result of compile code EXPR".
+#
+# Pass "-noprint" or "-nocode" to suppress print or code tests, respectively,
+# This is useful when the expression being tested modifies the object
+# being tested, e.g., "a++".
+#
+# These options must be passed LAST to CompileExpression::test.
+#
+# Examples:
+#
+# Both "code" and "print" tests are expected to xfail:
+# CompileExpression add_imp "foo" 3 -compile {xfail *-*-*} -print {xfail *-*-*}
+#
+# The "print $VARIABLE" portion of the "code" test is expected to kfail
+# (the actual "compile code" GDB command will succeed), but the "print"
+# test should pass:
+# CompileExpression add_imp "foo" 3 -value {kfail *-*-* gdb/1234}
+
+namespace eval ::CompileExpression {
+
+    # The variable name to check testing results.  This variable
+    # must be in scope when tests are run.
+    variable varName_ {}
+
+    # Start a new expression list.  VARNAME is the name of the variable
+    # that will be printed to check if the result of the test was
+    # successful.
+    proc new {varname} {
+       variable varName_
+
+       set varName_ $varname
+    }
+
+    # Test an expression.
+    #
+    # See the preamble for a list of valid optional arguments.
+    #
+    # Implicit expressions will be sent to GDB in the form
+    # "$varName = $EXP".  "p $varName" will be used to decide the pass
+    # or fail status of the test.
+    #
+    # Explicit expressions will be sent to GDB as-is and tested using only
+    # "compile code".  The expression should set the value of the variable
+    # $varName, which is then printed to determine whether the test passed
+    # or failed.
+    #
+    # Unlike explicit expressions, implicit expressions are tested with both
+    # "compile print" and "compile code".
+
+    proc test {exp result args} {
+       parse_args {{compile {"" ""}} {value {"" ""}} {print {"" ""}} {name ""}
+           {noprint} {nocode} {explicit}}
+
+       if {!$nocode} {
+           do_test_ code $exp $result $explicit $name \
+               [list $compile $value $print]
+       }
+       if {!$noprint} {
+           do_test_ print $exp $result $explicit $name \
+               [list $compile $value $print]
+       }
+    }
+
+    # Run a compile test for CMD ("print" or "code").
+
+    proc do_test_ {cmd exp result is_explicit tst fail_list} {
+       variable varName_
+
+       if {![string match $cmd "code"]
+           && ![string match $cmd "print"]} {
+           error "invalid command, $cmd; should be \"print\" or \"compile\""
+       }
+
+       # Get expected result of test.  Will be "" if test is
+       # expected to PASS.
+       lassign $fail_list fail_compile fail_value fail_print
+
+       # Set a test name if one hasn't been provided.
+       if {$tst == ""} {
+           set tst "compile $cmd $exp"
+       }
+
+       if {[string match $cmd "print"]} {
+           if {!$is_explicit} {
+               eval setup_failures_ $fail_print
+               gdb_test "compile print $exp" $result $tst
+           }
+       } else {
+           if {$is_explicit} {
+               set command "compile code $exp"
+           } else {
+               set command "compile code $varName_ = $exp"
+           }
+           eval setup_failures_ $fail_compile
+           gdb_test_no_output $command $tst
+           eval setup_failures_ $fail_value
+           gdb_test "p $varName_" "= $result" "result of $tst"
+       }
+    }
+
+    # A convenience proc used to set up xfail and kfail tests.
+    # HOW is either xfail or kfail (case is ignored).  ARGS is any
+    # optional architecture, bug number, or other string to pass to
+    # respective DejaGNU setup_$how routines.
+
+    proc setup_failures_ {how args} {
+       switch -nocase $how {
+           xfail {
+               eval setup_xfail $args
+           }
+
+           kfail {
+               eval setup_kfail $args
+           }
+
+           default {
+               # Do nothing.  Either the test is expected to PASS
+               # or we have an unhandled failure mode.
+           }
+       }
+    }
+}
diff --git a/include/gcc-cp-fe.def b/include/gcc-cp-fe.def
new file mode 100644 (file)
index 0000000..c367c1d
--- /dev/null
@@ -0,0 +1,1050 @@
+/* Interface between GCC C++ FE and GDB  -*- c -*-
+
+   Copyright (C) 2014-2017 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   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/>.  */
+
+
+
+/* Push namespace NAME as the current binding level, to which
+   newly-introduced decls will be bound.  An empty string identifies
+   the global namespace, whereas NULL identifies an anonymous
+   namespace.  A namespace named NAME is created in the current scope,
+   if needed.
+
+   If the newly-created namespace is to be an inline namespace, see
+   make_namespace_inline.  */
+
+GCC_METHOD1 (int /* bool */, push_namespace,
+            const char *)            /* Argument NAME.  */
+
+/* Push TYPE as the current binding level, making its members visible
+   for name lookup.  The current scope before the call must be the
+   scope in which the class was declared.  This should be used if the
+   definition of a class is already finished, but one wishes to define
+   a nested class, or to enter the scope of one of its member
+   functions.  */
+
+GCC_METHOD1 (int /* bool */, push_class,
+            gcc_type)          /* Argument TYPE.  */
+
+/* Push FUNCTION_DECL as the current (empty) binding level (see
+   reactivate_decl).  The current enclosing scope before the call must
+   be the scope in which the function was declared.  */
+
+GCC_METHOD1 (int /* bool */, push_function,
+            gcc_decl)       /* Argument FUNCTION_DECL.  */
+
+/* Make DECL visible (again?) within SCOPE.  When SCOPE is NULL, it
+   means the current scope; if it is not NULL, it must name a function
+   that is currently active, even if not at the top of the binding
+   chain.
+
+   This function can be used to make e.g. a global function or
+   variable visible in a namespace or local scope (overriding another
+   enclosing definition of the same name), but its most common
+   expected use of this primitive, that gives it its name, is to make
+   declarations visible again after reentering a function scope,
+   because when a function is entered with push_function, that does
+   NOT make any of the declarations nested in it visible for name
+   lookup.
+
+   There is a reason/excuse for that: unlike namespaces and classes,
+   G++ doesn't ever have to reenter function scopes, so its name
+   resolution infrastructure is not prepared to do that.  But wait,
+   there is also a good use for this apparent limitation: a function
+   may contain multiple scopes (blocks), and the name may be bound to
+   different symbols in each of these scopes.  With this interface, as
+   we reenter a function scope, we may choose which symbols to make
+   visible for the code snippet, or, if there could be template
+   functions in local scopes, for unresolved names in nested template
+   class default arguments, or in nested template function signatures.
+
+   As for making a local declaration visible for the code snippet,
+   there are two possibilities: a) introduce it upfront, while
+   entering the scope for the user expression (see the enter_scope
+   callback, called by g++ when encountering the push_user_expression
+   pragma), which might save some scope switching and reactivate_decl
+   (though this can't be helped if some declarations have to be
+   introduced and discarded, because of multiple definitions of the
+   same name in different scopes within a function: they have to be
+   defined in discriminator order); or b) introduce it when its name
+   is looked up, entering the scope, introducing the declaration,
+   leaving the scope, and then reactivating the declaration in its
+   local scope.
+
+   Here's some more detail on how reactivate_decl works.  Say there's
+   a function foo whose body looks like this:
+
+   {
+     {
+// point 1
+       class c {} o __attribute__ ((__used__)); // c  , o
+     }
+     struct c {
+       void f() {
+// point 2
+       }
+     } o __attribute__ ((__used__));            // c_0, o_0
+     {
+       class c {} p __attribute__ ((__used__)); // c_1, p
+// point 3
+       o.f();
+     }
+   }
+
+   When we are about to define class c at point 1, we enter the
+   function foo scope, and since no symbols are visible at point 1, we
+   proceed to declare class c.  We may then define the class right
+   away, or, if we leave the function scope, and we later wish to
+   define it, or to define object o, we can reenter the scope and just
+   use the previously-obtained gcc_decl to define the class, without
+   having to reactivate the declaration.
+
+   Now, if we are to set up the binding context for point 2, we have
+   to define c_0::f, and in order to do so, we have to declare and
+   define c_0.  Before we can declare c_0, we MUST at least declare c.
+
+     As a general rule, before we can declare or define any local name
+     with a discriminator, we have to at least declare any other
+     occurrences of the same name in the same enclosing entity with
+     lower or absent discriminator.
+
+   So, we declare c, then we leave the function scope and reenter it
+   so as to declare c_0 (also with name "c", which is why we have to
+   leave and reenter the function scope, otherwise we would get an
+   error because of the duplicate definition; g++ will assign a
+   discriminator because it still remembers there was an earlier
+   declaration of c_0 within the function, it's just no longer in
+   scope), then we can define c_0, including its member function f.
+
+   Likewise, if we wish to define o_0, we have to define o first.  If
+   we wish to declare (and maybe then define) c_1, we have to at least
+   declare (c and then) c_0 first.
+
+   Then, as we set up the binding context to compile a code snippet at
+   point 3, we may choose to activate c_1, o_0 and p upfront,
+   declaring and discarding c, c_0 and o, and then reentering the
+   funciton scope to declare c_1, o_0 and p; or we can wait for oracle
+   lookups of c, o or p.  If c is looked up, and the debugger resolves
+   c in the scope to c_1, it is expected to enter the function scope
+   from the top level, declare c, leave it, reenter it, declare c_0,
+   leave it, reenter it, declare c_1, leave it, and then reactivate
+   c_1 in the function scope.  If c_1 is needed as a complete type,
+   the definition may be given right after the declaration, or the
+   scope will have to be reentered in order to define the class.
+
+.  If the code snippet is at point 2, we don't need to (re)activate
+   any declaration: nothing from any local scope is visible.  Just
+   entering the scope of the class containing member function f
+   reactivates the names of its members, including the class name
+   itself.  */
+
+GCC_METHOD2 (int /* bool */, reactivate_decl,
+            gcc_decl,          /* Argument DECL.  */
+            gcc_decl)          /* Argument SCOPE.  */
+
+/* Pop the namespace last entered with push_namespace, or class last
+   entered with push_class, or function last entered with
+   push_function, restoring the binding level in effect before the
+   matching push_* call.  */
+
+GCC_METHOD0 (int /* bool */, pop_binding_level)
+
+/* Return the NAMESPACE_DECL, TYPE_DECL or FUNCTION_DECL of the
+   binding level that would be popped by pop_scope.  */
+
+GCC_METHOD0 (gcc_decl, get_current_binding_level_decl)
+
+/* Make the current binding level an inline namespace.  It must be a
+   namespace to begin with.  It is safe to call this more than once
+   for the same namespace, but after the first call, subsequent ones
+   will not return a success status.  */
+
+GCC_METHOD0 (int /* bool */, make_namespace_inline)
+
+/* Add USED_NS to the namespaces used by the current binding level.
+   Use get_current_binding_level_decl to obtain USED_NS's
+   gcc_decl.  */
+
+GCC_METHOD1 (int /* bool */, add_using_namespace,
+            gcc_decl)                  /* Argument USED_NS.  */
+
+/* Introduce a namespace alias declaration, as in:
+
+   namespace foo = [... ::] bar;
+
+   After this call, namespace TARGET will be visible as ALIAS within
+   the current namespace.  Get the declaration for TARGET by calling
+   get_current_binding_level_decl after pushing into it.  */
+
+GCC_METHOD2 (int /* bool */, add_namespace_alias,
+            const char *,              /* Argument ALIAS.  */
+            gcc_decl)                  /* Argument TARGET.  */
+
+/* Introduce a using declaration, as in:
+
+   using foo::bar;
+
+   The TARGET decl names the qualifying scope (foo:: above) and the
+   identifier (bar), but that does not mean that only TARGET will be
+   brought into the current scope: all bindings of TARGET's identifier
+   in the qualifying scope will be brought in.
+
+   FLAGS should specify GCC_CP_SYMBOL_USING.  If the current scope is
+   a class scope, visibility flags must be supplied.
+
+   Even when TARGET is template dependent, we don't need to specify
+   whether or not it is a typename: the supplied declaration (that
+   could be a template-dependent type converted to declaration by
+   get_type_decl) indicates so.  */
+
+GCC_METHOD2 (int /* bool */, add_using_decl,
+            enum gcc_cp_symbol_kind, /* Argument FLAGS.  */
+            gcc_decl)                /* Argument TARGET.  */
+
+/* Create a new "decl" in GCC, and bind it in the current binding
+   level.  A decl is a declaration, basically a kind of symbol.
+
+   NAME is the name of the new symbol.  SYM_KIND is the kind of
+   symbol being requested.  SYM_TYPE is the new symbol's C++ type;
+   except for labels, where this is not meaningful and should be
+   zero.  If SUBSTITUTION_NAME is not NULL, then a reference to this
+   decl in the source will later be substituted with a dereference
+   of a variable of the given name.  Otherwise, for symbols having
+   an address (e.g., functions), ADDRESS is the address.  FILENAME
+   and LINE_NUMBER refer to the symbol's source location.  If this
+   is not known, FILENAME can be NULL and LINE_NUMBER can be 0.
+   This function returns the new decl.
+
+   Use this function to register typedefs, functions and variables to
+   namespace and local binding levels, and typedefs, member functions
+   (static or not), and static data members to class binding levels.
+   Class members must have their access controls specified with
+   GCC_CP_ACCESS_* flags in SYM_KIND.
+
+   Note that, since access controls are disabled, we have no means to
+   express private, protected and public.
+
+   There are various flags that can be set in SYM_KIND to specify
+   additional semantics.  Look for GCC_CP_FLAGs in the definition of
+   enum gcc_cp_symbol_kind in gcc-cp-interface.h.
+
+   In order to define member functions, pass GCC_CP_SYMBOL_FUNCTION in
+   SYM_KIND, and a function_type for static member functions or a
+   method type for non-static member functions, including constructors
+   and destructors.  Use build_function_type to create a function
+   type; for a method type, start by creating a function type without
+   any compiler-introduced artificial arguments (the implicit this
+   pointer, and the __in_chrg added to constructors and destructors,
+   and __vtt_parm added to the former), and then use build_method_type
+   to create the method type out of the class type and the function
+   type.
+
+   For operator functions, set GCC_CP_FLAG_SPECIAL_FUNCTION in
+   SYM_KIND, in addition to any other applicable flags, and pass as
+   NAME a string starting with the two-character mangling for operator
+   name: "ps" for unary plus, "mL" for multiply and assign, *=; etc.
+   Use "cv" for type converstion operators (the target type portion
+   may be omitted, as it is taken from the return type in SYM_TYPE).
+   For operator"", use "li" followed by the identifier (the mangled
+   name mandates digits specifying the length of the identifier; if
+   present, they determine the end of the identifier, otherwise, the
+   identifier extents to the end of the string, so that "li3_Kme" and
+   "li_Km" are equivalent).
+
+   Constructors and destructors need special care, because for each
+   constructor and destructor there may be multiple clones defined
+   internally by the compiler.  With build_decl, you can introduce the
+   base declaration of a constructor or a destructor, setting
+   GCC_CP_FLAG_SPECIAL_FUNCTION the flag and using names starting with
+   capital "C" or "D", respectively, followed by a digit (see below),
+   a blank, or NUL ('\0').  DO NOT supply an ADDRESS or a
+   SUBSTITUTION_NAME to build_decl, it would be meaningless (and
+   rejected) for the base declaration; use define_cdtor_clone to
+   introduce the address of each clone.  For constructor templates,
+   declare the template with build_decl, and then, for each
+   specialization, introduce it with
+   build_function_template_specialization, and then define the
+   addresses of each of its clones with define_cdtor_clone.
+
+   NAMEs for GCC_CP_FLAG_SPECIAL_FUNCTION:
+
+     NAME    meaning
+     C?      constructor base declaration (? may be 1, 2, 4, blank or NUL)
+     D?      destructor base declaration (? may be 0, 1, 2, 4, blank or NUL)
+     nw      operator new
+     na      operator new[]
+     dl      operator delete
+     da      operator delete[]
+     ps      operator + (unary)
+     ng      operator - (unary)
+     ad      operator & (unary)
+     de      operator * (unary)
+     co      operator ~
+     pl      operator +
+     mi      operator -
+     ml      operator *
+     dv      operator /
+     rm      operator %
+     an      operator &
+     or      operator |
+     eo      operator ^
+     aS      operator =
+     pL      operator +=
+     mI      operator -=
+     mL      operator *=
+     dV      operator /=
+     rM      operator %=
+     aN      operator &=
+     oR      operator |=
+     eO      operator ^=
+     ls      operator <<
+     rs      operator >>
+     lS      operator <<=
+     rS      operator >>=
+     eq      operator ==
+     ne      operator !=
+     lt      operator <
+     gt      operator >
+     le      operator <=
+     ge      operator >=
+     nt      operator !
+     aa      operator &&
+     oo      operator ||
+     pp      operator ++
+     mm      operator --
+     cm      operator ,
+     pm      operator ->*
+     pt      operator ->
+     cl      operator ()
+     ix      operator []
+     qu      operator ?
+     cv      operator <T> (conversion operator)
+     li<id>  operator "" <id>
+
+   FIXME: How about attributes?  */
+
+GCC_METHOD7 (gcc_decl, build_decl,
+            const char *,            /* Argument NAME.  */
+            enum gcc_cp_symbol_kind, /* Argument SYM_KIND.  */
+            gcc_type,                /* Argument SYM_TYPE.  */
+            const char *,            /* Argument SUBSTITUTION_NAME.  */
+            gcc_address,             /* Argument ADDRESS.  */
+            const char *,            /* Argument FILENAME.  */
+            unsigned int)            /* Argument LINE_NUMBER.  */
+
+/* Supply the ADDRESS of one of the multiple clones of constructor or
+   destructor CDTOR.  The clone is specified by NAME, using the
+   following name mangling conventions:
+
+     C1      in-charge constructor
+     C2      not-in-charge constructor
+     C4      unified constructor
+     D0      deleting destructor
+     D1      in-charge destructor
+     D2      not-in-charge destructor
+     D4      unified destructor
+
+   The following information is not necessary to use the API.
+
+   C1 initializes an instance of the class (rather than of derived
+   classes), including virtual base classes, whereas C2 initializes a
+   sub-object (of the given class type) of an instance of some derived
+   class (or a full object that doesn't have any virtual base
+   classes).
+
+   D0 and D1 destruct an instance of the class, including virtual base
+   classes, but only the former calls operator delete to release the
+   object's storage at the end; D2 destructs a sub-object (of the
+   given class type) of an instance of a derived class (or a full
+   object that doesn't have any virtual base classes).
+
+   The [CD]4 manglings (and symbol definitions) are non-standard, but
+   GCC uses them in some cases: rather than assuming they are
+   in-charge or not-in-charge, they test the implicit argument that
+   the others ignore to tell how to behave.  These are used instead of
+   cloning when we just can't use aliases.  */
+
+GCC_METHOD3 (gcc_decl, define_cdtor_clone,
+            const char *,            /* Argument NAME.  */
+            gcc_decl,                /* Argument CDTOR.  */
+            gcc_address)             /* Argument ADDRESS.  */
+
+/* Return the type associated with the given declaration.  This is
+   most useful to obtain the type associated with a forward-declared
+   class, because it is the gcc_type, rather than the gcc_decl, that
+   has to be used to build other types, but build_decl returns a
+   gcc_decl rather than a gcc_type.  This call can in theory be used
+   to obtain the type from any other declaration; it is supposed to
+   return the same type that was supplied when the declaration was
+   created.  */
+
+GCC_METHOD1 (gcc_type, get_decl_type,
+            gcc_decl)            /* Argument DECL.  */
+
+/* Return the declaration for a type.  */
+
+GCC_METHOD1 (gcc_decl, get_type_decl,
+            gcc_type)            /* Argument TYPE.  */
+
+/* Declare DECL as a friend of the current class scope, if TYPE is
+   NULL, or of TYPE itself otherwise.  DECL may be a function or a
+   class, be they template generics, template specializations or not
+   templates.  TYPE must be a class type (not a template generic).
+
+   The add_friend call cannot introduce a declaration; even if the
+   friend is first declared as a friend in the source code, the
+   declaration belongs in the enclosing namespace, so it must be
+   introduced in that namespace, and the resulting declaration can
+   then be made a friend.
+
+   DECL cannot, however, be a member of a template class generic,
+   because we have no means to introduce their declarations.  This
+   interface has no notion of definitions for template generics.  As a
+   consequence, users of this interface must introduce each friend
+   template member specialization separately, i.e., instead of:
+
+     template <typename T> friend struct X<T>::M;
+
+   they must be declared as if they were:
+
+     friend struct X<onetype>::M;
+     friend struct X<anothertype>::M;
+     ... for each specialization of X.
+
+
+   Specializations of a template can have each others' members as
+   friends:
+
+     template <typename T> class foo {
+       int f();
+       template <typename U> friend int foo<U>::f();
+     };
+
+   It wouldn't always be possible to define all specializations of a
+   template class before introducing the friend declarations in their
+   expanded, per-specialization form.
+
+   In order to simplify such friend declarations, and to enable
+   incremental friend declarations as template specializations are
+   introduced, add_friend can be called after the befriending class is
+   fully defined, passing it a non-NULL TYPE argument naming the
+   befriending class type.  */
+
+GCC_METHOD2 (int /* bool */, add_friend,
+            gcc_decl,                /* Argument DECL.  */
+            gcc_type)                /* Argument TYPE.  */
+
+/* Return the type of a pointer to a given base type.  */
+
+GCC_METHOD1 (gcc_type, build_pointer_type,
+            gcc_type)                  /* Argument BASE_TYPE.  */
+
+/* Return the type of a reference to a given base type.  */
+
+GCC_METHOD2 (gcc_type, build_reference_type,
+            gcc_type,                  /* Argument BASE_TYPE.  */
+            enum gcc_cp_ref_qualifiers)   /* Argument RQUALS.  */
+
+/* Create a new pointer-to-member type.  MEMBER_TYPE is the data
+   member type, while CLASS_TYPE is the class type containing the data
+   member.  For pointers to member functions, MEMBER_TYPE must be a
+   method type, and CLASS_TYPE must be specified even though it might
+   be possible to extract it from the method type.  */
+
+GCC_METHOD2 (gcc_type, build_pointer_to_member_type,
+            gcc_type,                     /* Argument CLASS_TYPE.  */
+            gcc_type)                     /* Argument MEMBER_TYPE.  */
+
+/* Start a template parameter list scope and enters it, so that
+   subsequent build_type_template_parameter and
+   build_value_template_parameter calls create template parameters in
+   the list.  The list is closed by a build_decl call with
+   GCC_CP_SYMBOL_FUNCTION or GCC_CP_SYMBOL_CLASS, that, when the scope
+   is a template parameter list, declares a template function or a
+   template class with the then-closed parameter list.  The scope in
+   which the new declaration is to be introduced by build_decl must be
+   entered before calling start_template_decl, and build_decl returns
+   to that scope, from the template parameter list scope, before
+   introducing the declaration.  */
+
+GCC_METHOD0 (int /* bool */, start_template_decl)
+
+/* Build a typename template-parameter (e.g., the T in template
+   <typename T = X>).  Either PACK_P should be nonzero, to indicate an
+   argument pack (the last argument in a variadic template argument
+   list, as in template <typename... T>), or DEFAULT_TYPE may be
+   non-NULL to set the default type argument (e.g. X) for the template
+   parameter.  FILENAME and LINE_NUMBER may specify the source
+   location in which the template parameter was declared.  */
+
+GCC_METHOD5 (gcc_type, build_type_template_parameter,
+            const char *,                            /* Argument ID.  */
+            int /* bool */,                      /* Argument PACK_P.  */
+            gcc_type,                      /* Argument DEFAULT_TYPE.  */
+            const char *,                      /* Argument FILENAME.  */
+            unsigned int)                   /* Argument LINE_NUMBER.  */
+
+/* Build a template template-parameter (e.g., the T in template
+   <template <[...]> class T = X>).  DEFAULT_TEMPL may be non-NULL to
+   set the default type-template argument (e.g. X) for the template
+   template parameter.  FILENAME and LINE_NUMBER may specify the
+   source location in which the template parameter was declared.  */
+
+GCC_METHOD5 (gcc_utempl, build_template_template_parameter,
+            const char *,                            /* Argument ID.  */
+            int /* bool */,                      /* Argument PACK_P.  */
+            gcc_utempl,                   /* Argument DEFAULT_TEMPL.  */
+            const char *,                      /* Argument FILENAME.  */
+            unsigned int)                   /* Argument LINE_NUMBER.  */
+
+/* Build a value template-parameter (e.g., the V in template <typename
+   T, T V> or in template <int V = X>).  DEFAULT_VALUE may be non-NULL
+   to set the default value argument for the template parameter (e.g.,
+   X).  FILENAME and LINE_NUMBER may specify the source location in
+   which the template parameter was declared.  */
+
+GCC_METHOD5 (gcc_decl, build_value_template_parameter,
+            gcc_type,                              /* Argument TYPE.  */
+            const char *,                            /* Argument ID.  */
+            gcc_expr,                     /* Argument DEFAULT_VALUE.  */
+            const char *,                      /* Argument FILENAME.  */
+            unsigned int)                   /* Argument LINE_NUMBER.  */
+
+/* Build a template-dependent typename (e.g., typename T::bar or
+   typename T::template bart<X>).  ENCLOSING_TYPE should be the
+   template-dependent nested name specifier (e.g., T), ID should be
+   the name of the member of the ENCLOSING_TYPE (e.g., bar or bart),
+   and TARGS should be non-NULL and specify the template arguments
+   (e.g. <X>) iff ID is to name a class template.
+
+   In this and other calls, a template-dependent nested name specifier
+   may be a template class parameter (build_type_template_parameter),
+   a specialization (returned by build_dependent_type_template_id) of
+   a template template parameter (returned by
+   build_template_template_parameter) or a member type thereof
+   (returned by build_dependent_typename itself).  */
+
+GCC_METHOD3 (gcc_type, build_dependent_typename,
+            gcc_type,                    /* Argument ENCLOSING_TYPE.  */
+            const char *,                            /* Argument ID.  */
+            const struct gcc_cp_template_args *)  /* Argument TARGS.  */
+
+/* Build a template-dependent class template (e.g., T::template bart).
+   ENCLOSING_TYPE should be the template-dependent nested name
+   specifier (e.g., T), ID should be the name of the class template
+   member of the ENCLOSING_TYPE (e.g., bart).  */
+
+GCC_METHOD2 (gcc_utempl, build_dependent_class_template,
+            gcc_type,                    /* Argument ENCLOSING_TYPE.  */
+            const char *)                            /* Argument ID.  */
+
+/* Build a template-dependent type template-id (e.g., T<A>).
+   TEMPLATE_DECL should be a template template parameter (e.g., the T
+   in template <template <[...]> class T = X>), and TARGS should
+   specify the template arguments (e.g. <A>).  */
+
+GCC_METHOD2 (gcc_type, build_dependent_type_template_id,
+            gcc_utempl,                   /* Argument TEMPLATE_DECL.  */
+            const struct gcc_cp_template_args *)  /* Argument TARGS.  */
+
+/* Build a template-dependent expression (e.g., S::val or S::template
+   mtf<X>, or unqualified f or template tf<X>).
+
+   ENCLOSING_SCOPE should be a template-dependent nested name
+   specifier (e.g., T), a resolved namespace or class decl, or NULL
+   for unqualified names; ID should be the name of the member of the
+   ENCLOSING_SCOPE (e.g., val or mtf) or unqualified overloaded
+   function; and TARGS should list template arguments (e.g. <X>) when
+   mtf or tf are to name a template function, or be NULL otherwise.
+
+   Unqualified names and namespace- or class-qualified names can only
+   resolve to overloaded functions, to be used in contexts that
+   involve overload resolution that cannot be resolved because of
+   template-dependent argument or return types, such as call
+   expressions with template-dependent arguments, conversion
+   expressions to function types with template-dependent argument
+   types or the like.  Other cases of unqualified or
+   non-template-dependent-qualified names should NOT use this
+   function, and use decl_expr to convert the appropriate function or
+   object declaration to an expression.
+
+   If ID is the name of a special member function, FLAGS should be
+   GCC_CP_SYMBOL_FUNCTION|GCC_CP_FLAG_SPECIAL_FUNCTION, and ID should
+   be one of the encodings for special member functions documented in
+   build_decl.  Otherwise, FLAGS should be GCC_CP_SYMBOL_MASK, which
+   suggests the symbol kind is not known (though we know it is not a
+   type).
+
+   If ID denotes a conversion operator, CONV_TYPE should name the
+   target type of the conversion.  Otherwise, CONV_TYPE must be
+   NULL.  */
+
+GCC_METHOD5 (gcc_expr, build_dependent_expr,
+            gcc_decl,                   /* Argument ENCLOSING_SCOPE.  */
+            enum gcc_cp_symbol_kind,              /* Argument FLAGS.  */
+            const char *,                          /* Argument NAME.  */
+            gcc_type,                         /* Argument CONV_TYPE.  */
+            const struct gcc_cp_template_args *)  /* Argument TARGS.  */
+
+/* Build a gcc_expr for the value VALUE in type TYPE.  */
+
+GCC_METHOD2 (gcc_expr, build_literal_expr,
+            gcc_type,            /* Argument TYPE.  */
+            unsigned long)       /* Argument VALUE.  */
+
+/* Build a gcc_expr that denotes DECL, the declaration of a variable
+   or function in namespace scope, or of a static member variable or
+   function.  Use QUALIFIED_P to build the operand of unary & so as to
+   compute a pointer-to-member, rather than a regular pointer.  */
+
+GCC_METHOD2 (gcc_expr, build_decl_expr,
+            gcc_decl,                  /* Argument DECL.  */
+            int /* bool */)            /* Argument QUALIFIED_P.  */
+
+/* Build a gcc_expr that denotes the unary operation UNARY_OP applied
+   to the gcc_expr OPERAND.  For non-expr operands, see
+   unary_type_expr.  Besides the UNARY_OP encodings used for operator
+   names, we support "pp_" for preincrement, and "mm_" for
+   predecrement, "nx" for noexcept, "tw" for throw, "tr" for rethrow
+   (pass NULL as the operand), "te" for typeid, "sz" for sizeof, "az"
+   for alignof, "dl" for delete, "gsdl" for ::delete, "da" for
+   delete[], "gsda" for ::delete[], "sp" for pack expansion, "sZ" for
+   sizeof...(function argument pack).  */
+
+GCC_METHOD2 (gcc_expr, build_unary_expr,
+            const char *,        /* Argument UNARY_OP.  */
+            gcc_expr)            /* Argument OPERAND.  */
+
+/* Build a gcc_expr that denotes the binary operation BINARY_OP
+   applied to gcc_exprs OPERAND1 and OPERAND2.  Besides the BINARY_OP
+   encodings used for operator names, we support "ds" for the operator
+   token ".*" and "dt" for the operator token ".".  When using
+   operators that take a name as their second operand ("." and "->")
+   use decl_expr to convert the gcc_decl of the member name to a
+   gcc_expr, if the member name wasn't created with
+   e.g. build_dependent_expr.  */
+
+GCC_METHOD3 (gcc_expr, build_binary_expr,
+            const char *,        /* Argument BINARY_OP.  */
+            gcc_expr,            /* Argument OPERAND1.  */
+            gcc_expr)            /* Argument OPERAND2.  */
+
+/* Build a gcc_expr that denotes the ternary operation TERNARY_OP
+   applied to gcc_exprs OPERAND1, OPERAND2 and OPERAND3.  The only
+   supported TERNARY_OP is "qu", for the "?:" operator.  */
+
+GCC_METHOD4 (gcc_expr, build_ternary_expr,
+            const char *,        /* Argument TERNARY_OP.  */
+            gcc_expr,            /* Argument OPERAND1.  */
+            gcc_expr,            /* Argument OPERAND2.  */
+            gcc_expr)            /* Argument OPERAND3.  */
+
+/* Build a gcc_expr that denotes the unary operation UNARY_OP applied
+   to the gcc_type OPERAND.  Supported unary operations taking types
+   are "ti" for typeid, "st" for sizeof, "at" for alignof, and "sZ"
+   for sizeof...(template argument pack).  */
+
+GCC_METHOD2 (gcc_expr, build_unary_type_expr,
+            const char *,        /* Argument UNARY_OP.  */
+            gcc_type)            /* Argument OPERAND.  */
+
+/* Build a gcc_expr that denotes the binary operation BINARY_OP
+   applied to gcc_type OPERAND1 and gcc_expr OPERAND2.  Use this for
+   all kinds of (single-argument) type casts ("dc", "sc", "cc", "rc"
+   for dynamic, static, const and reinterpret casts, respectively;
+   "cv" for functional or C-style casts).  */
+
+GCC_METHOD3 (gcc_expr, build_cast_expr,
+            const char *,        /* Argument BINARY_OP.  */
+            gcc_type,            /* Argument OPERAND1.  */
+            gcc_expr)            /* Argument OPERAND2.  */
+
+/* Build a gcc_expr that denotes the conversion of an expression list
+   VALUES to TYPE, with ("tl") or without ("cv") braces, or a braced
+   initializer list of unspecified type (e.g., a component of another
+   braced initializer list; pass "il" for CONV_OP, and NULL for
+   TYPE).  */
+
+GCC_METHOD3 (gcc_expr, build_expression_list_expr,
+            const char *,                       /* Argument CONV_OP.  */
+            gcc_type,                              /* Argument TYPE.  */
+            const struct gcc_cp_function_args *) /* Argument VALUES.  */
+
+/* Build a gcc_expr that denotes a new ("nw") or new[] ("na")
+   expression of TYPE, with or without a GLOBAL_NS qualifier (prefix
+   the NEW_OP with "gs"), with or without PLACEMENT, with or without
+   INITIALIZER.  If it's not a placement new, PLACEMENT must be NULL
+   (rather than a zero-length placement arg list).  If there's no
+   specified initializer, INITIALIZER must be NULL; a zero-length arg
+   list stands for a default initializer.  */
+
+GCC_METHOD4 (gcc_expr, build_new_expr,
+            const char *,                             /* Argument NEW_OP.  */
+            const struct gcc_cp_function_args *,   /* Argument PLACEMENT.  */
+            gcc_type,                                   /* Argument TYPE.  */
+            const struct gcc_cp_function_args *) /* Argument INITIALIZER.  */
+
+/* Return a call expression that calls CALLABLE with arguments ARGS.
+   CALLABLE may be a function, a callable object, a pointer to
+   function, an unresolved expression, an unresolved overload set, an
+   object expression combined with a member function overload set or a
+   pointer-to-member.  If QUALIFIED_P, CALLABLE will be interpreted as
+   a qualified name, preventing virtual function dispatch.  */
+
+GCC_METHOD3 (gcc_expr, build_call_expr,
+            gcc_expr,                        /* Argument CALLABLE.  */
+            int /* bool */,               /* Argument QUALIFIED_P.  */
+            const struct gcc_cp_function_args *) /* Argument ARGS.  */
+
+/* Return the type of the gcc_expr OPERAND.
+   Use this for decltype.
+   For decltype (auto), pass a NULL OPERAND.
+
+   Note: for template-dependent expressions, the result is NULL,
+   because the type is only computed when template argument
+   substitution is performed.  */
+
+GCC_METHOD1 (gcc_type, get_expr_type,
+            gcc_expr)            /* Argument OPERAND.  */
+
+/* Introduce a specialization of a template function.
+
+   TEMPLATE_DECL is the template function, and TARGS are the arguments
+   for the specialization.  ADDRESS is the address of the
+   specialization.  FILENAME and LINE_NUMBER specify the source
+   location associated with the template function specialization.  */
+
+GCC_METHOD5 (gcc_decl, build_function_template_specialization,
+            gcc_decl,                     /* Argument TEMPLATE_DECL.  */
+            const struct gcc_cp_template_args *,  /* Argument TARGS.  */
+            gcc_address,                        /* Argument ADDRESS.  */
+            const char *,            /* Argument FILENAME.  */
+            unsigned int)            /* Argument LINE_NUMBER.  */
+
+/* Specialize a template class as an incomplete type.  A definition
+   can be supplied later, with start_class_type.
+
+   TEMPLATE_DECL is the template class, and TARGS are the arguments
+   for the specialization.  FILENAME and LINE_NUMBER specify the
+   source location associated with the template class
+   specialization.  */
+
+GCC_METHOD4 (gcc_decl, build_class_template_specialization,
+            gcc_decl,                     /* Argument TEMPLATE_DECL.  */
+            const struct gcc_cp_template_args *,  /* Argument TARGS.  */
+            const char *,            /* Argument FILENAME.  */
+            unsigned int)            /* Argument LINE_NUMBER.  */
+
+/* Start defining a 'class', 'struct' or 'union' type, entering its
+   own binding level.  Initially it has no fields.
+
+   TYPEDECL is the forward-declaration of the type, returned by
+   build_decl.  BASE_CLASSES indicate the base classes of class NAME.
+   FILENAME and LINE_NUMBER specify the source location associated
+   with the class definition, should they be different from those of
+   the forward declaration.  */
+
+GCC_METHOD4 (gcc_type, start_class_type,
+            gcc_decl,                /* Argument TYPEDECL.  */
+            const struct gcc_vbase_array *,/* Argument BASE_CLASSES.  */
+            const char *,            /* Argument FILENAME.  */
+            unsigned int)            /* Argument LINE_NUMBER.  */
+
+/* Create a new closure class type, record it as the
+   DISCRIMINATOR-numbered closure type in the current scope (or
+   associated with EXTRA_SCOPE, if non-NULL), and enter the closure
+   type's own binding level.  This primitive would sort of combine
+   build_decl and start_class_type, if they could be used to introduce
+   a closure type.  Initially it has no fields.
+
+   FILENAME and LINE_NUMBER specify the source location associated
+   with the class.  EXTRA_SCOPE, if non-NULL, must be a PARM_DECL of
+   the current function, or a FIELD_DECL of the current class.  If it
+   is NULL, the current scope must be a function.  */
+
+GCC_METHOD5 (gcc_type, start_closure_class_type,
+            int,                     /* Argument DISCRIMINATOR.  */
+            gcc_decl,                /* Argument EXTRA_SCOPE.  */
+            enum gcc_cp_symbol_kind, /* Argument FLAGS.  */
+            const char *,            /* Argument FILENAME.  */
+            unsigned int)            /* Argument LINE_NUMBER.  */
+
+/* Add a non-static data member to the most-recently-started
+   unfinished struct or union type.  FIELD_NAME is the field's name.
+   FIELD_TYPE is the type of the field.  BITSIZE and BITPOS indicate
+   where in the struct the field occurs.  */
+
+GCC_METHOD5 (gcc_decl, build_field,
+            const char *,                 /* Argument FIELD_NAME.  */
+            gcc_type,                     /* Argument FIELD_TYPE.  */
+            enum gcc_cp_symbol_kind,      /* Argument FIELD_FLAGS.  */
+            unsigned long,                /* Argument BITSIZE.  */
+            unsigned long)                /* Argument BITPOS.  */
+
+/* After all the fields have been added to a struct, class or union,
+   the struct or union type must be "finished".  This does some final
+   cleanups in GCC, and pops to the binding level that was in effect
+   before the matching start_class_type or
+   start_closure_class_type.  */
+
+GCC_METHOD1 (int /* bool */, finish_class_type,
+            unsigned long)                /* Argument SIZE_IN_BYTES.  */
+
+/* Create a new 'enum' type, and record it in the current binding
+   level.  The new type initially has no associated constants.
+
+   NAME is the enum name.  FILENAME and LINE_NUMBER specify its source
+   location.  */
+
+GCC_METHOD5 (gcc_type, start_enum_type,
+            const char *,            /* Argument NAME.  */
+            gcc_type,                /* Argument UNDERLYING_INT_TYPE. */
+            enum gcc_cp_symbol_kind, /* Argument FLAGS.  */
+            const char *,            /* Argument FILENAME.  */
+            unsigned int)            /* Argument LINE_NUMBER.  */
+
+/* Add a new constant to an enum type.  NAME is the constant's name
+   and VALUE is its value.  Returns a gcc_decl for the constant.  */
+
+GCC_METHOD3 (gcc_decl, build_enum_constant,
+            gcc_type,                 /* Argument ENUM_TYPE.  */
+            const char *,             /* Argument NAME.  */
+            unsigned long)            /* Argument VALUE.  */
+
+/* After all the constants have been added to an enum, the type must
+   be "finished".  This does some final cleanups in GCC.  */
+
+GCC_METHOD1 (int /* bool */, finish_enum_type,
+            gcc_type)                 /* Argument ENUM_TYPE.  */
+
+/* Create a new function type.  RETURN_TYPE is the type returned by
+   the function, and ARGUMENT_TYPES is a vector, of length NARGS, of
+   the argument types.  IS_VARARGS is true if the function is
+   varargs.  */
+
+GCC_METHOD3 (gcc_type, build_function_type,
+            gcc_type,                     /* Argument RETURN_TYPE.  */
+            const struct gcc_type_array *,/* Argument ARGUMENT_TYPES.  */
+            int /* bool */)               /* Argument IS_VARARGS.  */
+
+/* Create a variant of a function type with an exception
+   specification.  FUNCTION_TYPE is a function or method type.
+   EXCEPT_TYPES is an array with the list of exception types.  Zero as
+   the array length implies throw() AKA noexcept(true); NULL as the
+   pointer to gcc_type_array implies noexcept(false), which is almost
+   equivalent (but distinguishable by the compiler) to an unspecified
+   exception list.  */
+
+GCC_METHOD2 (gcc_type, build_exception_spec_variant,
+            gcc_type,                     /* Argument FUNCTION_TYPE.  */
+            const struct gcc_type_array *)/* Argument EXCEPT_TYPES.  */
+
+/* Create a new non-static member function type.  FUNC_TYPE is the
+   method prototype, without the implicit THIS pointer, added as a
+   pointer to the QUALS-qualified CLASS_TYPE.  If CLASS_TYPE is NULL,
+   this creates a cv-qualified (member) function type not associated
+   with any specific class, as needed to support "typedef void f(int)
+   const;", which can later be used to declare member functions and
+   pointers to member functions.  */
+
+GCC_METHOD4 (gcc_type, build_method_type,
+            gcc_type,                     /* Argument CLASS_TYPE.  */
+            gcc_type,                     /* Argument FUNC_TYPE.  */
+            enum gcc_cp_qualifiers,       /* Argument QUALS.  */
+            enum gcc_cp_ref_qualifiers)   /* Argument RQUALS.  */
+
+/* Return a declaration for the (INDEX - 1)th argument of
+   FUNCTION_DECL, i.e., for the first argument, use zero as the index.
+   If FUNCTION_DECL is a non-static member function, use -1 to get the
+   implicit THIS parameter.  */
+
+GCC_METHOD2 (gcc_decl, get_function_parameter_decl,
+            gcc_decl,                       /* Argument FUNCTION_DECL.  */
+            int)                                    /* Argument INDEX.  */
+
+/* Return a lambda expr that constructs an instance of CLOSURE_TYPE.
+   Only lambda exprs without any captures can be correctly created
+   through these mechanisms; that's all we need to support lambdas
+   expressions in default parameters, the only kind that may have to
+   be introduced through this interface.  */
+
+GCC_METHOD1 (gcc_expr, build_lambda_expr,
+            gcc_type)                        /* Argument CLOSURE_TYPE.  */
+
+/* Return an integer type with the given properties.  If BUILTIN_NAME
+   is non-NULL, it must name a builtin integral type with the given
+   signedness and size, and that is the type that will be returned.  */
+
+GCC_METHOD3 (gcc_type, get_int_type,
+            int /* bool */,               /* Argument IS_UNSIGNED.  */
+            unsigned long,                /* Argument SIZE_IN_BYTES.  */
+            const char *)                 /* Argument BUILTIN_NAME.  */
+
+/* Return the 'char' type, a distinct type from both 'signed char' and
+   'unsigned char' returned by int_type.  */
+
+GCC_METHOD0 (gcc_type, get_char_type)
+
+/* Return a floating point type with the given properties.  If BUILTIN_NAME
+   is non-NULL, it must name a builtin integral type with the given
+   signedness and size, and that is the type that will be returned.  */
+
+GCC_METHOD2 (gcc_type, get_float_type,
+            unsigned long,                /* Argument SIZE_IN_BYTES.  */
+            const char *)                 /* Argument BUILTIN_NAME.  */
+
+/* Return the 'void' type.  */
+
+GCC_METHOD0 (gcc_type, get_void_type)
+
+/* Return the 'bool' type.  */
+
+GCC_METHOD0 (gcc_type, get_bool_type)
+
+/* Return the std::nullptr_t type.  */
+
+GCC_METHOD0 (gcc_type, get_nullptr_type)
+
+/* Return the nullptr constant.  */
+
+GCC_METHOD0 (gcc_expr, get_nullptr_constant)
+
+/* Create a new array type.  If NUM_ELEMENTS is -1, then the array
+   is assumed to have an unknown length.  */
+
+GCC_METHOD2 (gcc_type, build_array_type,
+            gcc_type,                    /* Argument ELEMENT_TYPE.  */
+            int)                         /* Argument NUM_ELEMENTS.  */
+
+/* Create a new array type.  NUM_ELEMENTS is a template-dependent
+   expression.  */
+
+GCC_METHOD2 (gcc_type, build_dependent_array_type,
+            gcc_type,                    /* Argument ELEMENT_TYPE.  */
+            gcc_expr)                    /* Argument NUM_ELEMENTS.  */
+
+/* Create a new variably-sized array type.  UPPER_BOUND_NAME is the
+   name of a local variable that holds the upper bound of the array;
+   it is one less than the array size.  */
+
+GCC_METHOD2 (gcc_type, build_vla_array_type,
+            gcc_type,                    /* Argument ELEMENT_TYPE.  */
+            const char *)                /* Argument UPPER_BOUND_NAME.  */
+
+/* Return a qualified variant of a given base type.  QUALIFIERS says
+   which qualifiers to use; it is composed of or'd together
+   constants from 'enum gcc_cp_qualifiers'.  */
+
+GCC_METHOD2 (gcc_type, build_qualified_type,
+            gcc_type,                        /* Argument UNQUALIFIED_TYPE.  */
+            enum gcc_cp_qualifiers)          /* Argument QUALIFIERS.  */
+
+/* Build a complex type given its element type.  */
+
+GCC_METHOD1 (gcc_type, build_complex_type,
+            gcc_type)                    /* Argument ELEMENT_TYPE.  */
+
+/* Build a vector type given its element type and number of
+   elements.  */
+
+GCC_METHOD2 (gcc_type, build_vector_type,
+            gcc_type,                    /* Argument ELEMENT_TYPE.  */
+            int)                         /* Argument NUM_ELEMENTS.  */
+
+/* Build a constant.  NAME is the constant's name and VALUE is its
+   value.  FILENAME and LINE_NUMBER refer to the type's source
+   location.  If this is not known, FILENAME can be NULL and
+   LINE_NUMBER can be 0.  */
+
+GCC_METHOD5 (int /* bool */, build_constant,
+            gcc_type,            /* Argument TYPE.  */
+            const char *,        /* Argument NAME.  */
+            unsigned long,       /* Argument VALUE.  */
+            const char *,        /* Argument FILENAME.  */
+            unsigned int)        /* Argument LINE_NUMBER.  */
+
+/* Emit an error and return an error type object.  */
+
+GCC_METHOD1 (gcc_type, error,
+            const char *)               /* Argument MESSAGE.  */
+
+/* Declare a static_assert with the given CONDITION and ERRORMSG at
+   FILENAME:LINE_NUMBER.  */
+
+GCC_METHOD4 (int /* bool */, add_static_assert,
+            gcc_expr,     /* Argument CONDITION.  */
+            const char *, /* Argument ERRORMSG.  */
+            const char *, /* Argument FILENAME.  */
+            unsigned int) /* Argument LINE_NUMBER.  */
+
+#if 0
+
+/* FIXME: We don't want to expose the internal implementation detail
+   that default parms are stored in function types, and it's not clear
+   how this or other approaches would interact with the type sharing
+   of e.g. ctor clones, so we're leaving this out, since default args
+   are not even present in debug information anyway.  Besides, the set
+   of default args for a function may grow within its scope, and vary
+   independently in other scopes.  */
+
+/* Create a modified version of a function type that has default
+   values for some of its arguments.  The returned type should ONLY be
+   used to define functions or methods, never to declare parameters,
+   variables, types or the like.
+
+   DEFAULTS must have at most as many N_ELEMENTS as there are
+   arguments without default values in FUNCTION_TYPE.  Say, if
+   FUNCTION_TYPE has an argument list such as (T1, T2, T3, T4 = V0)
+   and DEFAULTS has 2 elements (V1, V2), the returned type will have
+   the following argument list: (T1, T2 = V1, T3 = V2, T4 = V0).
+
+   Any NULL expressions in DEFAULTS will be marked as deferred, and
+   they should be filled in with set_deferred_function_default_args.  */
+
+GCC_METHOD2 (gcc_type, add_function_default_args,
+            gcc_type,                       /* Argument FUNCTION_TYPE.  */
+            const struct gcc_cp_function_args *) /* Argument DEFAULTS.  */
+
+/* Fill in the first deferred default args in FUNCTION_DECL with the
+   expressions given in DEFAULTS.  This can be used when the
+   declaration of a parameter is needed to create a default
+   expression, such as taking the size of an earlier parameter, or
+   building a lambda expression in the parameter's context.  */
+
+GCC_METHOD2 (int /* bool */, set_deferred_function_default_args,
+            gcc_decl,                       /* Argument FUNCTION_DECL.  */
+            const struct gcc_cp_function_args *) /* Argument DEFAULTS.  */
+
+#endif
+
+
+/* When you add entry points, add them at the end, so that the new API
+   version remains compatible with the old version.
+
+   The following conventions have been observed as to naming entry points:
+
+   - build_* creates (and maybe records) something and returns it;
+   - add_* creates and records something, but doesn't return it;
+   - get_* obtains something without creating it;
+   - start_* marks the beginning of a compound (type, list, ...);
+   - finish_* completes the compound when needed.
+
+  Entry points that return an int (bool) and don't have a return value
+  specification return nonzero (true) on success and zero (false) on
+  failure.  This is in line with libcc1's conventions of returning a
+  zero-initialized value in case of e.g. a transport error.  */
diff --git a/include/gcc-cp-interface.h b/include/gcc-cp-interface.h
new file mode 100644 (file)
index 0000000..6ef9e22
--- /dev/null
@@ -0,0 +1,496 @@
+/* Interface between GCC C++ FE and GDB
+
+   Copyright (C) 2014-2017 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   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 GCC_CP_INTERFACE_H
+#define GCC_CP_INTERFACE_H
+
+#include "gcc-interface.h"
+
+/* This header defines the interface to the GCC API.  It must be both
+   valid C and valid C++, because it is included by both programs.  */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Forward declaration.  */
+
+struct gcc_cp_context;
+
+/*
+ * Definitions and declarations for the C++ front end.
+ */
+
+/* Defined versions of the C++ front-end API.  */
+
+enum gcc_cp_api_version
+{
+  GCC_CP_FE_VERSION_0 = 0
+};
+
+/* Qualifiers.  */
+
+enum gcc_cp_qualifiers
+{
+  GCC_CP_QUALIFIER_CONST = 1,
+  GCC_CP_QUALIFIER_VOLATILE = 2,
+  GCC_CP_QUALIFIER_RESTRICT = 4
+};
+
+/* Ref qualifiers.  */
+
+enum gcc_cp_ref_qualifiers {
+  GCC_CP_REF_QUAL_NONE = 0,
+  GCC_CP_REF_QUAL_LVALUE = 1,
+  GCC_CP_REF_QUAL_RVALUE = 2
+};
+
+/* Opaque typedef for unbound class templates.  They are used for
+   template arguments, and defaults for template template
+   parameters.  */
+
+typedef unsigned long long gcc_utempl;
+
+/* Opaque typedef for expressions.  They are used for template
+   arguments, defaults for non-type template parameters, and defaults
+   for function arguments.  */
+
+typedef unsigned long long gcc_expr;
+
+typedef enum
+  { GCC_CP_TPARG_VALUE, GCC_CP_TPARG_CLASS,
+    GCC_CP_TPARG_TEMPL, GCC_CP_TPARG_PACK }
+gcc_cp_template_arg_kind;
+
+typedef union
+{ gcc_expr value; gcc_type type; gcc_utempl templ; gcc_type pack; }
+gcc_cp_template_arg;
+
+/* An array of template arguments.  */
+
+struct gcc_cp_template_args
+{
+  /* Number of elements.  */
+
+  int n_elements;
+
+  /* kind[i] indicates what kind of template argument type[i] is.  */
+
+  char /* gcc_cp_template_arg_kind */ *kinds;
+
+  /* The template arguments.  */
+
+  gcc_cp_template_arg *elements;
+};
+
+/* An array of (default) function arguments.  */
+
+struct gcc_cp_function_args
+{
+  /* Number of elements.  */
+
+  int n_elements;
+
+  /* The (default) values for each argument.  */
+
+  gcc_expr *elements;
+};
+
+/* This enumerates the kinds of decls that GDB can create.  */
+
+enum gcc_cp_symbol_kind
+{
+  /* A function.  */
+
+  GCC_CP_SYMBOL_FUNCTION,
+
+  /* A variable.  */
+
+  GCC_CP_SYMBOL_VARIABLE,
+
+  /* A typedef, or an alias declaration (including template ones).  */
+
+  GCC_CP_SYMBOL_TYPEDEF,
+
+  /* A label.  */
+
+  GCC_CP_SYMBOL_LABEL,
+
+  /* A class, forward declared in build_decl (to be later defined in
+     start_class_definition), or, in a template parameter list scope,
+     a declaration of a template class, closing the parameter
+     list.  */
+
+  GCC_CP_SYMBOL_CLASS,
+
+  /* A union, forward declared in build_decl (to be later defined in
+     start_class_definition).  */
+
+  GCC_CP_SYMBOL_UNION,
+
+  /* An enumeration type being introduced with start_new_enum_type.  */
+
+  GCC_CP_SYMBOL_ENUM,
+
+  /* A nonstatic data member being introduced with new_field.  */
+
+  GCC_CP_SYMBOL_FIELD,
+
+  /* A base class in a gcc_vbase_array.  */
+
+  GCC_CP_SYMBOL_BASECLASS,
+
+  /* A using declaration in new_using_decl.  */
+
+  GCC_CP_SYMBOL_USING,
+
+  /* A (lambda) closure class type.  In many regards this is just like
+     a regular class, but it's not supposed to have base classes, some
+     of the member functions that are usually implicitly-defined are
+     deleted, and it should have an operator() member function that
+     holds the lambda body.  We can't instantiate objects of lambda
+     types from the snippet, but we can interact with them in such
+     ways as passing them to functions that take their types, and
+     calling their body.  */
+
+  GCC_CP_SYMBOL_LAMBDA_CLOSURE,
+
+  /* Marker to check that we haven't exceeded GCC_CP_SYMBOL_MASK.  */
+  GCC_CP_SYMBOL_END,
+
+  GCC_CP_SYMBOL_MASK = 15,
+
+  /* When defining a class member, at least one of the
+     GCC_CP_ACCESS_MASK bits must be set; when defining a namespace-
+     or union-scoped symbol, none of them must be set.  */
+
+  GCC_CP_ACCESS_PRIVATE,
+  GCC_CP_ACCESS_PUBLIC = GCC_CP_ACCESS_PRIVATE << 1,
+  GCC_CP_ACCESS_MASK = (GCC_CP_ACCESS_PUBLIC
+                              | GCC_CP_ACCESS_PRIVATE),
+  GCC_CP_ACCESS_PROTECTED = GCC_CP_ACCESS_MASK,
+  GCC_CP_ACCESS_NONE = 0,
+
+  GCC_CP_FLAG_BASE = GCC_CP_ACCESS_PRIVATE << 2,
+
+  /* Flags to be used along with GCC_CP_SYMBOL_FUNCTION:  */
+
+  /* This flag should be set for constructors, destructors and
+     operators.  */
+  GCC_CP_FLAG_SPECIAL_FUNCTION = GCC_CP_FLAG_BASE,
+
+  /* We intentionally cannot express inline, constexpr, or virtual
+     override for functions.  We can't inline or constexpr-replace
+     without a source-level body.  The override keyword is only
+     meaningful within the definition of the containing class.  */
+
+  /* This indicates a "virtual" member function, explicitly or
+     implicitly (due to a virtual function with the same name and
+     prototype in a base class) declared as such.  */
+  GCC_CP_FLAG_VIRTUAL_FUNCTION = GCC_CP_FLAG_BASE << 1,
+
+  /* The following two flags should only be set when the flag above is
+     set.  */
+
+  /* This indicates a pure virtual member function, i.e., one that is
+     declared with "= 0", even if a body is provided in the
+     definition.  */
+  GCC_CP_FLAG_PURE_VIRTUAL_FUNCTION = GCC_CP_FLAG_BASE << 2,
+
+  /* This indicates a "final" virtual member function.  */
+  GCC_CP_FLAG_FINAL_VIRTUAL_FUNCTION = GCC_CP_FLAG_BASE << 3,
+
+  /* This indicates a special member function should have its default
+     implementation.  This either means the function declaration
+     contains the "= default" tokens, or that the member function was
+     implicitly generated by the compiler, although the latter use is
+     discouraged: just let the compiler implicitly introduce it.
+
+     A member function defaulted after its first declaration has
+     slightly different ABI implications from one implicitly generated
+     or explicitly defaulted at the declaration (and definition)
+     point.  To avoid silent (possibly harmless) violation of the one
+     definition rule, it is recommended that this flag not be used for
+     such functions, and that the address of the definition be
+     supplied instead.  */
+  GCC_CP_FLAG_DEFAULTED_FUNCTION = GCC_CP_FLAG_BASE << 4,
+
+  /* This indicates a deleted member function, i.e., one that has been
+     defined as "= delete" at its declaration point, or one that has
+     been implicitly defined as deleted (with or without an explicit
+     "= default" definition).
+
+     This should not be used for implicitly-declared member functions
+     that resolve to deleted definitions, as it may affect the
+     implicit declaration of other member functions.  */
+  GCC_CP_FLAG_DELETED_FUNCTION = GCC_CP_FLAG_BASE << 5,
+
+  /* This indicates a constructor or type-conversion operator declared
+     as "explicit".  */
+
+  GCC_CP_FLAG_EXPLICIT_FUNCTION = GCC_CP_FLAG_BASE << 6,
+
+  GCC_CP_FLAG_END_FUNCTION,
+  GCC_CP_FLAG_MASK_FUNCTION = (((GCC_CP_FLAG_END_FUNCTION - 1) << 1)
+                              - GCC_CP_FLAG_BASE),
+
+  /* Flags to be used along with GCC_CP_SYMBOL_VARIABLE:  */
+
+  /* This indicates a variable declared as "constexpr".  */
+
+  GCC_CP_FLAG_CONSTEXPR_VARIABLE = GCC_CP_FLAG_BASE,
+
+  /* This indicates a variable declared as "thread_local".  ??? What
+     should the ADDRESS be?  */
+
+  GCC_CP_FLAG_THREAD_LOCAL_VARIABLE = GCC_CP_FLAG_BASE << 1,
+
+  GCC_CP_FLAG_END_VARIABLE,
+  GCC_CP_FLAG_MASK_VARIABLE = (((GCC_CP_FLAG_END_VARIABLE - 1) << 1)
+                              - GCC_CP_FLAG_BASE),
+
+  /* Flags to be used when defining nonstatic data members of classes
+     with new_field.  */
+
+  /* Use this when no flags are present.  */
+  GCC_CP_FLAG_FIELD_NOFLAG = 0,
+
+  /* This indicates the field is declared as mutable.  */
+  GCC_CP_FLAG_FIELD_MUTABLE = GCC_CP_FLAG_BASE,
+
+  GCC_CP_FLAG_END_FIELD,
+  GCC_CP_FLAG_MASK_FIELD = (((GCC_CP_FLAG_END_FIELD - 1) << 1)
+                           - GCC_CP_FLAG_BASE),
+
+  /* Flags to be used when defining an enum with
+     start_new_enum_type.  */
+
+  /* This indicates an enum type without any flags.  */
+  GCC_CP_FLAG_ENUM_NOFLAG = 0,
+
+  /* This indicates a scoped enum type.  */
+  GCC_CP_FLAG_ENUM_SCOPED = GCC_CP_FLAG_BASE,
+
+  GCC_CP_FLAG_END_ENUM,
+  GCC_CP_FLAG_MASK_ENUM = (((GCC_CP_FLAG_END_ENUM - 1) << 1)
+                              - GCC_CP_FLAG_BASE),
+
+
+  /* Flags to be used when introducing a class or a class template
+     with build_decl.  */
+
+  /* This indicates an enum type without any flags.  */
+  GCC_CP_FLAG_CLASS_NOFLAG = 0,
+
+  /* This indicates the class is actually a struct.  This has no
+     effect whatsoever on access control in this interface, since all
+     class members must have explicit access control bits set, but it
+     may affect error messages.  */
+  GCC_CP_FLAG_CLASS_IS_STRUCT = GCC_CP_FLAG_BASE,
+
+  GCC_CP_FLAG_END_CLASS,
+  GCC_CP_FLAG_MASK_CLASS = (((GCC_CP_FLAG_END_CLASS - 1) << 1)
+                              - GCC_CP_FLAG_BASE),
+
+
+  /* Flags to be used when introducing a virtual base class in a
+     gcc_vbase_array.  */
+
+  /* This indicates an enum type without any flags.  */
+  GCC_CP_FLAG_BASECLASS_NOFLAG = 0,
+
+  /* This indicates the class is actually a struct.  This has no
+     effect whatsoever on access control in this interface, since all
+     class members must have explicit access control bits set, but it
+     may affect error messages.  */
+  GCC_CP_FLAG_BASECLASS_VIRTUAL = GCC_CP_FLAG_BASE,
+
+  GCC_CP_FLAG_END_BASECLASS,
+  GCC_CP_FLAG_MASK_BASECLASS = (((GCC_CP_FLAG_END_BASECLASS - 1) << 1)
+                               - GCC_CP_FLAG_BASE),
+
+
+  GCC_CP_FLAG_MASK = (GCC_CP_FLAG_MASK_FUNCTION
+                     | GCC_CP_FLAG_MASK_VARIABLE
+                     | GCC_CP_FLAG_MASK_FIELD
+                     | GCC_CP_FLAG_MASK_ENUM
+                     | GCC_CP_FLAG_MASK_CLASS
+                     | GCC_CP_FLAG_MASK_BASECLASS
+                     )
+};
+
+
+/* An array of types used for creating lists of base classes.  */
+
+struct gcc_vbase_array
+{
+  /* Number of elements.  */
+
+  int n_elements;
+
+  /* The base classes.  */
+
+  gcc_type *elements;
+
+  /* Flags for each base class.  Used to indicate access control and
+     virtualness.  */
+
+  enum gcc_cp_symbol_kind *flags;
+};
+
+
+/* This enumerates the types of symbols that GCC might request from
+   GDB.  */
+
+enum gcc_cp_oracle_request
+{
+  /* An identifier in namespace scope -- type, variable, function,
+     namespace, template.  All namespace-scoped symbols with the
+     requested name, in any namespace (including the global
+     namespace), should be defined in response to this request.  */
+
+  GCC_CP_ORACLE_IDENTIFIER
+};
+
+/* The type of the function called by GCC to ask GDB for a symbol's
+   definition.  DATUM is an arbitrary value supplied when the oracle
+   function is registered.  CONTEXT is the GCC context in which the
+   request is being made.  REQUEST specifies what sort of symbol is
+   being requested, and IDENTIFIER is the name of the symbol.  */
+
+typedef void gcc_cp_oracle_function (void *datum,
+                                    struct gcc_cp_context *context,
+                                    enum gcc_cp_oracle_request request,
+                                    const char *identifier);
+
+/* The type of the function called by GCC to ask GDB for a symbol's
+   address.  This should return 0 if the address is not known.  */
+
+typedef gcc_address gcc_cp_symbol_address_function (void *datum,
+                                                   struct gcc_cp_context *ctxt,
+                                                   const char *identifier);
+
+/* The type of the function called by GCC to ask GDB to enter or leave
+   the user expression scope.  */
+
+typedef void gcc_cp_enter_leave_user_expr_scope_function (void *datum,
+                                                         struct gcc_cp_context
+                                                         *context);
+
+/* The vtable used by the C front end.  */
+
+struct gcc_cp_fe_vtable
+{
+  /* The version of the C interface.  The value is one of the
+     gcc_cp_api_version constants.  */
+
+  unsigned int cp_version;
+
+  /* Set the callbacks for this context.
+
+     The binding oracle is called whenever the C++ parser needs to
+     look up a symbol.  This gives the caller a chance to lazily
+     instantiate symbols using other parts of the gcc_cp_fe_interface
+     API.  The symbol is looked up without a scope, and the oracle
+     must supply a definition for ALL namespace-scoped definitions
+     bound to the symbol.
+
+     The address oracle is called whenever the C++ parser needs to
+     look up a symbol.  This may be called for symbols not provided by
+     the symbol oracle, such as built-in functions where GCC provides
+     the declaration; other internal symbols, such as those related
+     with thunks, rtti, and virtual tables are likely to be queried
+     through this interface too.  The identifier is a mangled symbol
+     name.
+
+     DATUM is an arbitrary piece of data that is passed back verbatim
+     to the callbacks in requests.  */
+
+  void (*set_callbacks) (struct gcc_cp_context *self,
+                        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);
+
+#define GCC_METHOD0(R, N) \
+  R (*N) (struct gcc_cp_context *);
+#define GCC_METHOD1(R, N, A) \
+  R (*N) (struct gcc_cp_context *, A);
+#define GCC_METHOD2(R, N, A, B) \
+  R (*N) (struct gcc_cp_context *, A, B);
+#define GCC_METHOD3(R, N, A, B, C) \
+  R (*N) (struct gcc_cp_context *, A, B, C);
+#define GCC_METHOD4(R, N, A, B, C, D) \
+  R (*N) (struct gcc_cp_context *, A, B, C, D);
+#define GCC_METHOD5(R, N, A, B, C, D, E) \
+  R (*N) (struct gcc_cp_context *, A, B, C, D, E);
+#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \
+  R (*N) (struct gcc_cp_context *, A, B, C, D, E, F, G);
+
+#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
+
+};
+
+/* The C front end object.  */
+
+struct gcc_cp_context
+{
+  /* Base class.  */
+
+  struct gcc_base_context base;
+
+  /* Our vtable.  This is a separate field because this is simpler
+     than implementing a vtable inheritance scheme in C.  */
+
+  const struct gcc_cp_fe_vtable *cp_ops;
+};
+
+/* The name of the .so that the compiler builds.  We dlopen this
+   later.  */
+
+#define GCC_CP_FE_LIBCC libcc1.so
+
+/* The compiler exports a single initialization function.  This macro
+   holds its name as a symbol.  */
+
+#define GCC_CP_FE_CONTEXT gcc_cp_fe_context
+
+/* The type of the initialization function.  The caller passes in the
+   desired base version and desired C-specific version.  If the
+   request can be satisfied, a compatible gcc_context object will be
+   returned.  Otherwise, the function returns NULL.  */
+
+typedef struct gcc_cp_context *gcc_cp_fe_context_function
+    (enum gcc_base_api_version,
+     enum gcc_cp_api_version);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GCC_CP_INTERFACE_H */