diff options
author | Alexandre Oliva <aoliva@redhat.com> | 2015-11-26 18:57:41 -0200 |
---|---|---|
committer | Alexandre Oliva <aoliva@redhat.com> | 2016-03-02 16:13:22 -0300 |
commit | e6893e22ba6d33f170483979f13f606b7441ca81 (patch) | |
tree | 431a7ac7578cd4f9528de6e3900f1423a34e9cd7 | |
parent | a79a3e6e7c20080ecfccc780e51cc601a2356349 (diff) | |
download | gcc-aoliva/libcp1-templates.tar.gz |
extend API to support templatesaoliva/libcp1-templates
-rw-r--r-- | include/gcc-cp-fe.def | 221 | ||||
-rw-r--r-- | include/gcc-cp-interface.h | 53 | ||||
-rw-r--r-- | libcc1/libcp1plugin.cc | 582 | ||||
-rw-r--r-- | libcc1/marshall-cp.hh | 72 | ||||
-rw-r--r-- | libcc1/rpc.hh | 39 |
5 files changed, 921 insertions, 46 deletions
diff --git a/include/gcc-cp-fe.def b/include/gcc-cp-fe.def index 777424886ef..dcbcd61cc5d 100644 --- a/include/gcc-cp-fe.def +++ b/include/gcc-cp-fe.def @@ -204,6 +204,203 @@ GCC_METHOD2 (gcc_type, build_pointer_to_member_type, gcc_type, /* Argument CLASS_TYPE. */ gcc_type) /* Argument MEMBER_TYPE. */ +/* Start a template parameter list, so that subsequent + build_template_typename_parm and build_template_value_parm calls + create template parameters in the list. The list is closed by a + new_decl call with GCC_CP_SYMBOL_FUNCTION or GCC_CP_SYMBOL_CLASS, + that, when the scope is a template parameter list, closes the + parameter list and declares a template function or a template class + with the parameter list. */ + +GCC_METHOD0 (int, start_new_template_decl) + +/* Return the declaration associated with the named type. It is the + declaration, rather than the type proper, that has to be passed as + a template parameter. */ + +GCC_METHOD1 (gcc_typedecl, type_decl, + gcc_type) /* Argument TYPE. */ + +/* 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_typedecl, new_template_typename_parm, + const char *, /* Argument ID. */ + int /* bool */, /* Argument PACK_P. */ + gcc_typedecl, /* 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, new_template_template_parm, + 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, new_template_value_parm, + gcc_typedecl, /* 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 (new_template_typename_parm), a + specialization (returned by new_dependent_typespec) of a template + template parameter (returned by new_template_template_parm) or a + member type thereof (returned by new_dependent_typename + itself). */ + +GCC_METHOD3 (gcc_typedecl, new_dependent_typename, + gcc_typedecl, /* 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, new_dependent_class_template, + gcc_typedecl, /* Argument ENCLOSING_TYPE. */ + const char *) /* Argument ID. */ + +/* Build a template-dependent template type specialization (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_typedecl, new_dependent_typespec, + gcc_utempl, /* Argument TEMPLATE_DECL. */ + const struct gcc_cp_template_args *) /* Argument TARGS. */ + +/* Build a template-dependent value expression (e.g., T::val or + T::template f<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., val or f), and TARGS should + list template arguments (e.g. <X>) when f is to name a template + function, or be NULL otherwise. */ + +GCC_METHOD3 (gcc_decl, new_dependent_value_expr, + gcc_typedecl, /* Argument ENCLOSING_TYPE. */ + const char *, /* Argument ID. */ + const struct gcc_cp_template_args *) /* Argument TARGS. */ + +/* Build a gcc_expr for the value VALUE in type TYPE. */ + +GCC_METHOD2 (gcc_expr, 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. */ + +GCC_METHOD1 (gcc_expr, decl_expr, + gcc_decl) /* Argument DECL. */ + +/* Build a gcc_expr that denotes the unary operation UNARY_OP applied + to the gcc_expr OPERAND. */ + +GCC_METHOD2 (gcc_expr, unary_value_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. */ + +GCC_METHOD3 (gcc_expr, binary_value_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. */ + +GCC_METHOD4 (gcc_expr, ternary_value_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, e.g., sizeof. */ + +GCC_METHOD2 (gcc_expr, 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 type casts, and to form a pointer-to-member. */ + +GCC_METHOD3 (gcc_expr, type_value_expr, + const char *, /* Argument BINARY_OP. */ + gcc_type, /* Argument OPERAND1. */ + gcc_expr) /* Argument OPERAND2. */ + +/* FIXME: function call operations? ctor/dtor? new/delete? */ + +/* Return the type of the gcc_expr OPERAND. + Use this for decltype. */ + +GCC_METHOD1 (gcc_typedecl, 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, specialize_function_template, + 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. */ + +/* Start defining a specialization of a template class, and enter its + own binding level. Initially it has no fields. + + TEMPLATE_DECL is the template class, and TARGS are the arguments + for the specialization. BASE_CLASSES indicate the base classes of + class NAME. FILENAME and LINE_NUMBER specify the source location + associated with the template class specialization. */ + +GCC_METHOD5 (gcc_type, start_specialize_class_template, + gcc_decl, /* Argument TEMPLATE_DECL. */ + const struct gcc_cp_template_args *, /* Argument TARGS. */ + const struct gcc_vbase_array *,/* Argument BASE_CLASSES. */ + const char *, /* Argument FILENAME. */ + unsigned int) /* Argument LINE_NUMBER. */ + /* Create a new 'class' (or 'struct') type, record it in the current binding level, and enter its own binding level. Initially it has no fields. @@ -232,14 +429,14 @@ GCC_METHOD3 (gcc_type, start_new_union_type, const char *, /* Argument FILENAME. */ unsigned int) /* Argument LINE_NUMBER. */ -/* Add a non-static data member to a 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. +/* 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. FIXME: how about mutable data members? */ -GCC_METHOD5 (int /* bool */, new_field, - gcc_type, /* Argument RECORD_OR_UNION_TYPE. */ +GCC_METHOD4 (int /* bool */, new_field, const char *, /* Argument FIELD_NAME. */ gcc_type, /* Argument FIELD_TYPE. */ unsigned long, /* Argument BITSIZE. */ @@ -250,8 +447,7 @@ GCC_METHOD5 (int /* bool */, new_field, cleanups in GCC, and pops to the binding level that was in effect before the matching build_class_type or build_union_type. */ -GCC_METHOD2 (int /* bool */, finish_record_or_union, - gcc_type, /* Argument RECORD_OR_UNION_TYPE. */ +GCC_METHOD1 (int /* bool */, finish_record_or_union, unsigned long) /* Argument SIZE_IN_BYTES. */ /* Create a new 'enum' type, and record it in the current binding @@ -267,8 +463,8 @@ GCC_METHOD5 (gcc_type, start_new_enum_type, 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. */ +/* Add a new constant to an enum type. NAME is the constant's name + and VALUE is its value. */ GCC_METHOD3 (int /* bool */, build_add_enum_constant, gcc_type, /* Argument ENUM_TYPE. */ @@ -352,6 +548,13 @@ 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. */ diff --git a/include/gcc-cp-interface.h b/include/gcc-cp-interface.h index 8a4a849f214..b002b0703ee 100644 --- a/include/gcc-cp-interface.h +++ b/include/gcc-cp-interface.h @@ -41,7 +41,7 @@ struct gcc_cp_context; enum gcc_cp_api_version { - GCC_CP_FE_VERSION_0 = 0xffffffff-4 + GCC_CP_FE_VERSION_0 = 0xffffffff-5 }; /* Qualifiers. */ @@ -79,6 +79,52 @@ struct gcc_vbase_array char /* bool */ *virtualp; }; +/* Opaque typedef for type declarations. They are used for template + arguments, defaults for type template parameters, and types used to + build type-conversion expressions. */ + +typedef unsigned long long gcc_typedecl; + +/* 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; + +/* FIXME: do we need to support argument packs? */ + +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_typedecl type; gcc_utempl templ; gcc_typedecl 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; +}; + /* This enumerates the kinds of decls that GDB can create. */ enum gcc_cp_symbol_kind @@ -99,6 +145,11 @@ enum gcc_cp_symbol_kind GCC_CP_SYMBOL_LABEL, + /* A class, or, in a template parameter list scope, a declaration of + a template class, closing the parameter list. */ + + GCC_CP_SYMBOL_CLASS, + GCC_CP_SYMBOL_MASK = 15, GCC_CP_FLAG_BASE, diff --git a/libcc1/libcp1plugin.cc b/libcc1/libcp1plugin.cc index abe42a0d0c6..dd3bb0e964f 100644 --- a/libcc1/libcp1plugin.cc +++ b/libcc1/libcp1plugin.cc @@ -61,6 +61,7 @@ #include "diagnostic.h" #include "langhooks.h" #include "langhooks-def.h" +#include "decl.h" #include "callbacks.hh" #include "connection.hh" @@ -271,6 +272,30 @@ plugin_init_extra_pragmas (void *, void *) +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) @@ -298,14 +323,8 @@ address_rewriter (tree *in, int *walk_subtrees, void *arg) // 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; - TREE_NO_WARNING (value.decl) = 1; - found_value = *slot; + value = build_decl_addr_value (value.decl, address); + found_value = record_decl_address (ctx, value); } else return NULL_TREE; @@ -422,6 +441,7 @@ plugin_get_current_binding_level (cc1_plugin::connection *self) return convert_out (decl); } + gcc_decl plugin_new_decl (cc1_plugin::connection *self, const char *name, @@ -477,10 +497,14 @@ plugin_new_decl (cc1_plugin::connection *self, gcc_assert (!sym_flags); return convert_out (error_mark_node); + /* FIXME: add GCC_CP_SYMBOL_CLASS. */ + default: abort (); } + /* FIXME: check for a template parameter list scope. */ + 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; @@ -886,16 +910,7 @@ plugin_new_decl (cc1_plugin::connection *self, else value.address = NULL; if (value.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; - /* We don't want GCC to warn about e.g. static functions - without a code definition. */ - TREE_NO_WARNING (decl) = 1; - } + record_decl_address (ctx, value); } if (class_member_p) @@ -946,21 +961,10 @@ plugin_build_reference_type (cc1_plugin::connection *, return convert_out (rtype); } -// TYPE_NAME needs to be a valid pointer, even if there is no name available. - static tree -build_named_class_type (enum tree_code code, - const char *name, - const gcc_vbase_array *base_classes, - source_location loc) +start_class_def (tree type, + const gcc_vbase_array *base_classes) { - tree type = make_class_type (code); - tree id = name ? get_identifier (name) : make_anon_name (); - tree type_decl = build_decl (loc, TYPE_DECL, id, type); - TYPE_NAME (type) = type_decl; - TYPE_STUB_DECL (type) = type_decl; - safe_pushtag (id, type, ts_current); - tree bases = NULL; if (base_classes) { @@ -979,6 +983,22 @@ build_named_class_type (enum tree_code code, return type; } +static tree +build_named_class_type (enum tree_code code, + const char *name, + const gcc_vbase_array *base_classes, + source_location loc) +{ + tree type = make_class_type (code); + tree id = name ? get_identifier (name) : make_anon_name (); + tree type_decl = build_decl (loc, TYPE_DECL, id, type); + TYPE_NAME (type) = type_decl; + TYPE_STUB_DECL (type) = type_decl; + safe_pushtag (id, type, ts_current); + + return start_class_def (type, base_classes); +} + gcc_type plugin_start_new_class_type (cc1_plugin::connection *self, const char *name, @@ -1012,13 +1032,12 @@ plugin_start_new_union_type (cc1_plugin::connection *self, int plugin_new_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 record_or_union_type = current_class_type; tree field_type = convert_in (field_type_in); gcc_assert (RECORD_OR_UNION_CODE_P (TREE_CODE (record_or_union_type))); @@ -1058,10 +1077,9 @@ plugin_new_field (cc1_plugin::connection *, 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); + tree record_or_union_type = current_class_type; gcc_assert (RECORD_OR_UNION_CODE_P (TREE_CODE (record_or_union_type))); @@ -1070,6 +1088,9 @@ plugin_finish_record_or_union (cc1_plugin::connection *, gcc_assert (compare_tree_int (TYPE_SIZE_UNIT (record_or_union_type), size_in_bytes) == 0); + // FIXME: end_template_decl if it's a template? I don't think so, + // we're only defining specializations. -lxo + return 1; } @@ -1246,6 +1267,479 @@ plugin_build_pointer_to_member_type (cc1_plugin::connection *self, return convert_out (ctx->preserve (memptr_type)); } +/* Abuse an unused field of the dummy template parms entry to hold the + parm list. */ +#define TP_PARM_LIST TREE_TYPE (current_template_parms) + +int +plugin_start_new_template_decl (cc1_plugin::connection *self ATTRIBUTE_UNUSED) +{ + begin_template_parm_list (); + + TP_PARM_LIST = NULL_TREE; + + return 0; +} + +gcc_typedecl +plugin_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_typedecl +plugin_new_template_typename_parm (cc1_plugin::connection *self, + const char *id, + int /* bool */ pack_p, + gcc_typedecl 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); + + 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); + + /* Return the type of the newly-added parm decl. */ + return convert_out (ctx->preserve (TREE_TYPE (tree_last (TP_PARM_LIST)))); +} + +gcc_utempl +plugin_new_template_template_parm (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); + + /* Finish the template parm list that started this template parm. */ + end_template_parm_list (TP_PARM_LIST); + + 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); + + /* Return the decl of the newly-added template template parm. */ + return convert_out (ctx->preserve (tree_last (TP_PARM_LIST))); +} + +gcc_decl +plugin_new_template_value_parm (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); + + 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); + + /* Return the newly-added parm decl. */ + return convert_out (ctx->preserve (tree_last (TP_PARM_LIST))); +} + +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_typedecl +plugin_new_dependent_typename (cc1_plugin::connection *self, + gcc_typedecl 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_new_dependent_class_template (cc1_plugin::connection *self, + gcc_typedecl 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_typedecl +plugin_new_dependent_typespec (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 (decl)); +} + +gcc_decl +plugin_new_dependent_value_expr (cc1_plugin::connection *self, + gcc_typedecl 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 = lookup_template_function (name, targlist (targs)); + tree res = build_qualified_name (NULL_TREE, type, name, !!targs); + return convert_out (ctx->preserve (res)); +} + +gcc_expr +plugin_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_decl_expr (cc1_plugin::connection *, gcc_decl decl_in) +{ + tree decl = convert_in (decl_in); + gcc_assert (DECL_P (decl)); + return convert_out (decl); +} + +gcc_expr +plugin_unary_value_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; + 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) + /* FIXME: how do we distinguish taking the address of a data + member from creating a pointer-to-member value? Both would + take the same decl as the operand, unless we require + different expr codes for e.g. this->member and + class::member. */ + 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; + /* FIXME: __real__, __imag__. */ + case CHARS2 ('p', 'p'): // operator ++ + case CHARS2 ('m', 'm'): // operator -- + default: + gcc_unreachable (); + } + processing_template_decl++; + tree val = build_x_unary_op (/*loc=*/0, opcode, op0, tf_error); + processing_template_decl--; + return convert_out (ctx->preserve (val)); +} + +gcc_expr +plugin_binary_value_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 = COMPONENT_REF; + break; + case CHARS2 ('i', 'x'): // operator [] + opcode = ARRAY_REF; + break; + default: + gcc_unreachable (); + } + processing_template_decl++; + tree val = build_x_binary_op (/*loc=*/0, opcode, op0, ERROR_MARK, + op1, ERROR_MARK, NULL, tf_error); + processing_template_decl--; + return convert_out (ctx->preserve (val)); +} + +gcc_expr +plugin_ternary_value_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++; + tree val = build_x_conditional_expr (/*loc=*/0, op0, op1, op2, tf_error); + processing_template_decl--; + return convert_out (ctx->preserve (val)); +} + +gcc_expr +plugin_unary_type_expr (cc1_plugin::connection *self, + const char *unary_op, + gcc_typedecl 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])) + { + /* FIXME: implement sizeof, alignof, ... */ + default: + gcc_unreachable (); + } + processing_template_decl++; + tree val = cxx_sizeof_or_alignof_type (type, opcode, true); + processing_template_decl--; + return convert_out (ctx->preserve (val)); +} + +gcc_expr +plugin_type_value_expr (cc1_plugin::connection *self, + const char *binary_op, + gcc_typedecl operand1, + gcc_expr operand2) +{ + plugin_context *ctx = static_cast<plugin_context *> (self); + tree type = convert_in (operand1); + tree expr = convert_in (operand2); + tree_code opcode = ERROR_MARK; + switch (CHARS2 (binary_op[0], binary_op[1])) + { + /* FIXME: implement type casts, ... */ + default: + gcc_unreachable (); + } + processing_template_decl++; + tree val = NULL_TREE; + processing_template_decl--; + return convert_out (ctx->preserve (val)); +} + +gcc_typedecl +plugin_expr_type (cc1_plugin::connection *, + gcc_expr operand) +{ + tree op0 = convert_in (operand); + tree type = TREE_TYPE (op0); + if (type) + type = TYPE_NAME (type); + return convert_out (type); +} + +gcc_decl +plugin_specialize_function_template (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 fnid = lookup_template_function (name, targsl); + if (TREE_CODE (fnid) == TEMPLATE_ID_EXPR) + SET_EXPR_LOCATION (fnid, loc); + + 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_type +plugin_start_specialize_class_template (cc1_plugin::connection *self, + gcc_decl template_decl, + const gcc_cp_template_args *args, + 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 name = convert_in (template_decl); + + // begin_specialization (); // hopefully we don't really need this + + tree tdecl = finish_template_type (name, targlist (args), false);; + DECL_SOURCE_LOCATION (tdecl) = loc; + + tree type = start_class_def (TREE_TYPE (tdecl), base_classes); + + return convert_out (ctx->preserve (type)); +} + gcc_type plugin_int_type (cc1_plugin::connection *self, int is_unsigned, unsigned long size_in_bytes) @@ -1310,6 +1804,24 @@ plugin_build_array_type (cc1_plugin::connection *self, } 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++; + tree itype = compute_array_index_type (name, size, tf_error); + tree type = build_cplus_array_type (element_type, itype); + 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) diff --git a/libcc1/marshall-cp.hh b/libcc1/marshall-cp.hh index 5f6fc65f525..8ce13eed5a7 100644 --- a/libcc1/marshall-cp.hh +++ b/libcc1/marshall-cp.hh @@ -136,6 +136,78 @@ namespace cc1_plugin *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; + } } #endif // CC1_PLUGIN_MARSHALL_CP_HH diff --git a/libcc1/rpc.hh b/libcc1/rpc.hh index be81c49df8b..f9efe04c02e 100644 --- a/libcc1/rpc.hh +++ b/libcc1/rpc.hh @@ -126,7 +126,7 @@ namespace cc1_plugin }; #ifdef GCC_CP_INTERFACE_H - // Specialization for gcc_type_array. + // Specialization for gcc_vbase_array. template<> class argument_wrapper<const gcc_vbase_array *> { @@ -162,6 +162,43 @@ namespace cc1_plugin 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 &); + }; #endif /* GCC_CP_INTERFACE_H */ // There are two kinds of template functions here: "call" and |