[9/9] C++ compile support

Message ID 20180810232534.481-10-keiths@redhat.com
State New, archived
Headers

Commit Message

Keith Seitz Aug. 10, 2018, 11:25 p.m. UTC
  This patch adds *basic* support for C++ to the compile feature.  It does
most simple type conversions, including everything that C compile does and
your basic "with-classes" type of C++.

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

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

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

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

gdb/ChangeLog:

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

gdb/testsuite/ChangeLog:

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

doc/ChangeLog:

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

Comments

Eli Zaretskii Aug. 11, 2018, 7:22 a.m. UTC | #1
> From: Keith Seitz <keiths@redhat.com>
> Date: Fri, 10 Aug 2018 16:25:34 -0700
> 
> This initial support has several glaring omissions:
> - No template support at all
>   I have follow-on patches for this, but they add much complexity
>   to this "basic" support.  Consequently, they will be submitted separately.
> - Cannot print functions
>   The code template needs tweaking, and I simply haven't gotten to it yet.
> - So-called "special function" support is not included
>   Using constructors, destructors, operators, etc will not work. I have
>   follow-on patches for that, but they require some work because of the
>   recent churn in symbol searching.
> - There are several test suite references to "compile/1234" bugs.
>   I will file bugs and update the test suite's bug references before pushing
>   these patches.

Shouldn't these omissions be mentioned somewhere?  Like in NEWS?

> +* GDB now has experimental support for the compilation and injection of
> +  C++ source code into the inferior.  This feature requires the GCC C++
> +  plug-in available since GCC 7.1.

The last sentence basically means "only on ELF platforms", right?  So
IMO this limitation should be stated explicitly, lest people get
excited, and then get disappointed.

> +set debug compile-oracle
> +show debug compile-oracle
> +  Control the display of debug output about symbol requests from
> +  the compiler plug-in.
> +
> +set debug compile-cplus-types
> +show debug compile-cplus-types
> +  Control the display of debug output about C++ type conversion
> +  in the compile feature.

I suggest to mention that these commands are only available/have
effect if the C++ compilation is supported.

> +@anchor{set debug compile-oracle}
> +@item set debug compile-oracle
> +@cindex compile oracle debugging info
> +Turns on or off display of symbol requests from the compiler plug-in
> +(the ``oracle'').  The default is off.

@dfn{oracle} should render better.  In any case, why do we call this
"the oracle"?  In the computing context, "oracle" has connotations
that we don't necessarily want to encourage, I think.  Why not
something like "set debug symbol-requests"?

> +Turns on or off the display of C++ type conversion debugging information.

Please use C@t{++} for C++ in the text, it renders better in the
printed manual.

OK for the documentation parts, with those nits fixed.

Thanks.
  
Tom Tromey Aug. 12, 2018, 12:16 a.m. UTC | #2
>>>>> "Keith" == Keith Seitz <keiths@redhat.com> writes:

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

Thanks for doing this.  This is very good.

Keith> +extern compile_instance *cplus_get_compile_context (void);

I think we stopped using (void) now.

Keith> +typedef compile_program<compile_cplus_instance,
Keith> +			cplus_push_user_expression, cplus_pop_user_expression,
Keith> +			cplus_add_code_header, c_add_code_footer,
Keith> +			cplus_add_input> cplus_compile_program;
Keith> +

Haha, this seemed like overkill to me, but I see it's already this way,
and it doesn't really matter I think.

Keith> diff --git a/gdb/compile/compile-cplus-support.c b/gdb/compile/compile-cplus-support.c
Keith> new file mode 100644
Keith> index 0000000000..42fc7692c4
[...]
Keith> +void
Keith> +gcc_cplus_enter_scope (void *datum, struct gcc_cp_context *gcc_context)
Keith> +{
Keith> +}
Keith> +
Keith> +void
Keith> +gcc_cplus_leave_scope (void *datum, struct gcc_cp_context *gcc_context)
Keith> +{
Keith> +}

Is this something that gets expanded in later patches?

If not, I'd suggest just making these private static methods on
compile_cplus_instance, to avoid needing a new file.

On the other hand, if this is expanded in the future, then it is totally
fine like this.

Keith> +/* Convert a given symbol, SYM, to the compiler's representation.
Keith> +   INSTANCE is the compiler instance.  IS_GLOBAL is true if the
Keith> +   symbol came from the global scope.  IS_LOCAL is true if the symbol
Keith> +   came from a local scope.  (Note that the two are not strictly
Keith> +   inverses because the symbol might have come from the static
Keith> +   scope.)  */
Keith> +
Keith> +static void
Keith> +convert_one_symbol (compile_cplus_instance *instance,
Keith> +		    struct block_symbol sym, bool is_global, bool is_local)

I think back in the day, I'd hoped that there would be more code sharing
between the C and C++ compile paths.  But maybe this wasn't possible?  I
didn't do a deep comparison or anything.  And it's fine if they have to
be separate.

Keith> +void _initialize_compile_cplus_symbols (void);

I think this declaration isn't needed any more.

Keith> +/* See description in compile-cplus.h.  */
Keith> +
Keith> +gdb::unique_xmalloc_ptr<char>
Keith> +decl_name (const char *natural)

This should return a std::string.  See below.

Keith> +      std::string symbol = (comp.bsymbol.symbol != nullptr
Keith> +			    ? SYMBOL_NATURAL_NAME (comp.bsymbol.symbol)
Keith> +			    : "<none>");

This could just be a const char * to avoid an allocation.

