diff mbox

[libcc1] add support for C++

Message ID orzii8dvt8.fsf@lxoliva.fsfla.org
State New
Headers show

Commit Message

Alexandre Oliva Jan. 30, 2017, 10:31 p.m. UTC
On Jan 27, 2017, Jason Merrill <jason@redhat.com> wrote:

> On Thu, Jan 26, 2017 at 9:11 PM, Alexandre Oliva <aoliva@redhat.com> wrote:
>> -   introduced, new_friend can be called after the befriended class is
>> +   introduced, new_friend can be called after the befriending class is

> s/new/add/ in the comment, too.

>> +/* Build a template-dependent template type id (e.g., T<A>).

> Let's say "type template-id".

> OK with those changes.

Thanks, here's what I'm checking in
(incremental patch first, full patch last)

Comments

Richard Biener May 26, 2017, 1 p.m. UTC | #1
On Mon, Jan 30, 2017 at 11:31 PM, Alexandre Oliva <aoliva@redhat.com> wrote:
> On Jan 27, 2017, Jason Merrill <jason@redhat.com> wrote:
>
>> On Thu, Jan 26, 2017 at 9:11 PM, Alexandre Oliva <aoliva@redhat.com> wrote:
>>> -   introduced, new_friend can be called after the befriended class is
>>> +   introduced, new_friend can be called after the befriending class is
>
>> s/new/add/ in the comment, too.
>
>>> +/* Build a template-dependent template type id (e.g., T<A>).
>
>> Let's say "type template-id".
>
>> OK with those changes.
>
> Thanks, here's what I'm checking in
> (incremental patch first, full patch last)

struct GTY(()) lang_identifier {
  struct c_common_identifier c_common;
  cxx_binding *namespace_bindings;
  cxx_binding *bindings;
  tree class_template_info;
  tree label_value;
  bool oracle_looked_up;
};

that increased lang_identifier size by 8 bytes while there's "plenty" of free
bits in tree_base (bonus point if you can reap a lang_flag).

Richard.

> diff --git a/include/gcc-cp-fe.def b/include/gcc-cp-fe.def
> index 396931a..c367c1d 100644
> --- a/include/gcc-cp-fe.def
> +++ b/include/gcc-cp-fe.def
> @@ -406,7 +406,7 @@ GCC_METHOD1 (gcc_decl, get_type_decl,
>     class, be they template generics, template specializations or not
>     templates.  TYPE must be a class type (not a template generic).
>
> -   The new_friend call cannot introduce a declaration; even if the
> +   The add_friend call cannot introduce a declaration; even if the
>     friend is first declared as a friend in the source code, the
>     declaration belongs in the enclosing namespace, so it must be
>     introduced in that namespace, and the resulting declaration can
> @@ -441,7 +441,7 @@ GCC_METHOD1 (gcc_decl, get_type_decl,
>
>     In order to simplify such friend declarations, and to enable
>     incremental friend declarations as template specializations are
> -   introduced, new_friend can be called after the befriending class is
> +   introduced, add_friend can be called after the befriending class is
>     fully defined, passing it a non-NULL TYPE argument naming the
>     befriending class type.  */
>
> @@ -477,10 +477,10 @@ GCC_METHOD2 (gcc_type, build_pointer_to_member_type,
>     GCC_CP_SYMBOL_FUNCTION or GCC_CP_SYMBOL_CLASS, that, when the scope
>     is a template parameter list, declares a template function or a
>     template class with the then-closed parameter list.  The scope in
> -   which the new declaration is to be introduced by new_decl must be
> -   entered before calling start_new_template_decl, and new_decl
> -   returns to that scope, from the template parameter list scope,
> -   before introducing the declaration.  */
> +   which the new declaration is to be introduced by build_decl must be
> +   entered before calling start_template_decl, and build_decl returns
> +   to that scope, from the template parameter list scope, before
> +   introducing the declaration.  */
>
>  GCC_METHOD0 (int /* bool */, start_template_decl)
>
> @@ -553,7 +553,7 @@ GCC_METHOD2 (gcc_utempl, build_dependent_class_template,
>              gcc_type,                    /* Argument ENCLOSING_TYPE.  */
>              const char *)                            /* Argument ID.  */
>
> -/* Build a template-dependent template type id (e.g., T<A>).
> +/* Build a template-dependent type template-id (e.g., T<A>).
>     TEMPLATE_DECL should be a template template parameter (e.g., the T
>     in template <template <[...]> class T = X>), and TARGS should
>     specify the template arguments (e.g. <A>).  */
>
>
> Introduce C++ support in libcc1
>
> Extend libcc1's with an API for C++ support.
>
> Extend libcc1's C API to distinguish between integral types with the
> same width, as in C++.  Likewise for float types.
>
> Export small bits of functionality from the C++ front-end for use in
> libcc1.  Add support for the C++ front-end to look up names and
> addresses using a libcc1-registered binding oracle.  Add support for
> global friends.
>
>
> for  gcc/cp/ChangeLog
>
>         Introduce C++ support in libcc1.
>         * cp-tree.h (struct lang_identifier): Add oracle_looked_up.
>         (ansi_opname): Rename to...
>         (cp_operator_id): ... this.  Adjust all callers.
>         (ansi_assopname): Rename to...
>         (cp_assignment_operator_id): ... this.  Adjust all callers.
>         (cp_literal_operator_id): Declare.
>         (set_global_friend): Declare.
>         (is_global_friend): Declare.
>         (enum cp_oracle_request): New type.
>         (cp_binding_oracle_function): New type.
>         (cp_binding_oracle): Declare.
>         (cp_finish_injected_record_type): Declare.
>         * friend.c (global_friend): New var.
>         (set_global_friend): New fn.
>         (is_global_friend): New fn.
>         (is_friend): Call is_global_friend.
>         * name-lookup.c (cp_binding_oracle): New var.
>         (query_oracle): New fn.
>         (qualified_lookup_using_namespace): Call query_oracle.
>         (lookup_name_real_1): Likewise.
>         * parser.c (cp_literal_operator_id): Drop static.
>         * search.c (friend_accessible_p): Call is_global_friend.
>         * semantics.c (is_this_parameter): Accept a variable if the
>         binding oracle is enabled.
>
> for  include
>
>         Introduce C++ support in libcc1.
>         * gcc-c-fe.def (int_type_v0): Rename from...
>         (int_type): ... this.  Introduce new version.
>         (float_type_v0): Rename from...
>         (float_type): ... this.  Introduce new version.
>         (char_type): New.
>         * gcc-c-interface.h (gcc_c_api_version): Add GCC_C_FE_VERSION_1.
>         (gcc_type_array): Move...
>         * gcc-interface.h: ... here.
>         * gcc-cp-fe.def: New.
>         * gcc-cp-interface.h: New.
>
> for  libcc1
>
>         Introduce C++ support.
>         * Makefile.am (AM_CPPFLAGS): Move some -I flags to...
>         (CPPFLAGS_FOR_C_FAMILY, CPPFLAGS_FOR_C, CPPFLAGS_FOR_CXX): ...
>         new macros.
>         (plugin_LTLIBRARIES): Add libcp1plugin.la.
>         (BUILT_SOURCES, MOSTLYCLEANFILES): Add...
>         (cp-compiler-name.h): ... this.  New.
>         (c-compiler-name.h): Rename all over from...
>         (compiler-name.h): ... this.  Create it atomically.
>         (marshall_c_source, marshall_cxx_source): New macros.
>         (libcc1plugin_la_SOURCES): Rename plugin.cc to libcc1plugin.cc.
>         Add marshall_c_source expansion.
>         (libcc1plugin.lo_CPPFLAGS): New macro.
>         (libcp1plugin_la_LDFLAGS): Likewise.
>         (libcp1plugin_la_SOURCES): Likewise.
>         (libcp1plugin.lo_CPPFLAGS): Likewise.
>         (libcp1plugin_la_LIBADD): Likewise.
>         (libcp1plugin_la_DEPENDENCIES): Likewise.
>         (libcp1plugin_la_LINK): Likewise.
>         (libcc1_la_SOURCES): Added marshall_c_source and
>         marshall_cxx_source expansions.
>         * Makefile.in: Rebuild.
>         * compiler-name.h: Rename all over to...
>         * c-compiler-name.h: ... this.  Define C_COMPILER_NAME instead
>         of COMPILER_NAME.
>         * plugin.cc: Rename all over to...
>         * libcc1plugin.cc: ... this.  Include marshall-c.hh.
>         (address_rewriter): Drop cleaning up of VLA sizes.
>         (plugin_build_decl): Mark decls as external.
>         (plugin_tagbind): Propagate name to all variants.
>         (build_anonymous_node): New.
>         (plugin_build_record_type): Use it instead of make_node.
>         (plugin_build_union_type): Likewise.
>         (plugin_build_enum_type): Likewise.
>         (plugin_finish_record_or_union): Update all type variants.
>         (safe_lookup_builtin_type): New.
>         (plugin_int_check): Factor out of, and add checks to, ...
>         (plugin_int_type): ... this.  Rename to...
>         (plugin_int_type_v0): ... this.
>         (plugin_int_type): New interface, new implementation.
>         (plugin_char_type): New.
>         (plugin_float_type_v0): Rename from...
>         (plugin_float_type): ... this.  New interface, new implementation.
>         (plugin_init): Bump handshake version.
>         * libcc1.cc: Include marshall-c.hh.  Drop gcc-interface.h.
>         (call_binding_oracle): Rename to...
>         (c_call_binding_oracle): ... this, into anonymous namespace.
>         (call_symbol_address): Rename to...
>         (c_call_symbol_address): ... this, likewise.
>         (GCC_METHOD#): Move methods into cc1plugin::c:: namespace.
>         (libcc1::compiler::find): Refer to C_COMPILER_NAME.
>         (fork_exec): Bump to GCC_C_FE_VERSION_1.
>         (libcc1_compile): Prefix callbacks with c_.
>         (gcc_c_fe_context): Accept GCC_C_FE_VERSION_1.
>         * libcc1.sym: Export gcc_cp_fe_context.
>         * libcp1.cc: New, mostly copied and adjusted from libcc1.cc.
>         * libcp1plugin.cc: New, initially copied from libcc1plugin.cc.
>         * libcp1plugin.sym: New.
>         * marshall-c.hh: New.  Move C-specific types from...
>         * marshall.cc: ... this.
>         (cc1_plugin::marshall_array_start): New.
>         (cc1_plugin::marshall_array_elmts): New.
>         (cc1_plugin::marshall for gcc_type_array): Use the above.
>         (cc1_plugin::unmarshall_array_start): New.
>         (cc1_plugin::unmarshall_array_elmts): New.
>         (cc1_plugin::unmarshall for gcc_type_array): Use the above.
>         * marshall.hh: Declare the new array building blocks.
>         Drop C-specific unmarshall declarations.
>         * marshall-cp.hh: New.
>         * names.cc (GCC_METHOD#): Add LANG:: to method names.
>         (LANG): Define while including gcc-c-fe.def and gcc-cp-fe.def.
>         * names.hh: Include gcc-c-fe.def and gcc-cp-fe.def in the
>         corresponding namespaces.
>         * rpc.hh: Don't include marshall.hh.
>         [GCC_CP_INTERFACE_H] (argument_wrapper): Specialize for
>         gcc_vbase_array, gcc_cp_template_args, gcc_cp_function_args.
> ---
>  gcc/cp/call.c              |   14
>  gcc/cp/class.c             |   10
>  gcc/cp/cp-tree.h           |   40
>  gcc/cp/decl.c              |    6
>  gcc/cp/decl2.c             |    2
>  gcc/cp/friend.c            |   43
>  gcc/cp/init.c              |    2
>  gcc/cp/lambda.c            |    2
>  gcc/cp/lex.c               |    2
>  gcc/cp/method.c            |   10
>  gcc/cp/name-lookup.c       |   27
>  gcc/cp/parser.c            |  103 +
>  gcc/cp/search.c            |    5
>  gcc/cp/semantics.c         |    7
>  gcc/cp/typeck.c            |    2
>  include/gcc-c-fe.def       |   35
>  include/gcc-c-interface.h  |   21
>  include/gcc-cp-fe.def      | 1050 ++++++++++++
>  include/gcc-cp-interface.h |  496 ++++++
>  include/gcc-interface.h    |   14
>  libcc1/Makefile.am         |   46 -
>  libcc1/Makefile.in         |   68 +
>  libcc1/libcc1.cc           |   78 -
>  libcc1/libcc1.sym          |    1
>  libcc1/libcc1plugin.cc     | 1020 ++++++++++++
>  libcc1/libcp1.cc           |  706 ++++++++
>  libcc1/libcp1plugin.cc     | 3789 ++++++++++++++++++++++++++++++++++++++++++++
>  libcc1/libcp1plugin.sym    |    2
>  libcc1/marshall-c.hh       |   59 +
>  libcc1/marshall-cp.hh      |  271 +++
>  libcc1/marshall.cc         |  111 +
>  libcc1/marshall.hh         |   15
>  libcc1/names.cc            |   20
>  libcc1/names.hh            |   18
>  libcc1/plugin.cc           |  921 -----------
>  libcc1/rpc.hh              |  113 +
>  36 files changed, 7978 insertions(+), 1151 deletions(-)
>  create mode 100644 include/gcc-cp-fe.def
>  create mode 100644 include/gcc-cp-interface.h
>  create mode 100644 libcc1/libcc1plugin.cc
>  create mode 100644 libcc1/libcp1.cc
>  create mode 100644 libcc1/libcp1plugin.cc
>  create mode 100644 libcc1/libcp1plugin.sym
>  create mode 100644 libcc1/marshall-c.hh
>  create mode 100644 libcc1/marshall-cp.hh
>  delete mode 100644 libcc1/plugin.cc
>
> diff --git a/gcc/cp/call.c b/gcc/cp/call.c
> index a78e1a9..2d127e6 100644
> --- a/gcc/cp/call.c
> +++ b/gcc/cp/call.c
> @@ -4426,7 +4426,7 @@ build_op_call_1 (tree obj, vec<tree, va_gc> **args, tsubst_flags_t complain)
>
>    if (TYPE_BINFO (type))
>      {
> -      fns = lookup_fnfields (TYPE_BINFO (type), ansi_opname (CALL_EXPR), 1);
> +      fns = lookup_fnfields (TYPE_BINFO (type), cp_operator_id (CALL_EXPR), 1);
>        if (fns == error_mark_node)
>         return error_mark_node;
>      }
> @@ -5136,7 +5136,7 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
>        add_builtin_candidates (&candidates,
>                               COND_EXPR,
>                               NOP_EXPR,
> -                             ansi_opname (COND_EXPR),
> +                             cp_operator_id (COND_EXPR),
>                               args,
>                               LOOKUP_NORMAL, complain);
>
> @@ -5559,10 +5559,10 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
>      {
>        code2 = TREE_CODE (arg3);
>        arg3 = NULL_TREE;
> -      fnname = ansi_assopname (code2);
> +      fnname = cp_assignment_operator_id (code2);
>      }
>    else
> -    fnname = ansi_opname (code);
> +    fnname = cp_operator_id (code);
>
>    arg1 = prep_operand (arg1);
>
> @@ -6167,7 +6167,7 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
>
>    type = strip_array_types (TREE_TYPE (TREE_TYPE (addr)));
>
> -  fnname = ansi_opname (code);
> +  fnname = cp_operator_id (code);
>
>    if (CLASS_TYPE_P (type)
>        && COMPLETE_TYPE_P (complete_type (type))
> @@ -8277,7 +8277,7 @@ build_special_member_call (tree instance, tree name, vec<tree, va_gc> **args,
>               || name == complete_dtor_identifier
>               || name == base_dtor_identifier
>               || name == deleting_dtor_identifier
> -             || name == ansi_assopname (NOP_EXPR));
> +             || name == cp_assignment_operator_id (NOP_EXPR));
>    if (TYPE_P (binfo))
>      {
>        /* Resolve the name.  */
> @@ -8305,7 +8305,7 @@ build_special_member_call (tree instance, tree name, vec<tree, va_gc> **args,
>        if (!same_type_ignoring_top_level_qualifiers_p
>           (TREE_TYPE (instance), BINFO_TYPE (binfo)))
>         {
> -         if (name != ansi_assopname (NOP_EXPR))
> +         if (name != cp_assignment_operator_id (NOP_EXPR))
>             /* For constructors and destructors, either the base is
>                non-virtual, or it is virtual but we are doing the
>                conversion from a constructor or destructor for the
> diff --git a/gcc/cp/class.c b/gcc/cp/class.c
> index b7c26a1..e243ef2 100644
> --- a/gcc/cp/class.c
> +++ b/gcc/cp/class.c
> @@ -3256,7 +3256,7 @@ static tree
>  dfs_declare_virt_assop_and_dtor (tree binfo, void *data)
>  {
>    tree bv, fn, t = (tree)data;
> -  tree opname = ansi_assopname (NOP_EXPR);
> +  tree opname = cp_assignment_operator_id (NOP_EXPR);
>
>    gcc_assert (t && CLASS_TYPE_P (t));
>    gcc_assert (binfo && TREE_CODE (binfo) == TREE_BINFO);
> @@ -5351,7 +5351,7 @@ vbase_has_user_provided_move_assign (tree type)
>  {
>    /* Does the type itself have a user-provided move assignment operator?  */
>    for (tree fns
> -        = lookup_fnfields_slot_nolazy (type, ansi_assopname (NOP_EXPR));
> +        = lookup_fnfields_slot_nolazy (type, cp_assignment_operator_id (NOP_EXPR));
>         fns; fns = OVL_NEXT (fns))
>      {
>        tree fn = OVL_CURRENT (fns);
> @@ -5515,7 +5515,7 @@ type_has_move_assign (tree t)
>        lazily_declare_fn (sfk_move_assignment, t);
>      }
>
> -  for (fns = lookup_fnfields_slot_nolazy (t, ansi_assopname (NOP_EXPR));
> +  for (fns = lookup_fnfields_slot_nolazy (t, cp_assignment_operator_id (NOP_EXPR));
>         fns; fns = OVL_NEXT (fns))
>      if (move_fn_p (OVL_CURRENT (fns)))
>        return true;
> @@ -5560,7 +5560,7 @@ type_has_user_declared_move_assign (tree t)
>    if (CLASSTYPE_LAZY_MOVE_ASSIGN (t))
>      return false;
>
> -  for (fns = lookup_fnfields_slot_nolazy (t, ansi_assopname (NOP_EXPR));
> +  for (fns = lookup_fnfields_slot_nolazy (t, cp_assignment_operator_id (NOP_EXPR));
>         fns; fns = OVL_NEXT (fns))
>      {
>        tree fn = OVL_CURRENT (fns);
> @@ -5681,7 +5681,7 @@ type_requires_array_cookie (tree type)
>       the array to the deallocation function, so we will need to store
>       a cookie.  */
>    fns = lookup_fnfields (TYPE_BINFO (type),
> -                        ansi_opname (VEC_DELETE_EXPR),
> +                        cp_operator_id (VEC_DELETE_EXPR),
>                          /*protect=*/0);
>    /* If there are no `operator []' members, or the lookup is
>       ambiguous, then we don't need a cookie.  */
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index f91b830..c0983bd 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -332,6 +332,7 @@ struct GTY(()) lang_identifier {
>    cxx_binding *bindings;
>    tree class_template_info;
>    tree label_value;
> +  bool oracle_looked_up;
>  };
>
>  /* Return a typed pointer version of T if it designates a
> @@ -1530,15 +1531,17 @@ struct GTY(()) language_function {
>  /* True if NAME is the IDENTIFIER_NODE for an overloaded "operator
>     new" or "operator delete".  */
>  #define NEW_DELETE_OPNAME_P(NAME)              \
> -  ((NAME) == ansi_opname (NEW_EXPR)            \
> -   || (NAME) == ansi_opname (VEC_NEW_EXPR)     \
> -   || (NAME) == ansi_opname (DELETE_EXPR)      \
> -   || (NAME) == ansi_opname (VEC_DELETE_EXPR))
> +  ((NAME) == cp_operator_id (NEW_EXPR)         \
> +   || (NAME) == cp_operator_id (VEC_NEW_EXPR)  \
> +   || (NAME) == cp_operator_id (DELETE_EXPR)   \
> +   || (NAME) == cp_operator_id (VEC_DELETE_EXPR))
>
> -#define ansi_opname(CODE) \
> +#define cp_operator_id(CODE) \
>    (operator_name_info[(int) (CODE)].identifier)
> -#define ansi_assopname(CODE) \
> +#define cp_assignment_operator_id(CODE) \
>    (assignment_operator_name_info[(int) (CODE)].identifier)
> +/* In parser.c.  */
> +extern tree cp_literal_operator_id (const char *);
>
>  /* TRUE if a tree code represents a statement.  */
>  extern bool statement_code_p[MAX_TREE_CODES];
> @@ -6027,6 +6030,9 @@ extern void make_friend_class                     (tree, tree, bool);
>  extern void add_friend                         (tree, tree, bool);
>  extern tree do_friend                          (tree, tree, tree, tree, enum overload_flags, bool);
>
> +extern void set_global_friend                  (tree);
> +extern bool is_global_friend                   (tree);
> +
>  /* in init.c */
>  extern tree expand_member_init                 (tree);
>  extern void emit_mem_initializers              (tree);
> @@ -6943,6 +6949,25 @@ extern void suggest_alternatives_for            (location_t, tree, bool);
>  extern bool suggest_alternative_in_explicit_scope (location_t, tree, tree);
>  extern tree strip_using_decl                    (tree);
>
> +/* Tell the binding oracle what kind of binding we are looking for.  */
> +
> +enum cp_oracle_request
> +{
> +  CP_ORACLE_IDENTIFIER
> +};
> +
> +/* If this is non-NULL, then it is a "binding oracle" which can lazily
> +   create bindings when needed by the C compiler.  The oracle is told
> +   the name and type of the binding to create.  It can call pushdecl
> +   or the like to ensure the binding is visible; or do nothing,
> +   leaving the binding untouched.  c-decl.c takes note of when the
> +   oracle has been called and will not call it again if it fails to
> +   create a given binding.  */
> +
> +typedef void cp_binding_oracle_function (enum cp_oracle_request, tree identifier);
> +
> +extern cp_binding_oracle_function *cp_binding_oracle;
> +
>  /* in constraint.cc */
>  extern void init_constraint_processing          ();
>  extern bool constraint_p                        (tree);
> @@ -7008,6 +7033,9 @@ extern void diagnose_constraints                (location_t, tree, tree);
>  extern tree decompose_conclusions               (tree);
>  extern bool subsumes                            (tree, tree);
>
> +/* In class.c */
> +extern void cp_finish_injected_record_type (tree);
> +
>  /* in vtable-class-hierarchy.c */
>  extern void vtv_compute_class_hierarchy_transitive_closure (void);
>  extern void vtv_generate_init_routine           (void);
> diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
> index 44aefd8..9bdfd4f 100644
> --- a/gcc/cp/decl.c
> +++ b/gcc/cp/decl.c
> @@ -4564,7 +4564,7 @@ static tree
>  push_cp_library_fn (enum tree_code operator_code, tree type,
>                     int ecf_flags)
>  {
> -  tree fn = build_cp_library_fn (ansi_opname (operator_code),
> +  tree fn = build_cp_library_fn (cp_operator_id (operator_code),
>                                  operator_code,
>                                  type, ecf_flags);
>    pushdecl (fn);
> @@ -12937,12 +12937,12 @@ grok_op_properties (tree decl, bool complain)
>      do
>        {
>  #define DEF_OPERATOR(NAME, CODE, MANGLING, ARITY, ASSN_P)      \
> -       if (ansi_opname (CODE) == name)                         \
> +       if (cp_operator_id (CODE) == name)                      \
>           {                                                     \
>             operator_code = (CODE);                             \
>             break;                                              \
>           }                                                     \
> -       else if (ansi_assopname (CODE) == name)                 \
> +       else if (cp_assignment_operator_id (CODE) == name)      \
>           {                                                     \
>             operator_code = (CODE);                             \
>             DECL_ASSIGNMENT_OPERATOR_P (decl) = 1;              \
> diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
> index a9a1d22..86d9820 100644
> --- a/gcc/cp/decl2.c
> +++ b/gcc/cp/decl2.c
> @@ -4386,7 +4386,7 @@ maybe_warn_sized_delete (enum tree_code code)
>    tree sized = NULL_TREE;
>    tree unsized = NULL_TREE;
>
> -  for (tree ovl = IDENTIFIER_GLOBAL_VALUE (ansi_opname (code));
> +  for (tree ovl = IDENTIFIER_GLOBAL_VALUE (cp_operator_id (code));
>         ovl; ovl = OVL_NEXT (ovl))
>      {
>        tree fn = OVL_CURRENT (ovl);
> diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c
> index 9eec9e4..3815dae 100644
> --- a/gcc/cp/friend.c
> +++ b/gcc/cp/friend.c
> @@ -24,6 +24,46 @@ along with GCC; see the file COPYING3.  If not see
>
>  /* Friend data structures are described in cp-tree.h.  */
>
> +
> +/* The GLOBAL_FRIEND scope (functions, classes, or templates) is
> +   regarded as a friend of every class.  This is only used by libcc1,
> +   to enable GDB's code snippets to access private members without
> +   disabling access control in general, which could cause different
> +   template overload resolution results when accessibility matters
> +   (e.g. tests for an accessible member).  */
> +
> +static tree global_friend;
> +
> +/* Set the GLOBAL_FRIEND for this compilation session.  It might be
> +   set multiple times, but always to the same scope.  */
> +
> +void
> +set_global_friend (tree scope)
> +{
> +  gcc_checking_assert (scope != NULL_TREE);
> +  gcc_assert (!global_friend || global_friend == scope);
> +  global_friend = scope;
> +}
> +
> +/* Return TRUE if SCOPE is the global friend.  */
> +
> +bool
> +is_global_friend (tree scope)
> +{
> +  gcc_checking_assert (scope != NULL_TREE);
> +
> +  if (global_friend == scope)
> +    return true;
> +
> +  if (!global_friend)
> +    return false;
> +
> +  if (is_specialization_of_friend (global_friend, scope))
> +    return true;
> +
> +  return false;
> +}
> +
>  /* Returns nonzero if SUPPLICANT is a friend of TYPE.  */
>
>  int
> @@ -36,6 +76,9 @@ is_friend (tree type, tree supplicant)
>    if (supplicant == NULL_TREE || type == NULL_TREE)
>      return 0;
>
> +  if (is_global_friend (supplicant))
> +    return 1;
> +
>    declp = DECL_P (supplicant);
>
>    if (declp)
> diff --git a/gcc/cp/init.c b/gcc/cp/init.c
> index de43d81..42f1c61 100644
> --- a/gcc/cp/init.c
> +++ b/gcc/cp/init.c
> @@ -2924,7 +2924,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
>    tree fnname;
>    tree fns;
>
> -  fnname = ansi_opname (array_p ? VEC_NEW_EXPR : NEW_EXPR);
> +  fnname = cp_operator_id (array_p ? VEC_NEW_EXPR : NEW_EXPR);
>
>    member_new_p = !globally_qualified_p
>                  && CLASS_TYPE_P (elt_type)
> diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
> index 4d22c3d..538c806 100644
> --- a/gcc/cp/lambda.c
> +++ b/gcc/cp/lambda.c
> @@ -202,7 +202,7 @@ lambda_function (tree lambda)
>    if (CLASSTYPE_TEMPLATE_INSTANTIATION (type)
>        && !COMPLETE_OR_OPEN_TYPE_P (type))
>      return NULL_TREE;
> -  lambda = lookup_member (type, ansi_opname (CALL_EXPR),
> +  lambda = lookup_member (type, cp_operator_id (CALL_EXPR),
>                           /*protect=*/0, /*want_type=*/false,
>                           tf_warning_or_error);
>    if (lambda)
> diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c
> index 60a70e9b..ad63186 100644
> --- a/gcc/cp/lex.c
> +++ b/gcc/cp/lex.c
> @@ -433,7 +433,7 @@ unqualified_name_lookup_error (tree name, location_t loc)
>
>    if (IDENTIFIER_OPNAME_P (name))
>      {
> -      if (name != ansi_opname (ERROR_MARK))
> +      if (name != cp_operator_id (ERROR_MARK))
>         error_at (loc, "%qD not defined", name);
>      }
>    else
> diff --git a/gcc/cp/method.c b/gcc/cp/method.c
> index 5b366f0..0a816e0 100644
> --- a/gcc/cp/method.c
> +++ b/gcc/cp/method.c
> @@ -812,7 +812,7 @@ do_build_copy_assign (tree fndecl)
>           parmvec = make_tree_vector_single (converted_parm);
>           finish_expr_stmt
>             (build_special_member_call (current_class_ref,
> -                                       ansi_assopname (NOP_EXPR),
> +                                       cp_assignment_operator_id (NOP_EXPR),
>                                         &parmvec,
>                                         base_binfo,
>                                         flags,
> @@ -1105,7 +1105,7 @@ get_copy_assign (tree type)
>    int quals = (TYPE_HAS_CONST_COPY_ASSIGN (type)
>                ? TYPE_QUAL_CONST : TYPE_UNQUALIFIED);
>    tree argtype = build_stub_type (type, quals, false);
> -  tree fn = locate_fn_flags (type, ansi_assopname (NOP_EXPR), argtype,
> +  tree fn = locate_fn_flags (type, cp_assignment_operator_id (NOP_EXPR), argtype,
>                              LOOKUP_NORMAL, tf_warning_or_error);
>    if (fn == error_mark_node)
>      return NULL_TREE;
> @@ -1463,7 +1463,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
>      case sfk_move_assignment:
>      case sfk_copy_assignment:
>        assign_p = true;
> -      fnname = ansi_assopname (NOP_EXPR);
> +      fnname = cp_assignment_operator_id (NOP_EXPR);
>        break;
>
>      case sfk_destructor:
> @@ -1622,7 +1622,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
>
>        if (check_vdtor && type_has_virtual_destructor (basetype))
>         {
> -         rval = locate_fn_flags (ctype, ansi_opname (DELETE_EXPR),
> +         rval = locate_fn_flags (ctype, cp_operator_id (DELETE_EXPR),
>                                   ptr_type_node, flags, complain);
>           /* Unlike for base ctor/op=/dtor, for operator delete it's fine
>              to have a null rval (no class-specific op delete).  */
> @@ -1941,7 +1941,7 @@ implicitly_declare_fn (special_function_kind kind, tree type,
>           || kind == sfk_move_assignment)
>         {
>           return_type = build_reference_type (type);
> -         name = ansi_assopname (NOP_EXPR);
> +         name = cp_assignment_operator_id (NOP_EXPR);
>         }
>        else
>         name = constructor_name (type);
> diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
> index 10fb540..a3cb7ee 100644
> --- a/gcc/cp/name-lookup.c
> +++ b/gcc/cp/name-lookup.c
> @@ -92,6 +92,28 @@ get_anonymous_namespace_name (void)
>
>  static GTY((deletable)) binding_entry free_binding_entry = NULL;
>
> +/* The binding oracle; see cp-tree.h.  */
> +
> +cp_binding_oracle_function *cp_binding_oracle;
> +
> +/* If we have a binding oracle, ask it for all namespace-scoped
> +   definitions of NAME.  */
> +
> +static inline void
> +query_oracle (tree name)
> +{
> +  if (!cp_binding_oracle)
> +    return;
> +
> +  /* LOOKED_UP holds the set of identifiers that we have already
> +     looked up with the oracle.  */
> +  static hash_set<tree> looked_up;
> +  if (looked_up.add (name))
> +    return;
> +
> +  cp_binding_oracle (CP_ORACLE_IDENTIFIER, name);
> +}
> +
>  /* Create a binding_entry object for (NAME, TYPE).  */
>
>  static inline binding_entry
> @@ -4706,6 +4728,8 @@ qualified_lookup_using_namespace (tree name, tree scope,
>    /* Look through namespace aliases.  */
>    scope = ORIGINAL_NAMESPACE (scope);
>
> +  query_oracle (name);
> +
>    /* Algorithm: Starting with SCOPE, walk through the set of used
>       namespaces.  For each used namespace, look through its inline
>       namespace set for any bindings and usings.  If no bindings are
> @@ -5030,6 +5054,8 @@ lookup_name_real_1 (tree name, int prefer_type, int nonclass, bool block_p,
>    cxx_binding *iter;
>    tree val = NULL_TREE;
>
> +  query_oracle (name);
> +
>    /* Conversion operators are handled specially because ordinary
>       unqualified name lookup will not find template conversion
>       operators.  */
> @@ -6238,6 +6264,7 @@ pushtag (tree name, tree type, tag_scope scope)
>    timevar_cond_stop (TV_NAME_LOOKUP, subtime);
>    return ret;
>  }
> +
>
>  /* Subroutines for reverting temporarily to top-level for instantiation
>     of templates and such.  We actually need to clear out the class- and
> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
> index 9a61eb1..2cbbb10 100644
> --- a/gcc/cp/parser.c
> +++ b/gcc/cp/parser.c
> @@ -249,9 +249,6 @@ static cp_token_cache *cp_token_cache_new
>  static void cp_parser_initial_pragma
>    (cp_token *);
>
> -static tree cp_literal_operator_id
> -  (const char *);
> -
>  static void cp_parser_cilk_simd
>    (cp_parser *, cp_token *, bool *);
>  static tree cp_parser_cilk_for
> @@ -10279,7 +10276,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
>
>      p = obstack_alloc (&declarator_obstack, 0);
>
> -    declarator = make_id_declarator (NULL_TREE, ansi_opname (CALL_EXPR),
> +    declarator = make_id_declarator (NULL_TREE, cp_operator_id (CALL_EXPR),
>                                      sfk_none);
>
>      quals = (LAMBDA_EXPR_MUTABLE_P (lambda_expr)
> @@ -14297,7 +14294,7 @@ cp_parser_operator_function_id (cp_parser* parser)
>  /* Return an identifier node for a user-defined literal operator.
>     The suffix identifier is chained to the operator name identifier.  */
>
> -static tree
> +tree
>  cp_literal_operator_id (const char* name)
>  {
>    tree identifier;
> @@ -14366,12 +14363,12 @@ cp_parser_operator (cp_parser* parser)
>             if (cp_token *close_token
>                 = cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE))
>               end_loc = close_token->location;
> -           id = ansi_opname (op == NEW_EXPR
> +           id = cp_operator_id (op == NEW_EXPR
>                               ? VEC_NEW_EXPR : VEC_DELETE_EXPR);
>           }
>         /* Otherwise, we have the non-array variant.  */
>         else
> -         id = ansi_opname (op);
> +         id = cp_operator_id (op);
>
>         location_t loc = make_location (start_loc, start_loc, end_loc);
>
> @@ -14379,147 +14376,147 @@ cp_parser_operator (cp_parser* parser)
>        }
>
>      case CPP_PLUS:
> -      id = ansi_opname (PLUS_EXPR);
> +      id = cp_operator_id (PLUS_EXPR);
>        break;
>
>      case CPP_MINUS:
> -      id = ansi_opname (MINUS_EXPR);
> +      id = cp_operator_id (MINUS_EXPR);
>        break;
>
>      case CPP_MULT:
> -      id = ansi_opname (MULT_EXPR);
> +      id = cp_operator_id (MULT_EXPR);
>        break;
>
>      case CPP_DIV:
> -      id = ansi_opname (TRUNC_DIV_EXPR);
> +      id = cp_operator_id (TRUNC_DIV_EXPR);
>        break;
>
>      case CPP_MOD:
> -      id = ansi_opname (TRUNC_MOD_EXPR);
> +      id = cp_operator_id (TRUNC_MOD_EXPR);
>        break;
>
>      case CPP_XOR:
> -      id = ansi_opname (BIT_XOR_EXPR);
> +      id = cp_operator_id (BIT_XOR_EXPR);
>        break;
>
>      case CPP_AND:
> -      id = ansi_opname (BIT_AND_EXPR);
> +      id = cp_operator_id (BIT_AND_EXPR);
>        break;
>
>      case CPP_OR:
> -      id = ansi_opname (BIT_IOR_EXPR);
> +      id = cp_operator_id (BIT_IOR_EXPR);
>        break;
>
>      case CPP_COMPL:
> -      id = ansi_opname (BIT_NOT_EXPR);
> +      id = cp_operator_id (BIT_NOT_EXPR);
>        break;
>
>      case CPP_NOT:
> -      id = ansi_opname (TRUTH_NOT_EXPR);
> +      id = cp_operator_id (TRUTH_NOT_EXPR);
>        break;
>
>      case CPP_EQ:
> -      id = ansi_assopname (NOP_EXPR);
> +      id = cp_assignment_operator_id (NOP_EXPR);
>        break;
>
>      case CPP_LESS:
> -      id = ansi_opname (LT_EXPR);
> +      id = cp_operator_id (LT_EXPR);
>        break;
>
>      case CPP_GREATER:
> -      id = ansi_opname (GT_EXPR);
> +      id = cp_operator_id (GT_EXPR);
>        break;
>
>      case CPP_PLUS_EQ:
> -      id = ansi_assopname (PLUS_EXPR);
> +      id = cp_assignment_operator_id (PLUS_EXPR);
>        break;
>
>      case CPP_MINUS_EQ:
> -      id = ansi_assopname (MINUS_EXPR);
> +      id = cp_assignment_operator_id (MINUS_EXPR);
>        break;
>
>      case CPP_MULT_EQ:
> -      id = ansi_assopname (MULT_EXPR);
> +      id = cp_assignment_operator_id (MULT_EXPR);
>        break;
>
>      case CPP_DIV_EQ:
> -      id = ansi_assopname (TRUNC_DIV_EXPR);
> +      id = cp_assignment_operator_id (TRUNC_DIV_EXPR);
>        break;
>
>      case CPP_MOD_EQ:
> -      id = ansi_assopname (TRUNC_MOD_EXPR);
> +      id = cp_assignment_operator_id (TRUNC_MOD_EXPR);
>        break;
>
>      case CPP_XOR_EQ:
> -      id = ansi_assopname (BIT_XOR_EXPR);
> +      id = cp_assignment_operator_id (BIT_XOR_EXPR);
>        break;
>
>      case CPP_AND_EQ:
> -      id = ansi_assopname (BIT_AND_EXPR);
> +      id = cp_assignment_operator_id (BIT_AND_EXPR);
>        break;
>
>      case CPP_OR_EQ:
> -      id = ansi_assopname (BIT_IOR_EXPR);
> +      id = cp_assignment_operator_id (BIT_IOR_EXPR);
>        break;
>
>      case CPP_LSHIFT:
> -      id = ansi_opname (LSHIFT_EXPR);
> +      id = cp_operator_id (LSHIFT_EXPR);
>        break;
>
>      case CPP_RSHIFT:
> -      id = ansi_opname (RSHIFT_EXPR);
> +      id = cp_operator_id (RSHIFT_EXPR);
>        break;
>
>      case CPP_LSHIFT_EQ:
> -      id = ansi_assopname (LSHIFT_EXPR);
> +      id = cp_assignment_operator_id (LSHIFT_EXPR);
>        break;
>
>      case CPP_RSHIFT_EQ:
> -      id = ansi_assopname (RSHIFT_EXPR);
> +      id = cp_assignment_operator_id (RSHIFT_EXPR);
>        break;
>
>      case CPP_EQ_EQ:
> -      id = ansi_opname (EQ_EXPR);
> +      id = cp_operator_id (EQ_EXPR);
>        break;
>
>      case CPP_NOT_EQ:
> -      id = ansi_opname (NE_EXPR);
> +      id = cp_operator_id (NE_EXPR);
>        break;
>
>      case CPP_LESS_EQ:
> -      id = ansi_opname (LE_EXPR);
> +      id = cp_operator_id (LE_EXPR);
>        break;
>
>      case CPP_GREATER_EQ:
> -      id = ansi_opname (GE_EXPR);
> +      id = cp_operator_id (GE_EXPR);
>        break;
>
>      case CPP_AND_AND:
> -      id = ansi_opname (TRUTH_ANDIF_EXPR);
> +      id = cp_operator_id (TRUTH_ANDIF_EXPR);
>        break;
>
>      case CPP_OR_OR:
> -      id = ansi_opname (TRUTH_ORIF_EXPR);
> +      id = cp_operator_id (TRUTH_ORIF_EXPR);
>        break;
>
>      case CPP_PLUS_PLUS:
> -      id = ansi_opname (POSTINCREMENT_EXPR);
> +      id = cp_operator_id (POSTINCREMENT_EXPR);
>        break;
>
>      case CPP_MINUS_MINUS:
> -      id = ansi_opname (PREDECREMENT_EXPR);
> +      id = cp_operator_id (PREDECREMENT_EXPR);
>        break;
>
>      case CPP_COMMA:
> -      id = ansi_opname (COMPOUND_EXPR);
> +      id = cp_operator_id (COMPOUND_EXPR);
>        break;
>
>      case CPP_DEREF_STAR:
> -      id = ansi_opname (MEMBER_REF);
> +      id = cp_operator_id (MEMBER_REF);
>        break;
>
>      case CPP_DEREF:
> -      id = ansi_opname (COMPONENT_REF);
> +      id = cp_operator_id (COMPONENT_REF);
>        break;
>
>      case CPP_OPEN_PAREN:
> @@ -14527,14 +14524,14 @@ cp_parser_operator (cp_parser* parser)
>        cp_lexer_consume_token (parser->lexer);
>        /* Look for the matching `)'.  */
>        cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
> -      return ansi_opname (CALL_EXPR);
> +      return cp_operator_id (CALL_EXPR);
>
>      case CPP_OPEN_SQUARE:
>        /* Consume the `['.  */
>        cp_lexer_consume_token (parser->lexer);
>        /* Look for the matching `]'.  */
>        cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
> -      return ansi_opname (ARRAY_REF);
> +      return cp_operator_id (ARRAY_REF);
>
>      case CPP_UTF8STRING:
>      case CPP_UTF8STRING_USERDEF:
> @@ -31964,21 +31961,21 @@ cp_parser_omp_clause_reduction (cp_parser *parser, tree list)
>             code = MIN_EXPR;
>           else if (strcmp (p, "max") == 0)
>             code = MAX_EXPR;
> -         else if (id == ansi_opname (PLUS_EXPR))
> +         else if (id == cp_operator_id (PLUS_EXPR))
>             code = PLUS_EXPR;
> -         else if (id == ansi_opname (MULT_EXPR))
> +         else if (id == cp_operator_id (MULT_EXPR))
>             code = MULT_EXPR;
> -         else if (id == ansi_opname (MINUS_EXPR))
> +         else if (id == cp_operator_id (MINUS_EXPR))
>             code = MINUS_EXPR;
> -         else if (id == ansi_opname (BIT_AND_EXPR))
> +         else if (id == cp_operator_id (BIT_AND_EXPR))
>             code = BIT_AND_EXPR;
> -         else if (id == ansi_opname (BIT_IOR_EXPR))
> +         else if (id == cp_operator_id (BIT_IOR_EXPR))
>             code = BIT_IOR_EXPR;
> -         else if (id == ansi_opname (BIT_XOR_EXPR))
> +         else if (id == cp_operator_id (BIT_XOR_EXPR))
>             code = BIT_XOR_EXPR;
> -         else if (id == ansi_opname (TRUTH_ANDIF_EXPR))
> +         else if (id == cp_operator_id (TRUTH_ANDIF_EXPR))
>             code = TRUTH_ANDIF_EXPR;
> -         else if (id == ansi_opname (TRUTH_ORIF_EXPR))
> +         else if (id == cp_operator_id (TRUTH_ORIF_EXPR))
>             code = TRUTH_ORIF_EXPR;
>           id = omp_reduction_id (code, id, NULL_TREE);
>           tree scope = parser->scope;
> diff --git a/gcc/cp/search.c b/gcc/cp/search.c
> index ec8f4ab..09c1b4e 100644
> --- a/gcc/cp/search.c
> +++ b/gcc/cp/search.c
> @@ -782,6 +782,9 @@ friend_accessible_p (tree scope, tree decl, tree type, tree otype)
>    if (!scope)
>      return 0;
>
> +  if (is_global_friend (scope))
> +    return 1;
> +
>    /* Is SCOPE itself a suitable P?  */
>    if (TYPE_P (scope) && protected_accessible_p (decl, scope, type, otype))
>      return 1;
> @@ -1664,7 +1667,7 @@ lookup_fnfields_1 (tree type, tree name)
>           if (CLASSTYPE_LAZY_MOVE_CTOR (type))
>             lazily_declare_fn (sfk_move_constructor, type);
>         }
> -      else if (name == ansi_assopname (NOP_EXPR))
> +      else if (name == cp_assignment_operator_id (NOP_EXPR))
>         {
>           if (CLASSTYPE_LAZY_COPY_ASSIGN (type))
>             lazily_declare_fn (sfk_copy_assignment, type);
> diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
> index 6d5ea95..e60e067 100644
> --- a/gcc/cp/semantics.c
> +++ b/gcc/cp/semantics.c
> @@ -5103,7 +5103,7 @@ omp_reduction_id (enum tree_code reduction_code, tree reduction_id, tree type)
>      case BIT_IOR_EXPR:
>      case TRUTH_ANDIF_EXPR:
>      case TRUTH_ORIF_EXPR:
> -      reduction_id = ansi_opname (reduction_code);
> +      reduction_id = cp_operator_id (reduction_code);
>        break;
>      case MIN_EXPR:
>        p = "min";
> @@ -9008,7 +9008,7 @@ classtype_has_nothrow_assign_or_copy_p (tree type, bool assign_p)
>    if (assign_p)
>      {
>        int ix;
> -      ix = lookup_fnfields_1 (type, ansi_assopname (NOP_EXPR));
> +      ix = lookup_fnfields_1 (type, cp_assignment_operator_id (NOP_EXPR));
>        if (ix < 0)
>         return false;
>        fns = (*CLASSTYPE_METHOD_VEC (type))[ix];
> @@ -9291,7 +9291,8 @@ is_this_parameter (tree t)
>  {
>    if (!DECL_P (t) || DECL_NAME (t) != this_identifier)
>      return false;
> -  gcc_assert (TREE_CODE (t) == PARM_DECL || is_capture_proxy (t));
> +  gcc_assert (TREE_CODE (t) == PARM_DECL || is_capture_proxy (t)
> +             || (cp_binding_oracle && TREE_CODE (t) == VAR_DECL));
>    return true;
>  }
>
> diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
> index f677b48..8f66d3c 100644
> --- a/gcc/cp/typeck.c
> +++ b/gcc/cp/typeck.c
> @@ -8881,7 +8881,7 @@ check_return_expr (tree retval, bool *no_warning)
>
>    /* Effective C++ rule 15.  See also start_function.  */
>    if (warn_ecpp
> -      && DECL_NAME (current_function_decl) == ansi_assopname(NOP_EXPR))
> +      && DECL_NAME (current_function_decl) == cp_assignment_operator_id (NOP_EXPR))
>      {
>        bool warn = true;
>
> diff --git a/include/gcc-c-fe.def b/include/gcc-c-fe.def
> index 09998ba..acf1940 100644
> --- a/include/gcc-c-fe.def
> +++ b/include/gcc-c-fe.def
> @@ -125,16 +125,18 @@ GCC_METHOD3 (gcc_type, build_function_type,
>              const struct gcc_type_array *, /* Argument ARGUMENT_TYPES.  */
>              int /* bool */)               /* Argument IS_VARARGS.  */
>
> -/* Return an integer type with the given properties.  */
> +/* Return an integer type with the given properties.
> +   Deprecated in v1, use int_type instead.  */
>
> -GCC_METHOD2 (gcc_type, int_type,
> +GCC_METHOD2 (gcc_type, int_type_v0,
>              int /* bool */,               /* Argument IS_UNSIGNED.  */
>              unsigned long)                /* Argument SIZE_IN_BYTES.  */
>
> -/* Return a floating point type with the given properties.  */
> +/* Return a floating point type with the given properties.
> +   Deprecated in v1, use float_type instead.  */
>
> -GCC_METHOD1 (gcc_type, float_type,
> -            unsigned long)                     /* Argument SIZE_IN_BYTES.  */
> +GCC_METHOD1 (gcc_type, float_type_v0,
> +            unsigned long)                /* Argument SIZE_IN_BYTES.  */
>
>  /* Return the 'void' type.  */
>
> @@ -195,3 +197,26 @@ GCC_METHOD5 (int /* bool */, build_constant,
>
>  GCC_METHOD1 (gcc_type, error,
>              const char *)               /* Argument MESSAGE.  */
> +
> +/* Return an integer type with the given properties.  If BUILTIN_NAME
> +   is non-NULL, it must name a builtin integral type with the given
> +   signedness and size, and that is the type that will be returned.  */
> +
> +GCC_METHOD3 (gcc_type, int_type,
> +            int /* bool */,               /* Argument IS_UNSIGNED.  */
> +            unsigned long,                /* Argument SIZE_IN_BYTES.  */
> +            const char *)                 /* Argument BUILTIN_NAME.  */
> +
> +/* Return the 'char' type, a distinct type from both 'signed char' and
> +   'unsigned char' returned by int_type.  */
> +
> +GCC_METHOD0 (gcc_type, char_type)
> +
> +/* Return a floating point type with the given properties.  If BUILTIN_NAME
> +   is non-NULL, it must name a builtin integral type with the given
> +   signedness and size, and that is the type that will be returned.  */
> +
> +GCC_METHOD2 (gcc_type, float_type,
> +            unsigned long,                /* Argument SIZE_IN_BYTES.  */
> +            const char *)                 /* Argument BUILTIN_NAME.  */
> +
> diff --git a/include/gcc-c-interface.h b/include/gcc-c-interface.h
> index 00ccbfb..e048c86 100644
> --- a/include/gcc-c-interface.h
> +++ b/include/gcc-c-interface.h
> @@ -41,7 +41,11 @@ struct gcc_c_context;
>
>  enum gcc_c_api_version
>  {
> -  GCC_C_FE_VERSION_0 = 0
> +  GCC_C_FE_VERSION_0 = 0,
> +
> +  /* Added char_type.  Added new version of int_type and float_type,
> +     deprecated int_type_v0 and float_type_v0.  */
> +  GCC_C_FE_VERSION_1 = 1
>  };
>
>  /* Qualifiers.  */
> @@ -111,19 +115,6 @@ typedef gcc_address gcc_c_symbol_address_function (void *datum,
>                                                    struct gcc_c_context *ctxt,
>                                                    const char *identifier);
>
> -/* An array of types used for creating a function type.  */
> -
> -struct gcc_type_array
> -{
> -  /* Number of elements.  */
> -
> -  int n_elements;
> -
> -  /* The elements.  */
> -
> -  gcc_type *elements;
> -};
> -
>  /* The vtable used by the C front end.  */
>
>  struct gcc_c_fe_vtable
> @@ -146,7 +137,7 @@ struct gcc_c_fe_vtable
>       provides the declaration.
>
>       DATUM is an arbitrary piece of data that is passed back verbatim
> -     to the callbakcs in requests.  */
> +     to the callbacks in requests.  */
>
>    void (*set_callbacks) (struct gcc_c_context *self,
>                          gcc_c_oracle_function *binding_oracle,
> diff --git a/include/gcc-cp-fe.def b/include/gcc-cp-fe.def
> new file mode 100644
> index 0000000..c367c1d
> --- /dev/null
> +++ b/include/gcc-cp-fe.def
> @@ -0,0 +1,1050 @@
> +/* Interface between GCC C++ FE and GDB  -*- c -*-
> +
> +   Copyright (C) 2014-2017 Free Software Foundation, Inc.
> +
> +   This file is part of GCC.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +
> +
> +/* Push namespace NAME as the current binding level, to which
> +   newly-introduced decls will be bound.  An empty string identifies
> +   the global namespace, whereas NULL identifies an anonymous
> +   namespace.  A namespace named NAME is created in the current scope,
> +   if needed.
> +
> +   If the newly-created namespace is to be an inline namespace, see
> +   make_namespace_inline.  */
> +
> +GCC_METHOD1 (int /* bool */, push_namespace,
> +            const char *)            /* Argument NAME.  */
> +
> +/* Push TYPE as the current binding level, making its members visible
> +   for name lookup.  The current scope before the call must be the
> +   scope in which the class was declared.  This should be used if the
> +   definition of a class is already finished, but one wishes to define
> +   a nested class, or to enter the scope of one of its member
> +   functions.  */
> +
> +GCC_METHOD1 (int /* bool */, push_class,
> +            gcc_type)          /* Argument TYPE.  */
> +
> +/* Push FUNCTION_DECL as the current (empty) binding level (see
> +   reactivate_decl).  The current enclosing scope before the call must
> +   be the scope in which the function was declared.  */
> +
> +GCC_METHOD1 (int /* bool */, push_function,
> +            gcc_decl)       /* Argument FUNCTION_DECL.  */
> +
> +/* Make DECL visible (again?) within SCOPE.  When SCOPE is NULL, it
> +   means the current scope; if it is not NULL, it must name a function
> +   that is currently active, even if not at the top of the binding
> +   chain.
> +
> +   This function can be used to make e.g. a global function or
> +   variable visible in a namespace or local scope (overriding another
> +   enclosing definition of the same name), but its most common
> +   expected use of this primitive, that gives it its name, is to make
> +   declarations visible again after reentering a function scope,
> +   because when a function is entered with push_function, that does
> +   NOT make any of the declarations nested in it visible for name
> +   lookup.
> +
> +   There is a reason/excuse for that: unlike namespaces and classes,
> +   G++ doesn't ever have to reenter function scopes, so its name
> +   resolution infrastructure is not prepared to do that.  But wait,
> +   there is also a good use for this apparent limitation: a function
> +   may contain multiple scopes (blocks), and the name may be bound to
> +   different symbols in each of these scopes.  With this interface, as
> +   we reenter a function scope, we may choose which symbols to make
> +   visible for the code snippet, or, if there could be template
> +   functions in local scopes, for unresolved names in nested template
> +   class default arguments, or in nested template function signatures.
> +
> +   As for making a local declaration visible for the code snippet,
> +   there are two possibilities: a) introduce it upfront, while
> +   entering the scope for the user expression (see the enter_scope
> +   callback, called by g++ when encountering the push_user_expression
> +   pragma), which might save some scope switching and reactivate_decl
> +   (though this can't be helped if some declarations have to be
> +   introduced and discarded, because of multiple definitions of the
> +   same name in different scopes within a function: they have to be
> +   defined in discriminator order); or b) introduce it when its name
> +   is looked up, entering the scope, introducing the declaration,
> +   leaving the scope, and then reactivating the declaration in its
> +   local scope.
> +
> +   Here's some more detail on how reactivate_decl works.  Say there's
> +   a function foo whose body looks like this:
> +
> +   {
> +     {
> +// point 1
> +       class c {} o __attribute__ ((__used__)); // c  , o
> +     }
> +     struct c {
> +       void f() {
> +// point 2
> +       }
> +     } o __attribute__ ((__used__));            // c_0, o_0
> +     {
> +       class c {} p __attribute__ ((__used__)); // c_1, p
> +// point 3
> +       o.f();
> +     }
> +   }
> +
> +   When we are about to define class c at point 1, we enter the
> +   function foo scope, and since no symbols are visible at point 1, we
> +   proceed to declare class c.  We may then define the class right
> +   away, or, if we leave the function scope, and we later wish to
> +   define it, or to define object o, we can reenter the scope and just
> +   use the previously-obtained gcc_decl to define the class, without
> +   having to reactivate the declaration.
> +
> +   Now, if we are to set up the binding context for point 2, we have
> +   to define c_0::f, and in order to do so, we have to declare and
> +   define c_0.  Before we can declare c_0, we MUST at least declare c.
> +
> +     As a general rule, before we can declare or define any local name
> +     with a discriminator, we have to at least declare any other
> +     occurrences of the same name in the same enclosing entity with
> +     lower or absent discriminator.
> +
> +   So, we declare c, then we leave the function scope and reenter it
> +   so as to declare c_0 (also with name "c", which is why we have to
> +   leave and reenter the function scope, otherwise we would get an
> +   error because of the duplicate definition; g++ will assign a
> +   discriminator because it still remembers there was an earlier
> +   declaration of c_0 within the function, it's just no longer in
> +   scope), then we can define c_0, including its member function f.
> +
> +   Likewise, if we wish to define o_0, we have to define o first.  If
> +   we wish to declare (and maybe then define) c_1, we have to at least
> +   declare (c and then) c_0 first.
> +
> +   Then, as we set up the binding context to compile a code snippet at
> +   point 3, we may choose to activate c_1, o_0 and p upfront,
> +   declaring and discarding c, c_0 and o, and then reentering the
> +   funciton scope to declare c_1, o_0 and p; or we can wait for oracle
> +   lookups of c, o or p.  If c is looked up, and the debugger resolves
> +   c in the scope to c_1, it is expected to enter the function scope
> +   from the top level, declare c, leave it, reenter it, declare c_0,
> +   leave it, reenter it, declare c_1, leave it, and then reactivate
> +   c_1 in the function scope.  If c_1 is needed as a complete type,
> +   the definition may be given right after the declaration, or the
> +   scope will have to be reentered in order to define the class.
> +
> +.  If the code snippet is at point 2, we don't need to (re)activate
> +   any declaration: nothing from any local scope is visible.  Just
> +   entering the scope of the class containing member function f
> +   reactivates the names of its members, including the class name
> +   itself.  */
> +
> +GCC_METHOD2 (int /* bool */, reactivate_decl,
> +            gcc_decl,          /* Argument DECL.  */
> +            gcc_decl)          /* Argument SCOPE.  */
> +
> +/* Pop the namespace last entered with push_namespace, or class last
> +   entered with push_class, or function last entered with
> +   push_function, restoring the binding level in effect before the
> +   matching push_* call.  */
> +
> +GCC_METHOD0 (int /* bool */, pop_binding_level)
> +
> +/* Return the NAMESPACE_DECL, TYPE_DECL or FUNCTION_DECL of the
> +   binding level that would be popped by pop_scope.  */
> +
> +GCC_METHOD0 (gcc_decl, get_current_binding_level_decl)
> +
> +/* Make the current binding level an inline namespace.  It must be a
> +   namespace to begin with.  It is safe to call this more than once
> +   for the same namespace, but after the first call, subsequent ones
> +   will not return a success status.  */
> +
> +GCC_METHOD0 (int /* bool */, make_namespace_inline)
> +
> +/* Add USED_NS to the namespaces used by the current binding level.
> +   Use get_current_binding_level_decl to obtain USED_NS's
> +   gcc_decl.  */
> +
> +GCC_METHOD1 (int /* bool */, add_using_namespace,
> +            gcc_decl)                  /* Argument USED_NS.  */
> +
> +/* Introduce a namespace alias declaration, as in:
> +
> +   namespace foo = [... ::] bar;
> +
> +   After this call, namespace TARGET will be visible as ALIAS within
> +   the current namespace.  Get the declaration for TARGET by calling
> +   get_current_binding_level_decl after pushing into it.  */
> +
> +GCC_METHOD2 (int /* bool */, add_namespace_alias,
> +            const char *,              /* Argument ALIAS.  */
> +            gcc_decl)                  /* Argument TARGET.  */
> +
> +/* Introduce a using declaration, as in:
> +
> +   using foo::bar;
> +
> +   The TARGET decl names the qualifying scope (foo:: above) and the
> +   identifier (bar), but that does not mean that only TARGET will be
> +   brought into the current scope: all bindings of TARGET's identifier
> +   in the qualifying scope will be brought in.
> +
> +   FLAGS should specify GCC_CP_SYMBOL_USING.  If the current scope is
> +   a class scope, visibility flags must be supplied.
> +
> +   Even when TARGET is template dependent, we don't need to specify
> +   whether or not it is a typename: the supplied declaration (that
> +   could be a template-dependent type converted to declaration by
> +   get_type_decl) indicates so.  */
> +
> +GCC_METHOD2 (int /* bool */, add_using_decl,
> +            enum gcc_cp_symbol_kind, /* Argument FLAGS.  */
> +            gcc_decl)                /* Argument TARGET.  */
> +
> +/* Create a new "decl" in GCC, and bind it in the current binding
> +   level.  A decl is a declaration, basically a kind of symbol.
> +
> +   NAME is the name of the new symbol.  SYM_KIND is the kind of
> +   symbol being requested.  SYM_TYPE is the new symbol's C++ type;
> +   except for labels, where this is not meaningful and should be
> +   zero.  If SUBSTITUTION_NAME is not NULL, then a reference to this
> +   decl in the source will later be substituted with a dereference
> +   of a variable of the given name.  Otherwise, for symbols having
> +   an address (e.g., functions), ADDRESS is the address.  FILENAME
> +   and LINE_NUMBER refer to the symbol's source location.  If this
> +   is not known, FILENAME can be NULL and LINE_NUMBER can be 0.
> +   This function returns the new decl.
> +
> +   Use this function to register typedefs, functions and variables to
> +   namespace and local binding levels, and typedefs, member functions
> +   (static or not), and static data members to class binding levels.
> +   Class members must have their access controls specified with
> +   GCC_CP_ACCESS_* flags in SYM_KIND.
> +
> +   Note that, since access controls are disabled, we have no means to
> +   express private, protected and public.
> +
> +   There are various flags that can be set in SYM_KIND to specify
> +   additional semantics.  Look for GCC_CP_FLAGs in the definition of
> +   enum gcc_cp_symbol_kind in gcc-cp-interface.h.
> +
> +   In order to define member functions, pass GCC_CP_SYMBOL_FUNCTION in
> +   SYM_KIND, and a function_type for static member functions or a
> +   method type for non-static member functions, including constructors
> +   and destructors.  Use build_function_type to create a function
> +   type; for a method type, start by creating a function type without
> +   any compiler-introduced artificial arguments (the implicit this
> +   pointer, and the __in_chrg added to constructors and destructors,
> +   and __vtt_parm added to the former), and then use build_method_type
> +   to create the method type out of the class type and the function
> +   type.
> +
> +   For operator functions, set GCC_CP_FLAG_SPECIAL_FUNCTION in
> +   SYM_KIND, in addition to any other applicable flags, and pass as
> +   NAME a string starting with the two-character mangling for operator
> +   name: "ps" for unary plus, "mL" for multiply and assign, *=; etc.
> +   Use "cv" for type converstion operators (the target type portion
> +   may be omitted, as it is taken from the return type in SYM_TYPE).
> +   For operator"", use "li" followed by the identifier (the mangled
> +   name mandates digits specifying the length of the identifier; if
> +   present, they determine the end of the identifier, otherwise, the
> +   identifier extents to the end of the string, so that "li3_Kme" and
> +   "li_Km" are equivalent).
> +
> +   Constructors and destructors need special care, because for each
> +   constructor and destructor there may be multiple clones defined
> +   internally by the compiler.  With build_decl, you can introduce the
> +   base declaration of a constructor or a destructor, setting
> +   GCC_CP_FLAG_SPECIAL_FUNCTION the flag and using names starting with
> +   capital "C" or "D", respectively, followed by a digit (see below),
> +   a blank, or NUL ('\0').  DO NOT supply an ADDRESS or a
> +   SUBSTITUTION_NAME to build_decl, it would be meaningless (and
> +   rejected) for the base declaration; use define_cdtor_clone to
> +   introduce the address of each clone.  For constructor templates,
> +   declare the template with build_decl, and then, for each
> +   specialization, introduce it with
> +   build_function_template_specialization, and then define the
> +   addresses of each of its clones with define_cdtor_clone.
> +
> +   NAMEs for GCC_CP_FLAG_SPECIAL_FUNCTION:
> +
> +     NAME    meaning
> +     C?      constructor base declaration (? may be 1, 2, 4, blank or NUL)
> +     D?      destructor base declaration (? may be 0, 1, 2, 4, blank or NUL)
> +     nw      operator new
> +     na      operator new[]
> +     dl      operator delete
> +     da      operator delete[]
> +     ps      operator + (unary)
> +     ng      operator - (unary)
> +     ad      operator & (unary)
> +     de      operator * (unary)
> +     co      operator ~
> +     pl      operator +
> +     mi      operator -
> +     ml      operator *
> +     dv      operator /
> +     rm      operator %
> +     an      operator &
> +     or      operator |
> +     eo      operator ^
> +     aS      operator =
> +     pL      operator +=
> +     mI      operator -=
> +     mL      operator *=
> +     dV      operator /=
> +     rM      operator %=
> +     aN      operator &=
> +     oR      operator |=
> +     eO      operator ^=
> +     ls      operator <<
> +     rs      operator >>
> +     lS      operator <<=
> +     rS      operator >>=
> +     eq      operator ==
> +     ne      operator !=
> +     lt      operator <
> +     gt      operator >
> +     le      operator <=
> +     ge      operator >=
> +     nt      operator !
> +     aa      operator &&
> +     oo      operator ||
> +     pp      operator ++
> +     mm      operator --
> +     cm      operator ,
> +     pm      operator ->*
> +     pt      operator ->
> +     cl      operator ()
> +     ix      operator []
> +     qu      operator ?
> +     cv      operator <T> (conversion operator)
> +     li<id>  operator "" <id>
> +
> +   FIXME: How about attributes?  */
> +
> +GCC_METHOD7 (gcc_decl, build_decl,
> +            const char *,            /* Argument NAME.  */
> +            enum gcc_cp_symbol_kind, /* Argument SYM_KIND.  */
> +            gcc_type,                /* Argument SYM_TYPE.  */
> +            const char *,            /* Argument SUBSTITUTION_NAME.  */
> +            gcc_address,             /* Argument ADDRESS.  */
> +            const char *,            /* Argument FILENAME.  */
> +            unsigned int)            /* Argument LINE_NUMBER.  */
> +
> +/* Supply the ADDRESS of one of the multiple clones of constructor or
> +   destructor CDTOR.  The clone is specified by NAME, using the
> +   following name mangling conventions:
> +
> +     C1      in-charge constructor
> +     C2      not-in-charge constructor
> +     C4      unified constructor
> +     D0      deleting destructor
> +     D1      in-charge destructor
> +     D2      not-in-charge destructor
> +     D4      unified destructor
> +
> +   The following information is not necessary to use the API.
> +
> +   C1 initializes an instance of the class (rather than of derived
> +   classes), including virtual base classes, whereas C2 initializes a
> +   sub-object (of the given class type) of an instance of some derived
> +   class (or a full object that doesn't have any virtual base
> +   classes).
> +
> +   D0 and D1 destruct an instance of the class, including virtual base
> +   classes, but only the former calls operator delete to release the
> +   object's storage at the end; D2 destructs a sub-object (of the
> +   given class type) of an instance of a derived class (or a full
> +   object that doesn't have any virtual base classes).
> +
> +   The [CD]4 manglings (and symbol definitions) are non-standard, but
> +   GCC uses them in some cases: rather than assuming they are
> +   in-charge or not-in-charge, they test the implicit argument that
> +   the others ignore to tell how to behave.  These are used instead of
> +   cloning when we just can't use aliases.  */
> +
> +GCC_METHOD3 (gcc_decl, define_cdtor_clone,
> +            const char *,            /* Argument NAME.  */
> +            gcc_decl,                /* Argument CDTOR.  */
> +            gcc_address)             /* Argument ADDRESS.  */
> +
> +/* Return the type associated with the given declaration.  This is
> +   most useful to obtain the type associated with a forward-declared
> +   class, because it is the gcc_type, rather than the gcc_decl, that
> +   has to be used to build other types, but build_decl returns a
> +   gcc_decl rather than a gcc_type.  This call can in theory be used
> +   to obtain the type from any other declaration; it is supposed to
> +   return the same type that was supplied when the declaration was
> +   created.  */
> +
> +GCC_METHOD1 (gcc_type, get_decl_type,
> +            gcc_decl)            /* Argument DECL.  */
> +
> +/* Return the declaration for a type.  */
> +
> +GCC_METHOD1 (gcc_decl, get_type_decl,
> +            gcc_type)            /* Argument TYPE.  */
> +
> +/* Declare DECL as a friend of the current class scope, if TYPE is
> +   NULL, or of TYPE itself otherwise.  DECL may be a function or a
> +   class, be they template generics, template specializations or not
> +   templates.  TYPE must be a class type (not a template generic).
> +
> +   The add_friend call cannot introduce a declaration; even if the
> +   friend is first declared as a friend in the source code, the
> +   declaration belongs in the enclosing namespace, so it must be
> +   introduced in that namespace, and the resulting declaration can
> +   then be made a friend.
> +
> +   DECL cannot, however, be a member of a template class generic,
> +   because we have no means to introduce their declarations.  This
> +   interface has no notion of definitions for template generics.  As a
> +   consequence, users of this interface must introduce each friend
> +   template member specialization separately, i.e., instead of:
> +
> +     template <typename T> friend struct X<T>::M;
> +
> +   they must be declared as if they were:
> +
> +     friend struct X<onetype>::M;
> +     friend struct X<anothertype>::M;
> +     ... for each specialization of X.
> +
> +
> +   Specializations of a template can have each others' members as
> +   friends:
> +
> +     template <typename T> class foo {
> +       int f();
> +       template <typename U> friend int foo<U>::f();
> +     };
> +
> +   It wouldn't always be possible to define all specializations of a
> +   template class before introducing the friend declarations in their
> +   expanded, per-specialization form.
> +
> +   In order to simplify such friend declarations, and to enable
> +   incremental friend declarations as template specializations are
> +   introduced, add_friend can be called after the befriending class is
> +   fully defined, passing it a non-NULL TYPE argument naming the
> +   befriending class type.  */
> +
> +GCC_METHOD2 (int /* bool */, add_friend,
> +            gcc_decl,                /* Argument DECL.  */
> +            gcc_type)                /* Argument TYPE.  */
> +
> +/* Return the type of a pointer to a given base type.  */
> +
> +GCC_METHOD1 (gcc_type, build_pointer_type,
> +            gcc_type)                  /* Argument BASE_TYPE.  */
> +
> +/* Return the type of a reference to a given base type.  */
> +
> +GCC_METHOD2 (gcc_type, build_reference_type,
> +            gcc_type,                  /* Argument BASE_TYPE.  */
> +            enum gcc_cp_ref_qualifiers)   /* Argument RQUALS.  */
> +
> +/* Create a new pointer-to-member type.  MEMBER_TYPE is the data
> +   member type, while CLASS_TYPE is the class type containing the data
> +   member.  For pointers to member functions, MEMBER_TYPE must be a
> +   method type, and CLASS_TYPE must be specified even though it might
> +   be possible to extract it from the method type.  */
> +
> +GCC_METHOD2 (gcc_type, build_pointer_to_member_type,
> +            gcc_type,                     /* Argument CLASS_TYPE.  */
> +            gcc_type)                     /* Argument MEMBER_TYPE.  */
> +
> +/* Start a template parameter list scope and enters it, so that
> +   subsequent build_type_template_parameter and
> +   build_value_template_parameter calls create template parameters in
> +   the list.  The list is closed by a build_decl call with
> +   GCC_CP_SYMBOL_FUNCTION or GCC_CP_SYMBOL_CLASS, that, when the scope
> +   is a template parameter list, declares a template function or a
> +   template class with the then-closed parameter list.  The scope in
> +   which the new declaration is to be introduced by build_decl must be
> +   entered before calling start_template_decl, and build_decl returns
> +   to that scope, from the template parameter list scope, before
> +   introducing the declaration.  */
> +
> +GCC_METHOD0 (int /* bool */, start_template_decl)
> +
> +/* Build a typename template-parameter (e.g., the T in template
> +   <typename T = X>).  Either PACK_P should be nonzero, to indicate an
> +   argument pack (the last argument in a variadic template argument
> +   list, as in template <typename... T>), or DEFAULT_TYPE may be
> +   non-NULL to set the default type argument (e.g. X) for the template
> +   parameter.  FILENAME and LINE_NUMBER may specify the source
> +   location in which the template parameter was declared.  */
> +
> +GCC_METHOD5 (gcc_type, build_type_template_parameter,
> +            const char *,                            /* Argument ID.  */
> +            int /* bool */,                      /* Argument PACK_P.  */
> +            gcc_type,                      /* Argument DEFAULT_TYPE.  */
> +            const char *,                      /* Argument FILENAME.  */
> +            unsigned int)                   /* Argument LINE_NUMBER.  */
> +
> +/* Build a template template-parameter (e.g., the T in template
> +   <template <[...]> class T = X>).  DEFAULT_TEMPL may be non-NULL to
> +   set the default type-template argument (e.g. X) for the template
> +   template parameter.  FILENAME and LINE_NUMBER may specify the
> +   source location in which the template parameter was declared.  */
> +
> +GCC_METHOD5 (gcc_utempl, build_template_template_parameter,
> +            const char *,                            /* Argument ID.  */
> +            int /* bool */,                      /* Argument PACK_P.  */
> +            gcc_utempl,                   /* Argument DEFAULT_TEMPL.  */
> +            const char *,                      /* Argument FILENAME.  */
> +            unsigned int)                   /* Argument LINE_NUMBER.  */
> +
> +/* Build a value template-parameter (e.g., the V in template <typename
> +   T, T V> or in template <int V = X>).  DEFAULT_VALUE may be non-NULL
> +   to set the default value argument for the template parameter (e.g.,
> +   X).  FILENAME and LINE_NUMBER may specify the source location in
> +   which the template parameter was declared.  */
> +
> +GCC_METHOD5 (gcc_decl, build_value_template_parameter,
> +            gcc_type,                              /* Argument TYPE.  */
> +            const char *,                            /* Argument ID.  */
> +            gcc_expr,                     /* Argument DEFAULT_VALUE.  */
> +            const char *,                      /* Argument FILENAME.  */
> +            unsigned int)                   /* Argument LINE_NUMBER.  */
> +
> +/* Build a template-dependent typename (e.g., typename T::bar or
> +   typename T::template bart<X>).  ENCLOSING_TYPE should be the
> +   template-dependent nested name specifier (e.g., T), ID should be
> +   the name of the member of the ENCLOSING_TYPE (e.g., bar or bart),
> +   and TARGS should be non-NULL and specify the template arguments
> +   (e.g. <X>) iff ID is to name a class template.
> +
> +   In this and other calls, a template-dependent nested name specifier
> +   may be a template class parameter (build_type_template_parameter),
> +   a specialization (returned by build_dependent_type_template_id) of
> +   a template template parameter (returned by
> +   build_template_template_parameter) or a member type thereof
> +   (returned by build_dependent_typename itself).  */
> +
> +GCC_METHOD3 (gcc_type, build_dependent_typename,
> +            gcc_type,                    /* Argument ENCLOSING_TYPE.  */
> +            const char *,                            /* Argument ID.  */
> +            const struct gcc_cp_template_args *)  /* Argument TARGS.  */
> +
> +/* Build a template-dependent class template (e.g., T::template bart).
> +   ENCLOSING_TYPE should be the template-dependent nested name
> +   specifier (e.g., T), ID should be the name of the class template
> +   member of the ENCLOSING_TYPE (e.g., bart).  */
> +
> +GCC_METHOD2 (gcc_utempl, build_dependent_class_template,
> +            gcc_type,                    /* Argument ENCLOSING_TYPE.  */
> +            const char *)                            /* Argument ID.  */
> +
> +/* Build a template-dependent type template-id (e.g., T<A>).
> +   TEMPLATE_DECL should be a template template parameter (e.g., the T
> +   in template <template <[...]> class T = X>), and TARGS should
> +   specify the template arguments (e.g. <A>).  */
> +
> +GCC_METHOD2 (gcc_type, build_dependent_type_template_id,
> +            gcc_utempl,                   /* Argument TEMPLATE_DECL.  */
> +            const struct gcc_cp_template_args *)  /* Argument TARGS.  */
> +
> +/* Build a template-dependent expression (e.g., S::val or S::template
> +   mtf<X>, or unqualified f or template tf<X>).
> +
> +   ENCLOSING_SCOPE should be a template-dependent nested name
> +   specifier (e.g., T), a resolved namespace or class decl, or NULL
> +   for unqualified names; ID should be the name of the member of the
> +   ENCLOSING_SCOPE (e.g., val or mtf) or unqualified overloaded
> +   function; and TARGS should list template arguments (e.g. <X>) when
> +   mtf or tf are to name a template function, or be NULL otherwise.
> +
> +   Unqualified names and namespace- or class-qualified names can only
> +   resolve to overloaded functions, to be used in contexts that
> +   involve overload resolution that cannot be resolved because of
> +   template-dependent argument or return types, such as call
> +   expressions with template-dependent arguments, conversion
> +   expressions to function types with template-dependent argument
> +   types or the like.  Other cases of unqualified or
> +   non-template-dependent-qualified names should NOT use this
> +   function, and use decl_expr to convert the appropriate function or
> +   object declaration to an expression.
> +
> +   If ID is the name of a special member function, FLAGS should be
> +   GCC_CP_SYMBOL_FUNCTION|GCC_CP_FLAG_SPECIAL_FUNCTION, and ID should
> +   be one of the encodings for special member functions documented in
> +   build_decl.  Otherwise, FLAGS should be GCC_CP_SYMBOL_MASK, which
> +   suggests the symbol kind is not known (though we know it is not a
> +   type).
> +
> +   If ID denotes a conversion operator, CONV_TYPE should name the
> +   target type of the conversion.  Otherwise, CONV_TYPE must be
> +   NULL.  */
> +
> +GCC_METHOD5 (gcc_expr, build_dependent_expr,
> +            gcc_decl,                   /* Argument ENCLOSING_SCOPE.  */
> +            enum gcc_cp_symbol_kind,              /* Argument FLAGS.  */
> +            const char *,                          /* Argument NAME.  */
> +            gcc_type,                         /* Argument CONV_TYPE.  */
> +            const struct gcc_cp_template_args *)  /* Argument TARGS.  */
> +
> +/* Build a gcc_expr for the value VALUE in type TYPE.  */
> +
> +GCC_METHOD2 (gcc_expr, build_literal_expr,
> +            gcc_type,            /* Argument TYPE.  */
> +            unsigned long)       /* Argument VALUE.  */
> +
> +/* Build a gcc_expr that denotes DECL, the declaration of a variable
> +   or function in namespace scope, or of a static member variable or
> +   function.  Use QUALIFIED_P to build the operand of unary & so as to
> +   compute a pointer-to-member, rather than a regular pointer.  */
> +
> +GCC_METHOD2 (gcc_expr, build_decl_expr,
> +            gcc_decl,                  /* Argument DECL.  */
> +            int /* bool */)            /* Argument QUALIFIED_P.  */
> +
> +/* Build a gcc_expr that denotes the unary operation UNARY_OP applied
> +   to the gcc_expr OPERAND.  For non-expr operands, see
> +   unary_type_expr.  Besides the UNARY_OP encodings used for operator
> +   names, we support "pp_" for preincrement, and "mm_" for
> +   predecrement, "nx" for noexcept, "tw" for throw, "tr" for rethrow
> +   (pass NULL as the operand), "te" for typeid, "sz" for sizeof, "az"
> +   for alignof, "dl" for delete, "gsdl" for ::delete, "da" for
> +   delete[], "gsda" for ::delete[], "sp" for pack expansion, "sZ" for
> +   sizeof...(function argument pack).  */
> +
> +GCC_METHOD2 (gcc_expr, build_unary_expr,
> +            const char *,        /* Argument UNARY_OP.  */
> +            gcc_expr)            /* Argument OPERAND.  */
> +
> +/* Build a gcc_expr that denotes the binary operation BINARY_OP
> +   applied to gcc_exprs OPERAND1 and OPERAND2.  Besides the BINARY_OP
> +   encodings used for operator names, we support "ds" for the operator
> +   token ".*" and "dt" for the operator token ".".  When using
> +   operators that take a name as their second operand ("." and "->")
> +   use decl_expr to convert the gcc_decl of the member name to a
> +   gcc_expr, if the member name wasn't created with
> +   e.g. build_dependent_expr.  */
> +
> +GCC_METHOD3 (gcc_expr, build_binary_expr,
> +            const char *,        /* Argument BINARY_OP.  */
> +            gcc_expr,            /* Argument OPERAND1.  */
> +            gcc_expr)            /* Argument OPERAND2.  */
> +
> +/* Build a gcc_expr that denotes the ternary operation TERNARY_OP
> +   applied to gcc_exprs OPERAND1, OPERAND2 and OPERAND3.  The only
> +   supported TERNARY_OP is "qu", for the "?:" operator.  */
> +
> +GCC_METHOD4 (gcc_expr, build_ternary_expr,
> +            const char *,        /* Argument TERNARY_OP.  */
> +            gcc_expr,            /* Argument OPERAND1.  */
> +            gcc_expr,            /* Argument OPERAND2.  */
> +            gcc_expr)            /* Argument OPERAND3.  */
> +
> +/* Build a gcc_expr that denotes the unary operation UNARY_OP applied
> +   to the gcc_type OPERAND.  Supported unary operations taking types
> +   are "ti" for typeid, "st" for sizeof, "at" for alignof, and "sZ"
> +   for sizeof...(template argument pack).  */
> +
> +GCC_METHOD2 (gcc_expr, build_unary_type_expr,
> +            const char *,        /* Argument UNARY_OP.  */
> +            gcc_type)            /* Argument OPERAND.  */
> +
> +/* Build a gcc_expr that denotes the binary operation BINARY_OP
> +   applied to gcc_type OPERAND1 and gcc_expr OPERAND2.  Use this for
> +   all kinds of (single-argument) type casts ("dc", "sc", "cc", "rc"
> +   for dynamic, static, const and reinterpret casts, respectively;
> +   "cv" for functional or C-style casts).  */
> +
> +GCC_METHOD3 (gcc_expr, build_cast_expr,
> +            const char *,        /* Argument BINARY_OP.  */
> +            gcc_type,            /* Argument OPERAND1.  */
> +            gcc_expr)            /* Argument OPERAND2.  */
> +
> +/* Build a gcc_expr that denotes the conversion of an expression list
> +   VALUES to TYPE, with ("tl") or without ("cv") braces, or a braced
> +   initializer list of unspecified type (e.g., a component of another
> +   braced initializer list; pass "il" for CONV_OP, and NULL for
> +   TYPE).  */
> +
> +GCC_METHOD3 (gcc_expr, build_expression_list_expr,
> +            const char *,                       /* Argument CONV_OP.  */
> +            gcc_type,                              /* Argument TYPE.  */
> +            const struct gcc_cp_function_args *) /* Argument VALUES.  */
> +
> +/* Build a gcc_expr that denotes a new ("nw") or new[] ("na")
> +   expression of TYPE, with or without a GLOBAL_NS qualifier (prefix
> +   the NEW_OP with "gs"), with or without PLACEMENT, with or without
> +   INITIALIZER.  If it's not a placement new, PLACEMENT must be NULL
> +   (rather than a zero-length placement arg list).  If there's no
> +   specified initializer, INITIALIZER must be NULL; a zero-length arg
> +   list stands for a default initializer.  */
> +
> +GCC_METHOD4 (gcc_expr, build_new_expr,
> +            const char *,                             /* Argument NEW_OP.  */
> +            const struct gcc_cp_function_args *,   /* Argument PLACEMENT.  */
> +            gcc_type,                                   /* Argument TYPE.  */
> +            const struct gcc_cp_function_args *) /* Argument INITIALIZER.  */
> +
> +/* Return a call expression that calls CALLABLE with arguments ARGS.
> +   CALLABLE may be a function, a callable object, a pointer to
> +   function, an unresolved expression, an unresolved overload set, an
> +   object expression combined with a member function overload set or a
> +   pointer-to-member.  If QUALIFIED_P, CALLABLE will be interpreted as
> +   a qualified name, preventing virtual function dispatch.  */
> +
> +GCC_METHOD3 (gcc_expr, build_call_expr,
> +            gcc_expr,                        /* Argument CALLABLE.  */
> +            int /* bool */,               /* Argument QUALIFIED_P.  */
> +            const struct gcc_cp_function_args *) /* Argument ARGS.  */
> +
> +/* Return the type of the gcc_expr OPERAND.
> +   Use this for decltype.
> +   For decltype (auto), pass a NULL OPERAND.
> +
> +   Note: for template-dependent expressions, the result is NULL,
> +   because the type is only computed when template argument
> +   substitution is performed.  */
> +
> +GCC_METHOD1 (gcc_type, get_expr_type,
> +            gcc_expr)            /* Argument OPERAND.  */
> +
> +/* Introduce a specialization of a template function.
> +
> +   TEMPLATE_DECL is the template function, and TARGS are the arguments
> +   for the specialization.  ADDRESS is the address of the
> +   specialization.  FILENAME and LINE_NUMBER specify the source
> +   location associated with the template function specialization.  */
> +
> +GCC_METHOD5 (gcc_decl, build_function_template_specialization,
> +            gcc_decl,                     /* Argument TEMPLATE_DECL.  */
> +            const struct gcc_cp_template_args *,  /* Argument TARGS.  */
> +            gcc_address,                        /* Argument ADDRESS.  */
> +            const char *,            /* Argument FILENAME.  */
> +            unsigned int)            /* Argument LINE_NUMBER.  */
> +
> +/* Specialize a template class as an incomplete type.  A definition
> +   can be supplied later, with start_class_type.
> +
> +   TEMPLATE_DECL is the template class, and TARGS are the arguments
> +   for the specialization.  FILENAME and LINE_NUMBER specify the
> +   source location associated with the template class
> +   specialization.  */
> +
> +GCC_METHOD4 (gcc_decl, build_class_template_specialization,
> +            gcc_decl,                     /* Argument TEMPLATE_DECL.  */
> +            const struct gcc_cp_template_args *,  /* Argument TARGS.  */
> +            const char *,            /* Argument FILENAME.  */
> +            unsigned int)            /* Argument LINE_NUMBER.  */
> +
> +/* Start defining a 'class', 'struct' or 'union' type, entering its
> +   own binding level.  Initially it has no fields.
> +
> +   TYPEDECL is the forward-declaration of the type, returned by
> +   build_decl.  BASE_CLASSES indicate the base classes of class NAME.
> +   FILENAME and LINE_NUMBER specify the source location associated
> +   with the class definition, should they be different from those of
> +   the forward declaration.  */
> +
> +GCC_METHOD4 (gcc_type, start_class_type,
> +            gcc_decl,                /* Argument TYPEDECL.  */
> +            const struct gcc_vbase_array *,/* Argument BASE_CLASSES.  */
> +            const char *,            /* Argument FILENAME.  */
> +            unsigned int)            /* Argument LINE_NUMBER.  */
> +
> +/* Create a new closure class type, record it as the
> +   DISCRIMINATOR-numbered closure type in the current scope (or
> +   associated with EXTRA_SCOPE, if non-NULL), and enter the closure
> +   type's own binding level.  This primitive would sort of combine
> +   build_decl and start_class_type, if they could be used to introduce
> +   a closure type.  Initially it has no fields.
> +
> +   FILENAME and LINE_NUMBER specify the source location associated
> +   with the class.  EXTRA_SCOPE, if non-NULL, must be a PARM_DECL of
> +   the current function, or a FIELD_DECL of the current class.  If it
> +   is NULL, the current scope must be a function.  */
> +
> +GCC_METHOD5 (gcc_type, start_closure_class_type,
> +            int,                     /* Argument DISCRIMINATOR.  */
> +            gcc_decl,                /* Argument EXTRA_SCOPE.  */
> +            enum gcc_cp_symbol_kind, /* Argument FLAGS.  */
> +            const char *,            /* Argument FILENAME.  */
> +            unsigned int)            /* Argument LINE_NUMBER.  */
> +
> +/* Add a non-static data member to the most-recently-started
> +   unfinished struct or union type.  FIELD_NAME is the field's name.
> +   FIELD_TYPE is the type of the field.  BITSIZE and BITPOS indicate
> +   where in the struct the field occurs.  */
> +
> +GCC_METHOD5 (gcc_decl, build_field,
> +            const char *,                 /* Argument FIELD_NAME.  */
> +            gcc_type,                     /* Argument FIELD_TYPE.  */
> +            enum gcc_cp_symbol_kind,      /* Argument FIELD_FLAGS.  */
> +            unsigned long,                /* Argument BITSIZE.  */
> +            unsigned long)                /* Argument BITPOS.  */
> +
> +/* After all the fields have been added to a struct, class or union,
> +   the struct or union type must be "finished".  This does some final
> +   cleanups in GCC, and pops to the binding level that was in effect
> +   before the matching start_class_type or
> +   start_closure_class_type.  */
> +
> +GCC_METHOD1 (int /* bool */, finish_class_type,
> +            unsigned long)                /* Argument SIZE_IN_BYTES.  */
> +
> +/* Create a new 'enum' type, and record it in the current binding
> +   level.  The new type initially has no associated constants.
> +
> +   NAME is the enum name.  FILENAME and LINE_NUMBER specify its source
> +   location.  */
> +
> +GCC_METHOD5 (gcc_type, start_enum_type,
> +            const char *,            /* Argument NAME.  */
> +            gcc_type,                /* Argument UNDERLYING_INT_TYPE. */
> +            enum gcc_cp_symbol_kind, /* Argument FLAGS.  */
> +            const char *,            /* Argument FILENAME.  */
> +            unsigned int)            /* Argument LINE_NUMBER.  */
> +
> +/* Add a new constant to an enum type.  NAME is the constant's name
> +   and VALUE is its value.  Returns a gcc_decl for the constant.  */
> +
> +GCC_METHOD3 (gcc_decl, build_enum_constant,
> +            gcc_type,                 /* Argument ENUM_TYPE.  */
> +            const char *,             /* Argument NAME.  */
> +            unsigned long)            /* Argument VALUE.  */
> +
> +/* After all the constants have been added to an enum, the type must
> +   be "finished".  This does some final cleanups in GCC.  */
> +
> +GCC_METHOD1 (int /* bool */, finish_enum_type,
> +            gcc_type)                 /* Argument ENUM_TYPE.  */
> +
> +/* Create a new function type.  RETURN_TYPE is the type returned by
> +   the function, and ARGUMENT_TYPES is a vector, of length NARGS, of
> +   the argument types.  IS_VARARGS is true if the function is
> +   varargs.  */
> +
> +GCC_METHOD3 (gcc_type, build_function_type,
> +            gcc_type,                     /* Argument RETURN_TYPE.  */
> +            const struct gcc_type_array *,/* Argument ARGUMENT_TYPES.  */
> +            int /* bool */)               /* Argument IS_VARARGS.  */
> +
> +/* Create a variant of a function type with an exception
> +   specification.  FUNCTION_TYPE is a function or method type.
> +   EXCEPT_TYPES is an array with the list of exception types.  Zero as
> +   the array length implies throw() AKA noexcept(true); NULL as the
> +   pointer to gcc_type_array implies noexcept(false), which is almost
> +   equivalent (but distinguishable by the compiler) to an unspecified
> +   exception list.  */
> +
> +GCC_METHOD2 (gcc_type, build_exception_spec_variant,
> +            gcc_type,                     /* Argument FUNCTION_TYPE.  */
> +            const struct gcc_type_array *)/* Argument EXCEPT_TYPES.  */
> +
> +/* Create a new non-static member function type.  FUNC_TYPE is the
> +   method prototype, without the implicit THIS pointer, added as a
> +   pointer to the QUALS-qualified CLASS_TYPE.  If CLASS_TYPE is NULL,
> +   this creates a cv-qualified (member) function type not associated
> +   with any specific class, as needed to support "typedef void f(int)
> +   const;", which can later be used to declare member functions and
> +   pointers to member functions.  */
> +
> +GCC_METHOD4 (gcc_type, build_method_type,
> +            gcc_type,                     /* Argument CLASS_TYPE.  */
> +            gcc_type,                     /* Argument FUNC_TYPE.  */
> +            enum gcc_cp_qualifiers,       /* Argument QUALS.  */
> +            enum gcc_cp_ref_qualifiers)   /* Argument RQUALS.  */
> +
> +/* Return a declaration for the (INDEX - 1)th argument of
> +   FUNCTION_DECL, i.e., for the first argument, use zero as the index.
> +   If FUNCTION_DECL is a non-static member function, use -1 to get the
> +   implicit THIS parameter.  */
> +
> +GCC_METHOD2 (gcc_decl, get_function_parameter_decl,
> +            gcc_decl,                       /* Argument FUNCTION_DECL.  */
> +            int)                                    /* Argument INDEX.  */
> +
> +/* Return a lambda expr that constructs an instance of CLOSURE_TYPE.
> +   Only lambda exprs without any captures can be correctly created
> +   through these mechanisms; that's all we need to support lambdas
> +   expressions in default parameters, the only kind that may have to
> +   be introduced through this interface.  */
> +
> +GCC_METHOD1 (gcc_expr, build_lambda_expr,
> +            gcc_type)                        /* Argument CLOSURE_TYPE.  */
> +
> +/* Return an integer type with the given properties.  If BUILTIN_NAME
> +   is non-NULL, it must name a builtin integral type with the given
> +   signedness and size, and that is the type that will be returned.  */
> +
> +GCC_METHOD3 (gcc_type, get_int_type,
> +            int /* bool */,               /* Argument IS_UNSIGNED.  */
> +            unsigned long,                /* Argument SIZE_IN_BYTES.  */
> +            const char *)                 /* Argument BUILTIN_NAME.  */
> +
> +/* Return the 'char' type, a distinct type from both 'signed char' and
> +   'unsigned char' returned by int_type.  */
> +
> +GCC_METHOD0 (gcc_type, get_char_type)
> +
> +/* Return a floating point type with the given properties.  If BUILTIN_NAME
> +   is non-NULL, it must name a builtin integral type with the given
> +   signedness and size, and that is the type that will be returned.  */
> +
> +GCC_METHOD2 (gcc_type, get_float_type,
> +            unsigned long,                /* Argument SIZE_IN_BYTES.  */
> +            const char *)                 /* Argument BUILTIN_NAME.  */
> +
> +/* Return the 'void' type.  */
> +
> +GCC_METHOD0 (gcc_type, get_void_type)
> +
> +/* Return the 'bool' type.  */
> +
> +GCC_METHOD0 (gcc_type, get_bool_type)
> +
> +/* Return the std::nullptr_t type.  */
> +
> +GCC_METHOD0 (gcc_type, get_nullptr_type)
> +
> +/* Return the nullptr constant.  */
> +
> +GCC_METHOD0 (gcc_expr, get_nullptr_constant)
> +
> +/* Create a new array type.  If NUM_ELEMENTS is -1, then the array
> +   is assumed to have an unknown length.  */
> +
> +GCC_METHOD2 (gcc_type, build_array_type,
> +            gcc_type,                    /* Argument ELEMENT_TYPE.  */
> +            int)                         /* Argument NUM_ELEMENTS.  */
> +
> +/* Create a new array type.  NUM_ELEMENTS is a template-dependent
> +   expression.  */
> +
> +GCC_METHOD2 (gcc_type, build_dependent_array_type,
> +            gcc_type,                    /* Argument ELEMENT_TYPE.  */
> +            gcc_expr)                    /* Argument NUM_ELEMENTS.  */
> +
> +/* Create a new variably-sized array type.  UPPER_BOUND_NAME is the
> +   name of a local variable that holds the upper bound of the array;
> +   it is one less than the array size.  */
> +
> +GCC_METHOD2 (gcc_type, build_vla_array_type,
> +            gcc_type,                    /* Argument ELEMENT_TYPE.  */
> +            const char *)                /* Argument UPPER_BOUND_NAME.  */
> +
> +/* Return a qualified variant of a given base type.  QUALIFIERS says
> +   which qualifiers to use; it is composed of or'd together
> +   constants from 'enum gcc_cp_qualifiers'.  */
> +
> +GCC_METHOD2 (gcc_type, build_qualified_type,
> +            gcc_type,                        /* Argument UNQUALIFIED_TYPE.  */
> +            enum gcc_cp_qualifiers)          /* Argument QUALIFIERS.  */
> +
> +/* Build a complex type given its element type.  */
> +
> +GCC_METHOD1 (gcc_type, build_complex_type,
> +            gcc_type)                    /* Argument ELEMENT_TYPE.  */
> +
> +/* Build a vector type given its element type and number of
> +   elements.  */
> +
> +GCC_METHOD2 (gcc_type, build_vector_type,
> +            gcc_type,                    /* Argument ELEMENT_TYPE.  */
> +            int)                         /* Argument NUM_ELEMENTS.  */
> +
> +/* Build a constant.  NAME is the constant's name and VALUE is its
> +   value.  FILENAME and LINE_NUMBER refer to the type's source
> +   location.  If this is not known, FILENAME can be NULL and
> +   LINE_NUMBER can be 0.  */
> +
> +GCC_METHOD5 (int /* bool */, build_constant,
> +            gcc_type,            /* Argument TYPE.  */
> +            const char *,        /* Argument NAME.  */
> +            unsigned long,       /* Argument VALUE.  */
> +            const char *,        /* Argument FILENAME.  */
> +            unsigned int)        /* Argument LINE_NUMBER.  */
> +
> +/* Emit an error and return an error type object.  */
> +
> +GCC_METHOD1 (gcc_type, error,
> +            const char *)               /* Argument MESSAGE.  */
> +
> +/* Declare a static_assert with the given CONDITION and ERRORMSG at
> +   FILENAME:LINE_NUMBER.  */
> +
> +GCC_METHOD4 (int /* bool */, add_static_assert,
> +            gcc_expr,     /* Argument CONDITION.  */
> +            const char *, /* Argument ERRORMSG.  */
> +            const char *, /* Argument FILENAME.  */
> +            unsigned int) /* Argument LINE_NUMBER.  */
> +
> +#if 0
> +
> +/* FIXME: We don't want to expose the internal implementation detail
> +   that default parms are stored in function types, and it's not clear
> +   how this or other approaches would interact with the type sharing
> +   of e.g. ctor clones, so we're leaving this out, since default args
> +   are not even present in debug information anyway.  Besides, the set
> +   of default args for a function may grow within its scope, and vary
> +   independently in other scopes.  */
> +
> +/* Create a modified version of a function type that has default
> +   values for some of its arguments.  The returned type should ONLY be
> +   used to define functions or methods, never to declare parameters,
> +   variables, types or the like.
> +
> +   DEFAULTS must have at most as many N_ELEMENTS as there are
> +   arguments without default values in FUNCTION_TYPE.  Say, if
> +   FUNCTION_TYPE has an argument list such as (T1, T2, T3, T4 = V0)
> +   and DEFAULTS has 2 elements (V1, V2), the returned type will have
> +   the following argument list: (T1, T2 = V1, T3 = V2, T4 = V0).
> +
> +   Any NULL expressions in DEFAULTS will be marked as deferred, and
> +   they should be filled in with set_deferred_function_default_args.  */
> +
> +GCC_METHOD2 (gcc_type, add_function_default_args,
> +            gcc_type,                       /* Argument FUNCTION_TYPE.  */
> +            const struct gcc_cp_function_args *) /* Argument DEFAULTS.  */
> +
> +/* Fill in the first deferred default args in FUNCTION_DECL with the
> +   expressions given in DEFAULTS.  This can be used when the
> +   declaration of a parameter is needed to create a default
> +   expression, such as taking the size of an earlier parameter, or
> +   building a lambda expression in the parameter's context.  */
> +
> +GCC_METHOD2 (int /* bool */, set_deferred_function_default_args,
> +            gcc_decl,                       /* Argument FUNCTION_DECL.  */
> +            const struct gcc_cp_function_args *) /* Argument DEFAULTS.  */
> +
> +#endif
> +
> +
> +/* When you add entry points, add them at the end, so that the new API
> +   version remains compatible with the old version.
> +
> +   The following conventions have been observed as to naming entry points:
> +
> +   - build_* creates (and maybe records) something and returns it;
> +   - add_* creates and records something, but doesn't return it;
> +   - get_* obtains something without creating it;
> +   - start_* marks the beginning of a compound (type, list, ...);
> +   - finish_* completes the compound when needed.
> +
> +  Entry points that return an int (bool) and don't have a return value
> +  specification return nonzero (true) on success and zero (false) on
> +  failure.  This is in line with libcc1's conventions of returning a
> +  zero-initialized value in case of e.g. a transport error.  */
> diff --git a/include/gcc-cp-interface.h b/include/gcc-cp-interface.h
> new file mode 100644
> index 0000000..6ef9e22
> --- /dev/null
> +++ b/include/gcc-cp-interface.h
> @@ -0,0 +1,496 @@
> +/* Interface between GCC C++ FE and GDB
> +
> +   Copyright (C) 2014-2017 Free Software Foundation, Inc.
> +
> +   This file is part of GCC.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#ifndef GCC_CP_INTERFACE_H
> +#define GCC_CP_INTERFACE_H
> +
> +#include "gcc-interface.h"
> +
> +/* This header defines the interface to the GCC API.  It must be both
> +   valid C and valid C++, because it is included by both programs.  */
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +/* Forward declaration.  */
> +
> +struct gcc_cp_context;
> +
> +/*
> + * Definitions and declarations for the C++ front end.
> + */
> +
> +/* Defined versions of the C++ front-end API.  */
> +
> +enum gcc_cp_api_version
> +{
> +  GCC_CP_FE_VERSION_0 = 0
> +};
> +
> +/* Qualifiers.  */
> +
> +enum gcc_cp_qualifiers
> +{
> +  GCC_CP_QUALIFIER_CONST = 1,
> +  GCC_CP_QUALIFIER_VOLATILE = 2,
> +  GCC_CP_QUALIFIER_RESTRICT = 4
> +};
> +
> +/* Ref qualifiers.  */
> +
> +enum gcc_cp_ref_qualifiers {
> +  GCC_CP_REF_QUAL_NONE = 0,
> +  GCC_CP_REF_QUAL_LVALUE = 1,
> +  GCC_CP_REF_QUAL_RVALUE = 2
> +};
> +
> +/* Opaque typedef for unbound class templates.  They are used for
> +   template arguments, and defaults for template template
> +   parameters.  */
> +
> +typedef unsigned long long gcc_utempl;
> +
> +/* Opaque typedef for expressions.  They are used for template
> +   arguments, defaults for non-type template parameters, and defaults
> +   for function arguments.  */
> +
> +typedef unsigned long long gcc_expr;
> +
> +typedef enum
> +  { GCC_CP_TPARG_VALUE, GCC_CP_TPARG_CLASS,
> +    GCC_CP_TPARG_TEMPL, GCC_CP_TPARG_PACK }
> +gcc_cp_template_arg_kind;
> +
> +typedef union
> +{ gcc_expr value; gcc_type type; gcc_utempl templ; gcc_type pack; }
> +gcc_cp_template_arg;
> +
> +/* An array of template arguments.  */
> +
> +struct gcc_cp_template_args
> +{
> +  /* Number of elements.  */
> +
> +  int n_elements;
> +
> +  /* kind[i] indicates what kind of template argument type[i] is.  */
> +
> +  char /* gcc_cp_template_arg_kind */ *kinds;
> +
> +  /* The template arguments.  */
> +
> +  gcc_cp_template_arg *elements;
> +};
> +
> +/* An array of (default) function arguments.  */
> +
> +struct gcc_cp_function_args
> +{
> +  /* Number of elements.  */
> +
> +  int n_elements;
> +
> +  /* The (default) values for each argument.  */
> +
> +  gcc_expr *elements;
> +};
> +
> +/* This enumerates the kinds of decls that GDB can create.  */
> +
> +enum gcc_cp_symbol_kind
> +{
> +  /* A function.  */
> +
> +  GCC_CP_SYMBOL_FUNCTION,
> +
> +  /* A variable.  */
> +
> +  GCC_CP_SYMBOL_VARIABLE,
> +
> +  /* A typedef, or an alias declaration (including template ones).  */
> +
> +  GCC_CP_SYMBOL_TYPEDEF,
> +
> +  /* A label.  */
> +
> +  GCC_CP_SYMBOL_LABEL,
> +
> +  /* A class, forward declared in build_decl (to be later defined in
> +     start_class_definition), or, in a template parameter list scope,
> +     a declaration of a template class, closing the parameter
> +     list.  */
> +
> +  GCC_CP_SYMBOL_CLASS,
> +
> +  /* A union, forward declared in build_decl (to be later defined in
> +     start_class_definition).  */
> +
> +  GCC_CP_SYMBOL_UNION,
> +
> +  /* An enumeration type being introduced with start_new_enum_type.  */
> +
> +  GCC_CP_SYMBOL_ENUM,
> +
> +  /* A nonstatic data member being introduced with new_field.  */
> +
> +  GCC_CP_SYMBOL_FIELD,
> +
> +  /* A base class in a gcc_vbase_array.  */
> +
> +  GCC_CP_SYMBOL_BASECLASS,
> +
> +  /* A using declaration in new_using_decl.  */
> +
> +  GCC_CP_SYMBOL_USING,
> +
> +  /* A (lambda) closure class type.  In many regards this is just like
> +     a regular class, but it's not supposed to have base classes, some
> +     of the member functions that are usually implicitly-defined are
> +     deleted, and it should have an operator() member function that
> +     holds the lambda body.  We can't instantiate objects of lambda
> +     types from the snippet, but we can interact with them in such
> +     ways as passing them to functions that take their types, and
> +     calling their body.  */
> +
> +  GCC_CP_SYMBOL_LAMBDA_CLOSURE,
> +
> +  /* Marker to check that we haven't exceeded GCC_CP_SYMBOL_MASK.  */
> +  GCC_CP_SYMBOL_END,
> +
> +  GCC_CP_SYMBOL_MASK = 15,
> +
> +  /* When defining a class member, at least one of the
> +     GCC_CP_ACCESS_MASK bits must be set; when defining a namespace-
> +     or union-scoped symbol, none of them must be set.  */
> +
> +  GCC_CP_ACCESS_PRIVATE,
> +  GCC_CP_ACCESS_PUBLIC = GCC_CP_ACCESS_PRIVATE << 1,
> +  GCC_CP_ACCESS_MASK = (GCC_CP_ACCESS_PUBLIC
> +                              | GCC_CP_ACCESS_PRIVATE),
> +  GCC_CP_ACCESS_PROTECTED = GCC_CP_ACCESS_MASK,
> +  GCC_CP_ACCESS_NONE = 0,
> +
> +  GCC_CP_FLAG_BASE = GCC_CP_ACCESS_PRIVATE << 2,
> +
> +  /* Flags to be used along with GCC_CP_SYMBOL_FUNCTION:  */
> +
> +  /* This flag should be set for constructors, destructors and
> +     operators.  */
> +  GCC_CP_FLAG_SPECIAL_FUNCTION = GCC_CP_FLAG_BASE,
> +
> +  /* We intentionally cannot express inline, constexpr, or virtual
> +     override for functions.  We can't inline or constexpr-replace
> +     without a source-level body.  The override keyword is only
> +     meaningful within the definition of the containing class.  */
> +
> +  /* This indicates a "virtual" member function, explicitly or
> +     implicitly (due to a virtual function with the same name and
> +     prototype in a base class) declared as such.  */
> +  GCC_CP_FLAG_VIRTUAL_FUNCTION = GCC_CP_FLAG_BASE << 1,
> +
> +  /* The following two flags should only be set when the flag above is
> +     set.  */
> +
> +  /* This indicates a pure virtual member function, i.e., one that is
> +     declared with "= 0", even if a body is provided in the
> +     definition.  */
> +  GCC_CP_FLAG_PURE_VIRTUAL_FUNCTION = GCC_CP_FLAG_BASE << 2,
> +
> +  /* This indicates a "final" virtual member function.  */
> +  GCC_CP_FLAG_FINAL_VIRTUAL_FUNCTION = GCC_CP_FLAG_BASE << 3,
> +
> +  /* This indicates a special member function should have its default
> +     implementation.  This either means the function declaration
> +     contains the "= default" tokens, or that the member function was
> +     implicitly generated by the compiler, although the latter use is
> +     discouraged: just let the compiler implicitly introduce it.
> +
> +     A member function defaulted after its first declaration has
> +     slightly different ABI implications from one implicitly generated
> +     or explicitly defaulted at the declaration (and definition)
> +     point.  To avoid silent (possibly harmless) violation of the one
> +     definition rule, it is recommended that this flag not be used for
> +     such functions, and that the address of the definition be
> +     supplied instead.  */
> +  GCC_CP_FLAG_DEFAULTED_FUNCTION = GCC_CP_FLAG_BASE << 4,
> +
> +  /* This indicates a deleted member function, i.e., one that has been
> +     defined as "= delete" at its declaration point, or one that has
> +     been implicitly defined as deleted (with or without an explicit
> +     "= default" definition).
> +
> +     This should not be used for implicitly-declared member functions
> +     that resolve to deleted definitions, as it may affect the
> +     implicit declaration of other member functions.  */
> +  GCC_CP_FLAG_DELETED_FUNCTION = GCC_CP_FLAG_BASE << 5,
> +
> +  /* This indicates a constructor or type-conversion operator declared
> +     as "explicit".  */
> +
> +  GCC_CP_FLAG_EXPLICIT_FUNCTION = GCC_CP_FLAG_BASE << 6,
> +
> +  GCC_CP_FLAG_END_FUNCTION,
> +  GCC_CP_FLAG_MASK_FUNCTION = (((GCC_CP_FLAG_END_FUNCTION - 1) << 1)
> +                              - GCC_CP_FLAG_BASE),
> +
> +  /* Flags to be used along with GCC_CP_SYMBOL_VARIABLE:  */
> +
> +  /* This indicates a variable declared as "constexpr".  */
> +
> +  GCC_CP_FLAG_CONSTEXPR_VARIABLE = GCC_CP_FLAG_BASE,
> +
> +  /* This indicates a variable declared as "thread_local".  ??? What
> +     should the ADDRESS be?  */
> +
> +  GCC_CP_FLAG_THREAD_LOCAL_VARIABLE = GCC_CP_FLAG_BASE << 1,
> +
> +  GCC_CP_FLAG_END_VARIABLE,
> +  GCC_CP_FLAG_MASK_VARIABLE = (((GCC_CP_FLAG_END_VARIABLE - 1) << 1)
> +                              - GCC_CP_FLAG_BASE),
> +
> +  /* Flags to be used when defining nonstatic data members of classes
> +     with new_field.  */
> +
> +  /* Use this when no flags are present.  */
> +  GCC_CP_FLAG_FIELD_NOFLAG = 0,
> +
> +  /* This indicates the field is declared as mutable.  */
> +  GCC_CP_FLAG_FIELD_MUTABLE = GCC_CP_FLAG_BASE,
> +
> +  GCC_CP_FLAG_END_FIELD,
> +  GCC_CP_FLAG_MASK_FIELD = (((GCC_CP_FLAG_END_FIELD - 1) << 1)
> +                           - GCC_CP_FLAG_BASE),
> +
> +  /* Flags to be used when defining an enum with
> +     start_new_enum_type.  */
> +
> +  /* This indicates an enum type without any flags.  */
> +  GCC_CP_FLAG_ENUM_NOFLAG = 0,
> +
> +  /* This indicates a scoped enum type.  */
> +  GCC_CP_FLAG_ENUM_SCOPED = GCC_CP_FLAG_BASE,
> +
> +  GCC_CP_FLAG_END_ENUM,
> +  GCC_CP_FLAG_MASK_ENUM = (((GCC_CP_FLAG_END_ENUM - 1) << 1)
> +                              - GCC_CP_FLAG_BASE),
> +
> +
> +  /* Flags to be used when introducing a class or a class template
> +     with build_decl.  */
> +
> +  /* This indicates an enum type without any flags.  */
> +  GCC_CP_FLAG_CLASS_NOFLAG = 0,
> +
> +  /* This indicates the class is actually a struct.  This has no
> +     effect whatsoever on access control in this interface, since all
> +     class members must have explicit access control bits set, but it
> +     may affect error messages.  */
> +  GCC_CP_FLAG_CLASS_IS_STRUCT = GCC_CP_FLAG_BASE,
> +
> +  GCC_CP_FLAG_END_CLASS,
> +  GCC_CP_FLAG_MASK_CLASS = (((GCC_CP_FLAG_END_CLASS - 1) << 1)
> +                              - GCC_CP_FLAG_BASE),
> +
> +
> +  /* Flags to be used when introducing a virtual base class in a
> +     gcc_vbase_array.  */
> +
> +  /* This indicates an enum type without any flags.  */
> +  GCC_CP_FLAG_BASECLASS_NOFLAG = 0,
> +
> +  /* This indicates the class is actually a struct.  This has no
> +     effect whatsoever on access control in this interface, since all
> +     class members must have explicit access control bits set, but it
> +     may affect error messages.  */
> +  GCC_CP_FLAG_BASECLASS_VIRTUAL = GCC_CP_FLAG_BASE,
> +
> +  GCC_CP_FLAG_END_BASECLASS,
> +  GCC_CP_FLAG_MASK_BASECLASS = (((GCC_CP_FLAG_END_BASECLASS - 1) << 1)
> +                               - GCC_CP_FLAG_BASE),
> +
> +
> +  GCC_CP_FLAG_MASK = (GCC_CP_FLAG_MASK_FUNCTION
> +                     | GCC_CP_FLAG_MASK_VARIABLE
> +                     | GCC_CP_FLAG_MASK_FIELD
> +                     | GCC_CP_FLAG_MASK_ENUM
> +                     | GCC_CP_FLAG_MASK_CLASS
> +                     | GCC_CP_FLAG_MASK_BASECLASS
> +                     )
> +};
> +
> +
> +/* An array of types used for creating lists of base classes.  */
> +
> +struct gcc_vbase_array
> +{
> +  /* Number of elements.  */
> +
> +  int n_elements;
> +
> +  /* The base classes.  */
> +
> +  gcc_type *elements;
> +
> +  /* Flags for each base class.  Used to indicate access control and
> +     virtualness.  */
> +
> +  enum gcc_cp_symbol_kind *flags;
> +};
> +
> +
> +/* This enumerates the types of symbols that GCC might request from
> +   GDB.  */
> +
> +enum gcc_cp_oracle_request
> +{
> +  /* An identifier in namespace scope -- type, variable, function,
> +     namespace, template.  All namespace-scoped symbols with the
> +     requested name, in any namespace (including the global
> +     namespace), should be defined in response to this request.  */
> +
> +  GCC_CP_ORACLE_IDENTIFIER
> +};
> +
> +/* The type of the function called by GCC to ask GDB for a symbol's
> +   definition.  DATUM is an arbitrary value supplied when the oracle
> +   function is registered.  CONTEXT is the GCC context in which the
> +   request is being made.  REQUEST specifies what sort of symbol is
> +   being requested, and IDENTIFIER is the name of the symbol.  */
> +
> +typedef void gcc_cp_oracle_function (void *datum,
> +                                    struct gcc_cp_context *context,
> +                                    enum gcc_cp_oracle_request request,
> +                                    const char *identifier);
> +
> +/* The type of the function called by GCC to ask GDB for a symbol's
> +   address.  This should return 0 if the address is not known.  */
> +
> +typedef gcc_address gcc_cp_symbol_address_function (void *datum,
> +                                                   struct gcc_cp_context *ctxt,
> +                                                   const char *identifier);
> +
> +/* The type of the function called by GCC to ask GDB to enter or leave
> +   the user expression scope.  */
> +
> +typedef void gcc_cp_enter_leave_user_expr_scope_function (void *datum,
> +                                                         struct gcc_cp_context
> +                                                         *context);
> +
> +/* The vtable used by the C front end.  */
> +
> +struct gcc_cp_fe_vtable
> +{
> +  /* The version of the C interface.  The value is one of the
> +     gcc_cp_api_version constants.  */
> +
> +  unsigned int cp_version;
> +
> +  /* Set the callbacks for this context.
> +
> +     The binding oracle is called whenever the C++ parser needs to
> +     look up a symbol.  This gives the caller a chance to lazily
> +     instantiate symbols using other parts of the gcc_cp_fe_interface
> +     API.  The symbol is looked up without a scope, and the oracle
> +     must supply a definition for ALL namespace-scoped definitions
> +     bound to the symbol.
> +
> +     The address oracle is called whenever the C++ parser needs to
> +     look up a symbol.  This may be called for symbols not provided by
> +     the symbol oracle, such as built-in functions where GCC provides
> +     the declaration; other internal symbols, such as those related
> +     with thunks, rtti, and virtual tables are likely to be queried
> +     through this interface too.  The identifier is a mangled symbol
> +     name.
> +
> +     DATUM is an arbitrary piece of data that is passed back verbatim
> +     to the callbacks in requests.  */
> +
> +  void (*set_callbacks) (struct gcc_cp_context *self,
> +                        gcc_cp_oracle_function *binding_oracle,
> +                        gcc_cp_symbol_address_function *address_oracle,
> +                        gcc_cp_enter_leave_user_expr_scope_function *enter_scope,
> +                        gcc_cp_enter_leave_user_expr_scope_function *leave_scope,
> +                        void *datum);
> +
> +#define GCC_METHOD0(R, N) \
> +  R (*N) (struct gcc_cp_context *);
> +#define GCC_METHOD1(R, N, A) \
> +  R (*N) (struct gcc_cp_context *, A);
> +#define GCC_METHOD2(R, N, A, B) \
> +  R (*N) (struct gcc_cp_context *, A, B);
> +#define GCC_METHOD3(R, N, A, B, C) \
> +  R (*N) (struct gcc_cp_context *, A, B, C);
> +#define GCC_METHOD4(R, N, A, B, C, D) \
> +  R (*N) (struct gcc_cp_context *, A, B, C, D);
> +#define GCC_METHOD5(R, N, A, B, C, D, E) \
> +  R (*N) (struct gcc_cp_context *, A, B, C, D, E);
> +#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \
> +  R (*N) (struct gcc_cp_context *, A, B, C, D, E, F, G);
> +
> +#include "gcc-cp-fe.def"
> +
> +#undef GCC_METHOD0
> +#undef GCC_METHOD1
> +#undef GCC_METHOD2
> +#undef GCC_METHOD3
> +#undef GCC_METHOD4
> +#undef GCC_METHOD5
> +#undef GCC_METHOD7
> +
> +};
> +
> +/* The C front end object.  */
> +
> +struct gcc_cp_context
> +{
> +  /* Base class.  */
> +
> +  struct gcc_base_context base;
> +
> +  /* Our vtable.  This is a separate field because this is simpler
> +     than implementing a vtable inheritance scheme in C.  */
> +
> +  const struct gcc_cp_fe_vtable *cp_ops;
> +};
> +
> +/* The name of the .so that the compiler builds.  We dlopen this
> +   later.  */
> +
> +#define GCC_CP_FE_LIBCC libcc1.so
> +
> +/* The compiler exports a single initialization function.  This macro
> +   holds its name as a symbol.  */
> +
> +#define GCC_CP_FE_CONTEXT gcc_cp_fe_context
> +
> +/* The type of the initialization function.  The caller passes in the
> +   desired base version and desired C-specific version.  If the
> +   request can be satisfied, a compatible gcc_context object will be
> +   returned.  Otherwise, the function returns NULL.  */
> +
> +typedef struct gcc_cp_context *gcc_cp_fe_context_function
> +    (enum gcc_base_api_version,
> +     enum gcc_cp_api_version);
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif /* GCC_CP_INTERFACE_H */
> diff --git a/include/gcc-interface.h b/include/gcc-interface.h
> index e3ffd18..1dc3498 100644
> --- a/include/gcc-interface.h
> +++ b/include/gcc-interface.h
> @@ -169,6 +169,20 @@ struct gcc_base_context
>    const struct gcc_base_vtable *ops;
>  };
>
> +/* An array of types used for creating function types in multiple
> +   languages.  */
> +
> +struct gcc_type_array
> +{
> +  /* Number of elements.  */
> +
> +  int n_elements;
> +
> +  /* The elements.  */
> +
> +  gcc_type *elements;
> +};
> +
>  /* The name of the dummy wrapper function generated by gdb.  */
>
>  #define GCC_FE_WRAPPER_FUNCTION "_gdb_expr"
> diff --git a/libcc1/Makefile.am b/libcc1/Makefile.am
> index 02f0675..5e61a92 100644
> --- a/libcc1/Makefile.am
> +++ b/libcc1/Makefile.am
> @@ -19,9 +19,11 @@
>  ACLOCAL_AMFLAGS = -I .. -I ../config
>  gcc_build_dir = ../gcc
>  AM_CPPFLAGS = -I $(srcdir)/../include -I $(srcdir)/../libgcc \
> -       -I $(gcc_build_dir) -I$(srcdir)/../gcc \
> -       -I $(srcdir)/../gcc/c -I $(srcdir)/../gcc/c-family \
> -       -I $(srcdir)/../libcpp/include $(GMPINC)
> +       -I $(gcc_build_dir) -I$(srcdir)/../gcc $($@_CPPFLAGS) $(GMPINC)
> +CPPFLAGS_FOR_C_FAMILY = -I $(srcdir)/../gcc/c-family \
> +       -I $(srcdir)/../libcpp/include
> +CPPFLAGS_FOR_C = $(CPPFLAGS_FOR_C_FAMILY) -I $(srcdir)/../gcc/c
> +CPPFLAGS_FOR_CXX = $(CPPFLAGS_FOR_C_FAMILY) -I $(srcdir)/../gcc/cp
>  AM_CXXFLAGS = $(WARN_FLAGS) $(WERROR) $(visibility)
>  override CXXFLAGS := $(filter-out -fsanitize=address,$(CXXFLAGS))
>  override LDFLAGS := $(filter-out -fsanitize=address,$(LDFLAGS))
> @@ -39,33 +41,57 @@ plugindir = $(libdir)/gcc/$(target_noncanonical)/$(gcc_version)/plugin
>  cc1libdir = $(libdir)/$(libsuffix)
>
>  if ENABLE_PLUGIN
> -plugin_LTLIBRARIES = libcc1plugin.la
> +plugin_LTLIBRARIES = libcc1plugin.la libcp1plugin.la
>  cc1lib_LTLIBRARIES = libcc1.la
>  endif
>
> -BUILT_SOURCES = compiler-name.h
> -MOSTLYCLEANFILES = compiler-name.h
> +BUILT_SOURCES = c-compiler-name.h cp-compiler-name.h
> +MOSTLYCLEANFILES = c-compiler-name.h cp-compiler-name.h
>
>  # Put this in a header so we don't run sed for each compilation.  This
>  # is also simpler to debug as one can easily see the constant.
> -compiler-name.h: Makefile
> -       echo "#define COMPILER_NAME \"`echo gcc | sed '$(transform)'`\"" > $@
> +# FIXME: compute it in configure.ac and output it in config.status, or
> +# introduce timestamp files for some indirection to avoid rebuilding it
> +# every time.
> +c-compiler-name.h: Makefile
> +       -rm -f $@T
> +       echo "#define C_COMPILER_NAME \"`echo gcc | sed '$(transform)'`\"" > $@T
> +       mv $@T $@ # $(SHELL) $(srcdir)/../move-if-change $@T $@
>
> +cp-compiler-name.h: Makefile
> +       -rm -f $@T
> +       echo "#define CP_COMPILER_NAME \"`echo g++ | sed '$(transform)'`\"" > $@T
> +       mv $@T $@ # $(SHELL) $(srcdir)/../move-if-change $@T $@
>
>  shared_source = callbacks.cc callbacks.hh connection.cc connection.hh \
>      marshall.cc marshall.hh rpc.hh status.hh
>
> +marshall_c_source = marshall-c.hh
> +marshall_cxx_source = marshall-cp.hh
> +
>  libcc1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1plugin.sym
> -libcc1plugin_la_SOURCES = plugin.cc $(shared_source)
> +libcc1plugin_la_SOURCES = libcc1plugin.cc $(shared_source) $(marshall_c_source)
> +libcc1plugin.lo_CPPFLAGS = $(CPPFLAGS_FOR_C)
>  libcc1plugin_la_LIBADD = $(libiberty)
>  libcc1plugin_la_DEPENDENCIES = $(libiberty_dep)
>  libcc1plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
>         $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
>         $(CXXFLAGS) $(libcc1plugin_la_LDFLAGS) $(LTLDFLAGS) -o $@
>
> +libcp1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcp1plugin.sym
> +libcp1plugin_la_SOURCES = libcp1plugin.cc $(shared_source) $(marshall_cxx_source)
> +libcp1plugin.lo_CPPFLAGS = $(CPPFLAGS_FOR_CXX)
> +libcp1plugin_la_LIBADD = $(libiberty)
> +libcp1plugin_la_DEPENDENCIES = $(libiberty_dep)
> +libcp1plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
> +       $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
> +       $(CXXFLAGS) $(libcp1plugin_la_LDFLAGS) $(LTLDFLAGS) -o $@
> +
>  LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
>  libcc1_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1.sym
> -libcc1_la_SOURCES = findcomp.cc libcc1.cc names.cc names.hh $(shared_source)
> +libcc1_la_SOURCES = findcomp.cc libcc1.cc libcp1.cc \
> +               names.cc names.hh $(shared_source) \
> +               $(marshall_c_source) $(marshall_cxx_source)
>  libcc1_la_LIBADD = $(libiberty)
>  libcc1_la_DEPENDENCIES = $(libiberty_dep)
>  libcc1_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
> diff --git a/libcc1/Makefile.in b/libcc1/Makefile.in
> index 21fb153..54babb0 100644
> --- a/libcc1/Makefile.in
> +++ b/libcc1/Makefile.in
> @@ -105,12 +105,19 @@ am__uninstall_files_from_dir = { \
>  am__installdirs = "$(DESTDIR)$(cc1libdir)" "$(DESTDIR)$(plugindir)"
>  LTLIBRARIES = $(cc1lib_LTLIBRARIES) $(plugin_LTLIBRARIES)
>  am__objects_1 = callbacks.lo connection.lo marshall.lo
> -am_libcc1_la_OBJECTS = findcomp.lo libcc1.lo names.lo $(am__objects_1)
> +am__objects_2 =
> +am_libcc1_la_OBJECTS = findcomp.lo libcc1.lo libcp1.lo names.lo \
> +       $(am__objects_1) $(am__objects_2) $(am__objects_2)
>  libcc1_la_OBJECTS = $(am_libcc1_la_OBJECTS)
>  @ENABLE_PLUGIN_TRUE@am_libcc1_la_rpath = -rpath $(cc1libdir)
> -am_libcc1plugin_la_OBJECTS = plugin.lo $(am__objects_1)
> +am_libcc1plugin_la_OBJECTS = libcc1plugin.lo $(am__objects_1) \
> +       $(am__objects_2)
>  libcc1plugin_la_OBJECTS = $(am_libcc1plugin_la_OBJECTS)
>  @ENABLE_PLUGIN_TRUE@am_libcc1plugin_la_rpath = -rpath $(plugindir)
> +am_libcp1plugin_la_OBJECTS = libcp1plugin.lo $(am__objects_1) \
> +       $(am__objects_2)
> +libcp1plugin_la_OBJECTS = $(am_libcp1plugin_la_OBJECTS)
> +@ENABLE_PLUGIN_TRUE@am_libcp1plugin_la_rpath = -rpath $(plugindir)
>  DEFAULT_INCLUDES = -I.@am__isrc@
>  depcomp = $(SHELL) $(top_srcdir)/../depcomp
>  am__depfiles_maybe = depfiles
> @@ -133,7 +140,8 @@ CCLD = $(CC)
>  LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
>         --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
>         $(LDFLAGS) -o $@
> -SOURCES = $(libcc1_la_SOURCES) $(libcc1plugin_la_SOURCES)
> +SOURCES = $(libcc1_la_SOURCES) $(libcc1plugin_la_SOURCES) \
> +       $(libcp1plugin_la_SOURCES)
>  am__can_run_installinfo = \
>    case $$AM_UPDATE_INFO_DIR in \
>      n|no|NO) false;; \
> @@ -277,10 +285,13 @@ visibility = @visibility@
>  ACLOCAL_AMFLAGS = -I .. -I ../config
>  gcc_build_dir = ../gcc
>  AM_CPPFLAGS = -I $(srcdir)/../include -I $(srcdir)/../libgcc \
> -       -I $(gcc_build_dir) -I$(srcdir)/../gcc \
> -       -I $(srcdir)/../gcc/c -I $(srcdir)/../gcc/c-family \
> -       -I $(srcdir)/../libcpp/include $(GMPINC)
> +       -I $(gcc_build_dir) -I$(srcdir)/../gcc $($@_CPPFLAGS) $(GMPINC)
>
> +CPPFLAGS_FOR_C_FAMILY = -I $(srcdir)/../gcc/c-family \
> +       -I $(srcdir)/../libcpp/include
> +
> +CPPFLAGS_FOR_C = $(CPPFLAGS_FOR_C_FAMILY) -I $(srcdir)/../gcc/c
> +CPPFLAGS_FOR_CXX = $(CPPFLAGS_FOR_C_FAMILY) -I $(srcdir)/../gcc/cp
>  AM_CXXFLAGS = $(WARN_FLAGS) $(WERROR) $(visibility)
>  # Can be simplified when libiberty becomes a normal convenience library.
>  libiberty_normal = ../libiberty/libiberty.a
> @@ -294,24 +305,39 @@ libiberty = $(if $(wildcard $(libiberty_noasan)),$(Wc)$(libiberty_noasan), \
>  libiberty_dep = $(patsubst $(Wc)%,%,$(libiberty))
>  plugindir = $(libdir)/gcc/$(target_noncanonical)/$(gcc_version)/plugin
>  cc1libdir = $(libdir)/$(libsuffix)
> -@ENABLE_PLUGIN_TRUE@plugin_LTLIBRARIES = libcc1plugin.la
> +@ENABLE_PLUGIN_TRUE@plugin_LTLIBRARIES = libcc1plugin.la libcp1plugin.la
>  @ENABLE_PLUGIN_TRUE@cc1lib_LTLIBRARIES = libcc1.la
> -BUILT_SOURCES = compiler-name.h
> -MOSTLYCLEANFILES = compiler-name.h
> +BUILT_SOURCES = c-compiler-name.h cp-compiler-name.h
> +MOSTLYCLEANFILES = c-compiler-name.h cp-compiler-name.h
>  shared_source = callbacks.cc callbacks.hh connection.cc connection.hh \
>      marshall.cc marshall.hh rpc.hh status.hh
>
> +marshall_c_source = marshall-c.hh
> +marshall_cxx_source = marshall-cp.hh
>  libcc1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1plugin.sym
> -libcc1plugin_la_SOURCES = plugin.cc $(shared_source)
> +libcc1plugin_la_SOURCES = libcc1plugin.cc $(shared_source) $(marshall_c_source)
> +libcc1plugin.lo_CPPFLAGS = $(CPPFLAGS_FOR_C)
>  libcc1plugin_la_LIBADD = $(libiberty)
>  libcc1plugin_la_DEPENDENCIES = $(libiberty_dep)
>  libcc1plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
>         $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
>         $(CXXFLAGS) $(libcc1plugin_la_LDFLAGS) $(LTLDFLAGS) -o $@
>
> +libcp1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcp1plugin.sym
> +libcp1plugin_la_SOURCES = libcp1plugin.cc $(shared_source) $(marshall_cxx_source)
> +libcp1plugin.lo_CPPFLAGS = $(CPPFLAGS_FOR_CXX)
> +libcp1plugin_la_LIBADD = $(libiberty)
> +libcp1plugin_la_DEPENDENCIES = $(libiberty_dep)
> +libcp1plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
> +       $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
> +       $(CXXFLAGS) $(libcp1plugin_la_LDFLAGS) $(LTLDFLAGS) -o $@
> +
>  LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
>  libcc1_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1.sym
> -libcc1_la_SOURCES = findcomp.cc libcc1.cc names.cc names.hh $(shared_source)
> +libcc1_la_SOURCES = findcomp.cc libcc1.cc libcp1.cc \
> +               names.cc names.hh $(shared_source) \
> +               $(marshall_c_source) $(marshall_cxx_source)
> +
>  libcc1_la_LIBADD = $(libiberty)
>  libcc1_la_DEPENDENCIES = $(libiberty_dep)
>  libcc1_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
> @@ -440,6 +466,8 @@ libcc1.la: $(libcc1_la_OBJECTS) $(libcc1_la_DEPENDENCIES) $(EXTRA_libcc1_la_DEPE
>         $(libcc1_la_LINK) $(am_libcc1_la_rpath) $(libcc1_la_OBJECTS) $(libcc1_la_LIBADD) $(LIBS)
>  libcc1plugin.la: $(libcc1plugin_la_OBJECTS) $(libcc1plugin_la_DEPENDENCIES) $(EXTRA_libcc1plugin_la_DEPENDENCIES)
>         $(libcc1plugin_la_LINK) $(am_libcc1plugin_la_rpath) $(libcc1plugin_la_OBJECTS) $(libcc1plugin_la_LIBADD) $(LIBS)
> +libcp1plugin.la: $(libcp1plugin_la_OBJECTS) $(libcp1plugin_la_DEPENDENCIES) $(EXTRA_libcp1plugin_la_DEPENDENCIES)
> +       $(libcp1plugin_la_LINK) $(am_libcp1plugin_la_rpath) $(libcp1plugin_la_OBJECTS) $(libcp1plugin_la_LIBADD) $(LIBS)
>
>  mostlyclean-compile:
>         -rm -f *.$(OBJEXT)
> @@ -451,9 +479,11 @@ distclean-compile:
>  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connection.Plo@am__quote@
>  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/findcomp.Plo@am__quote@
>  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcc1.Plo@am__quote@
> +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcc1plugin.Plo@am__quote@
> +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcp1.Plo@am__quote@
> +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcp1plugin.Plo@am__quote@
>  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/marshall.Plo@am__quote@
>  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/names.Plo@am__quote@
> -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin.Plo@am__quote@
>
>  .cc.o:
>  @am__fastdepCXX_TRUE@  $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
> @@ -674,8 +704,18 @@ override LDFLAGS := $(filter-out -fsanitize=address,$(LDFLAGS))
>
>  # Put this in a header so we don't run sed for each compilation.  This
>  # is also simpler to debug as one can easily see the constant.
> -compiler-name.h: Makefile
> -       echo "#define COMPILER_NAME \"`echo gcc | sed '$(transform)'`\"" > $@
> +# FIXME: compute it in configure.ac and output it in config.status, or
> +# introduce timestamp files for some indirection to avoid rebuilding it
> +# every time.
> +c-compiler-name.h: Makefile
> +       -rm -f $@T
> +       echo "#define C_COMPILER_NAME \"`echo gcc | sed '$(transform)'`\"" > $@T
> +       mv $@T $@ # $(SHELL) $(srcdir)/../move-if-change $@T $@
> +
> +cp-compiler-name.h: Makefile
> +       -rm -f $@T
> +       echo "#define CP_COMPILER_NAME \"`echo g++ | sed '$(transform)'`\"" > $@T
> +       mv $@T $@ # $(SHELL) $(srcdir)/../move-if-change $@T $@
>
>  # Tell versions [3.59,3.63) of GNU make to not export all variables.
>  # Otherwise a system limit (for SysV at least) may be exceeded.
> diff --git a/libcc1/libcc1.cc b/libcc1/libcc1.cc
> index 572bc2a..0ef6c11 100644
> --- a/libcc1/libcc1.cc
> +++ b/libcc1/libcc1.cc
> @@ -29,15 +29,15 @@ along with GCC; see the file COPYING3.  If not see
>  #include <sys/stat.h>
>  #include <stdlib.h>
>  #include <sstream>
> +#include "marshall-c.hh"
>  #include "rpc.hh"
>  #include "connection.hh"
>  #include "names.hh"
>  #include "callbacks.hh"
> -#include "gcc-interface.h"
>  #include "libiberty.h"
>  #include "xregex.h"
>  #include "findcomp.hh"
> -#include "compiler-name.h"
> +#include "c-compiler-name.h"
>  #include "intl.h"
>
>  struct libcc1;
> @@ -164,30 +164,35 @@ libcc1::~libcc1 ()
>
>
>
> -// This is a wrapper function that is called by the RPC system and
> -// that then forwards the call to the library user.  Note that the
> -// return value is not used; the type cannot be 'void' due to
> -// limitations in our simple RPC.
> -int
> -call_binding_oracle (cc1_plugin::connection *conn,
> -                    enum gcc_c_oracle_request request,
> -                    const char *identifier)
> -{
> -  libcc1 *self = ((libcc1_connection *) conn)->back_ptr;
> +// Enclose these functions in an anonymous namespace because they
> +// shouldn't be exported, but they can't be static because they're
> +// used as template arguments.
> +namespace {
> +  // This is a wrapper function that is called by the RPC system and
> +  // that then forwards the call to the library user.  Note that the
> +  // return value is not used; the type cannot be 'void' due to
> +  // limitations in our simple RPC.
> +  int
> +  c_call_binding_oracle (cc1_plugin::connection *conn,
> +                        enum gcc_c_oracle_request request,
> +                        const char *identifier)
> +  {
> +    libcc1 *self = ((libcc1_connection *) conn)->back_ptr;
>
> -  self->binding_oracle (self->oracle_datum, self, request, identifier);
> -  return 1;
> -}
> +    self->binding_oracle (self->oracle_datum, self, request, identifier);
> +    return 1;
> +  }
>
> -// This is a wrapper function that is called by the RPC system and
> -// that then forwards the call to the library user.
> -gcc_address
> -call_symbol_address (cc1_plugin::connection *conn, const char *identifier)
> -{
> -  libcc1 *self = ((libcc1_connection *) conn)->back_ptr;
> +  // This is a wrapper function that is called by the RPC system and
> +  // that then forwards the call to the library user.
> +  gcc_address
> +  c_call_symbol_address (cc1_plugin::connection *conn, const char *identifier)
> +  {
> +    libcc1 *self = ((libcc1_connection *) conn)->back_ptr;
>
> -  return self->address_oracle (self->oracle_datum, self, identifier);
> -}
> +    return self->address_oracle (self->oracle_datum, self, identifier);
> +  }
> +} /* anonymous namespace */
>
>
>
> @@ -298,19 +303,19 @@ static const struct gcc_c_fe_vtable c_vtable =
>    set_callbacks,
>
>  #define GCC_METHOD0(R, N) \
> -  rpc<R, cc1_plugin::N>,
> +  rpc<R, cc1_plugin::c::N>,
>  #define GCC_METHOD1(R, N, A) \
> -  rpc<R, cc1_plugin::N, A>,
> +  rpc<R, cc1_plugin::c::N, A>,
>  #define GCC_METHOD2(R, N, A, B) \
> -  rpc<R, cc1_plugin::N, A, B>,
> +  rpc<R, cc1_plugin::c::N, A, B>,
>  #define GCC_METHOD3(R, N, A, B, C) \
> -  rpc<R, cc1_plugin::N, A, B, C>,
> +  rpc<R, cc1_plugin::c::N, A, B, C>,
>  #define GCC_METHOD4(R, N, A, B, C, D) \
> -  rpc<R, cc1_plugin::N, A, B, C, D>,
> +  rpc<R, cc1_plugin::c::N, A, B, C, D>,
>  #define GCC_METHOD5(R, N, A, B, C, D, E) \
> -  rpc<R, cc1_plugin::N, A, B, C, D, E>,
> +  rpc<R, cc1_plugin::c::N, A, B, C, D, E>,
>  #define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \
> -  rpc<R, cc1_plugin::N, A, B, C, D, E, F, G>,
> +  rpc<R, cc1_plugin::c::N, A, B, C, D, E, F, G>,
>
>  #include "gcc-c-fe.def"
>
> @@ -377,13 +382,12 @@ libcc1::compiler::find (std::string &compiler ATTRIBUTE_UNUSED) const
>  char *
>  libcc1::compiler_triplet_regexp::find (std::string &compiler) const
>  {
> -  std::string rx = make_regexp (triplet_regexp_.c_str (), COMPILER_NAME);
> +  std::string rx = make_regexp (triplet_regexp_.c_str (), C_COMPILER_NAME);
>    if (self_->verbose)
>      fprintf (stderr, _("searching for compiler matching regex %s\n"),
>              rx.c_str());
>    regex_t triplet;
> -  int code;
> -  code = regcomp (&triplet, rx.c_str (), REG_EXTENDED | REG_NOSUB);
> +  int code = regcomp (&triplet, rx.c_str (), REG_EXTENDED | REG_NOSUB);
>    if (code != 0)
>      {
>        size_t len = regerror (code, &triplet, NULL, 0);
> @@ -532,7 +536,7 @@ fork_exec (libcc1 *self, char **argv, int spair_fds[2], int stderr_fds[2])
>
>        cc1_plugin::status result = cc1_plugin::FAIL;
>        if (self->connection->send ('H')
> -         && ::cc1_plugin::marshall (self->connection, GCC_C_FE_VERSION_0))
> +         && ::cc1_plugin::marshall (self->connection, GCC_C_FE_VERSION_1))
>         result = self->connection->wait_for_query ();
>
>        close (spair_fds[0]);
> @@ -601,12 +605,12 @@ libcc1_compile (struct gcc_base_context *s,
>      = cc1_plugin::callback<int,
>                            enum gcc_c_oracle_request,
>                            const char *,
> -                          call_binding_oracle>;
> +                          c_call_binding_oracle>;
>    self->connection->add_callback ("binding_oracle", fun);
>
>    fun = cc1_plugin::callback<gcc_address,
>                              const char *,
> -                            call_symbol_address>;
> +                            c_call_symbol_address>;
>    self->connection->add_callback ("address_oracle", fun);
>
>    char **argv = new (std::nothrow) char *[self->args.size () + 1];
> @@ -663,7 +667,7 @@ gcc_c_fe_context (enum gcc_base_api_version base_version,
>                   enum gcc_c_api_version c_version)
>  {
>    if ((base_version != GCC_FE_VERSION_0 && base_version != GCC_FE_VERSION_1)
> -      || c_version != GCC_C_FE_VERSION_0)
> +      || (c_version != GCC_C_FE_VERSION_0 && c_version != GCC_C_FE_VERSION_1))
>      return NULL;
>
>    return new libcc1 (&vtable, &c_vtable);
> diff --git a/libcc1/libcc1.sym b/libcc1/libcc1.sym
> index 86b1e3e..9d46f26 100644
> --- a/libcc1/libcc1.sym
> +++ b/libcc1/libcc1.sym
> @@ -1 +1,2 @@
>  gcc_c_fe_context
> +gcc_cp_fe_context
> diff --git a/libcc1/libcc1plugin.cc b/libcc1/libcc1plugin.cc
> new file mode 100644
> index 0000000..bd05c8d
> --- /dev/null
> +++ b/libcc1/libcc1plugin.cc
> @@ -0,0 +1,1020 @@
> +/* Library interface to C front end
> +   Copyright (C) 2014-2017 Free Software Foundation, Inc.
> +
> +   This file is part of GCC.
> +
> +   GCC 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, or (at your option) any later
> +   version.
> +
> +   GCC 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 GCC; see the file COPYING3.  If not see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include <cc1plugin-config.h>
> +
> +#undef PACKAGE_NAME
> +#undef PACKAGE_STRING
> +#undef PACKAGE_TARNAME
> +#undef PACKAGE_VERSION
> +
> +#include "../gcc/config.h"
> +
> +#undef PACKAGE_NAME
> +#undef PACKAGE_STRING
> +#undef PACKAGE_TARNAME
> +#undef PACKAGE_VERSION
> +
> +#include "gcc-plugin.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "stringpool.h"
> +
> +#include "gcc-interface.h"
> +#include "hash-set.h"
> +#include "machmode.h"
> +#include "vec.h"
> +#include "double-int.h"
> +#include "input.h"
> +#include "alias.h"
> +#include "symtab.h"
> +#include "options.h"
> +#include "wide-int.h"
> +#include "inchash.h"
> +#include "tree.h"
> +#include "fold-const.h"
> +#include "stor-layout.h"
> +#include "c-tree.h"
> +#include "toplev.h"
> +#include "timevar.h"
> +#include "hash-table.h"
> +#include "tm.h"
> +#include "c-family/c-pragma.h"
> +#include "c-lang.h"
> +#include "diagnostic.h"
> +#include "langhooks.h"
> +#include "langhooks-def.h"
> +
> +#include "callbacks.hh"
> +#include "connection.hh"
> +#include "marshall-c.hh"
> +#include "rpc.hh"
> +
> +#ifdef __GNUC__
> +#pragma GCC visibility push(default)
> +#endif
> +int plugin_is_GPL_compatible;
> +#ifdef __GNUC__
> +#pragma GCC visibility pop
> +#endif
> +
> +
> +
> +// This is put into the lang hooks when the plugin starts.
> +
> +static void
> +plugin_print_error_function (diagnostic_context *context, const char *file,
> +                            diagnostic_info *diagnostic)
> +{
> +  if (current_function_decl != NULL_TREE
> +      && DECL_NAME (current_function_decl) != NULL_TREE
> +      && strcmp (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),
> +                GCC_FE_WRAPPER_FUNCTION) == 0)
> +    return;
> +  lhd_print_error_function (context, file, diagnostic);
> +}
> +
> +
> +
> +static unsigned long long
> +convert_out (tree t)
> +{
> +  return (unsigned long long) (uintptr_t) t;
> +}
> +
> +static tree
> +convert_in (unsigned long long v)
> +{
> +  return (tree) (uintptr_t) v;
> +}
> +
> +
> +
> +struct decl_addr_value
> +{
> +  tree decl;
> +  tree address;
> +};
> +
> +struct decl_addr_hasher : free_ptr_hash<decl_addr_value>
> +{
> +  static inline hashval_t hash (const decl_addr_value *);
> +  static inline bool equal (const decl_addr_value *, const decl_addr_value *);
> +};
> +
> +inline hashval_t
> +decl_addr_hasher::hash (const decl_addr_value *e)
> +{
> +  return IDENTIFIER_HASH_VALUE (DECL_NAME (e->decl));
> +}
> +
> +inline bool
> +decl_addr_hasher::equal (const decl_addr_value *p1, const decl_addr_value *p2)
> +{
> +  return p1->decl == p2->decl;
> +}
> +
> +
> +
> +struct string_hasher : nofree_ptr_hash<const char>
> +{
> +  static inline hashval_t hash (const char *s)
> +  {
> +    return htab_hash_string (s);
> +  }
> +
> +  static inline bool equal (const char *p1, const char *p2)
> +  {
> +    return strcmp (p1, p2) == 0;
> +  }
> +};
> +
> +
> +
> +// A wrapper for pushdecl that doesn't let gdb have a chance to
> +// instantiate a symbol.
> +
> +static void
> +pushdecl_safe (tree decl)
> +{
> +  void (*save) (enum c_oracle_request, tree identifier);
> +
> +  save = c_binding_oracle;
> +  c_binding_oracle = NULL;
> +  pushdecl (decl);
> +  c_binding_oracle = save;
> +}
> +
> +
> +
> +struct plugin_context : public cc1_plugin::connection
> +{
> +  plugin_context (int fd);
> +
> +  // Map decls to addresses.
> +  hash_table<decl_addr_hasher> address_map;
> +
> +  // A collection of trees that are preserved for the GC.
> +  hash_table< nofree_ptr_hash<tree_node> > preserved;
> +
> +  // File name cache.
> +  hash_table<string_hasher> file_names;
> +
> +  // Perform GC marking.
> +  void mark ();
> +
> +  // Preserve a tree during the plugin's operation.
> +  tree preserve (tree t)
> +  {
> +    tree_node **slot = preserved.find_slot (t, INSERT);
> +    *slot = t;
> +    return t;
> +  }
> +
> +  source_location get_source_location (const char *filename,
> +                                      unsigned int line_number)
> +  {
> +    if (filename == NULL)
> +      return UNKNOWN_LOCATION;
> +
> +    filename = intern_filename (filename);
> +    linemap_add (line_table, LC_ENTER, false, filename, line_number);
> +    source_location loc = linemap_line_start (line_table, line_number, 0);
> +    linemap_add (line_table, LC_LEAVE, false, NULL, 0);
> +    return loc;
> +  }
> +
> +private:
> +
> +  // Add a file name to FILE_NAMES and return the canonical copy.
> +  const char *intern_filename (const char *filename)
> +  {
> +    const char **slot = file_names.find_slot (filename, INSERT);
> +    if (*slot == NULL)
> +      {
> +       /* The file name must live as long as the line map, which
> +          effectively means as long as this compilation.  So, we copy
> +          the string here but never free it.  */
> +       *slot = xstrdup (filename);
> +      }
> +    return *slot;
> +  }
> +};
> +
> +static plugin_context *current_context;
> +
> +
> +
> +plugin_context::plugin_context (int fd)
> +  : cc1_plugin::connection (fd),
> +    address_map (30),
> +    preserved (30),
> +    file_names (30)
> +{
> +}
> +
> +void
> +plugin_context::mark ()
> +{
> +  for (hash_table<decl_addr_hasher>::iterator it = address_map.begin ();
> +       it != address_map.end ();
> +       ++it)
> +    {
> +      ggc_mark ((*it)->decl);
> +      ggc_mark ((*it)->address);
> +    }
> +
> +  for (hash_table< nofree_ptr_hash<tree_node> >::iterator
> +        it = preserved.begin (); it != preserved.end (); ++it)
> +    ggc_mark (&*it);
> +}
> +
> +static void
> +plugin_binding_oracle (enum c_oracle_request kind, tree identifier)
> +{
> +  enum gcc_c_oracle_request request;
> +
> +  gcc_assert (current_context != NULL);
> +
> +  switch (kind)
> +    {
> +    case C_ORACLE_SYMBOL:
> +      request = GCC_C_ORACLE_SYMBOL;
> +      break;
> +    case C_ORACLE_TAG:
> +      request = GCC_C_ORACLE_TAG;
> +      break;
> +    case C_ORACLE_LABEL:
> +      request = GCC_C_ORACLE_LABEL;
> +      break;
> +    default:
> +      abort ();
> +    }
> +
> +  int ignore;
> +  cc1_plugin::call (current_context, "binding_oracle", &ignore,
> +                   request, IDENTIFIER_POINTER (identifier));
> +}
> +
> +static void
> +plugin_pragma_user_expression (cpp_reader *)
> +{
> +  c_binding_oracle = plugin_binding_oracle;
> +}
> +
> +static void
> +plugin_init_extra_pragmas (void *, void *)
> +{
> +  c_register_pragma ("GCC", "user_expression", plugin_pragma_user_expression);
> +}
> +
> +
> +
> +// Maybe rewrite a decl to its address.
> +static tree
> +address_rewriter (tree *in, int *walk_subtrees, void *arg)
> +{
> +  plugin_context *ctx = (plugin_context *) arg;
> +
> +  if (!DECL_P (*in) || DECL_NAME (*in) == NULL_TREE)
> +    return NULL_TREE;
> +
> +  decl_addr_value value;
> +  value.decl = *in;
> +  decl_addr_value *found_value = ctx->address_map.find (&value);
> +  if (found_value != NULL)
> +    ;
> +  else if (DECL_IS_BUILTIN (*in))
> +    {
> +      gcc_address address;
> +
> +      if (!cc1_plugin::call (ctx, "address_oracle", &address,
> +                            IDENTIFIER_POINTER (DECL_NAME (*in))))
> +       return NULL_TREE;
> +      if (address == 0)
> +       return NULL_TREE;
> +
> +      // Insert the decl into the address map in case it is referenced
> +      // again.
> +      value.address = build_int_cst_type (ptr_type_node, address);
> +      decl_addr_value **slot = ctx->address_map.find_slot (&value, INSERT);
> +      gcc_assert (*slot == NULL);
> +      *slot
> +       = static_cast<decl_addr_value *> (xmalloc (sizeof (decl_addr_value)));
> +      **slot = value;
> +      found_value = *slot;
> +    }
> +  else
> +    return NULL_TREE;
> +
> +  if (found_value->address != error_mark_node)
> +    {
> +      // We have an address for the decl, so rewrite the tree.
> +      tree ptr_type = build_pointer_type (TREE_TYPE (*in));
> +      *in = fold_build1 (INDIRECT_REF, TREE_TYPE (*in),
> +                        fold_build1 (CONVERT_EXPR, ptr_type,
> +                                     found_value->address));
> +    }
> +
> +  *walk_subtrees = 0;
> +
> +  return NULL_TREE;
> +}
> +
> +// When generating code for gdb, we want to be able to use absolute
> +// addresses to refer to otherwise external objects that gdb knows
> +// about.  gdb passes in these addresses when building decls, and then
> +// before gimplification we go through the trees, rewriting uses to
> +// the equivalent of "*(TYPE *) ADDR".
> +static void
> +rewrite_decls_to_addresses (void *function_in, void *)
> +{
> +  tree function = (tree) function_in;
> +
> +  // Do nothing if we're not in gdb.
> +  if (current_context == NULL)
> +    return;
> +
> +  walk_tree (&DECL_SAVED_TREE (function), address_rewriter, current_context,
> +            NULL);
> +}
> +
> +
> +
> +gcc_decl
> +plugin_build_decl (cc1_plugin::connection *self,
> +                  const char *name,
> +                  enum gcc_c_symbol_kind sym_kind,
> +                  gcc_type sym_type_in,
> +                  const char *substitution_name,
> +                  gcc_address address,
> +                  const char *filename,
> +                  unsigned int line_number)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree identifier = get_identifier (name);
> +  enum tree_code code;
> +  tree decl;
> +  tree sym_type = convert_in (sym_type_in);
> +
> +  switch (sym_kind)
> +    {
> +    case GCC_C_SYMBOL_FUNCTION:
> +      code = FUNCTION_DECL;
> +      break;
> +
> +    case GCC_C_SYMBOL_VARIABLE:
> +      code = VAR_DECL;
> +      break;
> +
> +    case GCC_C_SYMBOL_TYPEDEF:
> +      code = TYPE_DECL;
> +      break;
> +
> +    case GCC_C_SYMBOL_LABEL:
> +      // FIXME: we aren't ready to handle labels yet.
> +      // It isn't clear how to translate them properly
> +      // and in any case a "goto" isn't likely to work.
> +      return convert_out (error_mark_node);
> +
> +    default:
> +      abort ();
> +    }
> +
> +  source_location loc = ctx->get_source_location (filename, line_number);
> +
> +  decl = build_decl (loc, code, identifier, sym_type);
> +  TREE_USED (decl) = 1;
> +  TREE_ADDRESSABLE (decl) = 1;
> +
> +  if (sym_kind != GCC_C_SYMBOL_TYPEDEF)
> +    {
> +      decl_addr_value value;
> +
> +      DECL_EXTERNAL (decl) = 1;
> +      value.decl = decl;
> +      if (substitution_name != NULL)
> +       {
> +         // If the translator gave us a name without a binding,
> +         // we can just substitute error_mark_node, since we know the
> +         // translator will be reporting an error anyhow.
> +         value.address
> +           = lookup_name (get_identifier (substitution_name));
> +         if (value.address == NULL_TREE)
> +           value.address = error_mark_node;
> +       }
> +      else
> +       value.address = build_int_cst_type (ptr_type_node, address);
> +      decl_addr_value **slot = ctx->address_map.find_slot (&value, INSERT);
> +      gcc_assert (*slot == NULL);
> +      *slot
> +       = static_cast<decl_addr_value *> (xmalloc (sizeof (decl_addr_value)));
> +      **slot = value;
> +    }
> +
> +  return convert_out (ctx->preserve (decl));
> +}
> +
> +int
> +plugin_bind (cc1_plugin::connection *,
> +            gcc_decl decl_in, int is_global)
> +{
> +  tree decl = convert_in (decl_in);
> +  c_bind (DECL_SOURCE_LOCATION (decl), decl, is_global);
> +  rest_of_decl_compilation (decl, is_global, 0);
> +  return 1;
> +}
> +
> +int
> +plugin_tagbind (cc1_plugin::connection *self,
> +               const char *name, gcc_type tagged_type,
> +               const char *filename, unsigned int line_number)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree t = convert_in (tagged_type), x;
> +  c_pushtag (ctx->get_source_location (filename, line_number),
> +            get_identifier (name), t);
> +
> +  /* Propagate the newly-added type name so that previously-created
> +     variant types are not disconnected from their main variants.  */
> +  for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
> +    TYPE_NAME (x) = TYPE_NAME (t);
> +
> +  return 1;
> +}
> +
> +gcc_type
> +plugin_build_pointer_type (cc1_plugin::connection *,
> +                          gcc_type base_type)
> +{
> +  // No need to preserve a pointer type as the base type is preserved.
> +  return convert_out (build_pointer_type (convert_in (base_type)));
> +}
> +
> +// TYPE_NAME needs to be a valid pointer, even if there is no name available.
> +
> +static tree
> +build_anonymous_node (enum tree_code code)
> +{
> +  tree node = make_node (code);
> +  tree type_decl = build_decl (input_location, TYPE_DECL, NULL_TREE, node);
> +  TYPE_NAME (node) = type_decl;
> +  TYPE_STUB_DECL (node) = type_decl;
> +  return node;
> +}
> +
> +gcc_type
> +plugin_build_record_type (cc1_plugin::connection *self)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  return convert_out (ctx->preserve (build_anonymous_node (RECORD_TYPE)));
> +}
> +
> +gcc_type
> +plugin_build_union_type (cc1_plugin::connection *self)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  return convert_out (ctx->preserve (build_anonymous_node (UNION_TYPE)));
> +}
> +
> +int
> +plugin_build_add_field (cc1_plugin::connection *,
> +                       gcc_type record_or_union_type_in,
> +                       const char *field_name,
> +                       gcc_type field_type_in,
> +                       unsigned long bitsize,
> +                       unsigned long bitpos)
> +{
> +  tree record_or_union_type = convert_in (record_or_union_type_in);
> +  tree field_type = convert_in (field_type_in);
> +
> +  gcc_assert (TREE_CODE (record_or_union_type) == RECORD_TYPE
> +             || TREE_CODE (record_or_union_type) == UNION_TYPE);
> +
> +  /* Note that gdb does not preserve the location of field decls, so
> +     we can't provide a decent location here.  */
> +  tree decl = build_decl (BUILTINS_LOCATION, FIELD_DECL,
> +                         get_identifier (field_name), field_type);
> +  DECL_FIELD_CONTEXT (decl) = record_or_union_type;
> +
> +  if (TREE_CODE (field_type) == INTEGER_TYPE
> +      && TYPE_PRECISION (field_type) != bitsize)
> +    {
> +      DECL_BIT_FIELD_TYPE (decl) = field_type;
> +      TREE_TYPE (decl)
> +       = c_build_bitfield_integer_type (bitsize, TYPE_UNSIGNED (field_type));
> +    }
> +
> +  SET_DECL_MODE (decl, TYPE_MODE (TREE_TYPE (decl)));
> +
> +  // There's no way to recover this from DWARF.
> +  SET_DECL_OFFSET_ALIGN (decl, TYPE_PRECISION (pointer_sized_int_node));
> +
> +  tree pos = bitsize_int (bitpos);
> +  pos_from_bit (&DECL_FIELD_OFFSET (decl), &DECL_FIELD_BIT_OFFSET (decl),
> +               DECL_OFFSET_ALIGN (decl), pos);
> +
> +  DECL_SIZE (decl) = bitsize_int (bitsize);
> +  DECL_SIZE_UNIT (decl) = size_int ((bitsize + BITS_PER_UNIT - 1)
> +                                   / BITS_PER_UNIT);
> +
> +  DECL_CHAIN (decl) = TYPE_FIELDS (record_or_union_type);
> +  TYPE_FIELDS (record_or_union_type) = decl;
> +
> +  return 1;
> +}
> +
> +int
> +plugin_finish_record_or_union (cc1_plugin::connection *,
> +                              gcc_type record_or_union_type_in,
> +                              unsigned long size_in_bytes)
> +{
> +  tree record_or_union_type = convert_in (record_or_union_type_in);
> +
> +  gcc_assert (TREE_CODE (record_or_union_type) == RECORD_TYPE
> +             || TREE_CODE (record_or_union_type) == UNION_TYPE);
> +
> +  /* We built the field list in reverse order, so fix it now.  */
> +  TYPE_FIELDS (record_or_union_type)
> +    = nreverse (TYPE_FIELDS (record_or_union_type));
> +
> +  if (TREE_CODE (record_or_union_type) == UNION_TYPE)
> +    {
> +      /* Unions can just be handled by the generic code.  */
> +      layout_type (record_or_union_type);
> +    }
> +  else
> +    {
> +      // FIXME there's no way to get this from DWARF,
> +      // or even, it seems, a particularly good way to deduce it.
> +      SET_TYPE_ALIGN (record_or_union_type,
> +                     TYPE_PRECISION (pointer_sized_int_node));
> +
> +      TYPE_SIZE (record_or_union_type) = bitsize_int (size_in_bytes
> +                                                     * BITS_PER_UNIT);
> +      TYPE_SIZE_UNIT (record_or_union_type) = size_int (size_in_bytes);
> +
> +      compute_record_mode (record_or_union_type);
> +      finish_bitfield_layout (record_or_union_type);
> +      // FIXME we have no idea about TYPE_PACKED
> +    }
> +
> +  tree t = record_or_union_type, x;
> +  for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
> +    {
> +      /* Like finish_struct, update the qualified variant types.  */
> +      TYPE_FIELDS (x) = TYPE_FIELDS (t);
> +      TYPE_LANG_SPECIFIC (x) = TYPE_LANG_SPECIFIC (t);
> +      C_TYPE_FIELDS_READONLY (x) = C_TYPE_FIELDS_READONLY (t);
> +      C_TYPE_FIELDS_VOLATILE (x) = C_TYPE_FIELDS_VOLATILE (t);
> +      C_TYPE_VARIABLE_SIZE (x) = C_TYPE_VARIABLE_SIZE (t);
> +      /* We copy these fields too.  */
> +      SET_TYPE_ALIGN (x, TYPE_ALIGN (t));
> +      TYPE_SIZE (x) = TYPE_SIZE (t);
> +      TYPE_SIZE_UNIT (x) = TYPE_SIZE_UNIT (t);
> +      if (x != record_or_union_type)
> +       compute_record_mode (x);
> +    }
> +
> +  return 1;
> +}
> +
> +gcc_type
> +plugin_build_enum_type (cc1_plugin::connection *self,
> +                       gcc_type underlying_int_type_in)
> +{
> +  tree underlying_int_type = convert_in (underlying_int_type_in);
> +
> +  if (underlying_int_type == error_mark_node)
> +    return convert_out (error_mark_node);
> +
> +  tree result = build_anonymous_node (ENUMERAL_TYPE);
> +
> +  TYPE_PRECISION (result) = TYPE_PRECISION (underlying_int_type);
> +  TYPE_UNSIGNED (result) = TYPE_UNSIGNED (underlying_int_type);
> +
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  return convert_out (ctx->preserve (result));
> +}
> +
> +int
> +plugin_build_add_enum_constant (cc1_plugin::connection *,
> +                               gcc_type enum_type_in,
> +                               const char *name,
> +                               unsigned long value)
> +{
> +  tree cst, decl, cons;
> +  tree enum_type = convert_in (enum_type_in);
> +
> +  gcc_assert (TREE_CODE (enum_type) == ENUMERAL_TYPE);
> +
> +  cst = build_int_cst (enum_type, value);
> +  /* Note that gdb does not preserve the location of enum constants,
> +     so we can't provide a decent location here.  */
> +  decl = build_decl (BUILTINS_LOCATION, CONST_DECL,
> +                    get_identifier (name), enum_type);
> +  DECL_INITIAL (decl) = cst;
> +  pushdecl_safe (decl);
> +
> +  cons = tree_cons (DECL_NAME (decl), cst, TYPE_VALUES (enum_type));
> +  TYPE_VALUES (enum_type) = cons;
> +
> +  return 1;
> +}
> +
> +int
> +plugin_finish_enum_type (cc1_plugin::connection *,
> +                        gcc_type enum_type_in)
> +{
> +  tree enum_type = convert_in (enum_type_in);
> +  tree minnode, maxnode, iter;
> +
> +  iter = TYPE_VALUES (enum_type);
> +  minnode = maxnode = TREE_VALUE (iter);
> +  for (iter = TREE_CHAIN (iter);
> +       iter != NULL_TREE;
> +       iter = TREE_CHAIN (iter))
> +    {
> +      tree value = TREE_VALUE (iter);
> +      if (tree_int_cst_lt (maxnode, value))
> +       maxnode = value;
> +      if (tree_int_cst_lt (value, minnode))
> +       minnode = value;
> +    }
> +  TYPE_MIN_VALUE (enum_type) = minnode;
> +  TYPE_MAX_VALUE (enum_type) = maxnode;
> +
> +  layout_type (enum_type);
> +
> +  return 1;
> +}
> +
> +gcc_type
> +plugin_build_function_type (cc1_plugin::connection *self,
> +                           gcc_type return_type_in,
> +                           const struct gcc_type_array *argument_types_in,
> +                           int is_varargs)
> +{
> +  tree *argument_types;
> +  tree return_type = convert_in (return_type_in);
> +  tree result;
> +
> +  argument_types = new tree[argument_types_in->n_elements];
> +  for (int i = 0; i < argument_types_in->n_elements; ++i)
> +    argument_types[i] = convert_in (argument_types_in->elements[i]);
> +
> +  if (is_varargs)
> +    result = build_varargs_function_type_array (return_type,
> +                                               argument_types_in->n_elements,
> +                                               argument_types);
> +  else
> +    result = build_function_type_array (return_type,
> +                                       argument_types_in->n_elements,
> +                                       argument_types);
> +
> +  delete[] argument_types;
> +
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  return convert_out (ctx->preserve (result));
> +}
> +
> +/* Return a builtin type associated with BUILTIN_NAME.  */
> +
> +static tree
> +safe_lookup_builtin_type (const char *builtin_name)
> +{
> +  tree result = NULL_TREE;
> +
> +  if (!builtin_name)
> +    return result;
> +
> +  result = identifier_global_value (get_identifier (builtin_name));
> +
> +  if (!result)
> +    return result;
> +
> +  gcc_assert (TREE_CODE (result) == TYPE_DECL);
> +  result = TREE_TYPE (result);
> +  return result;
> +}
> +
> +static gcc_type
> +plugin_int_check (cc1_plugin::connection *self,
> +                 int is_unsigned, unsigned long size_in_bytes,
> +                 tree result)
> +{
> +  if (result == NULL_TREE)
> +    result = error_mark_node;
> +  else
> +    {
> +      gcc_assert (!TYPE_UNSIGNED (result) == !is_unsigned);
> +      gcc_assert (TREE_CODE (TYPE_SIZE (result)) == INTEGER_CST);
> +      gcc_assert (TYPE_PRECISION (result) == BITS_PER_UNIT * size_in_bytes);
> +
> +      plugin_context *ctx = static_cast<plugin_context *> (self);
> +      ctx->preserve (result);
> +    }
> +  return convert_out (result);
> +}
> +
> +gcc_type
> +plugin_int_type_v0 (cc1_plugin::connection *self,
> +                   int is_unsigned, unsigned long size_in_bytes)
> +{
> +  tree result = c_common_type_for_size (BITS_PER_UNIT * size_in_bytes,
> +                                       is_unsigned);
> +
> +  return plugin_int_check (self, is_unsigned, size_in_bytes, result);
> +}
> +
> +gcc_type
> +plugin_int_type (cc1_plugin::connection *self,
> +                int is_unsigned, unsigned long size_in_bytes,
> +                const char *builtin_name)
> +{
> +  if (!builtin_name)
> +    return plugin_int_type_v0 (self, is_unsigned, size_in_bytes);
> +
> +  tree result = safe_lookup_builtin_type (builtin_name);
> +  gcc_assert (!result || TREE_CODE (result) == INTEGER_TYPE);
> +
> +  return plugin_int_check (self, is_unsigned, size_in_bytes, result);
> +}
> +
> +gcc_type
> +plugin_char_type (cc1_plugin::connection *)
> +{
> +  return convert_out (char_type_node);
> +}
> +
> +gcc_type
> +plugin_float_type_v0 (cc1_plugin::connection *,
> +                  unsigned long size_in_bytes)
> +{
> +  if (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (float_type_node))
> +    return convert_out (float_type_node);
> +  if (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (double_type_node))
> +    return convert_out (double_type_node);
> +  if (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (long_double_type_node))
> +    return convert_out (long_double_type_node);
> +  return convert_out (error_mark_node);
> +}
> +
> +gcc_type
> +plugin_float_type (cc1_plugin::connection *self,
> +                  unsigned long size_in_bytes,
> +                  const char *builtin_name)
> +{
> +  if (!builtin_name)
> +    return plugin_float_type_v0 (self, size_in_bytes);
> +
> +  tree result = safe_lookup_builtin_type (builtin_name);
> +
> +  if (!result)
> +    return convert_out (error_mark_node);
> +
> +  gcc_assert (TREE_CODE (result) == REAL_TYPE);
> +  gcc_assert (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (result));
> +
> +  return convert_out (result);
> +}
> +
> +gcc_type
> +plugin_void_type (cc1_plugin::connection *)
> +{
> +  return convert_out (void_type_node);
> +}
> +
> +gcc_type
> +plugin_bool_type (cc1_plugin::connection *)
> +{
> +  return convert_out (boolean_type_node);
> +}
> +
> +gcc_type
> +plugin_build_array_type (cc1_plugin::connection *self,
> +                        gcc_type element_type_in, int num_elements)
> +{
> +  tree element_type = convert_in (element_type_in);
> +  tree result;
> +
> +  if (num_elements == -1)
> +    result = build_array_type (element_type, NULL_TREE);
> +  else
> +    result = build_array_type_nelts (element_type, num_elements);
> +
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  return convert_out (ctx->preserve (result));
> +}
> +
> +gcc_type
> +plugin_build_vla_array_type (cc1_plugin::connection *self,
> +                            gcc_type element_type_in,
> +                            const char *upper_bound_name)
> +{
> +  tree element_type = convert_in (element_type_in);
> +  tree upper_bound = lookup_name (get_identifier (upper_bound_name));
> +  tree range = build_index_type (upper_bound);
> +
> +  tree result = build_array_type (element_type, range);
> +  C_TYPE_VARIABLE_SIZE (result) = 1;
> +
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  return convert_out (ctx->preserve (result));
> +}
> +
> +gcc_type
> +plugin_build_qualified_type (cc1_plugin::connection *,
> +                            gcc_type unqualified_type_in,
> +                            enum gcc_qualifiers qualifiers)
> +{
> +  tree unqualified_type = convert_in (unqualified_type_in);
> +  int quals = 0;
> +
> +  if ((qualifiers & GCC_QUALIFIER_CONST) != 0)
> +    quals |= TYPE_QUAL_CONST;
> +  if ((qualifiers & GCC_QUALIFIER_VOLATILE) != 0)
> +    quals |= TYPE_QUAL_VOLATILE;
> +  if ((qualifiers & GCC_QUALIFIER_RESTRICT) != 0)
> +    quals |= TYPE_QUAL_RESTRICT;
> +
> +  return convert_out (build_qualified_type (unqualified_type, quals));
> +}
> +
> +gcc_type
> +plugin_build_complex_type (cc1_plugin::connection *self,
> +                          gcc_type base_type)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  return convert_out (ctx->preserve (build_complex_type (convert_in (base_type))));
> +}
> +
> +gcc_type
> +plugin_build_vector_type (cc1_plugin::connection *self,
> +                         gcc_type base_type, int nunits)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  return convert_out (ctx->preserve (build_vector_type (convert_in (base_type),
> +                                                       nunits)));
> +}
> +
> +int
> +plugin_build_constant (cc1_plugin::connection *self, gcc_type type_in,
> +                      const char *name, unsigned long value,
> +                      const char *filename, unsigned int line_number)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree cst, decl;
> +  tree type = convert_in (type_in);
> +
> +  cst = build_int_cst (type, value);
> +  decl = build_decl (ctx->get_source_location (filename, line_number),
> +                    CONST_DECL, get_identifier (name), type);
> +  DECL_INITIAL (decl) = cst;
> +  pushdecl_safe (decl);
> +
> +  return 1;
> +}
> +
> +gcc_type
> +plugin_error (cc1_plugin::connection *,
> +             const char *message)
> +{
> +  error ("%s", message);
> +  return convert_out (error_mark_node);
> +}
> +
> +
> +
> +// Perform GC marking.
> +
> +static void
> +gc_mark (void *, void *)
> +{
> +  if (current_context != NULL)
> +    current_context->mark ();
> +}
> +
> +#ifdef __GNUC__
> +#pragma GCC visibility push(default)
> +#endif
> +
> +int
> +plugin_init (struct plugin_name_args *plugin_info,
> +            struct plugin_gcc_version *)
> +{
> +  long fd = -1;
> +  for (int i = 0; i < plugin_info->argc; ++i)
> +    {
> +      if (strcmp (plugin_info->argv[i].key, "fd") == 0)
> +       {
> +         char *tail;
> +         errno = 0;
> +         fd = strtol (plugin_info->argv[i].value, &tail, 0);
> +         if (*tail != '\0' || errno != 0)
> +           fatal_error (input_location,
> +                        "%s: invalid file descriptor argument to plugin",
> +                        plugin_info->base_name);
> +         break;
> +       }
> +    }
> +  if (fd == -1)
> +    fatal_error (input_location,
> +                "%s: required plugin argument %<fd%> is missing",
> +                plugin_info->base_name);
> +
> +  current_context = new plugin_context (fd);
> +
> +  // Handshake.
> +  cc1_plugin::protocol_int version;
> +  if (!current_context->require ('H')
> +      || ! ::cc1_plugin::unmarshall (current_context, &version))
> +    fatal_error (input_location,
> +                "%s: handshake failed", plugin_info->base_name);
> +  if (version != GCC_C_FE_VERSION_1)
> +    fatal_error (input_location,
> +                "%s: unknown version in handshake", plugin_info->base_name);
> +
> +  register_callback (plugin_info->base_name, PLUGIN_PRAGMAS,
> +                    plugin_init_extra_pragmas, NULL);
> +  register_callback (plugin_info->base_name, PLUGIN_PRE_GENERICIZE,
> +                    rewrite_decls_to_addresses, NULL);
> +  register_callback (plugin_info->base_name, PLUGIN_GGC_MARKING,
> +                    gc_mark, NULL);
> +
> +  lang_hooks.print_error_function = plugin_print_error_function;
> +
> +#define GCC_METHOD0(R, N)                      \
> +  {                                            \
> +    cc1_plugin::callback_ftype *fun            \
> +      = cc1_plugin::callback<R, plugin_ ## N>; \
> +    current_context->add_callback (# N, fun);  \
> +  }
> +#define GCC_METHOD1(R, N, A)                           \
> +  {                                                    \
> +    cc1_plugin::callback_ftype *fun                    \
> +      = cc1_plugin::callback<R, A, plugin_ ## N>;      \
> +    current_context->add_callback (# N, fun);          \
> +  }
> +#define GCC_METHOD2(R, N, A, B)                                \
> +  {                                                    \
> +    cc1_plugin::callback_ftype *fun                    \
> +      = cc1_plugin::callback<R, A, B, plugin_ ## N>;   \
> +    current_context->add_callback (# N, fun);          \
> +  }
> +#define GCC_METHOD3(R, N, A, B, C)                     \
> +  {                                                    \
> +    cc1_plugin::callback_ftype *fun                    \
> +      = cc1_plugin::callback<R, A, B, C, plugin_ ## N>;        \
> +    current_context->add_callback (# N, fun);          \
> +  }
> +#define GCC_METHOD4(R, N, A, B, C, D)          \
> +  {                                            \
> +    cc1_plugin::callback_ftype *fun            \
> +      = cc1_plugin::callback<R, A, B, C, D,    \
> +                            plugin_ ## N>;     \
> +    current_context->add_callback (# N, fun);  \
> +  }
> +#define GCC_METHOD5(R, N, A, B, C, D, E)       \
> +  {                                            \
> +    cc1_plugin::callback_ftype *fun            \
> +      = cc1_plugin::callback<R, A, B, C, D, E, \
> +                            plugin_ ## N>;     \
> +    current_context->add_callback (# N, fun);  \
> +  }
> +#define GCC_METHOD7(R, N, A, B, C, D, E, F, G)         \
> +  {                                                    \
> +    cc1_plugin::callback_ftype *fun                    \
> +      = cc1_plugin::callback<R, A, B, C, D, E, F, G,   \
> +                            plugin_ ## N>;             \
> +    current_context->add_callback (# N, fun);          \
> +  }
> +
> +#include "gcc-c-fe.def"
> +
> +#undef GCC_METHOD0
> +#undef GCC_METHOD1
> +#undef GCC_METHOD2
> +#undef GCC_METHOD3
> +#undef GCC_METHOD4
> +#undef GCC_METHOD5
> +#undef GCC_METHOD7
> +
> +  return 0;
> +}
> diff --git a/libcc1/libcp1.cc b/libcc1/libcp1.cc
> new file mode 100644
> index 0000000..bbd8488
> --- /dev/null
> +++ b/libcc1/libcp1.cc
> @@ -0,0 +1,706 @@
> +/* The library used by gdb.
> +   Copyright (C) 2014-2017 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC 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, or (at your option) any later
> +version.
> +
> +GCC 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 GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#include <cc1plugin-config.h>
> +#include <vector>
> +#include <string>
> +#include <sys/socket.h>
> +#include <sys/types.h>
> +#include <unistd.h>
> +#include <sys/wait.h>
> +#include <stdio.h>
> +#include <errno.h>
> +#include <sys/stat.h>
> +#include <stdlib.h>
> +#include <sstream>
> +#include "marshall-cp.hh"
> +#include "rpc.hh"
> +#include "connection.hh"
> +#include "names.hh"
> +#include "callbacks.hh"
> +#include "libiberty.h"
> +#include "xregex.h"
> +#include "findcomp.hh"
> +#include "cp-compiler-name.h"
> +#include "intl.h"
> +
> +struct libcp1;
> +
> +class libcp1_connection;
> +
> +// The C compiler context that we hand back to our caller.
> +struct libcp1 : public gcc_cp_context
> +{
> +  libcp1 (const gcc_base_vtable *, const gcc_cp_fe_vtable *);
> +  ~libcp1 ();
> +
> +  // A convenience function to print something.
> +  void print (const char *str)
> +  {
> +    this->print_function (this->print_datum, str);
> +  }
> +
> +  libcp1_connection *connection;
> +
> +  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 *oracle_datum;
> +
> +  void (*print_function) (void *datum, const char *message);
> +  void *print_datum;
> +
> +  std::vector<std::string> args;
> +  std::string source_file;
> +
> +  /* Non-zero as an equivalent to gcc driver option "-v".  */
> +  bool verbose;
> +
> +  /* Compiler to set by set_triplet_regexp or set_driver_filename.  */
> +  class compiler
> +  {
> +  protected:
> +    libcp1 *self_;
> +  public:
> +    compiler (libcp1 *self) : self_ (self)
> +    {
> +    }
> +    virtual char *find (std::string &compiler) const;
> +    virtual ~compiler ()
> +    {
> +    }
> +  } *compilerp;
> +
> +  /* Compiler to set by set_triplet_regexp.  */
> +  class compiler_triplet_regexp : public compiler
> +  {
> +  private:
> +    std::string triplet_regexp_;
> +  public:
> +    virtual char *find (std::string &compiler) const;
> +    compiler_triplet_regexp (libcp1 *self, std::string triplet_regexp)
> +      : compiler (self), triplet_regexp_ (triplet_regexp)
> +    {
> +    }
> +    virtual ~compiler_triplet_regexp ()
> +    {
> +    }
> +  };
> +
> +  /* Compiler to set by set_driver_filename.  */
> +  class compiler_driver_filename : public compiler
> +  {
> +  private:
> +    std::string driver_filename_;
> +  public:
> +    virtual char *find (std::string &compiler) const;
> +    compiler_driver_filename (libcp1 *self, std::string driver_filename)
> +      : compiler (self), driver_filename_ (driver_filename)
> +    {
> +    }
> +    virtual ~compiler_driver_filename ()
> +    {
> +    }
> +  };
> +};
> +
> +// A local subclass of connection that holds a back-pointer to the
> +// gcc_c_context object that we provide to our caller.
> +class libcp1_connection : public cc1_plugin::connection
> +{
> +public:
> +
> +  libcp1_connection (int fd, int aux_fd, libcp1 *b)
> +    : connection (fd, aux_fd),
> +      back_ptr (b)
> +  {
> +  }
> +
> +  virtual void print (const char *buf)
> +  {
> +    back_ptr->print (buf);
> +  }
> +
> +  libcp1 *back_ptr;
> +};
> +
> +libcp1::libcp1 (const gcc_base_vtable *v,
> +                 const gcc_cp_fe_vtable *cv)
> +  : connection (NULL),
> +    binding_oracle (NULL),
> +    address_oracle (NULL),
> +    oracle_datum (NULL),
> +    print_function (NULL),
> +    print_datum (NULL),
> +    args (),
> +    source_file (),
> +    verbose (false),
> +    compilerp (new libcp1::compiler (this))
> +{
> +  base.ops = v;
> +  cp_ops = cv;
> +}
> +
> +libcp1::~libcp1 ()
> +{
> +  delete connection;
> +  delete compilerp;
> +}
> +
> +
> +
> +// Enclose these functions in an anonymous namespace because they
> +// shouldn't be exported, but they can't be static because they're
> +// used as template arguments.
> +namespace {
> +  // This is a wrapper function that is called by the RPC system and
> +  // that then forwards the call to the library user.  Note that the
> +  // return value is not used; the type cannot be 'void' due to
> +  // limitations in our simple RPC.
> +  int
> +  cp_call_binding_oracle (cc1_plugin::connection *conn,
> +                      enum gcc_cp_oracle_request request,
> +                      const char *identifier)
> +  {
> +    libcp1 *self = ((libcp1_connection *) conn)->back_ptr;
> +
> +    self->binding_oracle (self->oracle_datum, self, request, identifier);
> +    return 1;
> +  }
> +
> +  // This is a wrapper function that is called by the RPC system and
> +  // that then forwards the call to the library user.
> +  gcc_address
> +  cp_call_symbol_address (cc1_plugin::connection *conn, const char *identifier)
> +  {
> +    libcp1 *self = ((libcp1_connection *) conn)->back_ptr;
> +
> +    return self->address_oracle (self->oracle_datum, self, identifier);
> +  }
> +
> +  int
> +  cp_call_enter_scope (cc1_plugin::connection *conn)
> +  {
> +    libcp1 *self = ((libcp1_connection *) conn)->back_ptr;
> +
> +    self->enter_scope (self->oracle_datum, self);
> +    return 1;
> +  }
> +
> +  int
> +  cp_call_leave_scope (cc1_plugin::connection *conn)
> +  {
> +    libcp1 *self = ((libcp1_connection *) conn)->back_ptr;
> +
> +    self->leave_scope (self->oracle_datum, self);
> +    return 1;
> +  }
> +} /* anonymous namespace */
> +
> +
> +
> +static void
> +set_callbacks (struct gcc_cp_context *s,
> +              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)
> +{
> +  libcp1 *self = (libcp1 *) s;
> +
> +  self->binding_oracle = binding_oracle;
> +  self->address_oracle = address_oracle;
> +  self->enter_scope = enter_scope;
> +  self->leave_scope = leave_scope;
> +  self->oracle_datum = datum;
> +}
> +
> +// Instances of these rpc<> template functions are installed into the
> +// "cp_vtable".  These functions are parameterized by type and method
> +// name and forward the call via the connection.
> +
> +template<typename R, const char *&NAME>
> +R rpc (struct gcc_cp_context *s)
> +{
> +  libcp1 *self = (libcp1 *) s;
> +  R result;
> +
> +  if (!cc1_plugin::call (self->connection, NAME, &result))
> +    return 0;
> +  return result;
> +}
> +
> +template<typename R, const char *&NAME, typename A>
> +R rpc (struct gcc_cp_context *s, A arg)
> +{
> +  libcp1 *self = (libcp1 *) s;
> +  R result;
> +
> +  if (!cc1_plugin::call (self->connection, NAME, &result, arg))
> +    return 0;
> +  return result;
> +}
> +
> +template<typename R, const char *&NAME, typename A1, typename A2>
> +R rpc (struct gcc_cp_context *s, A1 arg1, A2 arg2)
> +{
> +  libcp1 *self = (libcp1 *) s;
> +  R result;
> +
> +  if (!cc1_plugin::call (self->connection, NAME, &result, arg1, arg2))
> +    return 0;
> +  return result;
> +}
> +
> +template<typename R, const char *&NAME, typename A1, typename A2, typename A3>
> +R rpc (struct gcc_cp_context *s, A1 arg1, A2 arg2, A3 arg3)
> +{
> +  libcp1 *self = (libcp1 *) s;
> +  R result;
> +
> +  if (!cc1_plugin::call (self->connection, NAME, &result, arg1, arg2, arg3))
> +    return 0;
> +  return result;
> +}
> +
> +template<typename R, const char *&NAME, typename A1, typename A2, typename A3,
> +        typename A4>
> +R rpc (struct gcc_cp_context *s, A1 arg1, A2 arg2, A3 arg3, A4 arg4)
> +{
> +  libcp1 *self = (libcp1 *) s;
> +  R result;
> +
> +  if (!cc1_plugin::call (self->connection, NAME, &result, arg1, arg2, arg3,
> +                        arg4))
> +    return 0;
> +  return result;
> +}
> +
> +template<typename R, const char *&NAME, typename A1, typename A2, typename A3,
> +        typename A4, typename A5>
> +R rpc (struct gcc_cp_context *s, A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5)
> +{
> +  libcp1 *self = (libcp1 *) s;
> +  R result;
> +
> +  if (!cc1_plugin::call (self->connection, NAME, &result, arg1, arg2, arg3,
> +                        arg4, arg5))
> +    return 0;
> +  return result;
> +}
> +
> +template<typename R, const char *&NAME, typename A1, typename A2, typename A3,
> +        typename A4, typename A5, typename A6, typename A7>
> +R rpc (struct gcc_cp_context *s, A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5,
> +       A6 arg6, A7 arg7)
> +{
> +  libcp1 *self = (libcp1 *) s;
> +  R result;
> +
> +  if (!cc1_plugin::call (self->connection, NAME, &result, arg1, arg2, arg3,
> +                        arg4, arg5, arg6, arg7))
> +    return 0;
> +  return result;
> +}
> +
> +static const struct gcc_cp_fe_vtable cp_vtable =
> +{
> +  GCC_CP_FE_VERSION_0,
> +  set_callbacks,
> +
> +#define GCC_METHOD0(R, N) \
> +  rpc<R, cc1_plugin::cp::N>,
> +#define GCC_METHOD1(R, N, A) \
> +  rpc<R, cc1_plugin::cp::N, A>,
> +#define GCC_METHOD2(R, N, A, B) \
> +  rpc<R, cc1_plugin::cp::N, A, B>,
> +#define GCC_METHOD3(R, N, A, B, C) \
> +  rpc<R, cc1_plugin::cp::N, A, B, C>,
> +#define GCC_METHOD4(R, N, A, B, C, D) \
> +  rpc<R, cc1_plugin::cp::N, A, B, C, D>,
> +#define GCC_METHOD5(R, N, A, B, C, D, E) \
> +  rpc<R, cc1_plugin::cp::N, A, B, C, D, E>,
> +#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \
> +  rpc<R, cc1_plugin::cp::N, A, B, C, D, E, F, G>,
> +
> +#include "gcc-cp-fe.def"
> +
> +#undef GCC_METHOD0
> +#undef GCC_METHOD1
> +#undef GCC_METHOD2
> +#undef GCC_METHOD3
> +#undef GCC_METHOD4
> +#undef GCC_METHOD5
> +#undef GCC_METHOD7
> +};
> +
> +
> +
> +// Construct an appropriate regexp to match the compiler name.
> +static std::string
> +make_regexp (const char *triplet_regexp, const char *compiler)
> +{
> +  std::stringstream buf;
> +
> +  buf << "^" << triplet_regexp << "-";
> +
> +  // Quote the compiler name in case it has something funny in it.
> +  for (const char *p = compiler; *p; ++p)
> +    {
> +      switch (*p)
> +       {
> +       case '.':
> +       case '^':
> +       case '$':
> +       case '*':
> +       case '+':
> +       case '?':
> +       case '(':
> +       case ')':
> +       case '[':
> +       case '{':
> +       case '\\':
> +       case '|':
> +         buf << '\\';
> +         break;
> +       }
> +      buf << *p;
> +    }
> +  buf << "$";
> +
> +  return buf.str ();
> +}
> +
> +static void
> +libcp1_set_verbose (struct gcc_base_context *s, int /* bool */ verbose)
> +{
> +  libcp1 *self = (libcp1 *) s;
> +
> +  self->verbose = verbose != 0;
> +}
> +
> +char *
> +libcp1::compiler::find (std::string &compiler ATTRIBUTE_UNUSED) const
> +{
> +  return xstrdup (_("Compiler has not been specified"));
> +}
> +
> +char *
> +libcp1::compiler_triplet_regexp::find (std::string &compiler) const
> +{
> +  std::string rx = make_regexp (triplet_regexp_.c_str (), CP_COMPILER_NAME);
> +  if (self_->verbose)
> +    fprintf (stderr, _("searching for compiler matching regex %s\n"),
> +            rx.c_str());
> +  regex_t triplet;
> +  int code = regcomp (&triplet, rx.c_str (), REG_EXTENDED | REG_NOSUB);
> +  if (code != 0)
> +    {
> +      size_t len = regerror (code, &triplet, NULL, 0);
> +      char err[len];
> +
> +      regerror (code, &triplet, err, len);
> +
> +      return concat ("Could not compile regexp \"",
> +                    rx.c_str (),
> +                    "\": ",
> +                    err,
> +                    (char *) NULL);
> +    }
> +
> +  if (!find_compiler (triplet, &compiler))
> +    {
> +      regfree (&triplet);
> +      return concat ("Could not find a compiler matching \"",
> +                    rx.c_str (),
> +                    "\"",
> +                    (char *) NULL);
> +    }
> +  regfree (&triplet);
> +  if (self_->verbose)
> +    fprintf (stderr, _("found compiler %s\n"), compiler.c_str());
> +  return NULL;
> +}
> +
> +char *
> +libcp1::compiler_driver_filename::find (std::string &compiler) const
> +{
> +  // Simulate fnotice by fprintf.
> +  if (self_->verbose)
> +    fprintf (stderr, _("using explicit compiler filename %s\n"),
> +            driver_filename_.c_str());
> +  compiler = driver_filename_;
> +  return NULL;
> +}
> +
> +static char *
> +libcp1_set_arguments (struct gcc_base_context *s,
> +                     int argc, char **argv)
> +{
> +  libcp1 *self = (libcp1 *) s;
> +
> +  std::string compiler;
> +  char *errmsg = self->compilerp->find (compiler);
> +  if (errmsg != NULL)
> +    return errmsg;
> +
> +  self->args.push_back (compiler);
> +
> +  for (int i = 0; i < argc; ++i)
> +    self->args.push_back (argv[i]);
> +
> +  return NULL;
> +}
> +
> +static char *
> +libcp1_set_triplet_regexp (struct gcc_base_context *s,
> +                          const char *triplet_regexp)
> +{
> +  libcp1 *self = (libcp1 *) s;
> +
> +  delete self->compilerp;
> +  self->compilerp = new libcp1::compiler_triplet_regexp (self, triplet_regexp);
> +  return NULL;
> +}
> +
> +static char *
> +libcp1_set_driver_filename (struct gcc_base_context *s,
> +                           const char *driver_filename)
> +{
> +  libcp1 *self = (libcp1 *) s;
> +
> +  delete self->compilerp;
> +  self->compilerp = new libcp1::compiler_driver_filename (self,
> +                                                         driver_filename);
> +  return NULL;
> +}
> +
> +static char *
> +libcp1_set_arguments_v0 (struct gcc_base_context *s,
> +                        const char *triplet_regexp,
> +                        int argc, char **argv)
> +{
> +  char *errmsg = libcp1_set_triplet_regexp (s, triplet_regexp);
> +  if (errmsg != NULL)
> +    return errmsg;
> +
> +  return libcp1_set_arguments (s, argc, argv);
> +}
> +
> +static void
> +libcp1_set_source_file (struct gcc_base_context *s,
> +                        const char *file)
> +{
> +  libcp1 *self = (libcp1 *) s;
> +
> +  self->source_file = file;
> +}
> +
> +static void
> +libcp1_set_print_callback (struct gcc_base_context *s,
> +                           void (*print_function) (void *datum,
> +                                                   const char *message),
> +                           void *datum)
> +{
> +  libcp1 *self = (libcp1 *) s;
> +
> +  self->print_function = print_function;
> +  self->print_datum = datum;
> +}
> +
> +static int
> +fork_exec (libcp1 *self, char **argv, int spair_fds[2], int stderr_fds[2])
> +{
> +  pid_t child_pid = fork ();
> +
> +  if (child_pid == -1)
> +    {
> +      close (spair_fds[0]);
> +      close (spair_fds[1]);
> +      close (stderr_fds[0]);
> +      close (stderr_fds[1]);
> +      return 0;
> +    }
> +
> +  if (child_pid == 0)
> +    {
> +      // Child.
> +      dup2 (stderr_fds[1], 1);
> +      dup2 (stderr_fds[1], 2);
> +      close (stderr_fds[0]);
> +      close (stderr_fds[1]);
> +      close (spair_fds[0]);
> +
> +      execvp (argv[0], argv);
> +      _exit (127);
> +    }
> +  else
> +    {
> +      // Parent.
> +      close (spair_fds[1]);
> +      close (stderr_fds[1]);
> +
> +      cc1_plugin::status result = cc1_plugin::FAIL;
> +      if (self->connection->send ('H')
> +         && ::cc1_plugin::marshall (self->connection, GCC_CP_FE_VERSION_0))
> +       result = self->connection->wait_for_query ();
> +
> +      close (spair_fds[0]);
> +      close (stderr_fds[0]);
> +
> +      while (true)
> +       {
> +         int status;
> +
> +         if (waitpid (child_pid, &status, 0) == -1)
> +           {
> +             if (errno != EINTR)
> +               return 0;
> +           }
> +
> +         if (!WIFEXITED (status) || WEXITSTATUS (status) != 0)
> +           return 0;
> +         break;
> +       }
> +
> +      if (!result)
> +       return 0;
> +      return 1;
> +    }
> +}
> +
> +static int
> +libcp1_compile (struct gcc_base_context *s,
> +               const char *filename)
> +{
> +  libcp1 *self = (libcp1 *) s;
> +
> +  int fds[2];
> +  if (socketpair (AF_UNIX, SOCK_STREAM, 0, fds) != 0)
> +    {
> +      self->print ("could not create socketpair\n");
> +      return 0;
> +    }
> +
> +  int stderr_fds[2];
> +  if (pipe (stderr_fds) != 0)
> +    {
> +      self->print ("could not create pipe\n");
> +      close (fds[0]);
> +      close (fds[1]);
> +      return 0;
> +    }
> +
> +  self->args.push_back ("-fplugin=libcp1plugin");
> +  char buf[100];
> +  if (snprintf (buf, sizeof (buf), "-fplugin-arg-libcp1plugin-fd=%d", fds[1])
> +      >= (long) sizeof (buf))
> +    abort ();
> +  self->args.push_back (buf);
> +
> +  self->args.push_back (self->source_file);
> +  self->args.push_back ("-c");
> +  self->args.push_back ("-o");
> +  self->args.push_back (filename);
> +  if (self->verbose)
> +    self->args.push_back ("-v");
> +
> +  self->connection = new libcp1_connection (fds[0], stderr_fds[0], self);
> +
> +  cc1_plugin::callback_ftype *fun
> +    = cc1_plugin::callback<int,
> +                          enum gcc_cp_oracle_request,
> +                          const char *,
> +                          cp_call_binding_oracle>;
> +  self->connection->add_callback ("binding_oracle", fun);
> +
> +  fun = cc1_plugin::callback<gcc_address,
> +                            const char *,
> +                            cp_call_symbol_address>;
> +  self->connection->add_callback ("address_oracle", fun);
> +
> +  fun = cc1_plugin::callback<int,
> +                            cp_call_enter_scope>;
> +  self->connection->add_callback ("enter_scope", fun);
> +
> +  fun = cc1_plugin::callback<int,
> +                            cp_call_leave_scope>;
> +  self->connection->add_callback ("leave_scope", fun);
> +
> +  char **argv = new (std::nothrow) char *[self->args.size () + 1];
> +  if (argv == NULL)
> +    return 0;
> +
> +  for (unsigned int i = 0; i < self->args.size (); ++i)
> +    argv[i] = const_cast<char *> (self->args[i].c_str ());
> +  argv[self->args.size ()] = NULL;
> +
> +  return fork_exec (self, argv, fds, stderr_fds);
> +}
> +
> +static int
> +libcp1_compile_v0 (struct gcc_base_context *s, const char *filename,
> +                  int verbose)
> +{
> +  libcp1_set_verbose (s, verbose);
> +  return libcp1_compile (s, filename);
> +}
> +
> +static void
> +libcp1_destroy (struct gcc_base_context *s)
> +{
> +  libcp1 *self = (libcp1 *) s;
> +
> +  delete self;
> +}
> +
> +static const struct gcc_base_vtable vtable =
> +{
> +  GCC_FE_VERSION_0,
> +  libcp1_set_arguments_v0,
> +  libcp1_set_source_file,
> +  libcp1_set_print_callback,
> +  libcp1_compile_v0,
> +  libcp1_destroy,
> +  libcp1_set_verbose,
> +  libcp1_compile,
> +  libcp1_set_arguments,
> +  libcp1_set_triplet_regexp,
> +  libcp1_set_driver_filename,
> +};
> +
> +extern "C" gcc_cp_fe_context_function gcc_cp_fe_context;
> +
> +#ifdef __GNUC__
> +#pragma GCC visibility push(default)
> +#endif
> +
> +extern "C"
> +struct gcc_cp_context *
> +gcc_cp_fe_context (enum gcc_base_api_version base_version,
> +                   enum gcc_cp_api_version cp_version)
> +{
> +  if ((base_version != GCC_FE_VERSION_0 && base_version != GCC_FE_VERSION_1)
> +      || cp_version != GCC_CP_FE_VERSION_0)
> +    return NULL;
> +
> +  return new libcp1 (&vtable, &cp_vtable);
> +}
> diff --git a/libcc1/libcp1plugin.cc b/libcc1/libcp1plugin.cc
> new file mode 100644
> index 0000000..545f28b9
> --- /dev/null
> +++ b/libcc1/libcp1plugin.cc
> @@ -0,0 +1,3789 @@
> +/* Library interface to C++ front end.
> +   Copyright (C) 2014-2017 Free Software Foundation, Inc.
> +
> +   This file is part of GCC.  As it interacts with GDB through libcc1,
> +   they all become a single program as regards the GNU GPL's requirements.
> +
> +   GCC 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, or (at your option) any later
> +   version.
> +
> +   GCC 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 GCC; see the file COPYING3.  If not see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include <cc1plugin-config.h>
> +
> +#undef PACKAGE_NAME
> +#undef PACKAGE_STRING
> +#undef PACKAGE_TARNAME
> +#undef PACKAGE_VERSION
> +
> +#include "../gcc/config.h"
> +
> +#undef PACKAGE_NAME
> +#undef PACKAGE_STRING
> +#undef PACKAGE_TARNAME
> +#undef PACKAGE_VERSION
> +
> +#include "gcc-plugin.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "stringpool.h"
> +
> +#include "gcc-interface.h"
> +#include "hash-set.h"
> +#include "machmode.h"
> +#include "vec.h"
> +#include "double-int.h"
> +#include "input.h"
> +#include "alias.h"
> +#include "symtab.h"
> +#include "options.h"
> +#include "wide-int.h"
> +#include "inchash.h"
> +#include "tree.h"
> +#include "fold-const.h"
> +#include "stor-layout.h"
> +#include "cp-tree.h"
> +#include "toplev.h"
> +#include "timevar.h"
> +#include "hash-table.h"
> +#include "tm.h"
> +#include "c-family/c-pragma.h"
> +// #include "c-lang.h"
> +#include "diagnostic.h"
> +#include "langhooks.h"
> +#include "langhooks-def.h"
> +#include "decl.h"
> +#include "function.h"
> +#undef cfun // we want to assign to it, and function.h won't let us
> +
> +#include "callbacks.hh"
> +#include "connection.hh"
> +#include "marshall-cp.hh"
> +#include "rpc.hh"
> +
> +#ifdef __GNUC__
> +#pragma GCC visibility push(default)
> +#endif
> +int plugin_is_GPL_compatible;
> +#ifdef __GNUC__
> +#pragma GCC visibility pop
> +#endif
> +
> +
> +
> +static int ATTRIBUTE_UNUSED
> +check_symbol_mask[GCC_CP_SYMBOL_MASK >= GCC_CP_SYMBOL_END ? 1 : -1];
> +
> +// This is put into the lang hooks when the plugin starts.
> +
> +static void
> +plugin_print_error_function (diagnostic_context *context, const char *file,
> +                            diagnostic_info *diagnostic)
> +{
> +  if (current_function_decl != NULL_TREE
> +      && DECL_NAME (current_function_decl) != NULL_TREE
> +      && strcmp (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),
> +                GCC_FE_WRAPPER_FUNCTION) == 0)
> +    return;
> +  lhd_print_error_function (context, file, diagnostic);
> +}
> +
> +
> +
> +static unsigned long long
> +convert_out (tree t)
> +{
> +  return (unsigned long long) (uintptr_t) t;
> +}
> +
> +static tree
> +convert_in (unsigned long long v)
> +{
> +  return (tree) (uintptr_t) v;
> +}
> +
> +
> +
> +struct decl_addr_value
> +{
> +  tree decl;
> +  tree address;
> +};
> +
> +struct decl_addr_hasher : free_ptr_hash<decl_addr_value>
> +{
> +  static inline hashval_t hash (const decl_addr_value *);
> +  static inline bool equal (const decl_addr_value *, const decl_addr_value *);
> +};
> +
> +inline hashval_t
> +decl_addr_hasher::hash (const decl_addr_value *e)
> +{
> +  return DECL_UID (e->decl);
> +}
> +
> +inline bool
> +decl_addr_hasher::equal (const decl_addr_value *p1, const decl_addr_value *p2)
> +{
> +  return p1->decl == p2->decl;
> +}
> +
> +
> +
> +struct string_hasher : nofree_ptr_hash<const char>
> +{
> +  static inline hashval_t hash (const char *s)
> +  {
> +    return htab_hash_string (s);
> +  }
> +
> +  static inline bool equal (const char *p1, const char *p2)
> +  {
> +    return strcmp (p1, p2) == 0;
> +  }
> +};
> +
> +
> +
> +struct plugin_context : public cc1_plugin::connection
> +{
> +  plugin_context (int fd);
> +
> +  // Map decls to addresses.
> +  hash_table<decl_addr_hasher> address_map;
> +
> +  // A collection of trees that are preserved for the GC.
> +  hash_table< nofree_ptr_hash<tree_node> > preserved;
> +
> +  // File name cache.
> +  hash_table<string_hasher> file_names;
> +
> +  // Perform GC marking.
> +  void mark ();
> +
> +  // Preserve a tree during the plugin's operation.
> +  tree preserve (tree t)
> +  {
> +    tree_node **slot = preserved.find_slot (t, INSERT);
> +    *slot = t;
> +    return t;
> +  }
> +
> +  source_location get_source_location (const char *filename,
> +                                      unsigned int line_number)
> +  {
> +    if (filename == NULL)
> +      return UNKNOWN_LOCATION;
> +
> +    filename = intern_filename (filename);
> +    linemap_add (line_table, LC_ENTER, false, filename, line_number);
> +    source_location loc = linemap_line_start (line_table, line_number, 0);
> +    linemap_add (line_table, LC_LEAVE, false, NULL, 0);
> +    return loc;
> +  }
> +
> +private:
> +
> +  // Add a file name to FILE_NAMES and return the canonical copy.
> +  const char *intern_filename (const char *filename)
> +  {
> +    const char **slot = file_names.find_slot (filename, INSERT);
> +    if (*slot == NULL)
> +      {
> +       /* The file name must live as long as the line map, which
> +          effectively means as long as this compilation.  So, we copy
> +          the string here but never free it.  */
> +       *slot = xstrdup (filename);
> +      }
> +    return *slot;
> +  }
> +};
> +
> +static plugin_context *current_context;
> +
> +
> +
> +plugin_context::plugin_context (int fd)
> +  : cc1_plugin::connection (fd),
> +    address_map (30),
> +    preserved (30),
> +    file_names (30)
> +{
> +}
> +
> +void
> +plugin_context::mark ()
> +{
> +  for (hash_table<decl_addr_hasher>::iterator it = address_map.begin ();
> +       it != address_map.end ();
> +       ++it)
> +    {
> +      ggc_mark ((*it)->decl);
> +      ggc_mark ((*it)->address);
> +    }
> +
> +  for (hash_table< nofree_ptr_hash<tree_node> >::iterator
> +        it = preserved.begin (); it != preserved.end (); ++it)
> +    ggc_mark (&*it);
> +}
> +
> +static void
> +plugin_binding_oracle (enum cp_oracle_request kind, tree identifier)
> +{
> +  enum gcc_cp_oracle_request request;
> +
> +  gcc_assert (current_context != NULL);
> +
> +  switch (kind)
> +    {
> +    case CP_ORACLE_IDENTIFIER:
> +      request = GCC_CP_ORACLE_IDENTIFIER;
> +      break;
> +    default:
> +      abort ();
> +    }
> +
> +  int ignore;
> +  cc1_plugin::call (current_context, "binding_oracle", &ignore,
> +                   request, IDENTIFIER_POINTER (identifier));
> +}
> +
> +static int push_count;
> +
> +/* at_function_scope_p () tests cfun, indicating we're actually
> +   compiling the function, but we don't even set it when pretending to
> +   enter a function scope.  We use this distinction to tell these two
> +   cases apart: we don't want to define e.g. class names in the user
> +   expression function's scope, when they're local to the original
> +   function, because they'd get the wrong linkage name.  */
> +
> +static bool
> +at_fake_function_scope_p ()
> +{
> +  return (!cfun || cfun->decl != current_function_decl)
> +    && current_scope () == current_function_decl;
> +}
> +
> +static void
> +push_fake_function (tree fndecl, scope_kind kind = sk_function_parms)
> +{
> +  current_function_decl = fndecl;
> +  begin_scope (kind, fndecl);
> +  ++function_depth;
> +  begin_scope (sk_block, NULL);
> +}
> +
> +static void
> +pop_scope ()
> +{
> +  if (toplevel_bindings_p () && current_namespace == global_namespace)
> +    pop_from_top_level ();
> +  else if (at_namespace_scope_p ())
> +    pop_namespace ();
> +  else if (at_class_scope_p ())
> +    popclass ();
> +  else
> +    {
> +      gcc_assert (at_fake_function_scope_p ());
> +      gcc_assert (!at_function_scope_p ());
> +      gcc_assert (current_binding_level->kind == sk_block
> +                 && current_binding_level->this_entity == NULL);
> +      leave_scope ();
> +      --function_depth;
> +      gcc_assert (current_binding_level->this_entity
> +                 == current_function_decl);
> +      leave_scope ();
> +      current_function_decl = NULL;
> +      for (cp_binding_level *scope = current_binding_level;
> +          scope; scope = scope->level_chain)
> +       if (scope->kind == sk_function_parms)
> +         {
> +           current_function_decl = scope->this_entity;
> +           break;
> +         }
> +    }
> +}
> +
> +static void
> +supplement_binding (cxx_binding *binding, tree decl)
> +{
> +  /* FIXME: this is pretty much a copy of supplement_binding_1 in
> +     ../gcc/cp/name-lookup.c; the few replaced/removed bits are marked
> +     with "// _1:".  */
> +  tree bval = binding->value;
> +  bool ok = true;
> +  tree target_bval = strip_using_decl (bval);
> +  tree target_decl = strip_using_decl (decl);
> +
> +  if (TREE_CODE (target_decl) == TYPE_DECL && DECL_ARTIFICIAL (target_decl)
> +      && target_decl != target_bval
> +      && (TREE_CODE (target_bval) != TYPE_DECL
> +         /* We allow pushing an enum multiple times in a class
> +            template in order to handle late matching of underlying
> +            type on an opaque-enum-declaration followed by an
> +            enum-specifier.  */
> +         || (processing_template_decl
> +             && TREE_CODE (TREE_TYPE (target_decl)) == ENUMERAL_TYPE
> +             && TREE_CODE (TREE_TYPE (target_bval)) == ENUMERAL_TYPE
> +             && (dependent_type_p (ENUM_UNDERLYING_TYPE
> +                                   (TREE_TYPE (target_decl)))
> +                 || dependent_type_p (ENUM_UNDERLYING_TYPE
> +                                      (TREE_TYPE (target_bval)))))))
> +    /* The new name is the type name.  */
> +    binding->type = decl;
> +  else if (/* TARGET_BVAL is null when push_class_level_binding moves
> +             an inherited type-binding out of the way to make room
> +             for a new value binding.  */
> +          !target_bval
> +          /* TARGET_BVAL is error_mark_node when TARGET_DECL's name
> +             has been used in a non-class scope prior declaration.
> +             In that case, we should have already issued a
> +             diagnostic; for graceful error recovery purpose, pretend
> +             this was the intended declaration for that name.  */
> +          || target_bval == error_mark_node
> +          /* If TARGET_BVAL is anticipated but has not yet been
> +             declared, pretend it is not there at all.  */
> +          || (TREE_CODE (target_bval) == FUNCTION_DECL
> +              && DECL_ANTICIPATED (target_bval)
> +              && !DECL_HIDDEN_FRIEND_P (target_bval)))
> +    binding->value = decl;
> +  else if (TREE_CODE (target_bval) == TYPE_DECL
> +          && DECL_ARTIFICIAL (target_bval)
> +          && target_decl != target_bval
> +          && (TREE_CODE (target_decl) != TYPE_DECL
> +              || same_type_p (TREE_TYPE (target_decl),
> +                              TREE_TYPE (target_bval))))
> +    {
> +      /* The old binding was a type name.  It was placed in
> +        VALUE field because it was thought, at the point it was
> +        declared, to be the only entity with such a name.  Move the
> +        type name into the type slot; it is now hidden by the new
> +        binding.  */
> +      binding->type = bval;
> +      binding->value = decl;
> +      binding->value_is_inherited = false;
> +    }
> +  else if (TREE_CODE (target_bval) == TYPE_DECL
> +          && TREE_CODE (target_decl) == TYPE_DECL
> +          && DECL_NAME (target_decl) == DECL_NAME (target_bval)
> +          && binding->scope->kind != sk_class
> +          && (same_type_p (TREE_TYPE (target_decl), TREE_TYPE (target_bval))
> +              /* If either type involves template parameters, we must
> +                 wait until instantiation.  */
> +              || uses_template_parms (TREE_TYPE (target_decl))
> +              || uses_template_parms (TREE_TYPE (target_bval))))
> +    /* We have two typedef-names, both naming the same type to have
> +       the same name.  In general, this is OK because of:
> +
> +        [dcl.typedef]
> +
> +        In a given scope, a typedef specifier can be used to redefine
> +        the name of any type declared in that scope to refer to the
> +        type to which it already refers.
> +
> +       However, in class scopes, this rule does not apply due to the
> +       stricter language in [class.mem] prohibiting redeclarations of
> +       members.  */
> +    ok = false;
> +  /* There can be two block-scope declarations of the same variable,
> +     so long as they are `extern' declarations.  However, there cannot
> +     be two declarations of the same static data member:
> +
> +       [class.mem]
> +
> +       A member shall not be declared twice in the
> +       member-specification.  */
> +  else if (VAR_P (target_decl)
> +          && VAR_P (target_bval)
> +          && DECL_EXTERNAL (target_decl) && DECL_EXTERNAL (target_bval)
> +          && !DECL_CLASS_SCOPE_P (target_decl))
> +    {
> +      duplicate_decls (decl, binding->value, /*newdecl_is_friend=*/false);
> +      ok = false;
> +    }
> +  else if (TREE_CODE (decl) == NAMESPACE_DECL
> +          && TREE_CODE (bval) == NAMESPACE_DECL
> +          && DECL_NAMESPACE_ALIAS (decl)
> +          && DECL_NAMESPACE_ALIAS (bval)
> +          && ORIGINAL_NAMESPACE (bval) == ORIGINAL_NAMESPACE (decl))
> +    /* [namespace.alias]
> +
> +      In a declarative region, a namespace-alias-definition can be
> +      used to redefine a namespace-alias declared in that declarative
> +      region to refer only to the namespace to which it already
> +      refers.  */
> +    ok = false;
> +  else if (maybe_remove_implicit_alias (bval))
> +    {
> +      /* There was a mangling compatibility alias using this mangled name,
> +        but now we have a real decl that wants to use it instead.  */
> +      binding->value = decl;
> +    }
> +  else
> +    {
> +      // _1: diagnose_name_conflict (decl, bval);
> +      ok = false;
> +    }
> +
> +  gcc_assert (ok); // _1: return ok;
> +}
> +
> +static void
> +reactivate_decl (tree decl, cp_binding_level *b)
> +{
> +  bool in_function_p = TREE_CODE (b->this_entity) == FUNCTION_DECL;
> +  gcc_assert (in_function_p
> +             || (b == current_binding_level
> +                 && !at_class_scope_p ()));
> +
> +  tree id = DECL_NAME (decl);
> +  tree type = NULL_TREE;
> +  if (TREE_CODE (decl) == TYPE_DECL)
> +    type = TREE_TYPE (decl);
> +
> +  if (type && TYPE_NAME (type) == decl
> +      && (RECORD_OR_UNION_CODE_P (TREE_CODE (type))
> +         || TREE_CODE (type) == ENUMERAL_TYPE))
> +    {
> +      gcc_assert (in_function_p && DECL_CONTEXT (decl) == b->this_entity);
> +      type = TREE_TYPE (decl);
> +    }
> +  else
> +    {
> +      gcc_assert (DECL_CONTEXT (decl) == b->this_entity
> +                 || DECL_CONTEXT (decl) == global_namespace
> +                 || TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL);
> +      type = NULL_TREE;
> +    }
> +
> +  /* Adjust IDENTIFIER_BINDING to what it would have been if we were
> +     at binding level B.  Save the binding chain up to that point in
> +     [binding, *chainp), and take note of the outermost bindings found
> +     before B.  */
> +  cxx_binding *binding = IDENTIFIER_BINDING (id), **chainp = NULL;
> +  tree *shadowing_type_p = NULL;
> +  if (binding)
> +    {
> +      cp_binding_level *bc = current_binding_level;
> +      for (cxx_binding *prev_binding = binding;
> +          prev_binding; prev_binding = prev_binding->previous)
> +       {
> +         while (bc != b && bc != prev_binding->scope)
> +           bc = bc->level_chain;
> +         if (bc == b)
> +           {
> +             if (!chainp)
> +               binding = NULL;
> +             break;
> +           }
> +         chainp = &prev_binding->previous;
> +         if (type)
> +           for (tree tshadow = prev_binding->scope->type_shadowed;
> +                tshadow; tshadow = TREE_CHAIN (tshadow))
> +             if (TREE_PURPOSE (tshadow) == id)
> +               {
> +                 shadowing_type_p = &TREE_VALUE (tshadow);
> +                 break;
> +               }
> +       }
> +    }
> +  if (chainp)
> +    {
> +      IDENTIFIER_BINDING (id) = *chainp;
> +      *chainp = NULL;
> +    }
> +
> +  /* Like push_local_binding, supplement or add a binding to the
> +     desired level.  */
> +  if (IDENTIFIER_BINDING (id) && IDENTIFIER_BINDING (id)->scope == b)
> +    supplement_binding (IDENTIFIER_BINDING (id), decl);
> +  else
> +    push_binding (id, decl, b);
> +
> +  /* Now restore the binding chain we'd temporarily removed.  */
> +  if (chainp)
> +    {
> +      *chainp = IDENTIFIER_BINDING (id);
> +      IDENTIFIER_BINDING (id) = binding;
> +
> +      if (type)
> +       {
> +         /* Insert the new type binding in the shadowing_type_p
> +            TREE_VALUE chain.  */
> +         tree shadowed_type = NULL_TREE;
> +         if (shadowing_type_p)
> +           {
> +             shadowed_type = *shadowing_type_p;
> +             *shadowing_type_p = type;
> +           }
> +
> +         b->type_shadowed = tree_cons (id, shadowed_type, b->type_shadowed);
> +         TREE_TYPE (b->type_shadowed) = type;
> +       }
> +    }
> +  else if (type)
> +    {
> +      /* Our new binding is the active one, so shadow the earlier
> +        binding.  */
> +      b->type_shadowed = tree_cons (id, REAL_IDENTIFIER_TYPE_VALUE (id),
> +                                   b->type_shadowed);
> +      TREE_TYPE (b->type_shadowed) = type;
> +      SET_IDENTIFIER_TYPE_VALUE (id, type);
> +    }
> +
> +  /* Record that we have a binding for ID, like add_decl_to_level.  */
> +  tree node = build_tree_list (NULL_TREE, decl);
> +  TREE_CHAIN (node) = b->names;
> +  b->names = node;
> +}
> +
> +static void
> +plugin_pragma_push_user_expression (cpp_reader *)
> +{
> +  if (push_count++)
> +    return;
> +
> +  gcc_assert (!current_class_ptr);
> +  gcc_assert (!current_class_ref);
> +
> +  gcc_assert (!cp_binding_oracle);
> +  cp_binding_oracle = plugin_binding_oracle;
> +
> +  /* Make the function containing the user expression a global
> +     friend, so as to bypass access controls in it.  */
> +  if (at_function_scope_p ())
> +    set_global_friend (current_function_decl);
> +
> +  gcc_assert (at_function_scope_p ());
> +  function *save_cfun = cfun;
> +  cp_binding_level *orig_binding_level = current_binding_level;
> +  {
> +    int success;
> +    cc1_plugin::call (current_context, "enter_scope", &success);
> +  }
> +  gcc_assert (at_fake_function_scope_p () || at_function_scope_p ());
> +
> +  function *unchanged_cfun = cfun;
> +  tree changed_func_decl = current_function_decl;
> +
> +  gcc_assert (current_class_type == DECL_CONTEXT (current_function_decl)
> +             || !(RECORD_OR_UNION_CODE_P
> +                  (TREE_CODE (DECL_CONTEXT (current_function_decl)))));
> +  push_fake_function (save_cfun->decl, sk_block);
> +  current_class_type = NULL_TREE;
> +  if (unchanged_cfun)
> +    {
> +      /* If we get here, GDB did NOT change the context.  */
> +      gcc_assert (cfun == save_cfun);
> +      gcc_assert (at_function_scope_p ());
> +      gcc_assert (orig_binding_level
> +                 == current_binding_level->level_chain->level_chain);
> +    }
> +  else
> +    {
> +      cfun = save_cfun;
> +      gcc_assert (at_function_scope_p ());
> +
> +      cp_binding_level *b = current_binding_level->level_chain;
> +      gcc_assert (b->this_entity == cfun->decl);
> +
> +      /* Reactivate local names from the previous context.  Use
> +        IDENTIFIER_MARKED to avoid reactivating shadowed names.  */
> +      for (cp_binding_level *level = orig_binding_level;;)
> +       {
> +         for (tree name = level->names;
> +              name; name = TREE_CHAIN (name))
> +           {
> +             tree decl = name;
> +             if (TREE_CODE (decl) == TREE_LIST)
> +               decl = TREE_VALUE (decl);
> +             if (IDENTIFIER_MARKED (DECL_NAME (decl)))
> +               continue;
> +             IDENTIFIER_MARKED (DECL_NAME (decl)) = 1;
> +             reactivate_decl (decl, b);
> +           }
> +         if (level->kind == sk_function_parms
> +             && level->this_entity == cfun->decl)
> +           break;
> +         gcc_assert (!level->this_entity);
> +         level = level->level_chain;
> +       }
> +
> +      /* Now, clear the markers.  */
> +      for (tree name = b->names; name; name = TREE_CHAIN (name))
> +       {
> +         tree decl = name;
> +         if (TREE_CODE (decl) == TREE_LIST)
> +           decl = TREE_VALUE (decl);
> +         gcc_assert (IDENTIFIER_MARKED (DECL_NAME (decl)));
> +         IDENTIFIER_MARKED (DECL_NAME (decl)) = 0;
> +       }
> +    }
> +
> +  if (unchanged_cfun || DECL_NONSTATIC_MEMBER_FUNCTION_P (changed_func_decl))
> +    {
> +      /* Check whether the oracle supplies us with a "this", and if
> +        so, arrange for data members and this itself to be
> +        usable.  */
> +      tree this_val = lookup_name (get_identifier ("this"));
> +      current_class_ref = !this_val ? NULL_TREE
> +       : cp_build_indirect_ref (this_val, RO_NULL, tf_warning_or_error);
> +      current_class_ptr = this_val;
> +    }
> +}
> +
> +static void
> +plugin_pragma_pop_user_expression (cpp_reader *)
> +{
> +  if (--push_count)
> +    return;
> +
> +  gcc_assert (cp_binding_oracle);
> +
> +  gcc_assert (at_function_scope_p ());
> +  function *save_cfun = cfun;
> +  current_class_ptr = NULL_TREE;
> +  current_class_ref = NULL_TREE;
> +
> +  cfun = NULL;
> +  pop_scope ();
> +  if (RECORD_OR_UNION_CODE_P (TREE_CODE (DECL_CONTEXT (current_function_decl))))
> +    current_class_type = DECL_CONTEXT (current_function_decl);
> +  {
> +    int success;
> +    cc1_plugin::call (current_context, "leave_scope", &success);
> +  }
> +  if (!cfun)
> +    cfun = save_cfun;
> +  else
> +    gcc_assert (cfun == save_cfun);
> +
> +  cp_binding_oracle = NULL;
> +  gcc_assert (at_function_scope_p ());
> +}
> +
> +static void
> +plugin_init_extra_pragmas (void *, void *)
> +{
> +  c_register_pragma ("GCC", "push_user_expression", plugin_pragma_push_user_expression);
> +  c_register_pragma ("GCC", "pop_user_expression", plugin_pragma_pop_user_expression);
> +  /* FIXME: this one should go once we get GDB to use push and pop.  */
> +  c_register_pragma ("GCC", "user_expression", plugin_pragma_push_user_expression);
> +}
> +
> +
> +
> +static decl_addr_value
> +build_decl_addr_value (tree decl, gcc_address address)
> +{
> +  decl_addr_value value = {
> +    decl,
> +    build_int_cst_type (ptr_type_node, address)
> +  };
> +  return value;
> +}
> +
> +static decl_addr_value *
> +record_decl_address (plugin_context *ctx, decl_addr_value value)
> +{
> +  decl_addr_value **slot = ctx->address_map.find_slot (&value, INSERT);
> +  gcc_assert (*slot == NULL);
> +  *slot
> +    = static_cast<decl_addr_value *> (xmalloc (sizeof (decl_addr_value)));
> +  **slot = value;
> +  /* We don't want GCC to warn about e.g. static functions
> +     without a code definition.  */
> +  TREE_NO_WARNING (value.decl) = 1;
> +  return *slot;
> +}
> +
> +// Maybe rewrite a decl to its address.
> +static tree
> +address_rewriter (tree *in, int *walk_subtrees, void *arg)
> +{
> +  plugin_context *ctx = (plugin_context *) arg;
> +
> +  if (!DECL_P (*in)
> +      || TREE_CODE (*in) == NAMESPACE_DECL
> +      || DECL_NAME (*in) == NULL_TREE)
> +    return NULL_TREE;
> +
> +  decl_addr_value value;
> +  value.decl = *in;
> +  decl_addr_value *found_value = ctx->address_map.find (&value);
> +  if (found_value != NULL)
> +    ;
> +  else if (HAS_DECL_ASSEMBLER_NAME_P (*in))
> +    {
> +      gcc_address address;
> +
> +      if (!cc1_plugin::call (ctx, "address_oracle", &address,
> +                            IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (*in))))
> +       return NULL_TREE;
> +      if (address == 0)
> +       return NULL_TREE;
> +
> +      // Insert the decl into the address map in case it is referenced
> +      // again.
> +      value = build_decl_addr_value (value.decl, address);
> +      found_value = record_decl_address (ctx, value);
> +    }
> +  else
> +    return NULL_TREE;
> +
> +  if (found_value->address != error_mark_node)
> +    {
> +      // We have an address for the decl, so rewrite the tree.
> +      tree ptr_type = build_pointer_type (TREE_TYPE (*in));
> +      *in = fold_build1 (INDIRECT_REF, TREE_TYPE (*in),
> +                        fold_build1 (CONVERT_EXPR, ptr_type,
> +                                     found_value->address));
> +    }
> +
> +  *walk_subtrees = 0;
> +
> +  return NULL_TREE;
> +}
> +
> +// When generating code for gdb, we want to be able to use absolute
> +// addresses to refer to otherwise external objects that gdb knows
> +// about.  gdb passes in these addresses when building decls, and then
> +// before gimplification we go through the trees, rewriting uses to
> +// the equivalent of "*(TYPE *) ADDR".
> +static void
> +rewrite_decls_to_addresses (void *function_in, void *)
> +{
> +  tree function = (tree) function_in;
> +
> +  // Do nothing if we're not in gdb.
> +  if (current_context == NULL)
> +    return;
> +
> +  walk_tree (&DECL_SAVED_TREE (function), address_rewriter, current_context,
> +            NULL);
> +}
> +
> +
> +
> +static inline tree
> +safe_push_template_decl (tree decl)
> +{
> +  void (*save_oracle) (enum cp_oracle_request, tree identifier);
> +
> +  save_oracle = cp_binding_oracle;
> +  cp_binding_oracle = NULL;
> +
> +  tree ret = push_template_decl (decl);
> +
> +  cp_binding_oracle = save_oracle;
> +
> +  return ret;
> +}
> +
> +static inline tree
> +safe_pushtag (tree name, tree type, tag_scope scope)
> +{
> +  void (*save_oracle) (enum cp_oracle_request, tree identifier);
> +
> +  save_oracle = cp_binding_oracle;
> +  cp_binding_oracle = NULL;
> +
> +  tree ret = pushtag (name, type, scope);
> +
> +  cp_binding_oracle = save_oracle;
> +
> +  return ret;
> +}
> +
> +static inline tree
> +safe_pushdecl_maybe_friend (tree decl, bool is_friend)
> +{
> +  void (*save_oracle) (enum cp_oracle_request, tree identifier);
> +
> +  save_oracle = cp_binding_oracle;
> +  cp_binding_oracle = NULL;
> +
> +  tree ret = pushdecl_maybe_friend (decl, is_friend);
> +
> +  cp_binding_oracle = save_oracle;
> +
> +  return ret;
> +}
> +
> +
> +
> +int
> +plugin_push_namespace (cc1_plugin::connection *,
> +                      const char *name)
> +{
> +  if (name && !*name)
> +    push_to_top_level ();
> +  else
> +    push_namespace (name ? get_identifier (name) : NULL);
> +
> +  return 1;
> +}
> +
> +int
> +plugin_push_class (cc1_plugin::connection *,
> +                  gcc_type type_in)
> +{
> +  tree type = convert_in (type_in);
> +  gcc_assert (RECORD_OR_UNION_CODE_P (TREE_CODE (type)));
> +  gcc_assert (TYPE_CONTEXT (type) == FROB_CONTEXT (current_scope ()));
> +
> +  pushclass (type);
> +
> +  return 1;
> +}
> +
> +int
> +plugin_push_function (cc1_plugin::connection *,
> +                     gcc_decl function_decl_in)
> +{
> +  tree fndecl = convert_in (function_decl_in);
> +  gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
> +  gcc_assert (DECL_CONTEXT (fndecl) == FROB_CONTEXT (current_scope ()));
> +
> +  push_fake_function (fndecl);
> +
> +  return 1;
> +}
> +
> +int
> +plugin_pop_binding_level (cc1_plugin::connection *)
> +{
> +  pop_scope ();
> +  return 1;
> +}
> +
> +int
> +plugin_reactivate_decl (cc1_plugin::connection *,
> +                       gcc_decl decl_in,
> +                       gcc_decl scope_in)
> +{
> +  tree decl = convert_in (decl_in);
> +  tree scope = convert_in (scope_in);
> +  gcc_assert (TREE_CODE (decl) == VAR_DECL
> +             || TREE_CODE (decl) == FUNCTION_DECL
> +             || TREE_CODE (decl) == TYPE_DECL);
> +  cp_binding_level *b;
> +  if (scope)
> +    {
> +      gcc_assert (TREE_CODE (scope) == FUNCTION_DECL);
> +      for (b = current_binding_level;
> +          b->this_entity != scope;
> +          b = b->level_chain)
> +       gcc_assert (b->this_entity != global_namespace);
> +    }
> +  else
> +    {
> +      gcc_assert (!at_class_scope_p ());
> +      b = current_binding_level;
> +    }
> +
> +  reactivate_decl (decl, b);
> +  return 1;
> +}
> +
> +static tree
> +get_current_scope ()
> +{
> +  tree decl;
> +
> +  if (at_namespace_scope_p ())
> +    decl = current_namespace;
> +  else if (at_class_scope_p ())
> +    decl = TYPE_NAME (current_class_type);
> +  else if (at_fake_function_scope_p () || at_function_scope_p ())
> +    decl = current_function_decl;
> +  else
> +    gcc_unreachable ();
> +
> +  return decl;
> +}
> +
> +gcc_decl
> +plugin_get_current_binding_level_decl (cc1_plugin::connection *)
> +{
> +  tree decl = get_current_scope ();
> +
> +  return convert_out (decl);
> +}
> +
> +int
> +plugin_make_namespace_inline (cc1_plugin::connection *)
> +{
> +  tree inline_ns = current_namespace;
> +
> +  gcc_assert (toplevel_bindings_p ());
> +  gcc_assert (inline_ns != global_namespace);
> +
> +  tree parent_ns = CP_DECL_CONTEXT (inline_ns);
> +
> +  if (purpose_member (DECL_NAMESPACE_ASSOCIATIONS (inline_ns),
> +                     parent_ns))
> +    return 0;
> +
> +  pop_namespace ();
> +
> +  gcc_assert (current_namespace == parent_ns);
> +
> +  DECL_NAMESPACE_ASSOCIATIONS (inline_ns)
> +    = tree_cons (parent_ns, 0,
> +                DECL_NAMESPACE_ASSOCIATIONS (inline_ns));
> +  do_using_directive (inline_ns);
> +
> +  push_namespace (DECL_NAME (inline_ns));
> +
> +  return 1;
> +}
> +
> +int
> +plugin_add_using_namespace (cc1_plugin::connection *,
> +                           gcc_decl used_ns_in)
> +{
> +  tree used_ns = convert_in (used_ns_in);
> +
> +  gcc_assert (TREE_CODE (used_ns) == NAMESPACE_DECL);
> +
> +  do_using_directive (used_ns);
> +
> +  return 1;
> +}
> +
> +int
> +plugin_add_namespace_alias (cc1_plugin::connection *,
> +                           const char *id,
> +                           gcc_decl target_in)
> +{
> +  tree name = get_identifier (id);
> +  tree target = convert_in (target_in);
> +
> +  do_namespace_alias (name, target);
> +
> +  return 1;
> +}
> +
> +static inline void
> +set_access_flags (tree decl, enum gcc_cp_symbol_kind flags)
> +{
> +  gcc_assert (!(flags & GCC_CP_ACCESS_MASK) == !DECL_CLASS_SCOPE_P (decl));
> +
> +  switch (flags & GCC_CP_ACCESS_MASK)
> +    {
> +    case GCC_CP_ACCESS_PRIVATE:
> +      TREE_PRIVATE (decl) = true;
> +      current_access_specifier = access_private_node;
> +      break;
> +
> +    case GCC_CP_ACCESS_PROTECTED:
> +      TREE_PROTECTED (decl) = true;
> +      current_access_specifier = access_protected_node;
> +      break;
> +
> +    case GCC_CP_ACCESS_PUBLIC:
> +      current_access_specifier = access_public_node;
> +      break;
> +
> +    default:
> +      break;
> +    }
> +}
> +
> +int
> +plugin_add_using_decl (cc1_plugin::connection *,
> +                      enum gcc_cp_symbol_kind flags,
> +                      gcc_decl target_in)
> +{
> +  tree target = convert_in (target_in);
> +  gcc_assert ((flags & GCC_CP_SYMBOL_MASK) == GCC_CP_SYMBOL_USING);
> +  gcc_assert (!(flags & GCC_CP_FLAG_MASK));
> +  enum gcc_cp_symbol_kind acc_flags;
> +  acc_flags = (enum gcc_cp_symbol_kind) (flags & GCC_CP_ACCESS_MASK);
> +
> +  gcc_assert (!template_parm_scope_p ());
> +
> +  bool class_member_p = at_class_scope_p ();
> +  gcc_assert (!(acc_flags & GCC_CP_ACCESS_MASK) == !class_member_p);
> +
> +  tree identifier = DECL_NAME (target);
> +  tree tcontext = DECL_CONTEXT (target);
> +
> +  if (UNSCOPED_ENUM_P (tcontext))
> +    tcontext = CP_TYPE_CONTEXT (tcontext);
> +
> +  if (class_member_p)
> +    {
> +      tree decl = do_class_using_decl (tcontext, identifier);
> +
> +      set_access_flags (decl, flags);
> +
> +      finish_member_declaration (decl);
> +    }
> +  else if (!at_namespace_scope_p ())
> +    {
> +      gcc_unreachable ();
> +      do_local_using_decl (target, tcontext, identifier);
> +    }
> +  else
> +    do_toplevel_using_decl (target, tcontext, identifier);
> +
> +  return 1;
> +}
> +
> +static tree
> +build_named_class_type (enum tree_code code,
> +                       tree id,
> +                       source_location loc)
> +{
> +  /* See at_fake_function_scope_p.  */
> +  gcc_assert (!at_function_scope_p ());
> +  tree type = make_class_type (code);
> +  tree type_decl = build_decl (loc, TYPE_DECL, id, type);
> +  TYPE_NAME (type) = type_decl;
> +  TYPE_STUB_DECL (type) = type_decl;
> +  DECL_CONTEXT (type_decl) = TYPE_CONTEXT (type);
> +
> +  return type_decl;
> +}
> +
> +/* Abuse an unused field of the dummy template parms entry to hold the
> +   parm list.  */
> +#define TP_PARM_LIST TREE_TYPE (current_template_parms)
> +
> +gcc_decl
> +plugin_build_decl (cc1_plugin::connection *self,
> +                  const char *name,
> +                  enum gcc_cp_symbol_kind sym_kind,
> +                  gcc_type sym_type_in,
> +                  const char *substitution_name,
> +                  gcc_address address,
> +                  const char *filename,
> +                  unsigned int line_number)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  gcc_assert (!name || !strchr (name, ':')); // FIXME: this can go eventually.
> +
> +  enum tree_code code;
> +  tree decl;
> +  tree sym_type = convert_in (sym_type_in);
> +  enum gcc_cp_symbol_kind sym_flags;
> +  sym_flags = (enum gcc_cp_symbol_kind) (sym_kind & GCC_CP_FLAG_MASK);
> +  enum gcc_cp_symbol_kind acc_flags;
> +  acc_flags = (enum gcc_cp_symbol_kind) (sym_kind & GCC_CP_ACCESS_MASK);
> +  sym_kind = (enum gcc_cp_symbol_kind) (sym_kind & GCC_CP_SYMBOL_MASK);
> +
> +  switch (sym_kind)
> +    {
> +    case GCC_CP_SYMBOL_FUNCTION:
> +      code = FUNCTION_DECL;
> +      gcc_assert (!(sym_flags & ~GCC_CP_FLAG_MASK_FUNCTION));
> +      break;
> +
> +    case GCC_CP_SYMBOL_VARIABLE:
> +      code = VAR_DECL;
> +      gcc_assert (!(sym_flags & ~GCC_CP_FLAG_MASK_VARIABLE));
> +      break;
> +
> +    case GCC_CP_SYMBOL_TYPEDEF:
> +      code = TYPE_DECL;
> +      gcc_assert (!sym_flags);
> +      break;
> +
> +    case GCC_CP_SYMBOL_CLASS:
> +      code = RECORD_TYPE;
> +      gcc_assert (!(sym_flags & ~GCC_CP_FLAG_MASK_CLASS));
> +      gcc_assert (!sym_type);
> +      break;
> +
> +    case GCC_CP_SYMBOL_UNION:
> +      code = UNION_TYPE;
> +      gcc_assert (!sym_flags);
> +      gcc_assert (!sym_type);
> +      break;
> +
> +    default:
> +      gcc_unreachable ();
> +    }
> +
> +  bool template_decl_p = template_parm_scope_p ();
> +
> +  if (template_decl_p)
> +    {
> +      gcc_assert (code == FUNCTION_DECL || code == RECORD_TYPE
> +                 || code == TYPE_DECL);
> +
> +      /* Finish the template parm list that started this template parm.  */
> +      end_template_parm_list (TP_PARM_LIST);
> +
> +      gcc_assert (!address);
> +      gcc_assert (!substitution_name);
> +    }
> +
> +  source_location loc = ctx->get_source_location (filename, line_number);
> +  bool class_member_p = at_class_scope_p ();
> +  bool ctor = false, dtor = false, assop = false;
> +  tree_code opcode = ERROR_MARK;
> +
> +  gcc_assert (!(acc_flags & GCC_CP_ACCESS_MASK) == !class_member_p);
> +
> +  tree identifier;
> +  if (code != FUNCTION_DECL
> +      || !(sym_flags & GCC_CP_FLAG_SPECIAL_FUNCTION))
> +    {
> +      if (name)
> +       identifier = get_identifier (name);
> +      else
> +       {
> +         gcc_assert (RECORD_OR_UNION_CODE_P (code));
> +         identifier = make_anon_name ();
> +       }
> +    }
> +
> +  if (code == FUNCTION_DECL)
> +    {
> +      if (sym_flags & GCC_CP_FLAG_SPECIAL_FUNCTION)
> +       {
> +#define CHARS2(f,s) (((unsigned char)f << CHAR_BIT) | (unsigned char)s)
> +         switch (CHARS2 (name[0], name[1]))
> +           {
> +           case CHARS2 ('C', 0x0): // ctor base declaration
> +           case CHARS2 ('C', ' '):
> +           case CHARS2 ('C', '1'):
> +           case CHARS2 ('C', '2'):
> +           case CHARS2 ('C', '4'):
> +             ctor = true;
> +           cdtor:
> +             gcc_assert (!address);
> +             gcc_assert (!substitution_name);
> +             identifier = DECL_NAME (TYPE_NAME (current_class_type));
> +             break;
> +           case CHARS2 ('D', 0x0): // dtor base declaration
> +           case CHARS2 ('D', ' '):
> +           case CHARS2 ('D', '0'):
> +           case CHARS2 ('D', '1'):
> +           case CHARS2 ('D', '2'):
> +           case CHARS2 ('D', '4'):
> +             gcc_assert (!template_decl_p);
> +             dtor = true;
> +             goto cdtor;
> +           case CHARS2 ('n', 'w'): // operator new
> +             opcode = NEW_EXPR;
> +             break;
> +           case CHARS2 ('n', 'a'): // operator new[]
> +             opcode = VEC_NEW_EXPR;
> +             break;
> +           case CHARS2 ('d', 'l'): // operator delete
> +             opcode = DELETE_EXPR;
> +             break;
> +           case CHARS2 ('d', 'a'): // operator delete[]
> +             opcode = VEC_DELETE_EXPR;
> +             break;
> +           case CHARS2 ('p', 's'): // operator + (unary)
> +             opcode = PLUS_EXPR;
> +             break;
> +           case CHARS2 ('n', 'g'): // operator - (unary)
> +             opcode = MINUS_EXPR;
> +             break;
> +           case CHARS2 ('a', 'd'): // operator & (unary)
> +             opcode = BIT_AND_EXPR;
> +             break;
> +           case CHARS2 ('d', 'e'): // operator * (unary)
> +             opcode = MULT_EXPR;
> +             break;
> +           case CHARS2 ('c', 'o'): // operator ~
> +             opcode = BIT_NOT_EXPR;
> +             break;
> +           case CHARS2 ('p', 'l'): // operator +
> +             opcode = PLUS_EXPR;
> +             break;
> +           case CHARS2 ('m', 'i'): // operator -
> +             opcode = MINUS_EXPR;
> +             break;
> +           case CHARS2 ('m', 'l'): // operator *
> +             opcode = MULT_EXPR;
> +             break;
> +           case CHARS2 ('d', 'v'): // operator /
> +             opcode = TRUNC_DIV_EXPR;
> +             break;
> +           case CHARS2 ('r', 'm'): // operator %
> +             opcode = TRUNC_MOD_EXPR;
> +             break;
> +           case CHARS2 ('a', 'n'): // operator &
> +             opcode = BIT_AND_EXPR;
> +             break;
> +           case CHARS2 ('o', 'r'): // operator |
> +             opcode = BIT_IOR_EXPR;
> +             break;
> +           case CHARS2 ('e', 'o'): // operator ^
> +             opcode = BIT_XOR_EXPR;
> +             break;
> +           case CHARS2 ('a', 'S'): // operator =
> +             opcode = NOP_EXPR;
> +             assop = true;
> +             break;
> +           case CHARS2 ('p', 'L'): // operator +=
> +             opcode = PLUS_EXPR;
> +             assop = true;
> +             break;
> +           case CHARS2 ('m', 'I'): // operator -=
> +             opcode = MINUS_EXPR;
> +             assop = true;
> +             break;
> +           case CHARS2 ('m', 'L'): // operator *=
> +             opcode = MULT_EXPR;
> +             assop = true;
> +             break;
> +           case CHARS2 ('d', 'V'): // operator /=
> +             opcode = TRUNC_DIV_EXPR;
> +             assop = true;
> +             break;
> +           case CHARS2 ('r', 'M'): // operator %=
> +             opcode = TRUNC_MOD_EXPR;
> +             assop = true;
> +             break;
> +           case CHARS2 ('a', 'N'): // operator &=
> +             opcode = BIT_AND_EXPR;
> +             assop = true;
> +             break;
> +           case CHARS2 ('o', 'R'): // operator |=
> +             opcode = BIT_IOR_EXPR;
> +             assop = true;
> +             break;
> +           case CHARS2 ('e', 'O'): // operator ^=
> +             opcode = BIT_XOR_EXPR;
> +             assop = true;
> +             break;
> +           case CHARS2 ('l', 's'): // operator <<
> +             opcode = LSHIFT_EXPR;
> +             break;
> +           case CHARS2 ('r', 's'): // operator >>
> +             opcode = RSHIFT_EXPR;
> +             break;
> +           case CHARS2 ('l', 'S'): // operator <<=
> +             opcode = LSHIFT_EXPR;
> +             assop = true;
> +             break;
> +           case CHARS2 ('r', 'S'): // operator >>=
> +             opcode = RSHIFT_EXPR;
> +             assop = true;
> +             break;
> +           case CHARS2 ('e', 'q'): // operator ==
> +             opcode = EQ_EXPR;
> +             break;
> +           case CHARS2 ('n', 'e'): // operator !=
> +             opcode = NE_EXPR;
> +             break;
> +           case CHARS2 ('l', 't'): // operator <
> +             opcode = LT_EXPR;
> +             break;
> +           case CHARS2 ('g', 't'): // operator >
> +             opcode = GT_EXPR;
> +             break;
> +           case CHARS2 ('l', 'e'): // operator <=
> +             opcode = LE_EXPR;
> +             break;
> +           case CHARS2 ('g', 'e'): // operator >=
> +             opcode = GE_EXPR;
> +             break;
> +           case CHARS2 ('n', 't'): // operator !
> +             opcode = TRUTH_NOT_EXPR;
> +             break;
> +           case CHARS2 ('a', 'a'): // operator &&
> +             opcode = TRUTH_ANDIF_EXPR;
> +             break;
> +           case CHARS2 ('o', 'o'): // operator ||
> +             opcode = TRUTH_ORIF_EXPR;
> +             break;
> +           case CHARS2 ('p', 'p'): // operator ++
> +             opcode = POSTINCREMENT_EXPR;
> +             break;
> +           case CHARS2 ('m', 'm'): // operator --
> +             /* This stands for either one as an operator name, and
> +                "pp" and "mm" stand for POST??CREMENT, but for some
> +                reason the parser uses this opcode name for
> +                operator--; let's follow their practice.  */
> +             opcode = PREDECREMENT_EXPR;
> +             break;
> +           case CHARS2 ('c', 'm'): // operator ,
> +             opcode = COMPOUND_EXPR;
> +             break;
> +           case CHARS2 ('p', 'm'): // operator ->*
> +             opcode = MEMBER_REF;
> +             break;
> +           case CHARS2 ('p', 't'): // operator ->
> +             opcode = COMPONENT_REF;
> +             break;
> +           case CHARS2 ('c', 'l'): // operator ()
> +             opcode = CALL_EXPR;
> +             break;
> +           case CHARS2 ('i', 'x'): // operator []
> +             opcode = ARRAY_REF;
> +             break;
> +           case CHARS2 ('c', 'v'): // operator <T> (conversion operator)
> +             identifier = mangle_conv_op_name_for_type (TREE_TYPE (sym_type));
> +             break;
> +             // C++11-only:
> +           case CHARS2 ('l', 'i'): // operator "" <id>
> +             {
> +               char *id = (char *)name + 2;
> +               bool freeid = false;
> +               if (*id >= '0' && *id <= '9')
> +                 {
> +                   unsigned len = 0;
> +                   do
> +                     {
> +                       len *= 10;
> +                       len += id[0] - '0';
> +                       id++;
> +                     }
> +                   while (*id && *id >= '0' && *id <= '9');
> +                   id = xstrndup (id, len);
> +                   freeid = true;
> +                 }
> +               identifier = cp_literal_operator_id (id);
> +               if (freeid)
> +                 free (id);
> +             }
> +             break;
> +           case CHARS2 ('q', 'u'): // ternary operator, not overloadable.
> +           default:
> +             gcc_unreachable ();
> +           }
> +
> +         if (opcode != ERROR_MARK)
> +           {
> +             if (assop)
> +               identifier = cp_assignment_operator_id (opcode);
> +             else
> +               identifier = cp_operator_id (opcode);
> +           }
> +       }
> +      decl = build_lang_decl_loc (loc, code, identifier, sym_type);
> +      /* FIXME: current_lang_name is lang_name_c while compiling an
> +        extern "C" function, and we haven't switched to a global
> +        context at this point, and this breaks function
> +        overloading.  */
> +      SET_DECL_LANGUAGE (decl, lang_cplusplus);
> +      if (TREE_CODE (sym_type) == METHOD_TYPE)
> +       DECL_ARGUMENTS (decl) = build_this_parm (current_class_type,
> +                                                cp_type_quals (sym_type));
> +      for (tree arg = TREE_CODE (sym_type) == METHOD_TYPE
> +            ? TREE_CHAIN (TYPE_ARG_TYPES (sym_type))
> +            : TYPE_ARG_TYPES (sym_type);
> +          arg && arg != void_list_node;
> +          arg = TREE_CHAIN (arg))
> +       {
> +         tree parm = cp_build_parm_decl (NULL_TREE, TREE_VALUE (arg));
> +         DECL_CHAIN (parm) = DECL_ARGUMENTS (decl);
> +         DECL_ARGUMENTS (decl) = parm;
> +       }
> +      DECL_ARGUMENTS (decl) = nreverse (DECL_ARGUMENTS (decl));
> +      if (class_member_p)
> +       {
> +         if (TREE_CODE (sym_type) == FUNCTION_TYPE)
> +           DECL_STATIC_FUNCTION_P (decl) = 1;
> +         if (sym_flags & GCC_CP_FLAG_VIRTUAL_FUNCTION)
> +           {
> +             DECL_VIRTUAL_P (decl) = 1;
> +             if (sym_flags & GCC_CP_FLAG_PURE_VIRTUAL_FUNCTION)
> +               DECL_PURE_VIRTUAL_P (decl) = 1;
> +             if (sym_flags & GCC_CP_FLAG_FINAL_VIRTUAL_FUNCTION)
> +               DECL_FINAL_P (decl) = 1;
> +           }
> +         else
> +           gcc_assert (!(sym_flags & (GCC_CP_FLAG_PURE_VIRTUAL_FUNCTION
> +                                      | GCC_CP_FLAG_FINAL_VIRTUAL_FUNCTION)));
> +       }
> +      else
> +       {
> +         gcc_assert (!(sym_flags & (GCC_CP_FLAG_VIRTUAL_FUNCTION
> +                                    | GCC_CP_FLAG_PURE_VIRTUAL_FUNCTION
> +                                    | GCC_CP_FLAG_FINAL_VIRTUAL_FUNCTION)));
> +         gcc_assert (!ctor && !dtor && !assop);
> +       }
> +      if (sym_flags & GCC_CP_FLAG_EXPLICIT_FUNCTION)
> +       DECL_NONCONVERTING_P (decl) = 1;
> +      if (sym_flags & GCC_CP_FLAG_DEFAULTED_FUNCTION)
> +       {
> +         DECL_INITIAL (decl) = ridpointers[(int)RID_DEFAULT];
> +         DECL_DEFAULTED_FN (decl) = 1;
> +       }
> +      if (sym_flags & GCC_CP_FLAG_DELETED_FUNCTION)
> +       {
> +         // DECL_INITIAL (decl) = ridpointers[(int)RID_DELETE];
> +         DECL_DELETED_FN (decl) = 1;
> +         DECL_DECLARED_INLINE_P (decl) = 1;
> +         DECL_INITIAL (decl) = error_mark_node;
> +       }
> +      if (ctor || dtor)
> +       {
> +         if (ctor)
> +           DECL_CONSTRUCTOR_P (decl) = 1;
> +         if (dtor)
> +           DECL_DESTRUCTOR_P (decl) = 1;
> +       }
> +      else
> +       {
> +         if ((sym_flags & GCC_CP_FLAG_SPECIAL_FUNCTION)
> +             && opcode != ERROR_MARK)
> +           SET_OVERLOADED_OPERATOR_CODE (decl, opcode);
> +         if (assop)
> +           DECL_ASSIGNMENT_OPERATOR_P (decl) = true;
> +       }
> +    }
> +  else if (RECORD_OR_UNION_CODE_P (code))
> +    {
> +      decl = build_named_class_type (code, identifier, loc);
> +      tree type = TREE_TYPE (decl);
> +
> +      if (code == RECORD_TYPE
> +         && !(sym_flags & GCC_CP_FLAG_CLASS_IS_STRUCT))
> +       CLASSTYPE_DECLARED_CLASS (type) = true;
> +    }
> +  else if (class_member_p)
> +    {
> +      decl = build_lang_decl_loc (loc, code, identifier, sym_type);
> +
> +      if (TREE_CODE (decl) == VAR_DECL)
> +       {
> +         DECL_THIS_STATIC (decl) = 1;
> +         // The remainder of this block does the same as:
> +         // set_linkage_for_static_data_member (decl);
> +         TREE_PUBLIC (decl) = 1;
> +         TREE_STATIC (decl) = 1;
> +         DECL_INTERFACE_KNOWN (decl) = 1;
> +
> +         // FIXME: sym_flags & GCC_CP_FLAG_THREAD_LOCAL_VARIABLE
> +         gcc_assert (!(sym_flags & GCC_CP_FLAG_THREAD_LOCAL_VARIABLE));
> +
> +         if (sym_flags & GCC_CP_FLAG_CONSTEXPR_VARIABLE)
> +           DECL_DECLARED_CONSTEXPR_P (decl) = true;
> +       }
> +    }
> +  else
> +    {
> +      decl = build_decl (loc, code, identifier, sym_type);
> +
> +      if (TREE_CODE (decl) == VAR_DECL)
> +       {
> +         // FIXME: sym_flags & GCC_CP_FLAG_THREAD_LOCAL_VARIABLE
> +         gcc_assert (!(sym_flags & GCC_CP_FLAG_THREAD_LOCAL_VARIABLE));
> +
> +         if (sym_flags & GCC_CP_FLAG_CONSTEXPR_VARIABLE)
> +           DECL_DECLARED_CONSTEXPR_P (decl) = true;
> +       }
> +    }
> +  TREE_USED (decl) = 1;
> +  TREE_ADDRESSABLE (decl) = 1;
> +
> +  if (class_member_p)
> +    DECL_CONTEXT (decl) = FROB_CONTEXT (current_class_type);
> +  else if (at_namespace_scope_p ())
> +    DECL_CONTEXT (decl) = FROB_CONTEXT (current_decl_namespace ());
> +
> +  set_access_flags (decl, acc_flags);
> +
> +  if (sym_kind != GCC_CP_SYMBOL_TYPEDEF
> +      && sym_kind != GCC_CP_SYMBOL_CLASS
> +      && sym_kind != GCC_CP_SYMBOL_UNION
> +      && !template_decl_p && !ctor && !dtor)
> +    {
> +      decl_addr_value value;
> +
> +      DECL_EXTERNAL (decl) = 1;
> +      value.decl = decl;
> +      if (substitution_name != NULL)
> +       {
> +         // If the translator gave us a name without a binding,
> +         // we can just substitute error_mark_node, since we know the
> +         // translator will be reporting an error anyhow.
> +         value.address
> +           = lookup_name (get_identifier (substitution_name));
> +         if (value.address == NULL_TREE)
> +           value.address = error_mark_node;
> +       }
> +      else if (address)
> +       value.address = build_int_cst_type (ptr_type_node, address);
> +      else
> +       value.address = NULL;
> +      if (value.address)
> +       record_decl_address (ctx, value);
> +    }
> +
> +  if (class_member_p && code == FUNCTION_DECL)
> +    {
> +      if (ctor || dtor)
> +       maybe_retrofit_in_chrg (decl);
> +
> +      grok_special_member_properties (decl);
> +    }
> +
> +  if (template_decl_p)
> +    {
> +      if (RECORD_OR_UNION_CODE_P (code))
> +       safe_pushtag (identifier, TREE_TYPE (decl), ts_current);
> +      else
> +       decl = safe_push_template_decl (decl);
> +
> +      tree tdecl = NULL_TREE;
> +      if (class_member_p)
> +       tdecl = finish_member_template_decl (decl);
> +
> +      end_template_decl ();
> +
> +      /* We only support one level of templates, because we only
> +        support declaring generics; actual definitions are only of
> +        specializations.  */
> +      gcc_assert (!template_parm_scope_p ());
> +
> +      if (class_member_p)
> +       finish_member_declaration (tdecl);
> +    }
> +  else if (RECORD_OR_UNION_CODE_P (code))
> +    safe_pushtag (identifier, TREE_TYPE (decl), ts_current);
> +  else if (class_member_p)
> +    finish_member_declaration (decl);
> +  else
> +    decl = safe_pushdecl_maybe_friend (decl, false);
> +
> +  if ((ctor || dtor)
> +      /* Don't crash after a duplicate declaration of a cdtor.  */
> +      && TYPE_METHODS (current_class_type) == decl)
> +    {
> +      /* ctors and dtors clones are chained after DECL.
> +        However, we create the clones before TYPE_METHODS is
> +        reversed.  We test for cloned methods after reversal,
> +        however, and the test requires the clones to follow
> +        DECL.  So, we reverse the chain of clones now, so
> +        that it will come out in the right order after
> +        reversal.  */
> +      tree save = DECL_CHAIN (decl);
> +      DECL_CHAIN (decl) = NULL_TREE;
> +      clone_function_decl (decl, /*update_method_vec_p=*/1);
> +      gcc_assert (TYPE_METHODS (current_class_type) == decl);
> +      TYPE_METHODS (current_class_type)
> +       = nreverse (TYPE_METHODS (current_class_type));
> +      DECL_CHAIN (decl) = save;
> +    }
> +
> +  rest_of_decl_compilation (decl, toplevel_bindings_p (), 0);
> +
> +  return convert_out (ctx->preserve (decl));
> +}
> +
> +gcc_decl
> +plugin_define_cdtor_clone (cc1_plugin::connection *self,
> +                          const char *name,
> +                          gcc_decl cdtor_in,
> +                          gcc_address address)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree decl = convert_in (cdtor_in);
> +  bool ctor = false;
> +  bool dtor = false;
> +  tree identifier;
> +
> +  switch (CHARS2 (name[0], name[1]))
> +    {
> +    case CHARS2 ('C', '1'): // in-charge constructor
> +      identifier = complete_ctor_identifier;
> +      ctor = true;
> +      break;
> +    case CHARS2 ('C', '2'): // not-in-charge constructor
> +      identifier = base_ctor_identifier;
> +      ctor = true;
> +      break;
> +    case CHARS2 ('C', '4'):
> +      identifier = ctor_identifier; // unified constructor
> +      ctor = true;
> +      break;
> +    case CHARS2 ('D', '0'): // deleting destructor
> +      identifier = deleting_dtor_identifier;
> +      dtor = true;
> +      break;
> +    case CHARS2 ('D', '1'): // in-charge destructor
> +      identifier = complete_dtor_identifier;
> +      dtor = true;
> +      break;
> +    case CHARS2 ('D', '2'): // not-in-charge destructor
> +      identifier = base_dtor_identifier;
> +      dtor = true;
> +      break;
> +    case CHARS2 ('D', '4'):
> +      identifier = dtor_identifier; // unified destructor
> +      dtor = true;
> +      break;
> +
> +    default:
> +      gcc_unreachable ();
> +    }
> +
> +  gcc_assert (!ctor != !dtor);
> +  gcc_assert (ctor
> +             ? (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)
> +                && DECL_NAME (decl) == ctor_identifier)
> +             : (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl)
> +                && DECL_NAME (decl) == dtor_identifier));
> +
> +  while (decl && DECL_NAME (decl) != identifier)
> +    {
> +      decl = DECL_CHAIN (decl);
> +      if (decl && !DECL_CLONED_FUNCTION_P (decl))
> +       decl = NULL_TREE;
> +    }
> +  gcc_assert (decl);
> +
> +  record_decl_address (ctx, build_decl_addr_value (decl, address));
> +
> +  return convert_out (decl);
> +}
> +
> +int
> +plugin_add_friend (cc1_plugin::connection * /* self */,
> +                  gcc_decl decl_in,
> +                  gcc_type type_in)
> +{
> +  tree decl = convert_in (decl_in);
> +  tree type = convert_in (type_in);
> +
> +  gcc_assert (type || at_class_scope_p ());
> +
> +  if (!type)
> +    type = current_class_type;
> +  else
> +    gcc_assert (TREE_CODE (type) == RECORD_TYPE);
> +
> +  if (TYPE_P (decl))
> +    make_friend_class (type, TREE_TYPE (decl), true);
> +  else
> +    {
> +      DECL_FRIEND_P (decl) = true;
> +      add_friend (type, decl, true);
> +    }
> +
> +  return 1;
> +}
> +
> +gcc_type
> +plugin_build_pointer_type (cc1_plugin::connection *,
> +                          gcc_type base_type)
> +{
> +  // No need to preserve a pointer type as the base type is preserved.
> +  return convert_out (build_pointer_type (convert_in (base_type)));
> +}
> +
> +gcc_type
> +plugin_build_reference_type (cc1_plugin::connection *,
> +                            gcc_type base_type_in,
> +                            enum gcc_cp_ref_qualifiers rquals)
> +{
> +  bool rval;
> +
> +  switch (rquals)
> +    {
> +    case GCC_CP_REF_QUAL_LVALUE:
> +      rval = false;
> +      break;
> +    case GCC_CP_REF_QUAL_RVALUE:
> +      rval = true;
> +      break;
> +    case GCC_CP_REF_QUAL_NONE:
> +    default:
> +      gcc_unreachable ();
> +    }
> +
> +  tree rtype = cp_build_reference_type (convert_in (base_type_in), rval);
> +
> +  return convert_out (rtype);
> +}
> +
> +static tree
> +start_class_def (tree type,
> +                const gcc_vbase_array *base_classes)
> +{
> +  tree bases = NULL;
> +  if (base_classes)
> +    {
> +      for (int i = 0; i < base_classes->n_elements; i++)
> +       {
> +         tree access;
> +
> +         gcc_assert ((base_classes->flags[i] & GCC_CP_SYMBOL_MASK)
> +                     == GCC_CP_SYMBOL_BASECLASS);
> +
> +         switch (base_classes->flags[i] & GCC_CP_ACCESS_MASK)
> +           {
> +           case GCC_CP_ACCESS_PRIVATE:
> +             access = ridpointers[(int)RID_PRIVATE];
> +             break;
> +
> +           case GCC_CP_ACCESS_PROTECTED:
> +             access = ridpointers[(int)RID_PROTECTED];
> +             break;
> +
> +           case GCC_CP_ACCESS_PUBLIC:
> +             access = ridpointers[(int)RID_PUBLIC];
> +             break;
> +
> +           default:
> +             gcc_unreachable ();
> +           }
> +
> +         tree base = finish_base_specifier
> +           (convert_in (base_classes->elements[i]), access,
> +            (base_classes->flags[i] & GCC_CP_FLAG_BASECLASS_VIRTUAL) != 0);
> +         TREE_CHAIN (base) = bases;
> +         bases = base;
> +       }
> +      bases = nreverse (bases);
> +    }
> +  xref_basetypes (type, bases);
> +  begin_class_definition (type);
> +  return type;
> +}
> +
> +gcc_type
> +plugin_start_class_type (cc1_plugin::connection *self,
> +                        gcc_decl typedecl_in,
> +                        const gcc_vbase_array *base_classes,
> +                        const char *filename,
> +                        unsigned int line_number)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  source_location loc = ctx->get_source_location (filename, line_number);
> +  tree typedecl = convert_in (typedecl_in);
> +  tree type = TREE_TYPE (typedecl);
> +
> +  gcc_assert (RECORD_OR_UNION_CODE_P (TREE_CODE (type)));
> +  gcc_assert (!COMPLETE_TYPE_P (type));
> +
> +  DECL_SOURCE_LOCATION (typedecl) = loc;
> +
> +  tree result = start_class_def (type, base_classes);
> +
> +  return convert_out (ctx->preserve (result));
> +}
> +
> +gcc_type
> +plugin_start_closure_class_type (cc1_plugin::connection *self,
> +                                int discriminator,
> +                                gcc_decl extra_scope_in,
> +                                enum gcc_cp_symbol_kind flags,
> +                                const char *filename,
> +                                unsigned int line_number)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree extra_scope = convert_in (extra_scope_in);
> +
> +  gcc_assert ((flags & GCC_CP_SYMBOL_MASK) == GCC_CP_SYMBOL_LAMBDA_CLOSURE);
> +  gcc_assert ((flags & (~(GCC_CP_SYMBOL_MASK | GCC_CP_ACCESS_MASK))) == 0);
> +
> +  gcc_assert (!(flags & GCC_CP_ACCESS_MASK) == !at_class_scope_p ());
> +
> +  /* See at_fake_function_scope_p.  */
> +  gcc_assert (!at_function_scope_p ());
> +
> +  if (extra_scope)
> +    {
> +      if (TREE_CODE (extra_scope) == PARM_DECL)
> +       {
> +         gcc_assert (at_fake_function_scope_p ());
> +         /* Check that the given extra_scope is one of the parameters of
> +            the current function.  */
> +         for (tree parm = DECL_ARGUMENTS (current_function_decl);
> +              ; parm = DECL_CHAIN (parm))
> +           {
> +             gcc_assert (parm);
> +             if (parm == extra_scope)
> +               break;
> +           }
> +       }
> +      else if (TREE_CODE (extra_scope) == FIELD_DECL)
> +       {
> +         gcc_assert (at_class_scope_p ());
> +         gcc_assert (DECL_CONTEXT (extra_scope) == current_class_type);
> +       }
> +      else
> +       /* FIXME: does this ever really occur?  */
> +       gcc_assert (TREE_CODE (extra_scope) == VAR_DECL);
> +    }
> +
> +  tree lambda_expr = build_lambda_expr ();
> +
> +  LAMBDA_EXPR_LOCATION (lambda_expr) = ctx->get_source_location (filename,
> +                                                                line_number);
> +
> +  tree type = begin_lambda_type (lambda_expr);
> +
> +  /* Instead of calling record_lambda_scope, do this:  */
> +  LAMBDA_EXPR_EXTRA_SCOPE (lambda_expr) = extra_scope;
> +  LAMBDA_EXPR_DISCRIMINATOR (lambda_expr) = discriminator;
> +
> +  tree decl = TYPE_NAME (type);
> +  determine_visibility (decl);
> +  set_access_flags (decl, flags);
> +
> +  return convert_out (ctx->preserve (type));
> +}
> +
> +gcc_expr
> +plugin_build_lambda_expr (cc1_plugin::connection *self,
> +                         gcc_type closure_type_in)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree closure_type = convert_in (closure_type_in);
> +
> +  gcc_assert (LAMBDA_TYPE_P (closure_type));
> +
> +  tree lambda_expr = CLASSTYPE_LAMBDA_EXPR (closure_type);
> +
> +  tree lambda_object = build_lambda_object (lambda_expr);
> +
> +  return convert_out (ctx->preserve (lambda_object));
> +}
> +
> +gcc_decl
> +plugin_build_field (cc1_plugin::connection *,
> +                   const char *field_name,
> +                   gcc_type field_type_in,
> +                   enum gcc_cp_symbol_kind flags,
> +                   unsigned long bitsize,
> +                   unsigned long bitpos)
> +{
> +  tree record_or_union_type = current_class_type;
> +  tree field_type = convert_in (field_type_in);
> +
> +  gcc_assert (at_class_scope_p ());
> +  gcc_assert (RECORD_OR_UNION_CODE_P (TREE_CODE (record_or_union_type)));
> +  gcc_assert ((flags & GCC_CP_SYMBOL_MASK) == GCC_CP_SYMBOL_FIELD);
> +  gcc_assert ((flags & (~(GCC_CP_SYMBOL_MASK | GCC_CP_ACCESS_MASK
> +                         | GCC_CP_FLAG_MASK_FIELD))) == 0);
> +  gcc_assert ((flags & GCC_CP_ACCESS_MASK));
> +
> +  /* Note that gdb does not preserve the location of field decls, so
> +     we can't provide a decent location here.  */
> +  tree decl = build_decl (BUILTINS_LOCATION, FIELD_DECL,
> +                         get_identifier (field_name), field_type);
> +  DECL_FIELD_CONTEXT (decl) = record_or_union_type;
> +
> +  set_access_flags (decl, flags);
> +
> +  if ((flags & GCC_CP_FLAG_FIELD_MUTABLE) != 0)
> +    DECL_MUTABLE_P (decl) = 1;
> +
> +  if (TREE_CODE (field_type) == INTEGER_TYPE
> +      && TYPE_PRECISION (field_type) != bitsize)
> +    {
> +      DECL_BIT_FIELD_TYPE (decl) = field_type;
> +      TREE_TYPE (decl)
> +       = c_build_bitfield_integer_type (bitsize, TYPE_UNSIGNED (field_type));
> +    }
> +
> +  DECL_MODE (decl) = TYPE_MODE (TREE_TYPE (decl));
> +
> +  // There's no way to recover this from DWARF.
> +  SET_DECL_OFFSET_ALIGN (decl, TYPE_PRECISION (pointer_sized_int_node));
> +
> +  tree pos = bitsize_int (bitpos);
> +  pos_from_bit (&DECL_FIELD_OFFSET (decl), &DECL_FIELD_BIT_OFFSET (decl),
> +               DECL_OFFSET_ALIGN (decl), pos);
> +
> +  DECL_SIZE (decl) = bitsize_int (bitsize);
> +  DECL_SIZE_UNIT (decl) = size_int ((bitsize + BITS_PER_UNIT - 1)
> +                                   / BITS_PER_UNIT);
> +
> +  DECL_CHAIN (decl) = TYPE_FIELDS (record_or_union_type);
> +  TYPE_FIELDS (record_or_union_type) = decl;
> +
> +  return convert_out (decl);
> +}
> +
> +int
> +plugin_finish_class_type (cc1_plugin::connection *,
> +                         unsigned long size_in_bytes)
> +{
> +  tree record_or_union_type = current_class_type;
> +
> +  gcc_assert (RECORD_OR_UNION_CODE_P (TREE_CODE (record_or_union_type)));
> +
> +  finish_struct (record_or_union_type, NULL);
> +
> +  gcc_assert (compare_tree_int (TYPE_SIZE_UNIT (record_or_union_type),
> +                               size_in_bytes) == 0);
> +
> +  return 1;
> +}
> +
> +gcc_type
> +plugin_start_enum_type (cc1_plugin::connection *self,
> +                       const char *name,
> +                       gcc_type underlying_int_type_in,
> +                       enum gcc_cp_symbol_kind flags,
> +                       const char *filename,
> +                       unsigned int line_number)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree underlying_int_type = convert_in (underlying_int_type_in);
> +
> +  gcc_assert ((flags & GCC_CP_SYMBOL_MASK) == GCC_CP_SYMBOL_ENUM);
> +  gcc_assert ((flags & (~(GCC_CP_SYMBOL_MASK | GCC_CP_ACCESS_MASK
> +                         | GCC_CP_FLAG_MASK_ENUM))) == 0);
> +  gcc_assert (!(flags & GCC_CP_ACCESS_MASK) == !at_class_scope_p ());
> +
> +  if (underlying_int_type == error_mark_node)
> +    return convert_out (error_mark_node);
> +
> +  bool is_new_type = false;
> +
> +  tree id = name ? get_identifier (name) : make_anon_name ();
> +
> +  tree type = start_enum (id, NULL_TREE,
> +                         underlying_int_type,
> +                         /* attributes = */ NULL_TREE,
> +                         !!(flags & GCC_CP_FLAG_ENUM_SCOPED), &is_new_type);
> +
> +  gcc_assert (is_new_type);
> +
> +  source_location loc = ctx->get_source_location (filename, line_number);
> +  tree type_decl = TYPE_NAME (type);
> +  DECL_SOURCE_LOCATION (type_decl) = loc;
> +  SET_OPAQUE_ENUM_P (type, false);
> +
> +  set_access_flags (type_decl, flags);
> +
> +  return convert_out (ctx->preserve (type));
> +}
> +
> +gcc_decl
> +plugin_build_enum_constant (cc1_plugin::connection *,
> +                           gcc_type enum_type_in,
> +                           const char *name,
> +                           unsigned long value)
> +{
> +  tree enum_type = convert_in (enum_type_in);
> +
> +  gcc_assert (TREE_CODE (enum_type) == ENUMERAL_TYPE);
> +
> +  build_enumerator (get_identifier (name), build_int_cst (enum_type, value),
> +                   enum_type, NULL_TREE, BUILTINS_LOCATION);
> +
> +  return convert_out (TREE_VALUE (TYPE_VALUES (enum_type)));
> +}
> +
> +int
> +plugin_finish_enum_type (cc1_plugin::connection *,
> +                        gcc_type enum_type_in)
> +{
> +  tree enum_type = convert_in (enum_type_in);
> +
> +  finish_enum_value_list (enum_type);
> +  finish_enum (enum_type);
> +
> +  return 1;
> +}
> +
> +gcc_type
> +plugin_build_function_type (cc1_plugin::connection *self,
> +                           gcc_type return_type_in,
> +                           const struct gcc_type_array *argument_types_in,
> +                           int is_varargs)
> +{
> +  tree *argument_types;
> +  tree return_type = convert_in (return_type_in);
> +  tree result;
> +
> +  argument_types = new tree[argument_types_in->n_elements];
> +  for (int i = 0; i < argument_types_in->n_elements; ++i)
> +    argument_types[i] = convert_in (argument_types_in->elements[i]);
> +
> +  if (is_varargs)
> +    result = build_varargs_function_type_array (return_type,
> +                                               argument_types_in->n_elements,
> +                                               argument_types);
> +  else
> +    result = build_function_type_array (return_type,
> +                                       argument_types_in->n_elements,
> +                                       argument_types);
> +
> +  delete[] argument_types;
> +
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  return convert_out (ctx->preserve (result));
> +}
> +
> +#if 0
> +
> +gcc_type
> +plugin_add_function_default_args (cc1_plugin::connection *self,
> +                                 gcc_type function_type_in,
> +                                 const struct gcc_cp_function_args *defaults)
> +{
> +  tree function_type = convert_in (function_type_in);
> +
> +  gcc_assert (TREE_CODE (function_type) == FUNCTION_TYPE);
> +
> +  if (!defaults || !defaults->n_elements)
> +    return function_type_in;
> +
> +  tree pargs = TYPE_ARG_TYPES (function_type);
> +  tree nargs = NULL_TREE;
> +
> +  /* Build a reversed copy of the list of default-less arguments in
> +     NARGS.  At the end of the loop, PARGS will point to the end of
> +     the argument list, or to the first argument that had a default
> +     value.  */
> +  while (pargs && TREE_VALUE (pargs) != void_list_node
> +        && !TREE_PURPOSE (pargs))
> +    {
> +      nargs = tree_cons (NULL_TREE, TREE_VALUE (pargs), nargs);
> +      pargs = TREE_CHAIN (pargs);
> +    }
> +
> +  /* Set the defaults in the now-leading NARGS, taking into account
> +     that NARGS is reversed but DEFAULTS->elements isn't.  */
> +  tree ndargs = nargs;
> +  int i = defaults->n_elements;
> +  while (i--)
> +    {
> +      gcc_assert (ndargs);
> +      tree deflt = convert_in (defaults->elements[i]);
> +      if (!deflt)
> +       deflt = error_mark_node;
> +      TREE_PURPOSE (ndargs) = deflt;
> +      ndargs = TREE_CHAIN (ndargs);
> +    }
> +
> +  /* Finally, reverse NARGS, and append the remaining PARGS that
> +     already had defaults.  */
> +  nargs = nreverse (nargs);
> +  nargs = chainon (nargs, pargs);
> +
> +  tree result = build_function_type (TREE_TYPE (function_type), nargs);
> +
> +  /* Copy exceptions, attributes and whatnot.  */
> +  result = build_exception_variant (result,
> +                                   TYPE_RAISES_EXCEPTIONS (function_type));
> +  result = cp_build_type_attribute_variant (result,
> +                                           TYPE_ATTRIBUTES (function_type));
> +
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  return convert_out (ctx->preserve (result));
> +}
> +
> +int
> +plugin_set_deferred_function_default_args (cc1_plugin::connection *,
> +                                          gcc_decl function_in,
> +                                          const struct gcc_cp_function_args
> +                                          *defaults)
> +{
> +  tree function = convert_in (function_in);
> +
> +  gcc_assert (TREE_CODE (function) == FUNCTION_DECL);
> +
> +  if (!defaults || !defaults->n_elements)
> +    return 1;
> +
> +  tree arg = FUNCTION_FIRST_USER_PARMTYPE (function);
> +
> +  for (int i = 0; i < defaults->n_elements; i++)
> +    {
> +      while (arg && TREE_PURPOSE (arg) != error_mark_node)
> +       arg = TREE_CHAIN (arg);
> +
> +      if (!arg)
> +       return 0;
> +
> +      TREE_PURPOSE (arg) = convert_in (defaults->elements[i]);
> +      arg = TREE_CHAIN (arg);
> +    }
> +
> +  return 1;
> +}
> +
> +#endif
> +
> +gcc_decl
> +plugin_get_function_parameter_decl (cc1_plugin::connection *,
> +                                   gcc_decl function_in,
> +                                   int index)
> +{
> +  tree function = convert_in (function_in);
> +
> +  gcc_assert (TREE_CODE (function) == FUNCTION_DECL);
> +
> +  if (index == -1)
> +    {
> +      gcc_assert (TREE_CODE (TREE_TYPE (function)) == METHOD_TYPE);
> +
> +      return convert_out (DECL_ARGUMENTS (function));
> +    }
> +
> +  gcc_assert (index >= 0);
> +
> +  tree args = FUNCTION_FIRST_USER_PARM (function);
> +
> +  for (int i = 0; args && i < index; i++)
> +    args = DECL_CHAIN (args);
> +
> +  return convert_out (args);
> +}
> +
> +gcc_type
> +plugin_build_exception_spec_variant (cc1_plugin::connection *self,
> +                                    gcc_type function_type_in,
> +                                    const struct gcc_type_array *except_types_in)
> +{
> +  tree function_type = convert_in (function_type_in);
> +  tree except_types = NULL_TREE;
> +
> +  if (!except_types_in)
> +    except_types = noexcept_false_spec;
> +  else if (!except_types_in->n_elements)
> +    except_types = empty_except_spec;
> +  else
> +    for (int i = 0; i < except_types_in->n_elements; i++)
> +      except_types = add_exception_specifier (except_types,
> +                                             convert_in
> +                                             (except_types_in->elements[i]),
> +                                             0);
> +
> +  function_type = build_exception_variant (function_type,
> +                                          except_types);
> +
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  return convert_out (ctx->preserve (function_type));
> +}
> +
> +gcc_type
> +plugin_build_method_type (cc1_plugin::connection *self,
> +                         gcc_type class_type_in,
> +                         gcc_type func_type_in,
> +                         enum gcc_cp_qualifiers quals_in,
> +                         enum gcc_cp_ref_qualifiers rquals_in)
> +{
> +  tree class_type = convert_in (class_type_in);
> +  tree func_type = convert_in (func_type_in);
> +  cp_cv_quals quals = 0;
> +  cp_ref_qualifier rquals;
> +
> +  if ((quals_in & GCC_CP_QUALIFIER_CONST) != 0)
> +    quals |= TYPE_QUAL_CONST;
> +  if ((quals_in & GCC_CP_QUALIFIER_VOLATILE) != 0)
> +    quals |= TYPE_QUAL_VOLATILE;
> +  gcc_assert ((quals_in & GCC_CP_QUALIFIER_RESTRICT) == 0);
> +
> +  switch (rquals_in)
> +    {
> +    case GCC_CP_REF_QUAL_NONE:
> +      rquals = REF_QUAL_NONE;
> +      break;
> +    case GCC_CP_REF_QUAL_LVALUE:
> +      rquals = REF_QUAL_LVALUE;
> +      break;
> +    case GCC_CP_REF_QUAL_RVALUE:
> +      rquals = REF_QUAL_RVALUE;
> +      break;
> +    default:
> +      gcc_unreachable ();
> +    }
> +
> +  tree method_type = class_type
> +    ? build_memfn_type (func_type, class_type, quals, rquals)
> +    : apply_memfn_quals (func_type, quals, rquals);
> +
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  return convert_out (ctx->preserve (method_type));
> +}
> +
> +gcc_type
> +plugin_build_pointer_to_member_type (cc1_plugin::connection *self,
> +                                    gcc_type class_type_in,
> +                                    gcc_type member_type_in)
> +{
> +  tree class_type = convert_in (class_type_in);
> +  tree member_type = convert_in (member_type_in);
> +
> +  tree memptr_type = build_ptrmem_type (class_type, member_type);
> +
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  return convert_out (ctx->preserve (memptr_type));
> +}
> +
> +int
> +plugin_start_template_decl (cc1_plugin::connection *)
> +{
> +  begin_template_parm_list ();
> +
> +  TP_PARM_LIST = NULL_TREE;
> +
> +  return 1;
> +}
> +
> +gcc_decl
> +plugin_get_type_decl (cc1_plugin::connection *,
> +                     gcc_type type_in)
> +{
> +  tree type = convert_in (type_in);
> +
> +  tree name = TYPE_NAME (type);
> +  gcc_assert (name);
> +
> +  return convert_out (name);
> +}
> +
> +gcc_type
> +plugin_get_decl_type (cc1_plugin::connection *,
> +                     gcc_decl decl_in)
> +{
> +  tree decl = convert_in (decl_in);
> +
> +  tree type = TREE_TYPE (decl);
> +  gcc_assert (type);
> +
> +  return convert_out (type);
> +}
> +
> +gcc_type
> +plugin_build_type_template_parameter (cc1_plugin::connection *self,
> +                                     const char *id,
> +                                     int /* bool */ pack_p,
> +                                     gcc_type default_type,
> +                                     const char *filename,
> +                                     unsigned int line_number)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  source_location loc = ctx->get_source_location (filename, line_number);
> +
> +  gcc_assert (template_parm_scope_p ());
> +
> +  tree parm = finish_template_type_parm (class_type_node, get_identifier (id));
> +  parm = build_tree_list (convert_in (default_type), parm);
> +
> +  gcc_assert (!(pack_p && default_type));
> +
> +  /* Create a type and a decl for the type parm, and add the decl to
> +     TP_PARM_LIST.  */
> +  TP_PARM_LIST = process_template_parm (TP_PARM_LIST, loc, parm,
> +                                       /* is_non_type = */ false, pack_p);
> +
> +  /* Locate the decl of the newly-added, processed template parm.  */
> +  parm = TREE_VALUE (tree_last (TP_PARM_LIST));
> +
> +  /* Return its type.  */
> +  return convert_out (ctx->preserve (TREE_TYPE (parm)));
> +}
> +
> +gcc_utempl
> +plugin_build_template_template_parameter (cc1_plugin::connection *self,
> +                                         const char *id,
> +                                         int /* bool */ pack_p,
> +                                         gcc_utempl default_templ,
> +                                         const char *filename,
> +                                         unsigned int line_number)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  source_location loc = ctx->get_source_location (filename, line_number);
> +
> +  gcc_assert (template_parm_scope_p ());
> +
> +  /* Finish the template parm list that started this template parm.  */
> +  end_template_parm_list (TP_PARM_LIST);
> +
> +  gcc_assert (template_parm_scope_p ());
> +
> +  tree parm = finish_template_template_parm (class_type_node,
> +                                            get_identifier (id));
> +  parm = build_tree_list (convert_in (default_templ), parm);
> +
> +  gcc_assert (!(pack_p && default_templ));
> +
> +  /* Create a type and a decl for the template parm, and add the decl
> +     to TP_PARM_LIST.  */
> +  TP_PARM_LIST = process_template_parm (TP_PARM_LIST, loc, parm,
> +                                       /* is_non_type = */ false, pack_p);
> +
> +  /* Locate the decl of the newly-added, processed template parm.  */
> +  parm = TREE_VALUE (tree_last (TP_PARM_LIST));
> +
> +  return convert_out (ctx->preserve (parm));
> +}
> +
> +gcc_decl
> +plugin_build_value_template_parameter (cc1_plugin::connection *self,
> +                                      gcc_type type,
> +                                      const char *id,
> +                                      gcc_expr default_value,
> +                                      const char *filename,
> +                                      unsigned int line_number)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  source_location loc = ctx->get_source_location (filename, line_number);
> +
> +  gcc_assert (template_parm_scope_p ());
> +
> +  cp_declarator declarator;
> +  memset (&declarator, 0, sizeof (declarator));
> +  // &declarator = make_id_declarator (NULL, get_identifier (id), sfk_none):
> +  declarator.kind = cdk_id;
> +  declarator.u.id.qualifying_scope = NULL;
> +  declarator.u.id.unqualified_name = get_identifier (id);
> +  declarator.u.id.sfk = sfk_none;
> +
> +  cp_decl_specifier_seq declspec;
> +  memset (&declspec, 0, sizeof (declspec));
> +  // cp_parser_set_decl_spec_type (&declspec, convert_in (type), -token-, false):
> +  declspec.any_specifiers_p = declspec.any_type_specifiers_p = true;
> +  declspec.type = convert_in (type);
> +  declspec.locations[ds_type_spec] = loc;
> +
> +  tree parm = grokdeclarator (&declarator, &declspec, TPARM, 0, 0);
> +  parm = build_tree_list (convert_in (default_value), parm);
> +
> +  /* Create a type and a decl for the template parm, and add the decl
> +     to TP_PARM_LIST.  */
> +  TP_PARM_LIST = process_template_parm (TP_PARM_LIST, loc, parm,
> +                                       /* is_non_type = */ true, false);
> +
> +  /* Locate the decl of the newly-added, processed template parm.  */
> +  parm = TREE_VALUE (tree_last (TP_PARM_LIST));
> +
> +  return convert_out (ctx->preserve (parm));
> +}
> +
> +static tree
> +targlist (const gcc_cp_template_args *targs)
> +{
> +  int n = targs->n_elements;
> +  tree vec = make_tree_vec (n);
> +  while (n--)
> +    {
> +      switch (targs->kinds[n])
> +       {
> +       case GCC_CP_TPARG_VALUE:
> +         TREE_VEC_ELT (vec, n) = convert_in (targs->elements[n].value);
> +         break;
> +       case GCC_CP_TPARG_CLASS:
> +         TREE_VEC_ELT (vec, n) = convert_in (targs->elements[n].type);
> +         break;
> +       case GCC_CP_TPARG_TEMPL:
> +         TREE_VEC_ELT (vec, n) = convert_in (targs->elements[n].templ);
> +         break;
> +       case GCC_CP_TPARG_PACK:
> +         TREE_VEC_ELT (vec, n) = convert_in (targs->elements[n].pack);
> +         break;
> +       default:
> +         gcc_unreachable ();
> +       }
> +    }
> +  return vec;
> +}
> +
> +gcc_type
> +plugin_build_dependent_typename (cc1_plugin::connection *self,
> +                                gcc_type enclosing_type,
> +                                const char *id,
> +                                const gcc_cp_template_args *targs)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree type = convert_in (enclosing_type);
> +  tree name = get_identifier (id);
> +  if (targs)
> +    name = build_min_nt_loc (/*loc=*/0, TEMPLATE_ID_EXPR,
> +                            name, targlist (targs));
> +  tree res = make_typename_type (type, name, typename_type,
> +                                /*complain=*/tf_error);
> +  return convert_out (ctx->preserve (res));
> +}
> +
> +gcc_utempl
> +plugin_build_dependent_class_template (cc1_plugin::connection *self,
> +                                      gcc_type enclosing_type,
> +                                      const char *id)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree type = convert_in (enclosing_type);
> +  tree name = get_identifier (id);
> +  tree res = make_unbound_class_template (type, name, NULL_TREE,
> +                                         /*complain=*/tf_error);
> +  return convert_out (ctx->preserve (res));
> +}
> +
> +gcc_type
> +plugin_build_dependent_type_template_id (cc1_plugin::connection *self,
> +                                        gcc_utempl template_decl,
> +                                        const gcc_cp_template_args *targs)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree type = convert_in (template_decl);
> +  tree decl = finish_template_type (type, targlist (targs),
> +                                   /*entering_scope=*/false);
> +  return convert_out (ctx->preserve (TREE_TYPE (decl)));
> +}
> +
> +gcc_expr
> +plugin_build_dependent_expr (cc1_plugin::connection *self,
> +                            gcc_decl enclosing_scope,
> +                            enum gcc_cp_symbol_kind flags,
> +                            const char *name,
> +                            gcc_type conv_type_in,
> +                            const gcc_cp_template_args *targs)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree scope = convert_in (enclosing_scope);
> +  tree conv_type = convert_in (conv_type_in);
> +  tree identifier;
> +
> +  if (TREE_CODE (scope) != NAMESPACE_DECL)
> +    {
> +      tree type = TREE_TYPE (scope);
> +      gcc_assert (TYPE_NAME (type) == scope);
> +      scope = type;
> +    }
> +
> +  if (flags == (GCC_CP_SYMBOL_FUNCTION | GCC_CP_FLAG_SPECIAL_FUNCTION))
> +    {
> +      bool assop = false, convop = false;
> +      tree_code opcode = ERROR_MARK;
> +
> +      switch (CHARS2 (name[0], name[1]))
> +       {
> +       case CHARS2 ('C', 0x0): // ctor base declaration
> +       case CHARS2 ('C', ' '):
> +       case CHARS2 ('C', '1'):
> +       case CHARS2 ('C', '2'):
> +       case CHARS2 ('C', '4'):
> +         identifier = ctor_identifier;
> +         break;
> +       case CHARS2 ('D', 0x0): // dtor base declaration
> +       case CHARS2 ('D', ' '):
> +       case CHARS2 ('D', '0'):
> +       case CHARS2 ('D', '1'):
> +       case CHARS2 ('D', '2'):
> +       case CHARS2 ('D', '4'):
> +         gcc_assert (!targs);
> +         identifier = dtor_identifier;
> +         break;
> +       case CHARS2 ('n', 'w'): // operator new
> +         opcode = NEW_EXPR;
> +         break;
> +       case CHARS2 ('n', 'a'): // operator new[]
> +         opcode = VEC_NEW_EXPR;
> +         break;
> +       case CHARS2 ('d', 'l'): // operator delete
> +         opcode = DELETE_EXPR;
> +         break;
> +       case CHARS2 ('d', 'a'): // operator delete[]
> +         opcode = VEC_DELETE_EXPR;
> +         break;
> +       case CHARS2 ('p', 's'): // operator + (unary)
> +         opcode = PLUS_EXPR;
> +         break;
> +       case CHARS2 ('n', 'g'): // operator - (unary)
> +         opcode = MINUS_EXPR;
> +         break;
> +       case CHARS2 ('a', 'd'): // operator & (unary)
> +         opcode = BIT_AND_EXPR;
> +         break;
> +       case CHARS2 ('d', 'e'): // operator * (unary)
> +         opcode = MULT_EXPR;
> +         break;
> +       case CHARS2 ('c', 'o'): // operator ~
> +         opcode = BIT_NOT_EXPR;
> +         break;
> +       case CHARS2 ('p', 'l'): // operator +
> +         opcode = PLUS_EXPR;
> +         break;
> +       case CHARS2 ('m', 'i'): // operator -
> +         opcode = MINUS_EXPR;
> +         break;
> +       case CHARS2 ('m', 'l'): // operator *
> +         opcode = MULT_EXPR;
> +         break;
> +       case CHARS2 ('d', 'v'): // operator /
> +         opcode = TRUNC_DIV_EXPR;
> +         break;
> +       case CHARS2 ('r', 'm'): // operator %
> +         opcode = TRUNC_MOD_EXPR;
> +         break;
> +       case CHARS2 ('a', 'n'): // operator &
> +         opcode = BIT_AND_EXPR;
> +         break;
> +       case CHARS2 ('o', 'r'): // operator |
> +         opcode = BIT_IOR_EXPR;
> +         break;
> +       case CHARS2 ('e', 'o'): // operator ^
> +         opcode = BIT_XOR_EXPR;
> +         break;
> +       case CHARS2 ('a', 'S'): // operator =
> +         opcode = NOP_EXPR;
> +         assop = true;
> +         break;
> +       case CHARS2 ('p', 'L'): // operator +=
> +         opcode = PLUS_EXPR;
> +         assop = true;
> +         break;
> +       case CHARS2 ('m', 'I'): // operator -=
> +         opcode = MINUS_EXPR;
> +         assop = true;
> +         break;
> +       case CHARS2 ('m', 'L'): // operator *=
> +         opcode = MULT_EXPR;
> +         assop = true;
> +         break;
> +       case CHARS2 ('d', 'V'): // operator /=
> +         opcode = TRUNC_DIV_EXPR;
> +         assop = true;
> +         break;
> +       case CHARS2 ('r', 'M'): // operator %=
> +         opcode = TRUNC_MOD_EXPR;
> +         assop = true;
> +         break;
> +       case CHARS2 ('a', 'N'): // operator &=
> +         opcode = BIT_AND_EXPR;
> +         assop = true;
> +         break;
> +       case CHARS2 ('o', 'R'): // operator |=
> +         opcode = BIT_IOR_EXPR;
> +         assop = true;
> +         break;
> +       case CHARS2 ('e', 'O'): // operator ^=
> +         opcode = BIT_XOR_EXPR;
> +         assop = true;
> +         break;
> +       case CHARS2 ('l', 's'): // operator <<
> +         opcode = LSHIFT_EXPR;
> +         break;
> +       case CHARS2 ('r', 's'): // operator >>
> +         opcode = RSHIFT_EXPR;
> +         break;
> +       case CHARS2 ('l', 'S'): // operator <<=
> +         opcode = LSHIFT_EXPR;
> +         assop = true;
> +         break;
> +       case CHARS2 ('r', 'S'): // operator >>=
> +         opcode = RSHIFT_EXPR;
> +         assop = true;
> +         break;
> +       case CHARS2 ('e', 'q'): // operator ==
> +         opcode = EQ_EXPR;
> +         break;
> +       case CHARS2 ('n', 'e'): // operator !=
> +         opcode = NE_EXPR;
> +         break;
> +       case CHARS2 ('l', 't'): // operator <
> +         opcode = LT_EXPR;
> +         break;
> +       case CHARS2 ('g', 't'): // operator >
> +         opcode = GT_EXPR;
> +         break;
> +       case CHARS2 ('l', 'e'): // operator <=
> +         opcode = LE_EXPR;
> +         break;
> +       case CHARS2 ('g', 'e'): // operator >=
> +         opcode = GE_EXPR;
> +         break;
> +       case CHARS2 ('n', 't'): // operator !
> +         opcode = TRUTH_NOT_EXPR;
> +         break;
> +       case CHARS2 ('a', 'a'): // operator &&
> +         opcode = TRUTH_ANDIF_EXPR;
> +         break;
> +       case CHARS2 ('o', 'o'): // operator ||
> +         opcode = TRUTH_ORIF_EXPR;
> +         break;
> +       case CHARS2 ('p', 'p'): // operator ++
> +         opcode = POSTINCREMENT_EXPR;
> +         break;
> +       case CHARS2 ('m', 'm'): // operator --
> +         opcode = PREDECREMENT_EXPR;
> +         break;
> +       case CHARS2 ('c', 'm'): // operator ,
> +         opcode = COMPOUND_EXPR;
> +         break;
> +       case CHARS2 ('p', 'm'): // operator ->*
> +         opcode = MEMBER_REF;
> +         break;
> +       case CHARS2 ('p', 't'): // operator ->
> +         opcode = COMPONENT_REF;
> +         break;
> +       case CHARS2 ('c', 'l'): // operator ()
> +         opcode = CALL_EXPR;
> +         break;
> +       case CHARS2 ('i', 'x'): // operator []
> +         opcode = ARRAY_REF;
> +         break;
> +       case CHARS2 ('c', 'v'): // operator <T> (conversion operator)
> +         convop = true;
> +         identifier = mangle_conv_op_name_for_type (conv_type);
> +         break;
> +         // C++11-only:
> +       case CHARS2 ('l', 'i'): // operator "" <id>
> +         {
> +           char *id = (char *)name + 2;
> +           bool freeid = false;
> +           if (*id >= '0' && *id <= '9')
> +             {
> +               unsigned len = 0;
> +               do
> +                 {
> +                   len *= 10;
> +                   len += id[0] - '0';
> +                   id++;
> +                 }
> +               while (*id && *id >= '0' && *id <= '9');
> +               id = xstrndup (id, len);
> +               freeid = true;
> +             }
> +           identifier = cp_literal_operator_id (id);
> +           if (freeid)
> +             free (id);
> +         }
> +         break;
> +       case CHARS2 ('q', 'u'): // ternary operator, not overloadable.
> +       default:
> +         gcc_unreachable ();
> +       }
> +
> +      gcc_assert (convop || !conv_type);
> +
> +      if (opcode != ERROR_MARK)
> +       {
> +         if (assop)
> +           identifier = cp_assignment_operator_id (opcode);
> +         else
> +           identifier = cp_operator_id (opcode);
> +       }
> +
> +      gcc_assert (identifier);
> +    }
> +  else
> +    {
> +      gcc_assert (flags == GCC_CP_SYMBOL_MASK);
> +      gcc_assert (!conv_type);
> +      identifier = get_identifier (name);
> +    }
> +  tree res = identifier;
> +  if (!scope)
> +    res = lookup_name_real (res, 0, 0, true, 0, 0);
> +  else if (!TYPE_P (scope) || !dependent_scope_p (scope))
> +    {
> +      res = lookup_qualified_name (scope, res, false, true);
> +      /* We've already resolved the name in the scope, so skip the
> +        build_qualified_name call below.  */
> +      scope = NULL;
> +    }
> +  if (targs)
> +    res = lookup_template_function (res, targlist (targs));
> +  if (scope)
> +    res = build_qualified_name (NULL_TREE, scope, res, !!targs);
> +  return convert_out (ctx->preserve (res));
> +}
> +
> +gcc_expr
> +plugin_build_literal_expr (cc1_plugin::connection *self,
> +                          gcc_type type, unsigned long value)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree t = convert_in (type);
> +  tree val = build_int_cst_type (t, (unsigned HOST_WIDE_INT) value);
> +  return convert_out (ctx->preserve (val));
> +}
> +
> +gcc_expr
> +plugin_build_decl_expr (cc1_plugin::connection *self,
> +                       gcc_decl decl_in,
> +                       int qualified_p)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree decl = convert_in (decl_in);
> +  gcc_assert (DECL_P (decl));
> +  tree result = decl;
> +  if (qualified_p)
> +    {
> +      gcc_assert (DECL_CLASS_SCOPE_P (decl));
> +      result = build_offset_ref (DECL_CONTEXT (decl), decl,
> +                                /*address_p=*/true, tf_error);
> +    }
> +  return convert_out (ctx->preserve (result));
> +}
> +
> +gcc_expr
> +plugin_build_unary_expr (cc1_plugin::connection *self,
> +                        const char *unary_op,
> +                        gcc_expr operand)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree op0 = convert_in (operand);
> +  tree_code opcode = ERROR_MARK;
> +  bool global_scope_p = false;
> +
> + once_more:
> +  switch (CHARS2 (unary_op[0], unary_op[1]))
> +    {
> +    case CHARS2 ('p', 's'): // operator + (unary)
> +      opcode = UNARY_PLUS_EXPR;
> +      break;
> +    case CHARS2 ('n', 'g'): // operator - (unary)
> +      opcode = NEGATE_EXPR;
> +      break;
> +    case CHARS2 ('a', 'd'): // operator & (unary)
> +      opcode = ADDR_EXPR;
> +      break;
> +    case CHARS2 ('d', 'e'): // operator * (unary)
> +      opcode = INDIRECT_REF;
> +      break;
> +    case CHARS2 ('c', 'o'): // operator ~
> +      opcode = BIT_NOT_EXPR;
> +      break;
> +    case CHARS2 ('n', 't'): // operator !
> +      opcode = TRUTH_NOT_EXPR;
> +      break;
> +    case CHARS2 ('p', 'p'): // operator ++
> +      opcode = unary_op[2] == '_' ? PREINCREMENT_EXPR : POSTINCREMENT_EXPR;
> +      break;
> +    case CHARS2 ('m', 'm'): // operator --
> +      opcode = unary_op[2] == '_' ? PREDECREMENT_EXPR : POSTDECREMENT_EXPR;
> +      break;
> +    case CHARS2 ('n', 'x'): // noexcept
> +      opcode = NOEXCEPT_EXPR;
> +      break;
> +    case CHARS2 ('t', 'w'): // throw
> +      gcc_assert (op0);
> +      opcode = THROW_EXPR;
> +      break;
> +    case CHARS2 ('t', 'r'): // rethrow
> +      gcc_assert (!op0);
> +      opcode = THROW_EXPR;
> +      break;
> +    case CHARS2 ('t', 'e'): // typeid (value)
> +      opcode = TYPEID_EXPR;
> +      break;
> +    case CHARS2 ('s', 'z'): // sizeof (value)
> +      opcode = SIZEOF_EXPR;
> +      break;
> +    case CHARS2 ('a', 'z'): // alignof (value)
> +      opcode = ALIGNOF_EXPR;
> +      break;
> +    case CHARS2 ('g', 's'): // global scope (for delete, delete[])
> +      gcc_assert (!global_scope_p);
> +      global_scope_p = true;
> +      unary_op += 2;
> +      goto once_more;
> +    case CHARS2 ('d', 'l'): // delete
> +      opcode = DELETE_EXPR;
> +      break;
> +    case CHARS2 ('d', 'a'): // delete[]
> +      opcode = VEC_DELETE_EXPR;
> +      break;
> +    case CHARS2 ('s', 'p'): // pack...
> +      opcode = EXPR_PACK_EXPANSION;
> +      break;
> +    case CHARS2 ('s', 'Z'): // sizeof...(pack)
> +      opcode = TYPE_PACK_EXPANSION; // Not really, but let's use its code.
> +      break;
> +
> +      /* FIXME: __real__, __imag__?  */
> +
> +    default:
> +      gcc_unreachable ();
> +    }
> +
> +  gcc_assert (!global_scope_p
> +             || opcode == DELETE_EXPR || opcode == VEC_DELETE_EXPR);
> +
> +  processing_template_decl++;
> +  bool template_dependent_p = op0
> +    && (type_dependent_expression_p (op0)
> +       || value_dependent_expression_p (op0));
> +  if (!template_dependent_p)
> +    processing_template_decl--;
> +
> +  tree result;
> +
> +  gcc_assert (op0 || opcode == THROW_EXPR);
> +
> +  switch (opcode)
> +    {
> +    case NOEXCEPT_EXPR:
> +      result = finish_noexcept_expr (op0, tf_error);
> +      break;
> +
> +    case THROW_EXPR:
> +      result = build_throw (op0);
> +      break;
> +
> +    case TYPEID_EXPR:
> +      result = build_typeid (op0, tf_error);
> +      break;
> +
> +    case SIZEOF_EXPR:
> +    case ALIGNOF_EXPR:
> +      result = cxx_sizeof_or_alignof_expr (op0, opcode, true);
> +      break;
> +
> +    case DELETE_EXPR:
> +    case VEC_DELETE_EXPR:
> +      result = delete_sanity (op0, NULL_TREE, opcode == VEC_DELETE_EXPR,
> +                             global_scope_p, tf_error);
> +      break;
> +
> +    case EXPR_PACK_EXPANSION:
> +      result = make_pack_expansion (op0);
> +      break;
> +
> +      // We're using this for sizeof...(pack).  */
> +    case TYPE_PACK_EXPANSION:
> +      result = make_pack_expansion (op0);
> +      PACK_EXPANSION_SIZEOF_P (result) = true;
> +      break;
> +
> +    default:
> +      result = build_x_unary_op (/*loc=*/0, opcode, op0, tf_error);
> +      break;
> +    }
> +
> +  if (template_dependent_p)
> +    processing_template_decl--;
> +
> +  return convert_out (ctx->preserve (result));
> +}
> +
> +gcc_expr
> +plugin_build_binary_expr (cc1_plugin::connection *self,
> +                         const char *binary_op,
> +                         gcc_expr operand1,
> +                         gcc_expr operand2)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree op0 = convert_in (operand1);
> +  tree op1 = convert_in (operand2);
> +  tree_code opcode = ERROR_MARK;
> +
> +  switch (CHARS2 (binary_op[0], binary_op[1]))
> +    {
> +    case CHARS2 ('p', 'l'): // operator +
> +      opcode = PLUS_EXPR;
> +      break;
> +    case CHARS2 ('m', 'i'): // operator -
> +      opcode = MINUS_EXPR;
> +      break;
> +    case CHARS2 ('m', 'l'): // operator *
> +      opcode = MULT_EXPR;
> +      break;
> +    case CHARS2 ('d', 'v'): // operator /
> +      opcode = TRUNC_DIV_EXPR;
> +      break;
> +    case CHARS2 ('r', 'm'): // operator %
> +      opcode = TRUNC_MOD_EXPR;
> +      break;
> +    case CHARS2 ('a', 'n'): // operator &
> +      opcode = BIT_AND_EXPR;
> +      break;
> +    case CHARS2 ('o', 'r'): // operator |
> +      opcode = BIT_IOR_EXPR;
> +      break;
> +    case CHARS2 ('e', 'o'): // operator ^
> +      opcode = BIT_XOR_EXPR;
> +      break;
> +    case CHARS2 ('l', 's'): // operator <<
> +      opcode = LSHIFT_EXPR;
> +      break;
> +    case CHARS2 ('r', 's'): // operator >>
> +      opcode = RSHIFT_EXPR;
> +      break;
> +    case CHARS2 ('e', 'q'): // operator ==
> +      opcode = EQ_EXPR;
> +      break;
> +    case CHARS2 ('n', 'e'): // operator !=
> +      opcode = NE_EXPR;
> +      break;
> +    case CHARS2 ('l', 't'): // operator <
> +      opcode = LT_EXPR;
> +      break;
> +    case CHARS2 ('g', 't'): // operator >
> +      opcode = GT_EXPR;
> +      break;
> +    case CHARS2 ('l', 'e'): // operator <=
> +      opcode = LE_EXPR;
> +      break;
> +    case CHARS2 ('g', 'e'): // operator >=
> +      opcode = GE_EXPR;
> +      break;
> +    case CHARS2 ('a', 'a'): // operator &&
> +      opcode = TRUTH_ANDIF_EXPR;
> +      break;
> +    case CHARS2 ('o', 'o'): // operator ||
> +      opcode = TRUTH_ORIF_EXPR;
> +      break;
> +    case CHARS2 ('c', 'm'): // operator ,
> +      opcode = COMPOUND_EXPR;
> +      break;
> +    case CHARS2 ('p', 'm'): // operator ->*
> +      opcode = MEMBER_REF;
> +      break;
> +    case CHARS2 ('p', 't'): // operator ->
> +      opcode = INDIRECT_REF; // Not really!  This will stand for
> +                            // INDIRECT_REF followed by COMPONENT_REF
> +                            // later on.
> +      break;
> +    case CHARS2 ('i', 'x'): // operator []
> +      opcode = ARRAY_REF;
> +      break;
> +    case CHARS2 ('d', 's'): // operator .*
> +      opcode = DOTSTAR_EXPR;
> +      break;
> +    case CHARS2 ('d', 't'): // operator .
> +      opcode = COMPONENT_REF;
> +      break;
> +
> +    default:
> +      gcc_unreachable ();
> +    }
> +
> +  processing_template_decl++;
> +  bool template_dependent_p = type_dependent_expression_p (op0)
> +    || value_dependent_expression_p (op0)
> +    || type_dependent_expression_p (op1)
> +    || value_dependent_expression_p (op1);
> +  if (!template_dependent_p)
> +    processing_template_decl--;
> +
> +  tree result;
> +
> +  switch (opcode)
> +    {
> +    case INDIRECT_REF: // This is actually a "->".
> +      op0 = build_x_arrow (/*loc=*/0, op0, tf_error);
> +      /* Fall through.  */
> +    case COMPONENT_REF:
> +      result = finish_class_member_access_expr (op0, op1,
> +                                               /*template_p=*/false,
> +                                               tf_error);
> +      break;
> +
> +    default:
> +      result = build_x_binary_op (/*loc=*/0, opcode, op0, ERROR_MARK,
> +                                 op1, ERROR_MARK, NULL, tf_error);
> +      break;
> +    }
> +
> +  if (template_dependent_p)
> +    processing_template_decl--;
> +
> +  return convert_out (ctx->preserve (result));
> +}
> +
> +gcc_expr
> +plugin_build_ternary_expr (cc1_plugin::connection *self,
> +                          const char *ternary_op,
> +                          gcc_expr operand1,
> +                          gcc_expr operand2,
> +                          gcc_expr operand3)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree op0 = convert_in (operand1);
> +  tree op1 = convert_in (operand2);
> +  tree op2 = convert_in (operand3);
> +  gcc_assert (CHARS2 (ternary_op[0], ternary_op[1])
> +             == CHARS2 ('q', 'u')); // ternary operator
> +
> +  processing_template_decl++;
> +  bool template_dependent_p = type_dependent_expression_p (op0)
> +    || value_dependent_expression_p (op0)
> +    || type_dependent_expression_p (op1)
> +    || value_dependent_expression_p (op1)
> +    || type_dependent_expression_p (op2)
> +    || value_dependent_expression_p (op2);
> +  if (!template_dependent_p)
> +    processing_template_decl--;
> +
> +  tree val = build_x_conditional_expr (/*loc=*/0, op0, op1, op2, tf_error);
> +
> +  if (template_dependent_p)
> +    processing_template_decl--;
> +
> +  return convert_out (ctx->preserve (val));
> +}
> +
> +gcc_expr
> +plugin_build_unary_type_expr (cc1_plugin::connection *self,
> +                             const char *unary_op,
> +                             gcc_type operand)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree type = convert_in (operand);
> +  tree_code opcode = ERROR_MARK;
> +
> +  switch (CHARS2 (unary_op[0], unary_op[1]))
> +    {
> +    case CHARS2 ('t', 'i'): // typeid (type)
> +      opcode = TYPEID_EXPR;
> +      break;
> +
> +    case CHARS2 ('s', 't'): // sizeof (type)
> +      opcode = SIZEOF_EXPR;
> +      break;
> +    case CHARS2 ('a', 't'): // alignof (type)
> +      opcode = ALIGNOF_EXPR;
> +      break;
> +
> +    case CHARS2 ('s', 'Z'): // sizeof...(pack)
> +      opcode = TYPE_PACK_EXPANSION; // Not really, but let's use its code.
> +      break;
> +
> +      // FIXME: do we have to handle "sp", for the size of a captured
> +      // template parameter pack from an alias template, taking
> +      // multiple template arguments?
> +
> +    default:
> +      gcc_unreachable ();
> +    }
> +
> +  processing_template_decl++;
> +  bool template_dependent_p = dependent_type_p (type);
> +  if (!template_dependent_p)
> +    processing_template_decl--;
> +
> +  tree result;
> +
> +  switch (opcode)
> +    {
> +    case TYPEID_EXPR:
> +      result = get_typeid (type, tf_error);
> +      break;
> +
> +      // We're using this for sizeof...(pack).  */
> +    case TYPE_PACK_EXPANSION:
> +      result = make_pack_expansion (type);
> +      PACK_EXPANSION_SIZEOF_P (result) = true;
> +      break;
> +
> +    default:
> +      result = cxx_sizeof_or_alignof_type (type, opcode, true);
> +    }
> +
> +  if (template_dependent_p)
> +    processing_template_decl--;
> +
> +  return convert_out (ctx->preserve (result));
> +}
> +
> +gcc_expr
> +plugin_build_cast_expr (cc1_plugin::connection *self,
> +                       const char *binary_op,
> +                       gcc_type operand1,
> +                       gcc_expr operand2)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree (*build_cast)(tree type, tree expr, tsubst_flags_t complain) = NULL;
> +  tree type = convert_in (operand1);
> +  tree expr = convert_in (operand2);
> +
> +  switch (CHARS2 (binary_op[0], binary_op[1]))
> +    {
> +    case CHARS2 ('d', 'c'): // dynamic_cast
> +      build_cast = build_dynamic_cast;
> +      break;
> +
> +    case CHARS2 ('s', 'c'): // static_cast
> +      build_cast = build_static_cast;
> +      break;
> +
> +    case CHARS2 ('c', 'c'): // const_cast
> +      build_cast = build_const_cast;
> +      break;
> +
> +    case CHARS2 ('r', 'c'): // reinterpret_cast
> +      build_cast = build_reinterpret_cast;
> +      break;
> +
> +    case CHARS2 ('c', 'v'): // C cast, conversion with one argument
> +      build_cast = cp_build_c_cast;
> +      break;
> +
> +    default:
> +      gcc_unreachable ();
> +    }
> +
> +  processing_template_decl++;
> +  bool template_dependent_p = dependent_type_p (type)
> +    || type_dependent_expression_p (expr)
> +    || value_dependent_expression_p (expr);
> +  if (!template_dependent_p)
> +    processing_template_decl--;
> +
> +  tree val = build_cast (type, expr, tf_error);
> +
> +  if (template_dependent_p)
> +    processing_template_decl--;
> +
> +  return convert_out (ctx->preserve (val));
> +}
> +
> +static inline vec<tree, va_gc> *
> +args_to_tree_vec (const struct gcc_cp_function_args *args_in)
> +{
> +  vec<tree, va_gc> *args = make_tree_vector ();
> +  for (int i = 0; i < args_in->n_elements; i++)
> +    vec_safe_push (args, convert_in (args_in->elements[i]));
> +  return args;
> +}
> +
> +static inline tree
> +args_to_tree_list (const struct gcc_cp_function_args *args_in)
> +{
> +  tree args, *tail = &args;
> +  for (int i = 0; i < args_in->n_elements; i++)
> +    {
> +      *tail = build_tree_list (NULL, convert_in (args_in->elements[i]));
> +      tail = &TREE_CHAIN (*tail);
> +    }
> +  return args;
> +}
> +
> +static inline vec<constructor_elt, va_gc> *
> +args_to_ctor_elts (const struct gcc_cp_function_args *args_in)
> +{
> +  vec<constructor_elt, va_gc> *args = NULL;
> +  for (int i = 0; i < args_in->n_elements; i++)
> +    CONSTRUCTOR_APPEND_ELT (args, NULL_TREE, convert_in (args_in->elements[i]));
> +  return args;
> +}
> +
> +gcc_expr
> +plugin_build_expression_list_expr (cc1_plugin::connection *self,
> +                                  const char *conv_op,
> +                                  gcc_type type_in,
> +                                  const struct gcc_cp_function_args *values_in)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree type = convert_in (type_in);
> +  tree args;
> +  tree result;
> +
> +  switch (CHARS2 (conv_op[0], conv_op[1]))
> +    {
> +    case CHARS2 ('c', 'v'): // conversion with parenthesized expression list
> +      gcc_assert (TYPE_P (type));
> +      args = args_to_tree_list (values_in);
> +      result = build_functional_cast (type, args, tf_error);
> +      break;
> +
> +    case CHARS2 ('t', 'l'): // conversion with braced expression list
> +      gcc_assert (type);
> +      gcc_assert (TYPE_P (type));
> +      args = make_node (CONSTRUCTOR);
> +      CONSTRUCTOR_ELTS (args) = args_to_ctor_elts (values_in);
> +      CONSTRUCTOR_IS_DIRECT_INIT (args) = 1;
> +      result = finish_compound_literal (type, args, tf_error);
> +      break;
> +
> +    case CHARS2 ('i', 'l'): // untyped braced expression list
> +      gcc_assert (!type);
> +      result = make_node (CONSTRUCTOR);
> +      CONSTRUCTOR_ELTS (result) = args_to_ctor_elts (values_in);
> +      break;
> +
> +    default:
> +      gcc_unreachable ();
> +    }
> +
> +  return convert_out (ctx->preserve (result));
> +}
> +
> +gcc_expr
> +plugin_build_new_expr (cc1_plugin::connection *self,
> +                      const char *new_op,
> +                      const struct gcc_cp_function_args *placement_in,
> +                      gcc_type type_in,
> +                      const struct gcc_cp_function_args *initializer_in)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree type = convert_in (type_in);
> +  vec<tree, va_gc> *placement = NULL, *initializer = NULL;
> +  bool global_scope_p = false;
> +  tree nelts = NULL;
> +
> +  if (placement_in)
> +    placement = args_to_tree_vec (placement_in);
> +  if (initializer_in)
> +    initializer = args_to_tree_vec (initializer_in);
> +
> +  gcc_assert (TYPE_P (type));
> +
> + once_more:
> +  switch (CHARS2 (new_op[0], new_op[1]))
> +    {
> +    case CHARS2 ('g', 's'):
> +      gcc_assert (!global_scope_p);
> +      global_scope_p = true;
> +      new_op += 2;
> +      goto once_more;
> +
> +    case CHARS2 ('n', 'w'): // non-array new
> +      gcc_assert (TREE_CODE (type) != ARRAY_TYPE);
> +      break;
> +
> +    case CHARS2 ('n', 'a'): // array new
> +      gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
> +      gcc_assert (TYPE_DOMAIN (type));
> +      {
> +       // Compute the length of the outermost array type, then discard it.
> +       tree maxelt = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
> +       tree eltype = TREE_TYPE (maxelt);
> +       tree onecst = integer_one_node;
> +
> +       processing_template_decl++;
> +       bool template_dependent_p = value_dependent_expression_p (maxelt)
> +         || type_dependent_expression_p (maxelt);
> +       if (!template_dependent_p)
> +         {
> +           processing_template_decl--;
> +           onecst = fold_convert (eltype, onecst);
> +         }
> +
> +       nelts = fold_build2 (PLUS_EXPR, eltype, nelts, onecst);
> +
> +       if (template_dependent_p)
> +         processing_template_decl--;
> +
> +       type = TREE_TYPE (type);
> +      }
> +      break;
> +
> +    default:
> +      gcc_unreachable ();
> +    }
> +
> +  processing_template_decl++;
> +  bool template_dependent_p = dependent_type_p (type)
> +    || value_dependent_expression_p (nelts)
> +    || (placement
> +       && any_type_dependent_arguments_p (placement))
> +    || (initializer
> +       && any_type_dependent_arguments_p (initializer));
> +  if (!template_dependent_p)
> +    processing_template_decl--;
> +
> +  tree result = build_new (&placement, type, nelts, &initializer,
> +                          global_scope_p, tf_error);
> +
> +  if (template_dependent_p)
> +    processing_template_decl--;
> +
> +  if (placement != NULL)
> +    release_tree_vector (placement);
> +  if (initializer != NULL)
> +    release_tree_vector (initializer);
> +
> +  return convert_out (ctx->preserve (result));
> +}
> +
> +gcc_expr
> +plugin_build_call_expr (cc1_plugin::connection *self,
> +                       gcc_expr callable_in, int qualified_p,
> +                       const struct gcc_cp_function_args *args_in)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree callable = convert_in (callable_in);
> +  tree call_expr;
> +
> +  vec<tree, va_gc> *args = args_to_tree_vec (args_in);
> +
> +  bool koenig_p = false;
> +  if (!qualified_p && !args->is_empty ())
> +    {
> +      if (identifier_p (callable))
> +       koenig_p = true;
> +      else if (is_overloaded_fn (callable))
> +       {
> +         tree fn = get_first_fn (callable);
> +         fn = STRIP_TEMPLATE (fn);
> +
> +         if (!DECL_FUNCTION_MEMBER_P (fn)
> +             && !DECL_LOCAL_FUNCTION_P (fn))
> +           koenig_p = true;
> +       }
> +    }
> +
> +  if (koenig_p && !any_type_dependent_arguments_p (args))
> +    callable = perform_koenig_lookup (callable, args, tf_none);
> +
> +  if (TREE_CODE (callable) == COMPONENT_REF)
> +    {
> +      tree object = TREE_OPERAND (callable, 0);
> +      tree memfn = TREE_OPERAND (callable, 1);
> +
> +      if (type_dependent_expression_p (object)
> +         || (!BASELINK_P (memfn) && TREE_CODE (memfn) != FIELD_DECL)
> +         || type_dependent_expression_p (memfn)
> +         || any_type_dependent_arguments_p (args))
> +       call_expr = build_nt_call_vec (callable, args);
> +      else if (BASELINK_P (memfn))
> +       call_expr = build_new_method_call (object, memfn, &args, NULL_TREE,
> +                                          qualified_p
> +                                          ? LOOKUP_NORMAL|LOOKUP_NONVIRTUAL
> +                                          : LOOKUP_NORMAL,
> +                                          NULL, tf_none);
> +      else
> +       call_expr = finish_call_expr (callable, &args, false, false, tf_none);
> +    }
> +  else if (TREE_CODE (callable) == OFFSET_REF
> +          || TREE_CODE (callable) == MEMBER_REF
> +          || TREE_CODE (callable) == DOTSTAR_EXPR)
> +    call_expr = build_offset_ref_call_from_tree (callable, &args, tf_none);
> +  else
> +    call_expr = finish_call_expr (callable, &args,
> +                                 !!qualified_p, koenig_p, tf_none);
> +
> +  release_tree_vector (args);
> +  return convert_out (ctx->preserve (call_expr));
> +}
> +
> +gcc_type
> +plugin_get_expr_type (cc1_plugin::connection *self,
> +                     gcc_expr operand)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree op0 = convert_in (operand);
> +  tree type;
> +  if (op0)
> +    type = TREE_TYPE (op0);
> +  else
> +    {
> +      type = make_decltype_auto ();
> +      AUTO_IS_DECLTYPE (type) = true;
> +    }
> +  return convert_out (ctx->preserve (type));
> +}
> +
> +gcc_decl
> +plugin_build_function_template_specialization (cc1_plugin::connection *self,
> +                                              gcc_decl template_decl,
> +                                              const gcc_cp_template_args *targs,
> +                                              gcc_address address,
> +                                              const char *filename,
> +                                              unsigned int line_number)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  source_location loc = ctx->get_source_location (filename, line_number);
> +  tree name = convert_in (template_decl);
> +  tree targsl = targlist (targs);
> +
> +  tree decl = tsubst (name, targsl, tf_error, NULL_TREE);
> +  DECL_SOURCE_LOCATION (decl) = loc;
> +
> +  record_decl_address (ctx, build_decl_addr_value (decl, address));
> +
> +  return convert_out (ctx->preserve (decl));
> +}
> +
> +gcc_decl
> +plugin_build_class_template_specialization (cc1_plugin::connection *self,
> +                                           gcc_decl template_decl,
> +                                           const gcc_cp_template_args *args,
> +                                           const char *filename,
> +                                           unsigned int line_number)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  source_location loc = ctx->get_source_location (filename, line_number);
> +  tree name = convert_in (template_decl);
> +
> +  tree tdecl = finish_template_type (name, targlist (args), false);;
> +  DECL_SOURCE_LOCATION (tdecl) = loc;
> +
> +  return convert_out (ctx->preserve (tdecl));
> +}
> +
> +/* Return a builtin type associated with BUILTIN_NAME.  */
> +
> +static tree
> +safe_lookup_builtin_type (const char *builtin_name)
> +{
> +  tree result = NULL_TREE;
> +
> +  if (!builtin_name)
> +    return result;
> +
> +  result = identifier_global_value (get_identifier (builtin_name));
> +
> +  if (!result)
> +    return result;
> +
> +  gcc_assert (TREE_CODE (result) == TYPE_DECL);
> +  result = TREE_TYPE (result);
> +  return result;
> +}
> +
> +gcc_type
> +plugin_get_int_type (cc1_plugin::connection *self,
> +                    int is_unsigned, unsigned long size_in_bytes,
> +                    const char *builtin_name)
> +{
> +  tree result;
> +
> +  if (builtin_name)
> +    {
> +      result = safe_lookup_builtin_type (builtin_name);
> +      gcc_assert (!result || TREE_CODE (result) == INTEGER_TYPE);
> +    }
> +  else
> +    result = c_common_type_for_size (BITS_PER_UNIT * size_in_bytes,
> +                                    is_unsigned);
> +
> +  if (result == NULL_TREE)
> +    result = error_mark_node;
> +  else
> +    {
> +      gcc_assert (!TYPE_UNSIGNED (result) == !is_unsigned);
> +      gcc_assert (TREE_CODE (TYPE_SIZE (result)) == INTEGER_CST);
> +      gcc_assert (TYPE_PRECISION (result) == BITS_PER_UNIT * size_in_bytes);
> +
> +      plugin_context *ctx = static_cast<plugin_context *> (self);
> +      ctx->preserve (result);
> +    }
> +  return convert_out (result);
> +}
> +
> +gcc_type
> +plugin_get_char_type (cc1_plugin::connection *)
> +{
> +  return convert_out (char_type_node);
> +}
> +
> +gcc_type
> +plugin_get_float_type (cc1_plugin::connection *,
> +                      unsigned long size_in_bytes,
> +                      const char *builtin_name)
> +{
> +  if (builtin_name)
> +    {
> +      tree result = safe_lookup_builtin_type (builtin_name);
> +
> +      if (!result)
> +       return convert_out (error_mark_node);
> +
> +      gcc_assert (TREE_CODE (result) == REAL_TYPE);
> +      gcc_assert (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (result));
> +
> +      return convert_out (result);
> +    }
> +
> +  if (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (float_type_node))
> +    return convert_out (float_type_node);
> +  if (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (double_type_node))
> +    return convert_out (double_type_node);
> +  if (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (long_double_type_node))
> +    return convert_out (long_double_type_node);
> +  return convert_out (error_mark_node);
> +}
> +
> +gcc_type
> +plugin_get_void_type (cc1_plugin::connection *)
> +{
> +  return convert_out (void_type_node);
> +}
> +
> +gcc_type
> +plugin_get_bool_type (cc1_plugin::connection *)
> +{
> +  return convert_out (boolean_type_node);
> +}
> +
> +gcc_type
> +plugin_get_nullptr_type (cc1_plugin::connection *)
> +{
> +  return convert_out (nullptr_type_node);
> +}
> +
> +gcc_expr
> +plugin_get_nullptr_constant (cc1_plugin::connection *)
> +{
> +  return convert_out (nullptr_node);
> +}
> +
> +gcc_type
> +plugin_build_array_type (cc1_plugin::connection *self,
> +                        gcc_type element_type_in, int num_elements)
> +{
> +  tree element_type = convert_in (element_type_in);
> +  tree result;
> +
> +  if (num_elements == -1)
> +    result = build_array_type (element_type, NULL_TREE);
> +  else
> +    result = build_array_type_nelts (element_type, num_elements);
> +
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  return convert_out (ctx->preserve (result));
> +}
> +
> +gcc_type
> +plugin_build_dependent_array_type (cc1_plugin::connection *self,
> +                                  gcc_type element_type_in,
> +                                  gcc_expr num_elements_in)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree element_type = convert_in (element_type_in);
> +  tree size = convert_in (num_elements_in);
> +  tree name = get_identifier ("dependent array type");
> +
> +  processing_template_decl++;
> +  bool template_dependent_p = dependent_type_p (element_type)
> +    || type_dependent_expression_p (size)
> +    || value_dependent_expression_p (size);
> +  if (!template_dependent_p)
> +    processing_template_decl--;
> +
> +  tree itype = compute_array_index_type (name, size, tf_error);
> +  tree type = build_cplus_array_type (element_type, itype);
> +
> +  if (template_dependent_p)
> +    processing_template_decl--;
> +
> +  return convert_out (ctx->preserve (type));
> +}
> +
> +gcc_type
> +plugin_build_vla_array_type (cc1_plugin::connection *self,
> +                            gcc_type element_type_in,
> +                            const char *upper_bound_name)
> +{
> +  tree element_type = convert_in (element_type_in);
> +  tree upper_bound = lookup_name (get_identifier (upper_bound_name));
> +  tree size = fold_build2 (PLUS_EXPR, TREE_TYPE (upper_bound), upper_bound,
> +                          build_one_cst (TREE_TYPE (upper_bound)));
> +  tree range = compute_array_index_type (NULL_TREE, size,
> +                                        tf_error);
> +
> +  tree result = build_cplus_array_type (element_type, range);
> +
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  return convert_out (ctx->preserve (result));
> +}
> +
> +gcc_type
> +plugin_build_qualified_type (cc1_plugin::connection *,
> +                            gcc_type unqualified_type_in,
> +                            enum gcc_cp_qualifiers qualifiers)
> +{
> +  tree unqualified_type = convert_in (unqualified_type_in);
> +  cp_cv_quals quals = 0;
> +
> +  if ((qualifiers & GCC_CP_QUALIFIER_CONST) != 0)
> +    quals |= TYPE_QUAL_CONST;
> +  if ((qualifiers & GCC_CP_QUALIFIER_VOLATILE) != 0)
> +    quals |= TYPE_QUAL_VOLATILE;
> +  if ((qualifiers & GCC_CP_QUALIFIER_RESTRICT) != 0)
> +    quals |= TYPE_QUAL_RESTRICT;
> +
> +  gcc_assert ((TREE_CODE (unqualified_type) != METHOD_TYPE
> +              && TREE_CODE (unqualified_type) != REFERENCE_TYPE)
> +             || quals == 0);
> +
> +  return convert_out (build_qualified_type (unqualified_type, quals));
> +}
> +
> +gcc_type
> +plugin_build_complex_type (cc1_plugin::connection *self,
> +                          gcc_type base_type)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  return convert_out (ctx->preserve (build_complex_type (convert_in (base_type))));
> +}
> +
> +gcc_type
> +plugin_build_vector_type (cc1_plugin::connection *self,
> +                         gcc_type base_type, int nunits)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  return convert_out (ctx->preserve (build_vector_type (convert_in (base_type),
> +                                                       nunits)));
> +}
> +
> +int
> +plugin_build_constant (cc1_plugin::connection *self, gcc_type type_in,
> +                      const char *name, unsigned long value,
> +                      const char *filename, unsigned int line_number)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree cst, decl;
> +  tree type = convert_in (type_in);
> +
> +  cst = build_int_cst (type, value);
> +  if (!TYPE_READONLY (type))
> +    type = build_qualified_type (type, TYPE_QUAL_CONST);
> +  decl = build_decl (ctx->get_source_location (filename, line_number),
> +                    VAR_DECL, get_identifier (name), type);
> +  TREE_STATIC (decl) = 1;
> +  TREE_READONLY (decl) = 1;
> +  cp_finish_decl (decl, cst, true, NULL, LOOKUP_ONLYCONVERTING);
> +  safe_pushdecl_maybe_friend (decl, false);
> +
> +  return 1;
> +}
> +
> +gcc_type
> +plugin_error (cc1_plugin::connection *,
> +             const char *message)
> +{
> +  error ("%s", message);
> +  return convert_out (error_mark_node);
> +}
> +
> +int
> +plugin_add_static_assert (cc1_plugin::connection *self,
> +                         gcc_expr condition_in,
> +                         const char *errormsg,
> +                         const char *filename,
> +                         unsigned int line_number)
> +{
> +  plugin_context *ctx = static_cast<plugin_context *> (self);
> +  tree condition = convert_in (condition_in);
> +
> +  if (!errormsg)
> +    errormsg = "";
> +
> +  tree message = build_string (strlen (errormsg) + 1, errormsg);
> +
> +  TREE_TYPE (message) = char_array_type_node;
> +  fix_string_type (message);
> +
> +  source_location loc = ctx->get_source_location (filename, line_number);
> +
> +  bool member_p = at_class_scope_p ();
> +
> +  finish_static_assert (condition, message, loc, member_p);
> +
> +  return 1;
> +}
> +
> +
> +
> +// Perform GC marking.
> +
> +static void
> +gc_mark (void *, void *)
> +{
> +  if (current_context != NULL)
> +    current_context->mark ();
> +}
> +
> +#ifdef __GNUC__
> +#pragma GCC visibility push(default)
> +#endif
> +
> +int
> +plugin_init (struct plugin_name_args *plugin_info,
> +            struct plugin_gcc_version *)
> +{
> +  long fd = -1;
> +  for (int i = 0; i < plugin_info->argc; ++i)
> +    {
> +      if (strcmp (plugin_info->argv[i].key, "fd") == 0)
> +       {
> +         char *tail;
> +         errno = 0;
> +         fd = strtol (plugin_info->argv[i].value, &tail, 0);
> +         if (*tail != '\0' || errno != 0)
> +           fatal_error (input_location,
> +                        "%s: invalid file descriptor argument to plugin",
> +                        plugin_info->base_name);
> +         break;
> +       }
> +    }
> +  if (fd == -1)
> +    fatal_error (input_location,
> +                "%s: required plugin argument %<fd%> is missing",
> +                plugin_info->base_name);
> +
> +  current_context = new plugin_context (fd);
> +
> +  // Handshake.
> +  cc1_plugin::protocol_int version;
> +  if (!current_context->require ('H')
> +      || ! ::cc1_plugin::unmarshall (current_context, &version))
> +    fatal_error (input_location,
> +                "%s: handshake failed", plugin_info->base_name);
> +  if (version != GCC_CP_FE_VERSION_0)
> +    fatal_error (input_location,
> +                "%s: unknown version in handshake", plugin_info->base_name);
> +
> +  register_callback (plugin_info->base_name, PLUGIN_PRAGMAS,
> +                    plugin_init_extra_pragmas, NULL);
> +  register_callback (plugin_info->base_name, PLUGIN_PRE_GENERICIZE,
> +                    rewrite_decls_to_addresses, NULL);
> +  register_callback (plugin_info->base_name, PLUGIN_GGC_MARKING,
> +                    gc_mark, NULL);
> +
> +  lang_hooks.print_error_function = plugin_print_error_function;
> +
> +#define GCC_METHOD0(R, N)                      \
> +  {                                            \
> +    cc1_plugin::callback_ftype *fun            \
> +      = cc1_plugin::callback<R, plugin_ ## N>; \
> +    current_context->add_callback (# N, fun);  \
> +  }
> +#define GCC_METHOD1(R, N, A)                           \
> +  {                                                    \
> +    cc1_plugin::callback_ftype *fun                    \
> +      = cc1_plugin::callback<R, A, plugin_ ## N>;      \
> +    current_context->add_callback (# N, fun);          \
> +  }
> +#define GCC_METHOD2(R, N, A, B)                                \
> +  {                                                    \
> +    cc1_plugin::callback_ftype *fun                    \
> +      = cc1_plugin::callback<R, A, B, plugin_ ## N>;   \
> +    current_context->add_callback (# N, fun);          \
> +  }
> +#define GCC_METHOD3(R, N, A, B, C)                     \
> +  {                                                    \
> +    cc1_plugin::callback_ftype *fun                    \
> +      = cc1_plugin::callback<R, A, B, C, plugin_ ## N>;        \
> +    current_context->add_callback (# N, fun);          \
> +  }
> +#define GCC_METHOD4(R, N, A, B, C, D)          \
> +  {                                            \
> +    cc1_plugin::callback_ftype *fun            \
> +      = cc1_plugin::callback<R, A, B, C, D,    \
> +                            plugin_ ## N>;     \
> +    current_context->add_callback (# N, fun);  \
> +  }
> +#define GCC_METHOD5(R, N, A, B, C, D, E)       \
> +  {                                            \
> +    cc1_plugin::callback_ftype *fun            \
> +      = cc1_plugin::callback<R, A, B, C, D, E, \
> +                            plugin_ ## N>;     \
> +    current_context->add_callback (# N, fun);  \
> +  }
> +#define GCC_METHOD7(R, N, A, B, C, D, E, F, G)         \
> +  {                                                    \
> +    cc1_plugin::callback_ftype *fun                    \
> +      = cc1_plugin::callback<R, A, B, C, D, E, F, G,   \
> +                            plugin_ ## N>;             \
> +    current_context->add_callback (# N, fun);          \
> +  }
> +
> +#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
> +
> +  return 0;
> +}
> diff --git a/libcc1/libcp1plugin.sym b/libcc1/libcp1plugin.sym
> new file mode 100644
> index 0000000..05d0f7b
> --- /dev/null
> +++ b/libcc1/libcp1plugin.sym
> @@ -0,0 +1,2 @@
> +plugin_init
> +plugin_is_GPL_compatible
> diff --git a/libcc1/marshall-c.hh b/libcc1/marshall-c.hh
> new file mode 100644
> index 0000000..8120c15
> --- /dev/null
> +++ b/libcc1/marshall-c.hh
> @@ -0,0 +1,59 @@
> +/* Marshalling and unmarshalling of C-specific types.
> +   Copyright (C) 2014-2017 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC 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, or (at your option) any later
> +version.
> +
> +GCC 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 GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#ifndef CC1_PLUGIN_MARSHALL_C_HH
> +#define CC1_PLUGIN_MARSHALL_C_HH
> +
> +#include "marshall.hh"
> +#include "gcc-c-interface.h"
> +
> +namespace cc1_plugin
> +{
> +  status
> +  unmarshall (connection *conn, enum gcc_c_symbol_kind *result)
> +  {
> +    protocol_int p;
> +    if (!unmarshall_intlike (conn, &p))
> +      return FAIL;
> +    *result = (enum gcc_c_symbol_kind) p;
> +    return OK;
> +  }
> +
> +  status
> +  unmarshall (connection *conn, enum gcc_c_oracle_request *result)
> +  {
> +    protocol_int p;
> +    if (!unmarshall_intlike (conn, &p))
> +      return FAIL;
> +    *result = (enum gcc_c_oracle_request) p;
> +    return OK;
> +  }
> +
> +  status
> +  unmarshall (connection *conn, enum gcc_qualifiers *result)
> +  {
> +    protocol_int p;
> +    if (!unmarshall_intlike (conn, &p))
> +      return FAIL;
> +    *result = (enum gcc_qualifiers) p;
> +    return OK;
> +  }
> +}
> +
> +#endif // CC1_PLUGIN_MARSHALL_C_HH
> diff --git a/libcc1/marshall-cp.hh b/libcc1/marshall-cp.hh
> new file mode 100644
> index 0000000..eec80f3
> --- /dev/null
> +++ b/libcc1/marshall-cp.hh
> @@ -0,0 +1,271 @@
> +/* Marshalling and unmarshalling of C++-specific types.
> +   Copyright (C) 2014-2017 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC 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, or (at your option) any later
> +version.
> +
> +GCC 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 GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#ifndef CC1_PLUGIN_MARSHALL_CXX_HH
> +#define CC1_PLUGIN_MARSHALL_CXX_HH
> +
> +#include "marshall.hh"
> +#include "gcc-cp-interface.h"
> +
> +namespace cc1_plugin
> +{
> +  status
> +  unmarshall (connection *conn, enum gcc_cp_symbol_kind *result)
> +  {
> +    protocol_int p;
> +    if (!unmarshall_intlike (conn, &p))
> +      return FAIL;
> +    *result = (enum gcc_cp_symbol_kind) p;
> +    return OK;
> +  }
> +
> +  status
> +  unmarshall (connection *conn, enum gcc_cp_oracle_request *result)
> +  {
> +    protocol_int p;
> +    if (!unmarshall_intlike (conn, &p))
> +      return FAIL;
> +    *result = (enum gcc_cp_oracle_request) p;
> +    return OK;
> +  }
> +
> +  status
> +  unmarshall (connection *conn, enum gcc_cp_qualifiers *result)
> +  {
> +    protocol_int p;
> +    if (!unmarshall_intlike (conn, &p))
> +      return FAIL;
> +    *result = (enum gcc_cp_qualifiers) p;
> +    return OK;
> +  }
> +
> +  status
> +  unmarshall (connection *conn, enum gcc_cp_ref_qualifiers *result)
> +  {
> +    protocol_int p;
> +    if (!unmarshall_intlike (conn, &p))
> +      return FAIL;
> +    *result = (enum gcc_cp_ref_qualifiers) p;
> +    return OK;
> +  }
> +
> +  // Send a gcc_vbase_array marker followed by the array.
> +  status
> +  marshall (connection *conn, const gcc_vbase_array *a)
> +  {
> +    size_t len;
> +
> +    if (a)
> +      len = a->n_elements;
> +    else
> +      len = (size_t)-1;
> +
> +    if (!marshall_array_start (conn, 'v', len))
> +      return FAIL;
> +
> +    if (!a)
> +      return OK;
> +
> +    if (!marshall_array_elmts (conn, len * sizeof (a->elements[0]),
> +                              a->elements))
> +      return FAIL;
> +
> +    return marshall_array_elmts (conn, len * sizeof (a->flags[0]),
> +                                a->flags);
> +  }
> +
> +  // Read a gcc_vbase_array marker, followed by a gcc_vbase_array.  The
> +  // resulting array must be freed by the caller, using 'delete[]' on
> +  // elements and virtualp, and 'delete' on the array object itself.
> +  status
> +  unmarshall (connection *conn, struct gcc_vbase_array **result)
> +  {
> +    size_t len;
> +
> +    if (!unmarshall_array_start (conn, 'v', &len))
> +      return FAIL;
> +
> +    if (len == (size_t)-1)
> +      {
> +       *result = NULL;
> +       return OK;
> +      }
> +
> +    struct gcc_vbase_array *gva = new gcc_vbase_array;
> +
> +    gva->n_elements = len;
> +    gva->elements = new gcc_type[len];
> +
> +    if (!unmarshall_array_elmts (conn,
> +                                len * sizeof (gva->elements[0]),
> +                                gva->elements))
> +      {
> +       delete[] gva->elements;
> +       delete gva;
> +       return FAIL;
> +      }
> +
> +    gva->flags = new enum gcc_cp_symbol_kind[len];
> +
> +    if (!unmarshall_array_elmts (conn,
> +                                len * sizeof (gva->flags[0]),
> +                                gva->flags))
> +      {
> +       delete[] gva->flags;
> +       delete[] gva->elements;
> +       delete gva;
> +       return FAIL;
> +      }
> +
> +    *result = gva;
> +    return OK;
> +  }
> +
> +  // Send a gcc_cp_template_args marker followed by the array.
> +  status
> +  marshall (connection *conn, const gcc_cp_template_args *a)
> +  {
> +    size_t len;
> +
> +    if (a)
> +      len = a->n_elements;
> +    else
> +      len = (size_t)-1;
> +
> +    if (!marshall_array_start (conn, 't', len))
> +      return FAIL;
> +
> +    if (!a)
> +      return OK;
> +
> +    if (!marshall_array_elmts (conn, len * sizeof (a->kinds[0]),
> +                              a->kinds))
> +      return FAIL;
> +
> +    return marshall_array_elmts (conn, len * sizeof (a->elements[0]),
> +                                a->elements);
> +  }
> +
> +  // Read a gcc_vbase_array marker, followed by a gcc_vbase_array.  The
> +  // resulting array must be freed by the caller, using 'delete[]' on
> +  // elements and virtualp, and 'delete' on the array object itself.
> +  status
> +  unmarshall (connection *conn, struct gcc_cp_template_args **result)
> +  {
> +    size_t len;
> +
> +    if (!unmarshall_array_start (conn, 't', &len))
> +      return FAIL;
> +
> +    if (len == (size_t)-1)
> +      {
> +       *result = NULL;
> +       return OK;
> +      }
> +
> +    struct gcc_cp_template_args *gva = new gcc_cp_template_args;
> +
> +    gva->n_elements = len;
> +    gva->kinds = new char[len];
> +
> +    if (!unmarshall_array_elmts (conn,
> +                                len * sizeof (gva->kinds[0]),
> +                                gva->kinds))
> +      {
> +       delete[] gva->kinds;
> +       delete gva;
> +       return FAIL;
> +      }
> +
> +    gva->elements = new gcc_cp_template_arg[len];
> +
> +    if (!unmarshall_array_elmts (conn,
> +                                len * sizeof (gva->elements[0]),
> +                                gva->elements))
> +      {
> +       delete[] gva->elements;
> +       delete[] gva->kinds;
> +       delete gva;
> +       return FAIL;
> +      }
> +
> +    *result = gva;
> +    return OK;
> +  }
> +
> +  // Send a gcc_cp_function_args marker followed by the array.
> +  status
> +  marshall (connection *conn, const gcc_cp_function_args *a)
> +  {
> +    size_t len;
> +
> +    if (a)
> +      len = a->n_elements;
> +    else
> +      len = (size_t)-1;
> +
> +    if (!marshall_array_start (conn, 'd', len))
> +      return FAIL;
> +
> +    if (!a)
> +      return OK;
> +
> +    return marshall_array_elmts (conn, len * sizeof (a->elements[0]),
> +                                a->elements);
> +  }
> +
> +  // Read a gcc_cp_function_args marker, followed by a
> +  // gcc_cp_function_args.  The resulting array must be freed
> +  // by the caller, using 'delete[]' on elements and virtualp, and
> +  // 'delete' on the array object itself.
> +  status
> +  unmarshall (connection *conn, struct gcc_cp_function_args **result)
> +  {
> +    size_t len;
> +
> +    if (!unmarshall_array_start (conn, 'd', &len))
> +      return FAIL;
> +
> +    if (len == (size_t)-1)
> +      {
> +       *result = NULL;
> +       return OK;
> +      }
> +
> +    struct gcc_cp_function_args *gva = new gcc_cp_function_args;
> +
> +    gva->n_elements = len;
> +    gva->elements = new gcc_expr[len];
> +
> +    if (!unmarshall_array_elmts (conn,
> +                                len * sizeof (gva->elements[0]),
> +                                gva->elements))
> +      {
> +       delete[] gva->elements;
> +       delete gva;
> +       return FAIL;
> +      }
> +
> +    *result = gva;
> +
> +    return OK;
> +  }
> +}
> +
> +#endif // CC1_PLUGIN_MARSHALL_CP_HH
> diff --git a/libcc1/marshall.cc b/libcc1/marshall.cc
> index 1f2d284..cf53cf7 100644
> --- a/libcc1/marshall.cc
> +++ b/libcc1/marshall.cc
> @@ -50,36 +50,6 @@ cc1_plugin::unmarshall_intlike (connection *conn, unsigned long long *result)
>  }
>
>  cc1_plugin::status
> -cc1_plugin::unmarshall (connection *conn, enum gcc_c_symbol_kind *result)
> -{
> -  protocol_int p;
> -  if (!unmarshall_intlike (conn, &p))
> -    return FAIL;
> -  *result = (enum gcc_c_symbol_kind) p;
> -  return OK;
> -}
> -
> -cc1_plugin::status
> -cc1_plugin::unmarshall (connection *conn, enum gcc_c_oracle_request *result)
> -{
> -  protocol_int p;
> -  if (!unmarshall_intlike (conn, &p))
> -    return FAIL;
> -  *result = (enum gcc_c_oracle_request) p;
> -  return OK;
> -}
> -
> -cc1_plugin::status
> -cc1_plugin::unmarshall (connection *conn, enum gcc_qualifiers *result)
> -{
> -  protocol_int p;
> -  if (!unmarshall_intlike (conn, &p))
> -    return FAIL;
> -  *result = (enum gcc_qualifiers) p;
> -  return OK;
> -}
> -
> -cc1_plugin::status
>  cc1_plugin::marshall (connection *conn, const char *str)
>  {
>    if (!conn->send ('s'))
> @@ -128,39 +98,98 @@ cc1_plugin::unmarshall (connection *conn, char **result)
>  }
>
>  cc1_plugin::status
> -cc1_plugin::marshall (connection *conn, const gcc_type_array *a)
> +cc1_plugin::marshall_array_start (connection *conn, char id,
> +                                 size_t n_elements)
>  {
> -  if (!conn->send ('a'))
> +  if (!conn->send (id))
>      return FAIL;
>
> -  unsigned long long r = a->n_elements;
> +  unsigned long long r = n_elements;
>    if (!conn->send (&r, sizeof (r)))
>      return FAIL;
>
> -  return conn->send (a->elements, r * sizeof (a->elements[0]));
> +  return OK;
>  }
>
>  cc1_plugin::status
> -cc1_plugin::unmarshall (connection *conn, gcc_type_array **result)
> +cc1_plugin::marshall_array_elmts (connection *conn, size_t n_bytes,
> +                                 void *elements)
> +{
> +  return conn->send (elements, n_bytes);
> +}
> +
> +cc1_plugin::status
> +cc1_plugin::unmarshall_array_start (connection *conn, char id,
> +                                   size_t *n_elements)
>  {
>    unsigned long long len;
>
> -  if (!conn->require ('a'))
> +  if (!conn->require (id))
>      return FAIL;
>    if (!conn->get (&len, sizeof (len)))
>      return FAIL;
>
> -  *result = new gcc_type_array;
> +  *n_elements = len;
> +
> +  return OK;
> +}
> +
> +cc1_plugin::status
> +cc1_plugin::unmarshall_array_elmts (connection *conn, size_t n_bytes,
> +                                   void *elements)
> +{
> +  return conn->get (elements, n_bytes);
> +}
> +
> +cc1_plugin::status
> +cc1_plugin::marshall (connection *conn, const gcc_type_array *a)
> +{
> +  size_t len;
> +
> +  if (a)
> +    len = a->n_elements;
> +  else
> +    len = (size_t)-1;
> +
> +  if (!marshall_array_start (conn, 'a', len))
> +    return FAIL;
> +
> +  if (!a)
> +    return OK;
> +
> +  return marshall_array_elmts (conn, len * sizeof (a->elements[0]),
> +                              a->elements);
> +}
> +
> +cc1_plugin::status
> +cc1_plugin::unmarshall (connection *conn, gcc_type_array **result)
> +{
> +  size_t len;
> +
> +  if (!unmarshall_array_start (conn, 'a', &len))
> +    return FAIL;
> +
> +  if (len == (size_t)-1)
> +    {
> +      *result = NULL;
> +      return OK;
> +    }
> +
> +  gcc_type_array *gta = new gcc_type_array;
>
> -  (*result)->n_elements = len;
> -  (*result)->elements = new gcc_type[len];
> +  gta->n_elements = len;
> +  gta->elements = new gcc_type[len];
>
> -  if (!conn->get ((*result)->elements, len * sizeof ((*result)->elements[0])))
> +  if (!unmarshall_array_elmts (conn,
> +                              len * sizeof (gta->elements[0]),
> +                              gta->elements))
>      {
> -      delete[] (*result)->elements;
> +      delete[] gta->elements;
>        delete *result;
>        return FAIL;
>      }
>
> +  *result = gta;
> +
>    return OK;
>  }
> diff --git a/libcc1/marshall.hh b/libcc1/marshall.hh
> index cf539c0..d238f3a 100644
> --- a/libcc1/marshall.hh
> +++ b/libcc1/marshall.hh
> @@ -21,7 +21,7 @@ along with GCC; see the file COPYING3.  If not see
>  #define CC1_PLUGIN_MARSHALL_HH
>
>  #include "status.hh"
> -#include "gcc-c-interface.h"
> +#include "gcc-interface.h"
>
>  namespace cc1_plugin
>  {
> @@ -44,6 +44,12 @@ namespace cc1_plugin
>    // integer store it in the out argument.
>    status unmarshall_intlike (connection *, protocol_int *);
>
> +  status marshall_array_start (connection *, char, size_t);
> +  status marshall_array_elmts (connection *, size_t, void *);
> +
> +  status unmarshall_array_start (connection *, char, size_t *);
> +  status unmarshall_array_elmts (connection *, size_t, void *);
> +
>    // A template function that can handle marshalling various integer
>    // objects to the connection.
>    template<typename T>
> @@ -67,13 +73,6 @@ namespace cc1_plugin
>      return OK;
>    }
>
> -  // Unmarshallers for some specific enum types.  With C++11 we
> -  // wouldn't need these, as we could add type traits to the scalar
> -  // unmarshaller.
> -  status unmarshall (connection *, enum gcc_c_symbol_kind *);
> -  status unmarshall (connection *, enum gcc_qualifiers *);
> -  status unmarshall (connection *, enum gcc_c_oracle_request *);
> -
>    // Send a string type marker followed by a string.
>    status marshall (connection *, const char *);
>
> diff --git a/libcc1/names.cc b/libcc1/names.cc
> index 2ac1fb4..3cd1a1b 100644
> --- a/libcc1/names.cc
> +++ b/libcc1/names.cc
> @@ -21,21 +21,27 @@ along with GCC; see the file COPYING3.  If not see
>  #include "names.hh"
>
>  #define GCC_METHOD0(R, N) \
> -  const char *cc1_plugin::N = # N;
> +  const char *cc1_plugin::LANG::N = # N;
>  #define GCC_METHOD1(R, N, A) \
> -  const char *cc1_plugin::N = # N;
> +  const char *cc1_plugin::LANG::N = # N;
>  #define GCC_METHOD2(R, N, A, B) \
> -  const char *cc1_plugin::N = # N;
> +  const char *cc1_plugin::LANG::N = # N;
>  #define GCC_METHOD3(R, N, A, B, C) \
> -  const char *cc1_plugin::N = # N;
> +  const char *cc1_plugin::LANG::N = # N;
>  #define GCC_METHOD4(R, N, A, B, C, D) \
> -  const char *cc1_plugin::N = # N;
> +  const char *cc1_plugin::LANG::N = # N;
>  #define GCC_METHOD5(R, N, A, B, C, D, E) \
> -  const char *cc1_plugin::N = # N;
> +  const char *cc1_plugin::LANG::N = # N;
>  #define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \
> -  const char *cc1_plugin::N = # N;
> +  const char *cc1_plugin::LANG::N = # N;
>
> +#define LANG c
>  #include "gcc-c-fe.def"
> +#undef LANG
> +
> +#define LANG cp
> +#include "gcc-cp-fe.def"
> +#undef LANG
>
>  #undef GCC_METHOD0
>  #undef GCC_METHOD1
> diff --git a/libcc1/names.hh b/libcc1/names.hh
> index 79069c3..d358e69 100644
> --- a/libcc1/names.hh
> +++ b/libcc1/names.hh
> @@ -22,10 +22,6 @@ along with GCC; see the file COPYING3.  If not see
>
>  namespace cc1_plugin
>  {
> -  // This code defines global string constants, one for each method in
> -  // gcc-c-fe.def.  This is needed so that they can be used as
> -  // template arguments elsewhere.
> -
>  #define GCC_METHOD0(R, N) \
>    extern const char *N;
>  #define GCC_METHOD1(R, N, A) \
> @@ -41,7 +37,21 @@ namespace cc1_plugin
>  #define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \
>    extern const char *N;
>
> +  namespace c
> +  {
> +  // This code defines global string constants, one for each method in
> +  // gcc-c-fe.def.  This is needed so that they can be used as
> +  // template arguments elsewhere.
>  #include "gcc-c-fe.def"
> +  }
> +
> +  namespace cp
> +  {
> +  // This code defines global string constants, one for each method in
> +  // gcc-cp-fe.def.  This is needed so that they can be used as
> +  // template arguments elsewhere.
> +#include "gcc-cp-fe.def"
> +  }
>
>  #undef GCC_METHOD0
>  #undef GCC_METHOD1
> diff --git a/libcc1/plugin.cc b/libcc1/plugin.cc
> deleted file mode 100644
> index a30cc6b..0000000
> --- a/libcc1/plugin.cc
> +++ /dev/null
> @@ -1,921 +0,0 @@
> -/* Library interface to C front end
> -   Copyright (C) 2014-2017 Free Software Foundation, Inc.
> -
> -   This file is part of GCC.
> -
> -   GCC 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, or (at your option) any later
> -   version.
> -
> -   GCC 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 GCC; see the file COPYING3.  If not see
> -   <http://www.gnu.org/licenses/>.  */
> -
> -#include <cc1plugin-config.h>
> -
> -#undef PACKAGE_NAME
> -#undef PACKAGE_STRING
> -#undef PACKAGE_TARNAME
> -#undef PACKAGE_VERSION
> -
> -#include "../gcc/config.h"
> -
> -#undef PACKAGE_NAME
> -#undef PACKAGE_STRING
> -#undef PACKAGE_TARNAME
> -#undef PACKAGE_VERSION
> -
> -#include "gcc-plugin.h"
> -#include "system.h"
> -#include "coretypes.h"
> -#include "stringpool.h"
> -
> -#include "gcc-interface.h"
> -#include "hash-set.h"
> -#include "machmode.h"
> -#include "vec.h"
> -#include "double-int.h"
> -#include "input.h"
> -#include "alias.h"
> -#include "symtab.h"
> -#include "options.h"
> -#include "wide-int.h"
> -#include "inchash.h"
> -#include "tree.h"
> -#include "fold-const.h"
> -#include "stor-layout.h"
> -#include "c-tree.h"
> -#include "toplev.h"
> -#include "timevar.h"
> -#include "hash-table.h"
> -#include "tm.h"
> -#include "c-family/c-pragma.h"
> -#include "c-lang.h"
> -#include "diagnostic.h"
> -#include "langhooks.h"
> -#include "langhooks-def.h"
> -
> -#include "callbacks.hh"
> -#include "connection.hh"
> -#include "rpc.hh"
> -
> -#ifdef __GNUC__
> -#pragma GCC visibility push(default)
> -#endif
> -int plugin_is_GPL_compatible;
> -#ifdef __GNUC__
> -#pragma GCC visibility pop
> -#endif
> -
> -
> -
> -// This is put into the lang hooks when the plugin starts.
> -
> -static void
> -plugin_print_error_function (diagnostic_context *context, const char *file,
> -                            diagnostic_info *diagnostic)
> -{
> -  if (current_function_decl != NULL_TREE
> -      && DECL_NAME (current_function_decl) != NULL_TREE
> -      && strcmp (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),
> -                GCC_FE_WRAPPER_FUNCTION) == 0)
> -    return;
> -  lhd_print_error_function (context, file, diagnostic);
> -}
> -
> -
> -
> -static unsigned long long
> -convert_out (tree t)
> -{
> -  return (unsigned long long) (uintptr_t) t;
> -}
> -
> -static tree
> -convert_in (unsigned long long v)
> -{
> -  return (tree) (uintptr_t) v;
> -}
> -
> -
> -
> -struct decl_addr_value
> -{
> -  tree decl;
> -  tree address;
> -};
> -
> -struct decl_addr_hasher : free_ptr_hash<decl_addr_value>
> -{
> -  static inline hashval_t hash (const decl_addr_value *);
> -  static inline bool equal (const decl_addr_value *, const decl_addr_value *);
> -};
> -
> -inline hashval_t
> -decl_addr_hasher::hash (const decl_addr_value *e)
> -{
> -  return IDENTIFIER_HASH_VALUE (DECL_NAME (e->decl));
> -}
> -
> -inline bool
> -decl_addr_hasher::equal (const decl_addr_value *p1, const decl_addr_value *p2)
> -{
> -  return p1->decl == p2->decl;
> -}
> -
> -
> -
> -struct string_hasher : nofree_ptr_hash<const char>
> -{
> -  static inline hashval_t hash (const char *s)
> -  {
> -    return htab_hash_string (s);
> -  }
> -
> -  static inline bool equal (const char *p1, const char *p2)
> -  {
> -    return strcmp (p1, p2) == 0;
> -  }
> -};
> -
> -
> -
> -// A wrapper for pushdecl that doesn't let gdb have a chance to
> -// instantiate a symbol.
> -
> -static void
> -pushdecl_safe (tree decl)
> -{
> -  void (*save) (enum c_oracle_request, tree identifier);
> -
> -  save = c_binding_oracle;
> -  c_binding_oracle = NULL;
> -  pushdecl (decl);
> -  c_binding_oracle = save;
> -}
> -
> -
> -
> -struct plugin_context : public cc1_plugin::connection
> -{
> -  plugin_context (int fd);
> -
> -  // Map decls to addresses.
> -  hash_table<decl_addr_hasher> address_map;
> -
> -  // A collection of trees that are preserved for the GC.
> -  hash_table< nofree_ptr_hash<tree_node> > preserved;
> -
> -  // File name cache.
> -  hash_table<string_hasher> file_names;
> -
> -  // Perform GC marking.
> -  void mark ();
> -
> -  // Preserve a tree during the plugin's operation.
> -  tree preserve (tree t)
> -  {
> -    tree_node **slot = preserved.find_slot (t, INSERT);
> -    *slot = t;
> -    return t;
> -  }
> -
> -  source_location get_source_location (const char *filename,
> -                                      unsigned int line_number)
> -  {
> -    if (filename == NULL)
> -      return UNKNOWN_LOCATION;
> -
> -    filename = intern_filename (filename);
> -    linemap_add (line_table, LC_ENTER, false, filename, line_number);
> -    source_location loc = linemap_line_start (line_table, line_number, 0);
> -    linemap_add (line_table, LC_LEAVE, false, NULL, 0);
> -    return loc;
> -  }
> -
> -private:
> -
> -  // Add a file name to FILE_NAMES and return the canonical copy.
> -  const char *intern_filename (const char *filename)
> -  {
> -    const char **slot = file_names.find_slot (filename, INSERT);
> -    if (*slot == NULL)
> -      {
> -       /* The file name must live as long as the line map, which
> -          effectively means as long as this compilation.  So, we copy
> -          the string here but never free it.  */
> -       *slot = xstrdup (filename);
> -      }
> -    return *slot;
> -  }
> -};
> -
> -static plugin_context *current_context;
> -
> -
> -
> -plugin_context::plugin_context (int fd)
> -  : cc1_plugin::connection (fd),
> -    address_map (30),
> -    preserved (30),
> -    file_names (30)
> -{
> -}
> -
> -void
> -plugin_context::mark ()
> -{
> -  for (hash_table<decl_addr_hasher>::iterator it = address_map.begin ();
> -       it != address_map.end ();
> -       ++it)
> -    {
> -      ggc_mark ((*it)->decl);
> -      ggc_mark ((*it)->address);
> -    }
> -
> -  for (hash_table< nofree_ptr_hash<tree_node> >::iterator
> -        it = preserved.begin (); it != preserved.end (); ++it)
> -    ggc_mark (&*it);
> -}
> -
> -static void
> -plugin_binding_oracle (enum c_oracle_request kind, tree identifier)
> -{
> -  enum gcc_c_oracle_request request;
> -
> -  gcc_assert (current_context != NULL);
> -
> -  switch (kind)
> -    {
> -    case C_ORACLE_SYMBOL:
> -      request = GCC_C_ORACLE_SYMBOL;
> -      break;
> -    case C_ORACLE_TAG:
> -      request = GCC_C_ORACLE_TAG;
> -      break;
> -    case C_ORACLE_LABEL:
> -      request = GCC_C_ORACLE_LABEL;
> -      break;
> -    default:
> -      abort ();
> -    }
> -
> -  int ignore;
> -  cc1_plugin::call (current_context, "binding_oracle", &ignore,
> -                   request, IDENTIFIER_POINTER (identifier));
> -}
> -
> -static void
> -plugin_pragma_user_expression (cpp_reader *)
> -{
> -  c_binding_oracle = plugin_binding_oracle;
> -}
> -
> -static void
> -plugin_init_extra_pragmas (void *, void *)
> -{
> -  c_register_pragma ("GCC", "user_expression", plugin_pragma_user_expression);
> -}
> -
> -
> -
> -// Maybe rewrite a decl to its address.
> -static tree
> -address_rewriter (tree *in, int *walk_subtrees, void *arg)
> -{
> -  plugin_context *ctx = (plugin_context *) arg;
> -
> -  if (!DECL_P (*in) || DECL_NAME (*in) == NULL_TREE)
> -    return NULL_TREE;
> -
> -  decl_addr_value value;
> -  value.decl = *in;
> -  decl_addr_value *found_value = ctx->address_map.find (&value);
> -  if (found_value != NULL)
> -    {
> -      // At this point we don't need VLA sizes for gdb-supplied
> -      // variables, and having them here confuses later passes, so we
> -      // drop them.
> -      if (C_TYPE_VARIABLE_SIZE (TREE_TYPE (*in)))
> -       {
> -         TREE_TYPE (*in)
> -           = build_array_type_nelts (TREE_TYPE (TREE_TYPE (*in)), 1);
> -         DECL_SIZE (*in) = TYPE_SIZE (TREE_TYPE (*in));
> -         DECL_SIZE_UNIT (*in) = TYPE_SIZE_UNIT (TREE_TYPE (*in));
> -       }
> -    }
> -  else if (DECL_IS_BUILTIN (*in))
> -    {
> -      gcc_address address;
> -
> -      if (!cc1_plugin::call (ctx, "address_oracle", &address,
> -                            IDENTIFIER_POINTER (DECL_NAME (*in))))
> -       return NULL_TREE;
> -      if (address == 0)
> -       return NULL_TREE;
> -
> -      // Insert the decl into the address map in case it is referenced
> -      // again.
> -      value.address = build_int_cst_type (ptr_type_node, address);
> -      decl_addr_value **slot = ctx->address_map.find_slot (&value, INSERT);
> -      gcc_assert (*slot == NULL);
> -      *slot
> -       = static_cast<decl_addr_value *> (xmalloc (sizeof (decl_addr_value)));
> -      **slot = value;
> -      found_value = *slot;
> -    }
> -  else
> -    return NULL_TREE;
> -
> -  if (found_value->address != error_mark_node)
> -    {
> -      // We have an address for the decl, so rewrite the tree.
> -      tree ptr_type = build_pointer_type (TREE_TYPE (*in));
> -      *in = fold_build1 (INDIRECT_REF, TREE_TYPE (*in),
> -                        fold_build1 (CONVERT_EXPR, ptr_type,
> -                                     found_value->address));
> -    }
> -
> -  *walk_subtrees = 0;
> -
> -  return NULL_TREE;
> -}
> -
> -// When generating code for gdb, we want to be able to use absolute
> -// addresses to refer to otherwise external objects that gdb knows
> -// about.  gdb passes in these addresses when building decls, and then
> -// before gimplification we go through the trees, rewriting uses to
> -// the equivalent of "*(TYPE *) ADDR".
> -static void
> -rewrite_decls_to_addresses (void *function_in, void *)
> -{
> -  tree function = (tree) function_in;
> -
> -  // Do nothing if we're not in gdb.
> -  if (current_context == NULL)
> -    return;
> -
> -  walk_tree (&DECL_SAVED_TREE (function), address_rewriter, current_context,
> -            NULL);
> -}
> -
> -
> -
> -gcc_decl
> -plugin_build_decl (cc1_plugin::connection *self,
> -                  const char *name,
> -                  enum gcc_c_symbol_kind sym_kind,
> -                  gcc_type sym_type_in,
> -                  const char *substitution_name,
> -                  gcc_address address,
> -                  const char *filename,
> -                  unsigned int line_number)
> -{
> -  plugin_context *ctx = static_cast<plugin_context *> (self);
> -  tree identifier = get_identifier (name);
> -  enum tree_code code;
> -  tree decl;
> -  tree sym_type = convert_in (sym_type_in);
> -
> -  switch (sym_kind)
> -    {
> -    case GCC_C_SYMBOL_FUNCTION:
> -      code = FUNCTION_DECL;
> -      break;
> -
> -    case GCC_C_SYMBOL_VARIABLE:
> -      code = VAR_DECL;
> -      break;
> -
> -    case GCC_C_SYMBOL_TYPEDEF:
> -      code = TYPE_DECL;
> -      break;
> -
> -    case GCC_C_SYMBOL_LABEL:
> -      // FIXME: we aren't ready to handle labels yet.
> -      // It isn't clear how to translate them properly
> -      // and in any case a "goto" isn't likely to work.
> -      return convert_out (error_mark_node);
> -
> -    default:
> -      abort ();
> -    }
> -
> -  source_location loc = ctx->get_source_location (filename, line_number);
> -
> -  decl = build_decl (loc, code, identifier, sym_type);
> -  TREE_USED (decl) = 1;
> -  TREE_ADDRESSABLE (decl) = 1;
> -
> -  if (sym_kind != GCC_C_SYMBOL_TYPEDEF)
> -    {
> -      decl_addr_value value;
> -
> -      value.decl = decl;
> -      if (substitution_name != NULL)
> -       {
> -         // If the translator gave us a name without a binding,
> -         // we can just substitute error_mark_node, since we know the
> -         // translator will be reporting an error anyhow.
> -         value.address
> -           = lookup_name (get_identifier (substitution_name));
> -         if (value.address == NULL_TREE)
> -           value.address = error_mark_node;
> -       }
> -      else
> -       value.address = build_int_cst_type (ptr_type_node, address);
> -      decl_addr_value **slot = ctx->address_map.find_slot (&value, INSERT);
> -      gcc_assert (*slot == NULL);
> -      *slot
> -       = static_cast<decl_addr_value *> (xmalloc (sizeof (decl_addr_value)));
> -      **slot = value;
> -    }
> -
> -  return convert_out (ctx->preserve (decl));
> -}
> -
> -int
> -plugin_bind (cc1_plugin::connection *,
> -            gcc_decl decl_in, int is_global)
> -{
> -  tree decl = convert_in (decl_in);
> -  c_bind (DECL_SOURCE_LOCATION (decl), decl, is_global);
> -  rest_of_decl_compilation (decl, is_global, 0);
> -  return 1;
> -}
> -
> -int
> -plugin_tagbind (cc1_plugin::connection *self,
> -               const char *name, gcc_type tagged_type,
> -               const char *filename, unsigned int line_number)
> -{
> -  plugin_context *ctx = static_cast<plugin_context *> (self);
> -  c_pushtag (ctx->get_source_location (filename, line_number),
> -            get_identifier (name), convert_in (tagged_type));
> -  return 1;
> -}
> -
> -gcc_type
> -plugin_build_pointer_type (cc1_plugin::connection *,
> -                          gcc_type base_type)
> -{
> -  // No need to preserve a pointer type as the base type is preserved.
> -  return convert_out (build_pointer_type (convert_in (base_type)));
> -}
> -
> -gcc_type
> -plugin_build_record_type (cc1_plugin::connection *self)
> -{
> -  plugin_context *ctx = static_cast<plugin_context *> (self);
> -  return convert_out (ctx->preserve (make_node (RECORD_TYPE)));
> -}
> -
> -gcc_type
> -plugin_build_union_type (cc1_plugin::connection *self)
> -{
> -  plugin_context *ctx = static_cast<plugin_context *> (self);
> -  return convert_out (ctx->preserve (make_node (UNION_TYPE)));
> -}
> -
> -int
> -plugin_build_add_field (cc1_plugin::connection *,
> -                       gcc_type record_or_union_type_in,
> -                       const char *field_name,
> -                       gcc_type field_type_in,
> -                       unsigned long bitsize,
> -                       unsigned long bitpos)
> -{
> -  tree record_or_union_type = convert_in (record_or_union_type_in);
> -  tree field_type = convert_in (field_type_in);
> -
> -  gcc_assert (TREE_CODE (record_or_union_type) == RECORD_TYPE
> -             || TREE_CODE (record_or_union_type) == UNION_TYPE);
> -
> -  /* Note that gdb does not preserve the location of field decls, so
> -     we can't provide a decent location here.  */
> -  tree decl = build_decl (BUILTINS_LOCATION, FIELD_DECL,
> -                         get_identifier (field_name), field_type);
> -  DECL_FIELD_CONTEXT (decl) = record_or_union_type;
> -
> -  if (TREE_CODE (field_type) == INTEGER_TYPE
> -      && TYPE_PRECISION (field_type) != bitsize)
> -    {
> -      DECL_BIT_FIELD_TYPE (decl) = field_type;
> -      TREE_TYPE (decl)
> -       = c_build_bitfield_integer_type (bitsize, TYPE_UNSIGNED (field_type));
> -    }
> -
> -  SET_DECL_MODE (decl, TYPE_MODE (TREE_TYPE (decl)));
> -
> -  // There's no way to recover this from DWARF.
> -  SET_DECL_OFFSET_ALIGN (decl, TYPE_PRECISION (pointer_sized_int_node));
> -
> -  tree pos = bitsize_int (bitpos);
> -  pos_from_bit (&DECL_FIELD_OFFSET (decl), &DECL_FIELD_BIT_OFFSET (decl),
> -               DECL_OFFSET_ALIGN (decl), pos);
> -
> -  DECL_SIZE (decl) = bitsize_int (bitsize);
> -  DECL_SIZE_UNIT (decl) = size_int ((bitsize + BITS_PER_UNIT - 1)
> -                                   / BITS_PER_UNIT);
> -
> -  DECL_CHAIN (decl) = TYPE_FIELDS (record_or_union_type);
> -  TYPE_FIELDS (record_or_union_type) = decl;
> -
> -  return 1;
> -}
> -
> -int
> -plugin_finish_record_or_union (cc1_plugin::connection *,
> -                              gcc_type record_or_union_type_in,
> -                              unsigned long size_in_bytes)
> -{
> -  tree record_or_union_type = convert_in (record_or_union_type_in);
> -
> -  gcc_assert (TREE_CODE (record_or_union_type) == RECORD_TYPE
> -             || TREE_CODE (record_or_union_type) == UNION_TYPE);
> -
> -  /* We built the field list in reverse order, so fix it now.  */
> -  TYPE_FIELDS (record_or_union_type)
> -    = nreverse (TYPE_FIELDS (record_or_union_type));
> -
> -  if (TREE_CODE (record_or_union_type) == UNION_TYPE)
> -    {
> -      /* Unions can just be handled by the generic code.  */
> -      layout_type (record_or_union_type);
> -    }
> -  else
> -    {
> -      // FIXME there's no way to get this from DWARF,
> -      // or even, it seems, a particularly good way to deduce it.
> -      SET_TYPE_ALIGN (record_or_union_type,
> -                     TYPE_PRECISION (pointer_sized_int_node));
> -
> -      TYPE_SIZE (record_or_union_type) = bitsize_int (size_in_bytes
> -                                                     * BITS_PER_UNIT);
> -      TYPE_SIZE_UNIT (record_or_union_type) = size_int (size_in_bytes);
> -
> -      compute_record_mode (record_or_union_type);
> -      finish_bitfield_layout (record_or_union_type);
> -      // FIXME we have no idea about TYPE_PACKED
> -    }
> -
> -  return 1;
> -}
> -
> -gcc_type
> -plugin_build_enum_type (cc1_plugin::connection *self,
> -                       gcc_type underlying_int_type_in)
> -{
> -  tree underlying_int_type = convert_in (underlying_int_type_in);
> -
> -  if (underlying_int_type == error_mark_node)
> -    return convert_out (error_mark_node);
> -
> -  tree result = make_node (ENUMERAL_TYPE);
> -
> -  TYPE_PRECISION (result) = TYPE_PRECISION (underlying_int_type);
> -  TYPE_UNSIGNED (result) = TYPE_UNSIGNED (underlying_int_type);
> -
> -  plugin_context *ctx = static_cast<plugin_context *> (self);
> -  return convert_out (ctx->preserve (result));
> -}
> -
> -int
> -plugin_build_add_enum_constant (cc1_plugin::connection *,
> -                               gcc_type enum_type_in,
> -                               const char *name,
> -                               unsigned long value)
> -{
> -  tree cst, decl, cons;
> -  tree enum_type = convert_in (enum_type_in);
> -
> -  gcc_assert (TREE_CODE (enum_type) == ENUMERAL_TYPE);
> -
> -  cst = build_int_cst (enum_type, value);
> -  /* Note that gdb does not preserve the location of enum constants,
> -     so we can't provide a decent location here.  */
> -  decl = build_decl (BUILTINS_LOCATION, CONST_DECL,
> -                    get_identifier (name), enum_type);
> -  DECL_INITIAL (decl) = cst;
> -  pushdecl_safe (decl);
> -
> -  cons = tree_cons (DECL_NAME (decl), cst, TYPE_VALUES (enum_type));
> -  TYPE_VALUES (enum_type) = cons;
> -
> -  return 1;
> -}
> -
> -int
> -plugin_finish_enum_type (cc1_plugin::connection *,
> -                        gcc_type enum_type_in)
> -{
> -  tree enum_type = convert_in (enum_type_in);
> -  tree minnode, maxnode, iter;
> -
> -  iter = TYPE_VALUES (enum_type);
> -  minnode = maxnode = TREE_VALUE (iter);
> -  for (iter = TREE_CHAIN (iter);
> -       iter != NULL_TREE;
> -       iter = TREE_CHAIN (iter))
> -    {
> -      tree value = TREE_VALUE (iter);
> -      if (tree_int_cst_lt (maxnode, value))
> -       maxnode = value;
> -      if (tree_int_cst_lt (value, minnode))
> -       minnode = value;
> -    }
> -  TYPE_MIN_VALUE (enum_type) = minnode;
> -  TYPE_MAX_VALUE (enum_type) = maxnode;
> -
> -  layout_type (enum_type);
> -
> -  return 1;
> -}
> -
> -gcc_type
> -plugin_build_function_type (cc1_plugin::connection *self,
> -                           gcc_type return_type_in,
> -                           const struct gcc_type_array *argument_types_in,
> -                           int is_varargs)
> -{
> -  tree *argument_types;
> -  tree return_type = convert_in (return_type_in);
> -  tree result;
> -
> -  argument_types = new tree[argument_types_in->n_elements];
> -  for (int i = 0; i < argument_types_in->n_elements; ++i)
> -    argument_types[i] = convert_in (argument_types_in->elements[i]);
> -
> -  if (is_varargs)
> -    result = build_varargs_function_type_array (return_type,
> -                                               argument_types_in->n_elements,
> -                                               argument_types);
> -  else
> -    result = build_function_type_array (return_type,
> -                                       argument_types_in->n_elements,
> -                                       argument_types);
> -
> -  delete[] argument_types;
> -
> -  plugin_context *ctx = static_cast<plugin_context *> (self);
> -  return convert_out (ctx->preserve (result));
> -}
> -
> -gcc_type
> -plugin_int_type (cc1_plugin::connection *self,
> -                int is_unsigned, unsigned long size_in_bytes)
> -{
> -  tree result = c_common_type_for_size (BITS_PER_UNIT * size_in_bytes,
> -                                       is_unsigned);
> -  if (result == NULL_TREE)
> -    result = error_mark_node;
> -  else
> -    {
> -      plugin_context *ctx = static_cast<plugin_context *> (self);
> -      ctx->preserve (result);
> -    }
> -  return convert_out (result);
> -}
> -
> -gcc_type
> -plugin_float_type (cc1_plugin::connection *,
> -                  unsigned long size_in_bytes)
> -{
> -  if (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (float_type_node))
> -    return convert_out (float_type_node);
> -  if (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (double_type_node))
> -    return convert_out (double_type_node);
> -  if (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (long_double_type_node))
> -    return convert_out (long_double_type_node);
> -  return convert_out (error_mark_node);
> -}
> -
> -gcc_type
> -plugin_void_type (cc1_plugin::connection *)
> -{
> -  return convert_out (void_type_node);
> -}
> -
> -gcc_type
> -plugin_bool_type (cc1_plugin::connection *)
> -{
> -  return convert_out (boolean_type_node);
> -}
> -
> -gcc_type
> -plugin_build_array_type (cc1_plugin::connection *self,
> -                        gcc_type element_type_in, int num_elements)
> -{
> -  tree element_type = convert_in (element_type_in);
> -  tree result;
> -
> -  if (num_elements == -1)
> -    result = build_array_type (element_type, NULL_TREE);
> -  else
> -    result = build_array_type_nelts (element_type, num_elements);
> -
> -  plugin_context *ctx = static_cast<plugin_context *> (self);
> -  return convert_out (ctx->preserve (result));
> -}
> -
> -gcc_type
> -plugin_build_vla_array_type (cc1_plugin::connection *self,
> -                            gcc_type element_type_in,
> -                            const char *upper_bound_name)
> -{
> -  tree element_type = convert_in (element_type_in);
> -  tree upper_bound = lookup_name (get_identifier (upper_bound_name));
> -  tree range = build_index_type (upper_bound);
> -
> -  tree result = build_array_type (element_type, range);
> -  C_TYPE_VARIABLE_SIZE (result) = 1;
> -
> -  plugin_context *ctx = static_cast<plugin_context *> (self);
> -  return convert_out (ctx->preserve (result));
> -}
> -
> -gcc_type
> -plugin_build_qualified_type (cc1_plugin::connection *,
> -                            gcc_type unqualified_type_in,
> -                            enum gcc_qualifiers qualifiers)
> -{
> -  tree unqualified_type = convert_in (unqualified_type_in);
> -  int quals = 0;
> -
> -  if ((qualifiers & GCC_QUALIFIER_CONST) != 0)
> -    quals |= TYPE_QUAL_CONST;
> -  if ((qualifiers & GCC_QUALIFIER_VOLATILE) != 0)
> -    quals |= TYPE_QUAL_VOLATILE;
> -  if ((qualifiers & GCC_QUALIFIER_RESTRICT) != 0)
> -    quals |= TYPE_QUAL_RESTRICT;
> -
> -  return convert_out (build_qualified_type (unqualified_type, quals));
> -}
> -
> -gcc_type
> -plugin_build_complex_type (cc1_plugin::connection *self,
> -                          gcc_type base_type)
> -{
> -  plugin_context *ctx = static_cast<plugin_context *> (self);
> -  return convert_out (ctx->preserve (build_complex_type (convert_in (base_type))));
> -}
> -
> -gcc_type
> -plugin_build_vector_type (cc1_plugin::connection *self,
> -                         gcc_type base_type, int nunits)
> -{
> -  plugin_context *ctx = static_cast<plugin_context *> (self);
> -  return convert_out (ctx->preserve (build_vector_type (convert_in (base_type),
> -                                                       nunits)));
> -}
> -
> -int
> -plugin_build_constant (cc1_plugin::connection *self, gcc_type type_in,
> -                      const char *name, unsigned long value,
> -                      const char *filename, unsigned int line_number)
> -{
> -  plugin_context *ctx = static_cast<plugin_context *> (self);
> -  tree cst, decl;
> -  tree type = convert_in (type_in);
> -
> -  cst = build_int_cst (type, value);
> -  decl = build_decl (ctx->get_source_location (filename, line_number),
> -                    CONST_DECL, get_identifier (name), type);
> -  DECL_INITIAL (decl) = cst;
> -  pushdecl_safe (decl);
> -
> -  return 1;
> -}
> -
> -gcc_type
> -plugin_error (cc1_plugin::connection *,
> -             const char *message)
> -{
> -  error ("%s", message);
> -  return convert_out (error_mark_node);
> -}
> -
> -
> -
> -// Perform GC marking.
> -
> -static void
> -gc_mark (void *, void *)
> -{
> -  if (current_context != NULL)
> -    current_context->mark ();
> -}
> -
> -#ifdef __GNUC__
> -#pragma GCC visibility push(default)
> -#endif
> -
> -int
> -plugin_init (struct plugin_name_args *plugin_info,
> -            struct plugin_gcc_version *)
> -{
> -  long fd = -1;
> -  for (int i = 0; i < plugin_info->argc; ++i)
> -    {
> -      if (strcmp (plugin_info->argv[i].key, "fd") == 0)
> -       {
> -         char *tail;
> -         errno = 0;
> -         fd = strtol (plugin_info->argv[i].value, &tail, 0);
> -         if (*tail != '\0' || errno != 0)
> -           fatal_error (input_location,
> -                        "%s: invalid file descriptor argument to plugin",
> -                        plugin_info->base_name);
> -         break;
> -       }
> -    }
> -  if (fd == -1)
> -    fatal_error (input_location,
> -                "%s: required plugin argument %<fd%> is missing",
> -                plugin_info->base_name);
> -
> -  current_context = new plugin_context (fd);
> -
> -  // Handshake.
> -  cc1_plugin::protocol_int version;
> -  if (!current_context->require ('H')
> -      || ! ::cc1_plugin::unmarshall (current_context, &version))
> -    fatal_error (input_location,
> -                "%s: handshake failed", plugin_info->base_name);
> -  if (version != GCC_C_FE_VERSION_0)
> -    fatal_error (input_location,
> -                "%s: unknown version in handshake", plugin_info->base_name);
> -
> -  register_callback (plugin_info->base_name, PLUGIN_PRAGMAS,
> -                    plugin_init_extra_pragmas, NULL);
> -  register_callback (plugin_info->base_name, PLUGIN_PRE_GENERICIZE,
> -                    rewrite_decls_to_addresses, NULL);
> -  register_callback (plugin_info->base_name, PLUGIN_GGC_MARKING,
> -                    gc_mark, NULL);
> -
> -  lang_hooks.print_error_function = plugin_print_error_function;
> -
> -#define GCC_METHOD0(R, N)                      \
> -  {                                            \
> -    cc1_plugin::callback_ftype *fun            \
> -      = cc1_plugin::callback<R, plugin_ ## N>; \
> -    current_context->add_callback (# N, fun);  \
> -  }
> -#define GCC_METHOD1(R, N, A)                           \
> -  {                                                    \
> -    cc1_plugin::callback_ftype *fun                    \
> -      = cc1_plugin::callback<R, A, plugin_ ## N>;      \
> -    current_context->add_callback (# N, fun);          \
> -  }
> -#define GCC_METHOD2(R, N, A, B)                                \
> -  {                                                    \
> -    cc1_plugin::callback_ftype *fun                    \
> -      = cc1_plugin::callback<R, A, B, plugin_ ## N>;   \
> -    current_context->add_callback (# N, fun);          \
> -  }
> -#define GCC_METHOD3(R, N, A, B, C)                     \
> -  {                                                    \
> -    cc1_plugin::callback_ftype *fun                    \
> -      = cc1_plugin::callback<R, A, B, C, plugin_ ## N>;        \
> -    current_context->add_callback (# N, fun);          \
> -  }
> -#define GCC_METHOD4(R, N, A, B, C, D)          \
> -  {                                            \
> -    cc1_plugin::callback_ftype *fun            \
> -      = cc1_plugin::callback<R, A, B, C, D,    \
> -                            plugin_ ## N>;     \
> -    current_context->add_callback (# N, fun);  \
> -  }
> -#define GCC_METHOD5(R, N, A, B, C, D, E)       \
> -  {                                            \
> -    cc1_plugin::callback_ftype *fun            \
> -      = cc1_plugin::callback<R, A, B, C, D, E, \
> -                            plugin_ ## N>;     \
> -    current_context->add_callback (# N, fun);  \
> -  }
> -#define GCC_METHOD7(R, N, A, B, C, D, E, F, G)         \
> -  {                                                    \
> -    cc1_plugin::callback_ftype *fun                    \
> -      = cc1_plugin::callback<R, A, B, C, D, E, F, G,   \
> -                            plugin_ ## N>;             \
> -    current_context->add_callback (# N, fun);          \
> -  }
> -
> -#include "gcc-c-fe.def"
> -
> -#undef GCC_METHOD0
> -#undef GCC_METHOD1
> -#undef GCC_METHOD2
> -#undef GCC_METHOD3
> -#undef GCC_METHOD4
> -#undef GCC_METHOD5
> -#undef GCC_METHOD7
> -
> -  return 0;
> -}
> diff --git a/libcc1/rpc.hh b/libcc1/rpc.hh
> index 01b793b..56a07c2 100644
> --- a/libcc1/rpc.hh
> +++ b/libcc1/rpc.hh
> @@ -21,7 +21,6 @@ along with GCC; see the file COPYING3.  If not see
>  #define CC1_PLUGIN_RPC_HH
>
>  #include "status.hh"
> -#include "marshall.hh"
>  #include "connection.hh"
>
>  namespace cc1_plugin
> @@ -126,6 +125,118 @@ namespace cc1_plugin
>      argument_wrapper &operator= (const argument_wrapper &);
>    };
>
> +#ifdef GCC_CP_INTERFACE_H
> +  // Specialization for gcc_vbase_array.
> +  template<>
> +  class argument_wrapper<const gcc_vbase_array *>
> +  {
> +  public:
> +    argument_wrapper () : m_object (NULL) { }
> +    ~argument_wrapper ()
> +    {
> +      // It would be nicer if gcc_type_array could have a destructor.
> +      // But, it is in code shared with gdb and cannot.
> +      if (m_object != NULL)
> +       {
> +         delete[] m_object->flags;
> +         delete[] m_object->elements;
> +       }
> +      delete m_object;
> +    }
> +
> +    operator const gcc_vbase_array * () const
> +    {
> +      return m_object;
> +    }
> +
> +    status unmarshall (connection *conn)
> +    {
> +      return ::cc1_plugin::unmarshall (conn, &m_object);
> +    }
> +
> +  private:
> +
> +    gcc_vbase_array *m_object;
> +
> +    // No copying or assignment allowed.
> +    argument_wrapper (const argument_wrapper &);
> +    argument_wrapper &operator= (const argument_wrapper &);
> +  };
> +
> +  // Specialization for gcc_cp_template_args.
> +  template<>
> +  class argument_wrapper<const gcc_cp_template_args *>
> +  {
> +  public:
> +    argument_wrapper () : m_object (NULL) { }
> +    ~argument_wrapper ()
> +    {
> +      // It would be nicer if gcc_type_array could have a destructor.
> +      // But, it is in code shared with gdb and cannot.
> +      if (m_object != NULL)
> +       {
> +         delete[] m_object->elements;
> +         delete[] m_object->kinds;
> +       }
> +      delete m_object;
> +    }
> +
> +    operator const gcc_cp_template_args * () const
> +    {
> +      return m_object;
> +    }
> +
> +    status unmarshall (connection *conn)
> +    {
> +      return ::cc1_plugin::unmarshall (conn, &m_object);
> +    }
> +
> +  private:
> +
> +    gcc_cp_template_args *m_object;
> +
> +    // No copying or assignment allowed.
> +    argument_wrapper (const argument_wrapper &);
> +    argument_wrapper &operator= (const argument_wrapper &);
> +  };
> +
> +  // Specialization for gcc_cp_function_args.
> +  template<>
> +  class argument_wrapper<const gcc_cp_function_args *>
> +  {
> +  public:
> +    argument_wrapper () : m_object (NULL) { }
> +    ~argument_wrapper ()
> +    {
> +      // It would be nicer if gcc_type_array could have a destructor.
> +      // But, it is in code shared with gdb and cannot.
> +      if (m_object != NULL)
> +       {
> +         delete[] m_object->elements;
> +       }
> +      delete m_object;
> +    }
> +
> +    operator const gcc_cp_function_args * () const
> +    {
> +      return m_object;
> +    }
> +
> +    status unmarshall (connection *conn)
> +    {
> +      return ::cc1_plugin::unmarshall (conn, &m_object);
> +    }
> +
> +  private:
> +
> +    gcc_cp_function_args *m_object;
> +
> +    // No copying or assignment allowed.
> +    argument_wrapper (const argument_wrapper &);
> +    argument_wrapper &operator= (const argument_wrapper &);
> +  };
> +#endif /* GCC_CP_INTERFACE_H */
> +
>    // There are two kinds of template functions here: "call" and
>    // "callback".  They are each repeated multiple times to handle
>    // different numbers of arguments.  (This would be improved with
>
>
> --
> Alexandre Oliva, freedom fighter    http://FSFLA.org/~lxoliva/
> You must be the change you wish to see in the world. -- Gandhi
> Be Free! -- http://FSFLA.org/   FSF Latin America board member
> Free Software Evangelist|Red Hat Brasil GNU Toolchain Engineer
Alexandre Oliva May 28, 2017, 1:45 p.m. UTC | #2
On May 26, 2017, Richard Biener <richard.guenther@gmail.com> wrote:

> On Mon, Jan 30, 2017 at 11:31 PM, Alexandre Oliva <aoliva@redhat.com> wrote:
>   bool oracle_looked_up;

> that increased lang_identifier size by 8 bytes while there's "plenty" of free
> bits in tree_base (bonus point if you can reap a lang_flag).

Oh, no!  I put it there temporarily, very early in the project, because
I couldn't find a better place (I looked for available bits elsewhere,
and I recall I couldn't find any); at the end we moved to a hash_set
(see query_oracle below), that makes a lot more sense since the bit is
only used when libcc1 is in use.  But I accidentally left in place the
data member I'd added before, completely unused :-(  Ouch!

>> +static inline void
>> +query_oracle (tree name)
>> +{
>> +  if (!cp_binding_oracle)
>> +    return;
>> +
>> +  /* LOOKED_UP holds the set of identifiers that we have already
>> +     looked up with the oracle.  */
>> +  static hash_set<tree> looked_up;
>> +  if (looked_up.add (name))
>> +    return;
>> +
>> +  cp_binding_oracle (CP_ORACLE_IDENTIFIER, name);
>> +}

I apologize for making G++ 7.1 plain waste memory on it.

I'll test and install the obvious fix, trunk and branch, though I might
be a bit slow in getting to it: Richard Stallman will be in town this
week, at my place, and we have a busy schedule, so my computer time and
attention will be severely limited.  There's no rush AFAIK, and I'll get
the fix in no later than next weekend, but of course I won't mind at all
if someone else beats me to it.

Thanks for catching this!
diff mbox

Patch

diff --git a/include/gcc-cp-fe.def b/include/gcc-cp-fe.def
index 396931a..c367c1d 100644
--- a/include/gcc-cp-fe.def
+++ b/include/gcc-cp-fe.def
@@ -406,7 +406,7 @@  GCC_METHOD1 (gcc_decl, get_type_decl,
    class, be they template generics, template specializations or not
    templates.  TYPE must be a class type (not a template generic).
 
-   The new_friend call cannot introduce a declaration; even if the
+   The add_friend call cannot introduce a declaration; even if the
    friend is first declared as a friend in the source code, the
    declaration belongs in the enclosing namespace, so it must be
    introduced in that namespace, and the resulting declaration can
@@ -441,7 +441,7 @@  GCC_METHOD1 (gcc_decl, get_type_decl,
 
    In order to simplify such friend declarations, and to enable
    incremental friend declarations as template specializations are
-   introduced, new_friend can be called after the befriending class is
+   introduced, add_friend can be called after the befriending class is
    fully defined, passing it a non-NULL TYPE argument naming the
    befriending class type.  */
 
@@ -477,10 +477,10 @@  GCC_METHOD2 (gcc_type, build_pointer_to_member_type,
    GCC_CP_SYMBOL_FUNCTION or GCC_CP_SYMBOL_CLASS, that, when the scope
    is a template parameter list, declares a template function or a
    template class with the then-closed parameter list.  The scope in
-   which the new declaration is to be introduced by new_decl must be
-   entered before calling start_new_template_decl, and new_decl
-   returns to that scope, from the template parameter list scope,
-   before introducing the declaration.  */
+   which the new declaration is to be introduced by build_decl must be
+   entered before calling start_template_decl, and build_decl returns
+   to that scope, from the template parameter list scope, before
+   introducing the declaration.  */
 
 GCC_METHOD0 (int /* bool */, start_template_decl)
 
@@ -553,7 +553,7 @@  GCC_METHOD2 (gcc_utempl, build_dependent_class_template,
 	     gcc_type,			  /* Argument ENCLOSING_TYPE.  */
 	     const char *)			      /* Argument ID.  */
 
-/* Build a template-dependent template type id (e.g., T<A>).
+/* Build a template-dependent type template-id (e.g., T<A>).
    TEMPLATE_DECL should be a template template parameter (e.g., the T
    in template <template <[...]> class T = X>), and TARGS should
    specify the template arguments (e.g. <A>).  */


Introduce C++ support in libcc1

Extend libcc1's with an API for C++ support.

Extend libcc1's C API to distinguish between integral types with the
same width, as in C++.  Likewise for float types.

Export small bits of functionality from the C++ front-end for use in
libcc1.  Add support for the C++ front-end to look up names and
addresses using a libcc1-registered binding oracle.  Add support for
global friends.


for  gcc/cp/ChangeLog

	Introduce C++ support in libcc1.
	* cp-tree.h (struct lang_identifier): Add oracle_looked_up.
	(ansi_opname): Rename to...
	(cp_operator_id): ... this.  Adjust all callers.
	(ansi_assopname): Rename to...
	(cp_assignment_operator_id): ... this.  Adjust all callers.
	(cp_literal_operator_id): Declare.
	(set_global_friend): Declare.
	(is_global_friend): Declare.
	(enum cp_oracle_request): New type.
	(cp_binding_oracle_function): New type.
	(cp_binding_oracle): Declare.
	(cp_finish_injected_record_type): Declare.
	* friend.c (global_friend): New var.
	(set_global_friend): New fn.
	(is_global_friend): New fn.
	(is_friend): Call is_global_friend.
	* name-lookup.c (cp_binding_oracle): New var.
	(query_oracle): New fn.
	(qualified_lookup_using_namespace): Call query_oracle.
	(lookup_name_real_1): Likewise.
	* parser.c (cp_literal_operator_id): Drop static.
	* search.c (friend_accessible_p): Call is_global_friend.
	* semantics.c (is_this_parameter): Accept a variable if the
	binding oracle is enabled.

for  include

	Introduce C++ support in libcc1.
	* gcc-c-fe.def (int_type_v0): Rename from...
	(int_type): ... this.  Introduce new version.
	(float_type_v0): Rename from...
	(float_type): ... this.  Introduce new version.
	(char_type): New.
	* gcc-c-interface.h (gcc_c_api_version): Add GCC_C_FE_VERSION_1.
	(gcc_type_array): Move...
	* gcc-interface.h: ... here.
	* gcc-cp-fe.def: New.
	* gcc-cp-interface.h: New.

for  libcc1

	Introduce C++ support.
	* Makefile.am (AM_CPPFLAGS): Move some -I flags to...
	(CPPFLAGS_FOR_C_FAMILY, CPPFLAGS_FOR_C, CPPFLAGS_FOR_CXX): ...
	new macros.
	(plugin_LTLIBRARIES): Add libcp1plugin.la.
	(BUILT_SOURCES, MOSTLYCLEANFILES): Add...
	(cp-compiler-name.h): ... this.  New.
	(c-compiler-name.h): Rename all over from...
	(compiler-name.h): ... this.  Create it atomically.
	(marshall_c_source, marshall_cxx_source): New macros.
	(libcc1plugin_la_SOURCES): Rename plugin.cc to libcc1plugin.cc.
	Add marshall_c_source expansion.
	(libcc1plugin.lo_CPPFLAGS): New macro.
	(libcp1plugin_la_LDFLAGS): Likewise.
	(libcp1plugin_la_SOURCES): Likewise.
	(libcp1plugin.lo_CPPFLAGS): Likewise.
	(libcp1plugin_la_LIBADD): Likewise.
	(libcp1plugin_la_DEPENDENCIES): Likewise.
	(libcp1plugin_la_LINK): Likewise.
	(libcc1_la_SOURCES): Added marshall_c_source and
	marshall_cxx_source expansions.
	* Makefile.in: Rebuild.
	* compiler-name.h: Rename all over to...
	* c-compiler-name.h: ... this.  Define C_COMPILER_NAME instead
	of COMPILER_NAME.
	* plugin.cc: Rename all over to...
	* libcc1plugin.cc: ... this.  Include marshall-c.hh.
	(address_rewriter): Drop cleaning up of VLA sizes.
	(plugin_build_decl): Mark decls as external.
	(plugin_tagbind): Propagate name to all variants.
	(build_anonymous_node): New.
	(plugin_build_record_type): Use it instead of make_node.
	(plugin_build_union_type): Likewise.
	(plugin_build_enum_type): Likewise.
	(plugin_finish_record_or_union): Update all type variants.
	(safe_lookup_builtin_type): New.
	(plugin_int_check): Factor out of, and add checks to, ...
	(plugin_int_type): ... this.  Rename to...
	(plugin_int_type_v0): ... this.
	(plugin_int_type): New interface, new implementation.
	(plugin_char_type): New.
	(plugin_float_type_v0): Rename from...
	(plugin_float_type): ... this.  New interface, new implementation.
	(plugin_init): Bump handshake version.
	* libcc1.cc: Include marshall-c.hh.  Drop gcc-interface.h.
	(call_binding_oracle): Rename to...
	(c_call_binding_oracle): ... this, into anonymous namespace.
	(call_symbol_address): Rename to...
	(c_call_symbol_address): ... this, likewise.
	(GCC_METHOD#): Move methods into cc1plugin::c:: namespace.
	(libcc1::compiler::find): Refer to C_COMPILER_NAME.
	(fork_exec): Bump to GCC_C_FE_VERSION_1.
	(libcc1_compile): Prefix callbacks with c_.
	(gcc_c_fe_context): Accept GCC_C_FE_VERSION_1.
	* libcc1.sym: Export gcc_cp_fe_context.
	* libcp1.cc: New, mostly copied and adjusted from libcc1.cc.
	* libcp1plugin.cc: New, initially copied from libcc1plugin.cc.
	* libcp1plugin.sym: New.
	* marshall-c.hh: New.  Move C-specific types from...
	* marshall.cc: ... this.
	(cc1_plugin::marshall_array_start): New.
	(cc1_plugin::marshall_array_elmts): New.
	(cc1_plugin::marshall for gcc_type_array): Use the above.
	(cc1_plugin::unmarshall_array_start): New.
	(cc1_plugin::unmarshall_array_elmts): New.
	(cc1_plugin::unmarshall for gcc_type_array): Use the above.
	* marshall.hh: Declare the new array building blocks.
	Drop C-specific unmarshall declarations.
	* marshall-cp.hh: New.
	* names.cc (GCC_METHOD#): Add LANG:: to method names.
	(LANG): Define while including gcc-c-fe.def and gcc-cp-fe.def.
	* names.hh: Include gcc-c-fe.def and gcc-cp-fe.def in the
	corresponding namespaces.
	* rpc.hh: Don't include marshall.hh.
	[GCC_CP_INTERFACE_H] (argument_wrapper): Specialize for
	gcc_vbase_array, gcc_cp_template_args, gcc_cp_function_args.
---
 gcc/cp/call.c              |   14 
 gcc/cp/class.c             |   10 
 gcc/cp/cp-tree.h           |   40 
 gcc/cp/decl.c              |    6 
 gcc/cp/decl2.c             |    2 
 gcc/cp/friend.c            |   43 
 gcc/cp/init.c              |    2 
 gcc/cp/lambda.c            |    2 
 gcc/cp/lex.c               |    2 
 gcc/cp/method.c            |   10 
 gcc/cp/name-lookup.c       |   27 
 gcc/cp/parser.c            |  103 +
 gcc/cp/search.c            |    5 
 gcc/cp/semantics.c         |    7 
 gcc/cp/typeck.c            |    2 
 include/gcc-c-fe.def       |   35 
 include/gcc-c-interface.h  |   21 
 include/gcc-cp-fe.def      | 1050 ++++++++++++
 include/gcc-cp-interface.h |  496 ++++++
 include/gcc-interface.h    |   14 
 libcc1/Makefile.am         |   46 -
 libcc1/Makefile.in         |   68 +
 libcc1/libcc1.cc           |   78 -
 libcc1/libcc1.sym          |    1 
 libcc1/libcc1plugin.cc     | 1020 ++++++++++++
 libcc1/libcp1.cc           |  706 ++++++++
 libcc1/libcp1plugin.cc     | 3789 ++++++++++++++++++++++++++++++++++++++++++++
 libcc1/libcp1plugin.sym    |    2 
 libcc1/marshall-c.hh       |   59 +
 libcc1/marshall-cp.hh      |  271 +++
 libcc1/marshall.cc         |  111 +
 libcc1/marshall.hh         |   15 
 libcc1/names.cc            |   20 
 libcc1/names.hh            |   18 
 libcc1/plugin.cc           |  921 -----------
 libcc1/rpc.hh              |  113 +
 36 files changed, 7978 insertions(+), 1151 deletions(-)
 create mode 100644 include/gcc-cp-fe.def
 create mode 100644 include/gcc-cp-interface.h
 create mode 100644 libcc1/libcc1plugin.cc
 create mode 100644 libcc1/libcp1.cc
 create mode 100644 libcc1/libcp1plugin.cc
 create mode 100644 libcc1/libcp1plugin.sym
 create mode 100644 libcc1/marshall-c.hh
 create mode 100644 libcc1/marshall-cp.hh
 delete mode 100644 libcc1/plugin.cc

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index a78e1a9..2d127e6 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -4426,7 +4426,7 @@  build_op_call_1 (tree obj, vec<tree, va_gc> **args, tsubst_flags_t complain)
 
   if (TYPE_BINFO (type))
     {
-      fns = lookup_fnfields (TYPE_BINFO (type), ansi_opname (CALL_EXPR), 1);
+      fns = lookup_fnfields (TYPE_BINFO (type), cp_operator_id (CALL_EXPR), 1);
       if (fns == error_mark_node)
 	return error_mark_node;
     }
@@ -5136,7 +5136,7 @@  build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
       add_builtin_candidates (&candidates,
 			      COND_EXPR,
 			      NOP_EXPR,
-			      ansi_opname (COND_EXPR),
+			      cp_operator_id (COND_EXPR),
 			      args,
 			      LOOKUP_NORMAL, complain);
 
@@ -5559,10 +5559,10 @@  build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
     {
       code2 = TREE_CODE (arg3);
       arg3 = NULL_TREE;
-      fnname = ansi_assopname (code2);
+      fnname = cp_assignment_operator_id (code2);
     }
   else
-    fnname = ansi_opname (code);
+    fnname = cp_operator_id (code);
 
   arg1 = prep_operand (arg1);
 
@@ -6167,7 +6167,7 @@  build_op_delete_call (enum tree_code code, tree addr, tree size,
 
   type = strip_array_types (TREE_TYPE (TREE_TYPE (addr)));
 
-  fnname = ansi_opname (code);
+  fnname = cp_operator_id (code);
 
   if (CLASS_TYPE_P (type)
       && COMPLETE_TYPE_P (complete_type (type))
@@ -8277,7 +8277,7 @@  build_special_member_call (tree instance, tree name, vec<tree, va_gc> **args,
 	      || name == complete_dtor_identifier
 	      || name == base_dtor_identifier
 	      || name == deleting_dtor_identifier
-	      || name == ansi_assopname (NOP_EXPR));
+	      || name == cp_assignment_operator_id (NOP_EXPR));
   if (TYPE_P (binfo))
     {
       /* Resolve the name.  */
@@ -8305,7 +8305,7 @@  build_special_member_call (tree instance, tree name, vec<tree, va_gc> **args,
       if (!same_type_ignoring_top_level_qualifiers_p
 	  (TREE_TYPE (instance), BINFO_TYPE (binfo)))
 	{
-	  if (name != ansi_assopname (NOP_EXPR))
+	  if (name != cp_assignment_operator_id (NOP_EXPR))
 	    /* For constructors and destructors, either the base is
 	       non-virtual, or it is virtual but we are doing the
 	       conversion from a constructor or destructor for the
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index b7c26a1..e243ef2 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -3256,7 +3256,7 @@  static tree
 dfs_declare_virt_assop_and_dtor (tree binfo, void *data)
 {
   tree bv, fn, t = (tree)data;
-  tree opname = ansi_assopname (NOP_EXPR);
+  tree opname = cp_assignment_operator_id (NOP_EXPR);
 
   gcc_assert (t && CLASS_TYPE_P (t));
   gcc_assert (binfo && TREE_CODE (binfo) == TREE_BINFO);
@@ -5351,7 +5351,7 @@  vbase_has_user_provided_move_assign (tree type)
 {
   /* Does the type itself have a user-provided move assignment operator?  */
   for (tree fns
-	 = lookup_fnfields_slot_nolazy (type, ansi_assopname (NOP_EXPR));
+	 = lookup_fnfields_slot_nolazy (type, cp_assignment_operator_id (NOP_EXPR));
        fns; fns = OVL_NEXT (fns))
     {
       tree fn = OVL_CURRENT (fns);
@@ -5515,7 +5515,7 @@  type_has_move_assign (tree t)
       lazily_declare_fn (sfk_move_assignment, t);
     }
 
-  for (fns = lookup_fnfields_slot_nolazy (t, ansi_assopname (NOP_EXPR));
+  for (fns = lookup_fnfields_slot_nolazy (t, cp_assignment_operator_id (NOP_EXPR));
        fns; fns = OVL_NEXT (fns))
     if (move_fn_p (OVL_CURRENT (fns)))
       return true;
@@ -5560,7 +5560,7 @@  type_has_user_declared_move_assign (tree t)
   if (CLASSTYPE_LAZY_MOVE_ASSIGN (t))
     return false;
 
-  for (fns = lookup_fnfields_slot_nolazy (t, ansi_assopname (NOP_EXPR));
+  for (fns = lookup_fnfields_slot_nolazy (t, cp_assignment_operator_id (NOP_EXPR));
        fns; fns = OVL_NEXT (fns))
     {
       tree fn = OVL_CURRENT (fns);
@@ -5681,7 +5681,7 @@  type_requires_array_cookie (tree type)
      the array to the deallocation function, so we will need to store
      a cookie.  */
   fns = lookup_fnfields (TYPE_BINFO (type),
-			 ansi_opname (VEC_DELETE_EXPR),
+			 cp_operator_id (VEC_DELETE_EXPR),
 			 /*protect=*/0);
   /* If there are no `operator []' members, or the lookup is
      ambiguous, then we don't need a cookie.  */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index f91b830..c0983bd 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -332,6 +332,7 @@  struct GTY(()) lang_identifier {
   cxx_binding *bindings;
   tree class_template_info;
   tree label_value;
+  bool oracle_looked_up;
 };
 
 /* Return a typed pointer version of T if it designates a
@@ -1530,15 +1531,17 @@  struct GTY(()) language_function {
 /* True if NAME is the IDENTIFIER_NODE for an overloaded "operator
    new" or "operator delete".  */
 #define NEW_DELETE_OPNAME_P(NAME)		\
-  ((NAME) == ansi_opname (NEW_EXPR)		\
-   || (NAME) == ansi_opname (VEC_NEW_EXPR)	\
-   || (NAME) == ansi_opname (DELETE_EXPR)	\
-   || (NAME) == ansi_opname (VEC_DELETE_EXPR))
+  ((NAME) == cp_operator_id (NEW_EXPR)		\
+   || (NAME) == cp_operator_id (VEC_NEW_EXPR)	\
+   || (NAME) == cp_operator_id (DELETE_EXPR)	\
+   || (NAME) == cp_operator_id (VEC_DELETE_EXPR))
 
-#define ansi_opname(CODE) \
+#define cp_operator_id(CODE) \
   (operator_name_info[(int) (CODE)].identifier)
-#define ansi_assopname(CODE) \
+#define cp_assignment_operator_id(CODE) \
   (assignment_operator_name_info[(int) (CODE)].identifier)
+/* In parser.c.  */
+extern tree cp_literal_operator_id (const char *);
 
 /* TRUE if a tree code represents a statement.  */
 extern bool statement_code_p[MAX_TREE_CODES];
@@ -6027,6 +6030,9 @@  extern void make_friend_class			(tree, tree, bool);
 extern void add_friend				(tree, tree, bool);
 extern tree do_friend				(tree, tree, tree, tree, enum overload_flags, bool);
 
+extern void set_global_friend			(tree);
+extern bool is_global_friend			(tree);
+
 /* in init.c */
 extern tree expand_member_init			(tree);
 extern void emit_mem_initializers		(tree);
@@ -6943,6 +6949,25 @@  extern void suggest_alternatives_for            (location_t, tree, bool);
 extern bool suggest_alternative_in_explicit_scope (location_t, tree, tree);
 extern tree strip_using_decl                    (tree);
 
+/* Tell the binding oracle what kind of binding we are looking for.  */
+
+enum cp_oracle_request
+{
+  CP_ORACLE_IDENTIFIER
+};
+
+/* If this is non-NULL, then it is a "binding oracle" which can lazily
+   create bindings when needed by the C compiler.  The oracle is told
+   the name and type of the binding to create.  It can call pushdecl
+   or the like to ensure the binding is visible; or do nothing,
+   leaving the binding untouched.  c-decl.c takes note of when the
+   oracle has been called and will not call it again if it fails to
+   create a given binding.  */
+
+typedef void cp_binding_oracle_function (enum cp_oracle_request, tree identifier);
+
+extern cp_binding_oracle_function *cp_binding_oracle;
+
 /* in constraint.cc */
 extern void init_constraint_processing          ();
 extern bool constraint_p                        (tree);
@@ -7008,6 +7033,9 @@  extern void diagnose_constraints                (location_t, tree, tree);
 extern tree decompose_conclusions               (tree);
 extern bool subsumes                            (tree, tree);
 
+/* In class.c */
+extern void cp_finish_injected_record_type (tree);
+
 /* in vtable-class-hierarchy.c */
 extern void vtv_compute_class_hierarchy_transitive_closure (void);
 extern void vtv_generate_init_routine           (void);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 44aefd8..9bdfd4f 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4564,7 +4564,7 @@  static tree
 push_cp_library_fn (enum tree_code operator_code, tree type,
 		    int ecf_flags)
 {
-  tree fn = build_cp_library_fn (ansi_opname (operator_code),
+  tree fn = build_cp_library_fn (cp_operator_id (operator_code),
 				 operator_code,
 				 type, ecf_flags);
   pushdecl (fn);
@@ -12937,12 +12937,12 @@  grok_op_properties (tree decl, bool complain)
     do
       {
 #define DEF_OPERATOR(NAME, CODE, MANGLING, ARITY, ASSN_P)	\
-	if (ansi_opname (CODE) == name)				\
+	if (cp_operator_id (CODE) == name)			\
 	  {							\
 	    operator_code = (CODE);				\
 	    break;						\
 	  }							\
-	else if (ansi_assopname (CODE) == name)			\
+	else if (cp_assignment_operator_id (CODE) == name)	\
 	  {							\
 	    operator_code = (CODE);				\
 	    DECL_ASSIGNMENT_OPERATOR_P (decl) = 1;		\
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index a9a1d22..86d9820 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -4386,7 +4386,7 @@  maybe_warn_sized_delete (enum tree_code code)
   tree sized = NULL_TREE;
   tree unsized = NULL_TREE;
 
-  for (tree ovl = IDENTIFIER_GLOBAL_VALUE (ansi_opname (code));
+  for (tree ovl = IDENTIFIER_GLOBAL_VALUE (cp_operator_id (code));
        ovl; ovl = OVL_NEXT (ovl))
     {
       tree fn = OVL_CURRENT (ovl);
diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c
index 9eec9e4..3815dae 100644
--- a/gcc/cp/friend.c
+++ b/gcc/cp/friend.c
@@ -24,6 +24,46 @@  along with GCC; see the file COPYING3.  If not see
 
 /* Friend data structures are described in cp-tree.h.  */
 
+
+/* The GLOBAL_FRIEND scope (functions, classes, or templates) is
+   regarded as a friend of every class.  This is only used by libcc1,
+   to enable GDB's code snippets to access private members without
+   disabling access control in general, which could cause different
+   template overload resolution results when accessibility matters
+   (e.g. tests for an accessible member).  */
+
+static tree global_friend;
+
+/* Set the GLOBAL_FRIEND for this compilation session.  It might be
+   set multiple times, but always to the same scope.  */
+
+void
+set_global_friend (tree scope)
+{
+  gcc_checking_assert (scope != NULL_TREE);
+  gcc_assert (!global_friend || global_friend == scope);
+  global_friend = scope;
+}
+
+/* Return TRUE if SCOPE is the global friend.  */
+
+bool
+is_global_friend (tree scope)
+{
+  gcc_checking_assert (scope != NULL_TREE);
+
+  if (global_friend == scope)
+    return true;
+
+  if (!global_friend)
+    return false;
+
+  if (is_specialization_of_friend (global_friend, scope))
+    return true;
+
+  return false;
+}
+
 /* Returns nonzero if SUPPLICANT is a friend of TYPE.  */
 
 int
@@ -36,6 +76,9 @@  is_friend (tree type, tree supplicant)
   if (supplicant == NULL_TREE || type == NULL_TREE)
     return 0;
 
+  if (is_global_friend (supplicant))
+    return 1;
+
   declp = DECL_P (supplicant);
 
   if (declp)
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index de43d81..42f1c61 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -2924,7 +2924,7 @@  build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
   tree fnname;
   tree fns;
 
-  fnname = ansi_opname (array_p ? VEC_NEW_EXPR : NEW_EXPR);
+  fnname = cp_operator_id (array_p ? VEC_NEW_EXPR : NEW_EXPR);
 
   member_new_p = !globally_qualified_p
 		 && CLASS_TYPE_P (elt_type)
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index 4d22c3d..538c806 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -202,7 +202,7 @@  lambda_function (tree lambda)
   if (CLASSTYPE_TEMPLATE_INSTANTIATION (type)
       && !COMPLETE_OR_OPEN_TYPE_P (type))
     return NULL_TREE;
-  lambda = lookup_member (type, ansi_opname (CALL_EXPR),
+  lambda = lookup_member (type, cp_operator_id (CALL_EXPR),
 			  /*protect=*/0, /*want_type=*/false,
 			  tf_warning_or_error);
   if (lambda)
diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c
index 60a70e9b..ad63186 100644
--- a/gcc/cp/lex.c
+++ b/gcc/cp/lex.c
@@ -433,7 +433,7 @@  unqualified_name_lookup_error (tree name, location_t loc)
 
   if (IDENTIFIER_OPNAME_P (name))
     {
-      if (name != ansi_opname (ERROR_MARK))
+      if (name != cp_operator_id (ERROR_MARK))
 	error_at (loc, "%qD not defined", name);
     }
   else
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 5b366f0..0a816e0 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -812,7 +812,7 @@  do_build_copy_assign (tree fndecl)
 	  parmvec = make_tree_vector_single (converted_parm);
 	  finish_expr_stmt
 	    (build_special_member_call (current_class_ref,
-					ansi_assopname (NOP_EXPR),
+					cp_assignment_operator_id (NOP_EXPR),
 					&parmvec,
 					base_binfo,
 					flags,
@@ -1105,7 +1105,7 @@  get_copy_assign (tree type)
   int quals = (TYPE_HAS_CONST_COPY_ASSIGN (type)
 	       ? TYPE_QUAL_CONST : TYPE_UNQUALIFIED);
   tree argtype = build_stub_type (type, quals, false);
-  tree fn = locate_fn_flags (type, ansi_assopname (NOP_EXPR), argtype,
+  tree fn = locate_fn_flags (type, cp_assignment_operator_id (NOP_EXPR), argtype,
 			     LOOKUP_NORMAL, tf_warning_or_error);
   if (fn == error_mark_node)
     return NULL_TREE;
@@ -1463,7 +1463,7 @@  synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
     case sfk_move_assignment:
     case sfk_copy_assignment:
       assign_p = true;
-      fnname = ansi_assopname (NOP_EXPR);
+      fnname = cp_assignment_operator_id (NOP_EXPR);
       break;
 
     case sfk_destructor:
@@ -1622,7 +1622,7 @@  synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
 
       if (check_vdtor && type_has_virtual_destructor (basetype))
 	{
-	  rval = locate_fn_flags (ctype, ansi_opname (DELETE_EXPR),
+	  rval = locate_fn_flags (ctype, cp_operator_id (DELETE_EXPR),
 				  ptr_type_node, flags, complain);
 	  /* Unlike for base ctor/op=/dtor, for operator delete it's fine
 	     to have a null rval (no class-specific op delete).  */
@@ -1941,7 +1941,7 @@  implicitly_declare_fn (special_function_kind kind, tree type,
 	  || kind == sfk_move_assignment)
 	{
 	  return_type = build_reference_type (type);
-	  name = ansi_assopname (NOP_EXPR);
+	  name = cp_assignment_operator_id (NOP_EXPR);
 	}
       else
 	name = constructor_name (type);
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 10fb540..a3cb7ee 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -92,6 +92,28 @@  get_anonymous_namespace_name (void)
 
 static GTY((deletable)) binding_entry free_binding_entry = NULL;
 
+/* The binding oracle; see cp-tree.h.  */
+
+cp_binding_oracle_function *cp_binding_oracle;
+
+/* If we have a binding oracle, ask it for all namespace-scoped
+   definitions of NAME.  */
+
+static inline void
+query_oracle (tree name)
+{
+  if (!cp_binding_oracle)
+    return;
+
+  /* LOOKED_UP holds the set of identifiers that we have already
+     looked up with the oracle.  */
+  static hash_set<tree> looked_up;
+  if (looked_up.add (name))
+    return;
+
+  cp_binding_oracle (CP_ORACLE_IDENTIFIER, name);
+}
+
 /* Create a binding_entry object for (NAME, TYPE).  */
 
 static inline binding_entry
@@ -4706,6 +4728,8 @@  qualified_lookup_using_namespace (tree name, tree scope,
   /* Look through namespace aliases.  */
   scope = ORIGINAL_NAMESPACE (scope);
 
+  query_oracle (name);
+
   /* Algorithm: Starting with SCOPE, walk through the set of used
      namespaces.  For each used namespace, look through its inline
      namespace set for any bindings and usings.  If no bindings are
@@ -5030,6 +5054,8 @@  lookup_name_real_1 (tree name, int prefer_type, int nonclass, bool block_p,
   cxx_binding *iter;
   tree val = NULL_TREE;
 
+  query_oracle (name);
+
   /* Conversion operators are handled specially because ordinary
      unqualified name lookup will not find template conversion
      operators.  */
@@ -6238,6 +6264,7 @@  pushtag (tree name, tree type, tag_scope scope)
   timevar_cond_stop (TV_NAME_LOOKUP, subtime);
   return ret;
 }
+
 
 /* Subroutines for reverting temporarily to top-level for instantiation
    of templates and such.  We actually need to clear out the class- and
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 9a61eb1..2cbbb10 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -249,9 +249,6 @@  static cp_token_cache *cp_token_cache_new
 static void cp_parser_initial_pragma
   (cp_token *);
 
-static tree cp_literal_operator_id
-  (const char *);
-
 static void cp_parser_cilk_simd
   (cp_parser *, cp_token *, bool *);
 static tree cp_parser_cilk_for
@@ -10279,7 +10276,7 @@  cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
 
     p = obstack_alloc (&declarator_obstack, 0);
 
-    declarator = make_id_declarator (NULL_TREE, ansi_opname (CALL_EXPR),
+    declarator = make_id_declarator (NULL_TREE, cp_operator_id (CALL_EXPR),
 				     sfk_none);
 
     quals = (LAMBDA_EXPR_MUTABLE_P (lambda_expr)
@@ -14297,7 +14294,7 @@  cp_parser_operator_function_id (cp_parser* parser)
 /* Return an identifier node for a user-defined literal operator.
    The suffix identifier is chained to the operator name identifier.  */
 
-static tree
+tree
 cp_literal_operator_id (const char* name)
 {
   tree identifier;
@@ -14366,12 +14363,12 @@  cp_parser_operator (cp_parser* parser)
 	    if (cp_token *close_token
 		= cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE))
 	      end_loc = close_token->location;
-	    id = ansi_opname (op == NEW_EXPR
+	    id = cp_operator_id (op == NEW_EXPR
 			      ? VEC_NEW_EXPR : VEC_DELETE_EXPR);
 	  }
 	/* Otherwise, we have the non-array variant.  */
 	else
-	  id = ansi_opname (op);
+	  id = cp_operator_id (op);
 
 	location_t loc = make_location (start_loc, start_loc, end_loc);
 
@@ -14379,147 +14376,147 @@  cp_parser_operator (cp_parser* parser)
       }
 
     case CPP_PLUS:
-      id = ansi_opname (PLUS_EXPR);
+      id = cp_operator_id (PLUS_EXPR);
       break;
 
     case CPP_MINUS:
-      id = ansi_opname (MINUS_EXPR);
+      id = cp_operator_id (MINUS_EXPR);
       break;
 
     case CPP_MULT:
-      id = ansi_opname (MULT_EXPR);
+      id = cp_operator_id (MULT_EXPR);
       break;
 
     case CPP_DIV:
-      id = ansi_opname (TRUNC_DIV_EXPR);
+      id = cp_operator_id (TRUNC_DIV_EXPR);
       break;
 
     case CPP_MOD:
-      id = ansi_opname (TRUNC_MOD_EXPR);
+      id = cp_operator_id (TRUNC_MOD_EXPR);
       break;
 
     case CPP_XOR:
-      id = ansi_opname (BIT_XOR_EXPR);
+      id = cp_operator_id (BIT_XOR_EXPR);
       break;
 
     case CPP_AND:
-      id = ansi_opname (BIT_AND_EXPR);
+      id = cp_operator_id (BIT_AND_EXPR);
       break;
 
     case CPP_OR:
-      id = ansi_opname (BIT_IOR_EXPR);
+      id = cp_operator_id (BIT_IOR_EXPR);
       break;
 
     case CPP_COMPL:
-      id = ansi_opname (BIT_NOT_EXPR);
+      id = cp_operator_id (BIT_NOT_EXPR);
       break;
 
     case CPP_NOT:
-      id = ansi_opname (TRUTH_NOT_EXPR);
+      id = cp_operator_id (TRUTH_NOT_EXPR);
       break;
 
     case CPP_EQ:
-      id = ansi_assopname (NOP_EXPR);
+      id = cp_assignment_operator_id (NOP_EXPR);
       break;
 
     case CPP_LESS:
-      id = ansi_opname (LT_EXPR);
+      id = cp_operator_id (LT_EXPR);
       break;
 
     case CPP_GREATER:
-      id = ansi_opname (GT_EXPR);
+      id = cp_operator_id (GT_EXPR);
       break;
 
     case CPP_PLUS_EQ:
-      id = ansi_assopname (PLUS_EXPR);
+      id = cp_assignment_operator_id (PLUS_EXPR);
       break;
 
     case CPP_MINUS_EQ:
-      id = ansi_assopname (MINUS_EXPR);
+      id = cp_assignment_operator_id (MINUS_EXPR);
       break;
 
     case CPP_MULT_EQ:
-      id = ansi_assopname (MULT_EXPR);
+      id = cp_assignment_operator_id (MULT_EXPR);
       break;
 
     case CPP_DIV_EQ:
-      id = ansi_assopname (TRUNC_DIV_EXPR);
+      id = cp_assignment_operator_id (TRUNC_DIV_EXPR);
       break;
 
     case CPP_MOD_EQ:
-      id = ansi_assopname (TRUNC_MOD_EXPR);
+      id = cp_assignment_operator_id (TRUNC_MOD_EXPR);
       break;
 
     case CPP_XOR_EQ:
-      id = ansi_assopname (BIT_XOR_EXPR);
+      id = cp_assignment_operator_id (BIT_XOR_EXPR);
       break;
 
     case CPP_AND_EQ:
-      id = ansi_assopname (BIT_AND_EXPR);
+      id = cp_assignment_operator_id (BIT_AND_EXPR);
       break;
 
     case CPP_OR_EQ:
-      id = ansi_assopname (BIT_IOR_EXPR);
+      id = cp_assignment_operator_id (BIT_IOR_EXPR);
       break;
 
     case CPP_LSHIFT:
-      id = ansi_opname (LSHIFT_EXPR);
+      id = cp_operator_id (LSHIFT_EXPR);
       break;
 
     case CPP_RSHIFT:
-      id = ansi_opname (RSHIFT_EXPR);
+      id = cp_operator_id (RSHIFT_EXPR);
       break;
 
     case CPP_LSHIFT_EQ:
-      id = ansi_assopname (LSHIFT_EXPR);
+      id = cp_assignment_operator_id (LSHIFT_EXPR);
       break;
 
     case CPP_RSHIFT_EQ:
-      id = ansi_assopname (RSHIFT_EXPR);
+      id = cp_assignment_operator_id (RSHIFT_EXPR);
       break;
 
     case CPP_EQ_EQ:
-      id = ansi_opname (EQ_EXPR);
+      id = cp_operator_id (EQ_EXPR);
       break;
 
     case CPP_NOT_EQ:
-      id = ansi_opname (NE_EXPR);
+      id = cp_operator_id (NE_EXPR);
       break;
 
     case CPP_LESS_EQ:
-      id = ansi_opname (LE_EXPR);
+      id = cp_operator_id (LE_EXPR);
       break;
 
     case CPP_GREATER_EQ:
-      id = ansi_opname (GE_EXPR);
+      id = cp_operator_id (GE_EXPR);
       break;
 
     case CPP_AND_AND:
-      id = ansi_opname (TRUTH_ANDIF_EXPR);
+      id = cp_operator_id (TRUTH_ANDIF_EXPR);
       break;
 
     case CPP_OR_OR:
-      id = ansi_opname (TRUTH_ORIF_EXPR);
+      id = cp_operator_id (TRUTH_ORIF_EXPR);
       break;
 
     case CPP_PLUS_PLUS:
-      id = ansi_opname (POSTINCREMENT_EXPR);
+      id = cp_operator_id (POSTINCREMENT_EXPR);
       break;
 
     case CPP_MINUS_MINUS:
-      id = ansi_opname (PREDECREMENT_EXPR);
+      id = cp_operator_id (PREDECREMENT_EXPR);
       break;
 
     case CPP_COMMA:
-      id = ansi_opname (COMPOUND_EXPR);
+      id = cp_operator_id (COMPOUND_EXPR);
       break;
 
     case CPP_DEREF_STAR:
-      id = ansi_opname (MEMBER_REF);
+      id = cp_operator_id (MEMBER_REF);
       break;
 
     case CPP_DEREF:
-      id = ansi_opname (COMPONENT_REF);
+      id = cp_operator_id (COMPONENT_REF);
       break;
 
     case CPP_OPEN_PAREN:
@@ -14527,14 +14524,14 @@  cp_parser_operator (cp_parser* parser)
       cp_lexer_consume_token (parser->lexer);
       /* Look for the matching `)'.  */
       cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
-      return ansi_opname (CALL_EXPR);
+      return cp_operator_id (CALL_EXPR);
 
     case CPP_OPEN_SQUARE:
       /* Consume the `['.  */
       cp_lexer_consume_token (parser->lexer);
       /* Look for the matching `]'.  */
       cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
-      return ansi_opname (ARRAY_REF);
+      return cp_operator_id (ARRAY_REF);
 
     case CPP_UTF8STRING:
     case CPP_UTF8STRING_USERDEF:
@@ -31964,21 +31961,21 @@  cp_parser_omp_clause_reduction (cp_parser *parser, tree list)
 	    code = MIN_EXPR;
 	  else if (strcmp (p, "max") == 0)
 	    code = MAX_EXPR;
-	  else if (id == ansi_opname (PLUS_EXPR))
+	  else if (id == cp_operator_id (PLUS_EXPR))
 	    code = PLUS_EXPR;
-	  else if (id == ansi_opname (MULT_EXPR))
+	  else if (id == cp_operator_id (MULT_EXPR))
 	    code = MULT_EXPR;
-	  else if (id == ansi_opname (MINUS_EXPR))
+	  else if (id == cp_operator_id (MINUS_EXPR))
 	    code = MINUS_EXPR;
-	  else if (id == ansi_opname (BIT_AND_EXPR))
+	  else if (id == cp_operator_id (BIT_AND_EXPR))
 	    code = BIT_AND_EXPR;
-	  else if (id == ansi_opname (BIT_IOR_EXPR))
+	  else if (id == cp_operator_id (BIT_IOR_EXPR))
 	    code = BIT_IOR_EXPR;
-	  else if (id == ansi_opname (BIT_XOR_EXPR))
+	  else if (id == cp_operator_id (BIT_XOR_EXPR))
 	    code = BIT_XOR_EXPR;
-	  else if (id == ansi_opname (TRUTH_ANDIF_EXPR))
+	  else if (id == cp_operator_id (TRUTH_ANDIF_EXPR))
 	    code = TRUTH_ANDIF_EXPR;
-	  else if (id == ansi_opname (TRUTH_ORIF_EXPR))
+	  else if (id == cp_operator_id (TRUTH_ORIF_EXPR))
 	    code = TRUTH_ORIF_EXPR;
 	  id = omp_reduction_id (code, id, NULL_TREE);
 	  tree scope = parser->scope;
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index ec8f4ab..09c1b4e 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -782,6 +782,9 @@  friend_accessible_p (tree scope, tree decl, tree type, tree otype)
   if (!scope)
     return 0;
 
+  if (is_global_friend (scope))
+    return 1;
+
   /* Is SCOPE itself a suitable P?  */
   if (TYPE_P (scope) && protected_accessible_p (decl, scope, type, otype))
     return 1;
@@ -1664,7 +1667,7 @@  lookup_fnfields_1 (tree type, tree name)
 	  if (CLASSTYPE_LAZY_MOVE_CTOR (type))
 	    lazily_declare_fn (sfk_move_constructor, type);
 	}
-      else if (name == ansi_assopname (NOP_EXPR))
+      else if (name == cp_assignment_operator_id (NOP_EXPR))
 	{
 	  if (CLASSTYPE_LAZY_COPY_ASSIGN (type))
 	    lazily_declare_fn (sfk_copy_assignment, type);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 6d5ea95..e60e067 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -5103,7 +5103,7 @@  omp_reduction_id (enum tree_code reduction_code, tree reduction_id, tree type)
     case BIT_IOR_EXPR:
     case TRUTH_ANDIF_EXPR:
     case TRUTH_ORIF_EXPR:
-      reduction_id = ansi_opname (reduction_code);
+      reduction_id = cp_operator_id (reduction_code);
       break;
     case MIN_EXPR:
       p = "min";
@@ -9008,7 +9008,7 @@  classtype_has_nothrow_assign_or_copy_p (tree type, bool assign_p)
   if (assign_p)
     {
       int ix;
-      ix = lookup_fnfields_1 (type, ansi_assopname (NOP_EXPR));
+      ix = lookup_fnfields_1 (type, cp_assignment_operator_id (NOP_EXPR));
       if (ix < 0)
 	return false;
       fns = (*CLASSTYPE_METHOD_VEC (type))[ix];
@@ -9291,7 +9291,8 @@  is_this_parameter (tree t)
 {
   if (!DECL_P (t) || DECL_NAME (t) != this_identifier)
     return false;
-  gcc_assert (TREE_CODE (t) == PARM_DECL || is_capture_proxy (t));
+  gcc_assert (TREE_CODE (t) == PARM_DECL || is_capture_proxy (t)
+	      || (cp_binding_oracle && TREE_CODE (t) == VAR_DECL));
   return true;
 }
 
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index f677b48..8f66d3c 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -8881,7 +8881,7 @@  check_return_expr (tree retval, bool *no_warning)
 
   /* Effective C++ rule 15.  See also start_function.  */
   if (warn_ecpp
-      && DECL_NAME (current_function_decl) == ansi_assopname(NOP_EXPR))
+      && DECL_NAME (current_function_decl) == cp_assignment_operator_id (NOP_EXPR))
     {
       bool warn = true;
 
diff --git a/include/gcc-c-fe.def b/include/gcc-c-fe.def
index 09998ba..acf1940 100644
--- a/include/gcc-c-fe.def
+++ b/include/gcc-c-fe.def
@@ -125,16 +125,18 @@  GCC_METHOD3 (gcc_type, build_function_type,
 	     const struct gcc_type_array *, /* Argument ARGUMENT_TYPES.  */
 	     int /* bool */)               /* Argument IS_VARARGS.  */
 
-/* Return an integer type with the given properties.  */
+/* Return an integer type with the given properties.
+   Deprecated in v1, use int_type instead.  */
 
-GCC_METHOD2 (gcc_type, int_type,
+GCC_METHOD2 (gcc_type, int_type_v0,
 	     int /* bool */,               /* Argument IS_UNSIGNED.  */
 	     unsigned long)                /* Argument SIZE_IN_BYTES.  */
 
-/* Return a floating point type with the given properties.  */
+/* Return a floating point type with the given properties.
+   Deprecated in v1, use float_type instead.  */
 
-GCC_METHOD1 (gcc_type, float_type,
-	     unsigned long)			/* Argument SIZE_IN_BYTES.  */
+GCC_METHOD1 (gcc_type, float_type_v0,
+	     unsigned long)                /* Argument SIZE_IN_BYTES.  */
 
 /* Return the 'void' type.  */
 
@@ -195,3 +197,26 @@  GCC_METHOD5 (int /* bool */, build_constant,
 
 GCC_METHOD1 (gcc_type, error,
 	     const char *)		 /* Argument MESSAGE.  */
+
+/* Return an integer type with the given properties.  If BUILTIN_NAME
+   is non-NULL, it must name a builtin integral type with the given
+   signedness and size, and that is the type that will be returned.  */
+
+GCC_METHOD3 (gcc_type, int_type,
+	     int /* bool */,               /* Argument IS_UNSIGNED.  */
+	     unsigned long,                /* Argument SIZE_IN_BYTES.  */
+	     const char *)		   /* Argument BUILTIN_NAME.  */
+
+/* Return the 'char' type, a distinct type from both 'signed char' and
+   'unsigned char' returned by int_type.  */
+
+GCC_METHOD0 (gcc_type, char_type)
+
+/* Return a floating point type with the given properties.  If BUILTIN_NAME
+   is non-NULL, it must name a builtin integral type with the given
+   signedness and size, and that is the type that will be returned.  */
+
+GCC_METHOD2 (gcc_type, float_type,
+	     unsigned long,                /* Argument SIZE_IN_BYTES.  */
+	     const char *)		   /* Argument BUILTIN_NAME.  */
+
diff --git a/include/gcc-c-interface.h b/include/gcc-c-interface.h
index 00ccbfb..e048c86 100644
--- a/include/gcc-c-interface.h
+++ b/include/gcc-c-interface.h
@@ -41,7 +41,11 @@  struct gcc_c_context;
 
 enum gcc_c_api_version
 {
-  GCC_C_FE_VERSION_0 = 0
+  GCC_C_FE_VERSION_0 = 0,
+
+  /* Added char_type.  Added new version of int_type and float_type,
+     deprecated int_type_v0 and float_type_v0.  */
+  GCC_C_FE_VERSION_1 = 1
 };
 
 /* Qualifiers.  */
@@ -111,19 +115,6 @@  typedef gcc_address gcc_c_symbol_address_function (void *datum,
 						   struct gcc_c_context *ctxt,
 						   const char *identifier);
 
-/* An array of types used for creating a function type.  */
-
-struct gcc_type_array
-{
-  /* Number of elements.  */
-
-  int n_elements;
-
-  /* The elements.  */
-
-  gcc_type *elements;
-};
-
 /* The vtable used by the C front end.  */
 
 struct gcc_c_fe_vtable
@@ -146,7 +137,7 @@  struct gcc_c_fe_vtable
      provides the declaration.
 
      DATUM is an arbitrary piece of data that is passed back verbatim
-     to the callbakcs in requests.  */
+     to the callbacks in requests.  */
 
   void (*set_callbacks) (struct gcc_c_context *self,
 			 gcc_c_oracle_function *binding_oracle,
diff --git a/include/gcc-cp-fe.def b/include/gcc-cp-fe.def
new file mode 100644
index 0000000..c367c1d
--- /dev/null
+++ b/include/gcc-cp-fe.def
@@ -0,0 +1,1050 @@ 
+/* Interface between GCC C++ FE and GDB  -*- c -*-
+
+   Copyright (C) 2014-2017 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+
+/* Push namespace NAME as the current binding level, to which
+   newly-introduced decls will be bound.  An empty string identifies
+   the global namespace, whereas NULL identifies an anonymous
+   namespace.  A namespace named NAME is created in the current scope,
+   if needed.
+
+   If the newly-created namespace is to be an inline namespace, see
+   make_namespace_inline.  */
+
+GCC_METHOD1 (int /* bool */, push_namespace,
+	     const char *)	      /* Argument NAME.  */
+
+/* Push TYPE as the current binding level, making its members visible
+   for name lookup.  The current scope before the call must be the
+   scope in which the class was declared.  This should be used if the
+   definition of a class is already finished, but one wishes to define
+   a nested class, or to enter the scope of one of its member
+   functions.  */
+
+GCC_METHOD1 (int /* bool */, push_class,
+	     gcc_type)		/* Argument TYPE.  */
+
+/* Push FUNCTION_DECL as the current (empty) binding level (see
+   reactivate_decl).  The current enclosing scope before the call must
+   be the scope in which the function was declared.  */
+
+GCC_METHOD1 (int /* bool */, push_function,
+	     gcc_decl)	     /* Argument FUNCTION_DECL.  */
+
+/* Make DECL visible (again?) within SCOPE.  When SCOPE is NULL, it
+   means the current scope; if it is not NULL, it must name a function
+   that is currently active, even if not at the top of the binding
+   chain.
+
+   This function can be used to make e.g. a global function or
+   variable visible in a namespace or local scope (overriding another
+   enclosing definition of the same name), but its most common
+   expected use of this primitive, that gives it its name, is to make
+   declarations visible again after reentering a function scope,
+   because when a function is entered with push_function, that does
+   NOT make any of the declarations nested in it visible for name
+   lookup.
+
+   There is a reason/excuse for that: unlike namespaces and classes,
+   G++ doesn't ever have to reenter function scopes, so its name
+   resolution infrastructure is not prepared to do that.  But wait,
+   there is also a good use for this apparent limitation: a function
+   may contain multiple scopes (blocks), and the name may be bound to
+   different symbols in each of these scopes.  With this interface, as
+   we reenter a function scope, we may choose which symbols to make
+   visible for the code snippet, or, if there could be template
+   functions in local scopes, for unresolved names in nested template
+   class default arguments, or in nested template function signatures.
+
+   As for making a local declaration visible for the code snippet,
+   there are two possibilities: a) introduce it upfront, while
+   entering the scope for the user expression (see the enter_scope
+   callback, called by g++ when encountering the push_user_expression
+   pragma), which might save some scope switching and reactivate_decl
+   (though this can't be helped if some declarations have to be
+   introduced and discarded, because of multiple definitions of the
+   same name in different scopes within a function: they have to be
+   defined in discriminator order); or b) introduce it when its name
+   is looked up, entering the scope, introducing the declaration,
+   leaving the scope, and then reactivating the declaration in its
+   local scope.
+
+   Here's some more detail on how reactivate_decl works.  Say there's
+   a function foo whose body looks like this:
+
+   {
+     {
+// point 1
+       class c {} o __attribute__ ((__used__)); // c  , o
+     }
+     struct c {
+       void f() {
+// point 2
+       }
+     } o __attribute__ ((__used__));            // c_0, o_0
+     {
+       class c {} p __attribute__ ((__used__)); // c_1, p
+// point 3
+       o.f();
+     }
+   }
+
+   When we are about to define class c at point 1, we enter the
+   function foo scope, and since no symbols are visible at point 1, we
+   proceed to declare class c.  We may then define the class right
+   away, or, if we leave the function scope, and we later wish to
+   define it, or to define object o, we can reenter the scope and just
+   use the previously-obtained gcc_decl to define the class, without
+   having to reactivate the declaration.
+
+   Now, if we are to set up the binding context for point 2, we have
+   to define c_0::f, and in order to do so, we have to declare and
+   define c_0.  Before we can declare c_0, we MUST at least declare c.
+
+     As a general rule, before we can declare or define any local name
+     with a discriminator, we have to at least declare any other
+     occurrences of the same name in the same enclosing entity with
+     lower or absent discriminator.
+
+   So, we declare c, then we leave the function scope and reenter it
+   so as to declare c_0 (also with name "c", which is why we have to
+   leave and reenter the function scope, otherwise we would get an
+   error because of the duplicate definition; g++ will assign a
+   discriminator because it still remembers there was an earlier
+   declaration of c_0 within the function, it's just no longer in
+   scope), then we can define c_0, including its member function f.
+
+   Likewise, if we wish to define o_0, we have to define o first.  If
+   we wish to declare (and maybe then define) c_1, we have to at least
+   declare (c and then) c_0 first.
+
+   Then, as we set up the binding context to compile a code snippet at
+   point 3, we may choose to activate c_1, o_0 and p upfront,
+   declaring and discarding c, c_0 and o, and then reentering the
+   funciton scope to declare c_1, o_0 and p; or we can wait for oracle
+   lookups of c, o or p.  If c is looked up, and the debugger resolves
+   c in the scope to c_1, it is expected to enter the function scope
+   from the top level, declare c, leave it, reenter it, declare c_0,
+   leave it, reenter it, declare c_1, leave it, and then reactivate
+   c_1 in the function scope.  If c_1 is needed as a complete type,
+   the definition may be given right after the declaration, or the
+   scope will have to be reentered in order to define the class.
+
+.  If the code snippet is at point 2, we don't need to (re)activate
+   any declaration: nothing from any local scope is visible.  Just
+   entering the scope of the class containing member function f
+   reactivates the names of its members, including the class name
+   itself.  */
+
+GCC_METHOD2 (int /* bool */, reactivate_decl,
+	     gcc_decl,		/* Argument DECL.  */
+	     gcc_decl)		/* Argument SCOPE.  */
+
+/* Pop the namespace last entered with push_namespace, or class last
+   entered with push_class, or function last entered with
+   push_function, restoring the binding level in effect before the
+   matching push_* call.  */
+
+GCC_METHOD0 (int /* bool */, pop_binding_level)
+
+/* Return the NAMESPACE_DECL, TYPE_DECL or FUNCTION_DECL of the
+   binding level that would be popped by pop_scope.  */
+
+GCC_METHOD0 (gcc_decl, get_current_binding_level_decl)
+
+/* Make the current binding level an inline namespace.  It must be a
+   namespace to begin with.  It is safe to call this more than once
+   for the same namespace, but after the first call, subsequent ones
+   will not return a success status.  */
+
+GCC_METHOD0 (int /* bool */, make_namespace_inline)
+
+/* Add USED_NS to the namespaces used by the current binding level.
+   Use get_current_binding_level_decl to obtain USED_NS's
+   gcc_decl.  */
+
+GCC_METHOD1 (int /* bool */, add_using_namespace,
+	     gcc_decl)			/* Argument USED_NS.  */
+
+/* Introduce a namespace alias declaration, as in:
+
+   namespace foo = [... ::] bar;
+
+   After this call, namespace TARGET will be visible as ALIAS within
+   the current namespace.  Get the declaration for TARGET by calling
+   get_current_binding_level_decl after pushing into it.  */
+
+GCC_METHOD2 (int /* bool */, add_namespace_alias,
+	     const char *,		/* Argument ALIAS.  */
+	     gcc_decl)			/* Argument TARGET.  */
+
+/* Introduce a using declaration, as in:
+
+   using foo::bar;
+
+   The TARGET decl names the qualifying scope (foo:: above) and the
+   identifier (bar), but that does not mean that only TARGET will be
+   brought into the current scope: all bindings of TARGET's identifier
+   in the qualifying scope will be brought in.
+
+   FLAGS should specify GCC_CP_SYMBOL_USING.  If the current scope is
+   a class scope, visibility flags must be supplied.
+
+   Even when TARGET is template dependent, we don't need to specify
+   whether or not it is a typename: the supplied declaration (that
+   could be a template-dependent type converted to declaration by
+   get_type_decl) indicates so.  */
+
+GCC_METHOD2 (int /* bool */, add_using_decl,
+	     enum gcc_cp_symbol_kind, /* Argument FLAGS.  */
+	     gcc_decl)		      /* Argument TARGET.  */
+
+/* Create a new "decl" in GCC, and bind it in the current binding
+   level.  A decl is a declaration, basically a kind of symbol.
+
+   NAME is the name of the new symbol.  SYM_KIND is the kind of
+   symbol being requested.  SYM_TYPE is the new symbol's C++ type;
+   except for labels, where this is not meaningful and should be
+   zero.  If SUBSTITUTION_NAME is not NULL, then a reference to this
+   decl in the source will later be substituted with a dereference
+   of a variable of the given name.  Otherwise, for symbols having
+   an address (e.g., functions), ADDRESS is the address.  FILENAME
+   and LINE_NUMBER refer to the symbol's source location.  If this
+   is not known, FILENAME can be NULL and LINE_NUMBER can be 0.
+   This function returns the new decl.
+
+   Use this function to register typedefs, functions and variables to
+   namespace and local binding levels, and typedefs, member functions
+   (static or not), and static data members to class binding levels.
+   Class members must have their access controls specified with
+   GCC_CP_ACCESS_* flags in SYM_KIND.
+
+   Note that, since access controls are disabled, we have no means to
+   express private, protected and public.
+
+   There are various flags that can be set in SYM_KIND to specify
+   additional semantics.  Look for GCC_CP_FLAGs in the definition of
+   enum gcc_cp_symbol_kind in gcc-cp-interface.h.
+
+   In order to define member functions, pass GCC_CP_SYMBOL_FUNCTION in
+   SYM_KIND, and a function_type for static member functions or a
+   method type for non-static member functions, including constructors
+   and destructors.  Use build_function_type to create a function
+   type; for a method type, start by creating a function type without
+   any compiler-introduced artificial arguments (the implicit this
+   pointer, and the __in_chrg added to constructors and destructors,
+   and __vtt_parm added to the former), and then use build_method_type
+   to create the method type out of the class type and the function
+   type.
+
+   For operator functions, set GCC_CP_FLAG_SPECIAL_FUNCTION in
+   SYM_KIND, in addition to any other applicable flags, and pass as
+   NAME a string starting with the two-character mangling for operator
+   name: "ps" for unary plus, "mL" for multiply and assign, *=; etc.
+   Use "cv" for type converstion operators (the target type portion
+   may be omitted, as it is taken from the return type in SYM_TYPE).
+   For operator"", use "li" followed by the identifier (the mangled
+   name mandates digits specifying the length of the identifier; if
+   present, they determine the end of the identifier, otherwise, the
+   identifier extents to the end of the string, so that "li3_Kme" and
+   "li_Km" are equivalent).
+
+   Constructors and destructors need special care, because for each
+   constructor and destructor there may be multiple clones defined
+   internally by the compiler.  With build_decl, you can introduce the
+   base declaration of a constructor or a destructor, setting
+   GCC_CP_FLAG_SPECIAL_FUNCTION the flag and using names starting with
+   capital "C" or "D", respectively, followed by a digit (see below),
+   a blank, or NUL ('\0').  DO NOT supply an ADDRESS or a
+   SUBSTITUTION_NAME to build_decl, it would be meaningless (and
+   rejected) for the base declaration; use define_cdtor_clone to
+   introduce the address of each clone.  For constructor templates,
+   declare the template with build_decl, and then, for each
+   specialization, introduce it with
+   build_function_template_specialization, and then define the
+   addresses of each of its clones with define_cdtor_clone.
+
+   NAMEs for GCC_CP_FLAG_SPECIAL_FUNCTION:
+
+     NAME    meaning
+     C?      constructor base declaration (? may be 1, 2, 4, blank or NUL)
+     D?      destructor base declaration (? may be 0, 1, 2, 4, blank or NUL)
+     nw      operator new
+     na      operator new[]
+     dl      operator delete
+     da      operator delete[]
+     ps      operator + (unary)
+     ng      operator - (unary)
+     ad      operator & (unary)
+     de      operator * (unary)
+     co      operator ~
+     pl      operator +
+     mi      operator -
+     ml      operator *
+     dv      operator /
+     rm      operator %
+     an      operator &
+     or      operator |
+     eo      operator ^
+     aS      operator =
+     pL      operator +=
+     mI      operator -=
+     mL      operator *=
+     dV      operator /=
+     rM      operator %=
+     aN      operator &=
+     oR      operator |=
+     eO      operator ^=
+     ls      operator <<
+     rs      operator >>
+     lS      operator <<=
+     rS      operator >>=
+     eq      operator ==
+     ne      operator !=
+     lt      operator <
+     gt      operator >
+     le      operator <=
+     ge      operator >=
+     nt      operator !
+     aa      operator &&
+     oo      operator ||
+     pp      operator ++
+     mm      operator --
+     cm      operator ,
+     pm      operator ->*
+     pt      operator ->
+     cl      operator ()
+     ix      operator []
+     qu      operator ?
+     cv      operator <T> (conversion operator)
+     li<id>  operator "" <id>
+
+   FIXME: How about attributes?  */
+
+GCC_METHOD7 (gcc_decl, build_decl,
+	     const char *,	      /* Argument NAME.  */
+	     enum gcc_cp_symbol_kind, /* Argument SYM_KIND.  */
+	     gcc_type,		      /* Argument SYM_TYPE.  */
+	     const char *,	      /* Argument SUBSTITUTION_NAME.  */
+	     gcc_address,	      /* Argument ADDRESS.  */
+	     const char *,	      /* Argument FILENAME.  */
+	     unsigned int)	      /* Argument LINE_NUMBER.  */
+
+/* Supply the ADDRESS of one of the multiple clones of constructor or
+   destructor CDTOR.  The clone is specified by NAME, using the
+   following name mangling conventions:
+
+     C1      in-charge constructor
+     C2      not-in-charge constructor
+     C4      unified constructor
+     D0      deleting destructor
+     D1      in-charge destructor
+     D2      not-in-charge destructor
+     D4      unified destructor
+
+   The following information is not necessary to use the API.
+
+   C1 initializes an instance of the class (rather than of derived
+   classes), including virtual base classes, whereas C2 initializes a
+   sub-object (of the given class type) of an instance of some derived
+   class (or a full object that doesn't have any virtual base
+   classes).
+
+   D0 and D1 destruct an instance of the class, including virtual base
+   classes, but only the former calls operator delete to release the
+   object's storage at the end; D2 destructs a sub-object (of the
+   given class type) of an instance of a derived class (or a full
+   object that doesn't have any virtual base classes).
+
+   The [CD]4 manglings (and symbol definitions) are non-standard, but
+   GCC uses them in some cases: rather than assuming they are
+   in-charge or not-in-charge, they test the implicit argument that
+   the others ignore to tell how to behave.  These are used instead of
+   cloning when we just can't use aliases.  */
+
+GCC_METHOD3 (gcc_decl, define_cdtor_clone,
+	     const char *,	      /* Argument NAME.  */
+	     gcc_decl,		      /* Argument CDTOR.  */
+	     gcc_address)	      /* Argument ADDRESS.  */
+
+/* Return the type associated with the given declaration.  This is
+   most useful to obtain the type associated with a forward-declared
+   class, because it is the gcc_type, rather than the gcc_decl, that
+   has to be used to build other types, but build_decl returns a
+   gcc_decl rather than a gcc_type.  This call can in theory be used
+   to obtain the type from any other declaration; it is supposed to
+   return the same type that was supplied when the declaration was
+   created.  */
+
+GCC_METHOD1 (gcc_type, get_decl_type,
+	     gcc_decl)            /* Argument DECL.  */
+
+/* Return the declaration for a type.  */
+
+GCC_METHOD1 (gcc_decl, get_type_decl,
+	     gcc_type)            /* Argument TYPE.  */
+
+/* Declare DECL as a friend of the current class scope, if TYPE is
+   NULL, or of TYPE itself otherwise.  DECL may be a function or a
+   class, be they template generics, template specializations or not
+   templates.  TYPE must be a class type (not a template generic).
+
+   The add_friend call cannot introduce a declaration; even if the
+   friend is first declared as a friend in the source code, the
+   declaration belongs in the enclosing namespace, so it must be
+   introduced in that namespace, and the resulting declaration can
+   then be made a friend.
+
+   DECL cannot, however, be a member of a template class generic,
+   because we have no means to introduce their declarations.  This
+   interface has no notion of definitions for template generics.  As a
+   consequence, users of this interface must introduce each friend
+   template member specialization separately, i.e., instead of:
+
+     template <typename T> friend struct X<T>::M;
+
+   they must be declared as if they were:
+
+     friend struct X<onetype>::M;
+     friend struct X<anothertype>::M;
+     ... for each specialization of X.
+
+
+   Specializations of a template can have each others' members as
+   friends:
+
+     template <typename T> class foo {
+       int f();
+       template <typename U> friend int foo<U>::f();
+     };
+
+   It wouldn't always be possible to define all specializations of a
+   template class before introducing the friend declarations in their
+   expanded, per-specialization form.
+
+   In order to simplify such friend declarations, and to enable
+   incremental friend declarations as template specializations are
+   introduced, add_friend can be called after the befriending class is
+   fully defined, passing it a non-NULL TYPE argument naming the
+   befriending class type.  */
+
+GCC_METHOD2 (int /* bool */, add_friend,
+	     gcc_decl,		      /* Argument DECL.  */
+	     gcc_type)		      /* Argument TYPE.  */
+
+/* Return the type of a pointer to a given base type.  */
+
+GCC_METHOD1 (gcc_type, build_pointer_type,
+	     gcc_type)			/* Argument BASE_TYPE.  */
+
+/* Return the type of a reference to a given base type.  */
+
+GCC_METHOD2 (gcc_type, build_reference_type,
+	     gcc_type,			/* Argument BASE_TYPE.  */
+	     enum gcc_cp_ref_qualifiers)   /* Argument RQUALS.  */
+
+/* Create a new pointer-to-member type.  MEMBER_TYPE is the data
+   member type, while CLASS_TYPE is the class type containing the data
+   member.  For pointers to member functions, MEMBER_TYPE must be a
+   method type, and CLASS_TYPE must be specified even though it might
+   be possible to extract it from the method type.  */
+
+GCC_METHOD2 (gcc_type, build_pointer_to_member_type,
+	     gcc_type,			   /* Argument CLASS_TYPE.  */
+	     gcc_type) 			   /* Argument MEMBER_TYPE.  */
+
+/* Start a template parameter list scope and enters it, so that
+   subsequent build_type_template_parameter and
+   build_value_template_parameter calls create template parameters in
+   the list.  The list is closed by a build_decl call with
+   GCC_CP_SYMBOL_FUNCTION or GCC_CP_SYMBOL_CLASS, that, when the scope
+   is a template parameter list, declares a template function or a
+   template class with the then-closed parameter list.  The scope in
+   which the new declaration is to be introduced by build_decl must be
+   entered before calling start_template_decl, and build_decl returns
+   to that scope, from the template parameter list scope, before
+   introducing the declaration.  */
+
+GCC_METHOD0 (int /* bool */, start_template_decl)
+
+/* Build a typename template-parameter (e.g., the T in template
+   <typename T = X>).  Either PACK_P should be nonzero, to indicate an
+   argument pack (the last argument in a variadic template argument
+   list, as in template <typename... T>), or DEFAULT_TYPE may be
+   non-NULL to set the default type argument (e.g. X) for the template
+   parameter.  FILENAME and LINE_NUMBER may specify the source
+   location in which the template parameter was declared.  */
+
+GCC_METHOD5 (gcc_type, build_type_template_parameter,
+	     const char *,			      /* Argument ID.  */
+	     int /* bool */,			  /* Argument PACK_P.  */
+	     gcc_type,			    /* Argument DEFAULT_TYPE.  */
+	     const char *,			/* Argument FILENAME.  */
+	     unsigned int)		     /* Argument LINE_NUMBER.  */
+
+/* Build a template template-parameter (e.g., the T in template
+   <template <[...]> class T = X>).  DEFAULT_TEMPL may be non-NULL to
+   set the default type-template argument (e.g. X) for the template
+   template parameter.  FILENAME and LINE_NUMBER may specify the
+   source location in which the template parameter was declared.  */
+
+GCC_METHOD5 (gcc_utempl, build_template_template_parameter,
+	     const char *,			      /* Argument ID.  */
+	     int /* bool */,			  /* Argument PACK_P.  */
+	     gcc_utempl,		   /* Argument DEFAULT_TEMPL.  */
+	     const char *,			/* Argument FILENAME.  */
+	     unsigned int)		     /* Argument LINE_NUMBER.  */
+
+/* Build a value template-parameter (e.g., the V in template <typename
+   T, T V> or in template <int V = X>).  DEFAULT_VALUE may be non-NULL
+   to set the default value argument for the template parameter (e.g.,
+   X).  FILENAME and LINE_NUMBER may specify the source location in
+   which the template parameter was declared.  */
+
+GCC_METHOD5 (gcc_decl, build_value_template_parameter,
+	     gcc_type,			  	    /* Argument TYPE.  */
+	     const char *,			      /* Argument ID.  */
+	     gcc_expr,			   /* Argument DEFAULT_VALUE.  */
+	     const char *,			/* Argument FILENAME.  */
+	     unsigned int)		     /* Argument LINE_NUMBER.  */
+
+/* Build a template-dependent typename (e.g., typename T::bar or
+   typename T::template bart<X>).  ENCLOSING_TYPE should be the
+   template-dependent nested name specifier (e.g., T), ID should be
+   the name of the member of the ENCLOSING_TYPE (e.g., bar or bart),
+   and TARGS should be non-NULL and specify the template arguments
+   (e.g. <X>) iff ID is to name a class template.
+
+   In this and other calls, a template-dependent nested name specifier
+   may be a template class parameter (build_type_template_parameter),
+   a specialization (returned by build_dependent_type_template_id) of
+   a template template parameter (returned by
+   build_template_template_parameter) or a member type thereof
+   (returned by build_dependent_typename itself).  */
+
+GCC_METHOD3 (gcc_type, build_dependent_typename,
+	     gcc_type,			  /* Argument ENCLOSING_TYPE.  */
+	     const char *,			      /* Argument ID.  */
+	     const struct gcc_cp_template_args *)  /* Argument TARGS.  */
+
+/* Build a template-dependent class template (e.g., T::template bart).
+   ENCLOSING_TYPE should be the template-dependent nested name
+   specifier (e.g., T), ID should be the name of the class template
+   member of the ENCLOSING_TYPE (e.g., bart).  */
+
+GCC_METHOD2 (gcc_utempl, build_dependent_class_template,
+	     gcc_type,			  /* Argument ENCLOSING_TYPE.  */
+	     const char *)			      /* Argument ID.  */
+
+/* Build a template-dependent type template-id (e.g., T<A>).
+   TEMPLATE_DECL should be a template template parameter (e.g., the T
+   in template <template <[...]> class T = X>), and TARGS should
+   specify the template arguments (e.g. <A>).  */
+
+GCC_METHOD2 (gcc_type, build_dependent_type_template_id,
+	     gcc_utempl,		   /* Argument TEMPLATE_DECL.  */
+	     const struct gcc_cp_template_args *)  /* Argument TARGS.  */
+
+/* Build a template-dependent expression (e.g., S::val or S::template
+   mtf<X>, or unqualified f or template tf<X>).
+
+   ENCLOSING_SCOPE should be a template-dependent nested name
+   specifier (e.g., T), a resolved namespace or class decl, or NULL
+   for unqualified names; ID should be the name of the member of the
+   ENCLOSING_SCOPE (e.g., val or mtf) or unqualified overloaded
+   function; and TARGS should list template arguments (e.g. <X>) when
+   mtf or tf are to name a template function, or be NULL otherwise.
+
+   Unqualified names and namespace- or class-qualified names can only
+   resolve to overloaded functions, to be used in contexts that
+   involve overload resolution that cannot be resolved because of
+   template-dependent argument or return types, such as call
+   expressions with template-dependent arguments, conversion
+   expressions to function types with template-dependent argument
+   types or the like.  Other cases of unqualified or
+   non-template-dependent-qualified names should NOT use this
+   function, and use decl_expr to convert the appropriate function or
+   object declaration to an expression.
+
+   If ID is the name of a special member function, FLAGS should be
+   GCC_CP_SYMBOL_FUNCTION|GCC_CP_FLAG_SPECIAL_FUNCTION, and ID should
+   be one of the encodings for special member functions documented in
+   build_decl.  Otherwise, FLAGS should be GCC_CP_SYMBOL_MASK, which
+   suggests the symbol kind is not known (though we know it is not a
+   type).
+
+   If ID denotes a conversion operator, CONV_TYPE should name the
+   target type of the conversion.  Otherwise, CONV_TYPE must be
+   NULL.  */
+
+GCC_METHOD5 (gcc_expr, build_dependent_expr,
+	     gcc_decl,			 /* Argument ENCLOSING_SCOPE.  */
+	     enum gcc_cp_symbol_kind,		   /* Argument FLAGS.  */
+	     const char *,			    /* Argument NAME.  */
+	     gcc_type,			       /* Argument CONV_TYPE.  */
+	     const struct gcc_cp_template_args *)  /* Argument TARGS.  */
+
+/* Build a gcc_expr for the value VALUE in type TYPE.  */
+
+GCC_METHOD2 (gcc_expr, build_literal_expr,
+	     gcc_type,		  /* Argument TYPE.  */
+	     unsigned long)	  /* Argument VALUE.  */
+
+/* Build a gcc_expr that denotes DECL, the declaration of a variable
+   or function in namespace scope, or of a static member variable or
+   function.  Use QUALIFIED_P to build the operand of unary & so as to
+   compute a pointer-to-member, rather than a regular pointer.  */
+
+GCC_METHOD2 (gcc_expr, build_decl_expr,
+	     gcc_decl,			/* Argument DECL.  */
+	     int /* bool */)		/* Argument QUALIFIED_P.  */
+
+/* Build a gcc_expr that denotes the unary operation UNARY_OP applied
+   to the gcc_expr OPERAND.  For non-expr operands, see
+   unary_type_expr.  Besides the UNARY_OP encodings used for operator
+   names, we support "pp_" for preincrement, and "mm_" for
+   predecrement, "nx" for noexcept, "tw" for throw, "tr" for rethrow
+   (pass NULL as the operand), "te" for typeid, "sz" for sizeof, "az"
+   for alignof, "dl" for delete, "gsdl" for ::delete, "da" for
+   delete[], "gsda" for ::delete[], "sp" for pack expansion, "sZ" for
+   sizeof...(function argument pack).  */
+
+GCC_METHOD2 (gcc_expr, build_unary_expr,
+	     const char *,	  /* Argument UNARY_OP.  */
+	     gcc_expr)		  /* Argument OPERAND.  */
+
+/* Build a gcc_expr that denotes the binary operation BINARY_OP
+   applied to gcc_exprs OPERAND1 and OPERAND2.  Besides the BINARY_OP
+   encodings used for operator names, we support "ds" for the operator
+   token ".*" and "dt" for the operator token ".".  When using
+   operators that take a name as their second operand ("." and "->")
+   use decl_expr to convert the gcc_decl of the member name to a
+   gcc_expr, if the member name wasn't created with
+   e.g. build_dependent_expr.  */
+
+GCC_METHOD3 (gcc_expr, build_binary_expr,
+	     const char *,	  /* Argument BINARY_OP.  */
+	     gcc_expr,		  /* Argument OPERAND1.  */
+	     gcc_expr)		  /* Argument OPERAND2.  */
+
+/* Build a gcc_expr that denotes the ternary operation TERNARY_OP
+   applied to gcc_exprs OPERAND1, OPERAND2 and OPERAND3.  The only
+   supported TERNARY_OP is "qu", for the "?:" operator.  */
+
+GCC_METHOD4 (gcc_expr, build_ternary_expr,
+	     const char *,	  /* Argument TERNARY_OP.  */
+	     gcc_expr,		  /* Argument OPERAND1.  */
+	     gcc_expr,		  /* Argument OPERAND2.  */
+	     gcc_expr)		  /* Argument OPERAND3.  */
+
+/* Build a gcc_expr that denotes the unary operation UNARY_OP applied
+   to the gcc_type OPERAND.  Supported unary operations taking types
+   are "ti" for typeid, "st" for sizeof, "at" for alignof, and "sZ"
+   for sizeof...(template argument pack).  */
+
+GCC_METHOD2 (gcc_expr, build_unary_type_expr,
+	     const char *,	  /* Argument UNARY_OP.  */
+	     gcc_type)		  /* Argument OPERAND.  */
+
+/* Build a gcc_expr that denotes the binary operation BINARY_OP
+   applied to gcc_type OPERAND1 and gcc_expr OPERAND2.  Use this for
+   all kinds of (single-argument) type casts ("dc", "sc", "cc", "rc"
+   for dynamic, static, const and reinterpret casts, respectively;
+   "cv" for functional or C-style casts).  */
+
+GCC_METHOD3 (gcc_expr, build_cast_expr,
+	     const char *,	  /* Argument BINARY_OP.  */
+	     gcc_type,		  /* Argument OPERAND1.  */
+	     gcc_expr)		  /* Argument OPERAND2.  */
+
+/* Build a gcc_expr that denotes the conversion of an expression list
+   VALUES to TYPE, with ("tl") or without ("cv") braces, or a braced
+   initializer list of unspecified type (e.g., a component of another
+   braced initializer list; pass "il" for CONV_OP, and NULL for
+   TYPE).  */
+
+GCC_METHOD3 (gcc_expr, build_expression_list_expr,
+	     const char *,			 /* Argument CONV_OP.  */
+	     gcc_type,				    /* Argument TYPE.  */
+	     const struct gcc_cp_function_args *) /* Argument VALUES.  */
+
+/* Build a gcc_expr that denotes a new ("nw") or new[] ("na")
+   expression of TYPE, with or without a GLOBAL_NS qualifier (prefix
+   the NEW_OP with "gs"), with or without PLACEMENT, with or without
+   INITIALIZER.  If it's not a placement new, PLACEMENT must be NULL
+   (rather than a zero-length placement arg list).  If there's no
+   specified initializer, INITIALIZER must be NULL; a zero-length arg
+   list stands for a default initializer.  */
+
+GCC_METHOD4 (gcc_expr, build_new_expr,
+	     const char *,			       /* Argument NEW_OP.  */
+	     const struct gcc_cp_function_args *,   /* Argument PLACEMENT.  */
+	     gcc_type,					 /* Argument TYPE.  */
+	     const struct gcc_cp_function_args *) /* Argument INITIALIZER.  */
+
+/* Return a call expression that calls CALLABLE with arguments ARGS.
+   CALLABLE may be a function, a callable object, a pointer to
+   function, an unresolved expression, an unresolved overload set, an
+   object expression combined with a member function overload set or a
+   pointer-to-member.  If QUALIFIED_P, CALLABLE will be interpreted as
+   a qualified name, preventing virtual function dispatch.  */
+
+GCC_METHOD3 (gcc_expr, build_call_expr,
+	     gcc_expr,			      /* Argument CALLABLE.  */
+	     int /* bool */,		   /* Argument QUALIFIED_P.  */
+	     const struct gcc_cp_function_args *) /* Argument ARGS.  */
+
+/* Return the type of the gcc_expr OPERAND.
+   Use this for decltype.
+   For decltype (auto), pass a NULL OPERAND.
+
+   Note: for template-dependent expressions, the result is NULL,
+   because the type is only computed when template argument
+   substitution is performed.  */
+
+GCC_METHOD1 (gcc_type, get_expr_type,
+	     gcc_expr)		  /* Argument OPERAND.  */
+
+/* Introduce a specialization of a template function.
+
+   TEMPLATE_DECL is the template function, and TARGS are the arguments
+   for the specialization.  ADDRESS is the address of the
+   specialization.  FILENAME and LINE_NUMBER specify the source
+   location associated with the template function specialization.  */
+
+GCC_METHOD5 (gcc_decl, build_function_template_specialization,
+	     gcc_decl,			   /* Argument TEMPLATE_DECL.  */
+	     const struct gcc_cp_template_args *,  /* Argument TARGS.  */
+	     gcc_address,			 /* Argument ADDRESS.  */
+	     const char *,	      /* Argument FILENAME.  */
+	     unsigned int)	      /* Argument LINE_NUMBER.  */
+
+/* Specialize a template class as an incomplete type.  A definition
+   can be supplied later, with start_class_type.
+
+   TEMPLATE_DECL is the template class, and TARGS are the arguments
+   for the specialization.  FILENAME and LINE_NUMBER specify the
+   source location associated with the template class
+   specialization.  */
+
+GCC_METHOD4 (gcc_decl, build_class_template_specialization,
+	     gcc_decl,			   /* Argument TEMPLATE_DECL.  */
+	     const struct gcc_cp_template_args *,  /* Argument TARGS.  */
+	     const char *,	      /* Argument FILENAME.  */
+	     unsigned int)	      /* Argument LINE_NUMBER.  */
+
+/* Start defining a 'class', 'struct' or 'union' type, entering its
+   own binding level.  Initially it has no fields.
+
+   TYPEDECL is the forward-declaration of the type, returned by
+   build_decl.  BASE_CLASSES indicate the base classes of class NAME.
+   FILENAME and LINE_NUMBER specify the source location associated
+   with the class definition, should they be different from those of
+   the forward declaration.  */
+
+GCC_METHOD4 (gcc_type, start_class_type,
+	     gcc_decl,		      /* Argument TYPEDECL.  */
+	     const struct gcc_vbase_array *,/* Argument BASE_CLASSES.  */
+	     const char *,	      /* Argument FILENAME.  */
+	     unsigned int)	      /* Argument LINE_NUMBER.  */
+
+/* Create a new closure class type, record it as the
+   DISCRIMINATOR-numbered closure type in the current scope (or
+   associated with EXTRA_SCOPE, if non-NULL), and enter the closure
+   type's own binding level.  This primitive would sort of combine
+   build_decl and start_class_type, if they could be used to introduce
+   a closure type.  Initially it has no fields.
+
+   FILENAME and LINE_NUMBER specify the source location associated
+   with the class.  EXTRA_SCOPE, if non-NULL, must be a PARM_DECL of
+   the current function, or a FIELD_DECL of the current class.  If it
+   is NULL, the current scope must be a function.  */
+
+GCC_METHOD5 (gcc_type, start_closure_class_type,
+	     int,		      /* Argument DISCRIMINATOR.  */
+	     gcc_decl,		      /* Argument EXTRA_SCOPE.  */
+	     enum gcc_cp_symbol_kind, /* Argument FLAGS.  */
+	     const char *,	      /* Argument FILENAME.  */
+	     unsigned int)	      /* Argument LINE_NUMBER.  */
+
+/* Add a non-static data member to the most-recently-started
+   unfinished struct or union type.  FIELD_NAME is the field's name.
+   FIELD_TYPE is the type of the field.  BITSIZE and BITPOS indicate
+   where in the struct the field occurs.  */
+
+GCC_METHOD5 (gcc_decl, build_field,
+	     const char *,		   /* Argument FIELD_NAME.  */
+	     gcc_type,			   /* Argument FIELD_TYPE.  */
+	     enum gcc_cp_symbol_kind,	   /* Argument FIELD_FLAGS.  */
+	     unsigned long,		   /* Argument BITSIZE.  */
+	     unsigned long)		   /* Argument BITPOS.  */
+
+/* After all the fields have been added to a struct, class or union,
+   the struct or union type must be "finished".  This does some final
+   cleanups in GCC, and pops to the binding level that was in effect
+   before the matching start_class_type or
+   start_closure_class_type.  */
+
+GCC_METHOD1 (int /* bool */, finish_class_type,
+	     unsigned long)		   /* Argument SIZE_IN_BYTES.  */
+
+/* Create a new 'enum' type, and record it in the current binding
+   level.  The new type initially has no associated constants.
+
+   NAME is the enum name.  FILENAME and LINE_NUMBER specify its source
+   location.  */
+
+GCC_METHOD5 (gcc_type, start_enum_type,
+	     const char *,	      /* Argument NAME.  */
+	     gcc_type,		      /* Argument UNDERLYING_INT_TYPE. */
+	     enum gcc_cp_symbol_kind, /* Argument FLAGS.  */
+	     const char *,	      /* Argument FILENAME.  */
+	     unsigned int)	      /* Argument LINE_NUMBER.  */
+
+/* Add a new constant to an enum type.  NAME is the constant's name
+   and VALUE is its value.  Returns a gcc_decl for the constant.  */
+
+GCC_METHOD3 (gcc_decl, build_enum_constant,
+	     gcc_type,		       /* Argument ENUM_TYPE.  */
+	     const char *,	       /* Argument NAME.  */
+	     unsigned long)	       /* Argument VALUE.  */
+
+/* After all the constants have been added to an enum, the type must
+   be "finished".  This does some final cleanups in GCC.  */
+
+GCC_METHOD1 (int /* bool */, finish_enum_type,
+	     gcc_type)		       /* Argument ENUM_TYPE.  */
+
+/* Create a new function type.  RETURN_TYPE is the type returned by
+   the function, and ARGUMENT_TYPES is a vector, of length NARGS, of
+   the argument types.  IS_VARARGS is true if the function is
+   varargs.  */
+
+GCC_METHOD3 (gcc_type, build_function_type,
+	     gcc_type,			   /* Argument RETURN_TYPE.  */
+	     const struct gcc_type_array *,/* Argument ARGUMENT_TYPES.  */
+	     int /* bool */)		   /* Argument IS_VARARGS.  */
+
+/* Create a variant of a function type with an exception
+   specification.  FUNCTION_TYPE is a function or method type.
+   EXCEPT_TYPES is an array with the list of exception types.  Zero as
+   the array length implies throw() AKA noexcept(true); NULL as the
+   pointer to gcc_type_array implies noexcept(false), which is almost
+   equivalent (but distinguishable by the compiler) to an unspecified
+   exception list.  */
+
+GCC_METHOD2 (gcc_type, build_exception_spec_variant,
+	     gcc_type,			   /* Argument FUNCTION_TYPE.  */
+	     const struct gcc_type_array *)/* Argument EXCEPT_TYPES.  */
+
+/* Create a new non-static member function type.  FUNC_TYPE is the
+   method prototype, without the implicit THIS pointer, added as a
+   pointer to the QUALS-qualified CLASS_TYPE.  If CLASS_TYPE is NULL,
+   this creates a cv-qualified (member) function type not associated
+   with any specific class, as needed to support "typedef void f(int)
+   const;", which can later be used to declare member functions and
+   pointers to member functions.  */
+
+GCC_METHOD4 (gcc_type, build_method_type,
+	     gcc_type,			   /* Argument CLASS_TYPE.  */
+	     gcc_type, 			   /* Argument FUNC_TYPE.  */
+	     enum gcc_cp_qualifiers,	   /* Argument QUALS.  */
+	     enum gcc_cp_ref_qualifiers)   /* Argument RQUALS.  */
+
+/* Return a declaration for the (INDEX - 1)th argument of
+   FUNCTION_DECL, i.e., for the first argument, use zero as the index.
+   If FUNCTION_DECL is a non-static member function, use -1 to get the
+   implicit THIS parameter.  */
+
+GCC_METHOD2 (gcc_decl, get_function_parameter_decl,
+	     gcc_decl,			     /* Argument FUNCTION_DECL.  */
+	     int)				     /* Argument INDEX.  */
+
+/* Return a lambda expr that constructs an instance of CLOSURE_TYPE.
+   Only lambda exprs without any captures can be correctly created
+   through these mechanisms; that's all we need to support lambdas
+   expressions in default parameters, the only kind that may have to
+   be introduced through this interface.  */
+
+GCC_METHOD1 (gcc_expr, build_lambda_expr,
+	     gcc_type)			      /* Argument CLOSURE_TYPE.  */
+
+/* Return an integer type with the given properties.  If BUILTIN_NAME
+   is non-NULL, it must name a builtin integral type with the given
+   signedness and size, and that is the type that will be returned.  */
+
+GCC_METHOD3 (gcc_type, get_int_type,
+	     int /* bool */,		   /* Argument IS_UNSIGNED.  */
+	     unsigned long,                /* Argument SIZE_IN_BYTES.  */
+	     const char *)		   /* Argument BUILTIN_NAME.  */
+
+/* Return the 'char' type, a distinct type from both 'signed char' and
+   'unsigned char' returned by int_type.  */
+
+GCC_METHOD0 (gcc_type, get_char_type)
+
+/* Return a floating point type with the given properties.  If BUILTIN_NAME
+   is non-NULL, it must name a builtin integral type with the given
+   signedness and size, and that is the type that will be returned.  */
+
+GCC_METHOD2 (gcc_type, get_float_type,
+	     unsigned long,                /* Argument SIZE_IN_BYTES.  */
+	     const char *)		   /* Argument BUILTIN_NAME.  */
+
+/* Return the 'void' type.  */
+
+GCC_METHOD0 (gcc_type, get_void_type)
+
+/* Return the 'bool' type.  */
+
+GCC_METHOD0 (gcc_type, get_bool_type)
+
+/* Return the std::nullptr_t type.  */
+
+GCC_METHOD0 (gcc_type, get_nullptr_type)
+
+/* Return the nullptr constant.  */
+
+GCC_METHOD0 (gcc_expr, get_nullptr_constant)
+
+/* Create a new array type.  If NUM_ELEMENTS is -1, then the array
+   is assumed to have an unknown length.  */
+
+GCC_METHOD2 (gcc_type, build_array_type,
+	     gcc_type,			  /* Argument ELEMENT_TYPE.  */
+	     int)			  /* Argument NUM_ELEMENTS.  */
+
+/* Create a new array type.  NUM_ELEMENTS is a template-dependent
+   expression.  */
+
+GCC_METHOD2 (gcc_type, build_dependent_array_type,
+	     gcc_type,			  /* Argument ELEMENT_TYPE.  */
+	     gcc_expr)			  /* Argument NUM_ELEMENTS.  */
+
+/* Create a new variably-sized array type.  UPPER_BOUND_NAME is the
+   name of a local variable that holds the upper bound of the array;
+   it is one less than the array size.  */
+
+GCC_METHOD2 (gcc_type, build_vla_array_type,
+	     gcc_type,			  /* Argument ELEMENT_TYPE.  */
+	     const char *)		  /* Argument UPPER_BOUND_NAME.  */
+
+/* Return a qualified variant of a given base type.  QUALIFIERS says
+   which qualifiers to use; it is composed of or'd together
+   constants from 'enum gcc_cp_qualifiers'.  */
+
+GCC_METHOD2 (gcc_type, build_qualified_type,
+	     gcc_type,			      /* Argument UNQUALIFIED_TYPE.  */
+	     enum gcc_cp_qualifiers)	      /* Argument QUALIFIERS.  */
+
+/* Build a complex type given its element type.  */
+
+GCC_METHOD1 (gcc_type, build_complex_type,
+	     gcc_type)			  /* Argument ELEMENT_TYPE.  */
+
+/* Build a vector type given its element type and number of
+   elements.  */
+
+GCC_METHOD2 (gcc_type, build_vector_type,
+	     gcc_type,			  /* Argument ELEMENT_TYPE.  */
+	     int)			  /* Argument NUM_ELEMENTS.  */
+
+/* Build a constant.  NAME is the constant's name and VALUE is its
+   value.  FILENAME and LINE_NUMBER refer to the type's source
+   location.  If this is not known, FILENAME can be NULL and
+   LINE_NUMBER can be 0.  */
+
+GCC_METHOD5 (int /* bool */, build_constant,
+	     gcc_type,		  /* Argument TYPE.  */
+	     const char *,	  /* Argument NAME.  */
+	     unsigned long,	  /* Argument VALUE.  */
+	     const char *,	  /* Argument FILENAME.  */
+	     unsigned int)	  /* Argument LINE_NUMBER.  */
+
+/* Emit an error and return an error type object.  */
+
+GCC_METHOD1 (gcc_type, error,
+	     const char *)		 /* Argument MESSAGE.  */
+
+/* Declare a static_assert with the given CONDITION and ERRORMSG at
+   FILENAME:LINE_NUMBER.  */
+
+GCC_METHOD4 (int /* bool */, add_static_assert,
+	     gcc_expr,     /* Argument CONDITION.  */
+	     const char *, /* Argument ERRORMSG.  */
+	     const char *, /* Argument FILENAME.  */
+	     unsigned int) /* Argument LINE_NUMBER.  */
+
+#if 0
+
+/* FIXME: We don't want to expose the internal implementation detail
+   that default parms are stored in function types, and it's not clear
+   how this or other approaches would interact with the type sharing
+   of e.g. ctor clones, so we're leaving this out, since default args
+   are not even present in debug information anyway.  Besides, the set
+   of default args for a function may grow within its scope, and vary
+   independently in other scopes.  */
+
+/* Create a modified version of a function type that has default
+   values for some of its arguments.  The returned type should ONLY be
+   used to define functions or methods, never to declare parameters,
+   variables, types or the like.
+
+   DEFAULTS must have at most as many N_ELEMENTS as there are
+   arguments without default values in FUNCTION_TYPE.  Say, if
+   FUNCTION_TYPE has an argument list such as (T1, T2, T3, T4 = V0)
+   and DEFAULTS has 2 elements (V1, V2), the returned type will have
+   the following argument list: (T1, T2 = V1, T3 = V2, T4 = V0).
+
+   Any NULL expressions in DEFAULTS will be marked as deferred, and
+   they should be filled in with set_deferred_function_default_args.  */
+
+GCC_METHOD2 (gcc_type, add_function_default_args,
+	     gcc_type,			     /* Argument FUNCTION_TYPE.  */
+	     const struct gcc_cp_function_args *) /* Argument DEFAULTS.  */
+
+/* Fill in the first deferred default args in FUNCTION_DECL with the
+   expressions given in DEFAULTS.  This can be used when the
+   declaration of a parameter is needed to create a default
+   expression, such as taking the size of an earlier parameter, or
+   building a lambda expression in the parameter's context.  */
+
+GCC_METHOD2 (int /* bool */, set_deferred_function_default_args,
+	     gcc_decl,			     /* Argument FUNCTION_DECL.  */
+	     const struct gcc_cp_function_args *) /* Argument DEFAULTS.  */
+
+#endif
+
+
+/* When you add entry points, add them at the end, so that the new API
+   version remains compatible with the old version.
+
+   The following conventions have been observed as to naming entry points:
+
+   - build_* creates (and maybe records) something and returns it;
+   - add_* creates and records something, but doesn't return it;
+   - get_* obtains something without creating it;
+   - start_* marks the beginning of a compound (type, list, ...);
+   - finish_* completes the compound when needed.
+
+  Entry points that return an int (bool) and don't have a return value
+  specification return nonzero (true) on success and zero (false) on
+  failure.  This is in line with libcc1's conventions of returning a
+  zero-initialized value in case of e.g. a transport error.  */
diff --git a/include/gcc-cp-interface.h b/include/gcc-cp-interface.h
new file mode 100644
index 0000000..6ef9e22
--- /dev/null
+++ b/include/gcc-cp-interface.h
@@ -0,0 +1,496 @@ 
+/* Interface between GCC C++ FE and GDB
+
+   Copyright (C) 2014-2017 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_CP_INTERFACE_H
+#define GCC_CP_INTERFACE_H
+
+#include "gcc-interface.h"
+
+/* This header defines the interface to the GCC API.  It must be both
+   valid C and valid C++, because it is included by both programs.  */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Forward declaration.  */
+
+struct gcc_cp_context;
+
+/*
+ * Definitions and declarations for the C++ front end.
+ */
+
+/* Defined versions of the C++ front-end API.  */
+
+enum gcc_cp_api_version
+{
+  GCC_CP_FE_VERSION_0 = 0
+};
+
+/* Qualifiers.  */
+
+enum gcc_cp_qualifiers
+{
+  GCC_CP_QUALIFIER_CONST = 1,
+  GCC_CP_QUALIFIER_VOLATILE = 2,
+  GCC_CP_QUALIFIER_RESTRICT = 4
+};
+
+/* Ref qualifiers.  */
+
+enum gcc_cp_ref_qualifiers {
+  GCC_CP_REF_QUAL_NONE = 0,
+  GCC_CP_REF_QUAL_LVALUE = 1,
+  GCC_CP_REF_QUAL_RVALUE = 2
+};
+
+/* Opaque typedef for unbound class templates.  They are used for
+   template arguments, and defaults for template template
+   parameters.  */
+
+typedef unsigned long long gcc_utempl;
+
+/* Opaque typedef for expressions.  They are used for template
+   arguments, defaults for non-type template parameters, and defaults
+   for function arguments.  */
+
+typedef unsigned long long gcc_expr;
+
+typedef enum
+  { GCC_CP_TPARG_VALUE, GCC_CP_TPARG_CLASS,
+    GCC_CP_TPARG_TEMPL, GCC_CP_TPARG_PACK }
+gcc_cp_template_arg_kind;
+
+typedef union
+{ gcc_expr value; gcc_type type; gcc_utempl templ; gcc_type pack; }
+gcc_cp_template_arg;
+
+/* An array of template arguments.  */
+
+struct gcc_cp_template_args
+{
+  /* Number of elements.  */
+
+  int n_elements;
+
+  /* kind[i] indicates what kind of template argument type[i] is.  */
+
+  char /* gcc_cp_template_arg_kind */ *kinds;
+
+  /* The template arguments.  */
+
+  gcc_cp_template_arg *elements;
+};
+
+/* An array of (default) function arguments.  */
+
+struct gcc_cp_function_args
+{
+  /* Number of elements.  */
+
+  int n_elements;
+
+  /* The (default) values for each argument.  */
+
+  gcc_expr *elements;
+};
+
+/* This enumerates the kinds of decls that GDB can create.  */
+
+enum gcc_cp_symbol_kind
+{
+  /* A function.  */
+
+  GCC_CP_SYMBOL_FUNCTION,
+
+  /* A variable.  */
+
+  GCC_CP_SYMBOL_VARIABLE,
+
+  /* A typedef, or an alias declaration (including template ones).  */
+
+  GCC_CP_SYMBOL_TYPEDEF,
+
+  /* A label.  */
+
+  GCC_CP_SYMBOL_LABEL,
+
+  /* A class, forward declared in build_decl (to be later defined in
+     start_class_definition), or, in a template parameter list scope,
+     a declaration of a template class, closing the parameter
+     list.  */
+
+  GCC_CP_SYMBOL_CLASS,
+
+  /* A union, forward declared in build_decl (to be later defined in
+     start_class_definition).  */
+
+  GCC_CP_SYMBOL_UNION,
+
+  /* An enumeration type being introduced with start_new_enum_type.  */
+
+  GCC_CP_SYMBOL_ENUM,
+
+  /* A nonstatic data member being introduced with new_field.  */
+
+  GCC_CP_SYMBOL_FIELD,
+
+  /* A base class in a gcc_vbase_array.  */
+
+  GCC_CP_SYMBOL_BASECLASS,
+
+  /* A using declaration in new_using_decl.  */
+
+  GCC_CP_SYMBOL_USING,
+
+  /* A (lambda) closure class type.  In many regards this is just like
+     a regular class, but it's not supposed to have base classes, some
+     of the member functions that are usually implicitly-defined are
+     deleted, and it should have an operator() member function that
+     holds the lambda body.  We can't instantiate objects of lambda
+     types from the snippet, but we can interact with them in such
+     ways as passing them to functions that take their types, and
+     calling their body.  */
+
+  GCC_CP_SYMBOL_LAMBDA_CLOSURE,
+
+  /* Marker to check that we haven't exceeded GCC_CP_SYMBOL_MASK.  */
+  GCC_CP_SYMBOL_END,
+
+  GCC_CP_SYMBOL_MASK = 15,
+
+  /* When defining a class member, at least one of the
+     GCC_CP_ACCESS_MASK bits must be set; when defining a namespace-
+     or union-scoped symbol, none of them must be set.  */
+
+  GCC_CP_ACCESS_PRIVATE,
+  GCC_CP_ACCESS_PUBLIC = GCC_CP_ACCESS_PRIVATE << 1,
+  GCC_CP_ACCESS_MASK = (GCC_CP_ACCESS_PUBLIC
+			       | GCC_CP_ACCESS_PRIVATE),
+  GCC_CP_ACCESS_PROTECTED = GCC_CP_ACCESS_MASK,
+  GCC_CP_ACCESS_NONE = 0,
+
+  GCC_CP_FLAG_BASE = GCC_CP_ACCESS_PRIVATE << 2,
+
+  /* Flags to be used along with GCC_CP_SYMBOL_FUNCTION:  */
+
+  /* This flag should be set for constructors, destructors and
+     operators.  */
+  GCC_CP_FLAG_SPECIAL_FUNCTION = GCC_CP_FLAG_BASE,
+
+  /* We intentionally cannot express inline, constexpr, or virtual
+     override for functions.  We can't inline or constexpr-replace
+     without a source-level body.  The override keyword is only
+     meaningful within the definition of the containing class.  */
+
+  /* This indicates a "virtual" member function, explicitly or
+     implicitly (due to a virtual function with the same name and
+     prototype in a base class) declared as such.  */
+  GCC_CP_FLAG_VIRTUAL_FUNCTION = GCC_CP_FLAG_BASE << 1,
+
+  /* The following two flags should only be set when the flag above is
+     set.  */
+
+  /* This indicates a pure virtual member function, i.e., one that is
+     declared with "= 0", even if a body is provided in the
+     definition.  */
+  GCC_CP_FLAG_PURE_VIRTUAL_FUNCTION = GCC_CP_FLAG_BASE << 2,
+
+  /* This indicates a "final" virtual member function.  */
+  GCC_CP_FLAG_FINAL_VIRTUAL_FUNCTION = GCC_CP_FLAG_BASE << 3,
+
+  /* This indicates a special member function should have its default
+     implementation.  This either means the function declaration
+     contains the "= default" tokens, or that the member function was
+     implicitly generated by the compiler, although the latter use is
+     discouraged: just let the compiler implicitly introduce it.
+
+     A member function defaulted after its first declaration has
+     slightly different ABI implications from one implicitly generated
+     or explicitly defaulted at the declaration (and definition)
+     point.  To avoid silent (possibly harmless) violation of the one
+     definition rule, it is recommended that this flag not be used for
+     such functions, and that the address of the definition be
+     supplied instead.  */
+  GCC_CP_FLAG_DEFAULTED_FUNCTION = GCC_CP_FLAG_BASE << 4,
+
+  /* This indicates a deleted member function, i.e., one that has been
+     defined as "= delete" at its declaration point, or one that has
+     been implicitly defined as deleted (with or without an explicit
+     "= default" definition).
+
+     This should not be used for implicitly-declared member functions
+     that resolve to deleted definitions, as it may affect the
+     implicit declaration of other member functions.  */
+  GCC_CP_FLAG_DELETED_FUNCTION = GCC_CP_FLAG_BASE << 5,
+
+  /* This indicates a constructor or type-conversion operator declared
+     as "explicit".  */
+
+  GCC_CP_FLAG_EXPLICIT_FUNCTION = GCC_CP_FLAG_BASE << 6,
+
+  GCC_CP_FLAG_END_FUNCTION,
+  GCC_CP_FLAG_MASK_FUNCTION = (((GCC_CP_FLAG_END_FUNCTION - 1) << 1)
+			       - GCC_CP_FLAG_BASE),
+
+  /* Flags to be used along with GCC_CP_SYMBOL_VARIABLE:  */
+
+  /* This indicates a variable declared as "constexpr".  */
+
+  GCC_CP_FLAG_CONSTEXPR_VARIABLE = GCC_CP_FLAG_BASE,
+
+  /* This indicates a variable declared as "thread_local".  ??? What
+     should the ADDRESS be?  */
+
+  GCC_CP_FLAG_THREAD_LOCAL_VARIABLE = GCC_CP_FLAG_BASE << 1,
+
+  GCC_CP_FLAG_END_VARIABLE,
+  GCC_CP_FLAG_MASK_VARIABLE = (((GCC_CP_FLAG_END_VARIABLE - 1) << 1)
+			       - GCC_CP_FLAG_BASE),
+
+  /* Flags to be used when defining nonstatic data members of classes
+     with new_field.  */
+
+  /* Use this when no flags are present.  */
+  GCC_CP_FLAG_FIELD_NOFLAG = 0,
+
+  /* This indicates the field is declared as mutable.  */
+  GCC_CP_FLAG_FIELD_MUTABLE = GCC_CP_FLAG_BASE,
+
+  GCC_CP_FLAG_END_FIELD,
+  GCC_CP_FLAG_MASK_FIELD = (((GCC_CP_FLAG_END_FIELD - 1) << 1)
+			    - GCC_CP_FLAG_BASE),
+
+  /* Flags to be used when defining an enum with
+     start_new_enum_type.  */
+
+  /* This indicates an enum type without any flags.  */
+  GCC_CP_FLAG_ENUM_NOFLAG = 0,
+
+  /* This indicates a scoped enum type.  */
+  GCC_CP_FLAG_ENUM_SCOPED = GCC_CP_FLAG_BASE,
+
+  GCC_CP_FLAG_END_ENUM,
+  GCC_CP_FLAG_MASK_ENUM = (((GCC_CP_FLAG_END_ENUM - 1) << 1)
+			       - GCC_CP_FLAG_BASE),
+
+
+  /* Flags to be used when introducing a class or a class template
+     with build_decl.  */
+
+  /* This indicates an enum type without any flags.  */
+  GCC_CP_FLAG_CLASS_NOFLAG = 0,
+
+  /* This indicates the class is actually a struct.  This has no
+     effect whatsoever on access control in this interface, since all
+     class members must have explicit access control bits set, but it
+     may affect error messages.  */
+  GCC_CP_FLAG_CLASS_IS_STRUCT = GCC_CP_FLAG_BASE,
+
+  GCC_CP_FLAG_END_CLASS,
+  GCC_CP_FLAG_MASK_CLASS = (((GCC_CP_FLAG_END_CLASS - 1) << 1)
+			       - GCC_CP_FLAG_BASE),
+
+
+  /* Flags to be used when introducing a virtual base class in a
+     gcc_vbase_array.  */
+
+  /* This indicates an enum type without any flags.  */
+  GCC_CP_FLAG_BASECLASS_NOFLAG = 0,
+
+  /* This indicates the class is actually a struct.  This has no
+     effect whatsoever on access control in this interface, since all
+     class members must have explicit access control bits set, but it
+     may affect error messages.  */
+  GCC_CP_FLAG_BASECLASS_VIRTUAL = GCC_CP_FLAG_BASE,
+
+  GCC_CP_FLAG_END_BASECLASS,
+  GCC_CP_FLAG_MASK_BASECLASS = (((GCC_CP_FLAG_END_BASECLASS - 1) << 1)
+				- GCC_CP_FLAG_BASE),
+
+
+  GCC_CP_FLAG_MASK = (GCC_CP_FLAG_MASK_FUNCTION
+		      | GCC_CP_FLAG_MASK_VARIABLE
+		      | GCC_CP_FLAG_MASK_FIELD
+		      | GCC_CP_FLAG_MASK_ENUM
+		      | GCC_CP_FLAG_MASK_CLASS
+		      | GCC_CP_FLAG_MASK_BASECLASS
+		      )
+};
+
+
+/* An array of types used for creating lists of base classes.  */
+
+struct gcc_vbase_array
+{
+  /* Number of elements.  */
+
+  int n_elements;
+
+  /* The base classes.  */
+
+  gcc_type *elements;
+
+  /* Flags for each base class.  Used to indicate access control and
+     virtualness.  */
+
+  enum gcc_cp_symbol_kind *flags;
+};
+
+
+/* This enumerates the types of symbols that GCC might request from
+   GDB.  */
+
+enum gcc_cp_oracle_request
+{
+  /* An identifier in namespace scope -- type, variable, function,
+     namespace, template.  All namespace-scoped symbols with the
+     requested name, in any namespace (including the global
+     namespace), should be defined in response to this request.  */
+
+  GCC_CP_ORACLE_IDENTIFIER
+};
+
+/* The type of the function called by GCC to ask GDB for a symbol's
+   definition.  DATUM is an arbitrary value supplied when the oracle
+   function is registered.  CONTEXT is the GCC context in which the
+   request is being made.  REQUEST specifies what sort of symbol is
+   being requested, and IDENTIFIER is the name of the symbol.  */
+
+typedef void gcc_cp_oracle_function (void *datum,
+				     struct gcc_cp_context *context,
+				     enum gcc_cp_oracle_request request,
+				     const char *identifier);
+
+/* The type of the function called by GCC to ask GDB for a symbol's
+   address.  This should return 0 if the address is not known.  */
+
+typedef gcc_address gcc_cp_symbol_address_function (void *datum,
+						    struct gcc_cp_context *ctxt,
+						    const char *identifier);
+
+/* The type of the function called by GCC to ask GDB to enter or leave
+   the user expression scope.  */
+
+typedef void gcc_cp_enter_leave_user_expr_scope_function (void *datum,
+							  struct gcc_cp_context
+							  *context);
+
+/* The vtable used by the C front end.  */
+
+struct gcc_cp_fe_vtable
+{
+  /* The version of the C interface.  The value is one of the
+     gcc_cp_api_version constants.  */
+
+  unsigned int cp_version;
+
+  /* Set the callbacks for this context.
+
+     The binding oracle is called whenever the C++ parser needs to
+     look up a symbol.  This gives the caller a chance to lazily
+     instantiate symbols using other parts of the gcc_cp_fe_interface
+     API.  The symbol is looked up without a scope, and the oracle
+     must supply a definition for ALL namespace-scoped definitions
+     bound to the symbol.
+
+     The address oracle is called whenever the C++ parser needs to
+     look up a symbol.  This may be called for symbols not provided by
+     the symbol oracle, such as built-in functions where GCC provides
+     the declaration; other internal symbols, such as those related
+     with thunks, rtti, and virtual tables are likely to be queried
+     through this interface too.  The identifier is a mangled symbol
+     name.
+
+     DATUM is an arbitrary piece of data that is passed back verbatim
+     to the callbacks in requests.  */
+
+  void (*set_callbacks) (struct gcc_cp_context *self,
+			 gcc_cp_oracle_function *binding_oracle,
+			 gcc_cp_symbol_address_function *address_oracle,
+			 gcc_cp_enter_leave_user_expr_scope_function *enter_scope,
+			 gcc_cp_enter_leave_user_expr_scope_function *leave_scope,
+			 void *datum);
+
+#define GCC_METHOD0(R, N) \
+  R (*N) (struct gcc_cp_context *);
+#define GCC_METHOD1(R, N, A) \
+  R (*N) (struct gcc_cp_context *, A);
+#define GCC_METHOD2(R, N, A, B) \
+  R (*N) (struct gcc_cp_context *, A, B);
+#define GCC_METHOD3(R, N, A, B, C) \
+  R (*N) (struct gcc_cp_context *, A, B, C);
+#define GCC_METHOD4(R, N, A, B, C, D) \
+  R (*N) (struct gcc_cp_context *, A, B, C, D);
+#define GCC_METHOD5(R, N, A, B, C, D, E) \
+  R (*N) (struct gcc_cp_context *, A, B, C, D, E);
+#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \
+  R (*N) (struct gcc_cp_context *, A, B, C, D, E, F, G);
+
+#include "gcc-cp-fe.def"
+
+#undef GCC_METHOD0
+#undef GCC_METHOD1
+#undef GCC_METHOD2
+#undef GCC_METHOD3
+#undef GCC_METHOD4
+#undef GCC_METHOD5
+#undef GCC_METHOD7
+
+};
+
+/* The C front end object.  */
+
+struct gcc_cp_context
+{
+  /* Base class.  */
+
+  struct gcc_base_context base;
+
+  /* Our vtable.  This is a separate field because this is simpler
+     than implementing a vtable inheritance scheme in C.  */
+
+  const struct gcc_cp_fe_vtable *cp_ops;
+};
+
+/* The name of the .so that the compiler builds.  We dlopen this
+   later.  */
+
+#define GCC_CP_FE_LIBCC libcc1.so
+
+/* The compiler exports a single initialization function.  This macro
+   holds its name as a symbol.  */
+
+#define GCC_CP_FE_CONTEXT gcc_cp_fe_context
+
+/* The type of the initialization function.  The caller passes in the
+   desired base version and desired C-specific version.  If the
+   request can be satisfied, a compatible gcc_context object will be
+   returned.  Otherwise, the function returns NULL.  */
+
+typedef struct gcc_cp_context *gcc_cp_fe_context_function
+    (enum gcc_base_api_version,
+     enum gcc_cp_api_version);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GCC_CP_INTERFACE_H */
diff --git a/include/gcc-interface.h b/include/gcc-interface.h
index e3ffd18..1dc3498 100644
--- a/include/gcc-interface.h
+++ b/include/gcc-interface.h
@@ -169,6 +169,20 @@  struct gcc_base_context
   const struct gcc_base_vtable *ops;
 };
 
+/* An array of types used for creating function types in multiple
+   languages.  */
+
+struct gcc_type_array
+{
+  /* Number of elements.  */
+
+  int n_elements;
+
+  /* The elements.  */
+
+  gcc_type *elements;
+};
+
 /* The name of the dummy wrapper function generated by gdb.  */
 
 #define GCC_FE_WRAPPER_FUNCTION "_gdb_expr"
diff --git a/libcc1/Makefile.am b/libcc1/Makefile.am
index 02f0675..5e61a92 100644
--- a/libcc1/Makefile.am
+++ b/libcc1/Makefile.am
@@ -19,9 +19,11 @@ 
 ACLOCAL_AMFLAGS = -I .. -I ../config
 gcc_build_dir = ../gcc
 AM_CPPFLAGS = -I $(srcdir)/../include -I $(srcdir)/../libgcc \
-	-I $(gcc_build_dir) -I$(srcdir)/../gcc \
-	-I $(srcdir)/../gcc/c -I $(srcdir)/../gcc/c-family \
-	-I $(srcdir)/../libcpp/include $(GMPINC)
+	-I $(gcc_build_dir) -I$(srcdir)/../gcc $($@_CPPFLAGS) $(GMPINC)
+CPPFLAGS_FOR_C_FAMILY = -I $(srcdir)/../gcc/c-family \
+	-I $(srcdir)/../libcpp/include
+CPPFLAGS_FOR_C = $(CPPFLAGS_FOR_C_FAMILY) -I $(srcdir)/../gcc/c
+CPPFLAGS_FOR_CXX = $(CPPFLAGS_FOR_C_FAMILY) -I $(srcdir)/../gcc/cp
 AM_CXXFLAGS = $(WARN_FLAGS) $(WERROR) $(visibility)
 override CXXFLAGS := $(filter-out -fsanitize=address,$(CXXFLAGS))
 override LDFLAGS := $(filter-out -fsanitize=address,$(LDFLAGS))
@@ -39,33 +41,57 @@  plugindir = $(libdir)/gcc/$(target_noncanonical)/$(gcc_version)/plugin
 cc1libdir = $(libdir)/$(libsuffix)
 
 if ENABLE_PLUGIN
-plugin_LTLIBRARIES = libcc1plugin.la
+plugin_LTLIBRARIES = libcc1plugin.la libcp1plugin.la
 cc1lib_LTLIBRARIES = libcc1.la
 endif
 
-BUILT_SOURCES = compiler-name.h
-MOSTLYCLEANFILES = compiler-name.h
+BUILT_SOURCES = c-compiler-name.h cp-compiler-name.h
+MOSTLYCLEANFILES = c-compiler-name.h cp-compiler-name.h
 
 # Put this in a header so we don't run sed for each compilation.  This
 # is also simpler to debug as one can easily see the constant.
-compiler-name.h: Makefile
-	echo "#define COMPILER_NAME \"`echo gcc | sed '$(transform)'`\"" > $@
+# FIXME: compute it in configure.ac and output it in config.status, or
+# introduce timestamp files for some indirection to avoid rebuilding it
+# every time.
+c-compiler-name.h: Makefile
+	-rm -f $@T
+	echo "#define C_COMPILER_NAME \"`echo gcc | sed '$(transform)'`\"" > $@T
+	mv $@T $@ # $(SHELL) $(srcdir)/../move-if-change $@T $@
 
+cp-compiler-name.h: Makefile
+	-rm -f $@T
+	echo "#define CP_COMPILER_NAME \"`echo g++ | sed '$(transform)'`\"" > $@T
+	mv $@T $@ # $(SHELL) $(srcdir)/../move-if-change $@T $@
 
 shared_source = callbacks.cc callbacks.hh connection.cc connection.hh \
     marshall.cc marshall.hh rpc.hh status.hh
 
+marshall_c_source = marshall-c.hh
+marshall_cxx_source = marshall-cp.hh
+
 libcc1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1plugin.sym
-libcc1plugin_la_SOURCES = plugin.cc $(shared_source)
+libcc1plugin_la_SOURCES = libcc1plugin.cc $(shared_source) $(marshall_c_source)
+libcc1plugin.lo_CPPFLAGS = $(CPPFLAGS_FOR_C)
 libcc1plugin_la_LIBADD = $(libiberty)
 libcc1plugin_la_DEPENDENCIES = $(libiberty_dep)
 libcc1plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
 	$(CXXFLAGS) $(libcc1plugin_la_LDFLAGS) $(LTLDFLAGS) -o $@
 
+libcp1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcp1plugin.sym
+libcp1plugin_la_SOURCES = libcp1plugin.cc $(shared_source) $(marshall_cxx_source)
+libcp1plugin.lo_CPPFLAGS = $(CPPFLAGS_FOR_CXX)
+libcp1plugin_la_LIBADD = $(libiberty)
+libcp1plugin_la_DEPENDENCIES = $(libiberty_dep)
+libcp1plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+	$(CXXFLAGS) $(libcp1plugin_la_LDFLAGS) $(LTLDFLAGS) -o $@
+
 LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
 libcc1_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1.sym
-libcc1_la_SOURCES = findcomp.cc libcc1.cc names.cc names.hh $(shared_source)
+libcc1_la_SOURCES = findcomp.cc libcc1.cc libcp1.cc \
+		names.cc names.hh $(shared_source) \
+		$(marshall_c_source) $(marshall_cxx_source)
 libcc1_la_LIBADD = $(libiberty)
 libcc1_la_DEPENDENCIES = $(libiberty_dep)
 libcc1_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
diff --git a/libcc1/Makefile.in b/libcc1/Makefile.in
index 21fb153..54babb0 100644
--- a/libcc1/Makefile.in
+++ b/libcc1/Makefile.in
@@ -105,12 +105,19 @@  am__uninstall_files_from_dir = { \
 am__installdirs = "$(DESTDIR)$(cc1libdir)" "$(DESTDIR)$(plugindir)"
 LTLIBRARIES = $(cc1lib_LTLIBRARIES) $(plugin_LTLIBRARIES)
 am__objects_1 = callbacks.lo connection.lo marshall.lo
-am_libcc1_la_OBJECTS = findcomp.lo libcc1.lo names.lo $(am__objects_1)
+am__objects_2 =
+am_libcc1_la_OBJECTS = findcomp.lo libcc1.lo libcp1.lo names.lo \
+	$(am__objects_1) $(am__objects_2) $(am__objects_2)
 libcc1_la_OBJECTS = $(am_libcc1_la_OBJECTS)
 @ENABLE_PLUGIN_TRUE@am_libcc1_la_rpath = -rpath $(cc1libdir)
-am_libcc1plugin_la_OBJECTS = plugin.lo $(am__objects_1)
+am_libcc1plugin_la_OBJECTS = libcc1plugin.lo $(am__objects_1) \
+	$(am__objects_2)
 libcc1plugin_la_OBJECTS = $(am_libcc1plugin_la_OBJECTS)
 @ENABLE_PLUGIN_TRUE@am_libcc1plugin_la_rpath = -rpath $(plugindir)
+am_libcp1plugin_la_OBJECTS = libcp1plugin.lo $(am__objects_1) \
+	$(am__objects_2)
+libcp1plugin_la_OBJECTS = $(am_libcp1plugin_la_OBJECTS)
+@ENABLE_PLUGIN_TRUE@am_libcp1plugin_la_rpath = -rpath $(plugindir)
 DEFAULT_INCLUDES = -I.@am__isrc@
 depcomp = $(SHELL) $(top_srcdir)/../depcomp
 am__depfiles_maybe = depfiles
@@ -133,7 +140,8 @@  CCLD = $(CC)
 LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
 	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
 	$(LDFLAGS) -o $@
-SOURCES = $(libcc1_la_SOURCES) $(libcc1plugin_la_SOURCES)
+SOURCES = $(libcc1_la_SOURCES) $(libcc1plugin_la_SOURCES) \
+	$(libcp1plugin_la_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -277,10 +285,13 @@  visibility = @visibility@
 ACLOCAL_AMFLAGS = -I .. -I ../config
 gcc_build_dir = ../gcc
 AM_CPPFLAGS = -I $(srcdir)/../include -I $(srcdir)/../libgcc \
-	-I $(gcc_build_dir) -I$(srcdir)/../gcc \
-	-I $(srcdir)/../gcc/c -I $(srcdir)/../gcc/c-family \
-	-I $(srcdir)/../libcpp/include $(GMPINC)
+	-I $(gcc_build_dir) -I$(srcdir)/../gcc $($@_CPPFLAGS) $(GMPINC)
 
+CPPFLAGS_FOR_C_FAMILY = -I $(srcdir)/../gcc/c-family \
+	-I $(srcdir)/../libcpp/include
+
+CPPFLAGS_FOR_C = $(CPPFLAGS_FOR_C_FAMILY) -I $(srcdir)/../gcc/c
+CPPFLAGS_FOR_CXX = $(CPPFLAGS_FOR_C_FAMILY) -I $(srcdir)/../gcc/cp
 AM_CXXFLAGS = $(WARN_FLAGS) $(WERROR) $(visibility)
 # Can be simplified when libiberty becomes a normal convenience library.
 libiberty_normal = ../libiberty/libiberty.a
@@ -294,24 +305,39 @@  libiberty = $(if $(wildcard $(libiberty_noasan)),$(Wc)$(libiberty_noasan), \
 libiberty_dep = $(patsubst $(Wc)%,%,$(libiberty))
 plugindir = $(libdir)/gcc/$(target_noncanonical)/$(gcc_version)/plugin
 cc1libdir = $(libdir)/$(libsuffix)
-@ENABLE_PLUGIN_TRUE@plugin_LTLIBRARIES = libcc1plugin.la
+@ENABLE_PLUGIN_TRUE@plugin_LTLIBRARIES = libcc1plugin.la libcp1plugin.la
 @ENABLE_PLUGIN_TRUE@cc1lib_LTLIBRARIES = libcc1.la
-BUILT_SOURCES = compiler-name.h
-MOSTLYCLEANFILES = compiler-name.h
+BUILT_SOURCES = c-compiler-name.h cp-compiler-name.h
+MOSTLYCLEANFILES = c-compiler-name.h cp-compiler-name.h
 shared_source = callbacks.cc callbacks.hh connection.cc connection.hh \
     marshall.cc marshall.hh rpc.hh status.hh
 
+marshall_c_source = marshall-c.hh
+marshall_cxx_source = marshall-cp.hh
 libcc1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1plugin.sym
-libcc1plugin_la_SOURCES = plugin.cc $(shared_source)
+libcc1plugin_la_SOURCES = libcc1plugin.cc $(shared_source) $(marshall_c_source)
+libcc1plugin.lo_CPPFLAGS = $(CPPFLAGS_FOR_C)
 libcc1plugin_la_LIBADD = $(libiberty)
 libcc1plugin_la_DEPENDENCIES = $(libiberty_dep)
 libcc1plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
 	$(CXXFLAGS) $(libcc1plugin_la_LDFLAGS) $(LTLDFLAGS) -o $@
 
+libcp1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcp1plugin.sym
+libcp1plugin_la_SOURCES = libcp1plugin.cc $(shared_source) $(marshall_cxx_source)
+libcp1plugin.lo_CPPFLAGS = $(CPPFLAGS_FOR_CXX)
+libcp1plugin_la_LIBADD = $(libiberty)
+libcp1plugin_la_DEPENDENCIES = $(libiberty_dep)
+libcp1plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+	$(CXXFLAGS) $(libcp1plugin_la_LDFLAGS) $(LTLDFLAGS) -o $@
+
 LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
 libcc1_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1.sym
-libcc1_la_SOURCES = findcomp.cc libcc1.cc names.cc names.hh $(shared_source)
+libcc1_la_SOURCES = findcomp.cc libcc1.cc libcp1.cc \
+		names.cc names.hh $(shared_source) \
+		$(marshall_c_source) $(marshall_cxx_source)
+
 libcc1_la_LIBADD = $(libiberty)
 libcc1_la_DEPENDENCIES = $(libiberty_dep)
 libcc1_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
@@ -440,6 +466,8 @@  libcc1.la: $(libcc1_la_OBJECTS) $(libcc1_la_DEPENDENCIES) $(EXTRA_libcc1_la_DEPE
 	$(libcc1_la_LINK) $(am_libcc1_la_rpath) $(libcc1_la_OBJECTS) $(libcc1_la_LIBADD) $(LIBS)
 libcc1plugin.la: $(libcc1plugin_la_OBJECTS) $(libcc1plugin_la_DEPENDENCIES) $(EXTRA_libcc1plugin_la_DEPENDENCIES) 
 	$(libcc1plugin_la_LINK) $(am_libcc1plugin_la_rpath) $(libcc1plugin_la_OBJECTS) $(libcc1plugin_la_LIBADD) $(LIBS)
+libcp1plugin.la: $(libcp1plugin_la_OBJECTS) $(libcp1plugin_la_DEPENDENCIES) $(EXTRA_libcp1plugin_la_DEPENDENCIES) 
+	$(libcp1plugin_la_LINK) $(am_libcp1plugin_la_rpath) $(libcp1plugin_la_OBJECTS) $(libcp1plugin_la_LIBADD) $(LIBS)
 
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
@@ -451,9 +479,11 @@  distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connection.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/findcomp.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcc1.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcc1plugin.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcp1.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcp1plugin.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/marshall.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/names.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin.Plo@am__quote@
 
 .cc.o:
 @am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -674,8 +704,18 @@  override LDFLAGS := $(filter-out -fsanitize=address,$(LDFLAGS))
 
 # Put this in a header so we don't run sed for each compilation.  This
 # is also simpler to debug as one can easily see the constant.
-compiler-name.h: Makefile
-	echo "#define COMPILER_NAME \"`echo gcc | sed '$(transform)'`\"" > $@
+# FIXME: compute it in configure.ac and output it in config.status, or
+# introduce timestamp files for some indirection to avoid rebuilding it
+# every time.
+c-compiler-name.h: Makefile
+	-rm -f $@T
+	echo "#define C_COMPILER_NAME \"`echo gcc | sed '$(transform)'`\"" > $@T
+	mv $@T $@ # $(SHELL) $(srcdir)/../move-if-change $@T $@
+
+cp-compiler-name.h: Makefile
+	-rm -f $@T
+	echo "#define CP_COMPILER_NAME \"`echo g++ | sed '$(transform)'`\"" > $@T
+	mv $@T $@ # $(SHELL) $(srcdir)/../move-if-change $@T $@
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/libcc1/libcc1.cc b/libcc1/libcc1.cc
index 572bc2a..0ef6c11 100644
--- a/libcc1/libcc1.cc
+++ b/libcc1/libcc1.cc
@@ -29,15 +29,15 @@  along with GCC; see the file COPYING3.  If not see
 #include <sys/stat.h>
 #include <stdlib.h>
 #include <sstream>
+#include "marshall-c.hh"
 #include "rpc.hh"
 #include "connection.hh"
 #include "names.hh"
 #include "callbacks.hh"
-#include "gcc-interface.h"
 #include "libiberty.h"
 #include "xregex.h"
 #include "findcomp.hh"
-#include "compiler-name.h"
+#include "c-compiler-name.h"
 #include "intl.h"
 
 struct libcc1;
@@ -164,30 +164,35 @@  libcc1::~libcc1 ()
 
 
 
-// This is a wrapper function that is called by the RPC system and
-// that then forwards the call to the library user.  Note that the
-// return value is not used; the type cannot be 'void' due to
-// limitations in our simple RPC.
-int
-call_binding_oracle (cc1_plugin::connection *conn,
-		     enum gcc_c_oracle_request request,
-		     const char *identifier)
-{
-  libcc1 *self = ((libcc1_connection *) conn)->back_ptr;
+// Enclose these functions in an anonymous namespace because they
+// shouldn't be exported, but they can't be static because they're
+// used as template arguments.
+namespace {
+  // This is a wrapper function that is called by the RPC system and
+  // that then forwards the call to the library user.  Note that the
+  // return value is not used; the type cannot be 'void' due to
+  // limitations in our simple RPC.
+  int
+  c_call_binding_oracle (cc1_plugin::connection *conn,
+			 enum gcc_c_oracle_request request,
+			 const char *identifier)
+  {
+    libcc1 *self = ((libcc1_connection *) conn)->back_ptr;
 
-  self->binding_oracle (self->oracle_datum, self, request, identifier);
-  return 1;
-}
+    self->binding_oracle (self->oracle_datum, self, request, identifier);
+    return 1;
+  }
 
-// This is a wrapper function that is called by the RPC system and
-// that then forwards the call to the library user.
-gcc_address
-call_symbol_address (cc1_plugin::connection *conn, const char *identifier)
-{
-  libcc1 *self = ((libcc1_connection *) conn)->back_ptr;
+  // This is a wrapper function that is called by the RPC system and
+  // that then forwards the call to the library user.
+  gcc_address
+  c_call_symbol_address (cc1_plugin::connection *conn, const char *identifier)
+  {
+    libcc1 *self = ((libcc1_connection *) conn)->back_ptr;
 
-  return self->address_oracle (self->oracle_datum, self, identifier);
-}
+    return self->address_oracle (self->oracle_datum, self, identifier);
+  }
+} /* anonymous namespace */
 
 
 
@@ -298,19 +303,19 @@  static const struct gcc_c_fe_vtable c_vtable =
   set_callbacks,
 
 #define GCC_METHOD0(R, N) \
-  rpc<R, cc1_plugin::N>,
+  rpc<R, cc1_plugin::c::N>,
 #define GCC_METHOD1(R, N, A) \
-  rpc<R, cc1_plugin::N, A>,
+  rpc<R, cc1_plugin::c::N, A>,
 #define GCC_METHOD2(R, N, A, B) \
-  rpc<R, cc1_plugin::N, A, B>,
+  rpc<R, cc1_plugin::c::N, A, B>,
 #define GCC_METHOD3(R, N, A, B, C) \
-  rpc<R, cc1_plugin::N, A, B, C>,
+  rpc<R, cc1_plugin::c::N, A, B, C>,
 #define GCC_METHOD4(R, N, A, B, C, D) \
-  rpc<R, cc1_plugin::N, A, B, C, D>,
+  rpc<R, cc1_plugin::c::N, A, B, C, D>,
 #define GCC_METHOD5(R, N, A, B, C, D, E) \
-  rpc<R, cc1_plugin::N, A, B, C, D, E>,
+  rpc<R, cc1_plugin::c::N, A, B, C, D, E>,
 #define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \
-  rpc<R, cc1_plugin::N, A, B, C, D, E, F, G>,
+  rpc<R, cc1_plugin::c::N, A, B, C, D, E, F, G>,
 
 #include "gcc-c-fe.def"
 
@@ -377,13 +382,12 @@  libcc1::compiler::find (std::string &compiler ATTRIBUTE_UNUSED) const
 char *
 libcc1::compiler_triplet_regexp::find (std::string &compiler) const
 {
-  std::string rx = make_regexp (triplet_regexp_.c_str (), COMPILER_NAME);
+  std::string rx = make_regexp (triplet_regexp_.c_str (), C_COMPILER_NAME);
   if (self_->verbose)
     fprintf (stderr, _("searching for compiler matching regex %s\n"),
 	     rx.c_str());
   regex_t triplet;
-  int code;
-  code = regcomp (&triplet, rx.c_str (), REG_EXTENDED | REG_NOSUB);
+  int code = regcomp (&triplet, rx.c_str (), REG_EXTENDED | REG_NOSUB);
   if (code != 0)
     {
       size_t len = regerror (code, &triplet, NULL, 0);
@@ -532,7 +536,7 @@  fork_exec (libcc1 *self, char **argv, int spair_fds[2], int stderr_fds[2])
 
       cc1_plugin::status result = cc1_plugin::FAIL;
       if (self->connection->send ('H')
-	  && ::cc1_plugin::marshall (self->connection, GCC_C_FE_VERSION_0))
+	  && ::cc1_plugin::marshall (self->connection, GCC_C_FE_VERSION_1))
 	result = self->connection->wait_for_query ();
 
       close (spair_fds[0]);
@@ -601,12 +605,12 @@  libcc1_compile (struct gcc_base_context *s,
     = cc1_plugin::callback<int,
 			   enum gcc_c_oracle_request,
 			   const char *,
-			   call_binding_oracle>;
+			   c_call_binding_oracle>;
   self->connection->add_callback ("binding_oracle", fun);
 
   fun = cc1_plugin::callback<gcc_address,
 			     const char *,
-			     call_symbol_address>;
+			     c_call_symbol_address>;
   self->connection->add_callback ("address_oracle", fun);
 
   char **argv = new (std::nothrow) char *[self->args.size () + 1];
@@ -663,7 +667,7 @@  gcc_c_fe_context (enum gcc_base_api_version base_version,
 		  enum gcc_c_api_version c_version)
 {
   if ((base_version != GCC_FE_VERSION_0 && base_version != GCC_FE_VERSION_1)
-      || c_version != GCC_C_FE_VERSION_0)
+      || (c_version != GCC_C_FE_VERSION_0 && c_version != GCC_C_FE_VERSION_1))
     return NULL;
 
   return new libcc1 (&vtable, &c_vtable);
diff --git a/libcc1/libcc1.sym b/libcc1/libcc1.sym
index 86b1e3e..9d46f26 100644
--- a/libcc1/libcc1.sym
+++ b/libcc1/libcc1.sym
@@ -1 +1,2 @@ 
 gcc_c_fe_context
+gcc_cp_fe_context
diff --git a/libcc1/libcc1plugin.cc b/libcc1/libcc1plugin.cc
new file mode 100644
index 0000000..bd05c8d
--- /dev/null
+++ b/libcc1/libcc1plugin.cc
@@ -0,0 +1,1020 @@ 
+/* Library interface to C front end
+   Copyright (C) 2014-2017 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC 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, or (at your option) any later
+   version.
+
+   GCC 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 GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <cc1plugin-config.h>
+
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+
+#include "../gcc/config.h"
+
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "stringpool.h"
+
+#include "gcc-interface.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "vec.h"
+#include "double-int.h"
+#include "input.h"
+#include "alias.h"
+#include "symtab.h"
+#include "options.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "tree.h"
+#include "fold-const.h"
+#include "stor-layout.h"
+#include "c-tree.h"
+#include "toplev.h"
+#include "timevar.h"
+#include "hash-table.h"
+#include "tm.h"
+#include "c-family/c-pragma.h"
+#include "c-lang.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+
+#include "callbacks.hh"
+#include "connection.hh"
+#include "marshall-c.hh"
+#include "rpc.hh"
+
+#ifdef __GNUC__
+#pragma GCC visibility push(default)
+#endif
+int plugin_is_GPL_compatible;
+#ifdef __GNUC__
+#pragma GCC visibility pop
+#endif
+
+
+
+// This is put into the lang hooks when the plugin starts.
+
+static void
+plugin_print_error_function (diagnostic_context *context, const char *file,
+			     diagnostic_info *diagnostic)
+{
+  if (current_function_decl != NULL_TREE
+      && DECL_NAME (current_function_decl) != NULL_TREE
+      && strcmp (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),
+		 GCC_FE_WRAPPER_FUNCTION) == 0)
+    return;
+  lhd_print_error_function (context, file, diagnostic);
+}
+
+
+
+static unsigned long long
+convert_out (tree t)
+{
+  return (unsigned long long) (uintptr_t) t;
+}
+
+static tree
+convert_in (unsigned long long v)
+{
+  return (tree) (uintptr_t) v;
+}
+
+
+
+struct decl_addr_value
+{
+  tree decl;
+  tree address;
+};
+
+struct decl_addr_hasher : free_ptr_hash<decl_addr_value>
+{
+  static inline hashval_t hash (const decl_addr_value *);
+  static inline bool equal (const decl_addr_value *, const decl_addr_value *);
+};
+
+inline hashval_t
+decl_addr_hasher::hash (const decl_addr_value *e)
+{
+  return IDENTIFIER_HASH_VALUE (DECL_NAME (e->decl));
+}
+
+inline bool
+decl_addr_hasher::equal (const decl_addr_value *p1, const decl_addr_value *p2)
+{
+  return p1->decl == p2->decl;
+}
+
+
+
+struct string_hasher : nofree_ptr_hash<const char>
+{
+  static inline hashval_t hash (const char *s)
+  {
+    return htab_hash_string (s);
+  }
+
+  static inline bool equal (const char *p1, const char *p2)
+  {
+    return strcmp (p1, p2) == 0;
+  }
+};
+
+
+
+// A wrapper for pushdecl that doesn't let gdb have a chance to
+// instantiate a symbol.
+
+static void
+pushdecl_safe (tree decl)
+{
+  void (*save) (enum c_oracle_request, tree identifier);
+
+  save = c_binding_oracle;
+  c_binding_oracle = NULL;
+  pushdecl (decl);
+  c_binding_oracle = save;
+}
+
+
+
+struct plugin_context : public cc1_plugin::connection
+{
+  plugin_context (int fd);
+
+  // Map decls to addresses.
+  hash_table<decl_addr_hasher> address_map;
+
+  // A collection of trees that are preserved for the GC.
+  hash_table< nofree_ptr_hash<tree_node> > preserved;
+
+  // File name cache.
+  hash_table<string_hasher> file_names;
+
+  // Perform GC marking.
+  void mark ();
+
+  // Preserve a tree during the plugin's operation.
+  tree preserve (tree t)
+  {
+    tree_node **slot = preserved.find_slot (t, INSERT);
+    *slot = t;
+    return t;
+  }
+
+  source_location get_source_location (const char *filename,
+				       unsigned int line_number)
+  {
+    if (filename == NULL)
+      return UNKNOWN_LOCATION;
+
+    filename = intern_filename (filename);
+    linemap_add (line_table, LC_ENTER, false, filename, line_number);
+    source_location loc = linemap_line_start (line_table, line_number, 0);
+    linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+    return loc;
+  }
+
+private:
+
+  // Add a file name to FILE_NAMES and return the canonical copy.
+  const char *intern_filename (const char *filename)
+  {
+    const char **slot = file_names.find_slot (filename, INSERT);
+    if (*slot == NULL)
+      {
+	/* The file name must live as long as the line map, which
+	   effectively means as long as this compilation.  So, we copy
+	   the string here but never free it.  */
+	*slot = xstrdup (filename);
+      }
+    return *slot;
+  }
+};
+
+static plugin_context *current_context;
+
+
+
+plugin_context::plugin_context (int fd)
+  : cc1_plugin::connection (fd),
+    address_map (30),
+    preserved (30),
+    file_names (30)
+{
+}
+
+void
+plugin_context::mark ()
+{
+  for (hash_table<decl_addr_hasher>::iterator it = address_map.begin ();
+       it != address_map.end ();
+       ++it)
+    {
+      ggc_mark ((*it)->decl);
+      ggc_mark ((*it)->address);
+    }
+
+  for (hash_table< nofree_ptr_hash<tree_node> >::iterator
+	 it = preserved.begin (); it != preserved.end (); ++it)
+    ggc_mark (&*it);
+}
+
+static void
+plugin_binding_oracle (enum c_oracle_request kind, tree identifier)
+{
+  enum gcc_c_oracle_request request;
+
+  gcc_assert (current_context != NULL);
+
+  switch (kind)
+    {
+    case C_ORACLE_SYMBOL:
+      request = GCC_C_ORACLE_SYMBOL;
+      break;
+    case C_ORACLE_TAG:
+      request = GCC_C_ORACLE_TAG;
+      break;
+    case C_ORACLE_LABEL:
+      request = GCC_C_ORACLE_LABEL;
+      break;
+    default:
+      abort ();
+    }
+
+  int ignore;
+  cc1_plugin::call (current_context, "binding_oracle", &ignore,
+		    request, IDENTIFIER_POINTER (identifier));
+}
+
+static void
+plugin_pragma_user_expression (cpp_reader *)
+{
+  c_binding_oracle = plugin_binding_oracle;
+}
+
+static void
+plugin_init_extra_pragmas (void *, void *)
+{
+  c_register_pragma ("GCC", "user_expression", plugin_pragma_user_expression);
+}
+
+
+
+// Maybe rewrite a decl to its address.
+static tree
+address_rewriter (tree *in, int *walk_subtrees, void *arg)
+{
+  plugin_context *ctx = (plugin_context *) arg;
+
+  if (!DECL_P (*in) || DECL_NAME (*in) == NULL_TREE)
+    return NULL_TREE;
+
+  decl_addr_value value;
+  value.decl = *in;
+  decl_addr_value *found_value = ctx->address_map.find (&value);
+  if (found_value != NULL)
+    ;
+  else if (DECL_IS_BUILTIN (*in))
+    {
+      gcc_address address;
+
+      if (!cc1_plugin::call (ctx, "address_oracle", &address,
+			     IDENTIFIER_POINTER (DECL_NAME (*in))))
+	return NULL_TREE;
+      if (address == 0)
+	return NULL_TREE;
+
+      // Insert the decl into the address map in case it is referenced
+      // again.
+      value.address = build_int_cst_type (ptr_type_node, address);
+      decl_addr_value **slot = ctx->address_map.find_slot (&value, INSERT);
+      gcc_assert (*slot == NULL);
+      *slot
+	= static_cast<decl_addr_value *> (xmalloc (sizeof (decl_addr_value)));
+      **slot = value;
+      found_value = *slot;
+    }
+  else
+    return NULL_TREE;
+
+  if (found_value->address != error_mark_node)
+    {
+      // We have an address for the decl, so rewrite the tree.
+      tree ptr_type = build_pointer_type (TREE_TYPE (*in));
+      *in = fold_build1 (INDIRECT_REF, TREE_TYPE (*in),
+			 fold_build1 (CONVERT_EXPR, ptr_type,
+				      found_value->address));
+    }
+
+  *walk_subtrees = 0;
+
+  return NULL_TREE;
+}
+
+// When generating code for gdb, we want to be able to use absolute
+// addresses to refer to otherwise external objects that gdb knows
+// about.  gdb passes in these addresses when building decls, and then
+// before gimplification we go through the trees, rewriting uses to
+// the equivalent of "*(TYPE *) ADDR".
+static void
+rewrite_decls_to_addresses (void *function_in, void *)
+{
+  tree function = (tree) function_in;
+
+  // Do nothing if we're not in gdb.
+  if (current_context == NULL)
+    return;
+
+  walk_tree (&DECL_SAVED_TREE (function), address_rewriter, current_context,
+	     NULL);
+}
+
+
+
+gcc_decl
+plugin_build_decl (cc1_plugin::connection *self,
+		   const char *name,
+		   enum gcc_c_symbol_kind sym_kind,
+		   gcc_type sym_type_in,
+		   const char *substitution_name,
+		   gcc_address address,
+		   const char *filename,
+		   unsigned int line_number)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree identifier = get_identifier (name);
+  enum tree_code code;
+  tree decl;
+  tree sym_type = convert_in (sym_type_in);
+
+  switch (sym_kind)
+    {
+    case GCC_C_SYMBOL_FUNCTION:
+      code = FUNCTION_DECL;
+      break;
+
+    case GCC_C_SYMBOL_VARIABLE:
+      code = VAR_DECL;
+      break;
+
+    case GCC_C_SYMBOL_TYPEDEF:
+      code = TYPE_DECL;
+      break;
+
+    case GCC_C_SYMBOL_LABEL:
+      // FIXME: we aren't ready to handle labels yet.
+      // It isn't clear how to translate them properly
+      // and in any case a "goto" isn't likely to work.
+      return convert_out (error_mark_node);
+
+    default:
+      abort ();
+    }
+
+  source_location loc = ctx->get_source_location (filename, line_number);
+
+  decl = build_decl (loc, code, identifier, sym_type);
+  TREE_USED (decl) = 1;
+  TREE_ADDRESSABLE (decl) = 1;
+
+  if (sym_kind != GCC_C_SYMBOL_TYPEDEF)
+    {
+      decl_addr_value value;
+
+      DECL_EXTERNAL (decl) = 1;
+      value.decl = decl;
+      if (substitution_name != NULL)
+	{
+	  // If the translator gave us a name without a binding,
+	  // we can just substitute error_mark_node, since we know the
+	  // translator will be reporting an error anyhow.
+	  value.address
+	    = lookup_name (get_identifier (substitution_name));
+	  if (value.address == NULL_TREE)
+	    value.address = error_mark_node;
+	}
+      else
+	value.address = build_int_cst_type (ptr_type_node, address);
+      decl_addr_value **slot = ctx->address_map.find_slot (&value, INSERT);
+      gcc_assert (*slot == NULL);
+      *slot
+	= static_cast<decl_addr_value *> (xmalloc (sizeof (decl_addr_value)));
+      **slot = value;
+    }
+
+  return convert_out (ctx->preserve (decl));
+}
+
+int
+plugin_bind (cc1_plugin::connection *,
+	     gcc_decl decl_in, int is_global)
+{
+  tree decl = convert_in (decl_in);
+  c_bind (DECL_SOURCE_LOCATION (decl), decl, is_global);
+  rest_of_decl_compilation (decl, is_global, 0);
+  return 1;
+}
+
+int
+plugin_tagbind (cc1_plugin::connection *self,
+		const char *name, gcc_type tagged_type,
+		const char *filename, unsigned int line_number)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree t = convert_in (tagged_type), x;
+  c_pushtag (ctx->get_source_location (filename, line_number),
+	     get_identifier (name), t);
+
+  /* Propagate the newly-added type name so that previously-created
+     variant types are not disconnected from their main variants.  */
+  for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
+    TYPE_NAME (x) = TYPE_NAME (t);
+
+  return 1;
+}
+
+gcc_type
+plugin_build_pointer_type (cc1_plugin::connection *,
+			   gcc_type base_type)
+{
+  // No need to preserve a pointer type as the base type is preserved.
+  return convert_out (build_pointer_type (convert_in (base_type)));
+}
+
+// TYPE_NAME needs to be a valid pointer, even if there is no name available.
+
+static tree
+build_anonymous_node (enum tree_code code)
+{
+  tree node = make_node (code);
+  tree type_decl = build_decl (input_location, TYPE_DECL, NULL_TREE, node);
+  TYPE_NAME (node) = type_decl;
+  TYPE_STUB_DECL (node) = type_decl;
+  return node;
+}
+
+gcc_type
+plugin_build_record_type (cc1_plugin::connection *self)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  return convert_out (ctx->preserve (build_anonymous_node (RECORD_TYPE)));
+}
+
+gcc_type
+plugin_build_union_type (cc1_plugin::connection *self)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  return convert_out (ctx->preserve (build_anonymous_node (UNION_TYPE)));
+}
+
+int
+plugin_build_add_field (cc1_plugin::connection *,
+			gcc_type record_or_union_type_in,
+			const char *field_name,
+			gcc_type field_type_in,
+			unsigned long bitsize,
+			unsigned long bitpos)
+{
+  tree record_or_union_type = convert_in (record_or_union_type_in);
+  tree field_type = convert_in (field_type_in);
+
+  gcc_assert (TREE_CODE (record_or_union_type) == RECORD_TYPE
+	      || TREE_CODE (record_or_union_type) == UNION_TYPE);
+
+  /* Note that gdb does not preserve the location of field decls, so
+     we can't provide a decent location here.  */
+  tree decl = build_decl (BUILTINS_LOCATION, FIELD_DECL,
+			  get_identifier (field_name), field_type);
+  DECL_FIELD_CONTEXT (decl) = record_or_union_type;
+
+  if (TREE_CODE (field_type) == INTEGER_TYPE
+      && TYPE_PRECISION (field_type) != bitsize)
+    {
+      DECL_BIT_FIELD_TYPE (decl) = field_type;
+      TREE_TYPE (decl)
+	= c_build_bitfield_integer_type (bitsize, TYPE_UNSIGNED (field_type));
+    }
+
+  SET_DECL_MODE (decl, TYPE_MODE (TREE_TYPE (decl)));
+
+  // There's no way to recover this from DWARF.
+  SET_DECL_OFFSET_ALIGN (decl, TYPE_PRECISION (pointer_sized_int_node));
+
+  tree pos = bitsize_int (bitpos);
+  pos_from_bit (&DECL_FIELD_OFFSET (decl), &DECL_FIELD_BIT_OFFSET (decl),
+		DECL_OFFSET_ALIGN (decl), pos);
+
+  DECL_SIZE (decl) = bitsize_int (bitsize);
+  DECL_SIZE_UNIT (decl) = size_int ((bitsize + BITS_PER_UNIT - 1)
+				    / BITS_PER_UNIT);
+
+  DECL_CHAIN (decl) = TYPE_FIELDS (record_or_union_type);
+  TYPE_FIELDS (record_or_union_type) = decl;
+
+  return 1;
+}
+
+int
+plugin_finish_record_or_union (cc1_plugin::connection *,
+			       gcc_type record_or_union_type_in,
+			       unsigned long size_in_bytes)
+{
+  tree record_or_union_type = convert_in (record_or_union_type_in);
+
+  gcc_assert (TREE_CODE (record_or_union_type) == RECORD_TYPE
+	      || TREE_CODE (record_or_union_type) == UNION_TYPE);
+
+  /* We built the field list in reverse order, so fix it now.  */
+  TYPE_FIELDS (record_or_union_type)
+    = nreverse (TYPE_FIELDS (record_or_union_type));
+
+  if (TREE_CODE (record_or_union_type) == UNION_TYPE)
+    {
+      /* Unions can just be handled by the generic code.  */
+      layout_type (record_or_union_type);
+    }
+  else
+    {
+      // FIXME there's no way to get this from DWARF,
+      // or even, it seems, a particularly good way to deduce it.
+      SET_TYPE_ALIGN (record_or_union_type,
+		      TYPE_PRECISION (pointer_sized_int_node));
+
+      TYPE_SIZE (record_or_union_type) = bitsize_int (size_in_bytes
+						      * BITS_PER_UNIT);
+      TYPE_SIZE_UNIT (record_or_union_type) = size_int (size_in_bytes);
+
+      compute_record_mode (record_or_union_type);
+      finish_bitfield_layout (record_or_union_type);
+      // FIXME we have no idea about TYPE_PACKED
+    }
+
+  tree t = record_or_union_type, x;
+  for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
+    {
+      /* Like finish_struct, update the qualified variant types.  */
+      TYPE_FIELDS (x) = TYPE_FIELDS (t);
+      TYPE_LANG_SPECIFIC (x) = TYPE_LANG_SPECIFIC (t);
+      C_TYPE_FIELDS_READONLY (x) = C_TYPE_FIELDS_READONLY (t);
+      C_TYPE_FIELDS_VOLATILE (x) = C_TYPE_FIELDS_VOLATILE (t);
+      C_TYPE_VARIABLE_SIZE (x) = C_TYPE_VARIABLE_SIZE (t);
+      /* We copy these fields too.  */
+      SET_TYPE_ALIGN (x, TYPE_ALIGN (t));
+      TYPE_SIZE (x) = TYPE_SIZE (t);
+      TYPE_SIZE_UNIT (x) = TYPE_SIZE_UNIT (t);
+      if (x != record_or_union_type)
+	compute_record_mode (x);
+    }
+
+  return 1;
+}
+
+gcc_type
+plugin_build_enum_type (cc1_plugin::connection *self,
+			gcc_type underlying_int_type_in)
+{
+  tree underlying_int_type = convert_in (underlying_int_type_in);
+
+  if (underlying_int_type == error_mark_node)
+    return convert_out (error_mark_node);
+
+  tree result = build_anonymous_node (ENUMERAL_TYPE);
+
+  TYPE_PRECISION (result) = TYPE_PRECISION (underlying_int_type);
+  TYPE_UNSIGNED (result) = TYPE_UNSIGNED (underlying_int_type);
+
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  return convert_out (ctx->preserve (result));
+}
+
+int
+plugin_build_add_enum_constant (cc1_plugin::connection *,
+				gcc_type enum_type_in,
+				const char *name,
+				unsigned long value)
+{
+  tree cst, decl, cons;
+  tree enum_type = convert_in (enum_type_in);
+
+  gcc_assert (TREE_CODE (enum_type) == ENUMERAL_TYPE);
+
+  cst = build_int_cst (enum_type, value);
+  /* Note that gdb does not preserve the location of enum constants,
+     so we can't provide a decent location here.  */
+  decl = build_decl (BUILTINS_LOCATION, CONST_DECL,
+		     get_identifier (name), enum_type);
+  DECL_INITIAL (decl) = cst;
+  pushdecl_safe (decl);
+
+  cons = tree_cons (DECL_NAME (decl), cst, TYPE_VALUES (enum_type));
+  TYPE_VALUES (enum_type) = cons;
+
+  return 1;
+}
+
+int
+plugin_finish_enum_type (cc1_plugin::connection *,
+			 gcc_type enum_type_in)
+{
+  tree enum_type = convert_in (enum_type_in);
+  tree minnode, maxnode, iter;
+
+  iter = TYPE_VALUES (enum_type);
+  minnode = maxnode = TREE_VALUE (iter);
+  for (iter = TREE_CHAIN (iter);
+       iter != NULL_TREE;
+       iter = TREE_CHAIN (iter))
+    {
+      tree value = TREE_VALUE (iter);
+      if (tree_int_cst_lt (maxnode, value))
+	maxnode = value;
+      if (tree_int_cst_lt (value, minnode))
+	minnode = value;
+    }
+  TYPE_MIN_VALUE (enum_type) = minnode;
+  TYPE_MAX_VALUE (enum_type) = maxnode;
+
+  layout_type (enum_type);
+
+  return 1;
+}
+
+gcc_type
+plugin_build_function_type (cc1_plugin::connection *self,
+			    gcc_type return_type_in,
+			    const struct gcc_type_array *argument_types_in,
+			    int is_varargs)
+{
+  tree *argument_types;
+  tree return_type = convert_in (return_type_in);
+  tree result;
+
+  argument_types = new tree[argument_types_in->n_elements];
+  for (int i = 0; i < argument_types_in->n_elements; ++i)
+    argument_types[i] = convert_in (argument_types_in->elements[i]);
+
+  if (is_varargs)
+    result = build_varargs_function_type_array (return_type,
+						argument_types_in->n_elements,
+						argument_types);
+  else
+    result = build_function_type_array (return_type,
+					argument_types_in->n_elements,
+					argument_types);
+
+  delete[] argument_types;
+
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  return convert_out (ctx->preserve (result));
+}
+
+/* Return a builtin type associated with BUILTIN_NAME.  */
+
+static tree
+safe_lookup_builtin_type (const char *builtin_name)
+{
+  tree result = NULL_TREE;
+
+  if (!builtin_name)
+    return result;
+
+  result = identifier_global_value (get_identifier (builtin_name));
+
+  if (!result)
+    return result;
+
+  gcc_assert (TREE_CODE (result) == TYPE_DECL);
+  result = TREE_TYPE (result);
+  return result;
+}
+
+static gcc_type
+plugin_int_check (cc1_plugin::connection *self,
+		  int is_unsigned, unsigned long size_in_bytes,
+		  tree result)
+{
+  if (result == NULL_TREE)
+    result = error_mark_node;
+  else
+    {
+      gcc_assert (!TYPE_UNSIGNED (result) == !is_unsigned);
+      gcc_assert (TREE_CODE (TYPE_SIZE (result)) == INTEGER_CST);
+      gcc_assert (TYPE_PRECISION (result) == BITS_PER_UNIT * size_in_bytes);
+
+      plugin_context *ctx = static_cast<plugin_context *> (self);
+      ctx->preserve (result);
+    }
+  return convert_out (result);
+}
+
+gcc_type
+plugin_int_type_v0 (cc1_plugin::connection *self,
+		    int is_unsigned, unsigned long size_in_bytes)
+{
+  tree result = c_common_type_for_size (BITS_PER_UNIT * size_in_bytes,
+					is_unsigned);
+
+  return plugin_int_check (self, is_unsigned, size_in_bytes, result);
+}
+
+gcc_type
+plugin_int_type (cc1_plugin::connection *self,
+		 int is_unsigned, unsigned long size_in_bytes,
+		 const char *builtin_name)
+{
+  if (!builtin_name)
+    return plugin_int_type_v0 (self, is_unsigned, size_in_bytes);
+
+  tree result = safe_lookup_builtin_type (builtin_name);
+  gcc_assert (!result || TREE_CODE (result) == INTEGER_TYPE);
+
+  return plugin_int_check (self, is_unsigned, size_in_bytes, result);
+}
+
+gcc_type
+plugin_char_type (cc1_plugin::connection *)
+{
+  return convert_out (char_type_node);
+}
+
+gcc_type
+plugin_float_type_v0 (cc1_plugin::connection *,
+		   unsigned long size_in_bytes)
+{
+  if (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (float_type_node))
+    return convert_out (float_type_node);
+  if (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (double_type_node))
+    return convert_out (double_type_node);
+  if (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (long_double_type_node))
+    return convert_out (long_double_type_node);
+  return convert_out (error_mark_node);
+}
+
+gcc_type
+plugin_float_type (cc1_plugin::connection *self,
+		   unsigned long size_in_bytes,
+		   const char *builtin_name)
+{
+  if (!builtin_name)
+    return plugin_float_type_v0 (self, size_in_bytes);
+
+  tree result = safe_lookup_builtin_type (builtin_name);
+
+  if (!result)
+    return convert_out (error_mark_node);
+
+  gcc_assert (TREE_CODE (result) == REAL_TYPE);
+  gcc_assert (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (result));
+
+  return convert_out (result);
+}
+
+gcc_type
+plugin_void_type (cc1_plugin::connection *)
+{
+  return convert_out (void_type_node);
+}
+
+gcc_type
+plugin_bool_type (cc1_plugin::connection *)
+{
+  return convert_out (boolean_type_node);
+}
+
+gcc_type
+plugin_build_array_type (cc1_plugin::connection *self,
+			 gcc_type element_type_in, int num_elements)
+{
+  tree element_type = convert_in (element_type_in);
+  tree result;
+
+  if (num_elements == -1)
+    result = build_array_type (element_type, NULL_TREE);
+  else
+    result = build_array_type_nelts (element_type, num_elements);
+
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  return convert_out (ctx->preserve (result));
+}
+
+gcc_type
+plugin_build_vla_array_type (cc1_plugin::connection *self,
+			     gcc_type element_type_in,
+			     const char *upper_bound_name)
+{
+  tree element_type = convert_in (element_type_in);
+  tree upper_bound = lookup_name (get_identifier (upper_bound_name));
+  tree range = build_index_type (upper_bound);
+
+  tree result = build_array_type (element_type, range);
+  C_TYPE_VARIABLE_SIZE (result) = 1;
+
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  return convert_out (ctx->preserve (result));
+}
+
+gcc_type
+plugin_build_qualified_type (cc1_plugin::connection *,
+			     gcc_type unqualified_type_in,
+			     enum gcc_qualifiers qualifiers)
+{
+  tree unqualified_type = convert_in (unqualified_type_in);
+  int quals = 0;
+
+  if ((qualifiers & GCC_QUALIFIER_CONST) != 0)
+    quals |= TYPE_QUAL_CONST;
+  if ((qualifiers & GCC_QUALIFIER_VOLATILE) != 0)
+    quals |= TYPE_QUAL_VOLATILE;
+  if ((qualifiers & GCC_QUALIFIER_RESTRICT) != 0)
+    quals |= TYPE_QUAL_RESTRICT;
+
+  return convert_out (build_qualified_type (unqualified_type, quals));
+}
+
+gcc_type
+plugin_build_complex_type (cc1_plugin::connection *self,
+			   gcc_type base_type)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  return convert_out (ctx->preserve (build_complex_type (convert_in (base_type))));
+}
+
+gcc_type
+plugin_build_vector_type (cc1_plugin::connection *self,
+			  gcc_type base_type, int nunits)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  return convert_out (ctx->preserve (build_vector_type (convert_in (base_type),
+							nunits)));
+}
+
+int
+plugin_build_constant (cc1_plugin::connection *self, gcc_type type_in,
+		       const char *name, unsigned long value,
+		       const char *filename, unsigned int line_number)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree cst, decl;
+  tree type = convert_in (type_in);
+
+  cst = build_int_cst (type, value);
+  decl = build_decl (ctx->get_source_location (filename, line_number),
+		     CONST_DECL, get_identifier (name), type);
+  DECL_INITIAL (decl) = cst;
+  pushdecl_safe (decl);
+
+  return 1;
+}
+
+gcc_type
+plugin_error (cc1_plugin::connection *,
+	      const char *message)
+{
+  error ("%s", message);
+  return convert_out (error_mark_node);
+}
+
+
+
+// Perform GC marking.
+
+static void
+gc_mark (void *, void *)
+{
+  if (current_context != NULL)
+    current_context->mark ();
+}
+
+#ifdef __GNUC__
+#pragma GCC visibility push(default)
+#endif
+
+int
+plugin_init (struct plugin_name_args *plugin_info,
+	     struct plugin_gcc_version *)
+{
+  long fd = -1;
+  for (int i = 0; i < plugin_info->argc; ++i)
+    {
+      if (strcmp (plugin_info->argv[i].key, "fd") == 0)
+	{
+	  char *tail;
+	  errno = 0;
+	  fd = strtol (plugin_info->argv[i].value, &tail, 0);
+	  if (*tail != '\0' || errno != 0)
+	    fatal_error (input_location,
+			 "%s: invalid file descriptor argument to plugin",
+			 plugin_info->base_name);
+	  break;
+	}
+    }
+  if (fd == -1)
+    fatal_error (input_location,
+		 "%s: required plugin argument %<fd%> is missing",
+		 plugin_info->base_name);
+
+  current_context = new plugin_context (fd);
+
+  // Handshake.
+  cc1_plugin::protocol_int version;
+  if (!current_context->require ('H')
+      || ! ::cc1_plugin::unmarshall (current_context, &version))
+    fatal_error (input_location,
+		 "%s: handshake failed", plugin_info->base_name);
+  if (version != GCC_C_FE_VERSION_1)
+    fatal_error (input_location,
+		 "%s: unknown version in handshake", plugin_info->base_name);
+
+  register_callback (plugin_info->base_name, PLUGIN_PRAGMAS,
+		     plugin_init_extra_pragmas, NULL);
+  register_callback (plugin_info->base_name, PLUGIN_PRE_GENERICIZE,
+		     rewrite_decls_to_addresses, NULL);
+  register_callback (plugin_info->base_name, PLUGIN_GGC_MARKING,
+		     gc_mark, NULL);
+
+  lang_hooks.print_error_function = plugin_print_error_function;
+
+#define GCC_METHOD0(R, N)			\
+  {						\
+    cc1_plugin::callback_ftype *fun		\
+      = cc1_plugin::callback<R, plugin_ ## N>;	\
+    current_context->add_callback (# N, fun);	\
+  }
+#define GCC_METHOD1(R, N, A)				\
+  {							\
+    cc1_plugin::callback_ftype *fun			\
+      = cc1_plugin::callback<R, A, plugin_ ## N>;	\
+    current_context->add_callback (# N, fun);		\
+  }
+#define GCC_METHOD2(R, N, A, B)				\
+  {							\
+    cc1_plugin::callback_ftype *fun			\
+      = cc1_plugin::callback<R, A, B, plugin_ ## N>;	\
+    current_context->add_callback (# N, fun);		\
+  }
+#define GCC_METHOD3(R, N, A, B, C)			\
+  {							\
+    cc1_plugin::callback_ftype *fun			\
+      = cc1_plugin::callback<R, A, B, C, plugin_ ## N>;	\
+    current_context->add_callback (# N, fun);		\
+  }
+#define GCC_METHOD4(R, N, A, B, C, D)		\
+  {						\
+    cc1_plugin::callback_ftype *fun		\
+      = cc1_plugin::callback<R, A, B, C, D,	\
+			     plugin_ ## N>;	\
+    current_context->add_callback (# N, fun);	\
+  }
+#define GCC_METHOD5(R, N, A, B, C, D, E)	\
+  {						\
+    cc1_plugin::callback_ftype *fun		\
+      = cc1_plugin::callback<R, A, B, C, D, E,	\
+			     plugin_ ## N>;	\
+    current_context->add_callback (# N, fun);	\
+  }
+#define GCC_METHOD7(R, N, A, B, C, D, E, F, G)		\
+  {							\
+    cc1_plugin::callback_ftype *fun			\
+      = cc1_plugin::callback<R, A, B, C, D, E, F, G,	\
+			     plugin_ ## N>;		\
+    current_context->add_callback (# N, fun);		\
+  }
+
+#include "gcc-c-fe.def"
+
+#undef GCC_METHOD0
+#undef GCC_METHOD1
+#undef GCC_METHOD2
+#undef GCC_METHOD3
+#undef GCC_METHOD4
+#undef GCC_METHOD5
+#undef GCC_METHOD7
+
+  return 0;
+}
diff --git a/libcc1/libcp1.cc b/libcc1/libcp1.cc
new file mode 100644
index 0000000..bbd8488
--- /dev/null
+++ b/libcc1/libcp1.cc
@@ -0,0 +1,706 @@ 
+/* The library used by gdb.
+   Copyright (C) 2014-2017 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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 GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include <cc1plugin-config.h>
+#include <vector>
+#include <string>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <sstream>
+#include "marshall-cp.hh"
+#include "rpc.hh"
+#include "connection.hh"
+#include "names.hh"
+#include "callbacks.hh"
+#include "libiberty.h"
+#include "xregex.h"
+#include "findcomp.hh"
+#include "cp-compiler-name.h"
+#include "intl.h"
+
+struct libcp1;
+
+class libcp1_connection;
+
+// The C compiler context that we hand back to our caller.
+struct libcp1 : public gcc_cp_context
+{
+  libcp1 (const gcc_base_vtable *, const gcc_cp_fe_vtable *);
+  ~libcp1 ();
+
+  // A convenience function to print something.
+  void print (const char *str)
+  {
+    this->print_function (this->print_datum, str);
+  }
+
+  libcp1_connection *connection;
+
+  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 *oracle_datum;
+
+  void (*print_function) (void *datum, const char *message);
+  void *print_datum;
+
+  std::vector<std::string> args;
+  std::string source_file;
+
+  /* Non-zero as an equivalent to gcc driver option "-v".  */
+  bool verbose;
+
+  /* Compiler to set by set_triplet_regexp or set_driver_filename.  */
+  class compiler
+  {
+  protected:
+    libcp1 *self_;
+  public:
+    compiler (libcp1 *self) : self_ (self)
+    {
+    }
+    virtual char *find (std::string &compiler) const;
+    virtual ~compiler ()
+    {
+    }
+  } *compilerp;
+
+  /* Compiler to set by set_triplet_regexp.  */
+  class compiler_triplet_regexp : public compiler
+  {
+  private:
+    std::string triplet_regexp_;
+  public:
+    virtual char *find (std::string &compiler) const;
+    compiler_triplet_regexp (libcp1 *self, std::string triplet_regexp)
+      : compiler (self), triplet_regexp_ (triplet_regexp)
+    {
+    }
+    virtual ~compiler_triplet_regexp ()
+    {
+    }
+  };
+
+  /* Compiler to set by set_driver_filename.  */
+  class compiler_driver_filename : public compiler
+  {
+  private:
+    std::string driver_filename_;
+  public:
+    virtual char *find (std::string &compiler) const;
+    compiler_driver_filename (libcp1 *self, std::string driver_filename)
+      : compiler (self), driver_filename_ (driver_filename)
+    {
+    }
+    virtual ~compiler_driver_filename ()
+    {
+    }
+  };
+};
+
+// A local subclass of connection that holds a back-pointer to the
+// gcc_c_context object that we provide to our caller.
+class libcp1_connection : public cc1_plugin::connection
+{
+public:
+
+  libcp1_connection (int fd, int aux_fd, libcp1 *b)
+    : connection (fd, aux_fd),
+      back_ptr (b)
+  {
+  }
+
+  virtual void print (const char *buf)
+  {
+    back_ptr->print (buf);
+  }
+
+  libcp1 *back_ptr;
+};
+
+libcp1::libcp1 (const gcc_base_vtable *v,
+		  const gcc_cp_fe_vtable *cv)
+  : connection (NULL),
+    binding_oracle (NULL),
+    address_oracle (NULL),
+    oracle_datum (NULL),
+    print_function (NULL),
+    print_datum (NULL),
+    args (),
+    source_file (),
+    verbose (false),
+    compilerp (new libcp1::compiler (this))
+{
+  base.ops = v;
+  cp_ops = cv;
+}
+
+libcp1::~libcp1 ()
+{
+  delete connection;
+  delete compilerp;
+}
+
+
+
+// Enclose these functions in an anonymous namespace because they
+// shouldn't be exported, but they can't be static because they're
+// used as template arguments.
+namespace {
+  // This is a wrapper function that is called by the RPC system and
+  // that then forwards the call to the library user.  Note that the
+  // return value is not used; the type cannot be 'void' due to
+  // limitations in our simple RPC.
+  int
+  cp_call_binding_oracle (cc1_plugin::connection *conn,
+		       enum gcc_cp_oracle_request request,
+		       const char *identifier)
+  {
+    libcp1 *self = ((libcp1_connection *) conn)->back_ptr;
+
+    self->binding_oracle (self->oracle_datum, self, request, identifier);
+    return 1;
+  }
+
+  // This is a wrapper function that is called by the RPC system and
+  // that then forwards the call to the library user.
+  gcc_address
+  cp_call_symbol_address (cc1_plugin::connection *conn, const char *identifier)
+  {
+    libcp1 *self = ((libcp1_connection *) conn)->back_ptr;
+
+    return self->address_oracle (self->oracle_datum, self, identifier);
+  }
+
+  int
+  cp_call_enter_scope (cc1_plugin::connection *conn)
+  {
+    libcp1 *self = ((libcp1_connection *) conn)->back_ptr;
+
+    self->enter_scope (self->oracle_datum, self);
+    return 1;
+  }
+
+  int
+  cp_call_leave_scope (cc1_plugin::connection *conn)
+  {
+    libcp1 *self = ((libcp1_connection *) conn)->back_ptr;
+
+    self->leave_scope (self->oracle_datum, self);
+    return 1;
+  }
+} /* anonymous namespace */
+
+
+
+static void
+set_callbacks (struct gcc_cp_context *s,
+	       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)
+{
+  libcp1 *self = (libcp1 *) s;
+
+  self->binding_oracle = binding_oracle;
+  self->address_oracle = address_oracle;
+  self->enter_scope = enter_scope;
+  self->leave_scope = leave_scope;
+  self->oracle_datum = datum;
+}
+
+// Instances of these rpc<> template functions are installed into the
+// "cp_vtable".  These functions are parameterized by type and method
+// name and forward the call via the connection.
+
+template<typename R, const char *&NAME>
+R rpc (struct gcc_cp_context *s)
+{
+  libcp1 *self = (libcp1 *) s;
+  R result;
+
+  if (!cc1_plugin::call (self->connection, NAME, &result))
+    return 0;
+  return result;
+}
+
+template<typename R, const char *&NAME, typename A>
+R rpc (struct gcc_cp_context *s, A arg)
+{
+  libcp1 *self = (libcp1 *) s;
+  R result;
+
+  if (!cc1_plugin::call (self->connection, NAME, &result, arg))
+    return 0;
+  return result;
+}
+
+template<typename R, const char *&NAME, typename A1, typename A2>
+R rpc (struct gcc_cp_context *s, A1 arg1, A2 arg2)
+{
+  libcp1 *self = (libcp1 *) s;
+  R result;
+
+  if (!cc1_plugin::call (self->connection, NAME, &result, arg1, arg2))
+    return 0;
+  return result;
+}
+
+template<typename R, const char *&NAME, typename A1, typename A2, typename A3>
+R rpc (struct gcc_cp_context *s, A1 arg1, A2 arg2, A3 arg3)
+{
+  libcp1 *self = (libcp1 *) s;
+  R result;
+
+  if (!cc1_plugin::call (self->connection, NAME, &result, arg1, arg2, arg3))
+    return 0;
+  return result;
+}
+
+template<typename R, const char *&NAME, typename A1, typename A2, typename A3,
+	 typename A4>
+R rpc (struct gcc_cp_context *s, A1 arg1, A2 arg2, A3 arg3, A4 arg4)
+{
+  libcp1 *self = (libcp1 *) s;
+  R result;
+
+  if (!cc1_plugin::call (self->connection, NAME, &result, arg1, arg2, arg3,
+			 arg4))
+    return 0;
+  return result;
+}
+
+template<typename R, const char *&NAME, typename A1, typename A2, typename A3,
+	 typename A4, typename A5>
+R rpc (struct gcc_cp_context *s, A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5)
+{
+  libcp1 *self = (libcp1 *) s;
+  R result;
+
+  if (!cc1_plugin::call (self->connection, NAME, &result, arg1, arg2, arg3,
+			 arg4, arg5))
+    return 0;
+  return result;
+}
+
+template<typename R, const char *&NAME, typename A1, typename A2, typename A3,
+	 typename A4, typename A5, typename A6, typename A7>
+R rpc (struct gcc_cp_context *s, A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5,
+       A6 arg6, A7 arg7)
+{
+  libcp1 *self = (libcp1 *) s;
+  R result;
+
+  if (!cc1_plugin::call (self->connection, NAME, &result, arg1, arg2, arg3,
+			 arg4, arg5, arg6, arg7))
+    return 0;
+  return result;
+}
+
+static const struct gcc_cp_fe_vtable cp_vtable =
+{
+  GCC_CP_FE_VERSION_0,
+  set_callbacks,
+
+#define GCC_METHOD0(R, N) \
+  rpc<R, cc1_plugin::cp::N>,
+#define GCC_METHOD1(R, N, A) \
+  rpc<R, cc1_plugin::cp::N, A>,
+#define GCC_METHOD2(R, N, A, B) \
+  rpc<R, cc1_plugin::cp::N, A, B>,
+#define GCC_METHOD3(R, N, A, B, C) \
+  rpc<R, cc1_plugin::cp::N, A, B, C>,
+#define GCC_METHOD4(R, N, A, B, C, D) \
+  rpc<R, cc1_plugin::cp::N, A, B, C, D>,
+#define GCC_METHOD5(R, N, A, B, C, D, E) \
+  rpc<R, cc1_plugin::cp::N, A, B, C, D, E>,
+#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \
+  rpc<R, cc1_plugin::cp::N, A, B, C, D, E, F, G>,
+
+#include "gcc-cp-fe.def"
+
+#undef GCC_METHOD0
+#undef GCC_METHOD1
+#undef GCC_METHOD2
+#undef GCC_METHOD3
+#undef GCC_METHOD4
+#undef GCC_METHOD5
+#undef GCC_METHOD7
+};
+
+
+
+// Construct an appropriate regexp to match the compiler name.
+static std::string
+make_regexp (const char *triplet_regexp, const char *compiler)
+{
+  std::stringstream buf;
+
+  buf << "^" << triplet_regexp << "-";
+
+  // Quote the compiler name in case it has something funny in it.
+  for (const char *p = compiler; *p; ++p)
+    {
+      switch (*p)
+	{
+	case '.':
+	case '^':
+	case '$':
+	case '*':
+	case '+':
+	case '?':
+	case '(':
+	case ')':
+	case '[':
+	case '{':
+	case '\\':
+	case '|':
+	  buf << '\\';
+	  break;
+	}
+      buf << *p;
+    }
+  buf << "$";
+
+  return buf.str ();
+}
+
+static void
+libcp1_set_verbose (struct gcc_base_context *s, int /* bool */ verbose)
+{
+  libcp1 *self = (libcp1 *) s;
+
+  self->verbose = verbose != 0;
+}
+
+char *
+libcp1::compiler::find (std::string &compiler ATTRIBUTE_UNUSED) const
+{
+  return xstrdup (_("Compiler has not been specified"));
+}
+
+char *
+libcp1::compiler_triplet_regexp::find (std::string &compiler) const
+{
+  std::string rx = make_regexp (triplet_regexp_.c_str (), CP_COMPILER_NAME);
+  if (self_->verbose)
+    fprintf (stderr, _("searching for compiler matching regex %s\n"),
+	     rx.c_str());
+  regex_t triplet;
+  int code = regcomp (&triplet, rx.c_str (), REG_EXTENDED | REG_NOSUB);
+  if (code != 0)
+    {
+      size_t len = regerror (code, &triplet, NULL, 0);
+      char err[len];
+
+      regerror (code, &triplet, err, len);
+
+      return concat ("Could not compile regexp \"",
+		     rx.c_str (),
+		     "\": ",
+		     err,
+		     (char *) NULL);
+    }
+
+  if (!find_compiler (triplet, &compiler))
+    {
+      regfree (&triplet);
+      return concat ("Could not find a compiler matching \"",
+		     rx.c_str (),
+		     "\"",
+		     (char *) NULL);
+    }
+  regfree (&triplet);
+  if (self_->verbose)
+    fprintf (stderr, _("found compiler %s\n"), compiler.c_str());
+  return NULL;
+}
+
+char *
+libcp1::compiler_driver_filename::find (std::string &compiler) const
+{
+  // Simulate fnotice by fprintf.
+  if (self_->verbose)
+    fprintf (stderr, _("using explicit compiler filename %s\n"),
+	     driver_filename_.c_str());
+  compiler = driver_filename_;
+  return NULL;
+}
+
+static char *
+libcp1_set_arguments (struct gcc_base_context *s,
+		      int argc, char **argv)
+{
+  libcp1 *self = (libcp1 *) s;
+
+  std::string compiler;
+  char *errmsg = self->compilerp->find (compiler);
+  if (errmsg != NULL)
+    return errmsg;
+
+  self->args.push_back (compiler);
+
+  for (int i = 0; i < argc; ++i)
+    self->args.push_back (argv[i]);
+
+  return NULL;
+}
+
+static char *
+libcp1_set_triplet_regexp (struct gcc_base_context *s,
+			   const char *triplet_regexp)
+{
+  libcp1 *self = (libcp1 *) s;
+
+  delete self->compilerp;
+  self->compilerp = new libcp1::compiler_triplet_regexp (self, triplet_regexp);
+  return NULL;
+}
+
+static char *
+libcp1_set_driver_filename (struct gcc_base_context *s,
+			    const char *driver_filename)
+{
+  libcp1 *self = (libcp1 *) s;
+
+  delete self->compilerp;
+  self->compilerp = new libcp1::compiler_driver_filename (self,
+							  driver_filename);
+  return NULL;
+}
+
+static char *
+libcp1_set_arguments_v0 (struct gcc_base_context *s,
+			 const char *triplet_regexp,
+			 int argc, char **argv)
+{
+  char *errmsg = libcp1_set_triplet_regexp (s, triplet_regexp);
+  if (errmsg != NULL)
+    return errmsg;
+
+  return libcp1_set_arguments (s, argc, argv);
+}
+
+static void
+libcp1_set_source_file (struct gcc_base_context *s,
+			 const char *file)
+{
+  libcp1 *self = (libcp1 *) s;
+
+  self->source_file = file;
+}
+
+static void
+libcp1_set_print_callback (struct gcc_base_context *s,
+			    void (*print_function) (void *datum,
+						    const char *message),
+			    void *datum)
+{
+  libcp1 *self = (libcp1 *) s;
+
+  self->print_function = print_function;
+  self->print_datum = datum;
+}
+
+static int
+fork_exec (libcp1 *self, char **argv, int spair_fds[2], int stderr_fds[2])
+{
+  pid_t child_pid = fork ();
+
+  if (child_pid == -1)
+    {
+      close (spair_fds[0]);
+      close (spair_fds[1]);
+      close (stderr_fds[0]);
+      close (stderr_fds[1]);
+      return 0;
+    }
+
+  if (child_pid == 0)
+    {
+      // Child.
+      dup2 (stderr_fds[1], 1);
+      dup2 (stderr_fds[1], 2);
+      close (stderr_fds[0]);
+      close (stderr_fds[1]);
+      close (spair_fds[0]);
+
+      execvp (argv[0], argv);
+      _exit (127);
+    }
+  else
+    {
+      // Parent.
+      close (spair_fds[1]);
+      close (stderr_fds[1]);
+
+      cc1_plugin::status result = cc1_plugin::FAIL;
+      if (self->connection->send ('H')
+	  && ::cc1_plugin::marshall (self->connection, GCC_CP_FE_VERSION_0))
+	result = self->connection->wait_for_query ();
+
+      close (spair_fds[0]);
+      close (stderr_fds[0]);
+
+      while (true)
+	{
+	  int status;
+
+	  if (waitpid (child_pid, &status, 0) == -1)
+	    {
+	      if (errno != EINTR)
+		return 0;
+	    }
+
+	  if (!WIFEXITED (status) || WEXITSTATUS (status) != 0)
+	    return 0;
+	  break;
+	}
+
+      if (!result)
+	return 0;
+      return 1;
+    }
+}
+
+static int
+libcp1_compile (struct gcc_base_context *s,
+		const char *filename)
+{
+  libcp1 *self = (libcp1 *) s;
+
+  int fds[2];
+  if (socketpair (AF_UNIX, SOCK_STREAM, 0, fds) != 0)
+    {
+      self->print ("could not create socketpair\n");
+      return 0;
+    }
+
+  int stderr_fds[2];
+  if (pipe (stderr_fds) != 0)
+    {
+      self->print ("could not create pipe\n");
+      close (fds[0]);
+      close (fds[1]);
+      return 0;
+    }
+
+  self->args.push_back ("-fplugin=libcp1plugin");
+  char buf[100];
+  if (snprintf (buf, sizeof (buf), "-fplugin-arg-libcp1plugin-fd=%d", fds[1])
+      >= (long) sizeof (buf))
+    abort ();
+  self->args.push_back (buf);
+
+  self->args.push_back (self->source_file);
+  self->args.push_back ("-c");
+  self->args.push_back ("-o");
+  self->args.push_back (filename);
+  if (self->verbose)
+    self->args.push_back ("-v");
+
+  self->connection = new libcp1_connection (fds[0], stderr_fds[0], self);
+
+  cc1_plugin::callback_ftype *fun
+    = cc1_plugin::callback<int,
+			   enum gcc_cp_oracle_request,
+			   const char *,
+			   cp_call_binding_oracle>;
+  self->connection->add_callback ("binding_oracle", fun);
+
+  fun = cc1_plugin::callback<gcc_address,
+			     const char *,
+			     cp_call_symbol_address>;
+  self->connection->add_callback ("address_oracle", fun);
+
+  fun = cc1_plugin::callback<int,
+			     cp_call_enter_scope>;
+  self->connection->add_callback ("enter_scope", fun);
+
+  fun = cc1_plugin::callback<int,
+			     cp_call_leave_scope>;
+  self->connection->add_callback ("leave_scope", fun);
+
+  char **argv = new (std::nothrow) char *[self->args.size () + 1];
+  if (argv == NULL)
+    return 0;
+
+  for (unsigned int i = 0; i < self->args.size (); ++i)
+    argv[i] = const_cast<char *> (self->args[i].c_str ());
+  argv[self->args.size ()] = NULL;
+
+  return fork_exec (self, argv, fds, stderr_fds);
+}
+
+static int
+libcp1_compile_v0 (struct gcc_base_context *s, const char *filename,
+		   int verbose)
+{
+  libcp1_set_verbose (s, verbose);
+  return libcp1_compile (s, filename);
+}
+
+static void
+libcp1_destroy (struct gcc_base_context *s)
+{
+  libcp1 *self = (libcp1 *) s;
+
+  delete self;
+}
+
+static const struct gcc_base_vtable vtable =
+{
+  GCC_FE_VERSION_0,
+  libcp1_set_arguments_v0,
+  libcp1_set_source_file,
+  libcp1_set_print_callback,
+  libcp1_compile_v0,
+  libcp1_destroy,
+  libcp1_set_verbose,
+  libcp1_compile,
+  libcp1_set_arguments,
+  libcp1_set_triplet_regexp,
+  libcp1_set_driver_filename,
+};
+
+extern "C" gcc_cp_fe_context_function gcc_cp_fe_context;
+
+#ifdef __GNUC__
+#pragma GCC visibility push(default)
+#endif
+
+extern "C"
+struct gcc_cp_context *
+gcc_cp_fe_context (enum gcc_base_api_version base_version,
+		    enum gcc_cp_api_version cp_version)
+{
+  if ((base_version != GCC_FE_VERSION_0 && base_version != GCC_FE_VERSION_1)
+      || cp_version != GCC_CP_FE_VERSION_0)
+    return NULL;
+
+  return new libcp1 (&vtable, &cp_vtable);
+}
diff --git a/libcc1/libcp1plugin.cc b/libcc1/libcp1plugin.cc
new file mode 100644
index 0000000..545f28b9
--- /dev/null
+++ b/libcc1/libcp1plugin.cc
@@ -0,0 +1,3789 @@ 
+/* Library interface to C++ front end.
+   Copyright (C) 2014-2017 Free Software Foundation, Inc.
+
+   This file is part of GCC.  As it interacts with GDB through libcc1,
+   they all become a single program as regards the GNU GPL's requirements.
+
+   GCC 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, or (at your option) any later
+   version.
+
+   GCC 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 GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <cc1plugin-config.h>
+
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+
+#include "../gcc/config.h"
+
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "stringpool.h"
+
+#include "gcc-interface.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "vec.h"
+#include "double-int.h"
+#include "input.h"
+#include "alias.h"
+#include "symtab.h"
+#include "options.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "tree.h"
+#include "fold-const.h"
+#include "stor-layout.h"
+#include "cp-tree.h"
+#include "toplev.h"
+#include "timevar.h"
+#include "hash-table.h"
+#include "tm.h"
+#include "c-family/c-pragma.h"
+// #include "c-lang.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+#include "decl.h"
+#include "function.h"
+#undef cfun // we want to assign to it, and function.h won't let us
+
+#include "callbacks.hh"
+#include "connection.hh"
+#include "marshall-cp.hh"
+#include "rpc.hh"
+
+#ifdef __GNUC__
+#pragma GCC visibility push(default)
+#endif
+int plugin_is_GPL_compatible;
+#ifdef __GNUC__
+#pragma GCC visibility pop
+#endif
+
+
+
+static int ATTRIBUTE_UNUSED
+check_symbol_mask[GCC_CP_SYMBOL_MASK >= GCC_CP_SYMBOL_END ? 1 : -1];
+
+// This is put into the lang hooks when the plugin starts.
+
+static void
+plugin_print_error_function (diagnostic_context *context, const char *file,
+			     diagnostic_info *diagnostic)
+{
+  if (current_function_decl != NULL_TREE
+      && DECL_NAME (current_function_decl) != NULL_TREE
+      && strcmp (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),
+		 GCC_FE_WRAPPER_FUNCTION) == 0)
+    return;
+  lhd_print_error_function (context, file, diagnostic);
+}
+
+
+
+static unsigned long long
+convert_out (tree t)
+{
+  return (unsigned long long) (uintptr_t) t;
+}
+
+static tree
+convert_in (unsigned long long v)
+{
+  return (tree) (uintptr_t) v;
+}
+
+
+
+struct decl_addr_value
+{
+  tree decl;
+  tree address;
+};
+
+struct decl_addr_hasher : free_ptr_hash<decl_addr_value>
+{
+  static inline hashval_t hash (const decl_addr_value *);
+  static inline bool equal (const decl_addr_value *, const decl_addr_value *);
+};
+
+inline hashval_t
+decl_addr_hasher::hash (const decl_addr_value *e)
+{
+  return DECL_UID (e->decl);
+}
+
+inline bool
+decl_addr_hasher::equal (const decl_addr_value *p1, const decl_addr_value *p2)
+{
+  return p1->decl == p2->decl;
+}
+
+
+
+struct string_hasher : nofree_ptr_hash<const char>
+{
+  static inline hashval_t hash (const char *s)
+  {
+    return htab_hash_string (s);
+  }
+
+  static inline bool equal (const char *p1, const char *p2)
+  {
+    return strcmp (p1, p2) == 0;
+  }
+};
+
+
+
+struct plugin_context : public cc1_plugin::connection
+{
+  plugin_context (int fd);
+
+  // Map decls to addresses.
+  hash_table<decl_addr_hasher> address_map;
+
+  // A collection of trees that are preserved for the GC.
+  hash_table< nofree_ptr_hash<tree_node> > preserved;
+
+  // File name cache.
+  hash_table<string_hasher> file_names;
+
+  // Perform GC marking.
+  void mark ();
+
+  // Preserve a tree during the plugin's operation.
+  tree preserve (tree t)
+  {
+    tree_node **slot = preserved.find_slot (t, INSERT);
+    *slot = t;
+    return t;
+  }
+
+  source_location get_source_location (const char *filename,
+				       unsigned int line_number)
+  {
+    if (filename == NULL)
+      return UNKNOWN_LOCATION;
+
+    filename = intern_filename (filename);
+    linemap_add (line_table, LC_ENTER, false, filename, line_number);
+    source_location loc = linemap_line_start (line_table, line_number, 0);
+    linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+    return loc;
+  }
+
+private:
+
+  // Add a file name to FILE_NAMES and return the canonical copy.
+  const char *intern_filename (const char *filename)
+  {
+    const char **slot = file_names.find_slot (filename, INSERT);
+    if (*slot == NULL)
+      {
+	/* The file name must live as long as the line map, which
+	   effectively means as long as this compilation.  So, we copy
+	   the string here but never free it.  */
+	*slot = xstrdup (filename);
+      }
+    return *slot;
+  }
+};
+
+static plugin_context *current_context;
+
+
+
+plugin_context::plugin_context (int fd)
+  : cc1_plugin::connection (fd),
+    address_map (30),
+    preserved (30),
+    file_names (30)
+{
+}
+
+void
+plugin_context::mark ()
+{
+  for (hash_table<decl_addr_hasher>::iterator it = address_map.begin ();
+       it != address_map.end ();
+       ++it)
+    {
+      ggc_mark ((*it)->decl);
+      ggc_mark ((*it)->address);
+    }
+
+  for (hash_table< nofree_ptr_hash<tree_node> >::iterator
+	 it = preserved.begin (); it != preserved.end (); ++it)
+    ggc_mark (&*it);
+}
+
+static void
+plugin_binding_oracle (enum cp_oracle_request kind, tree identifier)
+{
+  enum gcc_cp_oracle_request request;
+
+  gcc_assert (current_context != NULL);
+
+  switch (kind)
+    {
+    case CP_ORACLE_IDENTIFIER:
+      request = GCC_CP_ORACLE_IDENTIFIER;
+      break;
+    default:
+      abort ();
+    }
+
+  int ignore;
+  cc1_plugin::call (current_context, "binding_oracle", &ignore,
+		    request, IDENTIFIER_POINTER (identifier));
+}
+
+static int push_count;
+
+/* at_function_scope_p () tests cfun, indicating we're actually
+   compiling the function, but we don't even set it when pretending to
+   enter a function scope.  We use this distinction to tell these two
+   cases apart: we don't want to define e.g. class names in the user
+   expression function's scope, when they're local to the original
+   function, because they'd get the wrong linkage name.  */
+
+static bool
+at_fake_function_scope_p ()
+{
+  return (!cfun || cfun->decl != current_function_decl)
+    && current_scope () == current_function_decl;
+}
+
+static void
+push_fake_function (tree fndecl, scope_kind kind = sk_function_parms)
+{
+  current_function_decl = fndecl;
+  begin_scope (kind, fndecl);
+  ++function_depth;
+  begin_scope (sk_block, NULL);
+}
+
+static void
+pop_scope ()
+{
+  if (toplevel_bindings_p () && current_namespace == global_namespace)
+    pop_from_top_level ();
+  else if (at_namespace_scope_p ())
+    pop_namespace ();
+  else if (at_class_scope_p ())
+    popclass ();
+  else
+    {
+      gcc_assert (at_fake_function_scope_p ());
+      gcc_assert (!at_function_scope_p ());
+      gcc_assert (current_binding_level->kind == sk_block
+		  && current_binding_level->this_entity == NULL);
+      leave_scope ();
+      --function_depth;
+      gcc_assert (current_binding_level->this_entity
+		  == current_function_decl);
+      leave_scope ();
+      current_function_decl = NULL;
+      for (cp_binding_level *scope = current_binding_level;
+	   scope; scope = scope->level_chain)
+	if (scope->kind == sk_function_parms)
+	  {
+	    current_function_decl = scope->this_entity;
+	    break;
+	  }
+    }
+}
+
+static void
+supplement_binding (cxx_binding *binding, tree decl)
+{
+  /* FIXME: this is pretty much a copy of supplement_binding_1 in
+     ../gcc/cp/name-lookup.c; the few replaced/removed bits are marked
+     with "// _1:".  */
+  tree bval = binding->value;
+  bool ok = true;
+  tree target_bval = strip_using_decl (bval);
+  tree target_decl = strip_using_decl (decl);
+
+  if (TREE_CODE (target_decl) == TYPE_DECL && DECL_ARTIFICIAL (target_decl)
+      && target_decl != target_bval
+      && (TREE_CODE (target_bval) != TYPE_DECL
+	  /* We allow pushing an enum multiple times in a class
+	     template in order to handle late matching of underlying
+	     type on an opaque-enum-declaration followed by an
+	     enum-specifier.  */
+	  || (processing_template_decl
+	      && TREE_CODE (TREE_TYPE (target_decl)) == ENUMERAL_TYPE
+	      && TREE_CODE (TREE_TYPE (target_bval)) == ENUMERAL_TYPE
+	      && (dependent_type_p (ENUM_UNDERLYING_TYPE
+				    (TREE_TYPE (target_decl)))
+		  || dependent_type_p (ENUM_UNDERLYING_TYPE
+				       (TREE_TYPE (target_bval)))))))
+    /* The new name is the type name.  */
+    binding->type = decl;
+  else if (/* TARGET_BVAL is null when push_class_level_binding moves
+	      an inherited type-binding out of the way to make room
+	      for a new value binding.  */
+	   !target_bval
+	   /* TARGET_BVAL is error_mark_node when TARGET_DECL's name
+	      has been used in a non-class scope prior declaration.
+	      In that case, we should have already issued a
+	      diagnostic; for graceful error recovery purpose, pretend
+	      this was the intended declaration for that name.  */
+	   || target_bval == error_mark_node
+	   /* If TARGET_BVAL is anticipated but has not yet been
+	      declared, pretend it is not there at all.  */
+	   || (TREE_CODE (target_bval) == FUNCTION_DECL
+	       && DECL_ANTICIPATED (target_bval)
+	       && !DECL_HIDDEN_FRIEND_P (target_bval)))
+    binding->value = decl;
+  else if (TREE_CODE (target_bval) == TYPE_DECL
+	   && DECL_ARTIFICIAL (target_bval)
+	   && target_decl != target_bval
+	   && (TREE_CODE (target_decl) != TYPE_DECL
+	       || same_type_p (TREE_TYPE (target_decl),
+			       TREE_TYPE (target_bval))))
+    {
+      /* The old binding was a type name.  It was placed in
+	 VALUE field because it was thought, at the point it was
+	 declared, to be the only entity with such a name.  Move the
+	 type name into the type slot; it is now hidden by the new
+	 binding.  */
+      binding->type = bval;
+      binding->value = decl;
+      binding->value_is_inherited = false;
+    }
+  else if (TREE_CODE (target_bval) == TYPE_DECL
+	   && TREE_CODE (target_decl) == TYPE_DECL
+	   && DECL_NAME (target_decl) == DECL_NAME (target_bval)
+	   && binding->scope->kind != sk_class
+	   && (same_type_p (TREE_TYPE (target_decl), TREE_TYPE (target_bval))
+	       /* If either type involves template parameters, we must
+		  wait until instantiation.  */
+	       || uses_template_parms (TREE_TYPE (target_decl))
+	       || uses_template_parms (TREE_TYPE (target_bval))))
+    /* We have two typedef-names, both naming the same type to have
+       the same name.  In general, this is OK because of:
+
+	 [dcl.typedef]
+
+	 In a given scope, a typedef specifier can be used to redefine
+	 the name of any type declared in that scope to refer to the
+	 type to which it already refers.
+
+       However, in class scopes, this rule does not apply due to the
+       stricter language in [class.mem] prohibiting redeclarations of
+       members.  */
+    ok = false;
+  /* There can be two block-scope declarations of the same variable,
+     so long as they are `extern' declarations.  However, there cannot
+     be two declarations of the same static data member:
+
+       [class.mem]
+
+       A member shall not be declared twice in the
+       member-specification.  */
+  else if (VAR_P (target_decl)
+	   && VAR_P (target_bval)
+	   && DECL_EXTERNAL (target_decl) && DECL_EXTERNAL (target_bval)
+	   && !DECL_CLASS_SCOPE_P (target_decl))
+    {
+      duplicate_decls (decl, binding->value, /*newdecl_is_friend=*/false);
+      ok = false;
+    }
+  else if (TREE_CODE (decl) == NAMESPACE_DECL
+	   && TREE_CODE (bval) == NAMESPACE_DECL
+	   && DECL_NAMESPACE_ALIAS (decl)
+	   && DECL_NAMESPACE_ALIAS (bval)
+	   && ORIGINAL_NAMESPACE (bval) == ORIGINAL_NAMESPACE (decl))
+    /* [namespace.alias]
+
+      In a declarative region, a namespace-alias-definition can be
+      used to redefine a namespace-alias declared in that declarative
+      region to refer only to the namespace to which it already
+      refers.  */
+    ok = false;
+  else if (maybe_remove_implicit_alias (bval))
+    {
+      /* There was a mangling compatibility alias using this mangled name,
+	 but now we have a real decl that wants to use it instead.  */
+      binding->value = decl;
+    }
+  else
+    {
+      // _1: diagnose_name_conflict (decl, bval);
+      ok = false;
+    }
+
+  gcc_assert (ok); // _1: return ok;
+}
+
+static void
+reactivate_decl (tree decl, cp_binding_level *b)
+{
+  bool in_function_p = TREE_CODE (b->this_entity) == FUNCTION_DECL;
+  gcc_assert (in_function_p
+	      || (b == current_binding_level
+		  && !at_class_scope_p ()));
+
+  tree id = DECL_NAME (decl);
+  tree type = NULL_TREE;
+  if (TREE_CODE (decl) == TYPE_DECL)
+    type = TREE_TYPE (decl);
+
+  if (type && TYPE_NAME (type) == decl
+      && (RECORD_OR_UNION_CODE_P (TREE_CODE (type))
+	  || TREE_CODE (type) == ENUMERAL_TYPE))
+    {
+      gcc_assert (in_function_p && DECL_CONTEXT (decl) == b->this_entity);
+      type = TREE_TYPE (decl);
+    }
+  else
+    {
+      gcc_assert (DECL_CONTEXT (decl) == b->this_entity
+		  || DECL_CONTEXT (decl) == global_namespace
+		  || TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL);
+      type = NULL_TREE;
+    }
+
+  /* Adjust IDENTIFIER_BINDING to what it would have been if we were
+     at binding level B.  Save the binding chain up to that point in
+     [binding, *chainp), and take note of the outermost bindings found
+     before B.  */
+  cxx_binding *binding = IDENTIFIER_BINDING (id), **chainp = NULL;
+  tree *shadowing_type_p = NULL;
+  if (binding)
+    {
+      cp_binding_level *bc = current_binding_level;
+      for (cxx_binding *prev_binding = binding;
+	   prev_binding; prev_binding = prev_binding->previous)
+	{
+	  while (bc != b && bc != prev_binding->scope)
+	    bc = bc->level_chain;
+	  if (bc == b)
+	    {
+	      if (!chainp)
+		binding = NULL;
+	      break;
+	    }
+	  chainp = &prev_binding->previous;
+	  if (type)
+	    for (tree tshadow = prev_binding->scope->type_shadowed;
+		 tshadow; tshadow = TREE_CHAIN (tshadow))
+	      if (TREE_PURPOSE (tshadow) == id)
+		{
+		  shadowing_type_p = &TREE_VALUE (tshadow);
+		  break;
+		}
+	}
+    }
+  if (chainp)
+    {
+      IDENTIFIER_BINDING (id) = *chainp;
+      *chainp = NULL;
+    }
+
+  /* Like push_local_binding, supplement or add a binding to the
+     desired level.  */
+  if (IDENTIFIER_BINDING (id) && IDENTIFIER_BINDING (id)->scope == b)
+    supplement_binding (IDENTIFIER_BINDING (id), decl);
+  else
+    push_binding (id, decl, b);
+
+  /* Now restore the binding chain we'd temporarily removed.  */
+  if (chainp)
+    {
+      *chainp = IDENTIFIER_BINDING (id);
+      IDENTIFIER_BINDING (id) = binding;
+
+      if (type)
+	{
+	  /* Insert the new type binding in the shadowing_type_p
+	     TREE_VALUE chain.  */
+	  tree shadowed_type = NULL_TREE;
+	  if (shadowing_type_p)
+	    {
+	      shadowed_type = *shadowing_type_p;
+	      *shadowing_type_p = type;
+	    }
+
+	  b->type_shadowed = tree_cons (id, shadowed_type, b->type_shadowed);
+	  TREE_TYPE (b->type_shadowed) = type;
+	}
+    }
+  else if (type)
+    {
+      /* Our new binding is the active one, so shadow the earlier
+	 binding.  */
+      b->type_shadowed = tree_cons (id, REAL_IDENTIFIER_TYPE_VALUE (id),
+				    b->type_shadowed);
+      TREE_TYPE (b->type_shadowed) = type;
+      SET_IDENTIFIER_TYPE_VALUE (id, type);
+    }
+
+  /* Record that we have a binding for ID, like add_decl_to_level.  */
+  tree node = build_tree_list (NULL_TREE, decl);
+  TREE_CHAIN (node) = b->names;
+  b->names = node;
+}
+
+static void
+plugin_pragma_push_user_expression (cpp_reader *)
+{
+  if (push_count++)
+    return;
+
+  gcc_assert (!current_class_ptr);
+  gcc_assert (!current_class_ref);
+
+  gcc_assert (!cp_binding_oracle);
+  cp_binding_oracle = plugin_binding_oracle;
+
+  /* Make the function containing the user expression a global
+     friend, so as to bypass access controls in it.  */
+  if (at_function_scope_p ())
+    set_global_friend (current_function_decl);
+
+  gcc_assert (at_function_scope_p ());
+  function *save_cfun = cfun;
+  cp_binding_level *orig_binding_level = current_binding_level;
+  {
+    int success;
+    cc1_plugin::call (current_context, "enter_scope", &success);
+  }
+  gcc_assert (at_fake_function_scope_p () || at_function_scope_p ());
+
+  function *unchanged_cfun = cfun;
+  tree changed_func_decl = current_function_decl;
+
+  gcc_assert (current_class_type == DECL_CONTEXT (current_function_decl)
+	      || !(RECORD_OR_UNION_CODE_P
+		   (TREE_CODE (DECL_CONTEXT (current_function_decl)))));
+  push_fake_function (save_cfun->decl, sk_block);
+  current_class_type = NULL_TREE;
+  if (unchanged_cfun)
+    {
+      /* If we get here, GDB did NOT change the context.  */
+      gcc_assert (cfun == save_cfun);
+      gcc_assert (at_function_scope_p ());
+      gcc_assert (orig_binding_level
+		  == current_binding_level->level_chain->level_chain);
+    }
+  else
+    {
+      cfun = save_cfun;
+      gcc_assert (at_function_scope_p ());
+
+      cp_binding_level *b = current_binding_level->level_chain;
+      gcc_assert (b->this_entity == cfun->decl);
+
+      /* Reactivate local names from the previous context.  Use
+	 IDENTIFIER_MARKED to avoid reactivating shadowed names.  */
+      for (cp_binding_level *level = orig_binding_level;;)
+	{
+	  for (tree name = level->names;
+	       name; name = TREE_CHAIN (name))
+	    {
+	      tree decl = name;
+	      if (TREE_CODE (decl) == TREE_LIST)
+		decl = TREE_VALUE (decl);
+	      if (IDENTIFIER_MARKED (DECL_NAME (decl)))
+		continue;
+	      IDENTIFIER_MARKED (DECL_NAME (decl)) = 1;
+	      reactivate_decl (decl, b);
+	    }
+	  if (level->kind == sk_function_parms
+	      && level->this_entity == cfun->decl)
+	    break;
+	  gcc_assert (!level->this_entity);
+	  level = level->level_chain;
+	}
+
+      /* Now, clear the markers.  */
+      for (tree name = b->names; name; name = TREE_CHAIN (name))
+	{
+	  tree decl = name;
+	  if (TREE_CODE (decl) == TREE_LIST)
+	    decl = TREE_VALUE (decl);
+	  gcc_assert (IDENTIFIER_MARKED (DECL_NAME (decl)));
+	  IDENTIFIER_MARKED (DECL_NAME (decl)) = 0;
+	}
+    }
+
+  if (unchanged_cfun || DECL_NONSTATIC_MEMBER_FUNCTION_P (changed_func_decl))
+    {
+      /* Check whether the oracle supplies us with a "this", and if
+	 so, arrange for data members and this itself to be
+	 usable.  */
+      tree this_val = lookup_name (get_identifier ("this"));
+      current_class_ref = !this_val ? NULL_TREE
+	: cp_build_indirect_ref (this_val, RO_NULL, tf_warning_or_error);
+      current_class_ptr = this_val;
+    }
+}
+
+static void
+plugin_pragma_pop_user_expression (cpp_reader *)
+{
+  if (--push_count)
+    return;
+
+  gcc_assert (cp_binding_oracle);
+
+  gcc_assert (at_function_scope_p ());
+  function *save_cfun = cfun;
+  current_class_ptr = NULL_TREE;
+  current_class_ref = NULL_TREE;
+
+  cfun = NULL;
+  pop_scope ();
+  if (RECORD_OR_UNION_CODE_P (TREE_CODE (DECL_CONTEXT (current_function_decl))))
+    current_class_type = DECL_CONTEXT (current_function_decl);
+  {
+    int success;
+    cc1_plugin::call (current_context, "leave_scope", &success);
+  }
+  if (!cfun)
+    cfun = save_cfun;
+  else
+    gcc_assert (cfun == save_cfun);
+
+  cp_binding_oracle = NULL;
+  gcc_assert (at_function_scope_p ());
+}
+
+static void
+plugin_init_extra_pragmas (void *, void *)
+{
+  c_register_pragma ("GCC", "push_user_expression", plugin_pragma_push_user_expression);
+  c_register_pragma ("GCC", "pop_user_expression", plugin_pragma_pop_user_expression);
+  /* FIXME: this one should go once we get GDB to use push and pop.  */
+  c_register_pragma ("GCC", "user_expression", plugin_pragma_push_user_expression);
+}
+
+
+
+static decl_addr_value
+build_decl_addr_value (tree decl, gcc_address address)
+{
+  decl_addr_value value = {
+    decl,
+    build_int_cst_type (ptr_type_node, address)
+  };
+  return value;
+}
+
+static decl_addr_value *
+record_decl_address (plugin_context *ctx, decl_addr_value value)
+{
+  decl_addr_value **slot = ctx->address_map.find_slot (&value, INSERT);
+  gcc_assert (*slot == NULL);
+  *slot
+    = static_cast<decl_addr_value *> (xmalloc (sizeof (decl_addr_value)));
+  **slot = value;
+  /* We don't want GCC to warn about e.g. static functions
+     without a code definition.  */
+  TREE_NO_WARNING (value.decl) = 1;
+  return *slot;
+}
+
+// Maybe rewrite a decl to its address.
+static tree
+address_rewriter (tree *in, int *walk_subtrees, void *arg)
+{
+  plugin_context *ctx = (plugin_context *) arg;
+
+  if (!DECL_P (*in)
+      || TREE_CODE (*in) == NAMESPACE_DECL
+      || DECL_NAME (*in) == NULL_TREE)
+    return NULL_TREE;
+
+  decl_addr_value value;
+  value.decl = *in;
+  decl_addr_value *found_value = ctx->address_map.find (&value);
+  if (found_value != NULL)
+    ;
+  else if (HAS_DECL_ASSEMBLER_NAME_P (*in))
+    {
+      gcc_address address;
+
+      if (!cc1_plugin::call (ctx, "address_oracle", &address,
+			     IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (*in))))
+	return NULL_TREE;
+      if (address == 0)
+	return NULL_TREE;
+
+      // Insert the decl into the address map in case it is referenced
+      // again.
+      value = build_decl_addr_value (value.decl, address);
+      found_value = record_decl_address (ctx, value);
+    }
+  else
+    return NULL_TREE;
+
+  if (found_value->address != error_mark_node)
+    {
+      // We have an address for the decl, so rewrite the tree.
+      tree ptr_type = build_pointer_type (TREE_TYPE (*in));
+      *in = fold_build1 (INDIRECT_REF, TREE_TYPE (*in),
+			 fold_build1 (CONVERT_EXPR, ptr_type,
+				      found_value->address));
+    }
+
+  *walk_subtrees = 0;
+
+  return NULL_TREE;
+}
+
+// When generating code for gdb, we want to be able to use absolute
+// addresses to refer to otherwise external objects that gdb knows
+// about.  gdb passes in these addresses when building decls, and then
+// before gimplification we go through the trees, rewriting uses to
+// the equivalent of "*(TYPE *) ADDR".
+static void
+rewrite_decls_to_addresses (void *function_in, void *)
+{
+  tree function = (tree) function_in;
+
+  // Do nothing if we're not in gdb.
+  if (current_context == NULL)
+    return;
+
+  walk_tree (&DECL_SAVED_TREE (function), address_rewriter, current_context,
+	     NULL);
+}
+
+
+
+static inline tree
+safe_push_template_decl (tree decl)
+{
+  void (*save_oracle) (enum cp_oracle_request, tree identifier);
+
+  save_oracle = cp_binding_oracle;
+  cp_binding_oracle = NULL;
+
+  tree ret = push_template_decl (decl);
+
+  cp_binding_oracle = save_oracle;
+
+  return ret;
+}
+
+static inline tree
+safe_pushtag (tree name, tree type, tag_scope scope)
+{
+  void (*save_oracle) (enum cp_oracle_request, tree identifier);
+
+  save_oracle = cp_binding_oracle;
+  cp_binding_oracle = NULL;
+
+  tree ret = pushtag (name, type, scope);
+
+  cp_binding_oracle = save_oracle;
+
+  return ret;
+}
+
+static inline tree
+safe_pushdecl_maybe_friend (tree decl, bool is_friend)
+{
+  void (*save_oracle) (enum cp_oracle_request, tree identifier);
+
+  save_oracle = cp_binding_oracle;
+  cp_binding_oracle = NULL;
+
+  tree ret = pushdecl_maybe_friend (decl, is_friend);
+
+  cp_binding_oracle = save_oracle;
+
+  return ret;
+}
+
+
+
+int
+plugin_push_namespace (cc1_plugin::connection *,
+		       const char *name)
+{
+  if (name && !*name)
+    push_to_top_level ();
+  else
+    push_namespace (name ? get_identifier (name) : NULL);
+
+  return 1;
+}
+
+int
+plugin_push_class (cc1_plugin::connection *,
+		   gcc_type type_in)
+{
+  tree type = convert_in (type_in);
+  gcc_assert (RECORD_OR_UNION_CODE_P (TREE_CODE (type)));
+  gcc_assert (TYPE_CONTEXT (type) == FROB_CONTEXT (current_scope ()));
+
+  pushclass (type);
+
+  return 1;
+}
+
+int
+plugin_push_function (cc1_plugin::connection *,
+		      gcc_decl function_decl_in)
+{
+  tree fndecl = convert_in (function_decl_in);
+  gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
+  gcc_assert (DECL_CONTEXT (fndecl) == FROB_CONTEXT (current_scope ()));
+
+  push_fake_function (fndecl);
+
+  return 1;
+}
+
+int
+plugin_pop_binding_level (cc1_plugin::connection *)
+{
+  pop_scope ();
+  return 1;
+}
+
+int
+plugin_reactivate_decl (cc1_plugin::connection *,
+			gcc_decl decl_in,
+			gcc_decl scope_in)
+{
+  tree decl = convert_in (decl_in);
+  tree scope = convert_in (scope_in);
+  gcc_assert (TREE_CODE (decl) == VAR_DECL
+	      || TREE_CODE (decl) == FUNCTION_DECL
+	      || TREE_CODE (decl) == TYPE_DECL);
+  cp_binding_level *b;
+  if (scope)
+    {
+      gcc_assert (TREE_CODE (scope) == FUNCTION_DECL);
+      for (b = current_binding_level;
+	   b->this_entity != scope;
+	   b = b->level_chain)
+	gcc_assert (b->this_entity != global_namespace);
+    }
+  else
+    {
+      gcc_assert (!at_class_scope_p ());
+      b = current_binding_level;
+    }
+
+  reactivate_decl (decl, b);
+  return 1;
+}
+
+static tree
+get_current_scope ()
+{
+  tree decl;
+
+  if (at_namespace_scope_p ())
+    decl = current_namespace;
+  else if (at_class_scope_p ())
+    decl = TYPE_NAME (current_class_type);
+  else if (at_fake_function_scope_p () || at_function_scope_p ())
+    decl = current_function_decl;
+  else
+    gcc_unreachable ();
+
+  return decl;
+}
+
+gcc_decl
+plugin_get_current_binding_level_decl (cc1_plugin::connection *)
+{
+  tree decl = get_current_scope ();
+
+  return convert_out (decl);
+}
+
+int
+plugin_make_namespace_inline (cc1_plugin::connection *)
+{
+  tree inline_ns = current_namespace;
+
+  gcc_assert (toplevel_bindings_p ());
+  gcc_assert (inline_ns != global_namespace);
+
+  tree parent_ns = CP_DECL_CONTEXT (inline_ns);
+
+  if (purpose_member (DECL_NAMESPACE_ASSOCIATIONS (inline_ns),
+		      parent_ns))
+    return 0;
+
+  pop_namespace ();
+
+  gcc_assert (current_namespace == parent_ns);
+
+  DECL_NAMESPACE_ASSOCIATIONS (inline_ns)
+    = tree_cons (parent_ns, 0,
+		 DECL_NAMESPACE_ASSOCIATIONS (inline_ns));
+  do_using_directive (inline_ns);
+
+  push_namespace (DECL_NAME (inline_ns));
+
+  return 1;
+}
+
+int
+plugin_add_using_namespace (cc1_plugin::connection *,
+			    gcc_decl used_ns_in)
+{
+  tree used_ns = convert_in (used_ns_in);
+
+  gcc_assert (TREE_CODE (used_ns) == NAMESPACE_DECL);
+
+  do_using_directive (used_ns);
+
+  return 1;
+}
+
+int
+plugin_add_namespace_alias (cc1_plugin::connection *,
+			    const char *id,
+			    gcc_decl target_in)
+{
+  tree name = get_identifier (id);
+  tree target = convert_in (target_in);
+
+  do_namespace_alias (name, target);
+
+  return 1;
+}
+
+static inline void
+set_access_flags (tree decl, enum gcc_cp_symbol_kind flags)
+{
+  gcc_assert (!(flags & GCC_CP_ACCESS_MASK) == !DECL_CLASS_SCOPE_P (decl));
+
+  switch (flags & GCC_CP_ACCESS_MASK)
+    {
+    case GCC_CP_ACCESS_PRIVATE:
+      TREE_PRIVATE (decl) = true;
+      current_access_specifier = access_private_node;
+      break;
+
+    case GCC_CP_ACCESS_PROTECTED:
+      TREE_PROTECTED (decl) = true;
+      current_access_specifier = access_protected_node;
+      break;
+
+    case GCC_CP_ACCESS_PUBLIC:
+      current_access_specifier = access_public_node;
+      break;
+
+    default:
+      break;
+    }
+}
+
+int
+plugin_add_using_decl (cc1_plugin::connection *,
+		       enum gcc_cp_symbol_kind flags,
+		       gcc_decl target_in)
+{
+  tree target = convert_in (target_in);
+  gcc_assert ((flags & GCC_CP_SYMBOL_MASK) == GCC_CP_SYMBOL_USING);
+  gcc_assert (!(flags & GCC_CP_FLAG_MASK));
+  enum gcc_cp_symbol_kind acc_flags;
+  acc_flags = (enum gcc_cp_symbol_kind) (flags & GCC_CP_ACCESS_MASK);
+
+  gcc_assert (!template_parm_scope_p ());
+
+  bool class_member_p = at_class_scope_p ();
+  gcc_assert (!(acc_flags & GCC_CP_ACCESS_MASK) == !class_member_p);
+
+  tree identifier = DECL_NAME (target);
+  tree tcontext = DECL_CONTEXT (target);
+
+  if (UNSCOPED_ENUM_P (tcontext))
+    tcontext = CP_TYPE_CONTEXT (tcontext);
+
+  if (class_member_p)
+    {
+      tree decl = do_class_using_decl (tcontext, identifier);
+
+      set_access_flags (decl, flags);
+
+      finish_member_declaration (decl);
+    }
+  else if (!at_namespace_scope_p ())
+    {
+      gcc_unreachable ();
+      do_local_using_decl (target, tcontext, identifier);
+    }
+  else
+    do_toplevel_using_decl (target, tcontext, identifier);
+
+  return 1;
+}
+
+static tree
+build_named_class_type (enum tree_code code,
+			tree id,
+			source_location loc)
+{
+  /* See at_fake_function_scope_p.  */
+  gcc_assert (!at_function_scope_p ());
+  tree type = make_class_type (code);
+  tree type_decl = build_decl (loc, TYPE_DECL, id, type);
+  TYPE_NAME (type) = type_decl;
+  TYPE_STUB_DECL (type) = type_decl;
+  DECL_CONTEXT (type_decl) = TYPE_CONTEXT (type);
+
+  return type_decl;
+}
+
+/* Abuse an unused field of the dummy template parms entry to hold the
+   parm list.  */
+#define TP_PARM_LIST TREE_TYPE (current_template_parms)
+
+gcc_decl
+plugin_build_decl (cc1_plugin::connection *self,
+		   const char *name,
+		   enum gcc_cp_symbol_kind sym_kind,
+		   gcc_type sym_type_in,
+		   const char *substitution_name,
+		   gcc_address address,
+		   const char *filename,
+		   unsigned int line_number)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  gcc_assert (!name || !strchr (name, ':')); // FIXME: this can go eventually.
+
+  enum tree_code code;
+  tree decl;
+  tree sym_type = convert_in (sym_type_in);
+  enum gcc_cp_symbol_kind sym_flags;
+  sym_flags = (enum gcc_cp_symbol_kind) (sym_kind & GCC_CP_FLAG_MASK);
+  enum gcc_cp_symbol_kind acc_flags;
+  acc_flags = (enum gcc_cp_symbol_kind) (sym_kind & GCC_CP_ACCESS_MASK);
+  sym_kind = (enum gcc_cp_symbol_kind) (sym_kind & GCC_CP_SYMBOL_MASK);
+
+  switch (sym_kind)
+    {
+    case GCC_CP_SYMBOL_FUNCTION:
+      code = FUNCTION_DECL;
+      gcc_assert (!(sym_flags & ~GCC_CP_FLAG_MASK_FUNCTION));
+      break;
+
+    case GCC_CP_SYMBOL_VARIABLE:
+      code = VAR_DECL;
+      gcc_assert (!(sym_flags & ~GCC_CP_FLAG_MASK_VARIABLE));
+      break;
+
+    case GCC_CP_SYMBOL_TYPEDEF:
+      code = TYPE_DECL;
+      gcc_assert (!sym_flags);
+      break;
+
+    case GCC_CP_SYMBOL_CLASS:
+      code = RECORD_TYPE;
+      gcc_assert (!(sym_flags & ~GCC_CP_FLAG_MASK_CLASS));
+      gcc_assert (!sym_type);
+      break;
+
+    case GCC_CP_SYMBOL_UNION:
+      code = UNION_TYPE;
+      gcc_assert (!sym_flags);
+      gcc_assert (!sym_type);
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  bool template_decl_p = template_parm_scope_p ();
+
+  if (template_decl_p)
+    {
+      gcc_assert (code == FUNCTION_DECL || code == RECORD_TYPE
+		  || code == TYPE_DECL);
+
+      /* Finish the template parm list that started this template parm.  */
+      end_template_parm_list (TP_PARM_LIST);
+
+      gcc_assert (!address);
+      gcc_assert (!substitution_name);
+    }
+
+  source_location loc = ctx->get_source_location (filename, line_number);
+  bool class_member_p = at_class_scope_p ();
+  bool ctor = false, dtor = false, assop = false;
+  tree_code opcode = ERROR_MARK;
+
+  gcc_assert (!(acc_flags & GCC_CP_ACCESS_MASK) == !class_member_p);
+
+  tree identifier;
+  if (code != FUNCTION_DECL
+      || !(sym_flags & GCC_CP_FLAG_SPECIAL_FUNCTION))
+    {
+      if (name)
+	identifier = get_identifier (name);
+      else
+	{
+	  gcc_assert (RECORD_OR_UNION_CODE_P (code));
+	  identifier = make_anon_name ();
+	}
+    }
+
+  if (code == FUNCTION_DECL)
+    {
+      if (sym_flags & GCC_CP_FLAG_SPECIAL_FUNCTION)
+	{
+#define CHARS2(f,s) (((unsigned char)f << CHAR_BIT) | (unsigned char)s)
+	  switch (CHARS2 (name[0], name[1]))
+	    {
+	    case CHARS2 ('C', 0x0): // ctor base declaration
+	    case CHARS2 ('C', ' '):
+	    case CHARS2 ('C', '1'):
+	    case CHARS2 ('C', '2'):
+	    case CHARS2 ('C', '4'):
+	      ctor = true;
+	    cdtor:
+	      gcc_assert (!address);
+	      gcc_assert (!substitution_name);
+	      identifier = DECL_NAME (TYPE_NAME (current_class_type));
+	      break;
+	    case CHARS2 ('D', 0x0): // dtor base declaration
+	    case CHARS2 ('D', ' '):
+	    case CHARS2 ('D', '0'):
+	    case CHARS2 ('D', '1'):
+	    case CHARS2 ('D', '2'):
+	    case CHARS2 ('D', '4'):
+	      gcc_assert (!template_decl_p);
+	      dtor = true;
+	      goto cdtor;
+	    case CHARS2 ('n', 'w'): // operator new
+	      opcode = NEW_EXPR;
+	      break;
+	    case CHARS2 ('n', 'a'): // operator new[]
+	      opcode = VEC_NEW_EXPR;
+	      break;
+	    case CHARS2 ('d', 'l'): // operator delete
+	      opcode = DELETE_EXPR;
+	      break;
+	    case CHARS2 ('d', 'a'): // operator delete[]
+	      opcode = VEC_DELETE_EXPR;
+	      break;
+	    case CHARS2 ('p', 's'): // operator + (unary)
+	      opcode = PLUS_EXPR;
+	      break;
+	    case CHARS2 ('n', 'g'): // operator - (unary)
+	      opcode = MINUS_EXPR;
+	      break;
+	    case CHARS2 ('a', 'd'): // operator & (unary)
+	      opcode = BIT_AND_EXPR;
+	      break;
+	    case CHARS2 ('d', 'e'): // operator * (unary)
+	      opcode = MULT_EXPR;
+	      break;
+	    case CHARS2 ('c', 'o'): // operator ~
+	      opcode = BIT_NOT_EXPR;
+	      break;
+	    case CHARS2 ('p', 'l'): // operator +
+	      opcode = PLUS_EXPR;
+	      break;
+	    case CHARS2 ('m', 'i'): // operator -
+	      opcode = MINUS_EXPR;
+	      break;
+	    case CHARS2 ('m', 'l'): // operator *
+	      opcode = MULT_EXPR;
+	      break;
+	    case CHARS2 ('d', 'v'): // operator /
+	      opcode = TRUNC_DIV_EXPR;
+	      break;
+	    case CHARS2 ('r', 'm'): // operator %
+	      opcode = TRUNC_MOD_EXPR;
+	      break;
+	    case CHARS2 ('a', 'n'): // operator &
+	      opcode = BIT_AND_EXPR;
+	      break;
+	    case CHARS2 ('o', 'r'): // operator |
+	      opcode = BIT_IOR_EXPR;
+	      break;
+	    case CHARS2 ('e', 'o'): // operator ^
+	      opcode = BIT_XOR_EXPR;
+	      break;
+	    case CHARS2 ('a', 'S'): // operator =
+	      opcode = NOP_EXPR;
+	      assop = true;
+	      break;
+	    case CHARS2 ('p', 'L'): // operator +=
+	      opcode = PLUS_EXPR;
+	      assop = true;
+	      break;
+	    case CHARS2 ('m', 'I'): // operator -=
+	      opcode = MINUS_EXPR;
+	      assop = true;
+	      break;
+	    case CHARS2 ('m', 'L'): // operator *=
+	      opcode = MULT_EXPR;
+	      assop = true;
+	      break;
+	    case CHARS2 ('d', 'V'): // operator /=
+	      opcode = TRUNC_DIV_EXPR;
+	      assop = true;
+	      break;
+	    case CHARS2 ('r', 'M'): // operator %=
+	      opcode = TRUNC_MOD_EXPR;
+	      assop = true;
+	      break;
+	    case CHARS2 ('a', 'N'): // operator &=
+	      opcode = BIT_AND_EXPR;
+	      assop = true;
+	      break;
+	    case CHARS2 ('o', 'R'): // operator |=
+	      opcode = BIT_IOR_EXPR;
+	      assop = true;
+	      break;
+	    case CHARS2 ('e', 'O'): // operator ^=
+	      opcode = BIT_XOR_EXPR;
+	      assop = true;
+	      break;
+	    case CHARS2 ('l', 's'): // operator <<
+	      opcode = LSHIFT_EXPR;
+	      break;
+	    case CHARS2 ('r', 's'): // operator >>
+	      opcode = RSHIFT_EXPR;
+	      break;
+	    case CHARS2 ('l', 'S'): // operator <<=
+	      opcode = LSHIFT_EXPR;
+	      assop = true;
+	      break;
+	    case CHARS2 ('r', 'S'): // operator >>=
+	      opcode = RSHIFT_EXPR;
+	      assop = true;
+	      break;
+	    case CHARS2 ('e', 'q'): // operator ==
+	      opcode = EQ_EXPR;
+	      break;
+	    case CHARS2 ('n', 'e'): // operator !=
+	      opcode = NE_EXPR;
+	      break;
+	    case CHARS2 ('l', 't'): // operator <
+	      opcode = LT_EXPR;
+	      break;
+	    case CHARS2 ('g', 't'): // operator >
+	      opcode = GT_EXPR;
+	      break;
+	    case CHARS2 ('l', 'e'): // operator <=
+	      opcode = LE_EXPR;
+	      break;
+	    case CHARS2 ('g', 'e'): // operator >=
+	      opcode = GE_EXPR;
+	      break;
+	    case CHARS2 ('n', 't'): // operator !
+	      opcode = TRUTH_NOT_EXPR;
+	      break;
+	    case CHARS2 ('a', 'a'): // operator &&
+	      opcode = TRUTH_ANDIF_EXPR;
+	      break;
+	    case CHARS2 ('o', 'o'): // operator ||
+	      opcode = TRUTH_ORIF_EXPR;
+	      break;
+	    case CHARS2 ('p', 'p'): // operator ++
+	      opcode = POSTINCREMENT_EXPR;
+	      break;
+	    case CHARS2 ('m', 'm'): // operator --
+	      /* This stands for either one as an operator name, and
+		 "pp" and "mm" stand for POST??CREMENT, but for some
+		 reason the parser uses this opcode name for
+		 operator--; let's follow their practice.  */
+	      opcode = PREDECREMENT_EXPR;
+	      break;
+	    case CHARS2 ('c', 'm'): // operator ,
+	      opcode = COMPOUND_EXPR;
+	      break;
+	    case CHARS2 ('p', 'm'): // operator ->*
+	      opcode = MEMBER_REF;
+	      break;
+	    case CHARS2 ('p', 't'): // operator ->
+	      opcode = COMPONENT_REF;
+	      break;
+	    case CHARS2 ('c', 'l'): // operator ()
+	      opcode = CALL_EXPR;
+	      break;
+	    case CHARS2 ('i', 'x'): // operator []
+	      opcode = ARRAY_REF;
+	      break;
+	    case CHARS2 ('c', 'v'): // operator <T> (conversion operator)
+	      identifier = mangle_conv_op_name_for_type (TREE_TYPE (sym_type));
+	      break;
+	      // C++11-only:
+	    case CHARS2 ('l', 'i'): // operator "" <id>
+	      {
+		char *id = (char *)name + 2;
+		bool freeid = false;
+		if (*id >= '0' && *id <= '9')
+		  {
+		    unsigned len = 0;
+		    do
+		      {
+			len *= 10;
+			len += id[0] - '0';
+			id++;
+		      }
+		    while (*id && *id >= '0' && *id <= '9');
+		    id = xstrndup (id, len);
+		    freeid = true;
+		  }
+		identifier = cp_literal_operator_id (id);
+		if (freeid)
+		  free (id);
+	      }
+	      break;
+	    case CHARS2 ('q', 'u'): // ternary operator, not overloadable.
+	    default:
+	      gcc_unreachable ();
+	    }
+
+	  if (opcode != ERROR_MARK)
+	    {
+	      if (assop)
+		identifier = cp_assignment_operator_id (opcode);
+	      else
+		identifier = cp_operator_id (opcode);
+	    }
+	}
+      decl = build_lang_decl_loc (loc, code, identifier, sym_type);
+      /* FIXME: current_lang_name is lang_name_c while compiling an
+	 extern "C" function, and we haven't switched to a global
+	 context at this point, and this breaks function
+	 overloading.  */
+      SET_DECL_LANGUAGE (decl, lang_cplusplus);
+      if (TREE_CODE (sym_type) == METHOD_TYPE)
+	DECL_ARGUMENTS (decl) = build_this_parm (current_class_type,
+						 cp_type_quals (sym_type));
+      for (tree arg = TREE_CODE (sym_type) == METHOD_TYPE
+	     ? TREE_CHAIN (TYPE_ARG_TYPES (sym_type))
+	     : TYPE_ARG_TYPES (sym_type);
+	   arg && arg != void_list_node;
+	   arg = TREE_CHAIN (arg))
+	{
+	  tree parm = cp_build_parm_decl (NULL_TREE, TREE_VALUE (arg));
+	  DECL_CHAIN (parm) = DECL_ARGUMENTS (decl);
+	  DECL_ARGUMENTS (decl) = parm;
+	}
+      DECL_ARGUMENTS (decl) = nreverse (DECL_ARGUMENTS (decl));
+      if (class_member_p)
+	{
+	  if (TREE_CODE (sym_type) == FUNCTION_TYPE)
+	    DECL_STATIC_FUNCTION_P (decl) = 1;
+	  if (sym_flags & GCC_CP_FLAG_VIRTUAL_FUNCTION)
+	    {
+	      DECL_VIRTUAL_P (decl) = 1;
+	      if (sym_flags & GCC_CP_FLAG_PURE_VIRTUAL_FUNCTION)
+		DECL_PURE_VIRTUAL_P (decl) = 1;
+	      if (sym_flags & GCC_CP_FLAG_FINAL_VIRTUAL_FUNCTION)
+		DECL_FINAL_P (decl) = 1;
+	    }
+	  else
+	    gcc_assert (!(sym_flags & (GCC_CP_FLAG_PURE_VIRTUAL_FUNCTION
+				       | GCC_CP_FLAG_FINAL_VIRTUAL_FUNCTION)));
+	}
+      else
+	{
+	  gcc_assert (!(sym_flags & (GCC_CP_FLAG_VIRTUAL_FUNCTION
+				     | GCC_CP_FLAG_PURE_VIRTUAL_FUNCTION
+				     | GCC_CP_FLAG_FINAL_VIRTUAL_FUNCTION)));
+	  gcc_assert (!ctor && !dtor && !assop);
+	}
+      if (sym_flags & GCC_CP_FLAG_EXPLICIT_FUNCTION)
+	DECL_NONCONVERTING_P (decl) = 1;
+      if (sym_flags & GCC_CP_FLAG_DEFAULTED_FUNCTION)
+	{
+	  DECL_INITIAL (decl) = ridpointers[(int)RID_DEFAULT];
+	  DECL_DEFAULTED_FN (decl) = 1;
+	}
+      if (sym_flags & GCC_CP_FLAG_DELETED_FUNCTION)
+	{
+	  // DECL_INITIAL (decl) = ridpointers[(int)RID_DELETE];
+	  DECL_DELETED_FN (decl) = 1;
+	  DECL_DECLARED_INLINE_P (decl) = 1;
+	  DECL_INITIAL (decl) = error_mark_node;
+	}
+      if (ctor || dtor)
+	{
+	  if (ctor)
+	    DECL_CONSTRUCTOR_P (decl) = 1;
+	  if (dtor)
+	    DECL_DESTRUCTOR_P (decl) = 1;
+	}
+      else
+	{
+	  if ((sym_flags & GCC_CP_FLAG_SPECIAL_FUNCTION)
+	      && opcode != ERROR_MARK)
+	    SET_OVERLOADED_OPERATOR_CODE (decl, opcode);
+	  if (assop)
+	    DECL_ASSIGNMENT_OPERATOR_P (decl) = true;
+	}
+    }
+  else if (RECORD_OR_UNION_CODE_P (code))
+    {
+      decl = build_named_class_type (code, identifier, loc);
+      tree type = TREE_TYPE (decl);
+
+      if (code == RECORD_TYPE
+	  && !(sym_flags & GCC_CP_FLAG_CLASS_IS_STRUCT))
+	CLASSTYPE_DECLARED_CLASS (type) = true;
+    }
+  else if (class_member_p)
+    {
+      decl = build_lang_decl_loc (loc, code, identifier, sym_type);
+
+      if (TREE_CODE (decl) == VAR_DECL)
+	{
+	  DECL_THIS_STATIC (decl) = 1;
+	  // The remainder of this block does the same as:
+	  // set_linkage_for_static_data_member (decl);
+	  TREE_PUBLIC (decl) = 1;
+	  TREE_STATIC (decl) = 1;
+	  DECL_INTERFACE_KNOWN (decl) = 1;
+
+	  // FIXME: sym_flags & GCC_CP_FLAG_THREAD_LOCAL_VARIABLE
+	  gcc_assert (!(sym_flags & GCC_CP_FLAG_THREAD_LOCAL_VARIABLE));
+
+	  if (sym_flags & GCC_CP_FLAG_CONSTEXPR_VARIABLE)
+	    DECL_DECLARED_CONSTEXPR_P (decl) = true;
+	}
+    }
+  else
+    {
+      decl = build_decl (loc, code, identifier, sym_type);
+
+      if (TREE_CODE (decl) == VAR_DECL)
+	{
+	  // FIXME: sym_flags & GCC_CP_FLAG_THREAD_LOCAL_VARIABLE
+	  gcc_assert (!(sym_flags & GCC_CP_FLAG_THREAD_LOCAL_VARIABLE));
+
+	  if (sym_flags & GCC_CP_FLAG_CONSTEXPR_VARIABLE)
+	    DECL_DECLARED_CONSTEXPR_P (decl) = true;
+	}
+    }
+  TREE_USED (decl) = 1;
+  TREE_ADDRESSABLE (decl) = 1;
+
+  if (class_member_p)
+    DECL_CONTEXT (decl) = FROB_CONTEXT (current_class_type);
+  else if (at_namespace_scope_p ())
+    DECL_CONTEXT (decl) = FROB_CONTEXT (current_decl_namespace ());
+
+  set_access_flags (decl, acc_flags);
+
+  if (sym_kind != GCC_CP_SYMBOL_TYPEDEF
+      && sym_kind != GCC_CP_SYMBOL_CLASS
+      && sym_kind != GCC_CP_SYMBOL_UNION
+      && !template_decl_p && !ctor && !dtor)
+    {
+      decl_addr_value value;
+
+      DECL_EXTERNAL (decl) = 1;
+      value.decl = decl;
+      if (substitution_name != NULL)
+	{
+	  // If the translator gave us a name without a binding,
+	  // we can just substitute error_mark_node, since we know the
+	  // translator will be reporting an error anyhow.
+	  value.address
+	    = lookup_name (get_identifier (substitution_name));
+	  if (value.address == NULL_TREE)
+	    value.address = error_mark_node;
+	}
+      else if (address)
+	value.address = build_int_cst_type (ptr_type_node, address);
+      else
+	value.address = NULL;
+      if (value.address)
+	record_decl_address (ctx, value);
+    }
+
+  if (class_member_p && code == FUNCTION_DECL)
+    {
+      if (ctor || dtor)
+	maybe_retrofit_in_chrg (decl);
+
+      grok_special_member_properties (decl);
+    }
+
+  if (template_decl_p)
+    {
+      if (RECORD_OR_UNION_CODE_P (code))
+	safe_pushtag (identifier, TREE_TYPE (decl), ts_current);
+      else
+	decl = safe_push_template_decl (decl);
+
+      tree tdecl = NULL_TREE;
+      if (class_member_p)
+	tdecl = finish_member_template_decl (decl);
+
+      end_template_decl ();
+
+      /* We only support one level of templates, because we only
+	 support declaring generics; actual definitions are only of
+	 specializations.  */
+      gcc_assert (!template_parm_scope_p ());
+
+      if (class_member_p)
+	finish_member_declaration (tdecl);
+    }
+  else if (RECORD_OR_UNION_CODE_P (code))
+    safe_pushtag (identifier, TREE_TYPE (decl), ts_current);
+  else if (class_member_p)
+    finish_member_declaration (decl);
+  else
+    decl = safe_pushdecl_maybe_friend (decl, false);
+
+  if ((ctor || dtor)
+      /* Don't crash after a duplicate declaration of a cdtor.  */
+      && TYPE_METHODS (current_class_type) == decl)
+    {
+      /* ctors and dtors clones are chained after DECL.
+	 However, we create the clones before TYPE_METHODS is
+	 reversed.  We test for cloned methods after reversal,
+	 however, and the test requires the clones to follow
+	 DECL.  So, we reverse the chain of clones now, so
+	 that it will come out in the right order after
+	 reversal.  */
+      tree save = DECL_CHAIN (decl);
+      DECL_CHAIN (decl) = NULL_TREE;
+      clone_function_decl (decl, /*update_method_vec_p=*/1);
+      gcc_assert (TYPE_METHODS (current_class_type) == decl);
+      TYPE_METHODS (current_class_type)
+	= nreverse (TYPE_METHODS (current_class_type));
+      DECL_CHAIN (decl) = save;
+    }
+
+  rest_of_decl_compilation (decl, toplevel_bindings_p (), 0);
+
+  return convert_out (ctx->preserve (decl));
+}
+
+gcc_decl
+plugin_define_cdtor_clone (cc1_plugin::connection *self,
+			   const char *name,
+			   gcc_decl cdtor_in,
+			   gcc_address address)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree decl = convert_in (cdtor_in);
+  bool ctor = false;
+  bool dtor = false;
+  tree identifier;
+
+  switch (CHARS2 (name[0], name[1]))
+    {
+    case CHARS2 ('C', '1'): // in-charge constructor
+      identifier = complete_ctor_identifier;
+      ctor = true;
+      break;
+    case CHARS2 ('C', '2'): // not-in-charge constructor
+      identifier = base_ctor_identifier;
+      ctor = true;
+      break;
+    case CHARS2 ('C', '4'):
+      identifier = ctor_identifier; // unified constructor
+      ctor = true;
+      break;
+    case CHARS2 ('D', '0'): // deleting destructor
+      identifier = deleting_dtor_identifier;
+      dtor = true;
+      break;
+    case CHARS2 ('D', '1'): // in-charge destructor
+      identifier = complete_dtor_identifier;
+      dtor = true;
+      break;
+    case CHARS2 ('D', '2'): // not-in-charge destructor
+      identifier = base_dtor_identifier;
+      dtor = true;
+      break;
+    case CHARS2 ('D', '4'):
+      identifier = dtor_identifier; // unified destructor
+      dtor = true;
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  gcc_assert (!ctor != !dtor);
+  gcc_assert (ctor
+	      ? (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)
+		 && DECL_NAME (decl) == ctor_identifier)
+	      : (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl)
+		 && DECL_NAME (decl) == dtor_identifier));
+
+  while (decl && DECL_NAME (decl) != identifier)
+    {
+      decl = DECL_CHAIN (decl);
+      if (decl && !DECL_CLONED_FUNCTION_P (decl))
+	decl = NULL_TREE;
+    }
+  gcc_assert (decl);
+
+  record_decl_address (ctx, build_decl_addr_value (decl, address));
+
+  return convert_out (decl);
+}
+
+int
+plugin_add_friend (cc1_plugin::connection * /* self */,
+		   gcc_decl decl_in,
+		   gcc_type type_in)
+{
+  tree decl = convert_in (decl_in);
+  tree type = convert_in (type_in);
+
+  gcc_assert (type || at_class_scope_p ());
+
+  if (!type)
+    type = current_class_type;
+  else
+    gcc_assert (TREE_CODE (type) == RECORD_TYPE);
+
+  if (TYPE_P (decl))
+    make_friend_class (type, TREE_TYPE (decl), true);
+  else
+    {
+      DECL_FRIEND_P (decl) = true;
+      add_friend (type, decl, true);
+    }
+
+  return 1;
+}
+
+gcc_type
+plugin_build_pointer_type (cc1_plugin::connection *,
+			   gcc_type base_type)
+{
+  // No need to preserve a pointer type as the base type is preserved.
+  return convert_out (build_pointer_type (convert_in (base_type)));
+}
+
+gcc_type
+plugin_build_reference_type (cc1_plugin::connection *,
+			     gcc_type base_type_in,
+			     enum gcc_cp_ref_qualifiers rquals)
+{
+  bool rval;
+
+  switch (rquals)
+    {
+    case GCC_CP_REF_QUAL_LVALUE:
+      rval = false;
+      break;
+    case GCC_CP_REF_QUAL_RVALUE:
+      rval = true;
+      break;
+    case GCC_CP_REF_QUAL_NONE:
+    default:
+      gcc_unreachable ();
+    }
+
+  tree rtype = cp_build_reference_type (convert_in (base_type_in), rval);
+
+  return convert_out (rtype);
+}
+
+static tree
+start_class_def (tree type,
+		 const gcc_vbase_array *base_classes)
+{
+  tree bases = NULL;
+  if (base_classes)
+    {
+      for (int i = 0; i < base_classes->n_elements; i++)
+	{
+	  tree access;
+
+	  gcc_assert ((base_classes->flags[i] & GCC_CP_SYMBOL_MASK)
+		      == GCC_CP_SYMBOL_BASECLASS);
+
+	  switch (base_classes->flags[i] & GCC_CP_ACCESS_MASK)
+	    {
+	    case GCC_CP_ACCESS_PRIVATE:
+	      access = ridpointers[(int)RID_PRIVATE];
+	      break;
+
+	    case GCC_CP_ACCESS_PROTECTED:
+	      access = ridpointers[(int)RID_PROTECTED];
+	      break;
+
+	    case GCC_CP_ACCESS_PUBLIC:
+	      access = ridpointers[(int)RID_PUBLIC];
+	      break;
+
+	    default:
+	      gcc_unreachable ();
+	    }
+
+	  tree base = finish_base_specifier
+	    (convert_in (base_classes->elements[i]), access,
+	     (base_classes->flags[i] & GCC_CP_FLAG_BASECLASS_VIRTUAL) != 0);
+	  TREE_CHAIN (base) = bases;
+	  bases = base;
+	}
+      bases = nreverse (bases);
+    }
+  xref_basetypes (type, bases);
+  begin_class_definition (type);
+  return type;
+}
+
+gcc_type
+plugin_start_class_type (cc1_plugin::connection *self,
+			 gcc_decl typedecl_in,
+			 const gcc_vbase_array *base_classes,
+			 const char *filename,
+			 unsigned int line_number)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  source_location loc = ctx->get_source_location (filename, line_number);
+  tree typedecl = convert_in (typedecl_in);
+  tree type = TREE_TYPE (typedecl);
+
+  gcc_assert (RECORD_OR_UNION_CODE_P (TREE_CODE (type)));
+  gcc_assert (!COMPLETE_TYPE_P (type));
+
+  DECL_SOURCE_LOCATION (typedecl) = loc;
+
+  tree result = start_class_def (type, base_classes);
+
+  return convert_out (ctx->preserve (result));
+}
+
+gcc_type
+plugin_start_closure_class_type (cc1_plugin::connection *self,
+				 int discriminator,
+				 gcc_decl extra_scope_in,
+				 enum gcc_cp_symbol_kind flags,
+				 const char *filename,
+				 unsigned int line_number)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree extra_scope = convert_in (extra_scope_in);
+
+  gcc_assert ((flags & GCC_CP_SYMBOL_MASK) == GCC_CP_SYMBOL_LAMBDA_CLOSURE);
+  gcc_assert ((flags & (~(GCC_CP_SYMBOL_MASK | GCC_CP_ACCESS_MASK))) == 0);
+
+  gcc_assert (!(flags & GCC_CP_ACCESS_MASK) == !at_class_scope_p ());
+
+  /* See at_fake_function_scope_p.  */
+  gcc_assert (!at_function_scope_p ());
+
+  if (extra_scope)
+    {
+      if (TREE_CODE (extra_scope) == PARM_DECL)
+	{
+	  gcc_assert (at_fake_function_scope_p ());
+	  /* Check that the given extra_scope is one of the parameters of
+	     the current function.  */
+	  for (tree parm = DECL_ARGUMENTS (current_function_decl);
+	       ; parm = DECL_CHAIN (parm))
+	    {
+	      gcc_assert (parm);
+	      if (parm == extra_scope)
+		break;
+	    }
+	}
+      else if (TREE_CODE (extra_scope) == FIELD_DECL)
+	{
+	  gcc_assert (at_class_scope_p ());
+	  gcc_assert (DECL_CONTEXT (extra_scope) == current_class_type);
+	}
+      else
+	/* FIXME: does this ever really occur?  */
+	gcc_assert (TREE_CODE (extra_scope) == VAR_DECL);
+    }
+
+  tree lambda_expr = build_lambda_expr ();
+
+  LAMBDA_EXPR_LOCATION (lambda_expr) = ctx->get_source_location (filename,
+								 line_number);
+
+  tree type = begin_lambda_type (lambda_expr);
+
+  /* Instead of calling record_lambda_scope, do this:  */
+  LAMBDA_EXPR_EXTRA_SCOPE (lambda_expr) = extra_scope;
+  LAMBDA_EXPR_DISCRIMINATOR (lambda_expr) = discriminator;
+
+  tree decl = TYPE_NAME (type);
+  determine_visibility (decl);
+  set_access_flags (decl, flags);
+
+  return convert_out (ctx->preserve (type));
+}
+
+gcc_expr
+plugin_build_lambda_expr (cc1_plugin::connection *self,
+			  gcc_type closure_type_in)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree closure_type = convert_in (closure_type_in);
+
+  gcc_assert (LAMBDA_TYPE_P (closure_type));
+
+  tree lambda_expr = CLASSTYPE_LAMBDA_EXPR (closure_type);
+
+  tree lambda_object = build_lambda_object (lambda_expr);
+
+  return convert_out (ctx->preserve (lambda_object));
+}
+
+gcc_decl
+plugin_build_field (cc1_plugin::connection *,
+		    const char *field_name,
+		    gcc_type field_type_in,
+		    enum gcc_cp_symbol_kind flags,
+		    unsigned long bitsize,
+		    unsigned long bitpos)
+{
+  tree record_or_union_type = current_class_type;
+  tree field_type = convert_in (field_type_in);
+
+  gcc_assert (at_class_scope_p ());
+  gcc_assert (RECORD_OR_UNION_CODE_P (TREE_CODE (record_or_union_type)));
+  gcc_assert ((flags & GCC_CP_SYMBOL_MASK) == GCC_CP_SYMBOL_FIELD);
+  gcc_assert ((flags & (~(GCC_CP_SYMBOL_MASK | GCC_CP_ACCESS_MASK
+			  | GCC_CP_FLAG_MASK_FIELD))) == 0);
+  gcc_assert ((flags & GCC_CP_ACCESS_MASK));
+
+  /* Note that gdb does not preserve the location of field decls, so
+     we can't provide a decent location here.  */
+  tree decl = build_decl (BUILTINS_LOCATION, FIELD_DECL,
+			  get_identifier (field_name), field_type);
+  DECL_FIELD_CONTEXT (decl) = record_or_union_type;
+
+  set_access_flags (decl, flags);
+
+  if ((flags & GCC_CP_FLAG_FIELD_MUTABLE) != 0)
+    DECL_MUTABLE_P (decl) = 1;
+
+  if (TREE_CODE (field_type) == INTEGER_TYPE
+      && TYPE_PRECISION (field_type) != bitsize)
+    {
+      DECL_BIT_FIELD_TYPE (decl) = field_type;
+      TREE_TYPE (decl)
+	= c_build_bitfield_integer_type (bitsize, TYPE_UNSIGNED (field_type));
+    }
+
+  DECL_MODE (decl) = TYPE_MODE (TREE_TYPE (decl));
+
+  // There's no way to recover this from DWARF.
+  SET_DECL_OFFSET_ALIGN (decl, TYPE_PRECISION (pointer_sized_int_node));
+
+  tree pos = bitsize_int (bitpos);
+  pos_from_bit (&DECL_FIELD_OFFSET (decl), &DECL_FIELD_BIT_OFFSET (decl),
+		DECL_OFFSET_ALIGN (decl), pos);
+
+  DECL_SIZE (decl) = bitsize_int (bitsize);
+  DECL_SIZE_UNIT (decl) = size_int ((bitsize + BITS_PER_UNIT - 1)
+				    / BITS_PER_UNIT);
+
+  DECL_CHAIN (decl) = TYPE_FIELDS (record_or_union_type);
+  TYPE_FIELDS (record_or_union_type) = decl;
+
+  return convert_out (decl);
+}
+
+int
+plugin_finish_class_type (cc1_plugin::connection *,
+			  unsigned long size_in_bytes)
+{
+  tree record_or_union_type = current_class_type;
+
+  gcc_assert (RECORD_OR_UNION_CODE_P (TREE_CODE (record_or_union_type)));
+
+  finish_struct (record_or_union_type, NULL);
+
+  gcc_assert (compare_tree_int (TYPE_SIZE_UNIT (record_or_union_type),
+				size_in_bytes) == 0);
+
+  return 1;
+}
+
+gcc_type
+plugin_start_enum_type (cc1_plugin::connection *self,
+			const char *name,
+			gcc_type underlying_int_type_in,
+			enum gcc_cp_symbol_kind flags,
+			const char *filename,
+			unsigned int line_number)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree underlying_int_type = convert_in (underlying_int_type_in);
+
+  gcc_assert ((flags & GCC_CP_SYMBOL_MASK) == GCC_CP_SYMBOL_ENUM);
+  gcc_assert ((flags & (~(GCC_CP_SYMBOL_MASK | GCC_CP_ACCESS_MASK
+			  | GCC_CP_FLAG_MASK_ENUM))) == 0);
+  gcc_assert (!(flags & GCC_CP_ACCESS_MASK) == !at_class_scope_p ());
+
+  if (underlying_int_type == error_mark_node)
+    return convert_out (error_mark_node);
+
+  bool is_new_type = false;
+
+  tree id = name ? get_identifier (name) : make_anon_name ();
+
+  tree type = start_enum (id, NULL_TREE,
+			  underlying_int_type,
+			  /* attributes = */ NULL_TREE,
+			  !!(flags & GCC_CP_FLAG_ENUM_SCOPED), &is_new_type);
+
+  gcc_assert (is_new_type);
+
+  source_location loc = ctx->get_source_location (filename, line_number);
+  tree type_decl = TYPE_NAME (type);
+  DECL_SOURCE_LOCATION (type_decl) = loc;
+  SET_OPAQUE_ENUM_P (type, false);
+
+  set_access_flags (type_decl, flags);
+
+  return convert_out (ctx->preserve (type));
+}
+
+gcc_decl
+plugin_build_enum_constant (cc1_plugin::connection *,
+			    gcc_type enum_type_in,
+			    const char *name,
+			    unsigned long value)
+{
+  tree enum_type = convert_in (enum_type_in);
+
+  gcc_assert (TREE_CODE (enum_type) == ENUMERAL_TYPE);
+
+  build_enumerator (get_identifier (name), build_int_cst (enum_type, value),
+		    enum_type, NULL_TREE, BUILTINS_LOCATION);
+
+  return convert_out (TREE_VALUE (TYPE_VALUES (enum_type)));
+}
+
+int
+plugin_finish_enum_type (cc1_plugin::connection *,
+			 gcc_type enum_type_in)
+{
+  tree enum_type = convert_in (enum_type_in);
+
+  finish_enum_value_list (enum_type);
+  finish_enum (enum_type);
+
+  return 1;
+}
+
+gcc_type
+plugin_build_function_type (cc1_plugin::connection *self,
+			    gcc_type return_type_in,
+			    const struct gcc_type_array *argument_types_in,
+			    int is_varargs)
+{
+  tree *argument_types;
+  tree return_type = convert_in (return_type_in);
+  tree result;
+
+  argument_types = new tree[argument_types_in->n_elements];
+  for (int i = 0; i < argument_types_in->n_elements; ++i)
+    argument_types[i] = convert_in (argument_types_in->elements[i]);
+
+  if (is_varargs)
+    result = build_varargs_function_type_array (return_type,
+						argument_types_in->n_elements,
+						argument_types);
+  else
+    result = build_function_type_array (return_type,
+					argument_types_in->n_elements,
+					argument_types);
+
+  delete[] argument_types;
+
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  return convert_out (ctx->preserve (result));
+}
+
+#if 0
+
+gcc_type
+plugin_add_function_default_args (cc1_plugin::connection *self,
+				  gcc_type function_type_in,
+				  const struct gcc_cp_function_args *defaults)
+{
+  tree function_type = convert_in (function_type_in);
+
+  gcc_assert (TREE_CODE (function_type) == FUNCTION_TYPE);
+
+  if (!defaults || !defaults->n_elements)
+    return function_type_in;
+
+  tree pargs = TYPE_ARG_TYPES (function_type);
+  tree nargs = NULL_TREE;
+
+  /* Build a reversed copy of the list of default-less arguments in
+     NARGS.  At the end of the loop, PARGS will point to the end of
+     the argument list, or to the first argument that had a default
+     value.  */
+  while (pargs && TREE_VALUE (pargs) != void_list_node
+	 && !TREE_PURPOSE (pargs))
+    {
+      nargs = tree_cons (NULL_TREE, TREE_VALUE (pargs), nargs);
+      pargs = TREE_CHAIN (pargs);
+    }
+
+  /* Set the defaults in the now-leading NARGS, taking into account
+     that NARGS is reversed but DEFAULTS->elements isn't.  */
+  tree ndargs = nargs;
+  int i = defaults->n_elements;
+  while (i--)
+    {
+      gcc_assert (ndargs);
+      tree deflt = convert_in (defaults->elements[i]);
+      if (!deflt)
+	deflt = error_mark_node;
+      TREE_PURPOSE (ndargs) = deflt;
+      ndargs = TREE_CHAIN (ndargs);
+    }
+
+  /* Finally, reverse NARGS, and append the remaining PARGS that
+     already had defaults.  */
+  nargs = nreverse (nargs);
+  nargs = chainon (nargs, pargs);
+
+  tree result = build_function_type (TREE_TYPE (function_type), nargs);
+
+  /* Copy exceptions, attributes and whatnot.  */
+  result = build_exception_variant (result,
+				    TYPE_RAISES_EXCEPTIONS (function_type));
+  result = cp_build_type_attribute_variant (result,
+					    TYPE_ATTRIBUTES (function_type));
+
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  return convert_out (ctx->preserve (result));
+}
+
+int
+plugin_set_deferred_function_default_args (cc1_plugin::connection *,
+					   gcc_decl function_in,
+					   const struct gcc_cp_function_args
+					   *defaults)
+{
+  tree function = convert_in (function_in);
+
+  gcc_assert (TREE_CODE (function) == FUNCTION_DECL);
+
+  if (!defaults || !defaults->n_elements)
+    return 1;
+
+  tree arg = FUNCTION_FIRST_USER_PARMTYPE (function);
+
+  for (int i = 0; i < defaults->n_elements; i++)
+    {
+      while (arg && TREE_PURPOSE (arg) != error_mark_node)
+	arg = TREE_CHAIN (arg);
+
+      if (!arg)
+	return 0;
+
+      TREE_PURPOSE (arg) = convert_in (defaults->elements[i]);
+      arg = TREE_CHAIN (arg);
+    }
+
+  return 1;
+}
+
+#endif
+
+gcc_decl
+plugin_get_function_parameter_decl (cc1_plugin::connection *,
+				    gcc_decl function_in,
+				    int index)
+{
+  tree function = convert_in (function_in);
+
+  gcc_assert (TREE_CODE (function) == FUNCTION_DECL);
+
+  if (index == -1)
+    {
+      gcc_assert (TREE_CODE (TREE_TYPE (function)) == METHOD_TYPE);
+
+      return convert_out (DECL_ARGUMENTS (function));
+    }
+
+  gcc_assert (index >= 0);
+
+  tree args = FUNCTION_FIRST_USER_PARM (function);
+
+  for (int i = 0; args && i < index; i++)
+    args = DECL_CHAIN (args);
+
+  return convert_out (args);
+}
+
+gcc_type
+plugin_build_exception_spec_variant (cc1_plugin::connection *self,
+				     gcc_type function_type_in,
+				     const struct gcc_type_array *except_types_in)
+{
+  tree function_type = convert_in (function_type_in);
+  tree except_types = NULL_TREE;
+
+  if (!except_types_in)
+    except_types = noexcept_false_spec;
+  else if (!except_types_in->n_elements)
+    except_types = empty_except_spec;
+  else
+    for (int i = 0; i < except_types_in->n_elements; i++)
+      except_types = add_exception_specifier (except_types,
+					      convert_in
+					      (except_types_in->elements[i]),
+					      0);
+
+  function_type = build_exception_variant (function_type,
+					   except_types);
+
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  return convert_out (ctx->preserve (function_type));
+}
+
+gcc_type
+plugin_build_method_type (cc1_plugin::connection *self,
+			  gcc_type class_type_in,
+			  gcc_type func_type_in,
+			  enum gcc_cp_qualifiers quals_in,
+			  enum gcc_cp_ref_qualifiers rquals_in)
+{
+  tree class_type = convert_in (class_type_in);
+  tree func_type = convert_in (func_type_in);
+  cp_cv_quals quals = 0;
+  cp_ref_qualifier rquals;
+
+  if ((quals_in & GCC_CP_QUALIFIER_CONST) != 0)
+    quals |= TYPE_QUAL_CONST;
+  if ((quals_in & GCC_CP_QUALIFIER_VOLATILE) != 0)
+    quals |= TYPE_QUAL_VOLATILE;
+  gcc_assert ((quals_in & GCC_CP_QUALIFIER_RESTRICT) == 0);
+
+  switch (rquals_in)
+    {
+    case GCC_CP_REF_QUAL_NONE:
+      rquals = REF_QUAL_NONE;
+      break;
+    case GCC_CP_REF_QUAL_LVALUE:
+      rquals = REF_QUAL_LVALUE;
+      break;
+    case GCC_CP_REF_QUAL_RVALUE:
+      rquals = REF_QUAL_RVALUE;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  tree method_type = class_type
+    ? build_memfn_type (func_type, class_type, quals, rquals)
+    : apply_memfn_quals (func_type, quals, rquals);
+
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  return convert_out (ctx->preserve (method_type));
+}
+
+gcc_type
+plugin_build_pointer_to_member_type (cc1_plugin::connection *self,
+				     gcc_type class_type_in,
+				     gcc_type member_type_in)
+{
+  tree class_type = convert_in (class_type_in);
+  tree member_type = convert_in (member_type_in);
+
+  tree memptr_type = build_ptrmem_type (class_type, member_type);
+
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  return convert_out (ctx->preserve (memptr_type));
+}
+
+int
+plugin_start_template_decl (cc1_plugin::connection *)
+{
+  begin_template_parm_list ();
+
+  TP_PARM_LIST = NULL_TREE;
+
+  return 1;
+}
+
+gcc_decl
+plugin_get_type_decl (cc1_plugin::connection *,
+		      gcc_type type_in)
+{
+  tree type = convert_in (type_in);
+
+  tree name = TYPE_NAME (type);
+  gcc_assert (name);
+
+  return convert_out (name);
+}
+
+gcc_type
+plugin_get_decl_type (cc1_plugin::connection *,
+		      gcc_decl decl_in)
+{
+  tree decl = convert_in (decl_in);
+
+  tree type = TREE_TYPE (decl);
+  gcc_assert (type);
+
+  return convert_out (type);
+}
+
+gcc_type
+plugin_build_type_template_parameter (cc1_plugin::connection *self,
+				      const char *id,
+				      int /* bool */ pack_p,
+				      gcc_type default_type,
+				      const char *filename,
+				      unsigned int line_number)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  source_location loc = ctx->get_source_location (filename, line_number);
+
+  gcc_assert (template_parm_scope_p ());
+
+  tree parm = finish_template_type_parm (class_type_node, get_identifier (id));
+  parm = build_tree_list (convert_in (default_type), parm);
+
+  gcc_assert (!(pack_p && default_type));
+
+  /* Create a type and a decl for the type parm, and add the decl to
+     TP_PARM_LIST.  */
+  TP_PARM_LIST = process_template_parm (TP_PARM_LIST, loc, parm,
+					/* is_non_type = */ false, pack_p);
+
+  /* Locate the decl of the newly-added, processed template parm.  */
+  parm = TREE_VALUE (tree_last (TP_PARM_LIST));
+
+  /* Return its type.  */
+  return convert_out (ctx->preserve (TREE_TYPE (parm)));
+}
+
+gcc_utempl
+plugin_build_template_template_parameter (cc1_plugin::connection *self,
+					  const char *id,
+					  int /* bool */ pack_p,
+					  gcc_utempl default_templ,
+					  const char *filename,
+					  unsigned int line_number)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  source_location loc = ctx->get_source_location (filename, line_number);
+
+  gcc_assert (template_parm_scope_p ());
+
+  /* Finish the template parm list that started this template parm.  */
+  end_template_parm_list (TP_PARM_LIST);
+
+  gcc_assert (template_parm_scope_p ());
+
+  tree parm = finish_template_template_parm (class_type_node,
+					     get_identifier (id));
+  parm = build_tree_list (convert_in (default_templ), parm);
+
+  gcc_assert (!(pack_p && default_templ));
+
+  /* Create a type and a decl for the template parm, and add the decl
+     to TP_PARM_LIST.  */
+  TP_PARM_LIST = process_template_parm (TP_PARM_LIST, loc, parm,
+					/* is_non_type = */ false, pack_p);
+
+  /* Locate the decl of the newly-added, processed template parm.  */
+  parm = TREE_VALUE (tree_last (TP_PARM_LIST));
+
+  return convert_out (ctx->preserve (parm));
+}
+
+gcc_decl
+plugin_build_value_template_parameter (cc1_plugin::connection *self,
+				       gcc_type type,
+				       const char *id,
+				       gcc_expr default_value,
+				       const char *filename,
+				       unsigned int line_number)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  source_location loc = ctx->get_source_location (filename, line_number);
+
+  gcc_assert (template_parm_scope_p ());
+
+  cp_declarator declarator;
+  memset (&declarator, 0, sizeof (declarator));
+  // &declarator = make_id_declarator (NULL, get_identifier (id), sfk_none):
+  declarator.kind = cdk_id;
+  declarator.u.id.qualifying_scope = NULL;
+  declarator.u.id.unqualified_name = get_identifier (id);
+  declarator.u.id.sfk = sfk_none;
+
+  cp_decl_specifier_seq declspec;
+  memset (&declspec, 0, sizeof (declspec));
+  // cp_parser_set_decl_spec_type (&declspec, convert_in (type), -token-, false):
+  declspec.any_specifiers_p = declspec.any_type_specifiers_p = true;
+  declspec.type = convert_in (type);
+  declspec.locations[ds_type_spec] = loc;
+
+  tree parm = grokdeclarator (&declarator, &declspec, TPARM, 0, 0);
+  parm = build_tree_list (convert_in (default_value), parm);
+
+  /* Create a type and a decl for the template parm, and add the decl
+     to TP_PARM_LIST.  */
+  TP_PARM_LIST = process_template_parm (TP_PARM_LIST, loc, parm,
+					/* is_non_type = */ true, false);
+
+  /* Locate the decl of the newly-added, processed template parm.  */
+  parm = TREE_VALUE (tree_last (TP_PARM_LIST));
+
+  return convert_out (ctx->preserve (parm));
+}
+
+static tree
+targlist (const gcc_cp_template_args *targs)
+{
+  int n = targs->n_elements;
+  tree vec = make_tree_vec (n);
+  while (n--)
+    {
+      switch (targs->kinds[n])
+	{
+	case GCC_CP_TPARG_VALUE:
+	  TREE_VEC_ELT (vec, n) = convert_in (targs->elements[n].value);
+	  break;
+	case GCC_CP_TPARG_CLASS:
+	  TREE_VEC_ELT (vec, n) = convert_in (targs->elements[n].type);
+	  break;
+	case GCC_CP_TPARG_TEMPL:
+	  TREE_VEC_ELT (vec, n) = convert_in (targs->elements[n].templ);
+	  break;
+	case GCC_CP_TPARG_PACK:
+	  TREE_VEC_ELT (vec, n) = convert_in (targs->elements[n].pack);
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+    }
+  return vec;
+}
+
+gcc_type
+plugin_build_dependent_typename (cc1_plugin::connection *self,
+				 gcc_type enclosing_type,
+				 const char *id,
+				 const gcc_cp_template_args *targs)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree type = convert_in (enclosing_type);
+  tree name = get_identifier (id);
+  if (targs)
+    name = build_min_nt_loc (/*loc=*/0, TEMPLATE_ID_EXPR,
+			     name, targlist (targs));
+  tree res = make_typename_type (type, name, typename_type,
+				 /*complain=*/tf_error);
+  return convert_out (ctx->preserve (res));
+}
+
+gcc_utempl
+plugin_build_dependent_class_template (cc1_plugin::connection *self,
+				       gcc_type enclosing_type,
+				       const char *id)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree type = convert_in (enclosing_type);
+  tree name = get_identifier (id);
+  tree res = make_unbound_class_template (type, name, NULL_TREE,
+					  /*complain=*/tf_error);
+  return convert_out (ctx->preserve (res));
+}
+
+gcc_type
+plugin_build_dependent_type_template_id (cc1_plugin::connection *self,
+					 gcc_utempl template_decl,
+					 const gcc_cp_template_args *targs)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree type = convert_in (template_decl);
+  tree decl = finish_template_type (type, targlist (targs),
+				    /*entering_scope=*/false);
+  return convert_out (ctx->preserve (TREE_TYPE (decl)));
+}
+
+gcc_expr
+plugin_build_dependent_expr (cc1_plugin::connection *self,
+			     gcc_decl enclosing_scope,
+			     enum gcc_cp_symbol_kind flags,
+			     const char *name,
+			     gcc_type conv_type_in,
+			     const gcc_cp_template_args *targs)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree scope = convert_in (enclosing_scope);
+  tree conv_type = convert_in (conv_type_in);
+  tree identifier;
+
+  if (TREE_CODE (scope) != NAMESPACE_DECL)
+    {
+      tree type = TREE_TYPE (scope);
+      gcc_assert (TYPE_NAME (type) == scope);
+      scope = type;
+    }
+
+  if (flags == (GCC_CP_SYMBOL_FUNCTION | GCC_CP_FLAG_SPECIAL_FUNCTION))
+    {
+      bool assop = false, convop = false;
+      tree_code opcode = ERROR_MARK;
+
+      switch (CHARS2 (name[0], name[1]))
+	{
+	case CHARS2 ('C', 0x0): // ctor base declaration
+	case CHARS2 ('C', ' '):
+	case CHARS2 ('C', '1'):
+	case CHARS2 ('C', '2'):
+	case CHARS2 ('C', '4'):
+	  identifier = ctor_identifier;
+	  break;
+	case CHARS2 ('D', 0x0): // dtor base declaration
+	case CHARS2 ('D', ' '):
+	case CHARS2 ('D', '0'):
+	case CHARS2 ('D', '1'):
+	case CHARS2 ('D', '2'):
+	case CHARS2 ('D', '4'):
+	  gcc_assert (!targs);
+	  identifier = dtor_identifier;
+	  break;
+	case CHARS2 ('n', 'w'): // operator new
+	  opcode = NEW_EXPR;
+	  break;
+	case CHARS2 ('n', 'a'): // operator new[]
+	  opcode = VEC_NEW_EXPR;
+	  break;
+	case CHARS2 ('d', 'l'): // operator delete
+	  opcode = DELETE_EXPR;
+	  break;
+	case CHARS2 ('d', 'a'): // operator delete[]
+	  opcode = VEC_DELETE_EXPR;
+	  break;
+	case CHARS2 ('p', 's'): // operator + (unary)
+	  opcode = PLUS_EXPR;
+	  break;
+	case CHARS2 ('n', 'g'): // operator - (unary)
+	  opcode = MINUS_EXPR;
+	  break;
+	case CHARS2 ('a', 'd'): // operator & (unary)
+	  opcode = BIT_AND_EXPR;
+	  break;
+	case CHARS2 ('d', 'e'): // operator * (unary)
+	  opcode = MULT_EXPR;
+	  break;
+	case CHARS2 ('c', 'o'): // operator ~
+	  opcode = BIT_NOT_EXPR;
+	  break;
+	case CHARS2 ('p', 'l'): // operator +
+	  opcode = PLUS_EXPR;
+	  break;
+	case CHARS2 ('m', 'i'): // operator -
+	  opcode = MINUS_EXPR;
+	  break;
+	case CHARS2 ('m', 'l'): // operator *
+	  opcode = MULT_EXPR;
+	  break;
+	case CHARS2 ('d', 'v'): // operator /
+	  opcode = TRUNC_DIV_EXPR;
+	  break;
+	case CHARS2 ('r', 'm'): // operator %
+	  opcode = TRUNC_MOD_EXPR;
+	  break;
+	case CHARS2 ('a', 'n'): // operator &
+	  opcode = BIT_AND_EXPR;
+	  break;
+	case CHARS2 ('o', 'r'): // operator |
+	  opcode = BIT_IOR_EXPR;
+	  break;
+	case CHARS2 ('e', 'o'): // operator ^
+	  opcode = BIT_XOR_EXPR;
+	  break;
+	case CHARS2 ('a', 'S'): // operator =
+	  opcode = NOP_EXPR;
+	  assop = true;
+	  break;
+	case CHARS2 ('p', 'L'): // operator +=
+	  opcode = PLUS_EXPR;
+	  assop = true;
+	  break;
+	case CHARS2 ('m', 'I'): // operator -=
+	  opcode = MINUS_EXPR;
+	  assop = true;
+	  break;
+	case CHARS2 ('m', 'L'): // operator *=
+	  opcode = MULT_EXPR;
+	  assop = true;
+	  break;
+	case CHARS2 ('d', 'V'): // operator /=
+	  opcode = TRUNC_DIV_EXPR;
+	  assop = true;
+	  break;
+	case CHARS2 ('r', 'M'): // operator %=
+	  opcode = TRUNC_MOD_EXPR;
+	  assop = true;
+	  break;
+	case CHARS2 ('a', 'N'): // operator &=
+	  opcode = BIT_AND_EXPR;
+	  assop = true;
+	  break;
+	case CHARS2 ('o', 'R'): // operator |=
+	  opcode = BIT_IOR_EXPR;
+	  assop = true;
+	  break;
+	case CHARS2 ('e', 'O'): // operator ^=
+	  opcode = BIT_XOR_EXPR;
+	  assop = true;
+	  break;
+	case CHARS2 ('l', 's'): // operator <<
+	  opcode = LSHIFT_EXPR;
+	  break;
+	case CHARS2 ('r', 's'): // operator >>
+	  opcode = RSHIFT_EXPR;
+	  break;
+	case CHARS2 ('l', 'S'): // operator <<=
+	  opcode = LSHIFT_EXPR;
+	  assop = true;
+	  break;
+	case CHARS2 ('r', 'S'): // operator >>=
+	  opcode = RSHIFT_EXPR;
+	  assop = true;
+	  break;
+	case CHARS2 ('e', 'q'): // operator ==
+	  opcode = EQ_EXPR;
+	  break;
+	case CHARS2 ('n', 'e'): // operator !=
+	  opcode = NE_EXPR;
+	  break;
+	case CHARS2 ('l', 't'): // operator <
+	  opcode = LT_EXPR;
+	  break;
+	case CHARS2 ('g', 't'): // operator >
+	  opcode = GT_EXPR;
+	  break;
+	case CHARS2 ('l', 'e'): // operator <=
+	  opcode = LE_EXPR;
+	  break;
+	case CHARS2 ('g', 'e'): // operator >=
+	  opcode = GE_EXPR;
+	  break;
+	case CHARS2 ('n', 't'): // operator !
+	  opcode = TRUTH_NOT_EXPR;
+	  break;
+	case CHARS2 ('a', 'a'): // operator &&
+	  opcode = TRUTH_ANDIF_EXPR;
+	  break;
+	case CHARS2 ('o', 'o'): // operator ||
+	  opcode = TRUTH_ORIF_EXPR;
+	  break;
+	case CHARS2 ('p', 'p'): // operator ++
+	  opcode = POSTINCREMENT_EXPR;
+	  break;
+	case CHARS2 ('m', 'm'): // operator --
+	  opcode = PREDECREMENT_EXPR;
+	  break;
+	case CHARS2 ('c', 'm'): // operator ,
+	  opcode = COMPOUND_EXPR;
+	  break;
+	case CHARS2 ('p', 'm'): // operator ->*
+	  opcode = MEMBER_REF;
+	  break;
+	case CHARS2 ('p', 't'): // operator ->
+	  opcode = COMPONENT_REF;
+	  break;
+	case CHARS2 ('c', 'l'): // operator ()
+	  opcode = CALL_EXPR;
+	  break;
+	case CHARS2 ('i', 'x'): // operator []
+	  opcode = ARRAY_REF;
+	  break;
+	case CHARS2 ('c', 'v'): // operator <T> (conversion operator)
+	  convop = true;
+	  identifier = mangle_conv_op_name_for_type (conv_type);
+	  break;
+	  // C++11-only:
+	case CHARS2 ('l', 'i'): // operator "" <id>
+	  {
+	    char *id = (char *)name + 2;
+	    bool freeid = false;
+	    if (*id >= '0' && *id <= '9')
+	      {
+		unsigned len = 0;
+		do
+		  {
+		    len *= 10;
+		    len += id[0] - '0';
+		    id++;
+		  }
+		while (*id && *id >= '0' && *id <= '9');
+		id = xstrndup (id, len);
+		freeid = true;
+	      }
+	    identifier = cp_literal_operator_id (id);
+	    if (freeid)
+	      free (id);
+	  }
+	  break;
+	case CHARS2 ('q', 'u'): // ternary operator, not overloadable.
+	default:
+	  gcc_unreachable ();
+	}
+
+      gcc_assert (convop || !conv_type);
+
+      if (opcode != ERROR_MARK)
+	{
+	  if (assop)
+	    identifier = cp_assignment_operator_id (opcode);
+	  else
+	    identifier = cp_operator_id (opcode);
+	}
+
+      gcc_assert (identifier);
+    }
+  else
+    {
+      gcc_assert (flags == GCC_CP_SYMBOL_MASK);
+      gcc_assert (!conv_type);
+      identifier = get_identifier (name);
+    }
+  tree res = identifier;
+  if (!scope)
+    res = lookup_name_real (res, 0, 0, true, 0, 0);
+  else if (!TYPE_P (scope) || !dependent_scope_p (scope))
+    {
+      res = lookup_qualified_name (scope, res, false, true);
+      /* We've already resolved the name in the scope, so skip the
+	 build_qualified_name call below.  */
+      scope = NULL;
+    }
+  if (targs)
+    res = lookup_template_function (res, targlist (targs));
+  if (scope)
+    res = build_qualified_name (NULL_TREE, scope, res, !!targs);
+  return convert_out (ctx->preserve (res));
+}
+
+gcc_expr
+plugin_build_literal_expr (cc1_plugin::connection *self,
+			   gcc_type type, unsigned long value)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree t = convert_in (type);
+  tree val = build_int_cst_type (t, (unsigned HOST_WIDE_INT) value);
+  return convert_out (ctx->preserve (val));
+}
+
+gcc_expr
+plugin_build_decl_expr (cc1_plugin::connection *self,
+			gcc_decl decl_in,
+			int qualified_p)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree decl = convert_in (decl_in);
+  gcc_assert (DECL_P (decl));
+  tree result = decl;
+  if (qualified_p)
+    {
+      gcc_assert (DECL_CLASS_SCOPE_P (decl));
+      result = build_offset_ref (DECL_CONTEXT (decl), decl,
+				 /*address_p=*/true, tf_error);
+    }
+  return convert_out (ctx->preserve (result));
+}
+
+gcc_expr
+plugin_build_unary_expr (cc1_plugin::connection *self,
+			 const char *unary_op,
+			 gcc_expr operand)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree op0 = convert_in (operand);
+  tree_code opcode = ERROR_MARK;
+  bool global_scope_p = false;
+
+ once_more:
+  switch (CHARS2 (unary_op[0], unary_op[1]))
+    {
+    case CHARS2 ('p', 's'): // operator + (unary)
+      opcode = UNARY_PLUS_EXPR;
+      break;
+    case CHARS2 ('n', 'g'): // operator - (unary)
+      opcode = NEGATE_EXPR;
+      break;
+    case CHARS2 ('a', 'd'): // operator & (unary)
+      opcode = ADDR_EXPR;
+      break;
+    case CHARS2 ('d', 'e'): // operator * (unary)
+      opcode = INDIRECT_REF;
+      break;
+    case CHARS2 ('c', 'o'): // operator ~
+      opcode = BIT_NOT_EXPR;
+      break;
+    case CHARS2 ('n', 't'): // operator !
+      opcode = TRUTH_NOT_EXPR;
+      break;
+    case CHARS2 ('p', 'p'): // operator ++
+      opcode = unary_op[2] == '_' ? PREINCREMENT_EXPR : POSTINCREMENT_EXPR;
+      break;
+    case CHARS2 ('m', 'm'): // operator --
+      opcode = unary_op[2] == '_' ? PREDECREMENT_EXPR : POSTDECREMENT_EXPR;
+      break;
+    case CHARS2 ('n', 'x'): // noexcept
+      opcode = NOEXCEPT_EXPR;
+      break;
+    case CHARS2 ('t', 'w'): // throw
+      gcc_assert (op0);
+      opcode = THROW_EXPR;
+      break;
+    case CHARS2 ('t', 'r'): // rethrow
+      gcc_assert (!op0);
+      opcode = THROW_EXPR;
+      break;
+    case CHARS2 ('t', 'e'): // typeid (value)
+      opcode = TYPEID_EXPR;
+      break;
+    case CHARS2 ('s', 'z'): // sizeof (value)
+      opcode = SIZEOF_EXPR;
+      break;
+    case CHARS2 ('a', 'z'): // alignof (value)
+      opcode = ALIGNOF_EXPR;
+      break;
+    case CHARS2 ('g', 's'): // global scope (for delete, delete[])
+      gcc_assert (!global_scope_p);
+      global_scope_p = true;
+      unary_op += 2;
+      goto once_more;
+    case CHARS2 ('d', 'l'): // delete
+      opcode = DELETE_EXPR;
+      break;
+    case CHARS2 ('d', 'a'): // delete[]
+      opcode = VEC_DELETE_EXPR;
+      break;
+    case CHARS2 ('s', 'p'): // pack...
+      opcode = EXPR_PACK_EXPANSION;
+      break;
+    case CHARS2 ('s', 'Z'): // sizeof...(pack)
+      opcode = TYPE_PACK_EXPANSION; // Not really, but let's use its code.
+      break;
+
+      /* FIXME: __real__, __imag__?  */
+
+    default:
+      gcc_unreachable ();
+    }
+
+  gcc_assert (!global_scope_p
+	      || opcode == DELETE_EXPR || opcode == VEC_DELETE_EXPR);
+
+  processing_template_decl++;
+  bool template_dependent_p = op0
+    && (type_dependent_expression_p (op0)
+	|| value_dependent_expression_p (op0));
+  if (!template_dependent_p)
+    processing_template_decl--;
+
+  tree result;
+
+  gcc_assert (op0 || opcode == THROW_EXPR);
+
+  switch (opcode)
+    {
+    case NOEXCEPT_EXPR:
+      result = finish_noexcept_expr (op0, tf_error);
+      break;
+
+    case THROW_EXPR:
+      result = build_throw (op0);
+      break;
+
+    case TYPEID_EXPR:
+      result = build_typeid (op0, tf_error);
+      break;
+
+    case SIZEOF_EXPR:
+    case ALIGNOF_EXPR:
+      result = cxx_sizeof_or_alignof_expr (op0, opcode, true);
+      break;
+
+    case DELETE_EXPR:
+    case VEC_DELETE_EXPR:
+      result = delete_sanity (op0, NULL_TREE, opcode == VEC_DELETE_EXPR,
+			      global_scope_p, tf_error);
+      break;
+
+    case EXPR_PACK_EXPANSION:
+      result = make_pack_expansion (op0);
+      break;
+
+      // We're using this for sizeof...(pack).  */
+    case TYPE_PACK_EXPANSION:
+      result = make_pack_expansion (op0);
+      PACK_EXPANSION_SIZEOF_P (result) = true;
+      break;
+
+    default:
+      result = build_x_unary_op (/*loc=*/0, opcode, op0, tf_error);
+      break;
+    }
+
+  if (template_dependent_p)
+    processing_template_decl--;
+
+  return convert_out (ctx->preserve (result));
+}
+
+gcc_expr
+plugin_build_binary_expr (cc1_plugin::connection *self,
+			  const char *binary_op,
+			  gcc_expr operand1,
+			  gcc_expr operand2)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree op0 = convert_in (operand1);
+  tree op1 = convert_in (operand2);
+  tree_code opcode = ERROR_MARK;
+
+  switch (CHARS2 (binary_op[0], binary_op[1]))
+    {
+    case CHARS2 ('p', 'l'): // operator +
+      opcode = PLUS_EXPR;
+      break;
+    case CHARS2 ('m', 'i'): // operator -
+      opcode = MINUS_EXPR;
+      break;
+    case CHARS2 ('m', 'l'): // operator *
+      opcode = MULT_EXPR;
+      break;
+    case CHARS2 ('d', 'v'): // operator /
+      opcode = TRUNC_DIV_EXPR;
+      break;
+    case CHARS2 ('r', 'm'): // operator %
+      opcode = TRUNC_MOD_EXPR;
+      break;
+    case CHARS2 ('a', 'n'): // operator &
+      opcode = BIT_AND_EXPR;
+      break;
+    case CHARS2 ('o', 'r'): // operator |
+      opcode = BIT_IOR_EXPR;
+      break;
+    case CHARS2 ('e', 'o'): // operator ^
+      opcode = BIT_XOR_EXPR;
+      break;
+    case CHARS2 ('l', 's'): // operator <<
+      opcode = LSHIFT_EXPR;
+      break;
+    case CHARS2 ('r', 's'): // operator >>
+      opcode = RSHIFT_EXPR;
+      break;
+    case CHARS2 ('e', 'q'): // operator ==
+      opcode = EQ_EXPR;
+      break;
+    case CHARS2 ('n', 'e'): // operator !=
+      opcode = NE_EXPR;
+      break;
+    case CHARS2 ('l', 't'): // operator <
+      opcode = LT_EXPR;
+      break;
+    case CHARS2 ('g', 't'): // operator >
+      opcode = GT_EXPR;
+      break;
+    case CHARS2 ('l', 'e'): // operator <=
+      opcode = LE_EXPR;
+      break;
+    case CHARS2 ('g', 'e'): // operator >=
+      opcode = GE_EXPR;
+      break;
+    case CHARS2 ('a', 'a'): // operator &&
+      opcode = TRUTH_ANDIF_EXPR;
+      break;
+    case CHARS2 ('o', 'o'): // operator ||
+      opcode = TRUTH_ORIF_EXPR;
+      break;
+    case CHARS2 ('c', 'm'): // operator ,
+      opcode = COMPOUND_EXPR;
+      break;
+    case CHARS2 ('p', 'm'): // operator ->*
+      opcode = MEMBER_REF;
+      break;
+    case CHARS2 ('p', 't'): // operator ->
+      opcode = INDIRECT_REF; // Not really!  This will stand for
+			     // INDIRECT_REF followed by COMPONENT_REF
+			     // later on.
+      break;
+    case CHARS2 ('i', 'x'): // operator []
+      opcode = ARRAY_REF;
+      break;
+    case CHARS2 ('d', 's'): // operator .*
+      opcode = DOTSTAR_EXPR;
+      break;
+    case CHARS2 ('d', 't'): // operator .
+      opcode = COMPONENT_REF;
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  processing_template_decl++;
+  bool template_dependent_p = type_dependent_expression_p (op0)
+    || value_dependent_expression_p (op0)
+    || type_dependent_expression_p (op1)
+    || value_dependent_expression_p (op1);
+  if (!template_dependent_p)
+    processing_template_decl--;
+
+  tree result;
+
+  switch (opcode)
+    {
+    case INDIRECT_REF: // This is actually a "->".
+      op0 = build_x_arrow (/*loc=*/0, op0, tf_error);
+      /* Fall through.  */
+    case COMPONENT_REF:
+      result = finish_class_member_access_expr (op0, op1,
+						/*template_p=*/false,
+						tf_error);
+      break;
+
+    default:
+      result = build_x_binary_op (/*loc=*/0, opcode, op0, ERROR_MARK,
+				  op1, ERROR_MARK, NULL, tf_error);
+      break;
+    }
+
+  if (template_dependent_p)
+    processing_template_decl--;
+
+  return convert_out (ctx->preserve (result));
+}
+
+gcc_expr
+plugin_build_ternary_expr (cc1_plugin::connection *self,
+			   const char *ternary_op,
+			   gcc_expr operand1,
+			   gcc_expr operand2,
+			   gcc_expr operand3)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree op0 = convert_in (operand1);
+  tree op1 = convert_in (operand2);
+  tree op2 = convert_in (operand3);
+  gcc_assert (CHARS2 (ternary_op[0], ternary_op[1])
+	      == CHARS2 ('q', 'u')); // ternary operator
+
+  processing_template_decl++;
+  bool template_dependent_p = type_dependent_expression_p (op0)
+    || value_dependent_expression_p (op0)
+    || type_dependent_expression_p (op1)
+    || value_dependent_expression_p (op1)
+    || type_dependent_expression_p (op2)
+    || value_dependent_expression_p (op2);
+  if (!template_dependent_p)
+    processing_template_decl--;
+
+  tree val = build_x_conditional_expr (/*loc=*/0, op0, op1, op2, tf_error);
+
+  if (template_dependent_p)
+    processing_template_decl--;
+
+  return convert_out (ctx->preserve (val));
+}
+
+gcc_expr
+plugin_build_unary_type_expr (cc1_plugin::connection *self,
+			      const char *unary_op,
+			      gcc_type operand)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree type = convert_in (operand);
+  tree_code opcode = ERROR_MARK;
+
+  switch (CHARS2 (unary_op[0], unary_op[1]))
+    {
+    case CHARS2 ('t', 'i'): // typeid (type)
+      opcode = TYPEID_EXPR;
+      break;
+
+    case CHARS2 ('s', 't'): // sizeof (type)
+      opcode = SIZEOF_EXPR;
+      break;
+    case CHARS2 ('a', 't'): // alignof (type)
+      opcode = ALIGNOF_EXPR;
+      break;
+
+    case CHARS2 ('s', 'Z'): // sizeof...(pack)
+      opcode = TYPE_PACK_EXPANSION; // Not really, but let's use its code.
+      break;
+
+      // FIXME: do we have to handle "sp", for the size of a captured
+      // template parameter pack from an alias template, taking
+      // multiple template arguments?
+
+    default:
+      gcc_unreachable ();
+    }
+
+  processing_template_decl++;
+  bool template_dependent_p = dependent_type_p (type);
+  if (!template_dependent_p)
+    processing_template_decl--;
+
+  tree result;
+
+  switch (opcode)
+    {
+    case TYPEID_EXPR:
+      result = get_typeid (type, tf_error);
+      break;
+
+      // We're using this for sizeof...(pack).  */
+    case TYPE_PACK_EXPANSION:
+      result = make_pack_expansion (type);
+      PACK_EXPANSION_SIZEOF_P (result) = true;
+      break;
+
+    default:
+      result = cxx_sizeof_or_alignof_type (type, opcode, true);
+    }
+
+  if (template_dependent_p)
+    processing_template_decl--;
+
+  return convert_out (ctx->preserve (result));
+}
+
+gcc_expr
+plugin_build_cast_expr (cc1_plugin::connection *self,
+			const char *binary_op,
+			gcc_type operand1,
+			gcc_expr operand2)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree (*build_cast)(tree type, tree expr, tsubst_flags_t complain) = NULL;
+  tree type = convert_in (operand1);
+  tree expr = convert_in (operand2);
+
+  switch (CHARS2 (binary_op[0], binary_op[1]))
+    {
+    case CHARS2 ('d', 'c'): // dynamic_cast
+      build_cast = build_dynamic_cast;
+      break;
+
+    case CHARS2 ('s', 'c'): // static_cast
+      build_cast = build_static_cast;
+      break;
+
+    case CHARS2 ('c', 'c'): // const_cast
+      build_cast = build_const_cast;
+      break;
+
+    case CHARS2 ('r', 'c'): // reinterpret_cast
+      build_cast = build_reinterpret_cast;
+      break;
+
+    case CHARS2 ('c', 'v'): // C cast, conversion with one argument
+      build_cast = cp_build_c_cast;
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  processing_template_decl++;
+  bool template_dependent_p = dependent_type_p (type)
+    || type_dependent_expression_p (expr)
+    || value_dependent_expression_p (expr);
+  if (!template_dependent_p)
+    processing_template_decl--;
+
+  tree val = build_cast (type, expr, tf_error);
+
+  if (template_dependent_p)
+    processing_template_decl--;
+
+  return convert_out (ctx->preserve (val));
+}
+
+static inline vec<tree, va_gc> *
+args_to_tree_vec (const struct gcc_cp_function_args *args_in)
+{
+  vec<tree, va_gc> *args = make_tree_vector ();
+  for (int i = 0; i < args_in->n_elements; i++)
+    vec_safe_push (args, convert_in (args_in->elements[i]));
+  return args;
+}
+
+static inline tree
+args_to_tree_list (const struct gcc_cp_function_args *args_in)
+{
+  tree args, *tail = &args;
+  for (int i = 0; i < args_in->n_elements; i++)
+    {
+      *tail = build_tree_list (NULL, convert_in (args_in->elements[i]));
+      tail = &TREE_CHAIN (*tail);
+    }
+  return args;
+}
+
+static inline vec<constructor_elt, va_gc> *
+args_to_ctor_elts (const struct gcc_cp_function_args *args_in)
+{
+  vec<constructor_elt, va_gc> *args = NULL;
+  for (int i = 0; i < args_in->n_elements; i++)
+    CONSTRUCTOR_APPEND_ELT (args, NULL_TREE, convert_in (args_in->elements[i]));
+  return args;
+}
+
+gcc_expr
+plugin_build_expression_list_expr (cc1_plugin::connection *self,
+				   const char *conv_op,
+				   gcc_type type_in,
+				   const struct gcc_cp_function_args *values_in)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree type = convert_in (type_in);
+  tree args;
+  tree result;
+
+  switch (CHARS2 (conv_op[0], conv_op[1]))
+    {
+    case CHARS2 ('c', 'v'): // conversion with parenthesized expression list
+      gcc_assert (TYPE_P (type));
+      args = args_to_tree_list (values_in);
+      result = build_functional_cast (type, args, tf_error);
+      break;
+
+    case CHARS2 ('t', 'l'): // conversion with braced expression list
+      gcc_assert (type);
+      gcc_assert (TYPE_P (type));
+      args = make_node (CONSTRUCTOR);
+      CONSTRUCTOR_ELTS (args) = args_to_ctor_elts (values_in);
+      CONSTRUCTOR_IS_DIRECT_INIT (args) = 1;
+      result = finish_compound_literal (type, args, tf_error);
+      break;
+
+    case CHARS2 ('i', 'l'): // untyped braced expression list
+      gcc_assert (!type);
+      result = make_node (CONSTRUCTOR);
+      CONSTRUCTOR_ELTS (result) = args_to_ctor_elts (values_in);
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return convert_out (ctx->preserve (result));
+}
+
+gcc_expr
+plugin_build_new_expr (cc1_plugin::connection *self,
+		       const char *new_op,
+		       const struct gcc_cp_function_args *placement_in,
+		       gcc_type type_in,
+		       const struct gcc_cp_function_args *initializer_in)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree type = convert_in (type_in);
+  vec<tree, va_gc> *placement = NULL, *initializer = NULL;
+  bool global_scope_p = false;
+  tree nelts = NULL;
+
+  if (placement_in)
+    placement = args_to_tree_vec (placement_in);
+  if (initializer_in)
+    initializer = args_to_tree_vec (initializer_in);
+
+  gcc_assert (TYPE_P (type));
+
+ once_more:
+  switch (CHARS2 (new_op[0], new_op[1]))
+    {
+    case CHARS2 ('g', 's'):
+      gcc_assert (!global_scope_p);
+      global_scope_p = true;
+      new_op += 2;
+      goto once_more;
+
+    case CHARS2 ('n', 'w'): // non-array new
+      gcc_assert (TREE_CODE (type) != ARRAY_TYPE);
+      break;
+
+    case CHARS2 ('n', 'a'): // array new
+      gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
+      gcc_assert (TYPE_DOMAIN (type));
+      {
+	// Compute the length of the outermost array type, then discard it.
+	tree maxelt = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
+	tree eltype = TREE_TYPE (maxelt);
+	tree onecst = integer_one_node;
+
+	processing_template_decl++;
+	bool template_dependent_p = value_dependent_expression_p (maxelt)
+	  || type_dependent_expression_p (maxelt);
+	if (!template_dependent_p)
+	  {
+	    processing_template_decl--;
+	    onecst = fold_convert (eltype, onecst);
+	  }
+
+	nelts = fold_build2 (PLUS_EXPR, eltype, nelts, onecst);
+
+	if (template_dependent_p)
+	  processing_template_decl--;
+
+	type = TREE_TYPE (type);
+      }
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  processing_template_decl++;
+  bool template_dependent_p = dependent_type_p (type)
+    || value_dependent_expression_p (nelts)
+    || (placement
+	&& any_type_dependent_arguments_p (placement))
+    || (initializer
+	&& any_type_dependent_arguments_p (initializer));
+  if (!template_dependent_p)
+    processing_template_decl--;
+
+  tree result = build_new (&placement, type, nelts, &initializer,
+			   global_scope_p, tf_error);
+
+  if (template_dependent_p)
+    processing_template_decl--;
+
+  if (placement != NULL)
+    release_tree_vector (placement);
+  if (initializer != NULL)
+    release_tree_vector (initializer);
+
+  return convert_out (ctx->preserve (result));
+}
+
+gcc_expr
+plugin_build_call_expr (cc1_plugin::connection *self,
+			gcc_expr callable_in, int qualified_p,
+			const struct gcc_cp_function_args *args_in)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree callable = convert_in (callable_in);
+  tree call_expr;
+
+  vec<tree, va_gc> *args = args_to_tree_vec (args_in);
+
+  bool koenig_p = false;
+  if (!qualified_p && !args->is_empty ())
+    {
+      if (identifier_p (callable))
+	koenig_p = true;
+      else if (is_overloaded_fn (callable))
+	{
+	  tree fn = get_first_fn (callable);
+	  fn = STRIP_TEMPLATE (fn);
+
+	  if (!DECL_FUNCTION_MEMBER_P (fn)
+	      && !DECL_LOCAL_FUNCTION_P (fn))
+	    koenig_p = true;
+	}
+    }
+
+  if (koenig_p && !any_type_dependent_arguments_p (args))
+    callable = perform_koenig_lookup (callable, args, tf_none);
+
+  if (TREE_CODE (callable) == COMPONENT_REF)
+    {
+      tree object = TREE_OPERAND (callable, 0);
+      tree memfn = TREE_OPERAND (callable, 1);
+
+      if (type_dependent_expression_p (object)
+	  || (!BASELINK_P (memfn) && TREE_CODE (memfn) != FIELD_DECL)
+	  || type_dependent_expression_p (memfn)
+	  || any_type_dependent_arguments_p (args))
+	call_expr = build_nt_call_vec (callable, args);
+      else if (BASELINK_P (memfn))
+	call_expr = build_new_method_call (object, memfn, &args, NULL_TREE,
+					   qualified_p
+					   ? LOOKUP_NORMAL|LOOKUP_NONVIRTUAL
+					   : LOOKUP_NORMAL,
+					   NULL, tf_none);
+      else
+	call_expr = finish_call_expr (callable, &args, false, false, tf_none);
+    }
+  else if (TREE_CODE (callable) == OFFSET_REF
+	   || TREE_CODE (callable) == MEMBER_REF
+	   || TREE_CODE (callable) == DOTSTAR_EXPR)
+    call_expr = build_offset_ref_call_from_tree (callable, &args, tf_none);
+  else
+    call_expr = finish_call_expr (callable, &args,
+				  !!qualified_p, koenig_p, tf_none);
+
+  release_tree_vector (args);
+  return convert_out (ctx->preserve (call_expr));
+}
+
+gcc_type
+plugin_get_expr_type (cc1_plugin::connection *self,
+		      gcc_expr operand)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree op0 = convert_in (operand);
+  tree type;
+  if (op0)
+    type = TREE_TYPE (op0);
+  else
+    {
+      type = make_decltype_auto ();
+      AUTO_IS_DECLTYPE (type) = true;
+    }
+  return convert_out (ctx->preserve (type));
+}
+
+gcc_decl
+plugin_build_function_template_specialization (cc1_plugin::connection *self,
+					       gcc_decl template_decl,
+					       const gcc_cp_template_args *targs,
+					       gcc_address address,
+					       const char *filename,
+					       unsigned int line_number)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  source_location loc = ctx->get_source_location (filename, line_number);
+  tree name = convert_in (template_decl);
+  tree targsl = targlist (targs);
+
+  tree decl = tsubst (name, targsl, tf_error, NULL_TREE);
+  DECL_SOURCE_LOCATION (decl) = loc;
+
+  record_decl_address (ctx, build_decl_addr_value (decl, address));
+
+  return convert_out (ctx->preserve (decl));
+}
+
+gcc_decl
+plugin_build_class_template_specialization (cc1_plugin::connection *self,
+					    gcc_decl template_decl,
+					    const gcc_cp_template_args *args,
+					    const char *filename,
+					    unsigned int line_number)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  source_location loc = ctx->get_source_location (filename, line_number);
+  tree name = convert_in (template_decl);
+
+  tree tdecl = finish_template_type (name, targlist (args), false);;
+  DECL_SOURCE_LOCATION (tdecl) = loc;
+
+  return convert_out (ctx->preserve (tdecl));
+}
+
+/* Return a builtin type associated with BUILTIN_NAME.  */
+
+static tree
+safe_lookup_builtin_type (const char *builtin_name)
+{
+  tree result = NULL_TREE;
+
+  if (!builtin_name)
+    return result;
+
+  result = identifier_global_value (get_identifier (builtin_name));
+
+  if (!result)
+    return result;
+
+  gcc_assert (TREE_CODE (result) == TYPE_DECL);
+  result = TREE_TYPE (result);
+  return result;
+}
+
+gcc_type
+plugin_get_int_type (cc1_plugin::connection *self,
+		     int is_unsigned, unsigned long size_in_bytes,
+		     const char *builtin_name)
+{
+  tree result;
+
+  if (builtin_name)
+    {
+      result = safe_lookup_builtin_type (builtin_name);
+      gcc_assert (!result || TREE_CODE (result) == INTEGER_TYPE);
+    }
+  else
+    result = c_common_type_for_size (BITS_PER_UNIT * size_in_bytes,
+				     is_unsigned);
+
+  if (result == NULL_TREE)
+    result = error_mark_node;
+  else
+    {
+      gcc_assert (!TYPE_UNSIGNED (result) == !is_unsigned);
+      gcc_assert (TREE_CODE (TYPE_SIZE (result)) == INTEGER_CST);
+      gcc_assert (TYPE_PRECISION (result) == BITS_PER_UNIT * size_in_bytes);
+
+      plugin_context *ctx = static_cast<plugin_context *> (self);
+      ctx->preserve (result);
+    }
+  return convert_out (result);
+}
+
+gcc_type
+plugin_get_char_type (cc1_plugin::connection *)
+{
+  return convert_out (char_type_node);
+}
+
+gcc_type
+plugin_get_float_type (cc1_plugin::connection *,
+		       unsigned long size_in_bytes,
+		       const char *builtin_name)
+{
+  if (builtin_name)
+    {
+      tree result = safe_lookup_builtin_type (builtin_name);
+
+      if (!result)
+	return convert_out (error_mark_node);
+
+      gcc_assert (TREE_CODE (result) == REAL_TYPE);
+      gcc_assert (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (result));
+
+      return convert_out (result);
+    }
+
+  if (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (float_type_node))
+    return convert_out (float_type_node);
+  if (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (double_type_node))
+    return convert_out (double_type_node);
+  if (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (long_double_type_node))
+    return convert_out (long_double_type_node);
+  return convert_out (error_mark_node);
+}
+
+gcc_type
+plugin_get_void_type (cc1_plugin::connection *)
+{
+  return convert_out (void_type_node);
+}
+
+gcc_type
+plugin_get_bool_type (cc1_plugin::connection *)
+{
+  return convert_out (boolean_type_node);
+}
+
+gcc_type
+plugin_get_nullptr_type (cc1_plugin::connection *)
+{
+  return convert_out (nullptr_type_node);
+}
+
+gcc_expr
+plugin_get_nullptr_constant (cc1_plugin::connection *)
+{
+  return convert_out (nullptr_node);
+}
+
+gcc_type
+plugin_build_array_type (cc1_plugin::connection *self,
+			 gcc_type element_type_in, int num_elements)
+{
+  tree element_type = convert_in (element_type_in);
+  tree result;
+
+  if (num_elements == -1)
+    result = build_array_type (element_type, NULL_TREE);
+  else
+    result = build_array_type_nelts (element_type, num_elements);
+
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  return convert_out (ctx->preserve (result));
+}
+
+gcc_type
+plugin_build_dependent_array_type (cc1_plugin::connection *self,
+				   gcc_type element_type_in,
+				   gcc_expr num_elements_in)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree element_type = convert_in (element_type_in);
+  tree size = convert_in (num_elements_in);
+  tree name = get_identifier ("dependent array type");
+
+  processing_template_decl++;
+  bool template_dependent_p = dependent_type_p (element_type)
+    || type_dependent_expression_p (size)
+    || value_dependent_expression_p (size);
+  if (!template_dependent_p)
+    processing_template_decl--;
+
+  tree itype = compute_array_index_type (name, size, tf_error);
+  tree type = build_cplus_array_type (element_type, itype);
+
+  if (template_dependent_p)
+    processing_template_decl--;
+
+  return convert_out (ctx->preserve (type));
+}
+
+gcc_type
+plugin_build_vla_array_type (cc1_plugin::connection *self,
+			     gcc_type element_type_in,
+			     const char *upper_bound_name)
+{
+  tree element_type = convert_in (element_type_in);
+  tree upper_bound = lookup_name (get_identifier (upper_bound_name));
+  tree size = fold_build2 (PLUS_EXPR, TREE_TYPE (upper_bound), upper_bound,
+			   build_one_cst (TREE_TYPE (upper_bound)));
+  tree range = compute_array_index_type (NULL_TREE, size,
+					 tf_error);
+
+  tree result = build_cplus_array_type (element_type, range);
+
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  return convert_out (ctx->preserve (result));
+}
+
+gcc_type
+plugin_build_qualified_type (cc1_plugin::connection *,
+			     gcc_type unqualified_type_in,
+			     enum gcc_cp_qualifiers qualifiers)
+{
+  tree unqualified_type = convert_in (unqualified_type_in);
+  cp_cv_quals quals = 0;
+
+  if ((qualifiers & GCC_CP_QUALIFIER_CONST) != 0)
+    quals |= TYPE_QUAL_CONST;
+  if ((qualifiers & GCC_CP_QUALIFIER_VOLATILE) != 0)
+    quals |= TYPE_QUAL_VOLATILE;
+  if ((qualifiers & GCC_CP_QUALIFIER_RESTRICT) != 0)
+    quals |= TYPE_QUAL_RESTRICT;
+
+  gcc_assert ((TREE_CODE (unqualified_type) != METHOD_TYPE
+	       && TREE_CODE (unqualified_type) != REFERENCE_TYPE)
+	      || quals == 0);
+
+  return convert_out (build_qualified_type (unqualified_type, quals));
+}
+
+gcc_type
+plugin_build_complex_type (cc1_plugin::connection *self,
+			   gcc_type base_type)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  return convert_out (ctx->preserve (build_complex_type (convert_in (base_type))));
+}
+
+gcc_type
+plugin_build_vector_type (cc1_plugin::connection *self,
+			  gcc_type base_type, int nunits)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  return convert_out (ctx->preserve (build_vector_type (convert_in (base_type),
+							nunits)));
+}
+
+int
+plugin_build_constant (cc1_plugin::connection *self, gcc_type type_in,
+		       const char *name, unsigned long value,
+		       const char *filename, unsigned int line_number)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree cst, decl;
+  tree type = convert_in (type_in);
+
+  cst = build_int_cst (type, value);
+  if (!TYPE_READONLY (type))
+    type = build_qualified_type (type, TYPE_QUAL_CONST);
+  decl = build_decl (ctx->get_source_location (filename, line_number),
+		     VAR_DECL, get_identifier (name), type);
+  TREE_STATIC (decl) = 1;
+  TREE_READONLY (decl) = 1;
+  cp_finish_decl (decl, cst, true, NULL, LOOKUP_ONLYCONVERTING);
+  safe_pushdecl_maybe_friend (decl, false);
+
+  return 1;
+}
+
+gcc_type
+plugin_error (cc1_plugin::connection *,
+	      const char *message)
+{
+  error ("%s", message);
+  return convert_out (error_mark_node);
+}
+
+int
+plugin_add_static_assert (cc1_plugin::connection *self,
+			  gcc_expr condition_in,
+			  const char *errormsg,
+			  const char *filename,
+			  unsigned int line_number)
+{
+  plugin_context *ctx = static_cast<plugin_context *> (self);
+  tree condition = convert_in (condition_in);
+
+  if (!errormsg)
+    errormsg = "";
+
+  tree message = build_string (strlen (errormsg) + 1, errormsg);
+
+  TREE_TYPE (message) = char_array_type_node;
+  fix_string_type (message);
+
+  source_location loc = ctx->get_source_location (filename, line_number);
+
+  bool member_p = at_class_scope_p ();
+
+  finish_static_assert (condition, message, loc, member_p);
+
+  return 1;
+}
+
+
+
+// Perform GC marking.
+
+static void
+gc_mark (void *, void *)
+{
+  if (current_context != NULL)
+    current_context->mark ();
+}
+
+#ifdef __GNUC__
+#pragma GCC visibility push(default)
+#endif
+
+int
+plugin_init (struct plugin_name_args *plugin_info,
+	     struct plugin_gcc_version *)
+{
+  long fd = -1;
+  for (int i = 0; i < plugin_info->argc; ++i)
+    {
+      if (strcmp (plugin_info->argv[i].key, "fd") == 0)
+	{
+	  char *tail;
+	  errno = 0;
+	  fd = strtol (plugin_info->argv[i].value, &tail, 0);
+	  if (*tail != '\0' || errno != 0)
+	    fatal_error (input_location,
+			 "%s: invalid file descriptor argument to plugin",
+			 plugin_info->base_name);
+	  break;
+	}
+    }
+  if (fd == -1)
+    fatal_error (input_location,
+		 "%s: required plugin argument %<fd%> is missing",
+		 plugin_info->base_name);
+
+  current_context = new plugin_context (fd);
+
+  // Handshake.
+  cc1_plugin::protocol_int version;
+  if (!current_context->require ('H')
+      || ! ::cc1_plugin::unmarshall (current_context, &version))
+    fatal_error (input_location,
+		 "%s: handshake failed", plugin_info->base_name);
+  if (version != GCC_CP_FE_VERSION_0)
+    fatal_error (input_location,
+		 "%s: unknown version in handshake", plugin_info->base_name);
+
+  register_callback (plugin_info->base_name, PLUGIN_PRAGMAS,
+		     plugin_init_extra_pragmas, NULL);
+  register_callback (plugin_info->base_name, PLUGIN_PRE_GENERICIZE,
+		     rewrite_decls_to_addresses, NULL);
+  register_callback (plugin_info->base_name, PLUGIN_GGC_MARKING,
+		     gc_mark, NULL);
+
+  lang_hooks.print_error_function = plugin_print_error_function;
+
+#define GCC_METHOD0(R, N)			\
+  {						\
+    cc1_plugin::callback_ftype *fun		\
+      = cc1_plugin::callback<R, plugin_ ## N>;	\
+    current_context->add_callback (# N, fun);	\
+  }
+#define GCC_METHOD1(R, N, A)				\
+  {							\
+    cc1_plugin::callback_ftype *fun			\
+      = cc1_plugin::callback<R, A, plugin_ ## N>;	\
+    current_context->add_callback (# N, fun);		\
+  }
+#define GCC_METHOD2(R, N, A, B)				\
+  {							\
+    cc1_plugin::callback_ftype *fun			\
+      = cc1_plugin::callback<R, A, B, plugin_ ## N>;	\
+    current_context->add_callback (# N, fun);		\
+  }
+#define GCC_METHOD3(R, N, A, B, C)			\
+  {							\
+    cc1_plugin::callback_ftype *fun			\
+      = cc1_plugin::callback<R, A, B, C, plugin_ ## N>;	\
+    current_context->add_callback (# N, fun);		\
+  }
+#define GCC_METHOD4(R, N, A, B, C, D)		\
+  {						\
+    cc1_plugin::callback_ftype *fun		\
+      = cc1_plugin::callback<R, A, B, C, D,	\
+			     plugin_ ## N>;	\
+    current_context->add_callback (# N, fun);	\
+  }
+#define GCC_METHOD5(R, N, A, B, C, D, E)	\
+  {						\
+    cc1_plugin::callback_ftype *fun		\
+      = cc1_plugin::callback<R, A, B, C, D, E,	\
+			     plugin_ ## N>;	\
+    current_context->add_callback (# N, fun);	\
+  }
+#define GCC_METHOD7(R, N, A, B, C, D, E, F, G)		\
+  {							\
+    cc1_plugin::callback_ftype *fun			\
+      = cc1_plugin::callback<R, A, B, C, D, E, F, G,	\
+			     plugin_ ## N>;		\
+    current_context->add_callback (# N, fun);		\
+  }
+
+#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
+
+  return 0;
+}
diff --git a/libcc1/libcp1plugin.sym b/libcc1/libcp1plugin.sym
new file mode 100644
index 0000000..05d0f7b
--- /dev/null
+++ b/libcc1/libcp1plugin.sym
@@ -0,0 +1,2 @@ 
+plugin_init
+plugin_is_GPL_compatible
diff --git a/libcc1/marshall-c.hh b/libcc1/marshall-c.hh
new file mode 100644
index 0000000..8120c15
--- /dev/null
+++ b/libcc1/marshall-c.hh
@@ -0,0 +1,59 @@ 
+/* Marshalling and unmarshalling of C-specific types.
+   Copyright (C) 2014-2017 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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 GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef CC1_PLUGIN_MARSHALL_C_HH
+#define CC1_PLUGIN_MARSHALL_C_HH
+
+#include "marshall.hh"
+#include "gcc-c-interface.h"
+
+namespace cc1_plugin
+{
+  status
+  unmarshall (connection *conn, enum gcc_c_symbol_kind *result)
+  {
+    protocol_int p;
+    if (!unmarshall_intlike (conn, &p))
+      return FAIL;
+    *result = (enum gcc_c_symbol_kind) p;
+    return OK;
+  }
+
+  status
+  unmarshall (connection *conn, enum gcc_c_oracle_request *result)
+  {
+    protocol_int p;
+    if (!unmarshall_intlike (conn, &p))
+      return FAIL;
+    *result = (enum gcc_c_oracle_request) p;
+    return OK;
+  }
+
+  status
+  unmarshall (connection *conn, enum gcc_qualifiers *result)
+  {
+    protocol_int p;
+    if (!unmarshall_intlike (conn, &p))
+      return FAIL;
+    *result = (enum gcc_qualifiers) p;
+    return OK;
+  }
+}
+
+#endif // CC1_PLUGIN_MARSHALL_C_HH
diff --git a/libcc1/marshall-cp.hh b/libcc1/marshall-cp.hh
new file mode 100644
index 0000000..eec80f3
--- /dev/null
+++ b/libcc1/marshall-cp.hh
@@ -0,0 +1,271 @@ 
+/* Marshalling and unmarshalling of C++-specific types.
+   Copyright (C) 2014-2017 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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 GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef CC1_PLUGIN_MARSHALL_CXX_HH
+#define CC1_PLUGIN_MARSHALL_CXX_HH
+
+#include "marshall.hh"
+#include "gcc-cp-interface.h"
+
+namespace cc1_plugin
+{
+  status
+  unmarshall (connection *conn, enum gcc_cp_symbol_kind *result)
+  {
+    protocol_int p;
+    if (!unmarshall_intlike (conn, &p))
+      return FAIL;
+    *result = (enum gcc_cp_symbol_kind) p;
+    return OK;
+  }
+
+  status
+  unmarshall (connection *conn, enum gcc_cp_oracle_request *result)
+  {
+    protocol_int p;
+    if (!unmarshall_intlike (conn, &p))
+      return FAIL;
+    *result = (enum gcc_cp_oracle_request) p;
+    return OK;
+  }
+
+  status
+  unmarshall (connection *conn, enum gcc_cp_qualifiers *result)
+  {
+    protocol_int p;
+    if (!unmarshall_intlike (conn, &p))
+      return FAIL;
+    *result = (enum gcc_cp_qualifiers) p;
+    return OK;
+  }
+
+  status
+  unmarshall (connection *conn, enum gcc_cp_ref_qualifiers *result)
+  {
+    protocol_int p;
+    if (!unmarshall_intlike (conn, &p))
+      return FAIL;
+    *result = (enum gcc_cp_ref_qualifiers) p;
+    return OK;
+  }
+
+  // Send a gcc_vbase_array marker followed by the array.
+  status
+  marshall (connection *conn, const gcc_vbase_array *a)
+  {
+    size_t len;
+
+    if (a)
+      len = a->n_elements;
+    else
+      len = (size_t)-1;
+
+    if (!marshall_array_start (conn, 'v', len))
+      return FAIL;
+
+    if (!a)
+      return OK;
+
+    if (!marshall_array_elmts (conn, len * sizeof (a->elements[0]),
+			       a->elements))
+      return FAIL;
+
+    return marshall_array_elmts (conn, len * sizeof (a->flags[0]),
+				 a->flags);
+  }
+
+  // Read a gcc_vbase_array marker, followed by a gcc_vbase_array.  The
+  // resulting array must be freed by the caller, using 'delete[]' on
+  // elements and virtualp, and 'delete' on the array object itself.
+  status
+  unmarshall (connection *conn, struct gcc_vbase_array **result)
+  {
+    size_t len;
+
+    if (!unmarshall_array_start (conn, 'v', &len))
+      return FAIL;
+
+    if (len == (size_t)-1)
+      {
+	*result = NULL;
+	return OK;
+      }
+
+    struct gcc_vbase_array *gva = new gcc_vbase_array;
+
+    gva->n_elements = len;
+    gva->elements = new gcc_type[len];
+
+    if (!unmarshall_array_elmts (conn,
+				 len * sizeof (gva->elements[0]),
+				 gva->elements))
+      {
+	delete[] gva->elements;
+	delete gva;
+	return FAIL;
+      }
+
+    gva->flags = new enum gcc_cp_symbol_kind[len];
+
+    if (!unmarshall_array_elmts (conn,
+				 len * sizeof (gva->flags[0]),
+				 gva->flags))
+      {
+	delete[] gva->flags;
+	delete[] gva->elements;
+	delete gva;
+	return FAIL;
+      }
+
+    *result = gva;
+    return OK;
+  }
+
+  // Send a gcc_cp_template_args marker followed by the array.
+  status
+  marshall (connection *conn, const gcc_cp_template_args *a)
+  {
+    size_t len;
+
+    if (a)
+      len = a->n_elements;
+    else
+      len = (size_t)-1;
+
+    if (!marshall_array_start (conn, 't', len))
+      return FAIL;
+
+    if (!a)
+      return OK;
+
+    if (!marshall_array_elmts (conn, len * sizeof (a->kinds[0]),
+			       a->kinds))
+      return FAIL;
+
+    return marshall_array_elmts (conn, len * sizeof (a->elements[0]),
+				 a->elements);
+  }
+
+  // Read a gcc_vbase_array marker, followed by a gcc_vbase_array.  The
+  // resulting array must be freed by the caller, using 'delete[]' on
+  // elements and virtualp, and 'delete' on the array object itself.
+  status
+  unmarshall (connection *conn, struct gcc_cp_template_args **result)
+  {
+    size_t len;
+
+    if (!unmarshall_array_start (conn, 't', &len))
+      return FAIL;
+
+    if (len == (size_t)-1)
+      {
+	*result = NULL;
+	return OK;
+      }
+
+    struct gcc_cp_template_args *gva = new gcc_cp_template_args;
+
+    gva->n_elements = len;
+    gva->kinds = new char[len];
+
+    if (!unmarshall_array_elmts (conn,
+				 len * sizeof (gva->kinds[0]),
+				 gva->kinds))
+      {
+	delete[] gva->kinds;
+	delete gva;
+	return FAIL;
+      }
+
+    gva->elements = new gcc_cp_template_arg[len];
+
+    if (!unmarshall_array_elmts (conn,
+				 len * sizeof (gva->elements[0]),
+				 gva->elements))
+      {
+	delete[] gva->elements;
+	delete[] gva->kinds;
+	delete gva;
+	return FAIL;
+      }
+
+    *result = gva;
+    return OK;
+  }
+
+  // Send a gcc_cp_function_args marker followed by the array.
+  status
+  marshall (connection *conn, const gcc_cp_function_args *a)
+  {
+    size_t len;
+
+    if (a)
+      len = a->n_elements;
+    else
+      len = (size_t)-1;
+
+    if (!marshall_array_start (conn, 'd', len))
+      return FAIL;
+
+    if (!a)
+      return OK;
+
+    return marshall_array_elmts (conn, len * sizeof (a->elements[0]),
+				 a->elements);
+  }
+
+  // Read a gcc_cp_function_args marker, followed by a
+  // gcc_cp_function_args.  The resulting array must be freed
+  // by the caller, using 'delete[]' on elements and virtualp, and
+  // 'delete' on the array object itself.
+  status
+  unmarshall (connection *conn, struct gcc_cp_function_args **result)
+  {
+    size_t len;
+
+    if (!unmarshall_array_start (conn, 'd', &len))
+      return FAIL;
+
+    if (len == (size_t)-1)
+      {
+	*result = NULL;
+	return OK;
+      }
+
+    struct gcc_cp_function_args *gva = new gcc_cp_function_args;
+
+    gva->n_elements = len;
+    gva->elements = new gcc_expr[len];
+
+    if (!unmarshall_array_elmts (conn,
+				 len * sizeof (gva->elements[0]),
+				 gva->elements))
+      {
+	delete[] gva->elements;
+	delete gva;
+	return FAIL;
+      }
+
+    *result = gva;
+
+    return OK;
+  }
+}
+
+#endif // CC1_PLUGIN_MARSHALL_CP_HH
diff --git a/libcc1/marshall.cc b/libcc1/marshall.cc
index 1f2d284..cf53cf7 100644
--- a/libcc1/marshall.cc
+++ b/libcc1/marshall.cc
@@ -50,36 +50,6 @@  cc1_plugin::unmarshall_intlike (connection *conn, unsigned long long *result)
 }
 
 cc1_plugin::status
-cc1_plugin::unmarshall (connection *conn, enum gcc_c_symbol_kind *result)
-{
-  protocol_int p;
-  if (!unmarshall_intlike (conn, &p))
-    return FAIL;
-  *result = (enum gcc_c_symbol_kind) p;
-  return OK;
-}
-
-cc1_plugin::status
-cc1_plugin::unmarshall (connection *conn, enum gcc_c_oracle_request *result)
-{
-  protocol_int p;
-  if (!unmarshall_intlike (conn, &p))
-    return FAIL;
-  *result = (enum gcc_c_oracle_request) p;
-  return OK;
-}
-
-cc1_plugin::status
-cc1_plugin::unmarshall (connection *conn, enum gcc_qualifiers *result)
-{
-  protocol_int p;
-  if (!unmarshall_intlike (conn, &p))
-    return FAIL;
-  *result = (enum gcc_qualifiers) p;
-  return OK;
-}
-
-cc1_plugin::status
 cc1_plugin::marshall (connection *conn, const char *str)
 {
   if (!conn->send ('s'))
@@ -128,39 +98,98 @@  cc1_plugin::unmarshall (connection *conn, char **result)
 }
 
 cc1_plugin::status
-cc1_plugin::marshall (connection *conn, const gcc_type_array *a)
+cc1_plugin::marshall_array_start (connection *conn, char id,
+				  size_t n_elements)
 {
-  if (!conn->send ('a'))
+  if (!conn->send (id))
     return FAIL;
 
-  unsigned long long r = a->n_elements;
+  unsigned long long r = n_elements;
   if (!conn->send (&r, sizeof (r)))
     return FAIL;
 
-  return conn->send (a->elements, r * sizeof (a->elements[0]));
+  return OK;
 }
 
 cc1_plugin::status
-cc1_plugin::unmarshall (connection *conn, gcc_type_array **result)
+cc1_plugin::marshall_array_elmts (connection *conn, size_t n_bytes,
+				  void *elements)
+{
+  return conn->send (elements, n_bytes);
+}
+
+cc1_plugin::status
+cc1_plugin::unmarshall_array_start (connection *conn, char id,
+				    size_t *n_elements)
 {
   unsigned long long len;
 
-  if (!conn->require ('a'))
+  if (!conn->require (id))
     return FAIL;
   if (!conn->get (&len, sizeof (len)))
     return FAIL;
 
-  *result = new gcc_type_array;
+  *n_elements = len;
+
+  return OK;
+}
+
+cc1_plugin::status
+cc1_plugin::unmarshall_array_elmts (connection *conn, size_t n_bytes,
+				    void *elements)
+{
+  return conn->get (elements, n_bytes);
+}
+
+cc1_plugin::status
+cc1_plugin::marshall (connection *conn, const gcc_type_array *a)
+{
+  size_t len;
+
+  if (a)
+    len = a->n_elements;
+  else
+    len = (size_t)-1;
+
+  if (!marshall_array_start (conn, 'a', len))
+    return FAIL;
+
+  if (!a)
+    return OK;
+
+  return marshall_array_elmts (conn, len * sizeof (a->elements[0]),
+			       a->elements);
+}
+
+cc1_plugin::status
+cc1_plugin::unmarshall (connection *conn, gcc_type_array **result)
+{
+  size_t len;
+
+  if (!unmarshall_array_start (conn, 'a', &len))
+    return FAIL;
+
+  if (len == (size_t)-1)
+    {
+      *result = NULL;
+      return OK;
+    }
+
+  gcc_type_array *gta = new gcc_type_array;
 
-  (*result)->n_elements = len;
-  (*result)->elements = new gcc_type[len];
+  gta->n_elements = len;
+  gta->elements = new gcc_type[len];
 
-  if (!conn->get ((*result)->elements, len * sizeof ((*result)->elements[0])))
+  if (!unmarshall_array_elmts (conn,
+			       len * sizeof (gta->elements[0]),
+			       gta->elements))
     {
-      delete[] (*result)->elements;
+      delete[] gta->elements;
       delete *result;
       return FAIL;
     }
 
+  *result = gta;
+
   return OK;
 }
diff --git a/libcc1/marshall.hh b/libcc1/marshall.hh
index cf539c0..d238f3a 100644
--- a/libcc1/marshall.hh
+++ b/libcc1/marshall.hh
@@ -21,7 +21,7 @@  along with GCC; see the file COPYING3.  If not see
 #define CC1_PLUGIN_MARSHALL_HH
 
 #include "status.hh"
-#include "gcc-c-interface.h"
+#include "gcc-interface.h"
 
 namespace cc1_plugin
 {
@@ -44,6 +44,12 @@  namespace cc1_plugin
   // integer store it in the out argument.
   status unmarshall_intlike (connection *, protocol_int *);
 
+  status marshall_array_start (connection *, char, size_t);
+  status marshall_array_elmts (connection *, size_t, void *);
+
+  status unmarshall_array_start (connection *, char, size_t *);
+  status unmarshall_array_elmts (connection *, size_t, void *);
+
   // A template function that can handle marshalling various integer
   // objects to the connection.
   template<typename T>
@@ -67,13 +73,6 @@  namespace cc1_plugin
     return OK;
   }
 
-  // Unmarshallers for some specific enum types.  With C++11 we
-  // wouldn't need these, as we could add type traits to the scalar
-  // unmarshaller.
-  status unmarshall (connection *, enum gcc_c_symbol_kind *);
-  status unmarshall (connection *, enum gcc_qualifiers *);
-  status unmarshall (connection *, enum gcc_c_oracle_request *);
-
   // Send a string type marker followed by a string.
   status marshall (connection *, const char *);
 
diff --git a/libcc1/names.cc b/libcc1/names.cc
index 2ac1fb4..3cd1a1b 100644
--- a/libcc1/names.cc
+++ b/libcc1/names.cc
@@ -21,21 +21,27 @@  along with GCC; see the file COPYING3.  If not see
 #include "names.hh"
 
 #define GCC_METHOD0(R, N) \
-  const char *cc1_plugin::N = # N;
+  const char *cc1_plugin::LANG::N = # N;
 #define GCC_METHOD1(R, N, A) \
-  const char *cc1_plugin::N = # N;
+  const char *cc1_plugin::LANG::N = # N;
 #define GCC_METHOD2(R, N, A, B) \
-  const char *cc1_plugin::N = # N;
+  const char *cc1_plugin::LANG::N = # N;
 #define GCC_METHOD3(R, N, A, B, C) \
-  const char *cc1_plugin::N = # N;
+  const char *cc1_plugin::LANG::N = # N;
 #define GCC_METHOD4(R, N, A, B, C, D) \
-  const char *cc1_plugin::N = # N;
+  const char *cc1_plugin::LANG::N = # N;
 #define GCC_METHOD5(R, N, A, B, C, D, E) \
-  const char *cc1_plugin::N = # N;
+  const char *cc1_plugin::LANG::N = # N;
 #define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \
-  const char *cc1_plugin::N = # N;
+  const char *cc1_plugin::LANG::N = # N;
 
+#define LANG c
 #include "gcc-c-fe.def"
+#undef LANG
+
+#define LANG cp
+#include "gcc-cp-fe.def"
+#undef LANG
 
 #undef GCC_METHOD0
 #undef GCC_METHOD1
diff --git a/libcc1/names.hh b/libcc1/names.hh
index 79069c3..d358e69 100644
--- a/libcc1/names.hh
+++ b/libcc1/names.hh
@@ -22,10 +22,6 @@  along with GCC; see the file COPYING3.  If not see
 
 namespace cc1_plugin
 {
-  // This code defines global string constants, one for each method in
-  // gcc-c-fe.def.  This is needed so that they can be used as
-  // template arguments elsewhere.
-
 #define GCC_METHOD0(R, N) \
   extern const char *N;
 #define GCC_METHOD1(R, N, A) \
@@ -41,7 +37,21 @@  namespace cc1_plugin
 #define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \
   extern const char *N;
 
+  namespace c
+  {
+  // This code defines global string constants, one for each method in
+  // gcc-c-fe.def.  This is needed so that they can be used as
+  // template arguments elsewhere.
 #include "gcc-c-fe.def"
+  }
+
+  namespace cp
+  {
+  // This code defines global string constants, one for each method in
+  // gcc-cp-fe.def.  This is needed so that they can be used as
+  // template arguments elsewhere.
+#include "gcc-cp-fe.def"
+  }
 
 #undef GCC_METHOD0
 #undef GCC_METHOD1
diff --git a/libcc1/plugin.cc b/libcc1/plugin.cc
deleted file mode 100644
index a30cc6b..0000000
--- a/libcc1/plugin.cc
+++ /dev/null
@@ -1,921 +0,0 @@ 
-/* Library interface to C front end
-   Copyright (C) 2014-2017 Free Software Foundation, Inc.
-
-   This file is part of GCC.
-
-   GCC 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, or (at your option) any later
-   version.
-
-   GCC 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 GCC; see the file COPYING3.  If not see
-   <http://www.gnu.org/licenses/>.  */
-
-#include <cc1plugin-config.h>
-
-#undef PACKAGE_NAME
-#undef PACKAGE_STRING
-#undef PACKAGE_TARNAME
-#undef PACKAGE_VERSION
-
-#include "../gcc/config.h"
-
-#undef PACKAGE_NAME
-#undef PACKAGE_STRING
-#undef PACKAGE_TARNAME
-#undef PACKAGE_VERSION
-
-#include "gcc-plugin.h"
-#include "system.h"
-#include "coretypes.h"
-#include "stringpool.h"
-
-#include "gcc-interface.h"
-#include "hash-set.h"
-#include "machmode.h"
-#include "vec.h"
-#include "double-int.h"
-#include "input.h"
-#include "alias.h"
-#include "symtab.h"
-#include "options.h"
-#include "wide-int.h"
-#include "inchash.h"
-#include "tree.h"
-#include "fold-const.h"
-#include "stor-layout.h"
-#include "c-tree.h"
-#include "toplev.h"
-#include "timevar.h"
-#include "hash-table.h"
-#include "tm.h"
-#include "c-family/c-pragma.h"
-#include "c-lang.h"
-#include "diagnostic.h"
-#include "langhooks.h"
-#include "langhooks-def.h"
-
-#include "callbacks.hh"
-#include "connection.hh"
-#include "rpc.hh"
-
-#ifdef __GNUC__
-#pragma GCC visibility push(default)
-#endif
-int plugin_is_GPL_compatible;
-#ifdef __GNUC__
-#pragma GCC visibility pop
-#endif
-
-
-
-// This is put into the lang hooks when the plugin starts.
-
-static void
-plugin_print_error_function (diagnostic_context *context, const char *file,
-			     diagnostic_info *diagnostic)
-{
-  if (current_function_decl != NULL_TREE
-      && DECL_NAME (current_function_decl) != NULL_TREE
-      && strcmp (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),
-		 GCC_FE_WRAPPER_FUNCTION) == 0)
-    return;
-  lhd_print_error_function (context, file, diagnostic);
-}
-
-
-
-static unsigned long long
-convert_out (tree t)
-{
-  return (unsigned long long) (uintptr_t) t;
-}
-
-static tree
-convert_in (unsigned long long v)
-{
-  return (tree) (uintptr_t) v;
-}
-
-
-
-struct decl_addr_value
-{
-  tree decl;
-  tree address;
-};
-
-struct decl_addr_hasher : free_ptr_hash<decl_addr_value>
-{
-  static inline hashval_t hash (const decl_addr_value *);
-  static inline bool equal (const decl_addr_value *, const decl_addr_value *);
-};
-
-inline hashval_t
-decl_addr_hasher::hash (const decl_addr_value *e)
-{
-  return IDENTIFIER_HASH_VALUE (DECL_NAME (e->decl));
-}
-
-inline bool
-decl_addr_hasher::equal (const decl_addr_value *p1, const decl_addr_value *p2)
-{
-  return p1->decl == p2->decl;
-}
-
-
-
-struct string_hasher : nofree_ptr_hash<const char>
-{
-  static inline hashval_t hash (const char *s)
-  {
-    return htab_hash_string (s);
-  }
-
-  static inline bool equal (const char *p1, const char *p2)
-  {
-    return strcmp (p1, p2) == 0;
-  }
-};
-
-
-
-// A wrapper for pushdecl that doesn't let gdb have a chance to
-// instantiate a symbol.
-
-static void
-pushdecl_safe (tree decl)
-{
-  void (*save) (enum c_oracle_request, tree identifier);
-
-  save = c_binding_oracle;
-  c_binding_oracle = NULL;
-  pushdecl (decl);
-  c_binding_oracle = save;
-}
-
-
-
-struct plugin_context : public cc1_plugin::connection
-{
-  plugin_context (int fd);
-
-  // Map decls to addresses.
-  hash_table<decl_addr_hasher> address_map;
-
-  // A collection of trees that are preserved for the GC.
-  hash_table< nofree_ptr_hash<tree_node> > preserved;
-
-  // File name cache.
-  hash_table<string_hasher> file_names;
-
-  // Perform GC marking.
-  void mark ();
-
-  // Preserve a tree during the plugin's operation.
-  tree preserve (tree t)
-  {
-    tree_node **slot = preserved.find_slot (t, INSERT);
-    *slot = t;
-    return t;
-  }
-
-  source_location get_source_location (const char *filename,
-				       unsigned int line_number)
-  {
-    if (filename == NULL)
-      return UNKNOWN_LOCATION;
-
-    filename = intern_filename (filename);
-    linemap_add (line_table, LC_ENTER, false, filename, line_number);
-    source_location loc = linemap_line_start (line_table, line_number, 0);
-    linemap_add (line_table, LC_LEAVE, false, NULL, 0);
-    return loc;
-  }
-
-private:
-
-  // Add a file name to FILE_NAMES and return the canonical copy.
-  const char *intern_filename (const char *filename)
-  {
-    const char **slot = file_names.find_slot (filename, INSERT);
-    if (*slot == NULL)
-      {
-	/* The file name must live as long as the line map, which
-	   effectively means as long as this compilation.  So, we copy
-	   the string here but never free it.  */
-	*slot = xstrdup (filename);
-      }
-    return *slot;
-  }
-};
-
-static plugin_context *current_context;
-
-
-
-plugin_context::plugin_context (int fd)
-  : cc1_plugin::connection (fd),
-    address_map (30),
-    preserved (30),
-    file_names (30)
-{
-}
-
-void
-plugin_context::mark ()
-{
-  for (hash_table<decl_addr_hasher>::iterator it = address_map.begin ();
-       it != address_map.end ();
-       ++it)
-    {
-      ggc_mark ((*it)->decl);
-      ggc_mark ((*it)->address);
-    }
-
-  for (hash_table< nofree_ptr_hash<tree_node> >::iterator
-	 it = preserved.begin (); it != preserved.end (); ++it)
-    ggc_mark (&*it);
-}
-
-static void
-plugin_binding_oracle (enum c_oracle_request kind, tree identifier)
-{
-  enum gcc_c_oracle_request request;
-
-  gcc_assert (current_context != NULL);
-
-  switch (kind)
-    {
-    case C_ORACLE_SYMBOL:
-      request = GCC_C_ORACLE_SYMBOL;
-      break;
-    case C_ORACLE_TAG:
-      request = GCC_C_ORACLE_TAG;
-      break;
-    case C_ORACLE_LABEL:
-      request = GCC_C_ORACLE_LABEL;
-      break;
-    default:
-      abort ();
-    }
-
-  int ignore;
-  cc1_plugin::call (current_context, "binding_oracle", &ignore,
-		    request, IDENTIFIER_POINTER (identifier));
-}
-
-static void
-plugin_pragma_user_expression (cpp_reader *)
-{
-  c_binding_oracle = plugin_binding_oracle;
-}
-
-static void
-plugin_init_extra_pragmas (void *, void *)
-{
-  c_register_pragma ("GCC", "user_expression", plugin_pragma_user_expression);
-}
-
-
-
-// Maybe rewrite a decl to its address.
-static tree
-address_rewriter (tree *in, int *walk_subtrees, void *arg)
-{
-  plugin_context *ctx = (plugin_context *) arg;
-
-  if (!DECL_P (*in) || DECL_NAME (*in) == NULL_TREE)
-    return NULL_TREE;
-
-  decl_addr_value value;
-  value.decl = *in;
-  decl_addr_value *found_value = ctx->address_map.find (&value);
-  if (found_value != NULL)
-    {
-      // At this point we don't need VLA sizes for gdb-supplied
-      // variables, and having them here confuses later passes, so we
-      // drop them.
-      if (C_TYPE_VARIABLE_SIZE (TREE_TYPE (*in)))
-	{
-	  TREE_TYPE (*in)
-	    = build_array_type_nelts (TREE_TYPE (TREE_TYPE (*in)), 1);
-	  DECL_SIZE (*in) = TYPE_SIZE (TREE_TYPE (*in));
-	  DECL_SIZE_UNIT (*in) = TYPE_SIZE_UNIT (TREE_TYPE (*in));
-	}
-    }
-  else if (DECL_IS_BUILTIN (*in))
-    {
-      gcc_address address;
-
-      if (!cc1_plugin::call (ctx, "address_oracle", &address,
-			     IDENTIFIER_POINTER (DECL_NAME (*in))))
-	return NULL_TREE;
-      if (address == 0)
-	return NULL_TREE;
-
-      // Insert the decl into the address map in case it is referenced
-      // again.
-      value.address = build_int_cst_type (ptr_type_node, address);
-      decl_addr_value **slot = ctx->address_map.find_slot (&value, INSERT);
-      gcc_assert (*slot == NULL);
-      *slot
-	= static_cast<decl_addr_value *> (xmalloc (sizeof (decl_addr_value)));
-      **slot = value;
-      found_value = *slot;
-    }
-  else
-    return NULL_TREE;
-
-  if (found_value->address != error_mark_node)
-    {
-      // We have an address for the decl, so rewrite the tree.
-      tree ptr_type = build_pointer_type (TREE_TYPE (*in));
-      *in = fold_build1 (INDIRECT_REF, TREE_TYPE (*in),
-			 fold_build1 (CONVERT_EXPR, ptr_type,
-				      found_value->address));
-    }
-
-  *walk_subtrees = 0;
-
-  return NULL_TREE;
-}
-
-// When generating code for gdb, we want to be able to use absolute
-// addresses to refer to otherwise external objects that gdb knows
-// about.  gdb passes in these addresses when building decls, and then
-// before gimplification we go through the trees, rewriting uses to
-// the equivalent of "*(TYPE *) ADDR".
-static void
-rewrite_decls_to_addresses (void *function_in, void *)
-{
-  tree function = (tree) function_in;
-
-  // Do nothing if we're not in gdb.
-  if (current_context == NULL)
-    return;
-
-  walk_tree (&DECL_SAVED_TREE (function), address_rewriter, current_context,
-	     NULL);
-}
-
-
-
-gcc_decl
-plugin_build_decl (cc1_plugin::connection *self,
-		   const char *name,
-		   enum gcc_c_symbol_kind sym_kind,
-		   gcc_type sym_type_in,
-		   const char *substitution_name,
-		   gcc_address address,
-		   const char *filename,
-		   unsigned int line_number)
-{
-  plugin_context *ctx = static_cast<plugin_context *> (self);
-  tree identifier = get_identifier (name);
-  enum tree_code code;
-  tree decl;
-  tree sym_type = convert_in (sym_type_in);
-
-  switch (sym_kind)
-    {
-    case GCC_C_SYMBOL_FUNCTION:
-      code = FUNCTION_DECL;
-      break;
-
-    case GCC_C_SYMBOL_VARIABLE:
-      code = VAR_DECL;
-      break;
-
-    case GCC_C_SYMBOL_TYPEDEF:
-      code = TYPE_DECL;
-      break;
-
-    case GCC_C_SYMBOL_LABEL:
-      // FIXME: we aren't ready to handle labels yet.
-      // It isn't clear how to translate them properly
-      // and in any case a "goto" isn't likely to work.
-      return convert_out (error_mark_node);
-
-    default:
-      abort ();
-    }
-
-  source_location loc = ctx->get_source_location (filename, line_number);
-
-  decl = build_decl (loc, code, identifier, sym_type);
-  TREE_USED (decl) = 1;
-  TREE_ADDRESSABLE (decl) = 1;
-
-  if (sym_kind != GCC_C_SYMBOL_TYPEDEF)
-    {
-      decl_addr_value value;
-
-      value.decl = decl;
-      if (substitution_name != NULL)
-	{
-	  // If the translator gave us a name without a binding,
-	  // we can just substitute error_mark_node, since we know the
-	  // translator will be reporting an error anyhow.
-	  value.address
-	    = lookup_name (get_identifier (substitution_name));
-	  if (value.address == NULL_TREE)
-	    value.address = error_mark_node;
-	}
-      else
-	value.address = build_int_cst_type (ptr_type_node, address);
-      decl_addr_value **slot = ctx->address_map.find_slot (&value, INSERT);
-      gcc_assert (*slot == NULL);
-      *slot
-	= static_cast<decl_addr_value *> (xmalloc (sizeof (decl_addr_value)));
-      **slot = value;
-    }
-
-  return convert_out (ctx->preserve (decl));
-}
-
-int
-plugin_bind (cc1_plugin::connection *,
-	     gcc_decl decl_in, int is_global)
-{
-  tree decl = convert_in (decl_in);
-  c_bind (DECL_SOURCE_LOCATION (decl), decl, is_global);
-  rest_of_decl_compilation (decl, is_global, 0);
-  return 1;
-}
-
-int
-plugin_tagbind (cc1_plugin::connection *self,
-		const char *name, gcc_type tagged_type,
-		const char *filename, unsigned int line_number)
-{
-  plugin_context *ctx = static_cast<plugin_context *> (self);
-  c_pushtag (ctx->get_source_location (filename, line_number),
-	     get_identifier (name), convert_in (tagged_type));
-  return 1;
-}
-
-gcc_type
-plugin_build_pointer_type (cc1_plugin::connection *,
-			   gcc_type base_type)
-{
-  // No need to preserve a pointer type as the base type is preserved.
-  return convert_out (build_pointer_type (convert_in (base_type)));
-}
-
-gcc_type
-plugin_build_record_type (cc1_plugin::connection *self)
-{
-  plugin_context *ctx = static_cast<plugin_context *> (self);
-  return convert_out (ctx->preserve (make_node (RECORD_TYPE)));
-}
-
-gcc_type
-plugin_build_union_type (cc1_plugin::connection *self)
-{
-  plugin_context *ctx = static_cast<plugin_context *> (self);
-  return convert_out (ctx->preserve (make_node (UNION_TYPE)));
-}
-
-int
-plugin_build_add_field (cc1_plugin::connection *,
-			gcc_type record_or_union_type_in,
-			const char *field_name,
-			gcc_type field_type_in,
-			unsigned long bitsize,
-			unsigned long bitpos)
-{
-  tree record_or_union_type = convert_in (record_or_union_type_in);
-  tree field_type = convert_in (field_type_in);
-
-  gcc_assert (TREE_CODE (record_or_union_type) == RECORD_TYPE
-	      || TREE_CODE (record_or_union_type) == UNION_TYPE);
-
-  /* Note that gdb does not preserve the location of field decls, so
-     we can't provide a decent location here.  */
-  tree decl = build_decl (BUILTINS_LOCATION, FIELD_DECL,
-			  get_identifier (field_name), field_type);
-  DECL_FIELD_CONTEXT (decl) = record_or_union_type;
-
-  if (TREE_CODE (field_type) == INTEGER_TYPE
-      && TYPE_PRECISION (field_type) != bitsize)
-    {
-      DECL_BIT_FIELD_TYPE (decl) = field_type;
-      TREE_TYPE (decl)
-	= c_build_bitfield_integer_type (bitsize, TYPE_UNSIGNED (field_type));
-    }
-
-  SET_DECL_MODE (decl, TYPE_MODE (TREE_TYPE (decl)));
-
-  // There's no way to recover this from DWARF.
-  SET_DECL_OFFSET_ALIGN (decl, TYPE_PRECISION (pointer_sized_int_node));
-
-  tree pos = bitsize_int (bitpos);
-  pos_from_bit (&DECL_FIELD_OFFSET (decl), &DECL_FIELD_BIT_OFFSET (decl),
-		DECL_OFFSET_ALIGN (decl), pos);
-
-  DECL_SIZE (decl) = bitsize_int (bitsize);
-  DECL_SIZE_UNIT (decl) = size_int ((bitsize + BITS_PER_UNIT - 1)
-				    / BITS_PER_UNIT);
-
-  DECL_CHAIN (decl) = TYPE_FIELDS (record_or_union_type);
-  TYPE_FIELDS (record_or_union_type) = decl;
-
-  return 1;
-}
-
-int
-plugin_finish_record_or_union (cc1_plugin::connection *,
-			       gcc_type record_or_union_type_in,
-			       unsigned long size_in_bytes)
-{
-  tree record_or_union_type = convert_in (record_or_union_type_in);
-
-  gcc_assert (TREE_CODE (record_or_union_type) == RECORD_TYPE
-	      || TREE_CODE (record_or_union_type) == UNION_TYPE);
-
-  /* We built the field list in reverse order, so fix it now.  */
-  TYPE_FIELDS (record_or_union_type)
-    = nreverse (TYPE_FIELDS (record_or_union_type));
-
-  if (TREE_CODE (record_or_union_type) == UNION_TYPE)
-    {
-      /* Unions can just be handled by the generic code.  */
-      layout_type (record_or_union_type);
-    }
-  else
-    {
-      // FIXME there's no way to get this from DWARF,
-      // or even, it seems, a particularly good way to deduce it.
-      SET_TYPE_ALIGN (record_or_union_type,
-		      TYPE_PRECISION (pointer_sized_int_node));
-
-      TYPE_SIZE (record_or_union_type) = bitsize_int (size_in_bytes
-						      * BITS_PER_UNIT);
-      TYPE_SIZE_UNIT (record_or_union_type) = size_int (size_in_bytes);
-
-      compute_record_mode (record_or_union_type);
-      finish_bitfield_layout (record_or_union_type);
-      // FIXME we have no idea about TYPE_PACKED
-    }
-
-  return 1;
-}
-
-gcc_type
-plugin_build_enum_type (cc1_plugin::connection *self,
-			gcc_type underlying_int_type_in)
-{
-  tree underlying_int_type = convert_in (underlying_int_type_in);
-
-  if (underlying_int_type == error_mark_node)
-    return convert_out (error_mark_node);
-
-  tree result = make_node (ENUMERAL_TYPE);
-
-  TYPE_PRECISION (result) = TYPE_PRECISION (underlying_int_type);
-  TYPE_UNSIGNED (result) = TYPE_UNSIGNED (underlying_int_type);
-
-  plugin_context *ctx = static_cast<plugin_context *> (self);
-  return convert_out (ctx->preserve (result));
-}
-
-int
-plugin_build_add_enum_constant (cc1_plugin::connection *,
-				gcc_type enum_type_in,
-				const char *name,
-				unsigned long value)
-{
-  tree cst, decl, cons;
-  tree enum_type = convert_in (enum_type_in);
-
-  gcc_assert (TREE_CODE (enum_type) == ENUMERAL_TYPE);
-
-  cst = build_int_cst (enum_type, value);
-  /* Note that gdb does not preserve the location of enum constants,
-     so we can't provide a decent location here.  */
-  decl = build_decl (BUILTINS_LOCATION, CONST_DECL,
-		     get_identifier (name), enum_type);
-  DECL_INITIAL (decl) = cst;
-  pushdecl_safe (decl);
-
-  cons = tree_cons (DECL_NAME (decl), cst, TYPE_VALUES (enum_type));
-  TYPE_VALUES (enum_type) = cons;
-
-  return 1;
-}
-
-int
-plugin_finish_enum_type (cc1_plugin::connection *,
-			 gcc_type enum_type_in)
-{
-  tree enum_type = convert_in (enum_type_in);
-  tree minnode, maxnode, iter;
-
-  iter = TYPE_VALUES (enum_type);
-  minnode = maxnode = TREE_VALUE (iter);
-  for (iter = TREE_CHAIN (iter);
-       iter != NULL_TREE;
-       iter = TREE_CHAIN (iter))
-    {
-      tree value = TREE_VALUE (iter);
-      if (tree_int_cst_lt (maxnode, value))
-	maxnode = value;
-      if (tree_int_cst_lt (value, minnode))
-	minnode = value;
-    }
-  TYPE_MIN_VALUE (enum_type) = minnode;
-  TYPE_MAX_VALUE (enum_type) = maxnode;
-
-  layout_type (enum_type);
-
-  return 1;
-}
-
-gcc_type
-plugin_build_function_type (cc1_plugin::connection *self,
-			    gcc_type return_type_in,
-			    const struct gcc_type_array *argument_types_in,
-			    int is_varargs)
-{
-  tree *argument_types;
-  tree return_type = convert_in (return_type_in);
-  tree result;
-
-  argument_types = new tree[argument_types_in->n_elements];
-  for (int i = 0; i < argument_types_in->n_elements; ++i)
-    argument_types[i] = convert_in (argument_types_in->elements[i]);
-
-  if (is_varargs)
-    result = build_varargs_function_type_array (return_type,
-						argument_types_in->n_elements,
-						argument_types);
-  else
-    result = build_function_type_array (return_type,
-					argument_types_in->n_elements,
-					argument_types);
-
-  delete[] argument_types;
-
-  plugin_context *ctx = static_cast<plugin_context *> (self);
-  return convert_out (ctx->preserve (result));
-}
-
-gcc_type
-plugin_int_type (cc1_plugin::connection *self,
-		 int is_unsigned, unsigned long size_in_bytes)
-{
-  tree result = c_common_type_for_size (BITS_PER_UNIT * size_in_bytes,
-					is_unsigned);
-  if (result == NULL_TREE)
-    result = error_mark_node;
-  else
-    {
-      plugin_context *ctx = static_cast<plugin_context *> (self);
-      ctx->preserve (result);
-    }
-  return convert_out (result);
-}
-
-gcc_type
-plugin_float_type (cc1_plugin::connection *,
-		   unsigned long size_in_bytes)
-{
-  if (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (float_type_node))
-    return convert_out (float_type_node);
-  if (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (double_type_node))
-    return convert_out (double_type_node);
-  if (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (long_double_type_node))
-    return convert_out (long_double_type_node);
-  return convert_out (error_mark_node);
-}
-
-gcc_type
-plugin_void_type (cc1_plugin::connection *)
-{
-  return convert_out (void_type_node);
-}
-
-gcc_type
-plugin_bool_type (cc1_plugin::connection *)
-{
-  return convert_out (boolean_type_node);
-}
-
-gcc_type
-plugin_build_array_type (cc1_plugin::connection *self,
-			 gcc_type element_type_in, int num_elements)
-{
-  tree element_type = convert_in (element_type_in);
-  tree result;
-
-  if (num_elements == -1)
-    result = build_array_type (element_type, NULL_TREE);
-  else
-    result = build_array_type_nelts (element_type, num_elements);
-
-  plugin_context *ctx = static_cast<plugin_context *> (self);
-  return convert_out (ctx->preserve (result));
-}
-
-gcc_type
-plugin_build_vla_array_type (cc1_plugin::connection *self,
-			     gcc_type element_type_in,
-			     const char *upper_bound_name)
-{
-  tree element_type = convert_in (element_type_in);
-  tree upper_bound = lookup_name (get_identifier (upper_bound_name));
-  tree range = build_index_type (upper_bound);
-
-  tree result = build_array_type (element_type, range);
-  C_TYPE_VARIABLE_SIZE (result) = 1;
-
-  plugin_context *ctx = static_cast<plugin_context *> (self);
-  return convert_out (ctx->preserve (result));
-}
-
-gcc_type
-plugin_build_qualified_type (cc1_plugin::connection *,
-			     gcc_type unqualified_type_in,
-			     enum gcc_qualifiers qualifiers)
-{
-  tree unqualified_type = convert_in (unqualified_type_in);
-  int quals = 0;
-
-  if ((qualifiers & GCC_QUALIFIER_CONST) != 0)
-    quals |= TYPE_QUAL_CONST;
-  if ((qualifiers & GCC_QUALIFIER_VOLATILE) != 0)
-    quals |= TYPE_QUAL_VOLATILE;
-  if ((qualifiers & GCC_QUALIFIER_RESTRICT) != 0)
-    quals |= TYPE_QUAL_RESTRICT;
-
-  return convert_out (build_qualified_type (unqualified_type, quals));
-}
-
-gcc_type
-plugin_build_complex_type (cc1_plugin::connection *self,
-			   gcc_type base_type)
-{
-  plugin_context *ctx = static_cast<plugin_context *> (self);
-  return convert_out (ctx->preserve (build_complex_type (convert_in (base_type))));
-}
-
-gcc_type
-plugin_build_vector_type (cc1_plugin::connection *self,
-			  gcc_type base_type, int nunits)
-{
-  plugin_context *ctx = static_cast<plugin_context *> (self);
-  return convert_out (ctx->preserve (build_vector_type (convert_in (base_type),
-							nunits)));
-}
-
-int
-plugin_build_constant (cc1_plugin::connection *self, gcc_type type_in,
-		       const char *name, unsigned long value,
-		       const char *filename, unsigned int line_number)
-{
-  plugin_context *ctx = static_cast<plugin_context *> (self);
-  tree cst, decl;
-  tree type = convert_in (type_in);
-
-  cst = build_int_cst (type, value);
-  decl = build_decl (ctx->get_source_location (filename, line_number),
-		     CONST_DECL, get_identifier (name), type);
-  DECL_INITIAL (decl) = cst;
-  pushdecl_safe (decl);
-
-  return 1;
-}
-
-gcc_type
-plugin_error (cc1_plugin::connection *,
-	      const char *message)
-{
-  error ("%s", message);
-  return convert_out (error_mark_node);
-}
-
-
-
-// Perform GC marking.
-
-static void
-gc_mark (void *, void *)
-{
-  if (current_context != NULL)
-    current_context->mark ();
-}
-
-#ifdef __GNUC__
-#pragma GCC visibility push(default)
-#endif
-
-int
-plugin_init (struct plugin_name_args *plugin_info,
-	     struct plugin_gcc_version *)
-{
-  long fd = -1;
-  for (int i = 0; i < plugin_info->argc; ++i)
-    {
-      if (strcmp (plugin_info->argv[i].key, "fd") == 0)
-	{
-	  char *tail;
-	  errno = 0;
-	  fd = strtol (plugin_info->argv[i].value, &tail, 0);
-	  if (*tail != '\0' || errno != 0)
-	    fatal_error (input_location,
-			 "%s: invalid file descriptor argument to plugin",
-			 plugin_info->base_name);
-	  break;
-	}
-    }
-  if (fd == -1)
-    fatal_error (input_location,
-		 "%s: required plugin argument %<fd%> is missing",
-		 plugin_info->base_name);
-
-  current_context = new plugin_context (fd);
-
-  // Handshake.
-  cc1_plugin::protocol_int version;
-  if (!current_context->require ('H')
-      || ! ::cc1_plugin::unmarshall (current_context, &version))
-    fatal_error (input_location,
-		 "%s: handshake failed", plugin_info->base_name);
-  if (version != GCC_C_FE_VERSION_0)
-    fatal_error (input_location,
-		 "%s: unknown version in handshake", plugin_info->base_name);
-
-  register_callback (plugin_info->base_name, PLUGIN_PRAGMAS,
-		     plugin_init_extra_pragmas, NULL);
-  register_callback (plugin_info->base_name, PLUGIN_PRE_GENERICIZE,
-		     rewrite_decls_to_addresses, NULL);
-  register_callback (plugin_info->base_name, PLUGIN_GGC_MARKING,
-		     gc_mark, NULL);
-
-  lang_hooks.print_error_function = plugin_print_error_function;
-
-#define GCC_METHOD0(R, N)			\
-  {						\
-    cc1_plugin::callback_ftype *fun		\
-      = cc1_plugin::callback<R, plugin_ ## N>;	\
-    current_context->add_callback (# N, fun);	\
-  }
-#define GCC_METHOD1(R, N, A)				\
-  {							\
-    cc1_plugin::callback_ftype *fun			\
-      = cc1_plugin::callback<R, A, plugin_ ## N>;	\
-    current_context->add_callback (# N, fun);		\
-  }
-#define GCC_METHOD2(R, N, A, B)				\
-  {							\
-    cc1_plugin::callback_ftype *fun			\
-      = cc1_plugin::callback<R, A, B, plugin_ ## N>;	\
-    current_context->add_callback (# N, fun);		\
-  }
-#define GCC_METHOD3(R, N, A, B, C)			\
-  {							\
-    cc1_plugin::callback_ftype *fun			\
-      = cc1_plugin::callback<R, A, B, C, plugin_ ## N>;	\
-    current_context->add_callback (# N, fun);		\
-  }
-#define GCC_METHOD4(R, N, A, B, C, D)		\
-  {						\
-    cc1_plugin::callback_ftype *fun		\
-      = cc1_plugin::callback<R, A, B, C, D,	\
-			     plugin_ ## N>;	\
-    current_context->add_callback (# N, fun);	\
-  }
-#define GCC_METHOD5(R, N, A, B, C, D, E)	\
-  {						\
-    cc1_plugin::callback_ftype *fun		\
-      = cc1_plugin::callback<R, A, B, C, D, E,	\
-			     plugin_ ## N>;	\
-    current_context->add_callback (# N, fun);	\
-  }
-#define GCC_METHOD7(R, N, A, B, C, D, E, F, G)		\
-  {							\
-    cc1_plugin::callback_ftype *fun			\
-      = cc1_plugin::callback<R, A, B, C, D, E, F, G,	\
-			     plugin_ ## N>;		\
-    current_context->add_callback (# N, fun);		\
-  }
-
-#include "gcc-c-fe.def"
-
-#undef GCC_METHOD0
-#undef GCC_METHOD1
-#undef GCC_METHOD2
-#undef GCC_METHOD3
-#undef GCC_METHOD4
-#undef GCC_METHOD5
-#undef GCC_METHOD7
-
-  return 0;
-}
diff --git a/libcc1/rpc.hh b/libcc1/rpc.hh
index 01b793b..56a07c2 100644
--- a/libcc1/rpc.hh
+++ b/libcc1/rpc.hh
@@ -21,7 +21,6 @@  along with GCC; see the file COPYING3.  If not see
 #define CC1_PLUGIN_RPC_HH
 
 #include "status.hh"
-#include "marshall.hh"
 #include "connection.hh"
 
 namespace cc1_plugin
@@ -126,6 +125,118 @@  namespace cc1_plugin
     argument_wrapper &operator= (const argument_wrapper &);
   };
 
+#ifdef GCC_CP_INTERFACE_H
+  // Specialization for gcc_vbase_array.
+  template<>
+  class argument_wrapper<const gcc_vbase_array *>
+  {
+  public:
+    argument_wrapper () : m_object (NULL) { }
+    ~argument_wrapper ()
+    {
+      // It would be nicer if gcc_type_array could have a destructor.
+      // But, it is in code shared with gdb and cannot.
+      if (m_object != NULL)
+	{
+	  delete[] m_object->flags;
+	  delete[] m_object->elements;
+	}
+      delete m_object;
+    }
+
+    operator const gcc_vbase_array * () const
+    {
+      return m_object;
+    }
+
+    status unmarshall (connection *conn)
+    {
+      return ::cc1_plugin::unmarshall (conn, &m_object);
+    }
+
+  private:
+
+    gcc_vbase_array *m_object;
+
+    // No copying or assignment allowed.
+    argument_wrapper (const argument_wrapper &);
+    argument_wrapper &operator= (const argument_wrapper &);
+  };
+
+  // Specialization for gcc_cp_template_args.
+  template<>
+  class argument_wrapper<const gcc_cp_template_args *>
+  {
+  public:
+    argument_wrapper () : m_object (NULL) { }
+    ~argument_wrapper ()
+    {
+      // It would be nicer if gcc_type_array could have a destructor.
+      // But, it is in code shared with gdb and cannot.
+      if (m_object != NULL)
+	{
+	  delete[] m_object->elements;
+	  delete[] m_object->kinds;
+	}
+      delete m_object;
+    }
+
+    operator const gcc_cp_template_args * () const
+    {
+      return m_object;
+    }
+
+    status unmarshall (connection *conn)
+    {
+      return ::cc1_plugin::unmarshall (conn, &m_object);
+    }
+
+  private:
+
+    gcc_cp_template_args *m_object;
+
+    // No copying or assignment allowed.
+    argument_wrapper (const argument_wrapper &);
+    argument_wrapper &operator= (const argument_wrapper &);
+  };
+
+  // Specialization for gcc_cp_function_args.
+  template<>
+  class argument_wrapper<const gcc_cp_function_args *>
+  {
+  public:
+    argument_wrapper () : m_object (NULL) { }
+    ~argument_wrapper ()
+    {
+      // It would be nicer if gcc_type_array could have a destructor.
+      // But, it is in code shared with gdb and cannot.
+      if (m_object != NULL)
+	{
+	  delete[] m_object->elements;
+	}
+      delete m_object;
+    }
+
+    operator const gcc_cp_function_args * () const
+    {
+      return m_object;
+    }
+
+    status unmarshall (connection *conn)
+    {
+      return ::cc1_plugin::unmarshall (conn, &m_object);
+    }
+
+  private:
+
+    gcc_cp_function_args *m_object;
+
+    // No copying or assignment allowed.
+    argument_wrapper (const argument_wrapper &);
+    argument_wrapper &operator= (const argument_wrapper &);
+  };
+#endif /* GCC_CP_INTERFACE_H */
+
   // There are two kinds of template functions here: "call" and
   // "callback".  They are each repeated multiple times to handle
   // different numbers of arguments.  (This would be improved with