summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandre Oliva <aoliva@redhat.com>2015-11-26 18:57:41 -0200
committerAlexandre Oliva <aoliva@redhat.com>2016-03-02 16:13:22 -0300
commite6893e22ba6d33f170483979f13f606b7441ca81 (patch)
tree431a7ac7578cd4f9528de6e3900f1423a34e9cd7
parenta79a3e6e7c20080ecfccc780e51cc601a2356349 (diff)
downloadgcc-aoliva/libcp1-templates.tar.gz
extend API to support templatesaoliva/libcp1-templates
-rw-r--r--include/gcc-cp-fe.def221
-rw-r--r--include/gcc-cp-interface.h53
-rw-r--r--libcc1/libcp1plugin.cc582
-rw-r--r--libcc1/marshall-cp.hh72
-rw-r--r--libcc1/rpc.hh39
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