Keith> +/* Utility function to convert CODE into a string.  */
Keith> +
Keith> +static const char *
Keith> +type_code_to_string (enum type_code code)
Keith> +{
Keith> +  const char * const s[] =
Keith> +    {"BISTRING (deprecated)", "UNDEF (not used)",
Keith> +     "PTR", "ARRAY", "STRUCT", "UNION", "ENUM",
Keith> +     "FLAGS", "FUNC", "INT", "FLT", "VOID",
Keith> +     "SET", "RANGE", "STRING", "ERROR", "METHOD",
Keith> +     "METHODPTR", "MEMBERPTR", "REF", "RVALUE_REF", "CHAR", "BOOL",
Keith> +     "COMPLEX", "TYPEDEF", "NAMESPACE", "DECFLOAT", "MODULE",
Keith> +     "INTERNAL_FUNCTION", "XMETHOD"};
Keith> +
Keith> +  return s[code + 1];

This could get out of sync with gdbtypes.h.  So I'd suggest either (1)
taking the simple route and printing this as an integer; or (2) moving
the enum to a .defs file and auto-generating the strings from it, to
avoid any possibility of problems.  In case 2, type_code_to_string could
move to gdbtypes.c.

Keith> +	  scope_component comp
Keith> +	    = {
Keith> +	        decl_name (TYPE_NAME (type)).release (),
Keith> +		lookup_symbol (TYPE_NAME (type), block (), VAR_DOMAIN, nullptr)

scope_component::name is a std::string, so I think this decl_name call
will leak memory; which is why decl_name should return a std::string
itself.

Keith> +/* Return the declaration name of the symbol named NATURAL.
Keith> +   This returns a name with no function arguments or template parameters,
Keith> +   suitable for passing to the compiler plug-in.  */
Keith> +
Keith> +gdb::unique_xmalloc_ptr<char> decl_name (const char *natural);

This seems like a fairly generic name for something that is maybe
specific to the C++ compile code.

Tom
  
Keith Seitz Aug. 17, 2018, 5:50 p.m. UTC | #3
On 08/11/2018 12:22 AM, Eli Zaretskii wrote:
>> From: Keith Seitz <keiths@redhat.com>
>> Date: Fri, 10 Aug 2018 16:25:34 -0700
>>
>> This initial support has several glaring omissions:
>> - No template support at all
>>   I have follow-on patches for this, but they add much complexity
>>   to this "basic" support.  Consequently, they will be submitted separately.
>> - Cannot print functions
>>   The code template needs tweaking, and I simply haven't gotten to it yet.
>> - So-called "special function" support is not included
>>   Using constructors, destructors, operators, etc will not work. I have
>>   follow-on patches for that, but they require some work because of the
>>   recent churn in symbol searching.
>> - There are several test suite references to "compile/1234" bugs.
>>   I will file bugs and update the test suite's bug references before pushing
>>   these patches.
> 
> Shouldn't these omissions be mentioned somewhere?  Like in NEWS?

To be honest, I was hesitant to even mention this in NEWS at all (yet).
The code is *very* beta and incomplete (as you can see). That's why the
"experimental" moniker. Nonetheless, assuming we want to mention it, I've
changed the entry to:

* GDB now has experimental support for the compilation and injection of
  C++ source code into the inferior.  This beta release does not include
  support for several language features, such as templates, constructors,
  and operators.

> 
>> +* GDB now has experimental support for the compilation and injection of
>> +  C++ source code into the inferior.  This feature requires the GCC C++
>> +  plug-in available since GCC 7.1.
> 
> The last sentence basically means "only on ELF platforms", right?  So
> IMO this limitation should be stated explicitly, lest people get
> excited, and then get disappointed.

I'm not sure how to answer this. That seems like enumerating all the dependencies
of every dependency GDB has (bfd, libiberty, bison, etc). The feature (like the
C compile feature already included) requires the compiler plug-in. Whatever that
plug-in supports is what GDB supports.

Would you like me to include something like: "Currently tested on x86_64
GNU/Linux." That tells readers what is known to work without suggesting
all possible permutations of host/OS that might work [but are untested
AFAIK].

>> +set debug compile-oracle
>> +show debug compile-oracle
>> +  Control the display of debug output about symbol requests from
>> +  the compiler plug-in.
>> +
>> +set debug compile-cplus-types
>> +show debug compile-cplus-types
>> +  Control the display of debug output about C++ type conversion
>> +  in the compile feature.
> 
> I suggest to mention that these commands are only available/have
> effect if the C++ compilation is supported.

Maybe this is better/clearer?

set debug compile-cplus-types
show debug compile-cplus-types
  Control the display of debug output about type conversion in the
  C++ compile feature.  Commands have no effect while compiling for
  other languages.


>> +@anchor{set debug compile-oracle}
>> +@item set debug compile-oracle
>> +@cindex compile oracle debugging info
>> +Turns on or off display of symbol requests from the compiler plug-in
>> +(the ``oracle'').  The default is off.
> 
> @dfn{oracle} should render better.  In any case, why do we call this
> "the oracle"?  In the computing context, "oracle" has connotations
> that we don't necessarily want to encourage, I think.  Why not
> something like "set debug symbol-requests"?

This symbol resolver design is called the "oracle" internally (see also
references to this name in the Wiki page describing the compile project,
https://sourceware.org/gdb/wiki/GCCCompileAndExecute ).

Nonetheless, on second thought, it seems almost nonsensical to have a
special debug flag just for this. So I've removed the option and just
added the "oracle" debug output when the "normal" compile debug flag
is set. WDYT?

>> +Turns on or off the display of C++ type conversion debugging information.
> 
> Please use C@t{++} for C++ in the text, it renders better in the
> printed manual.

Done.

Would you like me to repost this patch?

Keith
  
Eli Zaretskii Aug. 17, 2018, 6:57 p.m. UTC | #4
> Cc: gdb-patches@sourceware.org
> From: Keith Seitz <keiths@redhat.com>
> Date: Fri, 17 Aug 2018 10:50:53 -0700
> 
> * GDB now has experimental support for the compilation and injection of
>   C++ source code into the inferior.  This beta release does not include
>   support for several language features, such as templates, constructors,
>   and operators.

This is fine, thanks.

> >> +* GDB now has experimental support for the compilation and injection of
> >> +  C++ source code into the inferior.  This feature requires the GCC C++
> >> +  plug-in available since GCC 7.1.
> > 
> > The last sentence basically means "only on ELF platforms", right?  So
> > IMO this limitation should be stated explicitly, lest people get
> > excited, and then get disappointed.
> 
> I'm not sure how to answer this. That seems like enumerating all the dependencies
> of every dependency GDB has (bfd, libiberty, bison, etc). The feature (like the
> C compile feature already included) requires the compiler plug-in. Whatever that
> plug-in supports is what GDB supports.

It is okay to say that this is supported only on platforms where
libcc1.so and the 'compile' command are available.  My problem was
with not qualifying this at all.

> Would you like me to include something like: "Currently tested on x86_64
> GNU/Linux."

Using "currently" is generally not advisable, as the meaning of that
word changes with time.

> >> +set debug compile-oracle
> >> +show debug compile-oracle
> >> +  Control the display of debug output about symbol requests from
> >> +  the compiler plug-in.
> >> +
> >> +set debug compile-cplus-types
> >> +show debug compile-cplus-types
> >> +  Control the display of debug output about C++ type conversion
> >> +  in the compile feature.
> > 
> > I suggest to mention that these commands are only available/have
> > effect if the C++ compilation is supported.
> 
> Maybe this is better/clearer?
> 
> set debug compile-cplus-types
> show debug compile-cplus-types
>   Control the display of debug output about type conversion in the
>   C++ compile feature.  Commands have no effect while compiling for
>   other languages.

Yes, better.

> Nonetheless, on second thought, it seems almost nonsensical to have a
> special debug flag just for this. So I've removed the option and just
> added the "oracle" debug output when the "normal" compile debug flag
> is set. WDYT?

OK.

> Would you like me to repost this patch?

That won't be needed, thanks.
  
Keith Seitz Aug. 20, 2018, 5:02 p.m. UTC | #5
On 08/17/2018 11:57 AM, Eli Zaretskii wrote:
>> I'm not sure how to answer this. That seems like enumerating all the dependencies
>> of every dependency GDB has (bfd, libiberty, bison, etc). The feature (like the
>> C compile feature already included) requires the compiler plug-in. Whatever that
>> plug-in supports is what GDB supports.
> 
> It is okay to say that this is supported only on platforms where
> libcc1.so and the 'compile' command are available.  My problem was
> with not qualifying this at all.

Gotcha. I've "copied" the announcement text from the original (C) compile
submission talking about compiler requirement:

 
  This feature requires GCC 7.1 or higher built with libcp1.so
  (the C++ plug-in).

>> Would you like me to include something like: "Currently tested on x86_64
>> GNU/Linux."
> 
> Using "currently" is generally not advisable, as the meaning of that
> word changes with time.

Indeed! I've removed this text in favor of the above requirement statement.

>> Would you like me to repost this patch?
> 
> That won't be needed, thanks.

Thank you for your comments/suggestions!

Keith
  

Patch

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index e12c54983c..c03dbbfec4 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,35 @@ 
 YYYY-MM-DD  Keith Seitz  <keiths@redhat.com>
 
+	* Makefile.in (SUBDIR_GCC_COMPILE_SRCS): Add compile-cplus-support.c,
+	compile-cplus-symbols.c, and compile-cplus-types.c.
+	(HFILES_NO_SRCDIR): Add gcc-cp-plugin.h.
+	* c-lang.c (cplus_language_defn): Set C++ compile functions.
+	* c-lang.h (cplus_get_compile_context, cplus_compute_program):
+	Declare.
+	* compile/compile-c-support.c: Include compile-cplus.h.
+	(load_libcompile): Templatize.
+	(get_compile_context): "New" function.
+	(c_get_compile_context): Use get_compile_context.
+	(cplus_get_compile_context): New function.
+	(cplus_push_user_expression, cplus_pop_user_expression)
+	(cplus_add_code_header, cplus_add_input, cplus_compile_program)
+	(cplus_compute_program): Define new structs/functions.
+	* compile/compile-cplus-support.c: New file.
+	* compile/compile-cplus-symmbols.c: New file.
+	* compile/compile-cplus-types.c: New file.
+	* compile/compile-cplus.h: New file.
+	* compile/compile-internal.h (debug_compile_oracle, GCC_TYPE_NONE):
+	Declare.
+	* compile/compile-object-load.c (get_out_value_type): Use
+	strncmp_iw when comparing symbol names.
+	(compile_object_load): Add mst_bss and mst_data.
+	* compile/compile.c (_initialize_compile): Remove
+	-Wno-implicit-function-declaration from `compile_args'.
+	* compile/gcc-cp-plugin.h: New file.
+	* NEWS: Mention C++ compile support and new debug options.
+
+YYYY-MM-DD  Keith Seitz  <keiths@redhat.com>
+
 	* linespec.c (collect_info::add_symbol): Make virtual.
 	(struct symbol_searcher_collect_info): New struct.
 	(symbol_searcher::find_all_symbols): New method.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 118c3c8062..9163e04d14 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -317,6 +317,9 @@  SUBDIR_GCC_COMPILE_SRCS = \
 	compile/compile-c-support.c \
 	compile/compile-c-symbols.c \
 	compile/compile-c-types.c \
+	compile/compile-cplus-support.c \
+	compile/compile-cplus-symbols.c \
+	compile/compile-cplus-types.c \
 	compile/compile-loc2c.c \
 	compile/compile-object-load.c \
 	compile/compile-object-run.c
@@ -1461,10 +1464,12 @@  HFILES_NO_SRCDIR = \
 	common/xml-utils.h \
 	compile/compile.h \
 	compile/compile-c.h \
+	compile/compile-cplus.h \
 	compile/compile-internal.h \
 	compile/compile-object-load.h \
 	compile/compile-object-run.h \
 	compile/gcc-c-plugin.h \
+	compile/gcc-cp-plugin.h \
 	config/nm-linux.h \
 	config/nm-nto.h \
 	config/djgpp/langinfo.h \
diff --git a/gdb/NEWS b/gdb/NEWS
index f275031345..cfc7789a9f 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,10 @@ 
 
 *** Changes since GDB 8.2
 
+* GDB now has experimental support for the compilation and injection of
+  C++ source code into the inferior.  This feature requires the GCC C++
+  plug-in available since GCC 7.1.
+ 
 * GDB and GDBserver now support IPv6 connections.  IPv6 addresses
   can be passed using the '[ADDRESS]:PORT' notation, or the regular
   'ADDRESS:PORT' method.
@@ -12,6 +16,16 @@ 
 
 * New commands
 
+set debug compile-oracle
+show debug compile-oracle
+  Control the display of debug output about symbol requests from
+  the compiler plug-in.
+
+set debug compile-cplus-types
+show debug compile-cplus-types
+  Control the display of debug output about C++ type conversion
+  in the compile feature.
+
 frame apply [all | COUNT | -COUNT | level LEVEL...] [FLAG]... COMMAND
   Apply a command to some frames.
   FLAG arguments allow to control what output to produce and how to handle
diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index 5ad580182c..6bae4c18ec 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -1017,8 +1017,8 @@  extern const struct language_defn cplus_language_defn =
   iterate_over_symbols,
   cp_search_name_hash,
   &cplus_varobj_ops,
-  NULL,
-  NULL,
+  cplus_get_compile_context,
+  cplus_compute_program,
   LANG_MAGIC
 };
 
diff --git a/gdb/c-lang.h b/gdb/c-lang.h
index b7bf08992b..9719ad50aa 100644
--- a/gdb/c-lang.h
+++ b/gdb/c-lang.h
@@ -160,6 +160,14 @@  extern int c_textual_element_type (struct type *, char);
 
 extern compile_instance *c_get_compile_context (void);
 
+/* Create a new instance of the C++ compiler and return it.  The new
+   compiler is owned by the caller and must be freed using the destroy
+   method.  This function never returns NULL, but rather throws an
+   exception on failure.  This is suitable for use as the
+   la_get_compile_instance language method.  */
+
+extern compile_instance *cplus_get_compile_context (void);
+
 /* This takes the user-supplied text and returns a new bit of code to
    compile.
 
@@ -172,4 +180,15 @@  extern std::string c_compute_program (compile_instance *inst,
 				      const struct block *expr_block,
 				      CORE_ADDR expr_pc);
 
+/* This takes the user-supplied text and returns a new bit of code to compile.
+
+   This is used as the la_compute_program language method; see that
+   for a description of the arguments.  */
+
+extern std::string cplus_compute_program (compile_instance *inst,
+					  const char *input,
+					  struct gdbarch *gdbarch,
+					  const struct block *expr_block,
+					  CORE_ADDR expr_pc);
+
 #endif /* !defined (C_LANG_H) */
diff --git a/gdb/compile/compile-c-support.c b/gdb/compile/compile-c-support.c
index e8993aa5eb..4c7893cf06 100644
--- a/gdb/compile/compile-c-support.c
+++ b/gdb/compile/compile-c-support.c
@@ -1,4 +1,4 @@ 
-/* C language support for compilation.
+/* C/C++ language support for compilation.
 
    Copyright (C) 2014-2018 Free Software Foundation, Inc.
 
@@ -20,6 +20,7 @@ 
 #include "defs.h"
 #include "compile-internal.h"
 #include "compile-c.h"
+#include "compile-cplus.h"
 #include "compile.h"
 #include "gdb-dlfcn.h"
 #include "c-lang.h"
@@ -67,25 +68,22 @@  c_get_range_decl_name (const struct dynamic_prop *prop)
 
 
 
-/* Helper function for c_get_compile_context.  Open the GCC front-end
-   shared library and return the symbol specified by the current
-   GCC_C_FE_CONTEXT.  */
+/* Load the plug-in library FE_LIBCC and return the initialization function
+   FE_CONTEXT.  */
 
-static gcc_c_fe_context_function *
-load_libcc (void)
+template <typename FUNCTYPE>
+FUNCTYPE *
+load_libcompile (const char *fe_libcc, const char *fe_context)
 {
-  gcc_c_fe_context_function *func;
+  FUNCTYPE *func;
 
-   /* gdb_dlopen will call error () on an error, so no need to check
-      value.  */
-  gdb_dlhandle_up handle = gdb_dlopen (STRINGIFY (GCC_C_FE_LIBCC));
-  func = (gcc_c_fe_context_function *) gdb_dlsym (handle,
-						  STRINGIFY (GCC_C_FE_CONTEXT));
+  /* gdb_dlopen will call error () on an error, so no need to check
+     value.  */
+  gdb_dlhandle_up handle = gdb_dlopen (fe_libcc);
+  func = (FUNCTYPE *) gdb_dlsym (handle, fe_context);
 
   if (func == NULL)
-    error (_("could not find symbol %s in library %s"),
-	   STRINGIFY (GCC_C_FE_CONTEXT),
-	   STRINGIFY (GCC_C_FE_LIBCC));
+    error (_("could not find symbol %s in library %s"), fe_context, fe_libcc);
 
   /* Leave the library open.  */
   handle.release ();
@@ -93,28 +91,57 @@  load_libcc (void)
 }
 
 /* Return the compile instance associated with the current context.
-   This function calls the symbol returned from the load_libcc
-   function.  This will provide the gcc_c_context.  */
+   This function calls the symbol returned from the load_libcompile
+   function.  FE_LIBCC is the library to load.  BASE_VERSION is the
+   base compile plug-in version we support.  API_VERSION is the
+   API version supported.  */
 
+template <typename INSTTYPE, typename FUNCTYPE, typename CTXTYPE,
+	  typename BASE_VERSION_TYPE, typename API_VERSION_TYPE>
 compile_instance *
-c_get_compile_context (void)
+get_compile_context (const char *fe_libcc, const char *fe_context,
+		     BASE_VERSION_TYPE base_version,
+		     API_VERSION_TYPE api_version)
 {
-  static gcc_c_fe_context_function *func;
-
-  struct gcc_c_context *context;
+  static FUNCTYPE *func;
+  static CTXTYPE *context;
 
   if (func == NULL)
     {
-      func = load_libcc ();
+      func = load_libcompile<FUNCTYPE> (fe_libcc, fe_context);
       gdb_assert (func != NULL);
     }
 
-  context = (*func) (GCC_FE_VERSION_0, GCC_C_FE_VERSION_0);
+  context = (*func) (base_version, api_version);
   if (context == NULL)
     error (_("The loaded version of GCC does not support the required version "
 	     "of the API."));
 
-  return new compile_c_instance (context);
+  return new INSTTYPE (context);
+}
+
+/* A C-language implementation of get_compile_context.  */
+
+compile_instance *
+c_get_compile_context (void)
+{
+  return get_compile_context
+    <compile_c_instance, gcc_c_fe_context_function, gcc_c_context,
+    gcc_base_api_version, gcc_c_api_version>
+    (STRINGIFY (GCC_C_FE_LIBCC), STRINGIFY (GCC_C_FE_CONTEXT),
+     GCC_FE_VERSION_0, GCC_C_FE_VERSION_0);
+}
+
+/* A C++-language implementation of get_compile_context.  */
+
+compile_instance *
+cplus_get_compile_context (void)
+{
+  return get_compile_context
+    <compile_cplus_instance, gcc_cp_fe_context_function, gcc_cp_context,
+     gcc_base_api_version, gcc_cp_api_version>
+    (STRINGIFY (GCC_CP_FE_LIBCC), STRINGIFY (GCC_CP_FE_CONTEXT),
+     GCC_FE_VERSION_0, GCC_CP_FE_VERSION_0);
 }
 
 
@@ -384,6 +411,113 @@  struct c_add_input
   }
 };
 
+/* C++-language policy to emit a push user expression pragma into
+   BUF.  */
+
+struct cplus_push_user_expression
+{
+  void push_user_expression (struct ui_file *buf)
+  {
+    fputs_unfiltered ("#pragma GCC push_user_expression\n", buf);
+  }
+};
+
+/* C++-language policy to emit a pop user expression pragma into BUF.  */
+
+struct cplus_pop_user_expression
+{
+  void pop_user_expression (struct ui_file *buf)
+  {
+    fputs_unfiltered ("#pragma GCC pop_user_expression\n", buf);
+  }
+};
+
+/* C++-language policy to construct a code header for a block of code.
+   Takes a scope TYPE argument which selects the correct header to
+   insert into BUF.  */
+
+struct cplus_add_code_header
+{
+  void add_code_header (enum compile_i_scope_types type, struct ui_file *buf)
+  {
+  switch (type)
+    {
+    case COMPILE_I_SIMPLE_SCOPE:
+      fputs_unfiltered ("void "
+			GCC_FE_WRAPPER_FUNCTION
+			" (struct "
+			COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG
+			" *"
+			COMPILE_I_SIMPLE_REGISTER_ARG_NAME
+			") {\n",
+			buf);
+      break;
+
+    case COMPILE_I_PRINT_ADDRESS_SCOPE:
+    case COMPILE_I_PRINT_VALUE_SCOPE:
+      fputs_unfiltered (
+			"#include <cstring>\n"
+			"#include <bits/move.h>\n"
+			"void "
+			GCC_FE_WRAPPER_FUNCTION
+			" (struct "
+			COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG
+			" *"
+			COMPILE_I_SIMPLE_REGISTER_ARG_NAME
+			", "
+			COMPILE_I_PRINT_OUT_ARG_TYPE
+			" "
+			COMPILE_I_PRINT_OUT_ARG
+			") {\n",
+			buf);
+      break;
+
+    case COMPILE_I_RAW_SCOPE:
+      break;
+
+    default:
+      gdb_assert_not_reached (_("Unknown compiler scope reached."));
+    }
+  }
+};
+
+/* C++-language policy to emit the user code snippet INPUT into BUF based on
+   the scope TYPE.  */
+
+struct cplus_add_input
+{
+  void add_input (enum compile_i_scope_types type, const char *input,
+		  struct ui_file *buf)
+  {
+    switch (type)
+      {
+      case COMPILE_I_PRINT_VALUE_SCOPE:
+      case COMPILE_I_PRINT_ADDRESS_SCOPE:
+	fprintf_unfiltered
+	  (buf,
+	   /* "auto" strips ref- and cv- qualifiers, so we need to also strip
+	      those from COMPILE_I_EXPR_PTR_TYPE.  */
+	   "auto " COMPILE_I_EXPR_VAL " = %s;\n"
+	   "typedef "
+	     "std::add_pointer<std::remove_cv<decltype (%s)>::type>::type "
+	     " __gdb_expr_ptr;\n"
+	   "__gdb_expr_ptr " COMPILE_I_EXPR_PTR_TYPE ";\n"
+	   "std::memcpy (" COMPILE_I_PRINT_OUT_ARG ", %s ("
+	   COMPILE_I_EXPR_VAL "),\n"
+	   "\tsizeof (*" COMPILE_I_EXPR_PTR_TYPE "));\n"
+	   ,input, input,
+	   (type == COMPILE_I_PRINT_ADDRESS_SCOPE
+	    ? "__builtin_addressof" : ""));
+	break;
+
+      default:
+	fputs_unfiltered (input, buf);
+	break;
+      }
+    fputs_unfiltered ("\n", buf);
+  }
+};
+
 /* A host class representing a compile program.
 
    CompileInstanceType is the type of the compile_instance for the
@@ -513,13 +647,18 @@  private:
   struct gdbarch *m_arch;
 };
 
-/* Type used for C program computations.  */
+/* The types used for C and C++ program computations.  */
 
 typedef compile_program<compile_c_instance,
 			c_push_user_expression, pop_user_expression_nop,
 			c_add_code_header, c_add_code_footer,
 			c_add_input> c_compile_program;
 
+typedef compile_program<compile_cplus_instance,
+			cplus_push_user_expression, cplus_pop_user_expression,
+			cplus_add_code_header, c_add_code_footer,
+			cplus_add_input> cplus_compile_program;
+
 /* The la_compute_program method for C.  */
 
 std::string
@@ -534,3 +673,19 @@  c_compute_program (compile_instance *inst,
 
   return program.compute (input, expr_block, expr_pc);
 }
+
+/* The la_compute_program method for C++.  */
+
+std::string
+cplus_compute_program (compile_instance *inst,
+		       const char *input,
+		       struct gdbarch *gdbarch,
+		       const struct block *expr_block,
+		       CORE_ADDR expr_pc)
+{
+  compile_cplus_instance *cplus_inst
+    = static_cast<compile_cplus_instance *> (inst);
+  cplus_compile_program program (cplus_inst, gdbarch);
+
+  return program.compute (input, expr_block, expr_pc);
+}
diff --git a/gdb/compile/compile-cplus-support.c b/gdb/compile/compile-cplus-support.c
new file mode 100644
index 0000000000..42fc7692c4
--- /dev/null
+++ b/gdb/compile/compile-cplus-support.c
@@ -0,0 +1,30 @@ 
+/* C++ language support for compilation.
+
+   Copyright (C) 2015-2018 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "gcc-cp-interface.h"
+
+void
+gcc_cplus_enter_scope (void *datum, struct gcc_cp_context *gcc_context)
+{
+}
+
+void
+gcc_cplus_leave_scope (void *datum, struct gcc_cp_context *gcc_context)
+{
+}
diff --git a/gdb/compile/compile-cplus-symbols.c b/gdb/compile/compile-cplus-symbols.c
new file mode 100644
index 0000000000..8e7be596d3
--- /dev/null
+++ b/gdb/compile/compile-cplus-symbols.c
@@ -0,0 +1,511 @@ 
+/* Convert symbols from GDB to GCC
+
+   Copyright (C) 2014-2018 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+#include "defs.h"
+#include "compile-internal.h"
+#include "compile-cplus.h"
+#include "gdb_assert.h"
+#include "symtab.h"
+#include "parser-defs.h"
+#include "block.h"
+#include "objfiles.h"
+#include "compile.h"
+#include "value.h"
+#include "exceptions.h"
+#include "gdbtypes.h"
+#include "dwarf2loc.h"
+#include "cp-support.h"
+#include "gdbcmd.h"
+#include "compile-c.h"
+
+/* See description in compile-internal.h.  */
+
+int debug_compile_oracle = 0;
+
+/* Convert a given symbol, SYM, to the compiler's representation.
+   INSTANCE is the compiler instance.  IS_GLOBAL is true if the
+   symbol came from the global scope.  IS_LOCAL is true if the symbol
+   came from a local scope.  (Note that the two are not strictly
+   inverses because the symbol might have come from the static
+   scope.)  */
+
+static void
+convert_one_symbol (compile_cplus_instance *instance,
+		    struct block_symbol sym, bool is_global, bool is_local)
+{
+  /* Squash compiler warning.  */
+  gcc_type sym_type = 0;
+  const char *filename = symbol_symtab (sym.symbol)->filename;
+  unsigned short line = SYMBOL_LINE (sym.symbol);
+
+  instance->error_symbol_once (sym.symbol);
+
+  if (SYMBOL_CLASS (sym.symbol) == LOC_LABEL)
+    sym_type = 0;
+  else
+    sym_type = instance->convert_type (SYMBOL_TYPE (sym.symbol));
+
+  if (SYMBOL_DOMAIN (sym.symbol) == STRUCT_DOMAIN)
+    {
+      /* Nothing to do.  */
+    }
+  else
+    {
+      /* Squash compiler warning.  */
+      gcc_cp_symbol_kind_flags kind = GCC_CP_FLAG_BASE;
+      CORE_ADDR addr = 0;
+      std::string name;
+      gdb::unique_xmalloc_ptr<char> symbol_name;
+
+      switch (SYMBOL_CLASS (sym.symbol))
+	{
+	case LOC_TYPEDEF:
+	  if (TYPE_CODE (SYMBOL_TYPE (sym.symbol)) == TYPE_CODE_TYPEDEF)
+	    kind = GCC_CP_SYMBOL_TYPEDEF;
+	  else  if (TYPE_CODE (SYMBOL_TYPE (sym.symbol)) == TYPE_CODE_NAMESPACE)
+	    return;
+	  break;
+
+	case LOC_LABEL:
+	  kind = GCC_CP_SYMBOL_LABEL;
+	  addr = SYMBOL_VALUE_ADDRESS (sym.symbol);
+	  break;
+
+	case LOC_BLOCK:
+	  {
+	    kind = GCC_CP_SYMBOL_FUNCTION;
+	    addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym.symbol));
+	    if (is_global && TYPE_GNU_IFUNC (SYMBOL_TYPE (sym.symbol)))
+	      addr = gnu_ifunc_resolve_addr (target_gdbarch (), addr);
+	  }
+	  break;
+
+	case LOC_CONST:
+	  if (TYPE_CODE (SYMBOL_TYPE (sym.symbol)) == TYPE_CODE_ENUM)
+	    {
+	      /* Already handled by convert_enum.  */
+	      return;
+	    }
+	  instance->plugin ().build_constant
+	    (sym_type, SYMBOL_NATURAL_NAME (sym.symbol),
+	     SYMBOL_VALUE (sym.symbol), filename, line);
+	  return;
+
+	case LOC_CONST_BYTES:
+	  error (_("Unsupported LOC_CONST_BYTES for symbol \"%s\"."),
+		 SYMBOL_PRINT_NAME (sym.symbol));
+
+	case LOC_UNDEF:
+	  internal_error (__FILE__, __LINE__, _("LOC_UNDEF found for \"%s\"."),
+			  SYMBOL_PRINT_NAME (sym.symbol));
+
+	case LOC_COMMON_BLOCK:
+	  error (_("Fortran common block is unsupported for compilation "
+		   "evaluaton of symbol \"%s\"."),
+		 SYMBOL_PRINT_NAME (sym.symbol));
+
+	case LOC_OPTIMIZED_OUT:
+	  error (_("Symbol \"%s\" cannot be used for compilation evaluation "
+		   "as it is optimized out."),
+		 SYMBOL_PRINT_NAME (sym.symbol));
+
+	case LOC_COMPUTED:
+	  if (is_local)
+	    goto substitution;
+	  /* Probably TLS here.  */
+	  warning (_("Symbol \"%s\" is thread-local and currently can only "
+		     "be referenced from the current thread in "
+		     "compiled code."),
+		   SYMBOL_PRINT_NAME (sym.symbol));
+	  /* FALLTHROUGH */
+	case LOC_UNRESOLVED:
+	  /* 'symbol_name' cannot be used here as that one is used only for
+	     local variables from compile_dwarf_expr_to_c.
+	     Global variables can be accessed by GCC only by their address, not
+	     by their name.  */
+	  {
+	    struct value *val;
+	    struct frame_info *frame = nullptr;
+
+	    if (symbol_read_needs_frame (sym.symbol))
+	      {
+		frame = get_selected_frame (nullptr);
+		if (frame == nullptr)
+		  error (_("Symbol \"%s\" cannot be used because "
+			   "there is no selected frame"),
+			 SYMBOL_PRINT_NAME (sym.symbol));
+	      }
+
+	    val = read_var_value (sym.symbol, sym.block, frame);
+	    if (VALUE_LVAL (val) != lval_memory)
+	      error (_("Symbol \"%s\" cannot be used for compilation "
+		       "evaluation as its address has not been found."),
+		     SYMBOL_PRINT_NAME (sym.symbol));
+
+	    kind = GCC_CP_SYMBOL_VARIABLE;
+	    addr = value_address (val);
+	  }
+	  break;
+
+
+	case LOC_REGISTER:
+	case LOC_ARG:
+	case LOC_REF_ARG:
+	case LOC_REGPARM_ADDR:
+	case LOC_LOCAL:
+	substitution:
+	  kind = GCC_CP_SYMBOL_VARIABLE;
+	  symbol_name = c_symbol_substitution_name (sym.symbol);
+	  break;
+
+	case LOC_STATIC:
+	  kind = GCC_CP_SYMBOL_VARIABLE;
+	  addr = SYMBOL_VALUE_ADDRESS (sym.symbol);
+	  break;
+
+	case LOC_FINAL_VALUE:
+	default:
+	  gdb_assert_not_reached ("Unreachable case in convert_one_symbol.");
+	}
+
+      /* Don't emit local variable decls for a raw expression.  */
+      if (instance->scope () != COMPILE_I_RAW_SCOPE || symbol_name == nullptr)
+	{
+	  compile_scope scope;
+
+	  /* For non-local symbols, create/push a new scope so that the
+	     symbol is properly scoped to the plug-in.  */
+	  if (!is_local)
+	    {
+	      scope
+		= instance->new_scope (SYMBOL_NATURAL_NAME (sym.symbol),
+				       SYMBOL_TYPE (sym.symbol));
+	      if (scope.nested_type () != GCC_TYPE_NONE)
+		{
+		  /* We found a symbol for this type that was defined inside
+		     some other symbol, e.g., a class tyepdef defined.  */
+		  return;
+		}
+
+	      instance->enter_scope (scope);
+	    }
+
+	  /* Get the `raw' name of the symbol.  */
+	  if (name.empty () && SYMBOL_NATURAL_NAME (sym.symbol) != nullptr)
+	    name = decl_name (SYMBOL_NATURAL_NAME (sym.symbol)).get ();
+
+	  /* Define the decl.  */
+	  instance->plugin ().build_decl
+	    ("variable", name.c_str (), kind, sym_type,
+	     symbol_name.get (), addr, filename, line);
+
+	  /* Pop scope for non-local symbols.  */
+	  if (!is_local)
+	    instance->leave_scope ();
+	}
+    }
+}
+
+/* Convert a full symbol to its gcc form.  CONTEXT is the compiler to
+   use, IDENTIFIER is the name of the symbol, SYM is the symbol
+   itself, and DOMAIN is the domain which was searched.  */
+
+static void
+convert_symbol_sym (compile_cplus_instance *instance,
+		    const char *identifier, struct block_symbol sym,
+		    domain_enum domain)
+{
+  /* If we found a symbol and it is not in the  static or global
+     scope, then we should first convert any static or global scope
+     symbol of the same name.  This lets this unusual case work:
+
+     int x; // Global.
+     int func(void)
+     {
+     int x;
+     // At this spot, evaluate "extern int x; x"
+     }
+  */
+
+  const struct block *static_block = block_static_block (sym.block);
+  /* STATIC_BLOCK is NULL if FOUND_BLOCK is the global block.  */
+  bool is_local_symbol = (sym.block != static_block && static_block != nullptr);
+  if (is_local_symbol)
+    {
+      struct block_symbol global_sym;
+
+      global_sym = lookup_symbol (identifier, nullptr, domain, nullptr);
+      /* If the outer symbol is in the static block, we ignore it, as
+	 it cannot be referenced.  */
+      if (global_sym.symbol != nullptr
+	  && global_sym.block != block_static_block (global_sym.block))
+	{
+	  if (compile_debug)
+	    fprintf_unfiltered (gdb_stdlog,
+				"gcc_convert_symbol \"%s\": global symbol\n",
+				identifier);
+	  convert_one_symbol (instance, global_sym, true, false);
+	}
+    }
+
+  if (compile_debug)
+    fprintf_unfiltered (gdb_stdlog,
+			"gcc_convert_symbol \"%s\": local symbol\n",
+			identifier);
+  convert_one_symbol (instance, sym, false, is_local_symbol);
+}
+
+/* Convert a minimal symbol to its gcc form.  CONTEXT is the compiler
+   to use and BMSYM is the minimal symbol to convert.  */
+
+static void
+convert_symbol_bmsym (compile_cplus_instance *instance,
+		      struct bound_minimal_symbol bmsym)
+{
+  struct minimal_symbol *msym = bmsym.minsym;
+  struct objfile *objfile = bmsym.objfile;
+  struct type *type;
+  gcc_cp_symbol_kind_flags kind;
+  gcc_type sym_type;
+  CORE_ADDR addr;
+
+  addr = MSYMBOL_VALUE_ADDRESS (objfile, msym);
+
+  /* Conversion copied from write_exp_msymbol.  */
+  switch (MSYMBOL_TYPE (msym))
+    {
+    case mst_text:
+    case mst_file_text:
+    case mst_solib_trampoline:
+      type = objfile_type (objfile)->nodebug_text_symbol;
+      kind = GCC_CP_SYMBOL_FUNCTION;
+      break;
+
+    case mst_text_gnu_ifunc:
+      /* nodebug_text_gnu_ifunc_symbol would cause:
+	 function return type cannot be function  */
+      type = objfile_type (objfile)->nodebug_text_symbol;
+      kind = GCC_CP_SYMBOL_FUNCTION;
+      addr = gnu_ifunc_resolve_addr (target_gdbarch (), addr);
+      break;
+
+    case mst_data:
+    case mst_file_data:
+    case mst_bss:
+    case mst_file_bss:
+      type = objfile_type (objfile)->nodebug_data_symbol;
+      kind = GCC_CP_SYMBOL_VARIABLE;
+      break;
+
+    case mst_slot_got_plt:
+      type = objfile_type (objfile)->nodebug_got_plt_symbol;
+      kind = GCC_CP_SYMBOL_FUNCTION;
+      break;
+
+    default:
+      type = objfile_type (objfile)->nodebug_unknown_symbol;
+      kind = GCC_CP_SYMBOL_VARIABLE;
+      break;
+    }
+
+  sym_type = instance->convert_type (type);
+  instance->plugin ().push_namespace ("");
+  instance->plugin ().build_decl
+    ("minsym", MSYMBOL_NATURAL_NAME (msym), kind, sym_type, nullptr, addr,
+     nullptr, 0);
+  instance->plugin ().pop_binding_level ("");
+}
+
+/* See compile-cplus.h.  */
+
+void
+gcc_cplus_convert_symbol (void *datum,
+			  struct gcc_cp_context *gcc_context,
+			  enum gcc_cp_oracle_request request ATTRIBUTE_UNUSED,
+			  const char *identifier)
+{
+  if (debug_compile_oracle)
+    fprintf_unfiltered (gdb_stdlog,
+			"got oracle request for \"%s\"\n", identifier);
+
+  bool found = false;
+  compile_cplus_instance *instance = (compile_cplus_instance *) datum;
+
+  TRY
+    {
+      /* Symbol searching is a three part process unfortunately.  */
+
+      /* First do a "standard" lookup, converting any found symbols.
+	 This will find variables in the current scope.  */
+
+      struct block_symbol sym
+	= lookup_symbol (identifier, instance->block (), VAR_DOMAIN, nullptr);
+
+      if (sym.symbol != nullptr)
+	{
+	  found = true;
+	  convert_symbol_sym (instance, identifier, sym, VAR_DOMAIN);
+	}
+
+      /* Then use linespec.c's multi-symbol search.  This should find
+	 all non-variable symbols for which we have debug info.  */
+
+      symbol_searcher searcher;
+      searcher.find_all_symbols (identifier, current_language,
+				 ALL_DOMAIN, nullptr, nullptr);
+
+      /* Convert any found symbols.  */
+      for (const auto &it : searcher.matching_symbols ())
+	{
+	  found = true;
+	  convert_symbol_sym (instance, identifier, it,
+			      SYMBOL_DOMAIN (it.symbol));
+	}
+
+      /* Finally, if no symbols have been found, fall back to minsyms.  */
+      if (!found)
+	{
+	  for (const auto &it : searcher.matching_msymbols ())
+	    {
+	      found = true;
+	      convert_symbol_bmsym (instance, it);
+	    }
+	}
+    }
+  CATCH (e, RETURN_MASK_ALL)
+    {
+      /* We can't allow exceptions to escape out of this callback.  Safest
+	 is to simply emit a gcc error.  */
+      instance->plugin ().error (e.message);
+    }
+  END_CATCH
+
+  if (compile_debug && !found)
+    fprintf_unfiltered (gdb_stdlog,
+			"gcc_convert_symbol \"%s\": lookup_symbol failed\n",
+			identifier);
+
+  if (debug_compile_oracle)
+    {
+      if (found)
+	fprintf_unfiltered (gdb_stdlog, "found type for %s\n", identifier);
+      else
+	{
+	  fprintf_unfiltered (gdb_stdlog, "did not find type for %s\n",
+			      identifier);
+	}
+    }
+
+  return;
+}
+
+/* See compile-cplus.h.  */
+
+gcc_address
+gcc_cplus_symbol_address (void *datum, struct gcc_cp_context *gcc_context,
+			  const char *identifier)
+{
+  compile_cplus_instance *instance = (compile_cplus_instance *) datum;
+  gcc_address result = 0;
+  int found = 0;
+
+  if (debug_compile_oracle)
+    fprintf_unfiltered (gdb_stdlog,
+			"got oracle request for address of %s\n", identifier);
+
+  /* We can't allow exceptions to escape out of this callback.  Safest
+     is to simply emit a gcc error.  */
+  TRY
+    {
+      struct symbol *sym
+	= lookup_symbol (identifier, nullptr, VAR_DOMAIN, nullptr).symbol;
+
+      if (sym != nullptr && SYMBOL_CLASS (sym) == LOC_BLOCK)
+	{
+	  if (compile_debug)
+	    fprintf_unfiltered (gdb_stdlog,
+				"gcc_symbol_address \"%s\": full symbol\n",
+				identifier);
+	  result = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
+	  if (TYPE_GNU_IFUNC (SYMBOL_TYPE (sym)))
+	    result = gnu_ifunc_resolve_addr (target_gdbarch (), result);
+	  found = 1;
+	}
+      else
+	{
+	  struct bound_minimal_symbol msym;
+
+	  msym = lookup_bound_minimal_symbol (identifier);
+	  if (msym.minsym != nullptr)
+	    {
+	      if (compile_debug)
+		fprintf_unfiltered (gdb_stdlog,
+				    "gcc_symbol_address \"%s\": minimal "
+				    "symbol\n",
+				    identifier);
+	      result = BMSYMBOL_VALUE_ADDRESS (msym);
+	      if (MSYMBOL_TYPE (msym.minsym) == mst_text_gnu_ifunc)
+		result = gnu_ifunc_resolve_addr (target_gdbarch (), result);
+	      found = 1;
+	    }
+	}
+    }
+
+  CATCH (e, RETURN_MASK_ERROR)
+    {
+      instance->plugin ().error (e.message);
+    }
+  END_CATCH
+
+  if (compile_debug && !found)
+    fprintf_unfiltered (gdb_stdlog,
+			"gcc_symbol_address \"%s\": failed\n",
+			identifier);
+
+  if (debug_compile_oracle)
+    {
+      if (found)
+	fprintf_unfiltered (gdb_stdlog, "found address for %s!\n", identifier);
+      else
+	fprintf_unfiltered (gdb_stdlog,
+			    "did not find address for %s\n", identifier);
+    }
+
+  return result;
+}
+
+
+
+void _initialize_compile_cplus_symbols (void);
+
+void
+_initialize_compile_cplus_symbols (void)
+{
+  add_setshow_boolean_cmd ("compile-oracle", no_class,
+			   &debug_compile_oracle, _("\
+Set debugging of compiler plug-in oracle requests."), _("\
+Show debugging of compiler plug-in oracle requests."), _("\
+When enabled debugging messages are printed for compiler plug-in\n\
+oracle requests."),
+			   nullptr,
+			   nullptr,
+			   &setdebuglist,
+			   &showdebuglist);
+}
diff --git a/gdb/compile/compile-cplus-types.c b/gdb/compile/compile-cplus-types.c
new file mode 100644
index 0000000000..3e197834fc
--- /dev/null
+++ b/gdb/compile/compile-cplus-types.c
@@ -0,0 +1,1430 @@ 
+/* Convert types from GDB to GCC
+
+   Copyright (C) 2014-2018 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+#include "defs.h"
+#include "common/preprocessor.h"
+#include "gdbtypes.h"
+#include "compile-internal.h"
+#include "compile-cplus.h"
+#include "gdb_assert.h"
+#include "symtab.h"
+#include "source.h"
+#include "cp-support.h"
+#include "cp-abi.h"
+#include "symtab.h"
+#include "objfiles.h"
+#include "block.h"
+#include "gdbcmd.h"
+#include "c-lang.h"
+#include "compile-c.h" 		/* Included for c_get_range_decl_name
+				   et al.  */
+#include <algorithm>
+
+/* Default compile flags for C++.  */
+
+const char *compile_cplus_instance::m_default_cflags = "-std=gnu++11";
+
+/* Flag to enable internal debugging.  */
+
+static int debug_compile_cplus_types = 0;
+
+/* Flag to enable internal scope switching debugging.  */
+
+static int debug_compile_cplus_scopes = 0;
+
+/* Forward declarations.  */
+
+static gcc_type compile_cplus_convert_func (compile_cplus_instance *instance,
+					    struct type *type,
+					    bool strip_artificial);
+
+/* See description in compile-cplus.h.  */
+
+gdb::unique_xmalloc_ptr<char>
+decl_name (const char *natural)
+{
+  if (natural == nullptr)
+    return nullptr;
+
+  char *name = cp_func_name (natural);
+  if (name != nullptr)
+    return gdb::unique_xmalloc_ptr<char> (name);
+
+  return gdb::unique_xmalloc_ptr<char> (xstrdup (natural));
+}
+
+/* Get the access flag for the NUM'th field of TYPE.  */
+
+static enum gcc_cp_symbol_kind
+get_field_access_flag (const struct type *type, int num)
+{
+  if (TYPE_FIELD_PROTECTED (type, num))
+    return GCC_CP_ACCESS_PROTECTED;
+  else if (TYPE_FIELD_PRIVATE (type, num))
+    return GCC_CP_ACCESS_PRIVATE;
+
+  /* GDB assumes everything else is public.  */
+  return GCC_CP_ACCESS_PUBLIC;
+}
+
+/* Get the access flag for the NUM'th method of TYPE's FNI'th
+   fieldlist.  */
+
+enum gcc_cp_symbol_kind
+get_method_access_flag (const struct type *type, int fni, int num)
+{
+  gdb_assert (TYPE_CODE (type) == TYPE_CODE_STRUCT);
+
+  /* If this type was not declared a class, everything is public.  */
+  if (!TYPE_DECLARED_CLASS (type))
+    return GCC_CP_ACCESS_PUBLIC;
+
+  /* Otherwise, read accessibility from the fn_field.  */
+  const struct fn_field *methods = TYPE_FN_FIELDLIST1 (type, fni);
+  if (TYPE_FN_FIELD_PROTECTED (methods, num))
+    return GCC_CP_ACCESS_PROTECTED;
+  else if (TYPE_FN_FIELD_PRIVATE (methods, num))
+    return GCC_CP_ACCESS_PRIVATE;
+  else
+    return GCC_CP_ACCESS_PUBLIC;
+}
+
+/* A useful debugging function to output the scope SCOPE to stdout.  */
+
+static void __attribute__ ((used))
+debug_print_scope (const compile_scope &scope)
+{
+  for (const auto &comp: scope)
+    {
+      std::string symbol = (comp.bsymbol.symbol != nullptr
+			    ? SYMBOL_NATURAL_NAME (comp.bsymbol.symbol)
+			    : "<none>");
+
+      printf_unfiltered ("\tname = %s, symbol = %s\n", comp.name.c_str (),
+			 symbol.c_str ());
+    }
+}
+
+/* Utility function to convert CODE into a string.  */
+
+static const char *
+type_code_to_string (enum type_code code)
+{
+  const char * const s[] =
+    {"BISTRING (deprecated)", "UNDEF (not used)",
+     "PTR", "ARRAY", "STRUCT", "UNION", "ENUM",
+     "FLAGS", "FUNC", "INT", "FLT", "VOID",
+     "SET", "RANGE", "STRING", "ERROR", "METHOD",
+     "METHODPTR", "MEMBERPTR", "REF", "RVALUE_REF", "CHAR", "BOOL",
+     "COMPLEX", "TYPEDEF", "NAMESPACE", "DECFLOAT", "MODULE",
+     "INTERNAL_FUNCTION", "XMETHOD"};
+
+  return s[code + 1];
+}
+
+/* See description in compile-cplus.h.  */
+
+compile_scope
+type_name_to_scope (const char *type_name, const struct block *block)
+{
+  compile_scope scope;
+
+  if (type_name == nullptr)
+    {
+      /* An anonymous type.  We cannot really do much here.  We simply cannot
+	 look up anonymous types easily/at all.  */
+      return scope;
+    }
+
+  const char *p = type_name;
+  std::string lookup_name;
+
+  while (*p != '\0')
+    {
+      /* Create a string token of the first component of TYPE_NAME.  */
+      int len = cp_find_first_component (p);
+      std::string s (p, len);
+
+      /* Advance past the last token.  */
+      p += len;
+
+      /* Look up the symbol and decide when to stop.  */
+      if (!lookup_name.empty ())
+	lookup_name += "::";
+      lookup_name += s;
+
+      /* Look up the resulting name.  */
+      struct block_symbol bsymbol
+	= lookup_symbol (lookup_name.c_str (), block, VAR_DOMAIN, nullptr);
+
+      if (bsymbol.symbol != nullptr)
+	{
+	  scope_component comp = {s, bsymbol};
+
+	  scope.push_back (comp);
+
+	  if (TYPE_CODE (SYMBOL_TYPE (bsymbol.symbol)) != TYPE_CODE_NAMESPACE)
+	    {
+	      /* We're done.  */
+	      break;
+	    }
+	}
+
+      if (*p == ':')
+	{
+	  ++p;
+	  if (*p == ':')
+	    ++p;
+	  else
+	    {
+	      /* This shouldn't happen since we are not attempting to
+		 loop over user input.  This name is generated by GDB
+		 from debug info.  */
+	      internal_error (__FILE__, __LINE__,
+			      _("malformed TYPE_NAME during parsing"));
+	    }
+	}
+    }
+
+  return scope;
+}
+
+/* Compare two scope_components for equality.  These are equal if the names
+   of the two components' are the same.  */
+
+bool
+operator== (const scope_component &lhs, const scope_component &rhs)
+{
+  return lhs.name == rhs.name;
+}
+
+/* Compare two scope_components for inequality.  These are not equal if
+   the two components' names are not equal.  */
+
+bool
+operator!= (const scope_component &lhs, const scope_component &rhs)
+{
+  return lhs.name != rhs.name;
+}
+
+/* Compare two compile_scopes for equality.  These are equal if they are both
+   contain the same number of components and each component is equal.  */
+
+bool
+operator== (const compile_scope &lhs, const compile_scope &rhs)
+{
+  if (lhs.size () != rhs.size ())
+    return false;
+
+  for (int i = 0; i < lhs.size (); ++i)
+    {
+      if (lhs[i] != rhs[i])
+	return false;
+    }
+
+  return true;
+}
+
+/* Compare two compile_scopes for inequality.  These are inequal if they
+   contain unequal number of elements or if any of the components are not
+   the same.  */
+
+bool
+operator!= (const compile_scope &lhs, const compile_scope &rhs)
+{
+  if (lhs.size () != rhs.size ())
+    return true;
+
+  for (int i = 0; i < lhs.size (); ++i)
+    {
+      if (lhs[i] != rhs[i])
+	return true;
+    }
+
+  return false;
+}
+
+/* See description in compile-cplus.h.  */
+
+void
+compile_cplus_instance::enter_scope (compile_scope &new_scope)
+{
+  bool must_push = m_scopes.empty () || m_scopes.back () != new_scope;
+
+  new_scope.m_pushed = must_push;
+
+  /* Save the new scope.  */
+  m_scopes.push_back (new_scope);
+
+  if (must_push)
+    {
+      if (debug_compile_cplus_scopes)
+	fprintf_unfiltered (gdb_stdlog, "entering new scope %p\n", new_scope);
+
+      /* Push the global namespace. */
+      plugin ().push_namespace ("");
+
+      /* Push all other namespaces.  Note that we do not push the last
+	 scope_component -- that's the actual type we are converting.  */
+      std::for_each
+	(new_scope.begin (), new_scope.end () - 1,
+	 [this] (const scope_component &comp)
+	 {
+	  gdb_assert (TYPE_CODE (SYMBOL_TYPE (comp.bsymbol.symbol))
+		      == TYPE_CODE_NAMESPACE);
+
+	  const char *ns = (comp.name == CP_ANONYMOUS_NAMESPACE_STR ? nullptr
+			    : comp.name.c_str ());
+
+	  this->plugin ().push_namespace (ns);
+	 });
+    }
+  else
+    {
+      if (debug_compile_cplus_scopes)
+	{
+	  fprintf_unfiltered (gdb_stdlog, "staying in current scope -- "
+			      "scopes are identical\n");
+	}
+    }
+}
+
+/* See description in compile-cplus.h.  */
+
+void
+compile_cplus_instance::leave_scope ()
+{
+  /* Get the current scope and remove it from the internal list of
+     scopes.  */
+  compile_scope current = m_scopes.back ();
+
+  m_scopes.pop_back ();
+
+  if (current.m_pushed)
+    {
+      if (debug_compile_cplus_scopes)
+	fprintf_unfiltered (gdb_stdlog, "leaving scope %p\n", current);
+
+      /* Pop namespaces.  */
+      std::for_each
+	(current.begin (),current.end () - 1,
+	 [this] (const scope_component &comp) {
+	  gdb_assert (TYPE_CODE (SYMBOL_TYPE (comp.bsymbol.symbol))
+		      == TYPE_CODE_NAMESPACE);
+	  this->plugin ().pop_binding_level (comp.name.c_str ());
+	});
+
+      /* Pop global namespace.  */
+      plugin ().pop_binding_level ("");
+    }
+  else
+    {
+      if (debug_compile_cplus_scopes)
+	fprintf_unfiltered (gdb_stdlog,
+			    "identical scopes -- not leaving scope\n");
+    }
+}
+
+/* See description in compile-cplus.h.  */
+
+compile_scope
+compile_cplus_instance::new_scope (const char *type_name, struct type *type)
+{
+  /* Break the type name into components.  If TYPE was defined in some
+     superclass, we do not process TYPE but process the enclosing type
+     instead.  */
+  compile_scope scope = type_name_to_scope (type_name, block ());
+
+  if (!scope.empty ())
+    {
+      /* Get the name of the last component, which should be the
+	 unqualified name of the type to process.  */
+      scope_component &comp = scope.back ();
+
+      if (!types_equal (type, SYMBOL_TYPE (comp.bsymbol.symbol))
+	  && (m_scopes.empty ()
+	      || (m_scopes.back ().back ().bsymbol.symbol
+		  != comp.bsymbol.symbol)))
+	{
+	  /* The type is defined inside another class(es).  Convert that
+	     type instead of defining this type.  */
+	  convert_type (SYMBOL_TYPE (comp.bsymbol.symbol));
+
+	  /* If the original type (passed in to us) is defined in a nested
+	     class, the previous call will give us that type's gcc_type.
+	     Upper layers are expecting to get the original type's
+	     gcc_type!  */
+	  get_cached_type (type, scope.m_nested_type);
+	  return scope;
+	}
+    }
+  else
+    {
+      if (TYPE_NAME (type) == nullptr)
+	{
+	  /* Anonymous type  */
+
+	  /* We don't have a qualified name for this to look up, but
+	     we need a scope.  We have to assume, then, that it is the same
+	     as the current scope, if any.  */
+	  if (!m_scopes.empty ())
+	    {
+	      scope = m_scopes.back ();
+	      scope.m_pushed = false;
+	    }
+	  else
+	    scope.push_back (scope_component ());
+	}
+      else
+	{
+	  scope_component comp
+	    = {
+	        decl_name (TYPE_NAME (type)).release (),
+		lookup_symbol (TYPE_NAME (type), block (), VAR_DOMAIN, nullptr)
+	      };
+	  scope.push_back (comp);
+	}
+    }
+
+  /* There must be at least one component in the compile_scope.  */
+  gdb_assert (scope.size () > 0);
+  return scope;
+}
+
+/* See description in compile-cplus.h.  */
+
+gcc_type
+compile_cplus_instance::convert_reference_base
+  (gcc_type base, enum gcc_cp_ref_qualifiers rquals)
+{
+  return this->plugin ().build_reference_type (base, rquals);
+}
+
+/* Convert a reference type to its gcc representation.  */
+
+static gcc_type
+compile_cplus_convert_reference (compile_cplus_instance *instance,
+				 struct type *type)
+{
+  gcc_type target = instance->convert_type (TYPE_TARGET_TYPE (type));
+
+  enum gcc_cp_ref_qualifiers quals = GCC_CP_REF_QUAL_NONE;
+  switch (TYPE_CODE (type))
+    {
+    case TYPE_CODE_REF:
+      quals = GCC_CP_REF_QUAL_LVALUE;
+      break;
+    case TYPE_CODE_RVALUE_REF:
+      quals = GCC_CP_REF_QUAL_RVALUE;
+      break;
+    default:
+      gdb_assert_not_reached ("unexpected type code for reference type");
+    }
+
+  return instance->convert_reference_base (target, quals);
+}
+
+/* See description in compile-cplus.h.  */
+
+gcc_type
+compile_cplus_instance::convert_pointer_base(gcc_type target)
+{
+  return plugin ().build_pointer_type (target);
+}
+
+/* Convert a pointer type to its gcc representation.  */
+
+static gcc_type
+compile_cplus_convert_pointer (compile_cplus_instance *instance,
+			       struct type *type)
+{
+  gcc_type target = instance->convert_type (TYPE_TARGET_TYPE (type));
+
+  return instance->convert_pointer_base (target);
+}
+
+/* Convert an array type to its gcc representation.  */
+
+static gcc_type
+compile_cplus_convert_array (compile_cplus_instance *instance,
+			     struct type *type)
+{
+  struct type *range = TYPE_INDEX_TYPE (type);
+  gcc_type element_type = instance->convert_type (TYPE_TARGET_TYPE (type));
+
+  if (TYPE_LOW_BOUND_KIND (range) != PROP_CONST)
+    {
+      const char *s = _("array type with non-constant"
+			" lower bound is not supported");
+
+      return instance->plugin ().error (s);
+    }
+
+  if (TYPE_LOW_BOUND (range) != 0)
+    {
+      const char *s = _("cannot convert array type with "
+			"non-zero lower bound to C");
+
+      return instance->plugin ().error (s);
+    }
+
+  if (TYPE_HIGH_BOUND_KIND (range) == PROP_LOCEXPR
+      || TYPE_HIGH_BOUND_KIND (range) == PROP_LOCLIST)
+    {
+      if (TYPE_VECTOR (type))
+	{
+	  const char *s = _("variably-sized vector type is not supported");
+
+	  return instance->plugin ().error (s);
+	}
+
+      std::string upper_bound
+	= c_get_range_decl_name (&TYPE_RANGE_DATA (range)->high);
+      return instance->plugin ().build_vla_array_type (element_type,
+					     upper_bound.c_str ());
+    }
+  else
+    {
+      LONGEST low_bound, high_bound, count;
+
+      if (get_array_bounds (type, &low_bound, &high_bound) == 0)
+	count = -1;
+      else
+	{
+	  gdb_assert (low_bound == 0); /* Ensured above.  */
+	  count = high_bound + 1;
+	}
+
+      if (TYPE_VECTOR (type))
+	return instance->plugin ().build_vector_type (element_type, count);
+
+      return instance->plugin ().build_array_type (element_type, count);
+    }
+}
+
+/* Convert a typedef of TYPE.  If not GCC_CP_ACCESS_NONE, NESTED_ACCESS
+   will define the accessibility of the typedef definition in its
+   containing class.  */
+
+static gcc_type
+compile_cplus_convert_typedef (compile_cplus_instance *instance,
+			       struct type *type,
+			       enum gcc_cp_symbol_kind nested_access)
+{
+  compile_scope scope = instance->new_scope (TYPE_NAME (type), type);
+
+  if (scope.nested_type () != GCC_TYPE_NONE)
+    return scope.nested_type ();
+
+  gdb::unique_xmalloc_ptr<char> name = decl_name (TYPE_NAME (type));
+
+  /* Make sure the scope for this type has been pushed.  */
+  instance->enter_scope (scope);
+
+  /* Convert the typedef's real type.  */
+  gcc_type typedef_type = instance->convert_type (check_typedef (type));
+
+  instance->plugin ().build_decl ("typedef", name.get (),
+				  GCC_CP_SYMBOL_TYPEDEF | nested_access,
+			typedef_type, 0, 0, nullptr, 0);
+
+  /* Completed this scope.  */
+  instance->leave_scope ();
+  return typedef_type;
+}
+
+/* Convert types defined in TYPE.  */
+
+static void
+compile_cplus_convert_type_defns (compile_cplus_instance *instance,
+				  struct type *type)
+{
+  int i;
+  enum gcc_cp_symbol_kind accessibility;
+
+  /* Convert typedefs.  */
+  for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (type); ++i)
+    {
+      if (TYPE_TYPEDEF_FIELD_PROTECTED (type, i))
+	accessibility = GCC_CP_ACCESS_PROTECTED;
+      else if (TYPE_TYPEDEF_FIELD_PRIVATE (type, i))
+	accessibility = GCC_CP_ACCESS_PRIVATE;
+      else
+	accessibility = GCC_CP_ACCESS_PUBLIC;
+      instance->convert_type (TYPE_TYPEDEF_FIELD_TYPE (type, i), accessibility);
+    }
+
+  /* Convert nested types.  */
+  for (i = 0; i < TYPE_NESTED_TYPES_COUNT (type); ++i)
+    {
+      if (TYPE_NESTED_TYPES_FIELD_PROTECTED (type, i))
+	accessibility = GCC_CP_ACCESS_PROTECTED;
+      else if (TYPE_NESTED_TYPES_FIELD_PRIVATE (type, i))
+	accessibility = GCC_CP_ACCESS_PRIVATE;
+      else
+	accessibility = GCC_CP_ACCESS_PUBLIC;
+      instance->convert_type (TYPE_NESTED_TYPES_FIELD_TYPE (type, i),
+			      accessibility);
+    }
+}
+
+/* Convert data members defined in TYPE, which should be struct/class/union
+   with gcc_type COMP_TYPE.  */
+
+static void
+compile_cplus_convert_struct_or_union_members
+  (compile_cplus_instance *instance, struct type *type, gcc_type comp_type)
+{
+  for (int i = TYPE_N_BASECLASSES (type); i < TYPE_NFIELDS (type); ++i)
+    {
+      const char *field_name = TYPE_FIELD_NAME (type, i);
+
+      if (TYPE_FIELD_IGNORE (type, i)
+	  || TYPE_FIELD_ARTIFICIAL (type, i))
+	continue;
+
+      /* GDB records unnamed/anonymous fields with empty string names.  */
+      if (*field_name == '\0')
+	field_name = nullptr;
+
+      gcc_type field_type
+	= instance->convert_type (TYPE_FIELD_TYPE (type, i));
+
+      if (field_is_static (&TYPE_FIELD (type, i)))
+	{
+	  CORE_ADDR physaddr;
+
+	  switch (TYPE_FIELD_LOC_KIND (type, i))
+	    {
+	    case FIELD_LOC_KIND_PHYSADDR:
+	      {
+		physaddr = TYPE_FIELD_STATIC_PHYSADDR (type, i);
+
+		instance->plugin ().build_decl
+		  ("field physaddr", field_name,
+		   (GCC_CP_SYMBOL_VARIABLE | get_field_access_flag (type, i)),
+		   field_type, nullptr, physaddr, nullptr, 0);
+	      }
+	      break;
+
+	    case FIELD_LOC_KIND_PHYSNAME:
+	      {
+		const char *physname = TYPE_FIELD_STATIC_PHYSNAME (type, i);
+		struct block_symbol sym
+		  = lookup_symbol (physname, instance->block (),
+				   VAR_DOMAIN, nullptr);
+
+		if (sym.symbol == nullptr)
+		  {
+		    /* We didn't actually find the symbol.  There's little
+		       we can do but ignore this member.  */
+		    continue;
+		  }
+		const char *filename = symbol_symtab (sym.symbol)->filename;
+		unsigned int line = SYMBOL_LINE (sym.symbol);
+
+		physaddr = SYMBOL_VALUE_ADDRESS (sym.symbol);
+		instance->plugin ().build_decl
+		  ("field physname", field_name,
+		   (GCC_CP_SYMBOL_VARIABLE| get_field_access_flag (type, i)),
+		   field_type, nullptr, physaddr, filename, line);
+	      }
+	      break;
+
+	    default:
+	      gdb_assert_not_reached
+		("unexpected static field location kind");
+	    }
+	}
+      else
+	{
+	  unsigned long bitsize = TYPE_FIELD_BITSIZE (type, i);
+	  enum gcc_cp_symbol_kind field_flags = GCC_CP_SYMBOL_FIELD
+	    | get_field_access_flag (type, i);
+
+	  if (bitsize == 0)
+	    bitsize = 8 * TYPE_LENGTH (TYPE_FIELD_TYPE (type, i));
+
+	  instance->plugin ().build_field
+	    (field_name, field_type, field_flags, bitsize,
+	     TYPE_FIELD_BITPOS (type, i));
+	}
+    }
+}
+
+/* Convert a method type to its gcc representation.  */
+
+static gcc_type
+compile_cplus_convert_method (compile_cplus_instance *instance,
+			      struct type *parent_type,
+			      struct type *method_type)
+{
+  /* Get the actual function type of the method, the corresponding class's
+     type and corresponding qualifier flags.  */
+  gcc_type func_type = compile_cplus_convert_func (instance, method_type, true);
+  gcc_type class_type = instance->convert_type (parent_type);
+  gcc_cp_qualifiers_flags quals = (enum gcc_cp_qualifiers) 0;
+
+  if (TYPE_CONST (method_type))
+    quals |= GCC_CP_QUALIFIER_CONST;
+  if (TYPE_VOLATILE (method_type))
+    quals |= GCC_CP_QUALIFIER_VOLATILE;
+  if (TYPE_RESTRICT (method_type))
+    quals |= GCC_CP_QUALIFIER_RESTRICT;
+
+  /* Not yet implemented.  */
+  gcc_cp_ref_qualifiers_flags rquals = GCC_CP_REF_QUAL_NONE;
+
+  return instance->plugin ().build_method_type
+    (class_type, func_type, quals, rquals);
+}
+
+/* Convert a member or method pointer represented by TYPE.  */
+
+static gcc_type
+compile_cplus_convert_memberptr (compile_cplus_instance *instance,
+				 struct type *type)
+{
+  struct type *containing_class = TYPE_SELF_TYPE (type);
+
+  if (containing_class == nullptr)
+    return GCC_TYPE_NONE;
+
+  gcc_type class_type = instance->convert_type (containing_class);
+  gcc_type member_type
+    = instance->convert_type (TYPE_TARGET_TYPE (type));
+
+  return instance->plugin ().build_pointer_to_member_type
+    (class_type, member_type);
+}
+
+/* Convert all methods defined in TYPE, which should be a class/struct/union
+   with gcc_type CLASS_TYPE.  */
+
+static void
+compile_cplus_convert_struct_or_union_methods (compile_cplus_instance *instance,
+					       struct type *type,
+					       gcc_type class_type)
+{
+  for (int i = 0; i < TYPE_NFN_FIELDS (type); ++i)
+    {
+      struct fn_field *methods = TYPE_FN_FIELDLIST1 (type, i);
+      gdb::unique_xmalloc_ptr<char> overloaded_name
+	= decl_name (TYPE_FN_FIELDLIST_NAME (type, i));
+
+      /* Loop through the fieldlist, adding decls to the compiler's
+	 representation of the class.  */
+      for (int j = 0; j < TYPE_FN_FIELDLIST_LENGTH (type, i); ++j)
+	{
+	  /* Skip artificial methods.  */
+	  if (TYPE_FN_FIELD_ARTIFICIAL (methods, j))
+	    continue;
+
+	  gcc_cp_symbol_kind_flags sym_kind = GCC_CP_SYMBOL_FUNCTION;
+	  gcc_type method_type;
+	  struct block_symbol sym
+	    = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (methods, j),
+			     instance->block (), VAR_DOMAIN, nullptr);
+
+	  if (sym.symbol == nullptr)
+	    {
+	      if (TYPE_FN_FIELD_VIRTUAL_P (methods, j))
+		{
+		  /* This is beyond hacky, and is really only a workaround for
+		     detecting pure virtual methods.  */
+		  method_type = compile_cplus_convert_method
+		    (instance, type, TYPE_FN_FIELD_TYPE (methods, j));
+
+		  instance->plugin ().build_decl
+		    ("pure virtual method", overloaded_name.get (),
+		     (sym_kind
+		      | get_method_access_flag (type, i, j)
+		      | GCC_CP_FLAG_VIRTUAL_FUNCTION
+		      | GCC_CP_FLAG_PURE_VIRTUAL_FUNCTION),
+		     method_type, nullptr, 0, nullptr, 0);
+		  continue;
+		}
+
+	      /* This can happen if we have a DW_AT_declaration DIE
+		 for the method, but no "definition"-type DIE (with
+		 DW_AT_specification referencing the decl DIE), i.e.,
+		 the compiler has probably optimized the method away.
+
+		 In this case, all we can hope to do is issue a warning
+		 to the user letting him know.  If the user has not actually
+		 requested using this method, things should still work.  */
+	      warning (_("Method %s appears to be optimized out.\n"
+			 "All references to this method will be undefined."),
+			 TYPE_FN_FIELD_PHYSNAME (methods, j));
+	      continue;
+	    }
+
+	  const char *filename = symbol_symtab (sym.symbol)->filename;
+	  unsigned int line = SYMBOL_LINE (sym.symbol);
+	  CORE_ADDR address = BLOCK_START (SYMBOL_BLOCK_VALUE (sym.symbol));
+	  const char *kind;
+
+	  if (TYPE_FN_FIELD_STATIC_P (methods, j))
+	    {
+	      kind = "static method";
+	      method_type = compile_cplus_convert_func
+		(instance, TYPE_FN_FIELD_TYPE (methods, j), true);
+	    }
+	  else
+	    {
+	      kind = "method";
+	      method_type = (compile_cplus_convert_method
+			     (instance, type, TYPE_FN_FIELD_TYPE (methods, j)));
+	    }
+
+	  if (TYPE_FN_FIELD_VIRTUAL_P (methods, j))
+	    sym_kind |= GCC_CP_FLAG_VIRTUAL_FUNCTION;
+
+	  instance->plugin ().build_decl
+	    (kind, overloaded_name.get (),
+	     sym_kind | get_method_access_flag (type, i, j),
+	     method_type, nullptr, address, filename, line);
+	}
+    }
+}
+
+/* Convert a struct or union type to its gcc representation.  If this type
+   was defined in another type, NESTED_ACCESS should indicate the
+   accessibility of this type.  */
+
+static gcc_type
+compile_cplus_convert_struct_or_union (compile_cplus_instance *instance,
+				       struct type *type,
+				       enum gcc_cp_symbol_kind nested_access)
+{
+  const char *filename = nullptr;
+  unsigned short line = 0;
+
+  /* Get the decl name of this type.  */
+  gdb::unique_xmalloc_ptr<char> name = decl_name (TYPE_NAME (type));
+
+  /* Create a new scope for TYPE.  */
+  compile_scope scope = instance->new_scope (TYPE_NAME (type), type);
+
+  if (scope.nested_type () != GCC_TYPE_NONE)
+    {
+      /* The type requested was actually defined inside another type,
+	 such as a nested class definition.  Return that type.  */
+      return scope.nested_type ();
+    }
+
+  /* Push all scopes.  */
+  instance->enter_scope (scope);
+
+  /* First we create the resulting type and enter it into our hash
+     table.  This lets recursive types work.  */
+
+  gcc_decl resuld;
+  if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
+    {
+      const char *what = TYPE_DECLARED_CLASS (type) ? "struct" : "class";
+
+      resuld = instance->plugin ().build_decl
+	(what, name.get (), (GCC_CP_SYMBOL_CLASS | nested_access
+			     | (TYPE_DECLARED_CLASS (type)
+				? GCC_CP_FLAG_CLASS_NOFLAG
+				: GCC_CP_FLAG_CLASS_IS_STRUCT)),
+	 0, nullptr, 0, filename, line);
+    }
+  else
+    {
+      gdb_assert (TYPE_CODE (type) == TYPE_CODE_UNION);
+      resuld = instance->plugin ().build_decl
+	("union", name.get (), GCC_CP_SYMBOL_UNION | nested_access,
+	 0, nullptr, 0, filename, line);
+    }
+
+  gcc_type result;
+  if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
+    {
+      struct gcc_vbase_array bases;
+      int num_baseclasses = TYPE_N_BASECLASSES (type);
+
+      memset (&bases, 0, sizeof (bases));
+
+      if (num_baseclasses > 0)
+	{
+	  bases.elements = XNEWVEC (gcc_type, num_baseclasses);
+	  bases.flags = XNEWVEC (enum gcc_cp_symbol_kind, num_baseclasses);
+	  bases.n_elements = num_baseclasses;
+	  for (int i = 0; i < num_baseclasses; ++i)
+	    {
+	      struct type *base_type = TYPE_BASECLASS (type, i);
+
+	      bases.flags[i] = GCC_CP_SYMBOL_BASECLASS
+		| get_field_access_flag (type, i)
+		| (BASETYPE_VIA_VIRTUAL (type, i)
+		   ? GCC_CP_FLAG_BASECLASS_VIRTUAL
+		   : GCC_CP_FLAG_BASECLASS_NOFLAG);
+	      bases.elements[i] = instance->convert_type (base_type);
+	    }
+	}
+
+      result = instance->plugin ().start_class_type
+	(name.get (), resuld, &bases, filename, line);
+      xfree (bases.flags);
+      xfree (bases.elements);
+    }
+  else
+    {
+      gdb_assert (TYPE_CODE (type) == TYPE_CODE_UNION);
+      result = instance->plugin ().start_class_type
+	(name.get (), resuld, nullptr, filename, line);
+    }
+
+  instance->insert_type (type, result);
+
+  /* Add definitions.  */
+  compile_cplus_convert_type_defns (instance, type);
+
+  /* Add methods.  */
+  compile_cplus_convert_struct_or_union_methods (instance, type, result);
+
+  /* Add members.  */
+  compile_cplus_convert_struct_or_union_members (instance, type, result);
+
+  /* All finished.  */
+  instance->plugin ().finish_class_type (name.get (), TYPE_LENGTH (type));
+
+  /* Pop all scopes.  */
+  instance->leave_scope ();
+  return result;
+}
+
+/* Convert an enum type to its gcc representation.  If this type
+   was defined in another type, NESTED_ACCESS should indicate the
+   accessibility of this type.*/
+
+static gcc_type
+compile_cplus_convert_enum (compile_cplus_instance *instance, struct type *type,
+			    enum gcc_cp_symbol_kind nested_access)
+{
+  int scoped_enum_p = FALSE;
+
+  /* Create a new scope for this type.  */
+  compile_scope scope = instance->new_scope (TYPE_NAME (type), type);
+
+  if (scope.nested_type () != GCC_TYPE_NONE)
+    {
+      /* The type requested was actually defined inside another type,
+	 such as a nested class definition.  Return that type.  */
+      return scope.nested_type ();
+    }
+
+  gdb::unique_xmalloc_ptr<char> name = decl_name (TYPE_NAME (type));
+
+  /* Push all scopes.  */
+  instance->enter_scope (scope);
+
+  gcc_type int_type
+    = instance->plugin ().get_int_type (TYPE_UNSIGNED (type),
+					TYPE_LENGTH (type), nullptr);
+  gcc_type result
+    = instance->plugin ().start_enum_type (name.get (), int_type,
+					   GCC_CP_SYMBOL_ENUM | nested_access
+					   | (scoped_enum_p
+					      ? GCC_CP_FLAG_ENUM_SCOPED
+					      : GCC_CP_FLAG_ENUM_NOFLAG),
+					   nullptr, 0);
+  for (int i = 0; i < TYPE_NFIELDS (type); ++i)
+    {
+      gdb::unique_xmalloc_ptr<char> fname
+	= decl_name (TYPE_FIELD_NAME (type, i));
+
+      if (TYPE_FIELD_LOC_KIND (type, i) != FIELD_LOC_KIND_ENUMVAL
+	  || fname == nullptr)
+	continue;
+
+      instance->plugin ().build_enum_constant (result, fname.get (),
+					       TYPE_FIELD_ENUMVAL (type, i));
+    }
+
+  /* Finish enum definition and pop scopes.  */
+  instance->plugin ().finish_enum_type (result);
+  instance->leave_scope ();
+  return result;
+}
+
+/* Convert a function type to its gcc representation.  This function does
+   not deal with function templates.  */
+
+static gcc_type
+compile_cplus_convert_func (compile_cplus_instance *instance,
+			    struct type *type, bool strip_artificial)
+{
+  int is_varargs = TYPE_VARARGS (type);
+  struct type *target_type = TYPE_TARGET_TYPE (type);
+
+  /* Functions with no debug info have no return type.  Ideally we'd
+     want to fallback to the type of the cast just before the
+     function, like GDB's built-in expression parser, but we don't
+     have access to that type here.  For now, fallback to int, like
+     GDB's parser used to do.  */
+  if (target_type == nullptr)
+    {
+      if (TYPE_OBJFILE_OWNED (type))
+	target_type = objfile_type (TYPE_OWNER (type).objfile)->builtin_int;
+      else
+	target_type = builtin_type (TYPE_OWNER (type).gdbarch)->builtin_int;
+      warning (_("function has unknown return type; assuming int"));
+    }
+
+  /* This approach means we can't make self-referential function
+     types.  Those are impossible in C, though.  */
+  gcc_type return_type = instance->convert_type (target_type);
+
+  struct gcc_type_array array =
+    { TYPE_NFIELDS (type), XNEWVEC (gcc_type, TYPE_NFIELDS (type)) };
+  int artificials = 0;
+  for (int i = 0; i < TYPE_NFIELDS (type); ++i)
+    {
+      if (strip_artificial && TYPE_FIELD_ARTIFICIAL (type, i))
+	{
+	  --array.n_elements;
+	  ++artificials;
+	}
+      else
+	{
+	  array.elements[i - artificials]
+	    = instance->convert_type (TYPE_FIELD_TYPE (type, i));
+	}
+    }
+
+  /* We omit setting the argument types to `void' to be a little flexible
+     with some minsyms like printf (compile-cplus.exp has examples).  */
+  gcc_type result = instance->plugin ().build_function_type
+    (return_type, &array, is_varargs);
+  xfree (array.elements);
+  return result;
+}
+
+/* Convert an integer type to its gcc representation.  */
+
+static gcc_type
+compile_cplus_convert_int (compile_cplus_instance *instance, struct type *type)
+{
+  if (TYPE_NOSIGN (type))
+    {
+      gdb_assert (TYPE_LENGTH (type) == 1);
+      return instance->plugin ().get_char_type ();
+    }
+
+  return instance->plugin ().get_int_type
+    (TYPE_UNSIGNED (type), TYPE_LENGTH (type), TYPE_NAME (type));
+}
+
+/* Convert a floating-point type to its gcc representation.  */
+
+static gcc_type
+compile_cplus_convert_float (compile_cplus_instance *instance,
+			     struct type *type)
+{
+  return instance->plugin ().get_float_type
+    (TYPE_LENGTH (type), TYPE_NAME (type));
+}
+
+/* Convert the 'void' type to its gcc representation.  */
+
+static gcc_type
+compile_cplus_convert_void (compile_cplus_instance *instance, struct type *type)
+{
+  return instance->plugin ().get_void_type ();
+}
+
+/* Convert a boolean type to its gcc representation.  */
+
+static gcc_type
+compile_cplus_convert_bool (compile_cplus_instance *instance, struct type *type)
+{
+  return instance->plugin ().get_bool_type ();
+}
+
+/* See description in compile-cplus.h.  */
+
+gcc_type
+compile_cplus_instance::convert_qualified_base (gcc_type base,
+						gcc_cp_qualifiers_flags quals)
+{
+  gcc_type result = base;
+
+  if (quals != GCC_CP_REF_QUAL_NONE)
+    result = plugin ().build_qualified_type (base, quals);
+
+  return result;
+}
+
+/* See description in compile-cplus.h.  */
+
+static gcc_type
+compile_cplus_convert_qualified (compile_cplus_instance *instance,
+				 struct type *type)
+{
+  struct type *unqual = make_unqualified_type (type);
+  gcc_cp_qualifiers_flags quals = (enum gcc_cp_qualifiers) 0;
+  gcc_type unqual_converted = instance->convert_type (unqual);
+
+  if (TYPE_CONST (type))
+    quals |= GCC_CP_QUALIFIER_CONST;
+  if (TYPE_VOLATILE (type))
+    quals |= GCC_CP_QUALIFIER_VOLATILE;
+  if (TYPE_RESTRICT (type))
+    quals |= GCC_CP_QUALIFIER_RESTRICT;
+
+  return instance->convert_qualified_base (unqual_converted, quals);
+}
+
+/* Convert a complex type to its gcc representation.  */
+
+static gcc_type
+compile_cplus_convert_complex (compile_cplus_instance *instance,
+			       struct type *type)
+{
+  gcc_type base = instance->convert_type (TYPE_TARGET_TYPE (type));
+
+  return instance->plugin ().build_complex_type (base);
+}
+
+/* Convert a namespace of TYPE.  */
+
+static gcc_type
+compile_cplus_convert_namespace (compile_cplus_instance *instance,
+				 struct type *type)
+{
+  compile_scope scope = instance->new_scope (TYPE_NAME (type), type);
+  gdb::unique_xmalloc_ptr<char> name = decl_name (TYPE_NAME (type));
+
+  /* Push scope.  */
+  instance->enter_scope (scope);
+
+  /* Convert this namespace.  */
+  instance->plugin ().push_namespace (name.get ());
+  instance->plugin ().pop_binding_level (name.get ());
+
+  /* Pop scope.  */
+  instance->leave_scope ();
+
+  /* Namespaces are non-cacheable types.  */
+  return GCC_TYPE_NONE;
+}
+
+/* A helper function which knows how to convert most types from their
+   gdb representation to the corresponding gcc form.  This examines
+   the TYPE and dispatches to the appropriate conversion function.  It
+   returns the gcc type.
+
+   If the type was defined in another type, NESTED_ACCESS should indicate the
+   accessibility of this type.  */
+
+static gcc_type
+convert_type_cplus_basic (compile_cplus_instance *instance,
+			  struct type *type,
+			  enum gcc_cp_symbol_kind nested_access)
+{
+  /* If we are converting a qualified type, first convert the
+     unqualified type and then apply the qualifiers.  */
+  if ((TYPE_INSTANCE_FLAGS (type) & (TYPE_INSTANCE_FLAG_CONST
+				     | TYPE_INSTANCE_FLAG_VOLATILE
+				     | TYPE_INSTANCE_FLAG_RESTRICT)) != 0)
+    return compile_cplus_convert_qualified (instance, type);
+
+  switch (TYPE_CODE (type))
+    {
+    case TYPE_CODE_REF:
+    case TYPE_CODE_RVALUE_REF:
+      return compile_cplus_convert_reference (instance, type);
+
+    case TYPE_CODE_PTR:
+      return compile_cplus_convert_pointer (instance, type);
+
+    case TYPE_CODE_ARRAY:
+      return compile_cplus_convert_array (instance, type);
+
+    case TYPE_CODE_STRUCT:
+    case TYPE_CODE_UNION:
+      return
+	compile_cplus_convert_struct_or_union (instance, type, nested_access);
+
+    case TYPE_CODE_ENUM:
+      return compile_cplus_convert_enum (instance, type, nested_access);
+
+    case TYPE_CODE_FUNC:
+      return compile_cplus_convert_func (instance, type, false);
+
+    case TYPE_CODE_METHOD:
+      return
+	compile_cplus_convert_method (instance, TYPE_SELF_TYPE (type), type);
+
+    case TYPE_CODE_MEMBERPTR:
+    case TYPE_CODE_METHODPTR:
+      return compile_cplus_convert_memberptr (instance, type);
+      break;
+
+    case TYPE_CODE_INT:
+      return compile_cplus_convert_int (instance, type);
+
+    case TYPE_CODE_FLT:
+      return compile_cplus_convert_float (instance, type);
+
+    case TYPE_CODE_VOID:
+      return compile_cplus_convert_void (instance, type);
+
+    case TYPE_CODE_BOOL:
+      return compile_cplus_convert_bool (instance, type);
+
+    case TYPE_CODE_COMPLEX:
+      return compile_cplus_convert_complex (instance, type);
+
+    case TYPE_CODE_NAMESPACE:
+      return compile_cplus_convert_namespace (instance, type);
+
+    case TYPE_CODE_TYPEDEF:
+      return compile_cplus_convert_typedef (instance, type, nested_access);
+
+    default:
+      break;
+    }
+
+  std::string s = string_printf (_("unhandled TYPE_CODE_%s"),
+				 type_code_to_string (TYPE_CODE (type)));
+
+  return instance->plugin ().error (s.c_str ());
+}
+
+gcc_type
+compile_cplus_instance::convert_type (struct type *type,
+				      enum gcc_cp_symbol_kind nested_access)
+{
+  /* Check if TYPE has already been converted.  */
+  gcc_type result;
+  if (get_cached_type (type, result))
+    return result;
+
+  /* It is the first time this type has been seen -- convert it
+     and cache it, if appropriate..  */
+  result = convert_type_cplus_basic (this, type, nested_access);
+  if (result != GCC_TYPE_NONE)
+    insert_type (type, result);
+  return result;
+}
+
+
+
+/* Plug-in forwards.  */
+
+/* C++ plug-in wrapper.  */
+
+/* A result printer for plug-in calls that return a gcc_type or
+   gcc_decl.  */
+
+static void
+compile_cplus_debug_output_1 (gcc_type arg)
+{
+  fprintf_unfiltered (gdb_stdlog, "%lld", arg);
+}
+
+static void
+compile_cplus_debug_output_1 (const char *arg)
+{
+  if (arg == nullptr)
+    fputs_unfiltered ("NULL", gdb_stdlog);
+  else
+    fputs_unfiltered (arg, gdb_stdlog);
+}
+
+static void
+compile_cplus_debug_output ()
+{
+}
+
+template <typename T>
+static void
+compile_cplus_debug_output_1 (const T *arg)
+{
+}
+
+template <typename T, typename... Targs>
+static void
+compile_cplus_debug_output (T arg, Targs... Args)
+{
+  compile_cplus_debug_output_1 (arg);
+  fputc_unfiltered (' ', gdb_stdlog);
+  compile_cplus_debug_output (Args...);
+}
+
+#define FORWARD(OP,...) m_context->cp_ops->OP(m_context, ##__VA_ARGS__)
+#define OUTPUT_DEBUG_RESULT(R)			  \
+  if (debug_compile_cplus_types)		  \
+    {						  \
+      fputs_unfiltered (": ", gdb_stdlog);	  \
+      compile_cplus_debug_output (R);		  \
+      fputc_unfiltered ('\n', gdb_stdlog);	  \
+    }						  \
+
+#define GCC_METHOD0(R, N)			  \
+  R gcc_cp_plugin::N () const			  \
+  {						  \
+    if (debug_compile_cplus_types)		  \
+      compile_cplus_debug_output (STRINGIFY (N)); \
+    auto result = FORWARD (N);			  \
+    OUTPUT_DEBUG_RESULT (result);		  \
+    return result;				  \
+  }
+#define GCC_METHOD1(R, N, A)				\
+  R gcc_cp_plugin::N (A a) const			\
+  {							\
+    if (debug_compile_cplus_types)			\
+      compile_cplus_debug_output (STRINGIFY (N), a);	\
+    auto result = FORWARD (N, a);			\
+    OUTPUT_DEBUG_RESULT (result);			\
+    return result;					\
+  }
+#define GCC_METHOD2(R, N, A, B)				\
+  R gcc_cp_plugin::N (A a, B b) const			\
+  {							\
+    if (debug_compile_cplus_types)			\
+      compile_cplus_debug_output (STRINGIFY (N), a, b);	\
+    auto result = FORWARD (N, a, b);			\
+    OUTPUT_DEBUG_RESULT (result);			\
+    return result;					\
+  }
+#define GCC_METHOD3(R, N, A, B, C) \
+  R gcc_cp_plugin::N (A a, B b, C c) const			\
+  {								\
+    if (debug_compile_cplus_types)				\
+      compile_cplus_debug_output (STRINGIFY (N), a, b, c);	\
+    auto result = FORWARD (N, a, b, c);				\
+    OUTPUT_DEBUG_RESULT (result);				\
+    return result;						\
+  }
+#define GCC_METHOD4(R, N, A, B, C, D)				\
+  R gcc_cp_plugin::N (A a, B b, C c, D d) const			\
+  {								\
+    if (debug_compile_cplus_types)				\
+      compile_cplus_debug_output (STRINGIFY (N), a, b, c, d);	\
+    auto result = FORWARD (N, a, b, c, d);			\
+    OUTPUT_DEBUG_RESULT (result);				\
+    return result;						\
+  }
+#define GCC_METHOD5(R, N, A, B, C, D, E)				\
+  R gcc_cp_plugin::N (A a, B b, C c, D d, E e) const			\
+  {									\
+    if (debug_compile_cplus_types)					\
+      compile_cplus_debug_output (STRINGIFY (N), a, b, c, d, e);	\
+    auto result = FORWARD (N, a, b, c, d, e);				\
+    OUTPUT_DEBUG_RESULT (result);					\
+    return result;							\
+  }
+#define GCC_METHOD7(R, N, A, B, C, D, E, F, G)				\
+  R gcc_cp_plugin::N (A a, B b, C c, D d, E e, F f, G g) const		\
+  {									\
+    if (debug_compile_cplus_types)					\
+      compile_cplus_debug_output (STRINGIFY (N), a, b, c, d, e, f, g);	\
+    auto result = FORWARD (N, a, b, c, d, e, f, g);			\
+    OUTPUT_DEBUG_RESULT (result);					\
+    return result;							\
+  }
+
+#include "gcc-cp-fe.def"
+
+#undef GCC_METHOD0
+#undef GCC_METHOD1
+#undef GCC_METHOD2
+#undef GCC_METHOD3
+#undef GCC_METHOD4
+#undef GCC_METHOD5
+#undef GCC_METHOD7
+#undef FORWARD
+#undef OUTPUT_DEBUG_RESULT
+
+gcc_expr
+gcc_cp_plugin::build_decl (const char *debug_decltype, const char *name,
+			   enum gcc_cp_symbol_kind sym_kind, gcc_type sym_type,
+			   const char *substitution_name, gcc_address address,
+			   const char *filename, unsigned int line_number)
+{
+  if (debug_compile_cplus_types)
+    fprintf_unfiltered (gdb_stdlog, "<%s> ", debug_decltype);
+
+  return build_decl (name, sym_kind, sym_type, substitution_name,
+		     address, filename, line_number);
+}
+
+gcc_type
+gcc_cp_plugin::start_class_type (const char *debug_name, gcc_decl typedecl,
+				 const struct gcc_vbase_array *base_classes,
+				 const char *filename, unsigned int line_number)
+{
+  if (debug_compile_cplus_types)
+    fprintf_unfiltered (gdb_stdlog, "<%s> ", debug_name);
+
+  return start_class_type (typedecl, base_classes, filename, line_number);
+}
+
+int
+gcc_cp_plugin::finish_class_type (const char *debug_name,
+				  unsigned long size_in_bytes)
+{
+  if (debug_compile_cplus_types)
+    fprintf_unfiltered (gdb_stdlog, "<%s> ", debug_name);
+
+  return finish_class_type (size_in_bytes);
+}
+
+int
+gcc_cp_plugin::pop_binding_level (const char *debug_name)
+{
+  if (debug_compile_cplus_types)
+    fprintf_unfiltered (gdb_stdlog, "<%s> ", debug_name);
+
+  return pop_binding_level ();
+}
+
+void _initialize_compile_cplus_types (void);
+
+void
+_initialize_compile_cplus_types (void)
+{
+  add_setshow_boolean_cmd ("compile-cplus-types", no_class,
+			     &debug_compile_cplus_types, _("\
+Set debugging of C++ compile type conversion."), _("\
+Show debugging of C++ compile type conversion."), _("\
+When enabled debugging messages are printed during C++ type conversion for\n\
+the compile commands."),
+			     nullptr,
+			     nullptr,
+			     &setdebuglist,
+			     &showdebuglist);
+
+  add_setshow_boolean_cmd ("compile-cplus-scopes", no_class,
+			     &debug_compile_cplus_scopes, _("\
+Set debugging of C++ compile scopes."), _("\
+Show debugging of C++ compile scopes."), _("\
+When enabled debugging messages are printed about definition scopes during\n\
+C++ type conversion for the compile commands."),
+			     nullptr,
+			     nullptr,
+			     &setdebuglist,
+			     &showdebuglist);
+}
diff --git a/gdb/compile/compile-cplus.h b/gdb/compile/compile-cplus.h
new file mode 100644
index 0000000000..0f246af310
--- /dev/null
+++ b/gdb/compile/compile-cplus.h
@@ -0,0 +1,207 @@ 
+/* Header file for GDB compile C++ language support.
+   Copyright (C) 2016-2018 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef GDB_COMPILE_CPLUS_H
+#define GDB_COMPILE_CPLUS_H
+
+#include "common/enum-flags.h"
+#include "gcc-cp-plugin.h"
+
+struct type;
+struct block;
+
+/* enum-flags wrapper  */
+DEF_ENUM_FLAGS_TYPE (enum gcc_cp_qualifiers, gcc_cp_qualifiers_flags);
+DEF_ENUM_FLAGS_TYPE (enum gcc_cp_ref_qualifiers, gcc_cp_ref_qualifiers_flags);
+DEF_ENUM_FLAGS_TYPE (enum gcc_cp_symbol_kind, gcc_cp_symbol_kind_flags);
+
+class compile_cplus_instance;
+
+/* A single component of a type's scope.  Type names are broken into
+   "components," a series of unqualified names comprising the type name,
+   e.g., "namespace1", "namespace2", "myclass".  */
+
+struct scope_component
+{
+  /* The unqualified name of this scope.  */
+  std::string name;
+
+  /* The block symbol for this type/scope.  */
+  struct block_symbol bsymbol;
+};
+
+/* Comparison operators for scope_components.  */
+
+bool operator== (const scope_component &lhs, const scope_component &rhs);
+bool operator!= (const scope_component &lhs, const scope_component &rhs);
+
+
+/* A single compiler scope used to define a type.
+
+   A compile_scope is a list of scope_components, where all leading
+   scope_components are namespaces, followed by a single non-namespace
+   type component (the actual type we are converting).  */
+
+class compile_scope : private std::vector<scope_component>
+{
+public:
+
+  using std::vector<scope_component>::push_back;
+  using std::vector<scope_component>::pop_back;
+  using std::vector<scope_component>::back;
+  using std::vector<scope_component>::empty;
+  using std::vector<scope_component>::size;
+  using std::vector<scope_component>::begin;
+  using std::vector<scope_component>::end;
+  using std::vector<scope_component>::operator[];
+
+  compile_scope ()
+    : m_nested_type (GCC_TYPE_NONE), m_pushed (false)
+  {
+  }
+
+  /* Return the gcc_type of the type if it is a nested definition.
+     Returns GCC_TYPE_NONE if this type was not nested.  */
+  gcc_type nested_type ()
+  {
+    return m_nested_type;
+  }
+
+private:
+
+  /* compile_cplus_instance is a friend class so that it can set the
+     following private members when compile_scopes are created.  */
+  friend compile_cplus_instance;
+
+  /* If the type was actually a nested type, this will hold that nested
+     type after the scope is pushed.  */
+  gcc_type m_nested_type;
+
+  /* If true, this scope was pushed to the compiler and all namespaces
+     must be popped when leaving the scope.  */
+  bool m_pushed;
+};
+
+/* Comparison operators for compile_scopes.  */
+
+bool operator== (const compile_scope &lhs, const compile_scope &rhs);
+bool operator!= (const compile_scope &lhs, const compile_scope &rhs);
+
+/* Convert TYPENAME into a vector of namespace and top-most/super
+   composite scopes.
+
+   For example, for the input "Namespace::classB::classInner", the
+   resultant vector will contain the tokens "Namespace" and
+   "classB".  */
+
+compile_scope type_name_to_scope (const char *type_name,
+				  const struct block *block);
+
+/* A callback suitable for use as the GCC C++ symbol oracle.  */
+
+extern gcc_cp_oracle_function gcc_cplus_convert_symbol;
+
+/* A callback suitable for use as the GCC C++ address oracle.  */
+
+extern gcc_cp_symbol_address_function gcc_cplus_symbol_address;
+
+/* Callbacks suitable for use as the GCC C++ enter/leave scope requests.  */
+
+extern gcc_cp_enter_leave_user_expr_scope_function gcc_cplus_enter_scope;
+extern gcc_cp_enter_leave_user_expr_scope_function gcc_cplus_leave_scope;
+
+/* A subclass of compile_instance that is specific to the C++ front
+   end.  */
+
+class compile_cplus_instance : public compile_instance
+{
+public:
+
+  explicit compile_cplus_instance (struct gcc_cp_context *gcc_cp)
+    : compile_instance (&gcc_cp->base, m_default_cflags),
+      m_plugin (gcc_cp)
+  {
+    m_plugin.set_callbacks (gcc_cplus_convert_symbol,
+			    gcc_cplus_symbol_address,
+			    gcc_cplus_enter_scope, gcc_cplus_leave_scope,
+			    this);
+  }
+
+  /* Convert a gdb type, TYPE, to a GCC type.
+
+     If this type was defined in another type, NESTED_ACCESS should indicate
+     the accessibility of this type (or GCC_CP_ACCESS_NONE if not a nested
+     type).  GCC_CP_ACCESS_NONE is the default nested access.
+
+     The new GCC type is returned.  */
+  gcc_type convert_type
+    (struct type *type,
+     enum gcc_cp_symbol_kind nested_access = GCC_CP_ACCESS_NONE);
+
+  /* Return a handle for the GCC plug-in.  */
+  gcc_cp_plugin &plugin () { return m_plugin; }
+
+  /* Factory method to create a new scope based on TYPE with name TYPE_NAME.
+     [TYPE_NAME could be TYPE_NAME or SYMBOL_NATURAL_NAME.]
+
+     If TYPE is a nested or local definition, nested_type () will return
+     the gcc_type of the conversion.
+
+     Otherwise, nested_type () is GCC_TYPE_NONE.  */
+  compile_scope new_scope (const char *type_name, struct type *type);
+
+  /* Enter the given NEW_SCOPE.  */
+  void enter_scope (compile_scope &scope);
+
+  /* Leave the current scope.  */
+  void leave_scope ();
+
+  /* Add the qualifiers given by QUALS to BASE.  */
+  gcc_type convert_qualified_base (gcc_type base,
+				   gcc_cp_qualifiers_flags quals);
+
+  /* Convert TARGET into a pointer type.  */
+  gcc_type convert_pointer_base (gcc_type target);
+
+  /* Convert BASE into a reference type.  RQUALS describes the reference.  */
+  gcc_type convert_reference_base (gcc_type base,
+				   enum gcc_cp_ref_qualifiers rquals);
+
+private:
+
+  /* Default compiler flags for C++.  */
+  static const char *m_default_cflags;
+
+  /* The GCC plug-in.  */
+  gcc_cp_plugin m_plugin;
+
+  /* A list of scopes we are processing.  */
+  std::vector<compile_scope> m_scopes;
+};
+
+/* Return the declaration name of the symbol named NATURAL.
+   This returns a name with no function arguments or template parameters,
+   suitable for passing to the compiler plug-in.  */
+
+gdb::unique_xmalloc_ptr<char> decl_name (const char *natural);
+
+/* Get the access flag for the NUM'th method of TYPE's FNI'th
+   fieldlist.  */
+
+enum gcc_cp_symbol_kind get_method_access_flag (const struct type *type,
+						int fni, int num);
+
+#endif /* GDB_COMPILE_CPLUS_H  */
diff --git a/gdb/compile/compile-internal.h b/gdb/compile/compile-internal.h
index c8d2d2f427..483a0d5f7f 100644
--- a/gdb/compile/compile-internal.h
+++ b/gdb/compile/compile-internal.h
@@ -23,6 +23,10 @@ 
 
 extern int compile_debug;
 
