diff options
author | Alexandre Oliva <aoliva@redhat.com> | 2015-05-20 23:33:38 -0300 |
---|---|---|
committer | Alexandre Oliva <aoliva@redhat.com> | 2016-02-19 19:54:59 -0200 |
commit | 34edef2e0ec1c128c11554f9f861c7b29a2fee06 (patch) | |
tree | 6bdfd33473587f3fe565cef56ca39d3227b89e3d | |
parent | bc9536b47eeb0f87b4cb54e51ef40744edbfcffc (diff) | |
download | gcc-34edef2e0ec1c128c11554f9f861c7b29a2fee06.tar.gz |
Introduce support for C++ in libcc1.
-rw-r--r-- | gcc/cp/cp-tree.h | 28 | ||||
-rw-r--r-- | gcc/cp/name-lookup.c | 34 | ||||
-rw-r--r-- | include/gcc-c-interface.h | 13 | ||||
-rw-r--r-- | include/gcc-cp-fe.def | 204 | ||||
-rw-r--r-- | include/gcc-cp-interface.h | 207 | ||||
-rw-r--r-- | include/gcc-interface.h | 14 | ||||
-rw-r--r-- | libcc1/Makefile.am | 44 | ||||
-rw-r--r-- | libcc1/Makefile.in | 66 | ||||
-rw-r--r-- | libcc1/libcc1.cc | 59 | ||||
-rw-r--r-- | libcc1/libcc1.sym | 1 | ||||
-rw-r--r-- | libcc1/libcc1plugin.cc (renamed from libcc1/plugin.cc) | 19 | ||||
-rw-r--r-- | libcc1/libcp1.cc | 535 | ||||
-rw-r--r-- | libcc1/libcp1plugin.cc | 965 | ||||
-rw-r--r-- | libcc1/libcp1plugin.sym | 2 | ||||
-rw-r--r-- | libcc1/marshall-c.hh | 59 | ||||
-rw-r--r-- | libcc1/marshall-cp.hh | 59 | ||||
-rw-r--r-- | libcc1/marshall.cc | 30 | ||||
-rw-r--r-- | libcc1/marshall.hh | 9 | ||||
-rw-r--r-- | libcc1/rpc.hh | 1 |
19 files changed, 2245 insertions, 104 deletions
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7800ae8316d..7f843e1d519 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -327,6 +327,7 @@ struct GTY(()) lang_identifier { cxx_binding *bindings; tree class_template_info; tree label_value; + bool oracle_looked_up; }; /* Return a typed pointer version of T if it designates a @@ -6828,6 +6829,30 @@ extern void clear_fold_cache (void); extern void suggest_alternatives_for (location_t, 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_SYMBOL, + CP_ORACLE_TAG, + CP_ORACLE_LABEL +}; + +/* 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; + +extern void cp_pushtag (location_t, tree, tree); +extern void cp_bind (location_t, tree, bool); + /* in constraint.cc */ extern void init_constraint_processing (); extern bool constraint_p (tree); @@ -6886,6 +6911,9 @@ extern tree decompose_assumptions (tree); extern tree decompose_conclusions (tree); extern bool subsumes (tree, tree); +/* In class.c */ +extern void cp_finish_injected_record_type (tree); + /* in vtable-class-hierarchy.c */ extern void vtv_compute_class_hierarchy_transitive_closure (void); extern void vtv_generate_init_routine (void); diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 89d84d7b1c3..19044d7c962 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -85,6 +85,10 @@ get_anonymous_namespace_name (void) static GTY((deletable)) binding_entry free_binding_entry = NULL; +/* The bindin oracle; see cp-tree.h. */ + +cp_binding_oracle_function *cp_binding_oracle; + /* Create a binding_entry object for (NAME, TYPE). */ static inline binding_entry @@ -4825,6 +4829,15 @@ lookup_name_real_1 (tree name, int prefer_type, int nonclass, bool block_p, cxx_binding *iter; tree val = NULL_TREE; + // FIXME: we need a more space-efficient representation for + // oracle_looked_up. + if (cp_binding_oracle && !LANG_IDENTIFIER_CAST (name)->oracle_looked_up) + { + LANG_IDENTIFIER_CAST (name)->oracle_looked_up = true; + cp_binding_oracle (CP_ORACLE_SYMBOL, name); + cp_binding_oracle (CP_ORACLE_TAG, name); + } + /* Conversion operators are handled specially because ordinary unqualified name lookup will not find template conversion operators. */ @@ -6035,6 +6048,27 @@ pushtag (tree name, tree type, tag_scope scope) timevar_cond_stop (TV_NAME_LOOKUP, subtime); return ret; } + +void +cp_bind (location_t loc, tree decl, bool is_global) +{ + DECL_SOURCE_LOCATION (decl) = loc; + + if (!is_global) + { + push_local_binding (DECL_NAME (decl), decl, 0); + return; + } + + /* Select the global namespace. */ + cp_binding_level *level = current_binding_level; + + while (level->level_chain) + level = level->level_chain; + + add_decl_to_level (decl, level); +} + /* Subroutines for reverting temporarily to top-level for instantiation of templates and such. We actually need to clear out the class- and diff --git a/include/gcc-c-interface.h b/include/gcc-c-interface.h index 95d0fc94e55..bb1e4e650f2 100644 --- a/include/gcc-c-interface.h +++ b/include/gcc-c-interface.h @@ -111,19 +111,6 @@ typedef gcc_address gcc_c_symbol_address_function (void *datum, struct gcc_c_context *ctxt, const char *identifier); -/* An array of types used for creating a function type. */ - -struct gcc_type_array -{ - /* Number of elements. */ - - int n_elements; - - /* The elements. */ - - gcc_type *elements; -}; - /* The vtable used by the C front end. */ struct gcc_c_fe_vtable diff --git a/include/gcc-cp-fe.def b/include/gcc-cp-fe.def new file mode 100644 index 00000000000..e52fef79ee4 --- /dev/null +++ b/include/gcc-cp-fe.def @@ -0,0 +1,204 @@ +/* Interface between GCC C FE and GDB -*- c -*- + + Copyright (C) 2014 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/>. */ + + + +/* Create a new "decl" in GCC. 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. */ + +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. */ + +/* Insert a GCC decl into the symbol table. DECL is the decl to + insert. IS_GLOBAL is true if this is an outermost binding, and + false if it is a possibly-shadowing binding. */ + +GCC_METHOD2 (int /* bool */, bind, + gcc_decl, /* Argument DECL. */ + int /* bool */) /* Argument IS_GLOBAL. */ +/* FIXME: do we want a namespace instead of IS_GLOBAL? */ + +/* Insert a tagged type into the symbol table. NAME is the tag name + of the type and TAGGED_TYPE is the type itself. TAGGED_TYPE must + be either a struct, union, or enum type, as these are the only + types that have tags. 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_METHOD4 (int /* bool */, tagbind, + const char *, /* Argument NAME. */ + gcc_type, /* Argument TAGGED_TYPE. */ + const char *, /* Argument FILENAME. */ + unsigned int) /* Argument LINE_NUMBER. */ + +/* Return the type of a pointer to a given base type. */ + +GCC_METHOD1 (gcc_type, build_pointer_type, + gcc_type) /* Argument BASE_TYPE. */ + +/* Create a new 'struct' type. Initially it has no fields. */ + +GCC_METHOD0 (gcc_type, build_record_type) + +/* Create a new 'union' type. Initially it has no fields. */ + +GCC_METHOD0 (gcc_type, build_union_type) + +/* Add a field 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. */ + +GCC_METHOD5 (int /* bool */, build_add_field, + gcc_type, /* Argument RECORD_OR_UNION_TYPE. */ + const char *, /* Argument FIELD_NAME. */ + gcc_type, /* Argument FIELD_TYPE. */ + unsigned long, /* Argument BITSIZE. */ + unsigned long) /* Argument BITPOS. */ +/* FIXME: can we use the above for member functions, particularly + virtual ones? */ + +/* FIXME: we need some means to add base classes. */ + +/* FIXME: we need some means to introduce namespaces. */ + +/* After all the fields have been added to a struct or union, the + struct or union type must be "finished". This does some final + cleanups in GCC. */ + +GCC_METHOD2 (int /* bool */, finish_record_or_union, + gcc_type, /* Argument RECORD_OR_UNION_TYPE. */ + unsigned long) /* Argument SIZE_IN_BYTES. */ + +/* Create a new 'enum' type. The new type initially has no + associated constants. */ + +GCC_METHOD1 (gcc_type, build_enum_type, + gcc_type) /* Argument UNDERLYING_INT_TYPE. */ + +/* 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. */ + 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. */ + +/* Return an integer type with the given properties. */ + +GCC_METHOD2 (gcc_type, int_type, + int /* bool */, /* Argument IS_UNSIGNED. */ + unsigned long) /* Argument SIZE_IN_BYTES. */ + +/* Return a floating point type with the given properties. */ + +GCC_METHOD1 (gcc_type, float_type, + unsigned long) /* Argument SIZE_IN_BYTES. */ + +/* Return the 'void' type. */ + +GCC_METHOD0 (gcc_type, void_type) + +/* Return the 'bool' type. */ + +GCC_METHOD0 (gcc_type, bool_type) + +/* 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 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. */ diff --git a/include/gcc-cp-interface.h b/include/gcc-cp-interface.h new file mode 100644 index 00000000000..73238a93324 --- /dev/null +++ b/include/gcc-cp-interface.h @@ -0,0 +1,207 @@ +/* Interface between GCC C++ FE and GDB + + Copyright (C) 2014 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 = 1 +}; + +/* Qualifiers. */ + +enum gcc_cp_qualifiers +{ + GCC_CP_QUALIFIER_CONST = 1, + GCC_CP_QUALIFIER_VOLATILE = 2, + GCC_CP_QUALIFIER_RESTRICT = 4 +}; + +/* 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. */ + + GCC_CP_SYMBOL_TYPEDEF, + + /* A label. */ + + GCC_CP_SYMBOL_LABEL +}; + +/* This enumerates the types of symbols that GCC might request from + GDB. */ + +enum gcc_cp_oracle_request +{ + /* An ordinary symbol -- a variable, function, typedef, or enum + constant. */ + + GCC_CP_ORACLE_SYMBOL, + + /* A struct, union, or enum tag. */ + + GCC_CP_ORACLE_TAG, + + /* A label. */ + + GCC_CP_ORACLE_LABEL +}; + +/* 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 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_c_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 address oracle is called whenever the C++ parser needs to + look up a symbol. This is only called for symbols not provided + by the symbol oracle -- that is, just built-in functions where + GCC provides the declaration. + + DATUM is an arbitrary piece of data that is passed back verbatim + to the callbakcs in requests. */ + + void (*set_callbacks) (struct gcc_cp_context *self, + gcc_cp_oracle_function *binding_oracle, + gcc_cp_symbol_address_function *address_oracle, + void *datum); + +#define GCC_METHOD0(R, N) \ + R (*N) (struct gcc_cp_context *); +#define GCC_METHOD1(R, N, A) \ + R (*N) (struct gcc_cp_context *, A); +#define GCC_METHOD2(R, N, A, B) \ + R (*N) (struct gcc_cp_context *, A, B); +#define GCC_METHOD3(R, N, A, B, C) \ + R (*N) (struct gcc_cp_context *, A, B, C); +#define GCC_METHOD4(R, N, A, B, C, D) \ + R (*N) (struct gcc_cp_context *, A, B, C, D); +#define GCC_METHOD5(R, N, A, B, C, D, E) \ + R (*N) (struct gcc_cp_context *, A, B, C, D, E); +#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \ + R (*N) (struct gcc_cp_context *, A, B, C, D, E, F, G); + +#include "gcc-cp-fe.def" + +#undef GCC_METHOD0 +#undef GCC_METHOD1 +#undef GCC_METHOD2 +#undef GCC_METHOD3 +#undef GCC_METHOD4 +#undef GCC_METHOD5 +#undef GCC_METHOD7 + +}; + +/* The C front end object. */ + +struct gcc_cp_context +{ + /* Base class. */ + + struct gcc_base_context base; + + /* Our vtable. This is a separate field because this is simpler + than implementing a vtable inheritance scheme in C. */ + + const struct gcc_cp_fe_vtable *cp_ops; +}; + +/* The name of the .so that the compiler builds. We dlopen this + later. */ + +#define GCC_CP_FE_LIBCC libcc1.so + +/* The compiler exports a single initialization function. This macro + holds its name as a symbol. */ + +#define GCC_CP_FE_CONTEXT gcc_cp_fe_context + +/* The type of the initialization function. The caller passes in the + desired base version and desired C-specific version. If the + request can be satisfied, a compatible gcc_context object will be + returned. Otherwise, the function returns NULL. */ + +typedef struct gcc_cp_context *gcc_cp_fe_context_function + (enum gcc_base_api_version, + enum gcc_cp_api_version); + +#ifdef __cplusplus +} +#endif + +#endif /* GCC_CP_INTERFACE_H */ diff --git a/include/gcc-interface.h b/include/gcc-interface.h index df7db6ec1df..743f334b51c 100644 --- a/include/gcc-interface.h +++ b/include/gcc-interface.h @@ -116,6 +116,20 @@ struct gcc_base_context const struct gcc_base_vtable *ops; }; +/* An array of types used for creating function types in multiple + languages. */ + +struct gcc_type_array +{ + /* Number of elements. */ + + int n_elements; + + /* The elements. */ + + gcc_type *elements; +}; + /* The name of the dummy wrapper function generated by gdb. */ #define GCC_FE_WRAPPER_FUNCTION "_gdb_expr" diff --git a/libcc1/Makefile.am b/libcc1/Makefile.am index 7a274b3470c..2793061f275 100644 --- a/libcc1/Makefile.am +++ b/libcc1/Makefile.am @@ -19,9 +19,11 @@ ACLOCAL_AMFLAGS = -I .. -I ../config gcc_build_dir = ../gcc AM_CPPFLAGS = -I $(srcdir)/../include -I $(srcdir)/../libgcc \ - -I $(gcc_build_dir) -I$(srcdir)/../gcc \ - -I $(srcdir)/../gcc/c -I $(srcdir)/../gcc/c-family \ - -I $(srcdir)/../libcpp/include $(GMPINC) + -I $(gcc_build_dir) -I$(srcdir)/../gcc $($@_CPPFLAGS) $(GMPINC) +CPPFLAGS_FOR_C_FAMILY = -I $(srcdir)/../gcc/c-family \ + -I $(srcdir)/../libcpp/include +CPPFLAGS_FOR_C = $(CPPFLAGS_FOR_C_FAMILY) -I $(srcdir)/../gcc/c +CPPFLAGS_FOR_CXX = $(CPPFLAGS_FOR_C_FAMILY) -I $(srcdir)/../gcc/cp AM_CXXFLAGS = $(WARN_FLAGS) $(WERROR) $(visibility) override CXXFLAGS := $(filter-out -fsanitize=address,$(CXXFLAGS)) override LDFLAGS := $(filter-out -fsanitize=address,$(LDFLAGS)) @@ -39,32 +41,56 @@ plugindir = $(libdir)/gcc/$(target_noncanonical)/$(gcc_version)/plugin cc1libdir = $(libdir)/$(libsuffix) if ENABLE_PLUGIN -plugin_LTLIBRARIES = libcc1plugin.la +plugin_LTLIBRARIES = libcc1plugin.la libcp1plugin.la cc1lib_LTLIBRARIES = libcc1.la endif -BUILT_SOURCES = compiler-name.h +BUILT_SOURCES = 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)'`\"" > compiler-name.h +# FIXME: compute it in configure.ac and output it in config.status, or +# introduce timestamp files for some indirection to avoid rebuilding it +# every time. +c-compiler-name.h: Makefile + -rm -f $@T + echo "#define C_COMPILER_NAME \"`echo gcc | sed '$(transform)'`\"" > $@T + mv $@T $@ # $(SHELL) $(srcdir)/../move-if-change $@T $@ +cp-compiler-name.h: Makefile + -rm -f $@T + echo "#define CP_COMPILER_NAME \"`echo g++ | sed '$(transform)'`\"" > $@T + mv $@T $@ # $(SHELL) $(srcdir)/../move-if-change $@T $@ shared_source = callbacks.cc callbacks.hh connection.cc connection.hh \ marshall.cc marshall.hh rpc.hh status.hh +marshall_c_source = marshall-c.hh +marshall_cxx_source = marshall-cp.hh + libcc1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1plugin.sym -libcc1plugin_la_SOURCES = plugin.cc $(shared_source) +libcc1plugin_la_SOURCES = libcc1plugin.cc $(shared_source) $(marshall_c_source) +libcc1plugin.lo_CPPFLAGS = $(CPPFLAGS_FOR_C) libcc1plugin_la_LIBADD = $(libiberty) libcc1plugin_la_DEPENDENCIES = $(libiberty_dep) libcc1plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(libcc1plugin_la_LDFLAGS) $(LTLDFLAGS) -o $@ +libcp1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcp1plugin.sym +libcp1plugin_la_SOURCES = libcp1plugin.cc $(shared_source) $(marshall_cxx_source) +libcp1plugin.lo_CPPFLAGS = $(CPPFLAGS_FOR_CXX) +libcp1plugin_la_LIBADD = $(libiberty) +libcp1plugin_la_DEPENDENCIES = $(libiberty_dep) +libcp1plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(libcp1plugin_la_LDFLAGS) $(LTLDFLAGS) -o $@ + LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS)) libcc1_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1.sym -libcc1_la_SOURCES = findcomp.cc libcc1.cc names.cc names.hh $(shared_source) +libcc1_la_SOURCES = findcomp.cc libcc1.cc libcp1.cc \ + names.cc names.hh $(shared_source) \ + $(marshall_c_source) $(marshall_cxx_source) libcc1_la_LIBADD = $(libiberty) libcc1_la_DEPENDENCIES = $(libiberty_dep) libcc1_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ diff --git a/libcc1/Makefile.in b/libcc1/Makefile.in index 83a1ec8c431..59860cec067 100644 --- a/libcc1/Makefile.in +++ b/libcc1/Makefile.in @@ -105,12 +105,19 @@ am__uninstall_files_from_dir = { \ am__installdirs = "$(DESTDIR)$(cc1libdir)" "$(DESTDIR)$(plugindir)" LTLIBRARIES = $(cc1lib_LTLIBRARIES) $(plugin_LTLIBRARIES) am__objects_1 = callbacks.lo connection.lo marshall.lo -am_libcc1_la_OBJECTS = findcomp.lo libcc1.lo names.lo $(am__objects_1) +am__objects_2 = +am_libcc1_la_OBJECTS = findcomp.lo libcc1.lo libcp1.lo names.lo \ + $(am__objects_1) $(am__objects_2) $(am__objects_2) libcc1_la_OBJECTS = $(am_libcc1_la_OBJECTS) @ENABLE_PLUGIN_TRUE@am_libcc1_la_rpath = -rpath $(cc1libdir) -am_libcc1plugin_la_OBJECTS = plugin.lo $(am__objects_1) +am_libcc1plugin_la_OBJECTS = libcc1plugin.lo $(am__objects_1) \ + $(am__objects_2) libcc1plugin_la_OBJECTS = $(am_libcc1plugin_la_OBJECTS) @ENABLE_PLUGIN_TRUE@am_libcc1plugin_la_rpath = -rpath $(plugindir) +am_libcp1plugin_la_OBJECTS = libcp1plugin.lo $(am__objects_1) \ + $(am__objects_2) +libcp1plugin_la_OBJECTS = $(am_libcp1plugin_la_OBJECTS) +@ENABLE_PLUGIN_TRUE@am_libcp1plugin_la_rpath = -rpath $(plugindir) DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/../depcomp am__depfiles_maybe = depfiles @@ -133,7 +140,8 @@ CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ -SOURCES = $(libcc1_la_SOURCES) $(libcc1plugin_la_SOURCES) +SOURCES = $(libcc1_la_SOURCES) $(libcc1plugin_la_SOURCES) \ + $(libcp1plugin_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ @@ -275,10 +283,13 @@ visibility = @visibility@ ACLOCAL_AMFLAGS = -I .. -I ../config gcc_build_dir = ../gcc AM_CPPFLAGS = -I $(srcdir)/../include -I $(srcdir)/../libgcc \ - -I $(gcc_build_dir) -I$(srcdir)/../gcc \ - -I $(srcdir)/../gcc/c -I $(srcdir)/../gcc/c-family \ - -I $(srcdir)/../libcpp/include $(GMPINC) + -I $(gcc_build_dir) -I$(srcdir)/../gcc $($@_CPPFLAGS) $(GMPINC) +CPPFLAGS_FOR_C_FAMILY = -I $(srcdir)/../gcc/c-family \ + -I $(srcdir)/../libcpp/include + +CPPFLAGS_FOR_C = $(CPPFLAGS_FOR_C_FAMILY) -I $(srcdir)/../gcc/c +CPPFLAGS_FOR_CXX = $(CPPFLAGS_FOR_C_FAMILY) -I $(srcdir)/../gcc/cp AM_CXXFLAGS = $(WARN_FLAGS) $(WERROR) $(visibility) # Can be simplified when libiberty becomes a normal convenience library. libiberty_normal = ../libiberty/libiberty.a @@ -292,23 +303,38 @@ libiberty = $(if $(wildcard $(libiberty_noasan)),$(Wc)$(libiberty_noasan), \ libiberty_dep = $(patsubst $(Wc)%,%,$(libiberty)) plugindir = $(libdir)/gcc/$(target_noncanonical)/$(gcc_version)/plugin cc1libdir = $(libdir)/$(libsuffix) -@ENABLE_PLUGIN_TRUE@plugin_LTLIBRARIES = libcc1plugin.la +@ENABLE_PLUGIN_TRUE@plugin_LTLIBRARIES = libcc1plugin.la libcp1plugin.la @ENABLE_PLUGIN_TRUE@cc1lib_LTLIBRARIES = libcc1.la -BUILT_SOURCES = compiler-name.h +BUILT_SOURCES = 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) \ @@ -437,6 +463,8 @@ libcc1.la: $(libcc1_la_OBJECTS) $(libcc1_la_DEPENDENCIES) $(EXTRA_libcc1_la_DEPE $(libcc1_la_LINK) $(am_libcc1_la_rpath) $(libcc1_la_OBJECTS) $(libcc1_la_LIBADD) $(LIBS) libcc1plugin.la: $(libcc1plugin_la_OBJECTS) $(libcc1plugin_la_DEPENDENCIES) $(EXTRA_libcc1plugin_la_DEPENDENCIES) $(libcc1plugin_la_LINK) $(am_libcc1plugin_la_rpath) $(libcc1plugin_la_OBJECTS) $(libcc1plugin_la_LIBADD) $(LIBS) +libcp1plugin.la: $(libcp1plugin_la_OBJECTS) $(libcp1plugin_la_DEPENDENCIES) $(EXTRA_libcp1plugin_la_DEPENDENCIES) + $(libcp1plugin_la_LINK) $(am_libcp1plugin_la_rpath) $(libcp1plugin_la_OBJECTS) $(libcp1plugin_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -448,9 +476,11 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connection.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/findcomp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcc1.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcc1plugin.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcp1.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcp1plugin.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/marshall.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/names.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin.Plo@am__quote@ .cc.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @@ -670,8 +700,18 @@ override LDFLAGS := $(filter-out -fsanitize=address,$(LDFLAGS)) # Put this in a header so we don't run sed for each compilation. This # is also simpler to debug as one can easily see the constant. -compiler-name.h: Makefile - echo "#define COMPILER_NAME \"`echo gcc | sed '$(transform)'`\"" > compiler-name.h +# FIXME: compute it in configure.ac and output it in config.status, or +# introduce timestamp files for some indirection to avoid rebuilding it +# every time. +c-compiler-name.h: Makefile + -rm -f $@T + echo "#define C_COMPILER_NAME \"`echo gcc | sed '$(transform)'`\"" > $@T + mv $@T $@ # $(SHELL) $(srcdir)/../move-if-change $@T $@ + +cp-compiler-name.h: Makefile + -rm -f $@T + echo "#define CP_COMPILER_NAME \"`echo g++ | sed '$(transform)'`\"" > $@T + mv $@T $@ # $(SHELL) $(srcdir)/../move-if-change $@T $@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff --git a/libcc1/libcc1.cc b/libcc1/libcc1.cc index 7d7d2c190c7..9db96243e8a 100644 --- a/libcc1/libcc1.cc +++ b/libcc1/libcc1.cc @@ -1,5 +1,5 @@ /* The library used by gdb. - Copyright (C) 2014 Free Software Foundation, Inc. + Copyright (C) 2014, 2015 Free Software Foundation, Inc. This file is part of GCC. @@ -29,15 +29,15 @@ along with GCC; see the file COPYING3. If not see #include <sys/stat.h> #include <stdlib.h> #include <sstream> +#include "marshall-c.hh" #include "rpc.hh" #include "connection.hh" #include "names.hh" #include "callbacks.hh" -#include "gcc-interface.h" #include "libiberty.h" #include "xregex.h" #include "findcomp.hh" -#include "compiler-name.h" +#include "c-compiler-name.h" struct libcc1; @@ -110,30 +110,35 @@ libcc1::~libcc1 () -// This is a wrapper function that is called by the RPC system and -// that then forwards the call to the library user. Note that the -// return value is not used; the type cannot be 'void' due to -// limitations in our simple RPC. -int -call_binding_oracle (cc1_plugin::connection *conn, - enum gcc_c_oracle_request request, - const char *identifier) -{ - libcc1 *self = ((libcc1_connection *) conn)->back_ptr; +// Enclose these functions in an anonymous namespace because they +// shouldn't be exported, but they can't be static because they're +// used as template arguments. +namespace { + // This is a wrapper function that is called by the RPC system and + // that then forwards the call to the library user. Note that the + // return value is not used; the type cannot be 'void' due to + // limitations in our simple RPC. + int + c_call_binding_oracle (cc1_plugin::connection *conn, + enum gcc_c_oracle_request request, + const char *identifier) + { + libcc1 *self = ((libcc1_connection *) conn)->back_ptr; - self->binding_oracle (self->oracle_datum, self, request, identifier); - return 1; -} + self->binding_oracle (self->oracle_datum, self, request, identifier); + return 1; + } -// This is a wrapper function that is called by the RPC system and -// that then forwards the call to the library user. -gcc_address -call_symbol_address (cc1_plugin::connection *conn, const char *identifier) -{ - libcc1 *self = ((libcc1_connection *) conn)->back_ptr; + // This is a wrapper function that is called by the RPC system and + // that then forwards the call to the library user. + gcc_address + c_call_symbol_address (cc1_plugin::connection *conn, const char *identifier) + { + libcc1 *self = ((libcc1_connection *) conn)->back_ptr; - return self->address_oracle (self->oracle_datum, self, identifier); -} + return self->address_oracle (self->oracle_datum, self, identifier); + } +} /* anonymous namespace */ @@ -315,7 +320,7 @@ libcc1_set_arguments (struct gcc_base_context *s, regex_t triplet; int code; - std::string rx = make_regexp (triplet_regexp, COMPILER_NAME); + std::string rx = make_regexp (triplet_regexp, C_COMPILER_NAME); code = regcomp (&triplet, rx.c_str (), REG_EXTENDED | REG_NOSUB); if (code != 0) { @@ -475,12 +480,12 @@ libcc1_compile (struct gcc_base_context *s, = cc1_plugin::callback<int, enum gcc_c_oracle_request, const char *, - call_binding_oracle>; + c_call_binding_oracle>; self->connection->add_callback ("binding_oracle", fun); fun = cc1_plugin::callback<gcc_address, const char *, - call_symbol_address>; + c_call_symbol_address>; self->connection->add_callback ("address_oracle", fun); char **argv = new (std::nothrow) char *[self->args.size () + 1]; diff --git a/libcc1/libcc1.sym b/libcc1/libcc1.sym index 86b1e3ea1e3..9d46f263b56 100644 --- a/libcc1/libcc1.sym +++ b/libcc1/libcc1.sym @@ -1 +1,2 @@ gcc_c_fe_context +gcc_cp_fe_context diff --git a/libcc1/plugin.cc b/libcc1/libcc1plugin.cc index 57fca7c9a7b..2fdbeead1b1 100644 --- a/libcc1/plugin.cc +++ b/libcc1/libcc1plugin.cc @@ -63,6 +63,7 @@ #include "callbacks.hh" #include "connection.hh" +#include "marshall-c.hh" #include "rpc.hh" #ifdef __GNUC__ @@ -469,18 +470,30 @@ plugin_build_pointer_type (cc1_plugin::connection *, 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 (make_node (RECORD_TYPE))); + 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 (make_node (UNION_TYPE))); + return convert_out (ctx->preserve (build_anonymous_node (UNION_TYPE))); } int @@ -577,7 +590,7 @@ plugin_build_enum_type (cc1_plugin::connection *self, if (underlying_int_type == error_mark_node) return convert_out (error_mark_node); - tree result = make_node (ENUMERAL_TYPE); + tree result = build_anonymous_node (ENUMERAL_TYPE); TYPE_PRECISION (result) = TYPE_PRECISION (underlying_int_type); TYPE_UNSIGNED (result) = TYPE_UNSIGNED (underlying_int_type); diff --git a/libcc1/libcp1.cc b/libcc1/libcp1.cc new file mode 100644 index 00000000000..4ee58259213 --- /dev/null +++ b/libcc1/libcp1.cc @@ -0,0 +1,535 @@ +/* The library used by gdb. + Copyright (C) 2014 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" + +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; + void *oracle_datum; + + void (*print_function) (void *datum, const char *message); + void *print_datum; + + std::vector<std::string> args; + std::string source_file; +}; + +// 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 () +{ + base.ops = v; + cp_ops = cv; +} + +libcp1::~libcp1 () +{ + delete connection; +} + + + +// 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); + } +} /* anonymous namespace */ + + + +static void +set_callbacks (struct gcc_cp_context *s, + gcc_cp_oracle_function *binding_oracle, + gcc_cp_symbol_address_function *address_oracle, + void *datum) +{ + libcp1 *self = (libcp1 *) s; + + self->binding_oracle = binding_oracle; + self->address_oracle = address_oracle; + 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::N>, +#define GCC_METHOD1(R, N, A) \ + rpc<R, cc1_plugin::N, A>, +#define GCC_METHOD2(R, N, A, B) \ + rpc<R, cc1_plugin::N, A, B>, +#define GCC_METHOD3(R, N, A, B, C) \ + rpc<R, cc1_plugin::N, A, B, C>, +#define GCC_METHOD4(R, N, A, B, C, D) \ + rpc<R, cc1_plugin::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>, +#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \ + rpc<R, cc1_plugin::N, A, B, C, D, E, F, G>, + +#include "gcc-cp-fe.def" + +#undef GCC_METHOD0 +#undef GCC_METHOD1 +#undef GCC_METHOD2 +#undef GCC_METHOD3 +#undef GCC_METHOD4 +#undef GCC_METHOD5 +#undef GCC_METHOD7 +}; + + + +// Construct an appropriate regexp to match the compiler name. +static std::string +make_regexp (const char *triplet_regexp, const char *compiler) +{ + std::stringstream buf; + + buf << "^" << triplet_regexp << "-"; + + // Quote the compiler name in case it has something funny in it. + for (const char *p = compiler; *p; ++p) + { + switch (*p) + { + case '.': + case '^': + case '$': + case '*': + case '+': + case '?': + case '(': + case ')': + case '[': + case '{': + case '\\': + case '|': + buf << '\\'; + break; + } + buf << *p; + } + buf << "$"; + + return buf.str (); +} + +static char * +libcp1_set_arguments (struct gcc_base_context *s, + const char *triplet_regexp, + int argc, char **argv) +{ + libcp1 *self = (libcp1 *) s; + regex_t triplet; + int code; + + std::string rx = make_regexp (triplet_regexp, CP_COMPILER_NAME); + 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); + } + + std::string compiler; + if (!find_compiler (triplet, &compiler)) + { + regfree (&triplet); + return concat ("Could not find a compiler matching \"", + rx.c_str (), + "\"", + (char *) NULL); + } + regfree (&triplet); + + self->args.push_back (compiler); + + for (int i = 0; i < argc; ++i) + self->args.push_back (argv[i]); + + return NULL; +} + +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, + int verbose) +{ + 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 (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); + + 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 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, + libcp1_set_source_file, + libcp1_set_print_callback, + libcp1_compile, + libcp1_destroy +}; + +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 || cp_version != GCC_CP_FE_VERSION_0) + return NULL; + + return new libcp1 (&vtable, &cp_vtable); +} diff --git a/libcc1/libcp1plugin.cc b/libcc1/libcp1plugin.cc new file mode 100644 index 00000000000..789be2c5adb --- /dev/null +++ b/libcc1/libcp1plugin.cc @@ -0,0 +1,965 @@ +/* Library interface to C front end + Copyright (C) 2014 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 "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 "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 + + + +// This is put into the lang hooks when the plugin starts. + +static void +plugin_print_error_function (diagnostic_context *context, const char *file, + diagnostic_info *diagnostic) +{ + if (current_function_decl != NULL_TREE + && DECL_NAME (current_function_decl) != NULL_TREE + && strcmp (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)), + GCC_FE_WRAPPER_FUNCTION) == 0) + return; + lhd_print_error_function (context, file, diagnostic); +} + + + +static unsigned long long +convert_out (tree t) +{ + return (unsigned long long) (uintptr_t) t; +} + +static tree +convert_in (unsigned long long v) +{ + return (tree) (uintptr_t) v; +} + + + +struct decl_addr_value +{ + tree decl; + tree address; +}; + +struct decl_addr_hasher : typed_free_remove<decl_addr_value> +{ + typedef decl_addr_value *value_type; + typedef decl_addr_value *compare_type; + + static inline hashval_t hash (const decl_addr_value *); + static inline bool equal (const decl_addr_value *, const decl_addr_value *); +}; + +inline hashval_t +decl_addr_hasher::hash (const decl_addr_value *e) +{ + return IDENTIFIER_HASH_VALUE (DECL_NAME (e->decl)); +} + +inline bool +decl_addr_hasher::equal (const decl_addr_value *p1, const decl_addr_value *p2) +{ + return p1->decl == p2->decl; +} + + + +struct string_hasher : typed_noop_remove<const char> +{ + typedef const char *value_type; + typedef const char *compare_type; + + static inline hashval_t hash (const char *s) + { + return htab_hash_string (s); + } + + static inline bool equal (const char *p1, const char *p2) + { + return strcmp (p1, p2) == 0; + } +}; + + + +// A wrapper for pushdecl that doesn't let gdb have a chance to +// instantiate a symbol. + +static void +pushdecl_safe (tree decl) +{ + void (*save) (enum cp_oracle_request, tree identifier); + + save = cp_binding_oracle; + cp_binding_oracle = NULL; + pushdecl (decl); + cp_binding_oracle = save; +} + + + +struct plugin_context : public cc1_plugin::connection +{ + plugin_context (int fd); + + // Map decls to addresses. + hash_table<decl_addr_hasher> address_map; + + // A collection of trees that are preserved for the GC. + hash_table< pointer_hash<tree_node> > preserved; + + // File name cache. + hash_table<string_hasher> file_names; + + // Perform GC marking. + void mark (); + + // Preserve a tree during the plugin's operation. + tree preserve (tree t) + { + tree_node **slot = preserved.find_slot (t, INSERT); + *slot = t; + return t; + } + + source_location get_source_location (const char *filename, + unsigned int line_number) + { + if (filename == NULL) + return UNKNOWN_LOCATION; + + filename = intern_filename (filename); + linemap_add (line_table, LC_ENTER, false, filename, line_number); + source_location loc = linemap_line_start (line_table, line_number, 0); + linemap_add (line_table, LC_LEAVE, false, NULL, 0); + return loc; + } + +private: + + // Add a file name to FILE_NAMES and return the canonical copy. + const char *intern_filename (const char *filename) + { + const char **slot = file_names.find_slot (filename, INSERT); + if (*slot == NULL) + { + /* The file name must live as long as the line map, which + effectively means as long as this compilation. So, we copy + the string here but never free it. */ + *slot = xstrdup (filename); + } + return *slot; + } +}; + +static plugin_context *current_context; + + + +plugin_context::plugin_context (int fd) + : cc1_plugin::connection (fd), + address_map (30), + preserved (30), + file_names (30) +{ +} + +void +plugin_context::mark () +{ + for (hash_table<decl_addr_hasher>::iterator it = address_map.begin (); + it != address_map.end (); + ++it) + { + ggc_mark ((*it)->decl); + ggc_mark ((*it)->address); + } + + for (hash_table< pointer_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_SYMBOL: + request = GCC_CP_ORACLE_SYMBOL; + break; + case CP_ORACLE_TAG: + request = GCC_CP_ORACLE_TAG; + break; + case CP_ORACLE_LABEL: + request = GCC_CP_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 *) +{ + cp_binding_oracle = plugin_binding_oracle; +} + +static void +plugin_init_extra_pragmas (void *, void *) +{ + c_register_pragma ("GCC", "user_expression", plugin_pragma_user_expression); +} + + + +// Maybe rewrite a decl to its address. +static tree +address_rewriter (tree *in, int *walk_subtrees, void *arg) +{ + plugin_context *ctx = (plugin_context *) arg; + + if (!DECL_P (*in) || DECL_NAME (*in) == NULL_TREE) + return NULL_TREE; + + decl_addr_value value; + value.decl = *in; + decl_addr_value *found_value = ctx->address_map.find (&value); + if (found_value != NULL) + { + // At this point we don't need VLA sizes for gdb-supplied + // variables, and having them here confuses later passes, so we + // drop them. + if (array_of_runtime_bound_p (TREE_TYPE (*in))) + { + TREE_TYPE (*in) + = build_array_type_nelts (TREE_TYPE (TREE_TYPE (*in)), 1); + DECL_SIZE (*in) = TYPE_SIZE (TREE_TYPE (*in)); + DECL_SIZE_UNIT (*in) = TYPE_SIZE_UNIT (TREE_TYPE (*in)); + } + } + else if (DECL_IS_BUILTIN (*in)) + { + gcc_address address; + + if (!cc1_plugin::call (ctx, "address_oracle", &address, + IDENTIFIER_POINTER (DECL_NAME (*in)))) + return NULL_TREE; + if (address == 0) + return NULL_TREE; + + // Insert the decl into the address map in case it is referenced + // again. + value.address = build_int_cst_type (ptr_type_node, address); + decl_addr_value **slot = ctx->address_map.find_slot (&value, INSERT); + gcc_assert (*slot == NULL); + *slot + = static_cast<decl_addr_value *> (xmalloc (sizeof (decl_addr_value))); + **slot = value; + found_value = *slot; + } + else + return NULL_TREE; + + if (found_value->address != error_mark_node) + { + // We have an address for the decl, so rewrite the tree. + tree ptr_type = build_pointer_type (TREE_TYPE (*in)); + *in = fold_build1 (INDIRECT_REF, TREE_TYPE (*in), + fold_build1 (CONVERT_EXPR, ptr_type, + found_value->address)); + } + + *walk_subtrees = 0; + + return NULL_TREE; +} + +// When generating code for gdb, we want to be able to use absolute +// addresses to refer to otherwise external objects that gdb knows +// about. gdb passes in these addresses when building decls, and then +// before gimplification we go through the trees, rewriting uses to +// the equivalent of "*(TYPE *) ADDR". +static void +rewrite_decls_to_addresses (void *function_in, void *) +{ + tree function = (tree) function_in; + + // Do nothing if we're not in gdb. + if (current_context == NULL) + return; + + walk_tree (&DECL_SAVED_TREE (function), address_rewriter, current_context, + NULL); +} + + + +gcc_decl +plugin_build_decl (cc1_plugin::connection *self, + const char *name, + enum gcc_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); + tree identifier = get_identifier (name); + enum tree_code code; + tree decl; + tree sym_type = convert_in (sym_type_in); + + switch (sym_kind) + { + case GCC_CP_SYMBOL_FUNCTION: + code = FUNCTION_DECL; + break; + + case GCC_CP_SYMBOL_VARIABLE: + code = VAR_DECL; + break; + + case GCC_CP_SYMBOL_TYPEDEF: + code = TYPE_DECL; + break; + + case GCC_CP_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_CP_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); + cp_bind (DECL_SOURCE_LOCATION (decl), decl, is_global); + rest_of_decl_compilation (decl, is_global, 0); + return 1; +} + +static tree name_placeholder; + +void +cp_pushtag (location_t loc, tree name, tree type) +{ + tree decl = TYPE_NAME (type); + DECL_SOURCE_LOCATION (decl) = loc; + gcc_assert (DECL_NAME (decl) == name_placeholder || DECL_NAME (decl) == name); + DECL_NAME (decl) = name; + pushtag (name, type, ts_global); +} + +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); + cp_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))); +} + +// 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; + if (code == RECORD_TYPE) + node = make_class_type (code); + else + node = make_node (code); + if (!name_placeholder) + name_placeholder = get_identifier ("name placeholder"); + tree type_decl = build_decl (input_location, TYPE_DECL, + name_placeholder, 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); + tree node = build_anonymous_node (RECORD_TYPE); + xref_basetypes (node, NULL); // for now + return convert_out (ctx->preserve (node)); +} + +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)); + } + + 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; + + // Now we may have to retrofit the newly-added binding into the + // active bindings. + + 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. + 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 = 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)); +} + +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_cplus_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_cp_qualifiers qualifiers) +{ + tree unqualified_type = convert_in (unqualified_type_in); + int 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; + + return convert_out (build_qualified_type (unqualified_type, quals)); +} + +gcc_type +plugin_build_complex_type (cc1_plugin::connection *self, + gcc_type base_type) +{ + plugin_context *ctx = static_cast<plugin_context *> (self); + return convert_out (ctx->preserve (build_complex_type (convert_in (base_type)))); +} + +gcc_type +plugin_build_vector_type (cc1_plugin::connection *self, + gcc_type base_type, int nunits) +{ + plugin_context *ctx = static_cast<plugin_context *> (self); + return convert_out (ctx->preserve (build_vector_type (convert_in (base_type), + nunits))); +} + +int +plugin_build_constant (cc1_plugin::connection *self, gcc_type type_in, + const char *name, unsigned long value, + const char *filename, unsigned int line_number) +{ + plugin_context *ctx = static_cast<plugin_context *> (self); + tree cst, decl; + tree type = convert_in (type_in); + + cst = build_int_cst (type, value); + decl = build_decl (ctx->get_source_location (filename, line_number), + CONST_DECL, get_identifier (name), type); + DECL_INITIAL (decl) = cst; + pushdecl_safe (decl); + + return 1; +} + +gcc_type +plugin_error (cc1_plugin::connection *, + const char *message) +{ + error ("%s", message); + return convert_out (error_mark_node); +} + + + +// Perform GC marking. + +static void +gc_mark (void *, void *) +{ + if (current_context != NULL) + current_context->mark (); +} + +#ifdef __GNUC__ +#pragma GCC visibility push(default) +#endif + +int +plugin_init (struct plugin_name_args *plugin_info, + struct plugin_gcc_version *) +{ + long fd = -1; + for (int i = 0; i < plugin_info->argc; ++i) + { + if (strcmp (plugin_info->argv[i].key, "fd") == 0) + { + char *tail; + errno = 0; + fd = strtol (plugin_info->argv[i].value, &tail, 0); + if (*tail != '\0' || errno != 0) + fatal_error (input_location, + "%s: invalid file descriptor argument to plugin", + plugin_info->base_name); + break; + } + } + if (fd == -1) + fatal_error (input_location, + "%s: required plugin argument %<fd%> is missing", + plugin_info->base_name); + + current_context = new plugin_context (fd); + + // Handshake. + cc1_plugin::protocol_int version; + if (!current_context->require ('H') + || ! ::cc1_plugin::unmarshall (current_context, &version)) + fatal_error (input_location, + "%s: handshake failed", plugin_info->base_name); + if (version != GCC_CP_FE_VERSION_0) + fatal_error (input_location, + "%s: unknown version in handshake", plugin_info->base_name); + + register_callback (plugin_info->base_name, PLUGIN_PRAGMAS, + plugin_init_extra_pragmas, NULL); + register_callback (plugin_info->base_name, PLUGIN_PRE_GENERICIZE, + rewrite_decls_to_addresses, NULL); + register_callback (plugin_info->base_name, PLUGIN_GGC_MARKING, + gc_mark, NULL); + + lang_hooks.print_error_function = plugin_print_error_function; + +#define GCC_METHOD0(R, N) \ + { \ + cc1_plugin::callback_ftype *fun \ + = cc1_plugin::callback<R, plugin_ ## N>; \ + current_context->add_callback (# N, fun); \ + } +#define GCC_METHOD1(R, N, A) \ + { \ + cc1_plugin::callback_ftype *fun \ + = cc1_plugin::callback<R, A, plugin_ ## N>; \ + current_context->add_callback (# N, fun); \ + } +#define GCC_METHOD2(R, N, A, B) \ + { \ + cc1_plugin::callback_ftype *fun \ + = cc1_plugin::callback<R, A, B, plugin_ ## N>; \ + current_context->add_callback (# N, fun); \ + } +#define GCC_METHOD3(R, N, A, B, C) \ + { \ + cc1_plugin::callback_ftype *fun \ + = cc1_plugin::callback<R, A, B, C, plugin_ ## N>; \ + current_context->add_callback (# N, fun); \ + } +#define GCC_METHOD4(R, N, A, B, C, D) \ + { \ + cc1_plugin::callback_ftype *fun \ + = cc1_plugin::callback<R, A, B, C, D, \ + plugin_ ## N>; \ + current_context->add_callback (# N, fun); \ + } +#define GCC_METHOD5(R, N, A, B, C, D, E) \ + { \ + cc1_plugin::callback_ftype *fun \ + = cc1_plugin::callback<R, A, B, C, D, E, \ + plugin_ ## N>; \ + current_context->add_callback (# N, fun); \ + } +#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \ + { \ + cc1_plugin::callback_ftype *fun \ + = cc1_plugin::callback<R, A, B, C, D, E, F, G, \ + plugin_ ## N>; \ + current_context->add_callback (# N, fun); \ + } + +#include "gcc-cp-fe.def" + +#undef GCC_METHOD0 +#undef GCC_METHOD1 +#undef GCC_METHOD2 +#undef GCC_METHOD3 +#undef GCC_METHOD4 +#undef GCC_METHOD5 +#undef GCC_METHOD7 + + return 0; +} diff --git a/libcc1/libcp1plugin.sym b/libcc1/libcp1plugin.sym new file mode 100644 index 00000000000..05d0f7b520f --- /dev/null +++ b/libcc1/libcp1plugin.sym @@ -0,0 +1,2 @@ +plugin_init +plugin_is_GPL_compatible diff --git a/libcc1/marshall-c.hh b/libcc1/marshall-c.hh new file mode 100644 index 00000000000..8505b06f228 --- /dev/null +++ b/libcc1/marshall-c.hh @@ -0,0 +1,59 @@ +/* Marshalling and unmarshalling of C-specific types. + Copyright (C) 2014 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef CC1_PLUGIN_MARSHALL_C_HH +#define CC1_PLUGIN_MARSHALL_C_HH + +#include "marshall.hh" +#include "gcc-c-interface.h" + +namespace cc1_plugin +{ + status + unmarshall (connection *conn, enum gcc_c_symbol_kind *result) + { + protocol_int p; + if (!unmarshall_intlike (conn, &p)) + return FAIL; + *result = (enum gcc_c_symbol_kind) p; + return OK; + } + + status + unmarshall (connection *conn, enum gcc_c_oracle_request *result) + { + protocol_int p; + if (!unmarshall_intlike (conn, &p)) + return FAIL; + *result = (enum gcc_c_oracle_request) p; + return OK; + } + + status + unmarshall (connection *conn, enum gcc_qualifiers *result) + { + protocol_int p; + if (!unmarshall_intlike (conn, &p)) + return FAIL; + *result = (enum gcc_qualifiers) p; + return OK; + } +} + +#endif // CC1_PLUGIN_MARSHALL_C_HH diff --git a/libcc1/marshall-cp.hh b/libcc1/marshall-cp.hh new file mode 100644 index 00000000000..45a9dc64b68 --- /dev/null +++ b/libcc1/marshall-cp.hh @@ -0,0 +1,59 @@ +/* Marshalling and unmarshalling of C++-specific types. + Copyright (C) 2014, 2015 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; + } +} + +#endif // CC1_PLUGIN_MARSHALL_CP_HH diff --git a/libcc1/marshall.cc b/libcc1/marshall.cc index 9119de652b7..0e4b77cb7e6 100644 --- a/libcc1/marshall.cc +++ b/libcc1/marshall.cc @@ -50,36 +50,6 @@ cc1_plugin::unmarshall_intlike (connection *conn, unsigned long long *result) } cc1_plugin::status -cc1_plugin::unmarshall (connection *conn, enum gcc_c_symbol_kind *result) -{ - protocol_int p; - if (!unmarshall_intlike (conn, &p)) - return FAIL; - *result = (enum gcc_c_symbol_kind) p; - return OK; -} - -cc1_plugin::status -cc1_plugin::unmarshall (connection *conn, enum gcc_c_oracle_request *result) -{ - protocol_int p; - if (!unmarshall_intlike (conn, &p)) - return FAIL; - *result = (enum gcc_c_oracle_request) p; - return OK; -} - -cc1_plugin::status -cc1_plugin::unmarshall (connection *conn, enum gcc_qualifiers *result) -{ - protocol_int p; - if (!unmarshall_intlike (conn, &p)) - return FAIL; - *result = (enum gcc_qualifiers) p; - return OK; -} - -cc1_plugin::status cc1_plugin::marshall (connection *conn, const char *str) { if (!conn->send ('s')) diff --git a/libcc1/marshall.hh b/libcc1/marshall.hh index 3f936e7a754..021ac965df9 100644 --- a/libcc1/marshall.hh +++ b/libcc1/marshall.hh @@ -21,7 +21,7 @@ along with GCC; see the file COPYING3. If not see #define CC1_PLUGIN_MARSHALL_HH #include "status.hh" -#include "gcc-c-interface.h" +#include "gcc-interface.h" namespace cc1_plugin { @@ -67,13 +67,6 @@ namespace cc1_plugin return OK; } - // Unmarshallers for some specific enum types. With C++11 we - // wouldn't need these, as we could add type traits to the scalar - // unmarshaller. - status unmarshall (connection *, enum gcc_c_symbol_kind *); - status unmarshall (connection *, enum gcc_qualifiers *); - status unmarshall (connection *, enum gcc_c_oracle_request *); - // Send a string type marker followed by a string. status marshall (connection *, const char *); diff --git a/libcc1/rpc.hh b/libcc1/rpc.hh index 58758d3d39e..43182a9c20a 100644 --- a/libcc1/rpc.hh +++ b/libcc1/rpc.hh @@ -21,7 +21,6 @@ along with GCC; see the file COPYING3. If not see #define CC1_PLUGIN_RPC_HH #include "status.hh" -#include "marshall.hh" #include "connection.hh" namespace cc1_plugin |