/* Library interface to C front end Copyright (C) 2014-2026 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 #define INCLUDE_VECTOR#define INCLUDE_MEMORY#define INCLUDE_VECTOR#include "gcc-plugin.h"#include "system.h"#include "coretypes.h"#include "stringpool.h" #include "gcc-interface.h"#include "hash-set.h"#include "machmode.h"#include "vec.h"#include "double-int.h"#include "input.h"#include "alias.h"#include "symtab.h"#include "options.h"#include "wide-int.h"#include "inchash.h"#include "tree.h"#include "fold-const.h"#include "stor-layout.h"#include "c-tree.h"#include "toplev.h"#include "timevar.h"#include "hash-table.h"#include "tm.h"#include "c-family/c-pragma.h"#include "c-lang.h"#include "diagnostic.h"#include "langhooks.h"#include "langhooks-def.h" #include "callbacks.hh"#include "connection.hh"#include "marshall.hh"#include "rpc.hh"#include "gcc-c-interface.h"#include "context.hh" using namespace cc1_plugin; // A wrapper for pushdecl that doesn't let gdb have a chance to// instantiate a symbol. static voidpushdecl_safe (tree decl){ void (*save) (enum c_oracle_request, tree identifier); save = c_binding_oracle; c_binding_oracle = NULL; pushdecl (decl); c_binding_oracle = save;} static voidplugin_binding_oracle (enum c_oracle_request kind, tree identifier){ enum gcc_c_oracle_request request; gcc_assert (current_context != NULL); switch (kind) { case C_ORACLE_SYMBOL: request = GCC_C_ORACLE_SYMBOL; break; case C_ORACLE_TAG: request = GCC_C_ORACLE_TAG; break; case C_ORACLE_LABEL: request = GCC_C_ORACLE_LABEL; break; default: abort (); } int ignore; cc1_plugin::call (current_context, "binding_oracle", &ignore, request, IDENTIFIER_POINTER (identifier));} static voidplugin_pragma_user_expression (cpp_reader *){ c_binding_oracle = plugin_binding_oracle;} static voidplugin_init_extra_pragmas (void *, void *){ c_register_pragma ("GCC", "user_expression", plugin_pragma_user_expression);} // Maybe rewrite a decl to its address.static treeaddress_rewriter (tree *in, int *walk_subtrees, void *arg){ plugin_context *ctx = (plugin_context *) arg; if (!DECL_P (*in) || DECL_NAME (*in) == NULL_TREE) return NULL_TREE; decl_addr_value value; value.decl = *in; decl_addr_value *found_value = ctx->address_map.find (&value); if (found_value != NULL) ; else if (DECL_IS_UNDECLARED_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 voidrewrite_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_declplugin_build_decl (cc1_plugin::connection *self, const char *name, enum gcc_c_symbol_kind sym_kind, gcc_type sym_type_in, const char *substitution_name, gcc_address address, const char *filename, unsigned int line_number){ plugin_context *ctx = static_cast<plugin_context *> (self); tree identifier = get_identifier (name); enum tree_code code; tree decl; tree sym_type = convert_in (sym_type_in); switch (sym_kind) { case GCC_C_SYMBOL_FUNCTION: code = FUNCTION_DECL; break; case GCC_C_SYMBOL_VARIABLE: code = VAR_DECL; break; case GCC_C_SYMBOL_TYPEDEF: code = TYPE_DECL; break; case GCC_C_SYMBOL_LABEL: // FIXME: we aren't ready to handle labels yet. // It isn't clear how to translate them properly // and in any case a "goto" isn't likely to work. return convert_out (error_mark_node); default: abort (); } location_t loc = ctx->get_location_t (filename, line_number); decl = build_decl (loc, code, identifier, sym_type); TREE_USED (decl) = 1; TREE_ADDRESSABLE (decl) = 1; if (sym_kind != GCC_C_SYMBOL_TYPEDEF) { decl_addr_value value; DECL_EXTERNAL (decl) = 1; value.decl = decl; if (substitution_name != NULL) { // If the translator gave us a name without a binding, // we can just substitute error_mark_node, since we know the // translator will be reporting an error anyhow. value.address = lookup_name (get_identifier (substitution_name)); if (value.address == NULL_TREE) value.address = error_mark_node; } else value.address = build_int_cst_type (ptr_type_node, address); decl_addr_value **slot = ctx->address_map.find_slot (&value, INSERT); gcc_assert (*slot == NULL); *slot = static_cast<decl_addr_value *> (xmalloc (sizeof (decl_addr_value))); **slot = value; } return convert_out (ctx->preserve (decl));} intplugin_bind (cc1_plugin::connection *, gcc_decl decl_in, int is_global){ tree decl = convert_in (decl_in); c_bind (DECL_SOURCE_LOCATION (decl), decl, is_global); rest_of_decl_compilation (decl, is_global, 0); return 1;} intplugin_tagbind (cc1_plugin::connection *self, const char *name, gcc_type tagged_type, const char *filename, unsigned int line_number){ plugin_context *ctx = static_cast<plugin_context *> (self); tree t = convert_in (tagged_type), x; c_pushtag (ctx->get_location_t (filename, line_number), get_identifier (name), t); /* Propagate the newly-added type name so that previously-created variant types are not disconnected from their main variants. */ for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x)) TYPE_NAME (x) = TYPE_NAME (t); return 1;} gcc_typeplugin_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 treebuild_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_typeplugin_build_record_type (cc1_plugin::connection *self){ plugin_context *ctx = static_cast<plugin_context *> (self); return convert_out (ctx->preserve (build_anonymous_node (RECORD_TYPE)));} gcc_typeplugin_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)));} intplugin_build_add_field (cc1_plugin::connection *, gcc_type record_or_union_type_in, const char *field_name, gcc_type field_type_in, unsigned long bitsize, unsigned long bitpos){ tree record_or_union_type = convert_in (record_or_union_type_in); tree field_type = convert_in (field_type_in); gcc_assert (TREE_CODE (record_or_union_type) == RECORD_TYPE || TREE_CODE (record_or_union_type) == UNION_TYPE); /* Note that gdb does not preserve the location of field decls, so we can't provide a decent location here. */ tree decl = build_decl (BUILTINS_LOCATION, FIELD_DECL, get_identifier (field_name), field_type); DECL_FIELD_CONTEXT (decl) = record_or_union_type; if (TREE_CODE (field_type) == INTEGER_TYPE && TYPE_PRECISION (field_type) != bitsize) { DECL_BIT_FIELD_TYPE (decl) = field_type; TREE_TYPE (decl) = c_build_bitfield_integer_type (bitsize, TYPE_UNSIGNED (field_type)); } SET_DECL_MODE (decl, TYPE_MODE (TREE_TYPE (decl))); // There's no way to recover this from DWARF. SET_DECL_OFFSET_ALIGN (decl, TYPE_PRECISION (pointer_sized_int_node)); tree pos = bitsize_int (bitpos); pos_from_bit (&DECL_FIELD_OFFSET (decl), &DECL_FIELD_BIT_OFFSET (decl), DECL_OFFSET_ALIGN (decl), pos); DECL_SIZE (decl) = bitsize_int (bitsize); DECL_SIZE_UNIT (decl) = size_int ((bitsize + BITS_PER_UNIT - 1) / BITS_PER_UNIT); DECL_CHAIN (decl) = TYPE_FIELDS (record_or_union_type); TYPE_FIELDS (record_or_union_type) = decl; return 1;} intplugin_finish_record_with_alignment (cc1_plugin::connection *, gcc_type record_or_union_type_in, unsigned long size_in_bytes, unsigned long align){ 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 { if (align == 0) align = TYPE_PRECISION (pointer_sized_int_node); SET_TYPE_ALIGN (record_or_union_type, align); TYPE_SIZE (record_or_union_type) = bitsize_int (size_in_bytes * BITS_PER_UNIT); TYPE_SIZE_UNIT (record_or_union_type) = size_int (size_in_bytes); compute_record_mode (record_or_union_type); finish_bitfield_layout (record_or_union_type); // FIXME we have no idea about TYPE_PACKED } tree t = record_or_union_type, x; for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x)) { /* Like finish_struct, update the qualified variant types. */ TYPE_FIELDS (x) = TYPE_FIELDS (t); TYPE_LANG_SPECIFIC (x) = TYPE_LANG_SPECIFIC (t); C_TYPE_FIELDS_READONLY (x) = C_TYPE_FIELDS_READONLY (t); C_TYPE_FIELDS_VOLATILE (x) = C_TYPE_FIELDS_VOLATILE (t); C_TYPE_VARIABLE_SIZE (x) = C_TYPE_VARIABLE_SIZE (t); /* We copy these fields too. */ SET_TYPE_ALIGN (x, TYPE_ALIGN (t)); TYPE_SIZE (x) = TYPE_SIZE (t); TYPE_SIZE_UNIT (x) = TYPE_SIZE_UNIT (t); if (x != record_or_union_type) compute_record_mode (x); } return 1;} intplugin_finish_record_or_union (cc1_plugin::connection *conn, gcc_type record_or_union_type_in, unsigned long size_in_bytes){ return plugin_finish_record_with_alignment (conn, record_or_union_type_in, size_in_bytes, 0);} gcc_typeplugin_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); ENUM_UNDERLYING_TYPE (result) = underlying_int_type; plugin_context *ctx = static_cast<plugin_context *> (self); return convert_out (ctx->preserve (result));} intplugin_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;} intplugin_finish_enum_type (cc1_plugin::connection *, gcc_type enum_type_in)Lines 1–500 of 832. Load more
/* Library interface to C front end Copyright (C) 2014-2026 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 #define INCLUDE_VECTOR #define INCLUDE_MEMORY #define INCLUDE_VECTOR #include "gcc-plugin.h" #include "system.h" #include "coretypes.h" #include "stringpool.h" #include "gcc-interface.h" #include "hash-set.h" #include "machmode.h" #include "vec.h" #include "double-int.h" #include "input.h" #include "alias.h" #include "symtab.h" #include "options.h" #include "wide-int.h" #include "inchash.h" #include "tree.h" #include "fold-const.h" #include "stor-layout.h" #include "c-tree.h" #include "toplev.h" #include "timevar.h" #include "hash-table.h" #include "tm.h" #include "c-family/c-pragma.h" #include "c-lang.h" #include "diagnostic.h" #include "langhooks.h" #include "langhooks-def.h" #include "callbacks.hh" #include "connection.hh" #include "marshall.hh" #include "rpc.hh" #include "gcc-c-interface.h" #include "context.hh" using namespace cc1_plugin; // A wrapper for pushdecl that doesn't let gdb have a chance to // instantiate a symbol. static void pushdecl_safe (tree decl) { void (*save) (enum c_oracle_request, tree identifier); save = c_binding_oracle; c_binding_oracle = NULL; pushdecl (decl); c_binding_oracle = save; } static void plugin_binding_oracle (enum c_oracle_request kind, tree identifier) { enum gcc_c_oracle_request request; gcc_assert (current_context != NULL); switch (kind) { case C_ORACLE_SYMBOL: request = GCC_C_ORACLE_SYMBOL; break; case C_ORACLE_TAG: request = GCC_C_ORACLE_TAG; break; case C_ORACLE_LABEL: request = GCC_C_ORACLE_LABEL; break; default: abort (); } int ignore; cc1_plugin::call (current_context, "binding_oracle", &ignore, request, IDENTIFIER_POINTER (identifier)); } static void plugin_pragma_user_expression (cpp_reader *) { c_binding_oracle = plugin_binding_oracle; } static void plugin_init_extra_pragmas (void *, void *) { c_register_pragma ("GCC", "user_expression", plugin_pragma_user_expression); } // Maybe rewrite a decl to its address. static tree address_rewriter (tree *in, int *walk_subtrees, void *arg) { plugin_context *ctx = (plugin_context *) arg; if (!DECL_P (*in) || DECL_NAME (*in) == NULL_TREE) return NULL_TREE; decl_addr_value value; value.decl = *in; decl_addr_value *found_value = ctx->address_map.find (&value); if (found_value != NULL) ; else if (DECL_IS_UNDECLARED_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_c_symbol_kind sym_kind, gcc_type sym_type_in, const char *substitution_name, gcc_address address, const char *filename, unsigned int line_number) { plugin_context *ctx = static_cast<plugin_context *> (self); tree identifier = get_identifier (name); enum tree_code code; tree decl; tree sym_type = convert_in (sym_type_in); switch (sym_kind) { case GCC_C_SYMBOL_FUNCTION: code = FUNCTION_DECL; break; case GCC_C_SYMBOL_VARIABLE: code = VAR_DECL; break; case GCC_C_SYMBOL_TYPEDEF: code = TYPE_DECL; break; case GCC_C_SYMBOL_LABEL: // FIXME: we aren't ready to handle labels yet. // It isn't clear how to translate them properly // and in any case a "goto" isn't likely to work. return convert_out (error_mark_node); default: abort (); } location_t loc = ctx->get_location_t (filename, line_number); decl = build_decl (loc, code, identifier, sym_type); TREE_USED (decl) = 1; TREE_ADDRESSABLE (decl) = 1; if (sym_kind != GCC_C_SYMBOL_TYPEDEF) { decl_addr_value value; DECL_EXTERNAL (decl) = 1; value.decl = decl; if (substitution_name != NULL) { // If the translator gave us a name without a binding, // we can just substitute error_mark_node, since we know the // translator will be reporting an error anyhow. value.address = lookup_name (get_identifier (substitution_name)); if (value.address == NULL_TREE) value.address = error_mark_node; } else value.address = build_int_cst_type (ptr_type_node, address); decl_addr_value **slot = ctx->address_map.find_slot (&value, INSERT); gcc_assert (*slot == NULL); *slot = static_cast<decl_addr_value *> (xmalloc (sizeof (decl_addr_value))); **slot = value; } return convert_out (ctx->preserve (decl)); } int plugin_bind (cc1_plugin::connection *, gcc_decl decl_in, int is_global) { tree decl = convert_in (decl_in); c_bind (DECL_SOURCE_LOCATION (decl), decl, is_global); rest_of_decl_compilation (decl, is_global, 0); return 1; } int plugin_tagbind (cc1_plugin::connection *self, const char *name, gcc_type tagged_type, const char *filename, unsigned int line_number) { plugin_context *ctx = static_cast<plugin_context *> (self); tree t = convert_in (tagged_type), x; c_pushtag (ctx->get_location_t (filename, line_number), get_identifier (name), t); /* Propagate the newly-added type name so that previously-created variant types are not disconnected from their main variants. */ for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x)) TYPE_NAME (x) = TYPE_NAME (t); return 1; } gcc_type plugin_build_pointer_type (cc1_plugin::connection *, gcc_type base_type) { // No need to preserve a pointer type as the base type is preserved. return convert_out (build_pointer_type (convert_in (base_type))); } // TYPE_NAME needs to be a valid pointer, even if there is no name available. static tree build_anonymous_node (enum tree_code code) { tree node = make_node (code); tree type_decl = build_decl (input_location, TYPE_DECL, NULL_TREE, node); TYPE_NAME (node) = type_decl; TYPE_STUB_DECL (node) = type_decl; return node; } gcc_type plugin_build_record_type (cc1_plugin::connection *self) { plugin_context *ctx = static_cast<plugin_context *> (self); return convert_out (ctx->preserve (build_anonymous_node (RECORD_TYPE))); } gcc_type plugin_build_union_type (cc1_plugin::connection *self) { plugin_context *ctx = static_cast<plugin_context *> (self); return convert_out (ctx->preserve (build_anonymous_node (UNION_TYPE))); } int plugin_build_add_field (cc1_plugin::connection *, gcc_type record_or_union_type_in, const char *field_name, gcc_type field_type_in, unsigned long bitsize, unsigned long bitpos) { tree record_or_union_type = convert_in (record_or_union_type_in); tree field_type = convert_in (field_type_in); gcc_assert (TREE_CODE (record_or_union_type) == RECORD_TYPE || TREE_CODE (record_or_union_type) == UNION_TYPE); /* Note that gdb does not preserve the location of field decls, so we can't provide a decent location here. */ tree decl = build_decl (BUILTINS_LOCATION, FIELD_DECL, get_identifier (field_name), field_type); DECL_FIELD_CONTEXT (decl) = record_or_union_type; if (TREE_CODE (field_type) == INTEGER_TYPE && TYPE_PRECISION (field_type) != bitsize) { DECL_BIT_FIELD_TYPE (decl) = field_type; TREE_TYPE (decl) = c_build_bitfield_integer_type (bitsize, TYPE_UNSIGNED (field_type)); } SET_DECL_MODE (decl, TYPE_MODE (TREE_TYPE (decl))); // There's no way to recover this from DWARF. SET_DECL_OFFSET_ALIGN (decl, TYPE_PRECISION (pointer_sized_int_node)); tree pos = bitsize_int (bitpos); pos_from_bit (&DECL_FIELD_OFFSET (decl), &DECL_FIELD_BIT_OFFSET (decl), DECL_OFFSET_ALIGN (decl), pos); DECL_SIZE (decl) = bitsize_int (bitsize); DECL_SIZE_UNIT (decl) = size_int ((bitsize + BITS_PER_UNIT - 1) / BITS_PER_UNIT); DECL_CHAIN (decl) = TYPE_FIELDS (record_or_union_type); TYPE_FIELDS (record_or_union_type) = decl; return 1; } int plugin_finish_record_with_alignment (cc1_plugin::connection *, gcc_type record_or_union_type_in, unsigned long size_in_bytes, unsigned long align) { 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 { if (align == 0) align = TYPE_PRECISION (pointer_sized_int_node); SET_TYPE_ALIGN (record_or_union_type, align); TYPE_SIZE (record_or_union_type) = bitsize_int (size_in_bytes * BITS_PER_UNIT); TYPE_SIZE_UNIT (record_or_union_type) = size_int (size_in_bytes); compute_record_mode (record_or_union_type); finish_bitfield_layout (record_or_union_type); // FIXME we have no idea about TYPE_PACKED } tree t = record_or_union_type, x; for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x)) { /* Like finish_struct, update the qualified variant types. */ TYPE_FIELDS (x) = TYPE_FIELDS (t); TYPE_LANG_SPECIFIC (x) = TYPE_LANG_SPECIFIC (t); C_TYPE_FIELDS_READONLY (x) = C_TYPE_FIELDS_READONLY (t); C_TYPE_FIELDS_VOLATILE (x) = C_TYPE_FIELDS_VOLATILE (t); C_TYPE_VARIABLE_SIZE (x) = C_TYPE_VARIABLE_SIZE (t); /* We copy these fields too. */ SET_TYPE_ALIGN (x, TYPE_ALIGN (t)); TYPE_SIZE (x) = TYPE_SIZE (t); TYPE_SIZE_UNIT (x) = TYPE_SIZE_UNIT (t); if (x != record_or_union_type) compute_record_mode (x); } return 1; } int plugin_finish_record_or_union (cc1_plugin::connection *conn, gcc_type record_or_union_type_in, unsigned long size_in_bytes) { return plugin_finish_record_with_alignment (conn, record_or_union_type_in, size_in_bytes, 0); } 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); ENUM_UNDERLYING_TYPE (result) = 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)