+/* Flag to enable internal debugging for oracle requests.  */
+
+extern int debug_compile_oracle;
+
 struct block;
 
 /* An object that maps a gdb type to a gcc type.  */
@@ -164,6 +168,10 @@  protected:
 #define COMPILE_I_EXPR_VAL "__gdb_expr_val"
 #define COMPILE_I_EXPR_PTR_TYPE "__gdb_expr_ptr_type"
 
+/* A "type" to indicate a NULL type.  */
+
+const gcc_type GCC_TYPE_NONE = (gcc_type) -1;
+
 /* Call gdbarch_register_name (GDBARCH, REGNUM) and convert its result
    to a form suitable for the compiler source.  The register names
    should not clash with inferior defined macros. */
diff --git a/gdb/compile/compile-object-load.c b/gdb/compile/compile-object-load.c
index a83f95dda9..873750b944 100644
--- a/gdb/compile/compile-object-load.c
+++ b/gdb/compile/compile-object-load.c
@@ -459,7 +459,8 @@  get_out_value_type (struct symbol *func_sym, struct objfile *objfile,
       if (function != NULL
 	  && (BLOCK_SUPERBLOCK (function_block)
 	      == BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK))
-	  && (strcmp (SYMBOL_LINKAGE_NAME (function), GCC_FE_WRAPPER_FUNCTION)
+	  && (strcmp_iw (SYMBOL_LINKAGE_NAME (function),
+			 GCC_FE_WRAPPER_FUNCTION)
 	      == 0))
 	break;
     }
