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
+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.
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;
}
add_builtin_candidates (&candidates,
COND_EXPR,
NOP_EXPR,
- ansi_opname (COND_EXPR),
+ cp_operator_id (COND_EXPR),
args,
LOOKUP_NORMAL, complain);
{
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);
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))
|| 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. */
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
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);
{
/* 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);
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;
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);
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. */
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
/* 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];
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);
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);
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);
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);
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; \
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);
/* 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
if (supplicant == NULL_TREE || type == NULL_TREE)
return 0;
+ if (is_global_friend (supplicant))
+ return 1;
+
declp = DECL_P (supplicant);
if (declp)
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)
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)
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
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,
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;
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:
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). */
|| 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);
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
/* 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
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. */
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
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
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)
/* 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;
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);
}
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:
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:
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;
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;
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);
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";
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];
{
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;
}
/* 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;
+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
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. */
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. */
+
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. */
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
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,
--- /dev/null
+/* 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. */
--- /dev/null
+/* 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 */
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"
+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.
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))
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) \
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
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;; \
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
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) \
$(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)
@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 $@ $<
# 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.
#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;
\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
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"
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);
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]);
= 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];
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);
gcc_c_fe_context
+gcc_cp_fe_context
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+plugin_init
+plugin_is_GPL_compatible
--- /dev/null
+/* 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
--- /dev/null
+/* 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
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)
{
}
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;
}
#define CC1_PLUGIN_MARSHALL_HH
#include "status.hh"
-#include "gcc-c-interface.h"
+#include "gcc-interface.h"
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>
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 *);
#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
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) \
#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
+++ /dev/null
-/* 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;
-}
#define CC1_PLUGIN_RPC_HH
#include "status.hh"
-#include "marshall.hh"
#include "connection.hh"
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