Introduce C++ support in libcc1
authorAlexandre Oliva <aoliva@redhat.com>
Tue, 31 Jan 2017 01:02:03 +0000 (01:02 +0000)
committerAlexandre Oliva <aoliva@gcc.gnu.org>
Tue, 31 Jan 2017 01:02:03 +0000 (01:02 +0000)
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/ChangeLog

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/ChangeLog

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.

From-SVN: r245051

39 files changed:
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/friend.c
gcc/cp/init.c
gcc/cp/lambda.c
gcc/cp/lex.c
gcc/cp/method.c
gcc/cp/name-lookup.c
gcc/cp/parser.c
gcc/cp/search.c
gcc/cp/semantics.c
gcc/cp/typeck.c
include/ChangeLog
include/gcc-c-fe.def
include/gcc-c-interface.h
include/gcc-cp-fe.def [new file with mode: 0644]
include/gcc-cp-interface.h [new file with mode: 0644]
include/gcc-interface.h
libcc1/ChangeLog
libcc1/Makefile.am
libcc1/Makefile.in
libcc1/libcc1.cc
libcc1/libcc1.sym
libcc1/libcc1plugin.cc [new file with mode: 0644]
libcc1/libcp1.cc [new file with mode: 0644]
libcc1/libcp1plugin.cc [new file with mode: 0644]
libcc1/libcp1plugin.sym [new file with mode: 0644]
libcc1/marshall-c.hh [new file with mode: 0644]
libcc1/marshall-cp.hh [new file with mode: 0644]
libcc1/marshall.cc
libcc1/marshall.hh
libcc1/names.cc
libcc1/names.hh
libcc1/plugin.cc [deleted file]
libcc1/rpc.hh

index 1f31731bc6919f7bdf3cb59b4ace17ed32311c68..18732c927e3360fce8f5c10ca67d959c13ac8bac 100644 (file)
@@ -1,3 +1,31 @@
+2017-01-30  Alexandre Oliva <aoliva@redhat.com>
+
+       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.
+
 2017-01-27  Jason Merrill  <jason@redhat.com>
 
        PR c++/78771 - ICE with inherited constructor.
index 8030d7ebb0be45d71905f1a73004cd08ef809448..6533214799d1bf40d68cf8b3bd3d104ebd2a4b75 100644 (file)
@@ -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))
@@ -8283,7 +8283,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.  */
@@ -8311,7 +8311,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
index 03a973084e5cff53e213a4c3ee9c220f8ae35226..d99ebcdc7dfd8993070e51857bd9178488ac904a 100644 (file)
@@ -3254,7 +3254,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);
@@ -5349,7 +5349,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);
@@ -5513,7 +5513,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;
@@ -5558,7 +5558,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);
@@ -5679,7 +5679,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.  */
index f412ddd6e4aa2e80b703cf8ef421ee8e686a18fb..a744d8372bff6bbd08ba4a6225880a48469bbce2 100644 (file)
@@ -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);
@@ -6944,6 +6950,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);
@@ -7009,6 +7034,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);
index 44aefd82b73eeaf12bd5cb91695692843632a96e..9bdfd4ff64ba8ad9a5a3827071e5b76d49d50dea 100644 (file)
@@ -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;              \
index a9a1d2286a84dcda45d4f58a5f61e873001361cb..86d98202f0d733f4f595940adf089263cdd75942 100644 (file)
@@ -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);
index 9eec9e488691066aabf2331298cc67dd60326276..3815daef4d5dcce1d6df796f08058779fb78eda3 100644 (file)
@@ -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)
index de43d81ce30264bd0f119999072efde2c065a790..42f1c6192eceeb6f61ba917ef25327662ab9b553 100644 (file)
@@ -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)
index 4d22c3d37d98c365e45500f17aab1a64aefa5ae1..538c80639574bdbd8a104a66b22146e6c081ff81 100644 (file)
@@ -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)
index 60a70e9b325ab2de16f56981583165f83d24708d..ad6318656ad96cae454f8476d9a93e08b1beb23b 100644 (file)
@@ -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
index e80b80606b56e6ad1c449b8c2bd2536715d3016f..941f9a657e49b791432ec9673543c04ad111c74b 100644 (file)
@@ -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).  */
@@ -1949,7 +1949,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);
index 10fb540e1f1ab2ce2405898dedb97384566fdd22..a3cb7eea9072d68863b93c8c502571b29c5cbe8c 100644 (file)
@@ -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;
 }