@@ -478,7 +479,7 @@  get_out_value_type (struct symbol *func_sym, struct objfile *objfile,
   gdb_ptr_type = check_typedef (gdb_ptr_type);
   if (TYPE_CODE (gdb_ptr_type) != TYPE_CODE_PTR)
     error (_("Type of \"%s\" is not a pointer"), COMPILE_I_EXPR_PTR_TYPE);
-  gdb_type_from_ptr = TYPE_TARGET_TYPE (gdb_ptr_type);
+  gdb_type_from_ptr = check_typedef (TYPE_TARGET_TYPE (gdb_ptr_type));
 
   if (types_deeply_equal (gdb_type, gdb_type_from_ptr))
     {
@@ -741,6 +742,8 @@  compile_object_load (const compile_file_names &file_names,
 	      ? mst_unknown : MSYMBOL_TYPE (bmsym.minsym))
 	{
 	case mst_text:
+	case mst_bss:
+	case mst_data:
 	  sym->value = BMSYMBOL_VALUE_ADDRESS (bmsym);
 	  if (compile_debug)
 	    fprintf_unfiltered (gdb_stdlog,
diff --git a/gdb/compile/compile.c b/gdb/compile/compile.c
index 31ae5970b9..efa4e8d0fa 100644
--- a/gdb/compile/compile.c
+++ b/gdb/compile/compile.c
@@ -995,7 +995,6 @@  String quoting is parsed like in shell, for example:\n\
 			 " -fPIE"
   /* We want warnings, except for some commonly happening for GDB commands.  */
 			 " -Wall "
-			 " -Wno-implicit-function-declaration"
 			 " -Wno-unused-but-set-variable"
 			 " -Wno-unused-variable"
   /* Override CU's possible -fstack-protector-strong.  */
diff --git a/gdb/compile/gcc-cp-plugin.h b/gdb/compile/gcc-cp-plugin.h
new file mode 100644
index 0000000000..1b72726a67
--- /dev/null
+++ b/gdb/compile/gcc-cp-plugin.h
@@ -0,0 +1,85 @@ 
+/* GCC C++ plug-in wrapper for GDB.
+
+   Copyright (C) 2018 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* A class representing the GCC C++ plug-in.  */
+
+#include "gcc-cp-interface.h"
+
+class gcc_cp_plugin
+{
+public:
+
+  explicit gcc_cp_plugin (struct gcc_cp_context *gcc_cp)
+    : m_context (gcc_cp)
+  {
+  }
+
+  /* Set the oracle callbacks to be used by the compiler plug-in.  */
+  void set_callbacks (gcc_cp_oracle_function *binding_oracle,
+		      gcc_cp_symbol_address_function *address_oracle,
+		      gcc_cp_enter_leave_user_expr_scope_function *enter_scope,
+		      gcc_cp_enter_leave_user_expr_scope_function *leave_scope,
+		      void *datum)
+  {
+    m_context->cp_ops->set_callbacks (m_context, binding_oracle,
+				      address_oracle, enter_scope, leave_scope,
+				      datum);
+  }
+
+  /* Returns the interface version of the compiler plug-in.  */
+  int version () const { return m_context->cp_ops->cp_version; }
+
+#define GCC_METHOD0(R, N) R N () const;
+#define GCC_METHOD1(R, N, A) R N (A) const;
+#define GCC_METHOD2(R, N, A, B) R N (A, B) const;
+#define GCC_METHOD3(R, N, A, B, C) R N (A, B, C) const;
+#define GCC_METHOD4(R, N, A, B, C, D) R N (A, B, C, D) const;
+#define GCC_METHOD5(R, N, A, B, C, D, E) R N (A, B, C, D, E) const;
+#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) R N (A, B, C, D, E, F, G) const;
+
+#include "gcc-cp-fe.def"
+
+#undef GCC_METHOD0
+#undef GCC_METHOD1
+#undef GCC_METHOD2
+#undef GCC_METHOD3
+#undef GCC_METHOD4
+#undef GCC_METHOD5
+#undef GCC_METHOD7
+
+  /* Special overloads of plug-in methods with added debugging information.  */
+
+  gcc_expr build_decl (const char *debug_decltype, const char *name,
+		       enum gcc_cp_symbol_kind sym_kind, gcc_type sym_type,
+		       const char *substitution_name, gcc_address address,
+		       const char *filename, unsigned int line_number);
+
+  gcc_type start_class_type (const char *debug_name, gcc_decl typedecl,
+			     const struct gcc_vbase_array *base_classes,
+			     const char *filename, unsigned int line_number);
+
+  int finish_class_type (const char *debug_name, unsigned long size_in_bytes);
+
+  int pop_binding_level (const char *debug_name);
+
+private:
+
+  /* The GCC C++ context.  */
+  struct gcc_cp_context *m_context;
+};
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index ceb4043e32..f8fcd33481 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,8 @@ 
+YYYY-MM-DD  Keith Seitz  <keiths@redhat.com>
+
+	* gdb.texinfo (Compiling and injecting code in GDB): Document
+	set/show "compile-oracle" and "compile-cplus-types" commands.
+
 2018-08-07  Simon Marchi  <simon.marchi@ericsson.com>
 
 	* gdb.texinfo (Index Files Speed Up GDB): Add section about
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index b931834400..c17c19caa2 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18689,6 +18689,26 @@  injecting the code.  The default is off.
 @item show debug compile
 Displays the current state of displaying @value{GDBN} process of
 compiling and injecting the code.
+
+@anchor{set debug compile-oracle}
+@item set debug compile-oracle
+@cindex compile oracle debugging info
+Turns on or off display of symbol requests from the compiler plug-in
+(the ``oracle'').  The default is off.
+
+@item show debug compile-oracle
+Displays the current state of displaying symbol requests made by the
+compiler plug-in.
+
+@anchor{set debug compile-cplus-types}
+@item set debug compile-cplus-types
+@cindex compile C++ type conversion
+Turns on or off the display of C++ type conversion debugging information.
+The default is off.
+
+@item show debug compile-cplus-types
+Displays the current state of displaying debugging information for
+C++ type conversion.
 @end table
 
 @subsection Compilation options for the @code{compile} command
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index bd3c3bfec5..050e406349 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,28 @@ 
+YYYY-MM-DD  Keith Seitz  <keiths@redhat.com>
+
+	* gdb.compile/compile-cplus-anonymous.cc: New file.
+	* gdb.compile/compile-cplus-anonymous.exp: New file.
+	* gdb.compile/compile-cplus-array-decay.cc: New file.
+	* gdb.compile/compile-cplus-array-decay.exp: New file.
+	* gdb.compile/compile-cplus-inherit.cc: New file.
+	* gdb.compile/compile-cplus-inherit.exp: New file.
+	* gdb.compile/compile-cplus-member.cc: New file.
+	* gdb.compile/compile-cplus-member.exp: New file.
+	* gdb.compile/compile-cplus-method.cc: New file.
+	* gdb.compile/compile-cplus-method.exp: New file.
+	* gdb.compile/compile-cplus-mod.c: "New" file.
+	* gdb.compile/compile-cplus-namespace.cc: New file.
+	* gdb.compile/compile-cplus-namespace.exp: New file.
+	* gdb.compile/compile-cplus-nested.cc: New file.
+	* gdb.compile/compile-cplus-nested.exp: New file.
+	* gdb.compile/compile-cplus-print.c: "New" file.
+	* gdb.compile/compile-cplus-print.exp: "New" file.
+	* gdb.compile/compile-cplus-virtual.cc: New file.
+	* gdb.compile/compile-cplus-virtual.exp: New file.
+	* gdb.compile/compile-cplus.c: "New" file.
+	* gdb.compile/compile-cplus.exp: "New" file.
+	* lib/compile-support.exp: New file.
+
 2018-08-09  Andrew Burgess  <andrew.burgess@embecosm.com>
 
 	* gdb.base/vla-optimized-out.exp: Add new test.
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-anonymous.cc b/gdb/testsuite/gdb.compile/compile-cplus-anonymous.cc
new file mode 100644
index 0000000000..4c6673249e
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-anonymous.cc
@@ -0,0 +1,76 @@ 
+/* Copyright 2015-2018 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+namespace {
+  static enum {ABC = 1, DEF, GHI, JKL} anon_e = GHI;
+  static union
+  {
+    char aa;
+    int bb;
+    float ff;
+    double dd;
+    void *pp;
+  } anon_u = { 'a' };
+
+  static struct
+  {
+    char *ptr;
+    int len;
+    struct
+    {
+      unsigned MAGIC;
+    };
+    union
+    {
+      int ua;
+      char *ub;
+    };
+  } anon_s = {"abracadabra", 11, 0xdead, 0xbeef};
+
+  struct A
+  {
+    A (void) : e (AA)
+    {
+      this->u.b = 0;
+      this->s.ptr = "hello";
+      this->s.len = 5;
+    }
+
+    enum {AA = 10, BB, CC, DD} e;
+    union
+    {
+      char a;
+      int b;
+      float f;
+      double d;
+      void *p;
+    } u;
+    struct
+    {
+      char *ptr;
+      int len;
+    } s;
+  };
+};
+
+int
+main (void)
+{
+  A a;
+  int var = 1234;
+
+  return a.u.b + a.s.len + static_cast<int> (a.e)
+    + static_cast<int> (anon_e) + anon_u.bb + anon_s.len; // break here
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-anonymous.exp b/gdb/testsuite/gdb.compile/compile-cplus-anonymous.exp
new file mode 100644
index 0000000000..0aa3290557
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-anonymous.exp
@@ -0,0 +1,64 @@ 
+# Copyright 2015-2018 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Anonymous type conversion tests for GDB's C++ compile feature.
+
+load_lib compile-support.exp
+
+standard_testfile .cc
+
+if {[skip_cplus_tests]} {
+    untested "skipping C++ tests"
+    return
+}
+
+if {[prepare_for_testing $testfile $testfile $srcfile \
+	 {debug nowarnings c++}]} {
+    return -1
+}
+
+if {![runto_main]} {
+    untested "could not run to main"
+    return -1
+}
+
+if {[skip_compile_feature_tests]} {
+    untested \
+	"compile command not supported (could not find libcc1 shared library?)"
+    return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+# Reminder, "var" is an integer; all these types get converted to `int'.
+CompileExpression::new "var"
+CompileExpression::test "anon_e" {(3|GHI)}
+CompileExpression::test "anon_u.aa" {97( 'a')?}
+CompileExpression::test "a.u.b" 0
+CompileExpression::test "a.s.len" 5
+CompileExpression::test "a.e" {(10|A::AA)}
+CompileExpression::test "(*a.s.ptr != 'h')" (0|false)
+CompileExpression::test "A::BB" {(11|A::BB)}
+CompileExpression::test "ABC" {(1|ABC)}
+CompileExpression::test "DEF" {(2|DEF)}
+CompileExpression::test "GHI" {(3|GHI)}
+CompileExpression::test "JKL" {(4|JKL)}
+
+set k "compile/1234 *-*-*"
+CompileExpression::test "anon_s.len" 11 -kfail $k
+CompileExpression::test "anon_s.MAGIC" "57005" -kfail $k
+CompileExpression::test "anon_s.ua" "48879" -kfail $k
+CompileExpression::test "(*anon_s.ptr == 'a')" (1|true) -kfail $k
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-array-decay.cc b/gdb/testsuite/gdb.compile/compile-cplus-array-decay.cc
new file mode 100644
index 0000000000..da51a65654
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-array-decay.cc
@@ -0,0 +1,31 @@ 
+/* Copyright 2017-2018 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+static const char *g_string_initializer = "hello";
+
+int
+main ()
+{
+   int integers[10];
+   const char *strings[10];
+
+   for (auto &i : integers)
+     i = 0;
+
+   for (auto &i : strings)
+     i = g_string_initializer;
+
+  return 0;			// break here
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-array-decay.exp b/gdb/testsuite/gdb.compile/compile-cplus-array-decay.exp
new file mode 100644
index 0000000000..fb3e63fd91
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-array-decay.exp
@@ -0,0 +1,50 @@ 
+# Copyright 2017-2018 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test whether GDB's C++ compile feature is decaying arrays into pointers.
+
+load_lib compile-support.exp
+
+standard_testfile .cc
+
+if {[skip_cplus_tests]} {
+    untested "skipping C++ tests"
+    return
+}
+
+if {[prepare_for_testing $testfile $testfile $srcfile \
+	 {debug nowarnings c++}]} {
+    return -1
+}
+
+if {![runto_main]} {
+    untested "could not run to main"
+    return -1
+}
+
+if {[skip_compile_feature_tests]} {
+    untested \
+	"compile command not supported (could not find libcc1 shared library?)"
+    return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+gdb_test "compile print integers" " = \\{0, 0, 0, 0, 0, 0, 0, 0, 0, 0\\}"
+
+gdb_test "compile print strings" " = \\{$hex \"hello\", $hex \"hello\",\
+    $hex \"hello\", $hex \"hello\", $hex \"hello\", $hex \"hello\",\
+    $hex \"hello\", $hex \"hello\", $hex \"hello\", $hex \"hello\"\\}"
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-inherit.cc b/gdb/testsuite/gdb.compile/compile-cplus-inherit.cc
new file mode 100644
index 0000000000..de81d1a182
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-inherit.cc
@@ -0,0 +1,58 @@ 
+/* Copyright 2015-2018 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+struct A
+{
+  A () : a_ (1) {}
+  int do_it (int amount) { return a_ + amount; }
+
+  int a_;
+};
+
+struct B
+{
+  B () : b_ (2) {}
+  int do_it (int amount) { return b_ - amount; }
+
+  int b_;
+};
+
+struct C
+{
+  C () : c_ (3) {}
+  int do_it (int amount) { return c_ * amount; }
+
+  int c_;
+};
+
+struct D : public A, B, C
+{
+  D () : d_ (4) {}
+
+  int d_;
+};
+
+int
+main (void)
+{
+  D d;
+  int var = 1234;
+
+  var = d.A::do_it (1)
+    + d.B::do_it (2)
+    + d.C::do_it (3);		// break here
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-inherit.exp b/gdb/testsuite/gdb.compile/compile-cplus-inherit.exp
new file mode 100644
index 0000000000..1978cb556a
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-inherit.exp
@@ -0,0 +1,53 @@ 
+# Copyright 2015-2018 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Inheritance tests for GDB's C++ compile feature.
+
+load_lib compile-support.exp
+
+standard_testfile .cc
+
+if {[skip_cplus_tests]} {
+    untested "skipping C++ tests"
+    return
+}
+
+if {[prepare_for_testing $testfile $testfile $srcfile \
+	 {debug nowarnings c++}]} {
+    return -1
+}
+
+if {![runto_main]} {
+    untested "could not run to main"
+    return -1
+}
+
+if {[skip_compile_feature_tests]} {
+    untested \
+	"compile command not supported (could not find libcc1 shared library?)"
+    return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+CompileExpression::new "var"
+CompileExpression::test "d.a_" 1
+CompileExpression::test "d.b_" 2
+CompileExpression::test "d.c_" 3
+CompileExpression::test "d.d_" 4
+CompileExpression::test "d.A::do_it (1)" 2
+CompileExpression::test "d.B::do_it (1)" 1
+CompileExpression::test "d.C::do_it (1)" 3
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-member.cc b/gdb/testsuite/gdb.compile/compile-cplus-member.cc
new file mode 100644
index 0000000000..428e3aab56
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-member.cc
@@ -0,0 +1,83 @@ 
+/* Copyright 2015-2018 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+class A;
+static int get_values (const A& a);
+
+enum myenum {E_A = 10, E_B, E_C, E_D, E_E};
+
+namespace N {
+  typedef enum {NA = 20, NB, NC, ND} ANON_NE;
+}
+
+namespace {
+  typedef enum {AA = 40, AB, AC, AD} ANON_E;
+}
+
+ANON_E g_e = AC;
+
+class A
+{
+public:
+  typedef int ATYPE;
+
+  A(void) : public_ (1), protected_ (N::NB), private_ (3) {}
+  ATYPE public_;
+  static const myenum s_public_;
+  friend ATYPE get_values (const A&);
+
+protected:
+  N::ANON_NE protected_;
+  static N::ANON_NE s_protected_;
+
+private:
+  ATYPE private_;
+  static myenum s_private_;
+};
+
+const myenum A::s_public_ = E_A;
+N::ANON_NE A::s_protected_ = N::NA;
+myenum A::s_private_ = E_C;
+
+static A::ATYPE
+get_values (const A& a)
+{
+  A::ATYPE val;
+
+  val = a.public_ + a.private_;	// 1 + 3
+  if (a.protected_ == N::NB)	// + 21
+    val += 21;
+  if (a.s_public_ == E_A)	// +10
+    val += 10;
+  if (a.s_protected_ == N::NA)	// +20
+    val += 20;
+  if (a.s_private_ == E_C)	// +30
+    val += 30;
+  if (g_e == AC)		// +40
+    val += 40;
+  return val;			// = 125
+}
+
+typedef int A::*PMI;
+
+int
+main (void)
+{
+  A a;
+  int var = 1234;
+  PMI pmi = &A::public_;
+
+  return a.*pmi + get_values (a);		// break here
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-member.exp b/gdb/testsuite/gdb.compile/compile-cplus-member.exp
new file mode 100644
index 0000000000..525ba43c00
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-member.exp
@@ -0,0 +1,77 @@ 
+# Copyright 2015-2018 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Member tests for GDB's C++ compile feature.
+
+load_lib compile-support.exp
+
+standard_testfile .cc
+
+if {[skip_cplus_tests]} {
+    untested "skipping C++ tests"
+    return
+}
+
+if {[prepare_for_testing $testfile $testfile $srcfile \
+	 {debug nowarnings c++}]} {
+    return -1
+}
+
+if {![runto_main]} {
+    untested "could not run to main"
+    return -1
+}
+
+if {[skip_compile_feature_tests]} {
+    untested \
+	"compile command not supported (could not find libcc1 shared library?)"
+    return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+CompileExpression::new "var"
+CompileExpression::test "a.public_" 1
+CompileExpression::test "a.protected_" {(21|N::NB)}
+CompileExpression::test "a.private_" 3
+CompileExpression::test "A::s_public_" {(10|E_A)}
+CompileExpression::test "A::s_protected_" {(20|N::NA)}
+CompileExpression::test "A::s_private_" {(12|E_C)}
+CompileExpression::test "A::ATYPE i = 10; var = i;" 10 -explicit
+CompileExpression::test "get_values (a)" 125
+CompileExpression::test "myenum me = E_B; var = me;" 11 -explicit
+CompileExpression::test "A::s_protected_ = N::NB; var = A::s_protected_;" \
+    21 -explicit
+CompileExpression::test "A::s_private_ = E_B; var = A::s_private_;" 11 -explicit
+CompileExpression::test "N::ANON_NE ae = N::ND; var = ae;" 23 -explicit
+CompileExpression::test {a.*pmi} 1
+CompileExpression::test {a.public_ = 2; var = a.*pmi; a.public_ = 1} 2 -explicit
+CompileExpression::test "g_e" {(42|AC)}
+
+# Test some compilation failures
+set failed {\r\nCompilation failed\.}
+# !!keiths: This should actually really work...
+gdb_test "compile code a.s_public_ = E_B" \
+    ".*assignment of read-only variable 'A::s_public_'$failed"
+
+gdb_test "compile code get_values ()" \
+    ".*too few arguments to function.*$failed"
+
+gdb_test "compile code ATYPE i;" \
+    ".*.ATYPE. was not declared in this scope$failed"
+
+gdb_test "compile code N::ANON_NE nse = E_A" \
+    ".*cannot convert.*$failed"
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-method.cc b/gdb/testsuite/gdb.compile/compile-cplus-method.cc
new file mode 100644
index 0000000000..b5470e06b6
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-method.cc
@@ -0,0 +1,91 @@ 
+/* Copyright 2015-2018 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+class A;
+static int get_value (const A* a);
+
+class A
+{
+public:
+  typedef int ATYPE;
+
+  A (void) : a_ (21) {}
+  ATYPE get_var (void) { return a_; }
+  ATYPE get_var (unsigned long a) { return 100; }
+  ATYPE get_var (ATYPE a) { return 101; }
+  ATYPE get_var (float a) { return 102; }
+  ATYPE get_var (void *a) { return 103;}
+  ATYPE get_var (A& lr) { return 104; }
+  ATYPE get_var (A const& lr) { return 105; }
+
+  ATYPE get_var1 (int n) { return a_ << n; }
+  ATYPE get_var2 (int incr, unsigned n) { return (a_ + incr) << n; }
+
+  static ATYPE get_1 (int a) { return a + 1; }
+  static ATYPE get_2 (int a, int b) { return a + b + 2; }
+
+  friend ATYPE get_value (const A*);
+
+private:
+  ATYPE a_;
+};
+
+static A::ATYPE
+get_value (A::ATYPE a)
+{
+  return a;
+}
+
+static A::ATYPE
+get_value (const A* a)
+{
+  return a->a_;
+}
+
+static A::ATYPE
+get_value (void)
+{
+  return 200;
+}
+
+typedef int (A::*PMF) (A::ATYPE);
+
+int
+main (void)
+{
+  A *a = new A ();
+  int var = 1234;
+  float f = 1.23;
+  unsigned long ul = 0xdeadbeef;
+  A const* ac = a;
+
+  PMF pmf = &A::get_var;
+  PMF *pmf_p = &pmf;
+
+  var -= a->get_var ();		// break here
+  var -= a->get_var (1);
+  var -= a->get_var (ul);
+  var -= a->get_var (f);
+  var -= a->get_var (a);
+  var -= a->get_var (*a);
+  var -= a->get_var (*ac);
+  var -= a->get_var1 (1);
+  var -= a->get_var2 (1, 2);
+  var += (a->*pmf) (1);
+  var -= (a->**pmf_p) (1);
+
+  return var - A::get_1 (1) + A::get_2 (1, 2) + get_value ()
+    + get_value (get_value ()) + get_value (a);
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-method.exp b/gdb/testsuite/gdb.compile/compile-cplus-method.exp
new file mode 100644
index 0000000000..3a5bb82850
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-method.exp
@@ -0,0 +1,67 @@ 
+# Copyright 2015-2018 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Method tests for GDB's C++ compile feature.
+
+load_lib compile-support.exp
+
+standard_testfile .cc
+
+if {[skip_cplus_tests]} {
+    untested "skipping C++ tests"
+    return
+}
+
+if {[prepare_for_testing $testfile $testfile $srcfile \
+	 {debug nowarnings c++}]} {
+    return -1
+}
+
+if {![runto_main]} {
+    untested "could not run to main"
+    return -1
+}
+
+if {[skip_compile_feature_tests]} {
+    untested \
+	"compile command not supported (could not find libcc1 shared library?)"
+    return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+CompileExpression::new "var"
+CompileExpression::test "a->get_var ()" 21
+CompileExpression::test "a->get_var (static_cast<unsigned long> (1))" 100
+CompileExpression::test "a->get_var (static_cast<int> (1))" 101
+CompileExpression::test "a->get_var (static_cast<float> (1))" 102
+CompileExpression::test "a->get_var (static_cast<void *> (a))" 103
+CompileExpression::test "a->get_var (*a)" 104
+CompileExpression::test "a->get_var (*ac)" 105
+CompileExpression::test "a->get_var1 (1)" 42
+CompileExpression::test "a->get_var2 (1, 2)" 88
+CompileExpression::test "A::get_1 (1)" 2
+CompileExpression::test "A::get_2 (1, 2)" 5
+CompileExpression::test "A::get_1 (a->get_var ())" 22
+CompileExpression::test "a->get_var1 (a->get_var () - 16)" 672
+CompileExpression::test "a->get_var2 (a->get_var (), A::get_1 (2))" 336
+CompileExpression::test "get_value ()" 200
+CompileExpression::test "get_value (a)" 21
+CompileExpression::test "get_value (get_value ())" 200
+CompileExpression::test {(a->*pmf) (1)} 101
+CompileExpression::test \
+    {pmf = &A::get_var1; var = (a->*pmf) (2); pmf = &A::get_var} 84 -explicit
+CompileExpression::test {(a->**pmf_p) (1)} 101
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-mod.c b/gdb/testsuite/gdb.compile/compile-cplus-mod.c
new file mode 100644
index 0000000000..56a135ba8c
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-mod.c
@@ -0,0 +1,28 @@ 
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2014-2018 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+extern "C" void
+_gdb_expr (void)
+{
+  // Make 'globalvar' lookup working.
+#pragma GCC push_user_expression
+
+  globalvar = 3;
+  globalvar += 4;
+
+#pragma GCC pop_user_expression
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-namespace.cc b/gdb/testsuite/gdb.compile/compile-cplus-namespace.cc
new file mode 100644
index 0000000000..1f8dc96cd9
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-namespace.cc
@@ -0,0 +1,52 @@ 
+/* Copyright 2015-2018 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+namespace N1
+{
+  namespace N2
+  {
+    namespace N3
+    {
+      namespace N4
+      {
+        static int n4static = 400;
+
+        struct S4
+        {
+          static int s4static;
+          int s4int_;
+          S4 (void) : s4int_ (4) {};
+          ~S4 (void) { --s4static; }
+
+         int get_var (void) { return s4int_; }
+         static int get_svar (void) { return s4static; }
+        };
+        int S4::s4static = 40;
+      }
+    }
+  }
+}
+
+int
+main (void)
+{
+  using namespace N1::N2::N3::N4;
+
+  S4 s4;
+  int var = 1234;
+
+  var += s4.s4int_; /* break here */
+  return S4::get_svar () - 10 * s4.get_var ();
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-namespace.exp b/gdb/testsuite/gdb.compile/compile-cplus-namespace.exp
new file mode 100644
index 0000000000..768a707b93
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-namespace.exp
@@ -0,0 +1,51 @@ 
+# Copyright 2015-2018 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Namespace tests for GDB's C++ compile feature.
+
+load_lib compile-support.exp
+
+standard_testfile .cc
+
+if {[skip_cplus_tests]} {
+    untested "skipping C++ tests"
+    return
+}
+
+if {[prepare_for_testing $testfile $testfile $srcfile \
+	 {debug nowarnings c++}]} {
+    return -1
+}
+
+if {![runto_main]} {
+    untested "could not run to main"
+    return -1
+}
+
+if {[skip_compile_feature_tests]} {
+    untested \
+	"compile command not supported (could not find libcc1 shared library?)"
+    return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+CompileExpression::new "var"
+CompileExpression::test "N1::N2::N3::N4::n4static" 400
+CompileExpression::test "N1::N2::N3::N4::S4::s4static" 40
+CompileExpression::test "s4.s4int_" 4
+CompileExpression::test "N1::N2::N3::N4::S4::get_svar ()" 40
+CompileExpression::test "s4.get_var ()" 4
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-nested.cc b/gdb/testsuite/gdb.compile/compile-cplus-nested.cc
new file mode 100644
index 0000000000..5d35cf9c51
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-nested.cc
@@ -0,0 +1,58 @@ 
+/* Copyright 2015-2018 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+class A
+{
+public:
+  A (void) : a_ (1) {}
+  int get (void);
+
+protected:
+  int a_;
+
+private:
+  /* It is important to not /not/ use the nested class definition in A.
+     This exercises a different path through the code.  */
+  struct Inner1
+  {
+    int a_;
+    Inner1 (void) : a_ (2) {}
+
+    struct Inner2
+    {
+      int a_;
+      Inner2 (void) : a_ (3) {}
+    };
+  };
+};
+
+int
+A::get (void)
+{
+  A::Inner1 i1;
+  A::Inner1::Inner2 i2;
+
+  return i1.a_ + i2.a_; // break here
+}
+
+int var = 1234;
+
+int
+main (void)
+{
+  A a;
+
+  return a.get ();
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-nested.exp b/gdb/testsuite/gdb.compile/compile-cplus-nested.exp
new file mode 100644
index 0000000000..3b5ba20b28
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-nested.exp
@@ -0,0 +1,53 @@ 
+# Copyright 2015-2018 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Nested type tests for GDB's C++ compile feature.
+
+load_lib compile-support.exp
+
+standard_testfile .cc
+
+if {[skip_cplus_tests]} {
+    untested "skipping C++ tests"
+    return
+}
+
+if {[prepare_for_testing $testfile $testfile $srcfile \
+	 {debug nowarnings c++}]} {
+    return -1
+}
+
+if {![runto_main]} {
+    untested "could not run to main"
+    return -1
+}
+
+if {[skip_compile_feature_tests]} {
+    untested \
+	"compile command not supported (could not find libcc1 shared library?)"
+    return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+CompileExpression::new "var"
+CompileExpression::test "i1.a_" 2
+CompileExpression::test "i2.a_" 3
+CompileExpression::test "A::Inner1 *i1p = &i1; var = i1p->a_;" 2 -explicit
+CompileExpression::test "A::Inner1::Inner2 *i2p = &i2; var = i2p->a_;" 3 \
+    -explicit
+CompileExpression::test "A::Inner1 &r1 = i1; var = r1.a_;" 2 -explicit
+CompileExpression::test "A::Inner1::Inner2 &r2 = i2; var = r2.a_;" 3 -explicit
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-print.c b/gdb/testsuite/gdb.compile/compile-cplus-print.c
new file mode 100644
index 0000000000..9e6575da66
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-print.c
@@ -0,0 +1,32 @@ 
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2015-2018 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+
+int varint = 10;
+int vararray[] = { 1, 2, 3, 4, 5 };
+int *vararrayp = vararray;
+struct object
+{
+  int field;
+} varobject = { 1 };
+
+int
+main (void)
+{
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-print.exp b/gdb/testsuite/gdb.compile/compile-cplus-print.exp
new file mode 100644
index 0000000000..b554c7ddb3
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-print.exp
@@ -0,0 +1,81 @@ 
+# Copyright 2015-2018 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+load_lib compile-support.exp
+
+standard_testfile
+
+get_compiler_info
+set options {}
+if [test_compiler_info gcc*] {
+    lappend options additional_flags=-g3
+    lappend options additional_flags=-std=gnu++11
+    lappend options c++
+}
+
+set srcfilesoptions [list ${srcfile} ${options}]
+
+if { [eval build_executable_from_specs ${testfile}.exp $testfile {$options} ${srcfilesoptions}] } {
+    return -1
+}
+
+clean_restart ${testfile}
+
+if {[skip_compile_feature_tests]} {
+    untested "compile command not supported (could not find libcc1 shared library?)"
+    return -1
+}
+
+gdb_test_no_output "set language c++" \
+    "Set language to C++"
+
+if ![runto_main] {
+    return -1
+}
+
+gdb_test "compile print varint" " = 10"
+gdb_test "compile print vararray" " = \\{1, 2, 3, 4, 5\\}"
+gdb_test "compile print main" " = \\{int \\(void\\)\\} 0x\[0-9a-f\]+"
+
+set test "compile print *vararray@3"
+gdb_test_multiple $test $test {
+    -re " = \\{1, 2, 3\\}\r\n$gdb_prompt $" {
+	pass $test
+    }
+    -re "warning: .*All references to this method will be undefined\.\r\n" {
+	exp_continue
+    }
+    -re ": error: stray '@' in program\r\n.*\r\n$gdb_prompt $" {
+	kfail compile/18489 "$test"
+    }
+}
+
+set test "compile print *vararrayp@3"
+gdb_test_multiple $test $test {
+    -re " = \\{1, 2, 3\\}\r\n$gdb_prompt $" {
+	pass $test
+    }
+    -re "warning: .*All references to this method will be undefined\.\r\n" {
+	exp_continue
+    }
+    -re ": error: stray '@' in program\r\n.*\r\n$gdb_prompt $" {
+	kfail compile/18489 "$test"
+    }
+}
+
+gdb_test "compile print/x 256" " = 0x100"
+gdb_test {print $} " = 256"
+
+gdb_test "compile print varobject" { = {field = 1}}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-virtual.cc b/gdb/testsuite/gdb.compile/compile-cplus-virtual.cc
new file mode 100644
index 0000000000..5083726303
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-virtual.cc
@@ -0,0 +1,54 @@ 
+/* Copyright 2015-2018 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+struct A
+{
+  virtual int doit (void) { return 1; }
+  virtual int doit3 (void) { return -3; }
+  virtual int doit2 (void) = 0;
+};
+
+struct B : virtual A
+{
+  int doit (void) { return 2; }
+  int doit2 (void) { return 22; }
+};
+
+struct C : virtual A
+{
+  int doit (void) { return 3; }
+  int doit2 (void) { return 33; }
+};
+
+struct D : B, C
+{
+  int doit (void) { return 4; }
+  int doit2 (void) { return 44; }
+};
+
+int
+main (void)
+{
+  int var = 1234;
+  B b;
+  C c;
+  D d;
+  A *ap = &d;
+
+  var = (b.doit () + c.doit () + d.doit () + d.doit3 ()
+	 + ap->doit () + ap->doit2 ());	// break here
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-virtual.exp b/gdb/testsuite/gdb.compile/compile-cplus-virtual.exp
new file mode 100644
index 0000000000..696cc03304
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-virtual.exp
@@ -0,0 +1,71 @@ 
+# Copyright 2015-2018 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Virtual method/inheritance tests for GDB's C++ compile feature.
+
+load_lib compile-support.exp
+
+standard_testfile .cc
+
+if {[skip_cplus_tests]} {
+    untested "skipping C++ tests"
+    return
+}
+
+if {[prepare_for_testing $testfile $testfile $srcfile \
+	 {debug nowarnings c++}]} {
+    return -1
+}
+
+if {![runto_main]} {
+    untested "could not run to main"
+    return -1
+}
+
+if {[skip_compile_feature_tests]} {
+    untested \
+	"compile command not supported (could not find libcc1 shared library?)"
+    return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+CompileExpression::new "var"
+CompileExpression::test "b.doit ()" 2
+CompileExpression::test "c.doit ()" 3
+CompileExpression::test "d.doit ()" 4
+CompileExpression::test "ap->doit ()" 4
+CompileExpression::test "b.doit2 ()" 22
+CompileExpression::test "c.doit2 ()" 33
+CompileExpression::test "d.doit2 ()" 44
+CompileExpression::test "ap->doit2 ()" 44
+CompileExpression::test "b.doit3 ()" -3
+CompileExpression::test "c.doit3 ()" -3
+CompileExpression::test "d.doit3 ()" -3
+
+# These two tests are "disabled".  They represent new/future features.
+# CompileExpression::test \
+    [concat "struct ABC {int doit2(void) { return 3333; }} abc;" \
+	 "var = abc.doit2()"] \
+    3333 -explicit
+# CompileExpression::test \
+    [concat "struct ABC : A {int doit2(void) { return 4444; }} abc;" \
+	 "var = abc.doit2()"] \
+    4444 -explicit
+
+# Test some error conditions
+gdb_test "compile code A a;" \
+    ".*cannot declare variable .a. to be of abstract type.*Compilation failed."
diff --git a/gdb/testsuite/gdb.compile/compile-cplus.c b/gdb/testsuite/gdb.compile/compile-cplus.c
new file mode 100644
index 0000000000..ab14514894
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus.c
@@ -0,0 +1,241 @@ 
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2014-2018 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdbool.h>
+#include <iostream>
+
+#define SOME_MACRO 23
+#define ARG_MACRO(X, Y) ((X) + (Y) - 1)
+
+
+enum enum_type {
+  ONE = 1,
+  TWO = 2
+};
+
+typedef int v4 __attribute__ ((vector_size (16)));
+
+union union_type;
+
+struct struct_type {
+  char charfield;
+  unsigned char ucharfield;
+  short shortfield;
+  unsigned short ushortfield;
+  int intfield;
+  unsigned int uintfield;
+  unsigned int bitfield : 3;
+  long longfield;
+  unsigned long ulongfield;
+  enum enum_type enumfield;
+  float floatfield;
+  double doublefield;
+  const union union_type *ptrfield;
+  struct struct_type *selffield;
+  int arrayfield[5];
+  _Complex double complexfield;
+  _Bool boolfield;
+  v4 vectorfield;
+};
+
+typedef int inttypedef;
+
+union union_type {
+  int intfield;
+  inttypedef typedeffield;
+};
+
+/* volatile provides some coverage of the conversion code.  */
+volatile struct struct_type struct_object;
+
+union union_type union_object;
+
+
+enum ulonger_enum_type {
+  REALLY_MINUS_1 = -1UL,
+};
+
+enum ulonger_enum_type ulonger;
+
+enum longer_enum_type {
+  MINUS_1 = -1,
+  FORCE_TO_LONG = 1L << ((8 * sizeof (long)) - 2)
+};
+
+enum longer_enum_type longer;
+
+int globalvar = 10;
+
+static void
+func_static (int addend)
+{
+  globalvar += addend;
+}
+
+void
+func_global (int subtrahend)
+{
+  globalvar -= subtrahend;
+}
+
+void
+no_args_or_locals (void)
+{
+  /* no_args_or_locals breakpoint */
+}
+
+int *intptr;
+int globalshadow = 10;
+static int staticshadow = 20;
+int externed = 7;
+
+class Base
+{
+  virtual int pure_virt () = 0;
+ public:
+  int return_value () {return a;}
+ private:
+  int a = 1;
+  int b = 2;
+};
+
+class Base2
+{
+  virtual int non_pure () {return 84;}
+ public:
+  int return_value () {return b;}
+ private:
+  int a = 3;
+  int b = 4;
+};
+
+class Base3
+{
+ public:
+  int return_value () {return b;}
+ private:
+  int b = 5;
+};
+
+
+class Multiple : public Base, public Base2
+{
+  int pure_virt ()
+  {
+    int a = Base::return_value ();
+    return a + 42;
+  }
+};
+//struct foo { foo(); virtual ~foo(); }; struct bar : virtual foo { bar(); ~bar(); }; struct baz : bar {}; bar::bar() {} bar::~bar() {} bar t; baz u;
+struct VirtualOnly
+{
+  VirtualOnly();
+  virtual ~VirtualOnly()=0;
+};
+
+VirtualOnly::VirtualOnly ()
+{
+}
+
+VirtualOnly::~VirtualOnly ()
+{
+}
+
+struct VirtualBase : virtual VirtualOnly
+{
+  int z = 22;
+  VirtualBase (void);
+  ~VirtualBase (void);
+};
+
+struct VirtualBase2 : VirtualBase {};
+
+VirtualBase::VirtualBase (void)
+{
+  z = 24;
+}
+
+VirtualBase::~VirtualBase (void)
+{
+  z = 22;
+}
+
+class Foo
+{
+  int var;
+  static const int public_static_var = 12;
+
+ private:
+  int private_var = 0;
+  int private_method (void);
+
+ public:
+  int public_var = 0;
+  int public_method (void);
+  void set_private_var (int);
+};
+
+void Foo::set_private_var (int i)
+{
+  private_var = i;
+}
+
+int Foo::private_method (void)
+{
+  return private_var;
+}
+
+int Foo::public_method (void)
+{
+  return public_var;
+}
+
+int
+main (void)
+{
+  int localvar = 50;
+  int shadowed = 51;
+  int bound = 3;
+  int unresolved = 10;
+  int globalshadow = 100;
+  int staticshadow = 200;
+  int externed = 9;
+  int f = 0;
+  int var = 0;
+  Foo foovar;
+  Multiple *multivar = new Multiple;
+  VirtualBase vbase;
+  VirtualBase2 vbase2;
+  static int static_local = 77000;
+
+  foovar.public_var = 42;
+  foovar.set_private_var (42);
+  multivar->Base2::return_value();
+  {
+    int another_local = 7;
+    int shadowed = 52;
+    extern int unresolved;
+    extern int externed;
+
+    int vla[bound];
+
+    func_static (0); /* break-here */
+    no_args_or_locals ();
+  }
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus.exp b/gdb/testsuite/gdb.compile/compile-cplus.exp
new file mode 100644
index 0000000000..cb8d9cbdfd
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus.exp
@@ -0,0 +1,341 @@ 
+# Copyright 2014-2018 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+load_lib compile-support.exp
+
+standard_testfile .c compile-shlib.c compile-constvar.S compile-nodebug.c
+
+get_compiler_info
+set options {}
+if [test_compiler_info gcc*] {
+    lappend options additional_flags=-g3
+    lappend options additional_flags=-std=gnu++11
+    lappend options c++
+}
+
+if { ![istarget x86_64-*-* ] || ![is_lp64_target] } {
+    verbose "Skipping x86_64 LOC_CONST test."
+    set srcfile3 ""
+}
+
+set srcfilesoptions [list ${srcfile} ${options}]
+if { $srcfile3 != "" } {
+    lappend srcfilesoptions $srcfile3 ${options}
+}
+lappend srcfilesoptions $srcfile4 "nodebug c++"
+if { [eval build_executable_from_specs ${testfile}.exp $testfile {$options} ${srcfilesoptions}] } {
+    return -1
+}
+
+clean_restart ${testfile}
+
+#
+# FIXME: Right now, for C++ we just duplicate the C tests, but force
+# the language to  C++
+#
+gdb_test_no_output "set language c++" \
+    "Set language to C++"
+
+if ![runto_main] {
+    return -1
+}
+
+if {[skip_compile_feature_tests]} {
+    untested "compile command not supported (could not find libcc1 shared library?)"
+    return -1
+}
+
+#
+# Test delimiter for code, and arguments.
+#
+
+
+gdb_test_no_output "compile code globalvar = SOME_MACRO;" \
+    "set variable from macro"
+gdb_test "p globalvar" " = 23" "expect 23"
+
+gdb_test_no_output "compile code globalvar = ARG_MACRO(0, 0);" \
+    "set variable from function-like macro"
+gdb_test "p globalvar" " = -1" "expect -1"
+
+gdb_test_no_output "compile code globalvar = 42;" "set variable"
+gdb_test "p globalvar" " = 42" "expect 42"
+
+gdb_test_no_output "compile code globalvar *= 2;" "modify variable"
+gdb_test "p globalvar" " = 84" "expect 84"
+
+gdb_test_no_output "compile file -r ${srcdir}/${subdir}/${testfile}-mod.c" \
+    "use external source file"
+gdb_test "p globalvar" " = 7" "expect 7"
+
+gdb_test_no_output "compile code func_static (2);" "call static function"
+gdb_test "p globalvar" " = 9" "expect 9"
+gdb_test_no_output "compile code func_global (1);" "call global function"
+gdb_test "p globalvar" " = 8" "expect 8"
+
+gdb_test_no_output \
+    "compile code globalvar = (sizeof (ulonger) == sizeof (long))" \
+    "compute size of ulonger"
+gdb_test "p globalvar" " = 1" "check size of ulonger"
+gdb_test_no_output \
+    "compile code globalvar = (sizeof (longer) == sizeof (long))" \
+    "compute size of longer"
+gdb_test "p globalvar" " = 1" "check size of longer"
+gdb_test_no_output "compile code globalvar = MINUS_1"
+gdb_test "p globalvar" " = -1" "check MINUS_1"
+
+gdb_test_no_output "compile code globalvar = static_local"
+gdb_test "p globalvar" " = 77000" "check static_local"
+
+gdb_test_no_output \
+    "compile code static int staticvar = 5; intptr = &staticvar" \
+    "do not keep jit in memory"
+gdb_test "p *intptr" "Cannot access memory at address 0x\[0-9a-f\]+" \
+    "expect 5"
+
+gdb_test "compile code func_doesnotexist ();" "error: \'func_doesnotexist\' was not declared in this scope.*"
+
+gdb_test "compile code *(volatile int *) 0 = 0;" \
+    "The program being debugged was signaled while in a function called from GDB\\.\r\nGDB remains in the frame where the signal was received\\.\r\n.*" \
+    "compile code segfault first"
+gdb_test "bt" \
+    "\r\n#0  \[^\r\n\]* in _gdb_expr \[^\r\n\]*\r\n#1  <function called from gdb>\r\n.*"
+
+set test "p/x \$pc"
+set infcall_pc 0
+gdb_test_multiple $test $test {
+    -re " = (0x\[0-9a-f\]+)\r\n$gdb_prompt $" {
+	set infcall_pc $expect_out(1,string)
+	pass $test
+    }
+}
+
+gdb_test "info sym $infcall_pc" "\r\n_gdb_expr.*" "info sym found"
+gdb_test "return" "\r\n#0  main .*" "return" \
+	 "Make _gdb_expr\\(__gdb_regs\\*\\) return now\\? \\(y or n\\) " "y"
+gdb_test "info sym $infcall_pc" "\r\nNo symbol matches .*" "info sym not found"
+
+gdb_test_no_output "set unwindonsignal on"
+gdb_test "compile code *(volatile int *) 0 = 0;" \
+    "The program being debugged was signaled while in a function called from GDB\\.\r\nGDB has restored the context to what it was before the call\\.\r\n.*" \
+    "compile code segfault second"
+
+gdb_breakpoint [gdb_get_line_number "break-here"]
+gdb_continue_to_breakpoint "break-here" ".* break-here .*"
+
+# C++ Specific tests.
+## Public methods and members
+
+gdb_test "print foovar.public_var" "42" \
+    "Test compile code foovar.public_var = 42 setting."
+gdb_test_no_output "compile code foovar.public_var = 43;" \
+    "set foobar.public_var to 43"
+gdb_test "print foovar.public_var" "43" \
+    "Test compile code foovar.public_var = 43 setting."
+gdb_test "print foovar.public_method ()" "43" \
+    "Test compile code foovar.public_method  = 43 setting."
+
+## Private methods and members
+gdb_test_no_output "compile code foovar.set_private_var (84);" \
+    "Call class function to set private_var"
+gdb_test "print foovar.private_var" "84" \
+    "Test compile code foovar.set_private_var = 84 setting."
+gdb_test_no_output "compile code foovar.private_var = 85"  \
+    "Directly set a private member in GDB compile5"
+gdb_test "print foovar.private_var" "85" \
+    "Test compile code foovar.set_private_var = 85 setting."
+
+## Simple inheritance
+CompileExpression::new "var"
+CompileExpression::test "class Baz: public Foo {public: int z = 12;}; Baz bazvar; bazvar.z = 24; var = bazvar.z" 24 -explicit
+## Multiple inheritance
+CompileExpression::test "class MI: public Base, public Base2 {int pure_virt () {return 42;}}; MI MIVar; var = MIVar.pure_virt();" 42 -explicit
+CompileExpression::test "class MI: public Base, public Base2 {int pure_virt () {return Base::return_value() + 42;}}; MI MIVar; var =  MIVar.pure_virt();" 43 -explicit
+CompileExpression::test "class Base3 {public: int z = 99;}; class MI: public Base, public Base3 {int pure_virt () {return Base3::z + 42;}}; MI MIVar; var = MIVar.pure_virt();" 141 -explicit
+
+gdb_test "p localvar" " = 50" "expect localvar 50"
+
+gdb_test_no_output "compile code localvar = 12;" "set localvar"
+gdb_test "p localvar" " = 12" "expect 12"
+
+gdb_test_no_output "compile code localvar *= 2;" "modify localvar"
+gdb_test "p localvar" " = 24" "expect 24"
+
+gdb_test_no_output "compile code localvar = shadowed" \
+    "test shadowing"
+gdb_test "p localvar" " = 52" "expect 52"
+
+gdb_test_no_output "compile code localvar = externed"
+gdb_test "p localvar" " = 7" "test extern in inner scope"
+
+gdb_test_no_output "compile code vla\[2\] = 7"
+gdb_test "p vla\[2\]" " = 7"
+gdb_test_no_output \
+    "compile code localvar = (sizeof (vla) == bound * sizeof (vla\[0\]))"
+gdb_test "p localvar" " = 1"
+
+#
+# Test setting fields and also many different types.
+#
+
+gdb_test_no_output "compile code struct_object.selffield = (struct_type*)&struct_object"
+gdb_test "print struct_object.selffield == &struct_object" " = true"
+
+gdb_test_no_output "compile code struct_object.charfield = 1"
+gdb_test "print struct_object.charfield" " = 1 '\\\\001'"
+gdb_test_no_output "compile code struct_object.ucharfield = 1"
+gdb_test "print struct_object.ucharfield" " = 1 '\\\\001'"
+
+foreach {field value} {
+    shortfield -5
+    ushortfield 5
+    intfield -7
+    uintfield 7
+    bitfield 2
+    longfield -9
+    ulongfield 9
+    enumfield ONE
+    floatfield 1
+    doublefield 2
+} {
+    gdb_test_no_output "compile code struct_object.$field = $value"
+    gdb_test "print struct_object.$field" " = $value"
+}
+
+gdb_test_no_output "compile code struct_object.arrayfield\[2\] = 7"
+gdb_test "print struct_object.arrayfield" \
+    " = \\{0, 0, 7, 0, 0\\}"
+
+gdb_test_no_output "compile code struct_object.complexfield = 7 + 5i"
+gdb_test "print struct_object.complexfield" " = 7 \\+ 5 \\* I"
+
+gdb_test_no_output "compile code struct_object.boolfield = 1"
+gdb_test "print struct_object.boolfield" " = true"
+
+gdb_test_no_output "compile code struct_object.vectorfield\[2\] = 7"
+gdb_test "print struct_object.vectorfield" \
+    " = \\{0, 0, 7, 0\\}"
+
+gdb_test_no_output "compile code union_object.typedeffield = 7"
+gdb_test "print union_object.typedeffield" " = 7"
+gdb_test "print union_object.intfield" " = 7"
+
+
+# LOC_UNRESOLVED tests.
+
+gdb_test "print unresolved" " = 20"
+gdb_test "compile code globalvar = unresolved;"
+gdb_test "print globalvar" " = 20" "print unresolved value"
+
+# Test shadowing with global and static variables.
+
+gdb_test_no_output "compile code globalshadow += 1;"
+gdb_test "print globalshadow" " = 101"
+gdb_test_no_output "compile code extern int globalshadow; globalshadow += 5;"
+gdb_test "print 'compile-cplus.c'::globalshadow" " = 15"
+gdb_test "print globalshadow" " = 101" "print globalshadow second time"
+gdb_test_no_output "compile code staticshadow += 2;"
+gdb_test "print staticshadow" " = 202"
+# "extern int staticshadow;" cannot access static variable.
+
+# Raw code cannot refer to locals.
+# As it references global variable we need the #pragma.
+# For #pragma we need multiline input.
+gdb_test_multiple "compile code -r" "compile code -r multiline 1" { -re "\r\n>$" {} }
+gdb_test_multiple "void _gdb_expr(void) {" "compile code -r multiline 2" { -re "\r\n>$" {} }
+gdb_test_multiple "#pragma GCC push_user_expression" "compile code -r multiline 3" { -re "\r\n>$" {} }
+gdb_test_multiple "  globalshadow = 77000;" "compile code -r multiline 4" { -re "\r\n>$" {} }
+gdb_test_multiple "#pragma GCC pop_user_expression" "compile code -r multiline 5" { -re "\r\n>$" {} }
+gdb_test_multiple "}" "compile code -r multiline 6" { -re "\r\n>$" {} }
+gdb_test_no_output "end" "compile code -r multiline 7"
+gdb_test "print 'compile-cplus.c'::globalshadow" " = 77000" \
+    "check globalshadow with -r"
+
+# Test GOT vs. resolving jit function pointers.
+
+gdb_test_no_output "compile -raw -- extern \"C\" void abort(); int func(){return 21;} void _gdb_expr(){int (*funcp)()=func; if (funcp()!=21) abort();}" \
+    "pointer to jit function"
+
+#
+# Test the case where the registers structure would not normally have
+# any fields.
+#
+
+gdb_breakpoint [gdb_get_line_number "no_args_or_locals breakpoint"]
+gdb_continue_to_breakpoint "no_args_or_locals"
+
+gdb_test_no_output "compile code globalvar = 77;" "set variable to 77"
+gdb_test "p globalvar" " = 77" "expect 77"
+
+
+# Test reference to minimal_symbol, not (full) symbol.
+
+gdb_test_no_output "compile code globalvar = func_nodebug (75);" \
+    "call func_nodebug"
+gdb_test "p globalvar" " = -75" "expect -75"
+gdb_test_no_output \
+  "compile code int (*funcp) (int) = (int(*)(int))func_nodebug; globalvar = funcp (76);" \
+  "call func_nodebug indirectly"
+gdb_test "p globalvar" " = -76" "expect -76"
+
+
+# Test compiled module memory protection.
+
+gdb_test_no_output "set debug compile on"
+gdb_test "compile code static const int readonly = 1; *(int *) &readonly = 2;" \
+    "The program being debugged was signaled while in a function called from GDB\\.\r\nGDB has restored the context to what it was before the call\\.\r\n.*"
+gdb_test_no_output "set debug compile off"
+
+
+#
+# Some simple coverage tests.
+#
+
+gdb_test "show debug compile" "Compile debugging is .*"
+gdb_test "show compile-args" \
+    "Compile command command-line arguments are .*"
+gdb_test "compile code -z" "Unknown argument.*"
+
+gdb_test "set lang rust" \
+    "Warning: the current language does not match this frame."
+gdb_test "compile code globalvar" "No compiler support for language rust\."
+gdb_test_no_output "set lang auto"
+
+gdb_test_no_output "compile code union union_type newdecl_u"
+gdb_test_no_output "compile code struct struct_type newdecl_s"
+gdb_test_no_output "compile code inttypedef newdecl_i"
+
+gdb_test "compile file" \
+    "You must provide a filename for this command.*" \
+    "Test compile file without a filename"
+gdb_test "compile file -r" \
+    "You must provide a filename with the raw option set.*" \
+    "Test compile file and raw option without a filename"
+gdb_test "compile file -z" \
+    "Unknown argument.*" \
+    "Test compile file with unknown argument"
+
+
+# LOC_CONST tests.
+
+if { $srcfile3 != "" } {
+    gdb_test "p constvar" " = 3"
+    gdb_test "info addr constvar" {Symbol "constvar" is constant\.}
+
+    gdb_test "compile code globalvar = constvar;"
+    gdb_test "print globalvar" " = 3" "print constvar value"
+} else {
+    untested "print constvar value"
+}
diff --git a/gdb/testsuite/lib/compile-support.exp b/gdb/testsuite/lib/compile-support.exp
new file mode 100644
index 0000000000..b784c3549b
--- /dev/null
+++ b/gdb/testsuite/lib/compile-support.exp
@@ -0,0 +1,227 @@ 
+# Copyright 2015-2018 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Generic/oft used support routines for testing GDB's compile feature.
+
+# Return 1 if we should skip tests of the "compile" feature.
+# This must be invoked after the inferior has been started.
+
+proc skip_compile_feature_tests {} {
+    global gdb_prompt
+
+    set result 0
+    gdb_test_multiple "compile code -- ;" "check for working compile command" {
+	"Could not load libcc1.*\r\n$gdb_prompt $" {
+	    set result 1
+	}
+	-re "Command not supported on this host\\..*\r\n$gdb_prompt $" {
+	    set result 1
+	}
+	-re "\r\n$gdb_prompt $" {
+	}
+    }
+    return $result
+}
+
+# This namespace provides some convenience functions for running
+# "compile code" and "compile print" tests.
+#
+# Exported functions are defined inline below.
+#
+# General usage:
+#
+# Start a new session, noting that the variable "var" will be used for
+# "compile code" expressions.  This variable /must/ exist in the stopped
+# location.
+#
+# CompileExpression::new "var"
+#
+# Test the implicit expression "foo;" with result/value 3.
+# CompileExpression::test "foo" 3
+# ---> Runs the following tests (name of tests ignored for illustration)
+#    gdb_test_no_output "compile code var = foo"
+#    gdb_test "p var" "= 3"
+#    gdb_test "compile print foo;" "= 3"
+#
+# Test the explicit expression "a = function (3); var = a;" with the result 21.
+# CompileExpression::test "a = function (3); var = a;" 21 -explicit
+# ---> Runs the following tests (name of tests ignored for illustration)
+#    gdb_test_no_output "compile code a = function (3); var = a;"
+#    gdb_test "p var" "= 21"
+#
+# Additional option flags may be passed to test to control the behavior
+# of the test harness:
+#
+# Pass -explicit to specify that the test uses an explicit expression,
+# one which sets the value of the variable (see above).  Only the code test
+# will be run.
+#
+# Pass -value and/or -print to indicate that the value and/or print steps
+# will optionally fail. Specify "xfail" or "kfail" to indicate how
+# particular step will fail.  These may be followed by any accepted DejaGNU
+# parameters such as architecture and bug#.  [See examples below.]
+#
+# To specify that the compile (and consequently print and value tests) is
+# expected to kfail/xfail, use -kfail or -xfail with any appropriate
+# DejaGNU parameters.  Both options override -print and -value.
+# [-xfail is given precedence over -kfail should both be given.]
+#
+# -value is used when a "code" test is run, specifying that the "compile
+# code" and "print VAR" steps will fail in the prescribed manner.
+# [If the print step generates a PASS, the test is considered invalidly
+# written.  VAR's value should /always/ be invalidated before a test is
+# run.]
+#
+# -print is used to specify that an expression will fail in the prescribed
+# manner when "print" test is executed.
+#
+# Pass "-name NAME" to set an optional test name.  If not specified,
+# the harness will use test names such as "compile code EXPR" and
+# "result of compile code EXPR".
+#
+# Pass "-noprint" or "-nocode" to suppress print or code tests, respectively,
+# This is useful when the expression being tested modifies the object
+# being tested, e.g., "a++".
+#
+# These options must be passed LAST to CompileExpression::test.
+#
+# Examples:
+#
+# Both "code" and "print" tests are expected to xfail:
+# CompileExpression add_imp "foo" 3 -compile {xfail *-*-*} -print {xfail *-*-*}
+#
+# The "print $VARIABLE" portion of the "code" test is expected to kfail
+# (the actual "compile code" GDB command will succeed), but the "print"
+# test should pass:
+# CompileExpression add_imp "foo" 3 -value {kfail *-*-* gdb/1234}
+
+namespace eval ::CompileExpression {
+
+    # The variable name to check testing results.  This variable
+    # must be in scope when tests are run.
+    variable varName_ {}
+
+    # Start a new expression list.  VARNAME is the name of the variable
+    # that will be printed to check if the result of the test was
+    # successful.
+    proc new {varname} {
+	variable varName_
+
+	set varName_ $varname
+    }
+
+    # Test an expression.
+    #
+    # See the preamble for a list of valid optional arguments.
+    #
+    # Implicit expressions will be sent to GDB in the form
+    # "$varName = $EXP".  "p $varName" will be used to decide the pass
+    # or fail status of the test.
+    #
+    # Explicit expressions will be sent to GDB as-is and tested using only
+    # "compile code".  The expression should set the value of the variable
+    # $varName, which is then printed to determine whether the test passed
+    # or failed.
+    #
+    # Unlike explicit expressions, implicit expressions are tested with both
+    # "compile print" and "compile code".
+
+    proc test {exp result args} {
+	parse_args {{value {"" ""}} {print {"" ""}} {name ""}
+	    {noprint} {nocode} {explicit} {xfail {"" ""}} {kfail {"" ""}}}
+
+	if {[lindex $xfail 0] != ""} {
+	    set l "xfail $xfail"
+	} elseif {[lindex $kfail 0] != ""} {
+	    set l "kfail $kfail"
+	} else {
+	    set l ""
+	    set compile {"" ""}
+	}
+	if {$l != ""} {
+	    set compile $l
+	    set print $l
+	    set value $l
+	}
+
+	if {!$nocode} {
+	    do_test_ code $exp $result $explicit $name \
+		[list $compile $value $print]
+	}
+	if {!$noprint} {
+	    do_test_ print $exp $result $explicit $name \
+		[list $compile $value $print]
+	}
+    }
+
+    # Run a compile test for CMD ("print" or "code").
+
+    proc do_test_ {cmd exp result is_explicit tst fail_list} {
+	variable varName_
+
+	if {![string match $cmd "code"]
+	    && ![string match $cmd "print"]} {
+	    error "invalid command, $cmd; should be \"print\" or \"compile\""
+	}
+
+	# Get expected result of test.  Will be "" if test is
+	# expected to PASS.
+	lassign $fail_list fail_compile fail_value fail_print
+
+	# Set a test name if one hasn't been provided.
+	if {$tst == ""} {
+	    set tst "compile $cmd $exp"
+	}
+
+	if {[string match $cmd "print"]} {
+	    if {!$is_explicit} {
+		eval setup_failures_ $fail_print
+		gdb_test "compile print $exp" $result $tst
+	    }
+	} else {
+	    if {$is_explicit} {
+		set command "compile code $exp"
+	    } else {
+		set command "compile code $varName_ = $exp"
+	    }
+	    eval setup_failures_ $fail_compile
+	    gdb_test_no_output $command $tst
+	    eval setup_failures_ $fail_value
+	    gdb_test "p $varName_" "= $result" "result of $tst"
+	}
+    }
+
+    # A convenience proc used to set up xfail and kfail tests.
+    # HOW is either xfail or kfail (case is ignored).  ARGS is any
+    # optional architecture, bug number, or other string to pass to
+    # respective DejaGNU setup_$how routines.
+
+    proc setup_failures_ {how args} {
+	switch -nocase $how {
+	    xfail {
+		eval setup_xfail $args
+	    }
+
+	    kfail {
+		eval setup_kfail $args
+	    }
+
+	    default {
+		# Do nothing.  Either the test is expected to PASS
+		# or we have an unhandled failure mode.
+	    }
+	}
+    }
+}