+
 \f
 /* Subroutines for reverting temporarily to top-level for instantiation
    of templates and such.  We actually need to clear out the class- and
index 7f685506bc176e2a528470459d2440e2b8d15e4a..592f903a6f98be64a289ab3efcd4bf4b2c7f1ad5 100644 (file)
@@ -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:
@@ -31991,21 +31988,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;
index ec8f4ab4ba6c538c5003caffd5301d63785a62a8..09c1b4e6456d24682eb3246de361a4e8354f6ba4 100644 (file)
@@ -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);
index 42b555c5883304f0942830328683ddcb158f4eec..bd91e1832f73f1486ddb40b3cdef2664068b9a1b 100644 (file)
@@ -5107,7 +5107,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";
@@ -9012,7 +9012,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];
@@ -9295,7 +9295,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;
 }
 
index f677b48ee5824fd2c9d653924f66932555a4d4e9..8f66d3c7933c1475b9e2538512a96f44c61e72a3 100644 (file)
@@ -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;
 
index c1a52dbfca2fc5c9a1ec0e076dfb1f8716c73aa6..43b20717b69dc5f2cc3a428767f0dbf0fd4d60cb 100644 (file)
@@ -1,3 +1,17 @@
+2017-01-30  Alexandre Oliva <aoliva@redhat.com>
+
+       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.
+
 2017-01-30  Jan Kratochvil <jan.kratochvil@redhat.com>
 
        * gcc-interface.h (enum gcc_base_api_version): Update comment
index 09998ba67e75cdad8c08f3aa15d6837e2f73d748..acf1940c0122fbc3579bdc1dcedd23bb745365c9 100644 (file)
@@ -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.  */
+
index 00ccbfb2a75e82f14cc864eb3b31303cedc7f477..e048c863070d6c90cc547a47b6f9e80f7b4a8f33 100644 (file)
@@ -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 (file)
index 0000000..c367c1d
--- /dev/null
@@ -0,0 +1,1050 @@
+/* Interface between GCC C++ FE and GDB  -*- c -*-
+
+   Copyright (C) 2014-2017 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+
+/* Push namespace NAME as the current binding level, to which
+   newly-introduced decls will be bound.  An empty string identifies
+   the global namespace, whereas NULL identifies an anonymous
+   namespace.  A namespace named NAME is created in the current scope,
+   if needed.
+
+   If the newly-created namespace is to be an inline namespace, see
+   make_namespace_inline.  */
+
+GCC_METHOD1 (int /* bool */, push_namespace,
+            const char *)            /* Argument NAME.  */
+
+/* Push TYPE as the current binding level, making its members visible
+   for name lookup.  The current scope before the call must be the
+   scope in which the class was declared.  This should be used if the
+   definition of a class is already finished, but one wishes to define
+   a nested class, or to enter the scope of one of its member
+   functions.  */
+
+GCC_METHOD1 (int /* bool */, push_class,
+            gcc_type)          /* Argument TYPE.  */
+
+/* Push FUNCTION_DECL as the current (empty) binding level (see
+   reactivate_decl).  The current enclosing scope before the call must
+   be the scope in which the function was declared.  */
+
+GCC_METHOD1 (int /* bool */, push_function,
+            gcc_decl)       /* Argument FUNCTION_DECL.  */
+
+/* Make DECL visible (again?) within SCOPE.  When SCOPE is NULL, it
+   means the current scope; if it is not NULL, it must name a function
+   that is currently active, even if not at the top of the binding
+   chain.
+
+   This function can be used to make e.g. a global function or
+   variable visible in a namespace or local scope (overriding another
+   enclosing definition of the same name), but its most common
+   expected use of this primitive, that gives it its name, is to make
+   declarations visible again after reentering a function scope,
+   because when a function is entered with push_function, that does
+   NOT make any of the declarations nested in it visible for name
+   lookup.
+
+   There is a reason/excuse for that: unlike namespaces and classes,
+   G++ doesn't ever have to reenter function scopes, so its name
+   resolution infrastructure is not prepared to do that.  But wait,
+   there is also a good use for this apparent limitation: a function
+   may contain multiple scopes (blocks), and the name may be bound to
+   different symbols in each of these scopes.  With this interface, as
+   we reenter a function scope, we may choose which symbols to make
+   visible for the code snippet, or, if there could be template
+   functions in local scopes, for unresolved names in nested template
+   class default arguments, or in nested template function signatures.
+
+   As for making a local declaration visible for the code snippet,
+   there are two possibilities: a) introduce it upfront, while
+   entering the scope for the user expression (see the enter_scope
+   callback, called by g++ when encountering the push_user_expression
+   pragma), which might save some scope switching and reactivate_decl
+   (though this can't be helped if some declarations have to be
+   introduced and discarded, because of multiple definitions of the
+   same name in different scopes within a function: they have to be
+   defined in discriminator order); or b) introduce it when its name
+   is looked up, entering the scope, introducing the declaration,
+   leaving the scope, and then reactivating the declaration in its
+   local scope.
+
+   Here's some more detail on how reactivate_decl works.  Say there's
+   a function foo whose body looks like this:
+
+   {
+     {
+// point 1
+       class c {} o __attribute__ ((__used__)); // c  , o
+     }
+     struct c {
+       void f() {
+// point 2
+       }
+     } o __attribute__ ((__used__));            // c_0, o_0
+     {
+       class c {} p __attribute__ ((__used__)); // c_1, p
+// point 3
+       o.f();
+     }
+   }
+
+   When we are about to define class c at point 1, we enter the
+   function foo scope, and since no symbols are visible at point 1, we
+   proceed to declare class c.  We may then define the class right
+   away, or, if we leave the function scope, and we later wish to
+   define it, or to define object o, we can reenter the scope and just
+   use the previously-obtained gcc_decl to define the class, without
+   having to reactivate the declaration.
+
+   Now, if we are to set up the binding context for point 2, we have
+   to define c_0::f, and in order to do so, we have to declare and
+   define c_0.  Before we can declare c_0, we MUST at least declare c.
+
+     As a general rule, before we can declare or define any local name
+     with a discriminator, we have to at least declare any other
+     occurrences of the same name in the same enclosing entity with
+     lower or absent discriminator.
+
+   So, we declare c, then we leave the function scope and reenter it
+   so as to declare c_0 (also with name "c", which is why we have to
+   leave and reenter the function scope, otherwise we would get an
+   error because of the duplicate definition; g++ will assign a
+   discriminator because it still remembers there was an earlier
+   declaration of c_0 within the function, it's just no longer in
+   scope), then we can define c_0, including its member function f.
+
+   Likewise, if we wish to define o_0, we have to define o first.  If
+   we wish to declare (and maybe then define) c_1, we have to at least
+   declare (c and then) c_0 first.
+
+   Then, as we set up the binding context to compile a code snippet at
+   point 3, we may choose to activate c_1, o_0 and p upfront,
+   declaring and discarding c, c_0 and o, and then reentering the
+   funciton scope to declare c_1, o_0 and p; or we can wait for oracle
+   lookups of c, o or p.  If c is looked up, and the debugger resolves
+   c in the scope to c_1, it is expected to enter the function scope
+   from the top level, declare c, leave it, reenter it, declare c_0,
+   leave it, reenter it, declare c_1, leave it, and then reactivate
+   c_1 in the function scope.  If c_1 is needed as a complete type,
+   the definition may be given right after the declaration, or the
+   scope will have to be reentered in order to define the class.
+
+.  If the code snippet is at point 2, we don't need to (re)activate
+   any declaration: nothing from any local scope is visible.  Just
+   entering the scope of the class containing member function f
+   reactivates the names of its members, including the class name
+   itself.  */
+
+GCC_METHOD2 (int /* bool */, reactivate_decl,
+            gcc_decl,          /* Argument DECL.  */
+            gcc_decl)          /* Argument SCOPE.  */
+
+/* Pop the namespace last entered with push_namespace, or class last
+   entered with push_class, or function last entered with
+   push_function, restoring the binding level in effect before the
+   matching push_* call.  */
+
+GCC_METHOD0 (int /* bool */, pop_binding_level)
+
+/* Return the NAMESPACE_DECL, TYPE_DECL or FUNCTION_DECL of the
+   binding level that would be popped by pop_scope.  */
+
+GCC_METHOD0 (gcc_decl, get_current_binding_level_decl)
+
+/* Make the current binding level an inline namespace.  It must be a
+   namespace to begin with.  It is safe to call this more than once
+   for the same namespace, but after the first call, subsequent ones
+   will not return a success status.  */
+
+GCC_METHOD0 (int /* bool */, make_namespace_inline)
+
+/* Add USED_NS to the namespaces used by the current binding level.
+   Use get_current_binding_level_decl to obtain USED_NS's
+   gcc_decl.  */
+
+GCC_METHOD1 (int /* bool */, add_using_namespace,
+            gcc_decl)                  /* Argument USED_NS.  */
+
+/* Introduce a namespace alias declaration, as in:
+
+   namespace foo = [... ::] bar;
+
+   After this call, namespace TARGET will be visible as ALIAS within
+   the current namespace.  Get the declaration for TARGET by calling
+   get_current_binding_level_decl after pushing into it.  */
+
+GCC_METHOD2 (int /* bool */, add_namespace_alias,
+            const char *,              /* Argument ALIAS.  */
+            gcc_decl)                  /* Argument TARGET.  */
+
+/* Introduce a using declaration, as in:
+
+   using foo::bar;
+
+   The TARGET decl names the qualifying scope (foo:: above) and the
+   identifier (bar), but that does not mean that only TARGET will be
+   brought into the current scope: all bindings of TARGET's identifier
+   in the qualifying scope will be brought in.
+
+   FLAGS should specify GCC_CP_SYMBOL_USING.  If the current scope is
+   a class scope, visibility flags must be supplied.
+
+   Even when TARGET is template dependent, we don't need to specify
+   whether or not it is a typename: the supplied declaration (that
+   could be a template-dependent type converted to declaration by
+   get_type_decl) indicates so.  */
+
+GCC_METHOD2 (int /* bool */, add_using_decl,
+            enum gcc_cp_symbol_kind, /* Argument FLAGS.  */
+            gcc_decl)                /* Argument TARGET.  */
+
+/* Create a new "decl" in GCC, and bind it in the current binding
+   level.  A decl is a declaration, basically a kind of symbol.
+
+   NAME is the name of the new symbol.  SYM_KIND is the kind of
+   symbol being requested.  SYM_TYPE is the new symbol's C++ type;
+   except for labels, where this is not meaningful and should be
+   zero.  If SUBSTITUTION_NAME is not NULL, then a reference to this
+   decl in the source will later be substituted with a dereference
+   of a variable of the given name.  Otherwise, for symbols having
+   an address (e.g., functions), ADDRESS is the address.  FILENAME
+   and LINE_NUMBER refer to the symbol's source location.  If this
+   is not known, FILENAME can be NULL and LINE_NUMBER can be 0.
+   This function returns the new decl.
+
+   Use this function to register typedefs, functions and variables to
+   namespace and local binding levels, and typedefs, member functions
+   (static or not), and static data members to class binding levels.
+   Class members must have their access controls specified with
+   GCC_CP_ACCESS_* flags in SYM_KIND.
+
+   Note that, since access controls are disabled, we have no means to
+   express private, protected and public.
+
+   There are various flags that can be set in SYM_KIND to specify
+   additional semantics.  Look for GCC_CP_FLAGs in the definition of
+   enum gcc_cp_symbol_kind in gcc-cp-interface.h.
+
+   In order to define member functions, pass GCC_CP_SYMBOL_FUNCTION in
+   SYM_KIND, and a function_type for static member functions or a
+   method type for non-static member functions, including constructors
+   and destructors.  Use build_function_type to create a function
+   type; for a method type, start by creating a function type without
+   any compiler-introduced artificial arguments (the implicit this
+   pointer, and the __in_chrg added to constructors and destructors,
+   and __vtt_parm added to the former), and then use build_method_type
+   to create the method type out of the class type and the function
+   type.
+
+   For operator functions, set GCC_CP_FLAG_SPECIAL_FUNCTION in
+   SYM_KIND, in addition to any other applicable flags, and pass as
+   NAME a string starting with the two-character mangling for operator
+   name: "ps" for unary plus, "mL" for multiply and assign, *=; etc.
+   Use "cv" for type converstion operators (the target type portion
+   may be omitted, as it is taken from the return type in SYM_TYPE).
+   For operator"", use "li" followed by the identifier (the mangled
+   name mandates digits specifying the length of the identifier; if
+   present, they determine the end of the identifier, otherwise, the
+   identifier extents to the end of the string, so that "li3_Kme" and
+   "li_Km" are equivalent).
+
+   Constructors and destructors need special care, because for each
+   constructor and destructor there may be multiple clones defined
+   internally by the compiler.  With build_decl, you can introduce the
+   base declaration of a constructor or a destructor, setting
+   GCC_CP_FLAG_SPECIAL_FUNCTION the flag and using names starting with
+   capital "C" or "D", respectively, followed by a digit (see below),
+   a blank, or NUL ('\0').  DO NOT supply an ADDRESS or a
+   SUBSTITUTION_NAME to build_decl, it would be meaningless (and
+   rejected) for the base declaration; use define_cdtor_clone to
+   introduce the address of each clone.  For constructor templates,
+   declare the template with build_decl, and then, for each
+   specialization, introduce it with
+   build_function_template_specialization, and then define the
+   addresses of each of its clones with define_cdtor_clone.
+
+   NAMEs for GCC_CP_FLAG_SPECIAL_FUNCTION:
+
+     NAME    meaning
+     C?      constructor base declaration (? may be 1, 2, 4, blank or NUL)
+     D?      destructor base declaration (? may be 0, 1, 2, 4, blank or NUL)
+     nw      operator new
+     na      operator new[]
+     dl      operator delete
+     da      operator delete[]
+     ps      operator + (unary)
+     ng      operator - (unary)
+     ad      operator & (unary)
+     de      operator * (unary)
+     co      operator ~
+     pl      operator +
+     mi      operator -
+     ml      operator *
+     dv      operator /
+     rm      operator %
+     an      operator &
+     or      operator |
+     eo      operator ^
+     aS      operator =
+     pL      operator +=
+     mI      operator -=
+     mL      operator *=
+     dV      operator /=
+     rM      operator %=
+     aN      operator &=
+     oR      operator |=
+     eO      operator ^=
+     ls      operator <<
+     rs      operator >>
+     lS      operator <<=
+     rS      operator >>=
+     eq      operator ==
+     ne      operator !=
+     lt      operator <
+     gt      operator >
+     le      operator <=
+     ge      operator >=
+     nt      operator !
+     aa      operator &&
+     oo      operator ||
+     pp      operator ++
+     mm      operator --
+     cm      operator ,
+     pm      operator ->*
+     pt      operator ->
+     cl      operator ()
+     ix      operator []
+     qu      operator ?
+     cv      operator <T> (conversion operator)
+     li<id>  operator "" <id>
+
+   FIXME: How about attributes?  */
+
+GCC_METHOD7 (gcc_decl, build_decl,
+            const char *,            /* Argument NAME.  */
+            enum gcc_cp_symbol_kind, /* Argument SYM_KIND.  */
+            gcc_type,                /* Argument SYM_TYPE.  */
+            const char *,            /* Argument SUBSTITUTION_NAME.  */
+            gcc_address,             /* Argument ADDRESS.  */
+            const char *,            /* Argument FILENAME.  */
+            unsigned int)            /* Argument LINE_NUMBER.  */
+
+/* Supply the ADDRESS of one of the multiple clones of constructor or
+   destructor CDTOR.  The clone is specified by NAME, using the
+   following name mangling conventions:
+
+     C1      in-charge constructor
+     C2      not-in-charge constructor
+     C4      unified constructor
+     D0      deleting destructor
+     D1      in-charge destructor
+     D2      not-in-charge destructor
+     D4      unified destructor
+
+   The following information is not necessary to use the API.
+
+   C1 initializes an instance of the class (rather than of derived
+   classes), including virtual base classes, whereas C2 initializes a
+   sub-object (of the given class type) of an instance of some derived
+   class (or a full object that doesn't have any virtual base
+   classes).
+
+   D0 and D1 destruct an instance of the class, including virtual base
+   classes, but only the former calls operator delete to release the
+   object's storage at the end; D2 destructs a sub-object (of the
+   given class type) of an instance of a derived class (or a full
+   object that doesn't have any virtual base classes).
+
+   The [CD]4 manglings (and symbol definitions) are non-standard, but
+   GCC uses them in some cases: rather than assuming they are
+   in-charge or not-in-charge, they test the implicit argument that
+   the others ignore to tell how to behave.  These are used instead of
+   cloning when we just can't use aliases.  */
+
+GCC_METHOD3 (gcc_decl, define_cdtor_clone,
+            const char *,            /* Argument NAME.  */
+            gcc_decl,                /* Argument CDTOR.  */
+            gcc_address)             /* Argument ADDRESS.  */
+
+/* Return the type associated with the given declaration.  This is
+   most useful to obtain the type associated with a forward-declared
+   class, because it is the gcc_type, rather than the gcc_decl, that
+   has to be used to build other types, but build_decl returns a
+   gcc_decl rather than a gcc_type.  This call can in theory be used
+   to obtain the type from any other declaration; it is supposed to
+   return the same type that was supplied when the declaration was
+   created.  */
+
+GCC_METHOD1 (gcc_type, get_decl_type,
+            gcc_decl)            /* Argument DECL.  */
+
+/* Return the declaration for a type.  */
+
+GCC_METHOD1 (gcc_decl, get_type_decl,
+            gcc_type)            /* Argument TYPE.  */
+
+/* Declare DECL as a friend of the current class scope, if TYPE is
+   NULL, or of TYPE itself otherwise.  DECL may be a function or a
+   class, be they template generics, template specializations or not
+   templates.  TYPE must be a class type (not a template generic).
+
+   The add_friend call cannot introduce a declaration; even if the
+   friend is first declared as a friend in the source code, the
+   declaration belongs in the enclosing namespace, so it must be
+   introduced in that namespace, and the resulting declaration can
+   then be made a friend.
+
+   DECL cannot, however, be a member of a template class generic,
+   because we have no means to introduce their declarations.  This
+   interface has no notion of definitions for template generics.  As a
+   consequence, users of this interface must introduce each friend
+   template member specialization separately, i.e., instead of:
+
+     template <typename T> friend struct X<T>::M;
+
+   they must be declared as if they were:
+
+     friend struct X<onetype>::M;
+     friend struct X<anothertype>::M;
+     ... for each specialization of X.
+
+
+   Specializations of a template can have each others' members as
+   friends:
+
+     template <typename T> class foo {
+       int f();
+       template <typename U> friend int foo<U>::f();
+     };
+
+   It wouldn't always be possible to define all specializations of a
+   template class before introducing the friend declarations in their
+   expanded, per-specialization form.
+
+   In order to simplify such friend declarations, and to enable
+   incremental friend declarations as template specializations are
+   introduced, add_friend can be called after the befriending class is
+   fully defined, passing it a non-NULL TYPE argument naming the
+   befriending class type.  */
+
+GCC_METHOD2 (int /* bool */, add_friend,
+            gcc_decl,                /* Argument DECL.  */
+            gcc_type)                /* Argument TYPE.  */
+
+/* Return the type of a pointer to a given base type.  */
+
+GCC_METHOD1 (gcc_type, build_pointer_type,
+            gcc_type)                  /* Argument BASE_TYPE.  */
+
+/* Return the type of a reference to a given base type.  */
+
+GCC_METHOD2 (gcc_type, build_reference_type,
+            gcc_type,                  /* Argument BASE_TYPE.  */
+            enum gcc_cp_ref_qualifiers)   /* Argument RQUALS.  */
+
+/* Create a new pointer-to-member type.  MEMBER_TYPE is the data
+   member type, while CLASS_TYPE is the class type containing the data
+   member.  For pointers to member functions, MEMBER_TYPE must be a
+   method type, and CLASS_TYPE must be specified even though it might
+   be possible to extract it from the method type.  */
+
+GCC_METHOD2 (gcc_type, build_pointer_to_member_type,
+            gcc_type,                     /* Argument CLASS_TYPE.  */
+            gcc_type)                     /* Argument MEMBER_TYPE.  */
+
+/* Start a template parameter list scope and enters it, so that
+   subsequent build_type_template_parameter and
+   build_value_template_parameter calls create template parameters in
+   the list.  The list is closed by a build_decl call with
+   GCC_CP_SYMBOL_FUNCTION or GCC_CP_SYMBOL_CLASS, that, when the scope
+   is a template parameter list, declares a template function or a
+   template class with the then-closed parameter list.  The scope in
+   which the new declaration is to be introduced by build_decl must be
+   entered before calling start_template_decl, and build_decl returns
+   to that scope, from the template parameter list scope, before
+   introducing the declaration.  */
+
+GCC_METHOD0 (int /* bool */, start_template_decl)
+
+/* Build a typename template-parameter (e.g., the T in template
+   <typename T = X>).  Either PACK_P should be nonzero, to indicate an
+   argument pack (the last argument in a variadic template argument
+   list, as in template <typename... T>), or DEFAULT_TYPE may be
+   non-NULL to set the default type argument (e.g. X) for the template
+   parameter.  FILENAME and LINE_NUMBER may specify the source
+   location in which the template parameter was declared.  */
+
+GCC_METHOD5 (gcc_type, build_type_template_parameter,
+            const char *,                            /* Argument ID.  */
+            int /* bool */,                      /* Argument PACK_P.  */
+            gcc_type,                      /* Argument DEFAULT_TYPE.  */
+            const char *,                      /* Argument FILENAME.  */
+            unsigned int)                   /* Argument LINE_NUMBER.  */
+
+/* Build a template template-parameter (e.g., the T in template
+   <template <[...]> class T = X>).  DEFAULT_TEMPL may be non-NULL to
+   set the default type-template argument (e.g. X) for the template
+   template parameter.  FILENAME and LINE_NUMBER may specify the
+   source location in which the template parameter was declared.  */
+
+GCC_METHOD5 (gcc_utempl, build_template_template_parameter,
+            const char *,                            /* Argument ID.  */
+            int /* bool */,                      /* Argument PACK_P.  */
+            gcc_utempl,                   /* Argument DEFAULT_TEMPL.  */
+            const char *,                      /* Argument FILENAME.  */
+            unsigned int)                   /* Argument LINE_NUMBER.  */
+
+/* Build a value template-parameter (e.g., the V in template <typename
+   T, T V> or in template <int V = X>).  DEFAULT_VALUE may be non-NULL
+   to set the default value argument for the template parameter (e.g.,
+   X).  FILENAME and LINE_NUMBER may specify the source location in
+   which the template parameter was declared.  */
+
+GCC_METHOD5 (gcc_decl, build_value_template_parameter,
+            gcc_type,                              /* Argument TYPE.  */
+            const char *,                            /* Argument ID.  */
+            gcc_expr,                     /* Argument DEFAULT_VALUE.  */
+            const char *,                      /* Argument FILENAME.  */
+            unsigned int)                   /* Argument LINE_NUMBER.  */
+
+/* Build a template-dependent typename (e.g., typename T::bar or
+   typename T::template bart<X>).  ENCLOSING_TYPE should be the
+   template-dependent nested name specifier (e.g., T), ID should be
+   the name of the member of the ENCLOSING_TYPE (e.g., bar or bart),
+   and TARGS should be non-NULL and specify the template arguments
+   (e.g. <X>) iff ID is to name a class template.
+
+   In this and other calls, a template-dependent nested name specifier
+   may be a template class parameter (build_type_template_parameter),
+   a specialization (returned by build_dependent_type_template_id) of
+   a template template parameter (returned by
+   build_template_template_parameter) or a member type thereof
+   (returned by build_dependent_typename itself).  */
+
+GCC_METHOD3 (gcc_type, build_dependent_typename,
+            gcc_type,                    /* Argument ENCLOSING_TYPE.  */
+            const char *,                            /* Argument ID.  */
+            const struct gcc_cp_template_args *)  /* Argument TARGS.  */
+
+/* Build a template-dependent class template (e.g., T::template bart).
+   ENCLOSING_TYPE should be the template-dependent nested name
+   specifier (e.g., T), ID should be the name of the class template
+   member of the ENCLOSING_TYPE (e.g., bart).  */
+
+GCC_METHOD2 (gcc_utempl, build_dependent_class_template,
+            gcc_type,                    /* Argument ENCLOSING_TYPE.  */
+            const char *)                            /* Argument ID.  */
+
+/* Build a template-dependent type template-id (e.g., T<A>).
+   TEMPLATE_DECL should be a template template parameter (e.g., the T
+   in template <template <[...]> class T = X>), and TARGS should
+   specify the template arguments (e.g. <A>).  */
+
+GCC_METHOD2 (gcc_type, build_dependent_type_template_id,
+            gcc_utempl,                   /* Argument TEMPLATE_DECL.  */
+            const struct gcc_cp_template_args *)  /* Argument TARGS.  */
+
+/* Build a template-dependent expression (e.g., S::val or S::template
+   mtf<X>, or unqualified f or template tf<X>).
+
+   ENCLOSING_SCOPE should be a template-dependent nested name
+   specifier (e.g., T), a resolved namespace or class decl, or NULL
+   for unqualified names; ID should be the name of the member of the
+   ENCLOSING_SCOPE (e.g., val or mtf) or unqualified overloaded
+   function; and TARGS should list template arguments (e.g. <X>) when
+   mtf or tf are to name a template function, or be NULL otherwise.
+
+   Unqualified names and namespace- or class-qualified names can only
+   resolve to overloaded functions, to be used in contexts that
+   involve overload resolution that cannot be resolved because of
+   template-dependent argument or return types, such as call
+   expressions with template-dependent arguments, conversion
+   expressions to function types with template-dependent argument
+   types or the like.  Other cases of unqualified or
+   non-template-dependent-qualified names should NOT use this
+   function, and use decl_expr to convert the appropriate function or
+   object declaration to an expression.
+
+   If ID is the name of a special member function, FLAGS should be
+   GCC_CP_SYMBOL_FUNCTION|GCC_CP_FLAG_SPECIAL_FUNCTION, and ID should
+   be one of the encodings for special member functions documented in
+   build_decl.  Otherwise, FLAGS should be GCC_CP_SYMBOL_MASK, which
+   suggests the symbol kind is not known (though we know it is not a
+   type).
+
+   If ID denotes a conversion operator, CONV_TYPE should name the
+   target type of the conversion.  Otherwise, CONV_TYPE must be
+   NULL.  */
+
+GCC_METHOD5 (gcc_expr, build_dependent_expr,
+            gcc_decl,                   /* Argument ENCLOSING_SCOPE.  */
+            enum gcc_cp_symbol_kind,              /* Argument FLAGS.  */
+            const char *,                          /* Argument NAME.  */
+            gcc_type,                         /* Argument CONV_TYPE.  */
+            const struct gcc_cp_template_args *)  /* Argument TARGS.  */
+
+/* Build a gcc_expr for the value VALUE in type TYPE.  */
+
+GCC_METHOD2 (gcc_expr, build_literal_expr,
+            gcc_type,            /* Argument TYPE.  */
+            unsigned long)       /* Argument VALUE.  */
+
+/* Build a gcc_expr that denotes DECL, the declaration of a variable
+   or function in namespace scope, or of a static member variable or
+   function.  Use QUALIFIED_P to build the operand of unary & so as to
+   compute a pointer-to-member, rather than a regular pointer.  */
+
+GCC_METHOD2 (gcc_expr, build_decl_expr,
+            gcc_decl,                  /* Argument DECL.  */
+            int /* bool */)            /* Argument QUALIFIED_P.  */
+
+/* Build a gcc_expr that denotes the unary operation UNARY_OP applied
+   to the gcc_expr OPERAND.  For non-expr operands, see
+   unary_type_expr.  Besides the UNARY_OP encodings used for operator
+   names, we support "pp_" for preincrement, and "mm_" for
+   predecrement, "nx" for noexcept, "tw" for throw, "tr" for rethrow
+   (pass NULL as the operand), "te" for typeid, "sz" for sizeof, "az"
+   for alignof, "dl" for delete, "gsdl" for ::delete, "da" for
+   delete[], "gsda" for ::delete[], "sp" for pack expansion, "sZ" for
+   sizeof...(function argument pack).  */
+
+GCC_METHOD2 (gcc_expr, build_unary_expr,
+            const char *,        /* Argument UNARY_OP.  */
+            gcc_expr)            /* Argument OPERAND.  */
+
+/* Build a gcc_expr that denotes the binary operation BINARY_OP
+   applied to gcc_exprs OPERAND1 and OPERAND2.  Besides the BINARY_OP
+   encodings used for operator names, we support "ds" for the operator
+   token ".*" and "dt" for the operator token ".".  When using
+   operators that take a name as their second operand ("." and "->")
+   use decl_expr to convert the gcc_decl of the member name to a
+   gcc_expr, if the member name wasn't created with
+   e.g. build_dependent_expr.  */
+
+GCC_METHOD3 (gcc_expr, build_binary_expr,
+            const char *,        /* Argument BINARY_OP.  */
+            gcc_expr,            /* Argument OPERAND1.  */
+            gcc_expr)            /* Argument OPERAND2.  */
+
+/* Build a gcc_expr that denotes the ternary operation TERNARY_OP
+   applied to gcc_exprs OPERAND1, OPERAND2 and OPERAND3.  The only
+   supported TERNARY_OP is "qu", for the "?:" operator.  */
+
+GCC_METHOD4 (gcc_expr, build_ternary_expr,
+            const char *,        /* Argument TERNARY_OP.  */
+            gcc_expr,            /* Argument OPERAND1.  */
+            gcc_expr,            /* Argument OPERAND2.  */
+            gcc_expr)            /* Argument OPERAND3.  */
+
+/* Build a gcc_expr that denotes the unary operation UNARY_OP applied
+   to the gcc_type OPERAND.  Supported unary operations taking types
+   are "ti" for typeid, "st" for sizeof, "at" for alignof, and "sZ"
+   for sizeof...(template argument pack).  */
+
+GCC_METHOD2 (gcc_expr, build_unary_type_expr,
+            const char *,        /* Argument UNARY_OP.  */
+            gcc_type)            /* Argument OPERAND.  */
+
+/* Build a gcc_expr that denotes the binary operation BINARY_OP
+   applied to gcc_type OPERAND1 and gcc_expr OPERAND2.  Use this for
+   all kinds of (single-argument) type casts ("dc", "sc", "cc", "rc"
+   for dynamic, static, const and reinterpret casts, respectively;
+   "cv" for functional or C-style casts).  */
+
+GCC_METHOD3 (gcc_expr, build_cast_expr,
+            const char *,        /* Argument BINARY_OP.  */
+            gcc_type,            /* Argument OPERAND1.  */
+            gcc_expr)            /* Argument OPERAND2.  */
+
+/* Build a gcc_expr that denotes the conversion of an expression list
+   VALUES to TYPE, with ("tl") or without ("cv") braces, or a braced
+   initializer list of unspecified type (e.g., a component of another
+   braced initializer list; pass "il" for CONV_OP, and NULL for
+   TYPE).  */
+
+GCC_METHOD3 (gcc_expr, build_expression_list_expr,
+            const char *,                       /* Argument CONV_OP.  */
+            gcc_type,                              /* Argument TYPE.  */
+            const struct gcc_cp_function_args *) /* Argument VALUES.  */
+
+/* Build a gcc_expr that denotes a new ("nw") or new[] ("na")
+   expression of TYPE, with or without a GLOBAL_NS qualifier (prefix
+   the NEW_OP with "gs"), with or without PLACEMENT, with or without
+   INITIALIZER.  If it's not a placement new, PLACEMENT must be NULL
+   (rather than a zero-length placement arg list).  If there's no
+   specified initializer, INITIALIZER must be NULL; a zero-length arg
+   list stands for a default initializer.  */
+
+GCC_METHOD4 (gcc_expr, build_new_expr,
+            const char *,                             /* Argument NEW_OP.  */
+            const struct gcc_cp_function_args *,   /* Argument PLACEMENT.  */
+            gcc_type,                                   /* Argument TYPE.  */
+            const struct gcc_cp_function_args *) /* Argument INITIALIZER.  */
+
+/* Return a call expression that calls CALLABLE with arguments ARGS.
+   CALLABLE may be a function, a callable object, a pointer to
+   function, an unresolved expression, an unresolved overload set, an
+   object expression combined with a member function overload set or a
+   pointer-to-member.  If QUALIFIED_P, CALLABLE will be interpreted as
+   a qualified name, preventing virtual function dispatch.  */
+
+GCC_METHOD3 (gcc_expr, build_call_expr,
+            gcc_expr,                        /* Argument CALLABLE.  */
+            int /* bool */,               /* Argument QUALIFIED_P.  */
+            const struct gcc_cp_function_args *) /* Argument ARGS.  */
+
+/* Return the type of the gcc_expr OPERAND.
+   Use this for decltype.
+   For decltype (auto), pass a NULL OPERAND.
+
+   Note: for template-dependent expressions, the result is NULL,
+   because the type is only computed when template argument
+   substitution is performed.  */
+
+GCC_METHOD1 (gcc_type, get_expr_type,
+            gcc_expr)            /* Argument OPERAND.  */
+
+/* Introduce a specialization of a template function.
+
+   TEMPLATE_DECL is the template function, and TARGS are the arguments
+   for the specialization.  ADDRESS is the address of the
+   specialization.  FILENAME and LINE_NUMBER specify the source
+   location associated with the template function specialization.  */
+
+GCC_METHOD5 (gcc_decl, build_function_template_specialization,
+            gcc_decl,                     /* Argument TEMPLATE_DECL.  */
+            const struct gcc_cp_template_args *,  /* Argument TARGS.  */
+            gcc_address,                        /* Argument ADDRESS.  */
+            const char *,            /* Argument FILENAME.  */
+            unsigned int)            /* Argument LINE_NUMBER.  */
+
+/* Specialize a template class as an incomplete type.  A definition
+   can be supplied later, with start_class_type.
+
+   TEMPLATE_DECL is the template class, and TARGS are the arguments
+   for the specialization.  FILENAME and LINE_NUMBER specify the
+   source location associated with the template class
+   specialization.  */
+
+GCC_METHOD4 (gcc_decl, build_class_template_specialization,
+            gcc_decl,                     /* Argument TEMPLATE_DECL.  */
+            const struct gcc_cp_template_args *,  /* Argument TARGS.  */
+            const char *,            /* Argument FILENAME.  */
+            unsigned int)            /* Argument LINE_NUMBER.  */
+
+/* Start defining a 'class', 'struct' or 'union' type, entering its
+   own binding level.  Initially it has no fields.
+
+   TYPEDECL is the forward-declaration of the type, returned by
+   build_decl.  BASE_CLASSES indicate the base classes of class NAME.
+   FILENAME and LINE_NUMBER specify the source location associated
+   with the class definition, should they be different from those of
+   the forward declaration.  */
+
+GCC_METHOD4 (gcc_type, start_class_type,
+            gcc_decl,                /* Argument TYPEDECL.  */
+            const struct gcc_vbase_array *,/* Argument BASE_CLASSES.  */
+            const char *,            /* Argument FILENAME.  */
+            unsigned int)            /* Argument LINE_NUMBER.  */
+
+/* Create a new closure class type, record it as the
+   DISCRIMINATOR-numbered closure type in the current scope (or
+   associated with EXTRA_SCOPE, if non-NULL), and enter the closure
+   type's own binding level.  This primitive would sort of combine
+   build_decl and start_class_type, if they could be used to introduce
+   a closure type.  Initially it has no fields.
+
+   FILENAME and LINE_NUMBER specify the source location associated
+   with the class.  EXTRA_SCOPE, if non-NULL, must be a PARM_DECL of
+   the current function, or a FIELD_DECL of the current class.  If it
+   is NULL, the current scope must be a function.  */
+
+GCC_METHOD5 (gcc_type, start_closure_class_type,
+            int,                     /* Argument DISCRIMINATOR.  */
+            gcc_decl,                /* Argument EXTRA_SCOPE.  */
+            enum gcc_cp_symbol_kind, /* Argument FLAGS.  */
+            const char *,            /* Argument FILENAME.  */
+            unsigned int)            /* Argument LINE_NUMBER.  */
+
+/* Add a non-static data member to the most-recently-started
+   unfinished struct or union type.  FIELD_NAME is the field's name.
+   FIELD_TYPE is the type of the field.  BITSIZE and BITPOS indicate
+   where in the struct the field occurs.  */
+
+GCC_METHOD5 (gcc_decl, build_field,
+            const char *,                 /* Argument FIELD_NAME.  */
+            gcc_type,                     /* Argument FIELD_TYPE.  */
+            enum gcc_cp_symbol_kind,      /* Argument FIELD_FLAGS.  */
+            unsigned long,                /* Argument BITSIZE.  */
+            unsigned long)                /* Argument BITPOS.  */
+
+/* After all the fields have been added to a struct, class or union,
+   the struct or union type must be "finished".  This does some final
+   cleanups in GCC, and pops to the binding level that was in effect
+   before the matching start_class_type or
+   start_closure_class_type.  */
+
+GCC_METHOD1 (int /* bool */, finish_class_type,
+            unsigned long)                /* Argument SIZE_IN_BYTES.  */
+
+/* Create a new 'enum' type, and record it in the current binding
+   level.  The new type initially has no associated constants.
+
+   NAME is the enum name.  FILENAME and LINE_NUMBER specify its source
+   location.  */
+
+GCC_METHOD5 (gcc_type, start_enum_type,
+            const char *,            /* Argument NAME.  */
+            gcc_type,                /* Argument UNDERLYING_INT_TYPE. */
+            enum gcc_cp_symbol_kind, /* Argument FLAGS.  */
+            const char *,            /* Argument FILENAME.  */
+            unsigned int)            /* Argument LINE_NUMBER.  */
+
+/* Add a new constant to an enum type.  NAME is the constant's name
+   and VALUE is its value.  Returns a gcc_decl for the constant.  */
+
+GCC_METHOD3 (gcc_decl, build_enum_constant,
+            gcc_type,                 /* Argument ENUM_TYPE.  */
+            const char *,             /* Argument NAME.  */
+            unsigned long)            /* Argument VALUE.  */
+
+/* After all the constants have been added to an enum, the type must
+   be "finished".  This does some final cleanups in GCC.  */
+
+GCC_METHOD1 (int /* bool */, finish_enum_type,
+            gcc_type)                 /* Argument ENUM_TYPE.  */
+
+/* Create a new function type.  RETURN_TYPE is the type returned by
+   the function, and ARGUMENT_TYPES is a vector, of length NARGS, of
+   the argument types.  IS_VARARGS is true if the function is
+   varargs.  */
+
+GCC_METHOD3 (gcc_type, build_function_type,
+            gcc_type,                     /* Argument RETURN_TYPE.  */
+            const struct gcc_type_array *,/* Argument ARGUMENT_TYPES.  */
+            int /* bool */)               /* Argument IS_VARARGS.  */
+
+/* Create a variant of a function type with an exception
+   specification.  FUNCTION_TYPE is a function or method type.
+   EXCEPT_TYPES is an array with the list of exception types.  Zero as
+   the array length implies throw() AKA noexcept(true); NULL as the
+   pointer to gcc_type_array implies noexcept(false), which is almost
+   equivalent (but distinguishable by the compiler) to an unspecified
+   exception list.  */
+
+GCC_METHOD2 (gcc_type, build_exception_spec_variant,
+            gcc_type,                     /* Argument FUNCTION_TYPE.  */
+            const struct gcc_type_array *)/* Argument EXCEPT_TYPES.  */
+
+/* Create a new non-static member function type.  FUNC_TYPE is the
+   method prototype, without the implicit THIS pointer, added as a
+   pointer to the QUALS-qualified CLASS_TYPE.  If CLASS_TYPE is NULL,
+   this creates a cv-qualified (member) function type not associated
+   with any specific class, as needed to support "typedef void f(int)
+   const;", which can later be used to declare member functions and
+   pointers to member functions.  */
+
+GCC_METHOD4 (gcc_type, build_method_type,
+            gcc_type,                     /* Argument CLASS_TYPE.  */
+            gcc_type,                     /* Argument FUNC_TYPE.  */
+            enum gcc_cp_qualifiers,       /* Argument QUALS.  */
+            enum gcc_cp_ref_qualifiers)   /* Argument RQUALS.  */
+
+/* Return a declaration for the (INDEX - 1)th argument of
+   FUNCTION_DECL, i.e., for the first argument, use zero as the index.
+   If FUNCTION_DECL is a non-static member function, use -1 to get the
+   implicit THIS parameter.  */
+
+GCC_METHOD2 (gcc_decl, get_function_parameter_decl,
+            gcc_decl,                       /* Argument FUNCTION_DECL.  */
+            int)                                    /* Argument INDEX.  */
+
+/* Return a lambda expr that constructs an instance of CLOSURE_TYPE.
+   Only lambda exprs without any captures can be correctly created
+   through these mechanisms; that's all we need to support lambdas
+   expressions in default parameters, the only kind that may have to
+   be introduced through this interface.  */
+
+GCC_METHOD1 (gcc_expr, build_lambda_expr,
+            gcc_type)                        /* Argument CLOSURE_TYPE.  */
+
+/* Return an integer type with the given properties.  If BUILTIN_NAME
+   is non-NULL, it must name a builtin integral type with the given
+   signedness and size, and that is the type that will be returned.  */
+
+GCC_METHOD3 (gcc_type, get_int_type,
+            int /* bool */,               /* Argument IS_UNSIGNED.  */
+            unsigned long,                /* Argument SIZE_IN_BYTES.  */
+            const char *)                 /* Argument BUILTIN_NAME.  */
+
+/* Return the 'char' type, a distinct type from both 'signed char' and
+   'unsigned char' returned by int_type.  */
+
+GCC_METHOD0 (gcc_type, get_char_type)
+
+/* Return a floating point type with the given properties.  If BUILTIN_NAME
+   is non-NULL, it must name a builtin integral type with the given
+   signedness and size, and that is the type that will be returned.  */
+
+GCC_METHOD2 (gcc_type, get_float_type,
+            unsigned long,                /* Argument SIZE_IN_BYTES.  */
+            const char *)                 /* Argument BUILTIN_NAME.  */
+
+/* Return the 'void' type.  */
+
+GCC_METHOD0 (gcc_type, get_void_type)
+
+/* Return the 'bool' type.  */
+
+GCC_METHOD0 (gcc_type, get_bool_type)
+
+/* Return the std::nullptr_t type.  */
+
+GCC_METHOD0 (gcc_type, get_nullptr_type)
+
+/* Return the nullptr constant.  */
+
+GCC_METHOD0 (gcc_expr, get_nullptr_constant)
+
+/* Create a new array type.  If NUM_ELEMENTS is -1, then the array
+   is assumed to have an unknown length.  */
+
+GCC_METHOD2 (gcc_type, build_array_type,
+            gcc_type,                    /* Argument ELEMENT_TYPE.  */
+            int)                         /* Argument NUM_ELEMENTS.  */
+
+/* Create a new array type.  NUM_ELEMENTS is a template-dependent
+   expression.  */
+
+GCC_METHOD2 (gcc_type, build_dependent_array_type,
+            gcc_type,                    /* Argument ELEMENT_TYPE.  */
+            gcc_expr)                    /* Argument NUM_ELEMENTS.  */
+
+/* Create a new variably-sized array type.  UPPER_BOUND_NAME is the
+   name of a local variable that holds the upper bound of the array;
+   it is one less than the array size.  */
+
+GCC_METHOD2 (gcc_type, build_vla_array_type,
+            gcc_type,                    /* Argument ELEMENT_TYPE.  */
+            const char *)                /* Argument UPPER_BOUND_NAME.  */
+
+/* Return a qualified variant of a given base type.  QUALIFIERS says
+   which qualifiers to use; it is composed of or'd together
+   constants from 'enum gcc_cp_qualifiers'.  */
+
+GCC_METHOD2 (gcc_type, build_qualified_type,
+            gcc_type,                        /* Argument UNQUALIFIED_TYPE.  */
+            enum gcc_cp_qualifiers)          /* Argument QUALIFIERS.  */
+
+/* Build a complex type given its element type.  */
+
+GCC_METHOD1 (gcc_type, build_complex_type,
+            gcc_type)                    /* Argument ELEMENT_TYPE.  */
+
+/* Build a vector type given its element type and number of
+   elements.  */
+
+GCC_METHOD2 (gcc_type, build_vector_type,
+            gcc_type,                    /* Argument ELEMENT_TYPE.  */
+            int)                         /* Argument NUM_ELEMENTS.  */
+
+/* Build a constant.  NAME is the constant's name and VALUE is its
+   value.  FILENAME and LINE_NUMBER refer to the type's source
+   location.  If this is not known, FILENAME can be NULL and
+   LINE_NUMBER can be 0.  */
+
+GCC_METHOD5 (int /* bool */, build_constant,
+            gcc_type,            /* Argument TYPE.  */
+            const char *,        /* Argument NAME.  */
+            unsigned long,       /* Argument VALUE.  */
+            const char *,        /* Argument FILENAME.  */
+            unsigned int)        /* Argument LINE_NUMBER.  */
+
+/* Emit an error and return an error type object.  */
+
+GCC_METHOD1 (gcc_type, error,
+            const char *)               /* Argument MESSAGE.  */
+
+/* Declare a static_assert with the given CONDITION and ERRORMSG at
+   FILENAME:LINE_NUMBER.  */
+
+GCC_METHOD4 (int /* bool */, add_static_assert,
+            gcc_expr,     /* Argument CONDITION.  */
+            const char *, /* Argument ERRORMSG.  */
+            const char *, /* Argument FILENAME.  */
+            unsigned int) /* Argument LINE_NUMBER.  */
+
+#if 0
+
+/* FIXME: We don't want to expose the internal implementation detail
+   that default parms are stored in function types, and it's not clear
+   how this or other approaches would interact with the type sharing
+   of e.g. ctor clones, so we're leaving this out, since default args
+   are not even present in debug information anyway.  Besides, the set
+   of default args for a function may grow within its scope, and vary
+   independently in other scopes.  */
+
+/* Create a modified version of a function type that has default
+   values for some of its arguments.  The returned type should ONLY be
+   used to define functions or methods, never to declare parameters,
+   variables, types or the like.
+
+   DEFAULTS must have at most as many N_ELEMENTS as there are
+   arguments without default values in FUNCTION_TYPE.  Say, if
+   FUNCTION_TYPE has an argument list such as (T1, T2, T3, T4 = V0)
+   and DEFAULTS has 2 elements (V1, V2), the returned type will have
+   the following argument list: (T1, T2 = V1, T3 = V2, T4 = V0).
+
+   Any NULL expressions in DEFAULTS will be marked as deferred, and
+   they should be filled in with set_deferred_function_default_args.  */
+
+GCC_METHOD2 (gcc_type, add_function_default_args,
+            gcc_type,                       /* Argument FUNCTION_TYPE.  */
+            const struct gcc_cp_function_args *) /* Argument DEFAULTS.  */
+
+/* Fill in the first deferred default args in FUNCTION_DECL with the
+   expressions given in DEFAULTS.  This can be used when the
+   declaration of a parameter is needed to create a default
+   expression, such as taking the size of an earlier parameter, or
+   building a lambda expression in the parameter's context.  */
+
+GCC_METHOD2 (int /* bool */, set_deferred_function_default_args,
+            gcc_decl,                       /* Argument FUNCTION_DECL.  */
+            const struct gcc_cp_function_args *) /* Argument DEFAULTS.  */
+
+#endif
+
+
+/* When you add entry points, add them at the end, so that the new API
+   version remains compatible with the old version.
+
+   The following conventions have been observed as to naming entry points:
+
+   - build_* creates (and maybe records) something and returns it;
+   - add_* creates and records something, but doesn't return it;
+   - get_* obtains something without creating it;
+   - start_* marks the beginning of a compound (type, list, ...);
+   - finish_* completes the compound when needed.
+
+  Entry points that return an int (bool) and don't have a return value
+  specification return nonzero (true) on success and zero (false) on
+  failure.  This is in line with libcc1's conventions of returning a
+  zero-initialized value in case of e.g. a transport error.  */
diff --git a/include/gcc-cp-interface.h b/include/gcc-cp-interface.h
new file mode 100644 (file)
index 0000000..6ef9e22
--- /dev/null
@@ -0,0 +1,496 @@
+/* Interface between GCC C++ FE and GDB
+
+   Copyright (C) 2014-2017 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_CP_INTERFACE_H
+#define GCC_CP_INTERFACE_H
+
+#include "gcc-interface.h"
+
+/* This header defines the interface to the GCC API.  It must be both
+   valid C and valid C++, because it is included by both programs.  */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Forward declaration.  */
+
+struct gcc_cp_context;
+
+/*
+ * Definitions and declarations for the C++ front end.
+ */
+
+/* Defined versions of the C++ front-end API.  */
+
+enum gcc_cp_api_version
+{
+  GCC_CP_FE_VERSION_0 = 0
+};
+
+/* Qualifiers.  */
+
+enum gcc_cp_qualifiers
+{
+  GCC_CP_QUALIFIER_CONST = 1,
+  GCC_CP_QUALIFIER_VOLATILE = 2,
+  GCC_CP_QUALIFIER_RESTRICT = 4
+};
+
+/* Ref qualifiers.  */
+
+enum gcc_cp_ref_qualifiers {
+  GCC_CP_REF_QUAL_NONE = 0,
+  GCC_CP_REF_QUAL_LVALUE = 1,
+  GCC_CP_REF_QUAL_RVALUE = 2
+};
+
+/* Opaque typedef for unbound class templates.  They are used for
+   template arguments, and defaults for template template
+   parameters.  */
+
+typedef unsigned long long gcc_utempl;
+
+/* Opaque typedef for expressions.  They are used for template
+   arguments, defaults for non-type template parameters, and defaults
+   for function arguments.  */
+
+typedef unsigned long long gcc_expr;
+
+typedef enum
+  { GCC_CP_TPARG_VALUE, GCC_CP_TPARG_CLASS,
+    GCC_CP_TPARG_TEMPL, GCC_CP_TPARG_PACK }
+gcc_cp_template_arg_kind;
+
+typedef union
+{ gcc_expr value; gcc_type type; gcc_utempl templ; gcc_type pack; }
+gcc_cp_template_arg;
+
+/* An array of template arguments.  */
+
+struct gcc_cp_template_args
+{
+  /* Number of elements.  */
+
+  int n_elements;
+
+  /* kind[i] indicates what kind of template argument type[i] is.  */
+
+  char /* gcc_cp_template_arg_kind */ *kinds;
+
+  /* The template arguments.  */
+
+  gcc_cp_template_arg *elements;
+};
+
+/* An array of (default) function arguments.  */
+
+struct gcc_cp_function_args
+{
+  /* Number of elements.  */
+
+  int n_elements;
+
+  /* The (default) values for each argument.  */
+
+  gcc_expr *elements;
+};
+
+/* This enumerates the kinds of decls that GDB can create.  */
+
+enum gcc_cp_symbol_kind
+{
+  /* A function.  */
+
+  GCC_CP_SYMBOL_FUNCTION,
+
+  /* A variable.  */
+
+  GCC_CP_SYMBOL_VARIABLE,
+
+  /* A typedef, or an alias declaration (including template ones).  */
+
+  GCC_CP_SYMBOL_TYPEDEF,
+
+  /* A label.  */
+
+  GCC_CP_SYMBOL_LABEL,
+
+  /* A class, forward declared in build_decl (to be later defined in
+     start_class_definition), or, in a template parameter list scope,
+     a declaration of a template class, closing the parameter
+     list.  */
+
+  GCC_CP_SYMBOL_CLASS,
+
+  /* A union, forward declared in build_decl (to be later defined in
+     start_class_definition).  */
+
+  GCC_CP_SYMBOL_UNION,
+
+  /* An enumeration type being introduced with start_new_enum_type.  */
+
+  GCC_CP_SYMBOL_ENUM,
+
+  /* A nonstatic data member being introduced with new_field.  */
+
+  GCC_CP_SYMBOL_FIELD,
+
+  /* A base class in a gcc_vbase_array.  */
+
+  GCC_CP_SYMBOL_BASECLASS,
+
+  /* A using declaration in new_using_decl.  */
+
+  GCC_CP_SYMBOL_USING,
+
+  /* A (lambda) closure class type.  In many regards this is just like
+     a regular class, but it's not supposed to have base classes, some
+     of the member functions that are usually implicitly-defined are
+     deleted, and it should have an operator() member function that
+     holds the lambda body.  We can't instantiate objects of lambda
+     types from the snippet, but we can interact with them in such
+     ways as passing them to functions that take their types, and
+     calling their body.  */
+
+  GCC_CP_SYMBOL_LAMBDA_CLOSURE,
+
+  /* Marker to check that we haven't exceeded GCC_CP_SYMBOL_MASK.  */
+  GCC_CP_SYMBOL_END,
+
+  GCC_CP_SYMBOL_MASK = 15,
+
+  /* When defining a class member, at least one of the
+     GCC_CP_ACCESS_MASK bits must be set; when defining a namespace-
+     or union-scoped symbol, none of them must be set.  */
+
+  GCC_CP_ACCESS_PRIVATE,
+  GCC_CP_ACCESS_PUBLIC = GCC_CP_ACCESS_PRIVATE << 1,
+  GCC_CP_ACCESS_MASK = (GCC_CP_ACCESS_PUBLIC
+                              | GCC_CP_ACCESS_PRIVATE),
+  GCC_CP_ACCESS_PROTECTED = GCC_CP_ACCESS_MASK,
+  GCC_CP_ACCESS_NONE = 0,
+
+  GCC_CP_FLAG_BASE = GCC_CP_ACCESS_PRIVATE << 2,
+
+  /* Flags to be used along with GCC_CP_SYMBOL_FUNCTION:  */
+
+  /* This flag should be set for constructors, destructors and
+     operators.  */
+  GCC_CP_FLAG_SPECIAL_FUNCTION = GCC_CP_FLAG_BASE,
+
+  /* We intentionally cannot express inline, constexpr, or virtual
+     override for functions.  We can't inline or constexpr-replace
+     without a source-level body.  The override keyword is only
+     meaningful within the definition of the containing class.  */
+
+  /* This indicates a "virtual" member function, explicitly or
+     implicitly (due to a virtual function with the same name and
+     prototype in a base class) declared as such.  */
+  GCC_CP_FLAG_VIRTUAL_FUNCTION = GCC_CP_FLAG_BASE << 1,
+
+  /* The following two flags should only be set when the flag above is
+     set.  */
+
+  /* This indicates a pure virtual member function, i.e., one that is
+     declared with "= 0", even if a body is provided in the
+     definition.  */
+  GCC_CP_FLAG_PURE_VIRTUAL_FUNCTION = GCC_CP_FLAG_BASE << 2,
+
+  /* This indicates a "final" virtual member function.  */
+  GCC_CP_FLAG_FINAL_VIRTUAL_FUNCTION = GCC_CP_FLAG_BASE << 3,
+
+  /* This indicates a special member function should have its default
+     implementation.  This either means the function declaration
+     contains the "= default" tokens, or that the member function was
+     implicitly generated by the compiler, although the latter use is
+     discouraged: just let the compiler implicitly introduce it.
+
+     A member function defaulted after its first declaration has
+     slightly different ABI implications from one implicitly generated
+     or explicitly defaulted at the declaration (and definition)
+     point.  To avoid silent (possibly harmless) violation of the one
+     definition rule, it is recommended that this flag not be used for
+     such functions, and that the address of the definition be
+     supplied instead.  */
+  GCC_CP_FLAG_DEFAULTED_FUNCTION = GCC_CP_FLAG_BASE << 4,
+
+  /* This indicates a deleted member function, i.e., one that has been
+     defined as "= delete" at its declaration point, or one that has
+     been implicitly defined as deleted (with or without an explicit
+     "= default" definition).
+
+     This should not be used for implicitly-declared member functions
+     that resolve to deleted definitions, as it may affect the
+     implicit declaration of other member functions.  */
+  GCC_CP_FLAG_DELETED_FUNCTION = GCC_CP_FLAG_BASE << 5,
+
+  /* This indicates a constructor or type-conversion operator declared
+     as "explicit".  */
+
+  GCC_CP_FLAG_EXPLICIT_FUNCTION = GCC_CP_FLAG_BASE << 6,
+
+  GCC_CP_FLAG_END_FUNCTION,
+  GCC_CP_FLAG_MASK_FUNCTION = (((GCC_CP_FLAG_END_FUNCTION - 1) << 1)
+                              - GCC_CP_FLAG_BASE),
+
+  /* Flags to be used along with GCC_CP_SYMBOL_VARIABLE:  */
+
+  /* This indicates a variable declared as "constexpr".  */
+
+  GCC_CP_FLAG_CONSTEXPR_VARIABLE = GCC_CP_FLAG_BASE,
+
+  /* This indicates a variable declared as "thread_local".  ??? What
+     should the ADDRESS be?  */
+
+  GCC_CP_FLAG_THREAD_LOCAL_VARIABLE = GCC_CP_FLAG_BASE << 1,
+
+  GCC_CP_FLAG_END_VARIABLE,
+  GCC_CP_FLAG_MASK_VARIABLE = (((GCC_CP_FLAG_END_VARIABLE - 1) << 1)
+                              - GCC_CP_FLAG_BASE),
+
+  /* Flags to be used when defining nonstatic data members of classes
+     with new_field.  */
+
+  /* Use this when no flags are present.  */
+  GCC_CP_FLAG_FIELD_NOFLAG = 0,
+
+  /* This indicates the field is declared as mutable.  */
+  GCC_CP_FLAG_FIELD_MUTABLE = GCC_CP_FLAG_BASE,
+
+  GCC_CP_FLAG_END_FIELD,
+  GCC_CP_FLAG_MASK_FIELD = (((GCC_CP_FLAG_END_FIELD - 1) << 1)
+                           - GCC_CP_FLAG_BASE),
+
+  /* Flags to be used when defining an enum with
+     start_new_enum_type.  */
+
+  /* This indicates an enum type without any flags.  */
+  GCC_CP_FLAG_ENUM_NOFLAG = 0,
+
+  /* This indicates a scoped enum type.  */
+  GCC_CP_FLAG_ENUM_SCOPED = GCC_CP_FLAG_BASE,
+
+  GCC_CP_FLAG_END_ENUM,
+  GCC_CP_FLAG_MASK_ENUM = (((GCC_CP_FLAG_END_ENUM - 1) << 1)
+                              - GCC_CP_FLAG_BASE),
+
+
+  /* Flags to be used when introducing a class or a class template
+     with build_decl.  */
+
+  /* This indicates an enum type without any flags.  */
+  GCC_CP_FLAG_CLASS_NOFLAG = 0,
+
+  /* This indicates the class is actually a struct.  This has no
+     effect whatsoever on access control in this interface, since all
+     class members must have explicit access control bits set, but it
+     may affect error messages.  */
+  GCC_CP_FLAG_CLASS_IS_STRUCT = GCC_CP_FLAG_BASE,
+
+  GCC_CP_FLAG_END_CLASS,
+  GCC_CP_FLAG_MASK_CLASS = (((GCC_CP_FLAG_END_CLASS - 1) << 1)
+                              - GCC_CP_FLAG_BASE),
+
+
+  /* Flags to be used when introducing a virtual base class in a
+     gcc_vbase_array.  */
+
+  /* This indicates an enum type without any flags.  */
+  GCC_CP_FLAG_BASECLASS_NOFLAG = 0,
+
+  /* This indicates the class is actually a struct.  This has no
+     effect whatsoever on access control in this interface, since all
+     class members must have explicit access control bits set, but it
+     may affect error messages.  */
+  GCC_CP_FLAG_BASECLASS_VIRTUAL = GCC_CP_FLAG_BASE,
+
+  GCC_CP_FLAG_END_BASECLASS,
+  GCC_CP_FLAG_MASK_BASECLASS = (((GCC_CP_FLAG_END_BASECLASS - 1) << 1)
+                               - GCC_CP_FLAG_BASE),
+
+
+  GCC_CP_FLAG_MASK = (GCC_CP_FLAG_MASK_FUNCTION
+                     | GCC_CP_FLAG_MASK_VARIABLE
+                     | GCC_CP_FLAG_MASK_FIELD
+                     | GCC_CP_FLAG_MASK_ENUM
+                     | GCC_CP_FLAG_MASK_CLASS
+                     | GCC_CP_FLAG_MASK_BASECLASS
+                     )
+};
+
+
+/* An array of types used for creating lists of base classes.  */
+
+struct gcc_vbase_array
+{
+  /* Number of elements.  */
+
+  int n_elements;
+
+  /* The base classes.  */
+
+  gcc_type *elements;
+
+  /* Flags for each base class.  Used to indicate access control and
+     virtualness.  */
+
+  enum gcc_cp_symbol_kind *flags;
+};
+
+
+/* This enumerates the types of symbols that GCC might request from
+   GDB.  */
+
+enum gcc_cp_oracle_request
+{
+  /* An identifier in namespace scope -- type, variable, function,
+     namespace, template.  All namespace-scoped symbols with the
+     requested name, in any namespace (including the global
+     namespace), should be defined in response to this request.  */
+
+  GCC_CP_ORACLE_IDENTIFIER
+};
+
+/* The type of the function called by GCC to ask GDB for a symbol's
+   definition.  DATUM is an arbitrary value supplied when the oracle
+   function is registered.  CONTEXT is the GCC context in which the
+   request is being made.  REQUEST specifies what sort of symbol is
+   being requested, and IDENTIFIER is the name of the symbol.  */
+
+typedef void gcc_cp_oracle_function (void *datum,
+                                    struct gcc_cp_context *context,
+                                    enum gcc_cp_oracle_request request,
+                                    const char *identifier);
+
+/* The type of the function called by GCC to ask GDB for a symbol's
+   address.  This should return 0 if the address is not known.  */
+
+typedef gcc_address gcc_cp_symbol_address_function (void *datum,
+                                                   struct gcc_cp_context *ctxt,
+                                                   const char *identifier);
+
+/* The type of the function called by GCC to ask GDB to enter or leave
+   the user expression scope.  */
+
+typedef void gcc_cp_enter_leave_user_expr_scope_function (void *datum,
+                                                         struct gcc_cp_context
+                                                         *context);
+
+/* The vtable used by the C front end.  */
+
+struct gcc_cp_fe_vtable
+{
+  /* The version of the C interface.  The value is one of the
+     gcc_cp_api_version constants.  */
+
+  unsigned int cp_version;
+
+  /* Set the callbacks for this context.
+
+     The binding oracle is called whenever the C++ parser needs to
+     look up a symbol.  This gives the caller a chance to lazily
+     instantiate symbols using other parts of the gcc_cp_fe_interface
+     API.  The symbol is looked up without a scope, and the oracle
+     must supply a definition for ALL namespace-scoped definitions
+     bound to the symbol.
+
+     The address oracle is called whenever the C++ parser needs to
+     look up a symbol.  This may be called for symbols not provided by
+     the symbol oracle, such as built-in functions where GCC provides
+     the declaration; other internal symbols, such as those related
+     with thunks, rtti, and virtual tables are likely to be queried
+     through this interface too.  The identifier is a mangled symbol
+     name.
+
+     DATUM is an arbitrary piece of data that is passed back verbatim
+     to the callbacks in requests.  */
+
+  void (*set_callbacks) (struct gcc_cp_context *self,
+                        gcc_cp_oracle_function *binding_oracle,
+                        gcc_cp_symbol_address_function *address_oracle,
+                        gcc_cp_enter_leave_user_expr_scope_function *enter_scope,
+                        gcc_cp_enter_leave_user_expr_scope_function *leave_scope,
+                        void *datum);
+
+#define GCC_METHOD0(R, N) \
+  R (*N) (struct gcc_cp_context *);
+#define GCC_METHOD1(R, N, A) \
+  R (*N) (struct gcc_cp_context *, A);
+#define GCC_METHOD2(R, N, A, B) \
+  R (*N) (struct gcc_cp_context *, A, B);
+#define GCC_METHOD3(R, N, A, B, C) \
+  R (*N) (struct gcc_cp_context *, A, B, C);
+#define GCC_METHOD4(R, N, A, B, C, D) \
+  R (*N) (struct gcc_cp_context *, A, B, C, D);
+#define GCC_METHOD5(R, N, A, B, C, D, E) \
+  R (*N) (struct gcc_cp_context *, A, B, C, D, E);
+#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \
+  R (*N) (struct gcc_cp_context *, A, B, C, D, E, F, G);
+
+#include "gcc-cp-fe.def"
+
+#undef GCC_METHOD0
+#undef GCC_METHOD1
+#undef GCC_METHOD2
+#undef GCC_METHOD3
+#undef GCC_METHOD4
+#undef GCC_METHOD5
+#undef GCC_METHOD7
+
+};
+
+/* The C front end object.  */
+
+struct gcc_cp_context
+{
+  /* Base class.  */
+
+  struct gcc_base_context base;
+
+  /* Our vtable.  This is a separate field because this is simpler
+     than implementing a vtable inheritance scheme in C.  */
+
+  const struct gcc_cp_fe_vtable *cp_ops;
+};
+
+/* The name of the .so that the compiler builds.  We dlopen this
+   later.  */
+
+#define GCC_CP_FE_LIBCC libcc1.so
+
+/* The compiler exports a single initialization function.  This macro
+   holds its name as a symbol.  */
+
+#define GCC_CP_FE_CONTEXT gcc_cp_fe_context
+
+/* The type of the initialization function.  The caller passes in the
+   desired base version and desired C-specific version.  If the
+   request can be satisfied, a compatible gcc_context object will be
+   returned.  Otherwise, the function returns NULL.  */
+
+typedef struct gcc_cp_context *gcc_cp_fe_context_function
+    (enum gcc_base_api_version,
+     enum gcc_cp_api_version);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GCC_CP_INTERFACE_H */
index e3ffd18a75d78472554703b91362fb32184bff61..1dc3498e877b765e9e94862ce6bc14e407d81b99 100644 (file)
@@ -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"
index 9a943148a3be3eacca016c5a671b0da1b99e4d4d..5db05c58ba720d54d4896d4d3bf7a0553e70844a 100644 (file)
@@ -1,3 +1,82 @@
+2017-01-30  Alexandre Oliva <aoliva@redhat.com>
+
+       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.
+
 2017-01-30  Jan Kratochvil <jan.kratochvil@redhat.com>
 
        * findcomp.cc: Include system.h.
index 02f067564a5e3a679952cc5b7c0df253adf4c153..5e61a92a26b05ed756a44c74262b843e01a3c045 100644 (file)
 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) \
index 21fb1536d89b41baca7ce4b582eae9827febb600..54babb02a49c7c24ba18c5b9e623b428aef59620 100644 (file)
@@ -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.
index 572bc2ae9ea318a9a0b54454136e0fda8410dfea..0ef6c112dae20f46872310446202b20376828f9a 100644 (file)
@@ -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 ()
 
 \f
 
-// 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 */
 
 \f
 
@@ -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);
index 86b1e3ea1e34f9126cf463dac398aaabd4feec88..9d46f263b562a5ef5c5a6617142df621bfffd9e1 100644 (file)
@@ -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 (file)
index 0000000..bd05c8d
--- /dev/null
@@ -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
+
+\f
+
+// 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);
+}
+
+\f
+
+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;
+}
+
+\f
+
+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;
+}
+
+\f
+
+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;
+  }
+};
+
+\f
+
+// 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;
+}
+
+\f
+
+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;
+
+\f
+
+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);
+}
+
+\f
+
+// 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);
+}
+
+\f
+
+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);
+}
+
+\f
+
+// 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 (file)
index 0000000..bbd8488
--- /dev/null
@@ -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;
+}
+
+\f
+
+// 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 */
+
+\f
+
+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
+};
+
+\f
+
+// 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 (file)
index 0000000..545f28b
--- /dev/null
@@ -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
+
+\f
+
+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);
+}
+
+\f
+
+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;
+}
+
+\f
+
+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;
+}
+
+\f
+
+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;
+  }
+};
+
+\f
+
+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;
+
+\f
+
+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);
+}
+
+\f
+
+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);
+}
+
+\f
+
+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;
+}
+
+\f
+
+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;
+}
+
+\f
+
+// 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 (file)
index 0000000..05d0f7b
--- /dev/null
@@ -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 (file)
index 0000000..8120c15
--- /dev/null
@@ -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 (file)
index 0000000..eec80f3
--- /dev/null
@@ -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
index 1f2d284660f94a1ba53c838413b06dbed7df9ca8..cf53cf7c4f2da4deb7c20c0eb69f0af43cd052e6 100644 (file)
@@ -49,36 +49,6 @@ cc1_plugin::unmarshall_intlike (connection *conn, unsigned long long *result)
   return conn->get (result, sizeof (*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)
 {
@@ -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;
 }
index cf539c008179d52cf74c28f996da21b053a97cd8..d238f3a75f223a98293709a8dda34521983f30d3 100644 (file)
@@ -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 *);
 
index 2ac1fb48cb91d22529da2c81ddfdb6e811851d8e..3cd1a1b761db5d0a04ef0f54ea047a0e493333b8 100644 (file)
@@ -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
index 79069c3764ec770687b484052eb7ccb6a068c77e..d358e697c7edf390d01007c89835ad7e4177260d 100644 (file)
@@ -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 (file)
index a30cc6b..0000000
+++ /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
-
-\f
-
-// 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);
-}
-
-\f
-
-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;
-}
-
-\f
-
-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;
-}
-
-\f
-
-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;
-  }
-};
-
-\f
-
-// 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;
-}
-
-\f
-
-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;
-
-\f
-
-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);
-}
-
-\f
-
-// 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);
-}
-
-\f
-
-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);
-}
-
-\f
-
-// 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;
-}
index 01b793bce26d38365e85e0165a9066885fc8fc54..56a07c2b9de5aac089081f0d4e713bc37afa2e14 100644 (file)
@@ -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