X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fattribs.c;h=4d91a0d65250b4d0f6cb42266beb640e34857814;hp=74786a543768f5681476efd86d4b4c0fc57a4cdf;hb=8135a42b49e8d0cffae093b782b3636838b363ca;hpb=771d21fab6794ddeb9c317b7e6fd7e47ef70985a diff --git a/gcc/attribs.c b/gcc/attribs.c index 74786a54376..4d91a0d6525 100644 --- a/gcc/attribs.c +++ b/gcc/attribs.c @@ -1,12 +1,13 @@ /* Functions dealing with attribute handling, used by most front ends. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - 2002 Free Software Foundation, Inc. + 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 + 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 2, or (at your option) any later +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 @@ -15,178 +16,115 @@ 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 COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +along with GCC; see the file COPYING3. If not see +. */ #include "config.h" #include "system.h" +#include "coretypes.h" +#include "tm.h" #include "tree.h" #include "flags.h" #include "toplev.h" #include "output.h" #include "rtl.h" #include "ggc.h" -#include "expr.h" #include "tm_p.h" -#include "obstack.h" #include "cpplib.h" #include "target.h" #include "langhooks.h" +#include "hashtab.h" +#include "plugin.h" -static void init_attributes PARAMS ((void)); +static void init_attributes (void); -/* Table of the tables of attributes (common, format, language, machine) +/* Table of the tables of attributes (common, language, format, machine) searched. */ static const struct attribute_spec *attribute_tables[4]; -static bool attributes_initialized = false; +/* Hashtable mapping names (represented as substrings) to attribute specs. */ +static htab_t attribute_hash; + +/* Substring representation. */ -static tree handle_packed_attribute PARAMS ((tree *, tree, tree, int, - bool *)); -static tree handle_nocommon_attribute PARAMS ((tree *, tree, tree, int, - bool *)); -static tree handle_common_attribute PARAMS ((tree *, tree, tree, int, - bool *)); -static tree handle_noreturn_attribute PARAMS ((tree *, tree, tree, int, - bool *)); -static tree handle_noinline_attribute PARAMS ((tree *, tree, tree, int, - bool *)); -static tree handle_always_inline_attribute PARAMS ((tree *, tree, tree, int, - bool *)); -static tree handle_used_attribute PARAMS ((tree *, tree, tree, int, - bool *)); -static tree handle_unused_attribute PARAMS ((tree *, tree, tree, int, - bool *)); -static tree handle_const_attribute PARAMS ((tree *, tree, tree, int, - bool *)); -static tree handle_transparent_union_attribute PARAMS ((tree *, tree, tree, - int, bool *)); -static tree handle_constructor_attribute PARAMS ((tree *, tree, tree, int, - bool *)); -static tree handle_destructor_attribute PARAMS ((tree *, tree, tree, int, - bool *)); -static tree handle_mode_attribute PARAMS ((tree *, tree, tree, int, - bool *)); -static tree handle_section_attribute PARAMS ((tree *, tree, tree, int, - bool *)); -static tree handle_aligned_attribute PARAMS ((tree *, tree, tree, int, - bool *)); -static tree handle_weak_attribute PARAMS ((tree *, tree, tree, int, - bool *)); -static tree handle_alias_attribute PARAMS ((tree *, tree, tree, int, - bool *)); -static tree handle_visibility_attribute PARAMS ((tree *, tree, tree, int, - bool *)); -static tree handle_no_instrument_function_attribute PARAMS ((tree *, tree, - tree, int, - bool *)); -static tree handle_malloc_attribute PARAMS ((tree *, tree, tree, int, - bool *)); -static tree handle_no_limit_stack_attribute PARAMS ((tree *, tree, tree, int, - bool *)); -static tree handle_pure_attribute PARAMS ((tree *, tree, tree, int, - bool *)); -static tree handle_deprecated_attribute PARAMS ((tree *, tree, tree, int, - bool *)); -static tree handle_vector_size_attribute PARAMS ((tree *, tree, tree, int, - bool *)); -static tree vector_size_helper PARAMS ((tree, tree)); - -/* Table of machine-independent attributes common to all C-like languages. */ -static const struct attribute_spec c_common_attribute_table[] = +struct substring { - /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ - { "packed", 0, 0, false, false, false, - handle_packed_attribute }, - { "nocommon", 0, 0, true, false, false, - handle_nocommon_attribute }, - { "common", 0, 0, true, false, false, - handle_common_attribute }, - /* FIXME: logically, noreturn attributes should be listed as - "false, true, true" and apply to function types. But implementing this - would require all the places in the compiler that use TREE_THIS_VOLATILE - on a decl to identify non-returning functions to be located and fixed - to check the function type instead. */ - { "noreturn", 0, 0, true, false, false, - handle_noreturn_attribute }, - { "volatile", 0, 0, true, false, false, - handle_noreturn_attribute }, - { "noinline", 0, 0, true, false, false, - handle_noinline_attribute }, - { "always_inline", 0, 0, true, false, false, - handle_always_inline_attribute }, - { "used", 0, 0, true, false, false, - handle_used_attribute }, - { "unused", 0, 0, false, false, false, - handle_unused_attribute }, - /* The same comments as for noreturn attributes apply to const ones. */ - { "const", 0, 0, true, false, false, - handle_const_attribute }, - { "transparent_union", 0, 0, false, false, false, - handle_transparent_union_attribute }, - { "constructor", 0, 0, true, false, false, - handle_constructor_attribute }, - { "destructor", 0, 0, true, false, false, - handle_destructor_attribute }, - { "mode", 1, 1, false, true, false, - handle_mode_attribute }, - { "section", 1, 1, true, false, false, - handle_section_attribute }, - { "aligned", 0, 1, false, false, false, - handle_aligned_attribute }, - { "weak", 0, 0, true, false, false, - handle_weak_attribute }, - { "alias", 1, 1, true, false, false, - handle_alias_attribute }, - { "no_instrument_function", 0, 0, true, false, false, - handle_no_instrument_function_attribute }, - { "malloc", 0, 0, true, false, false, - handle_malloc_attribute }, - { "no_stack_limit", 0, 0, true, false, false, - handle_no_limit_stack_attribute }, - { "pure", 0, 0, true, false, false, - handle_pure_attribute }, - { "deprecated", 0, 0, false, false, false, - handle_deprecated_attribute }, - { "vector_size", 1, 1, false, true, false, - handle_vector_size_attribute }, - { "visibility", 1, 1, true, false, false, - handle_visibility_attribute }, - { NULL, 0, 0, false, false, false, NULL } + const char *str; + int length; }; +static bool attributes_initialized = false; + /* Default empty table of attributes. */ + static const struct attribute_spec empty_attribute_table[] = { { NULL, 0, 0, false, false, false, NULL } }; -/* Table of machine-independent attributes for checking formats, if used. */ -const struct attribute_spec *format_attribute_table = empty_attribute_table; +/* Return base name of the attribute. Ie '__attr__' is turned into 'attr'. + To avoid need for copying, we simply return length of the string. */ + +static void +extract_attribute_substring (struct substring *str) +{ + if (str->length > 4 && str->str[0] == '_' && str->str[1] == '_' + && str->str[str->length - 1] == '_' && str->str[str->length - 2] == '_') + { + str->length -= 4; + str->str += 2; + } +} + +/* Simple hash function to avoid need to scan whole string. */ + +static inline hashval_t +substring_hash (const char *str, int l) +{ + return str[0] + str[l - 1] * 256 + l * 65536; +} -/* Table of machine-independent attributes for a particular language. */ -const struct attribute_spec *lang_attribute_table = empty_attribute_table; +/* Used for attribute_hash. */ -/* Flag saying whether common language attributes are to be supported. */ -int lang_attribute_common = 1; +static hashval_t +hash_attr (const void *p) +{ + const struct attribute_spec *const spec = (const struct attribute_spec *) p; + const int l = strlen (spec->name); + + return substring_hash (spec->name, l); +} + +/* Used for attribute_hash. */ + +static int +eq_attr (const void *p, const void *q) +{ + const struct attribute_spec *const spec = (const struct attribute_spec *) p; + const struct substring *const str = (const struct substring *) q; + + return (!strncmp (spec->name, str->str, str->length) && !spec->name[str->length]); +} /* Initialize attribute tables, and make some sanity checks if --enable-checking. */ static void -init_attributes () +init_attributes (void) { -#ifdef ENABLE_CHECKING size_t i; -#endif + int k; - attribute_tables[0] - = lang_attribute_common ? c_common_attribute_table : empty_attribute_table; - attribute_tables[1] = lang_attribute_table; - attribute_tables[2] = format_attribute_table; + attribute_tables[0] = lang_hooks.common_attribute_table; + attribute_tables[1] = lang_hooks.attribute_table; + attribute_tables[2] = lang_hooks.format_attribute_table; attribute_tables[3] = targetm.attribute_table; + /* Translate NULL pointers to pointers to the empty table. */ + for (i = 0; i < ARRAY_SIZE (attribute_tables); i++) + if (attribute_tables[i] == NULL) + attribute_tables[i] = empty_attribute_table; + #ifdef ENABLE_CHECKING /* Make some sanity checks on the attribute tables. */ for (i = 0; i < ARRAY_SIZE (attribute_tables); i++) @@ -198,25 +136,25 @@ init_attributes () /* The name must not begin and end with __. */ const char *name = attribute_tables[i][j].name; int len = strlen (name); - if (name[0] == '_' && name[1] == '_' - && name[len - 1] == '_' && name[len - 2] == '_') - abort (); + + gcc_assert (!(name[0] == '_' && name[1] == '_' + && name[len - 1] == '_' && name[len - 2] == '_')); + /* The minimum and maximum lengths must be consistent. */ - if (attribute_tables[i][j].min_length < 0) - abort (); - if (attribute_tables[i][j].max_length != -1 - && (attribute_tables[i][j].max_length - < attribute_tables[i][j].min_length)) - abort (); + gcc_assert (attribute_tables[i][j].min_length >= 0); + + gcc_assert (attribute_tables[i][j].max_length == -1 + || (attribute_tables[i][j].max_length + >= attribute_tables[i][j].min_length)); + /* An attribute cannot require both a DECL and a TYPE. */ - if (attribute_tables[i][j].decl_required - && attribute_tables[i][j].type_required) - abort (); + gcc_assert (!attribute_tables[i][j].decl_required + || !attribute_tables[i][j].type_required); + /* If an attribute requires a function type, in particular it requires a type. */ - if (attribute_tables[i][j].function_type_required - && !attribute_tables[i][j].type_required) - abort (); + gcc_assert (!attribute_tables[i][j].function_type_required + || attribute_tables[i][j].type_required); } } @@ -226,9 +164,8 @@ init_attributes () int j, k; for (j = 0; attribute_tables[i][j].name != NULL; j++) for (k = j + 1; attribute_tables[i][k].name != NULL; k++) - if (!strcmp (attribute_tables[i][j].name, - attribute_tables[i][k].name)) - abort (); + gcc_assert (strcmp (attribute_tables[i][j].name, + attribute_tables[i][k].name)); } /* Check that no name occurs in more than one table. */ for (i = 0; i < ARRAY_SIZE (attribute_tables); i++) @@ -238,14 +175,52 @@ init_attributes () for (j = i + 1; j < ARRAY_SIZE (attribute_tables); j++) for (k = 0; attribute_tables[i][k].name != NULL; k++) for (l = 0; attribute_tables[j][l].name != NULL; l++) - if (!strcmp (attribute_tables[i][k].name, - attribute_tables[j][l].name)) - abort (); + gcc_assert (strcmp (attribute_tables[i][k].name, + attribute_tables[j][l].name)); } #endif + attribute_hash = htab_create (200, hash_attr, eq_attr, NULL); + for (i = 0; i < ARRAY_SIZE (attribute_tables); i++) + for (k = 0; attribute_tables[i][k].name != NULL; k++) + { + register_attribute (&attribute_tables[i][k]); + } + invoke_plugin_callbacks (PLUGIN_ATTRIBUTES, NULL); attributes_initialized = true; } + +/* Insert a single ATTR into the attribute table. */ + +void +register_attribute (const struct attribute_spec *attr) +{ + struct substring str; + void **slot; + + str.str = attr->name; + str.length = strlen (str.str); + slot = htab_find_slot_with_hash (attribute_hash, &str, + substring_hash (str.str, str.length), + INSERT); + gcc_assert (!*slot); + *slot = (void *) CONST_CAST (struct attribute_spec *, attr); +} + +/* Return the spec for the attribute named NAME. */ + +const struct attribute_spec * +lookup_attribute_spec (tree name) +{ + struct substring attr; + + attr.str = IDENTIFIER_POINTER (name); + attr.length = IDENTIFIER_LENGTH (name); + extract_attribute_substring (&attr); + return (const struct attribute_spec *) + htab_find_with_hash (attribute_hash, &attr, + substring_hash (attr.str, attr.length)); +} /* Process the attributes listed in ATTRIBUTES and install them in *NODE, which is either a DECL (including a TYPE_DECL) or a TYPE. If a DECL, @@ -254,68 +229,82 @@ init_attributes () information, in the form of a bitwise OR of flags in enum attribute_flags from tree.h. Depending on these flags, some attributes may be returned to be applied at a later stage (for example, to apply - a decl attribute to the declaration rather than to its type). If - ATTR_FLAG_BUILT_IN is not set and *NODE is a DECL, then also consider - whether there might be some default attributes to apply to this DECL; - if so, decl_attributes will be called recursively with those attributes - and ATTR_FLAG_BUILT_IN set. */ + a decl attribute to the declaration rather than to its type). */ tree -decl_attributes (node, attributes, flags) - tree *node, attributes; - int flags; +decl_attributes (tree *node, tree attributes, int flags) { tree a; tree returned_attrs = NULL_TREE; + if (TREE_TYPE (*node) == error_mark_node) + return NULL_TREE; + if (!attributes_initialized) init_attributes (); - (*targetm.insert_attributes) (*node, &attributes); + /* If this is a function and the user used #pragma GCC optimize, add the + options to the attribute((optimize(...))) list. */ + if (TREE_CODE (*node) == FUNCTION_DECL && current_optimize_pragma) + { + tree cur_attr = lookup_attribute ("optimize", attributes); + tree opts = copy_list (current_optimize_pragma); + + if (! cur_attr) + attributes + = tree_cons (get_identifier ("optimize"), opts, attributes); + else + TREE_VALUE (cur_attr) = chainon (opts, TREE_VALUE (cur_attr)); + } + + if (TREE_CODE (*node) == FUNCTION_DECL + && optimization_current_node != optimization_default_node + && !DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node)) + DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node) = optimization_current_node; + + /* If this is a function and the user used #pragma GCC target, add the + options to the attribute((target(...))) list. */ + if (TREE_CODE (*node) == FUNCTION_DECL + && current_target_pragma + && targetm.target_option.valid_attribute_p (*node, NULL_TREE, + current_target_pragma, 0)) + { + tree cur_attr = lookup_attribute ("target", attributes); + tree opts = copy_list (current_target_pragma); + + if (! cur_attr) + attributes = tree_cons (get_identifier ("target"), opts, attributes); + else + TREE_VALUE (cur_attr) = chainon (opts, TREE_VALUE (cur_attr)); + } - if (DECL_P (*node) && TREE_CODE (*node) == FUNCTION_DECL - && !(flags & (int) ATTR_FLAG_BUILT_IN)) - (*lang_hooks.insert_default_attributes) (*node); + targetm.insert_attributes (*node, &attributes); for (a = attributes; a; a = TREE_CHAIN (a)) { tree name = TREE_PURPOSE (a); tree args = TREE_VALUE (a); tree *anode = node; - const struct attribute_spec *spec = NULL; + const struct attribute_spec *spec = lookup_attribute_spec (name); bool no_add_attrs = 0; - size_t i; - - for (i = 0; i < ARRAY_SIZE (attribute_tables); i++) - { - int j; - - for (j = 0; attribute_tables[i][j].name != NULL; j++) - { - if (is_attribute_p (attribute_tables[i][j].name, name)) - { - spec = &attribute_tables[i][j]; - break; - } - } - if (spec != NULL) - break; - } + int fn_ptr_quals = 0; + tree fn_ptr_tmp = NULL_TREE; if (spec == NULL) { - warning ("`%s' attribute directive ignored", - IDENTIFIER_POINTER (name)); + warning (OPT_Wattributes, "%qE attribute directive ignored", + name); continue; } else if (list_length (args) < spec->min_length || (spec->max_length >= 0 && list_length (args) > spec->max_length)) { - error ("wrong number of arguments specified for `%s' attribute", - IDENTIFIER_POINTER (name)); + error ("wrong number of arguments specified for %qE attribute", + name); continue; } + gcc_assert (is_attribute_p (spec->name, name)); if (spec->decl_required && !DECL_P (*anode)) { @@ -329,8 +318,8 @@ decl_attributes (node, attributes, flags) } else { - warning ("`%s' attribute does not apply to types", - IDENTIFIER_POINTER (name)); + warning (OPT_Wattributes, "%qE attribute does not apply to types", + name); continue; } } @@ -342,7 +331,11 @@ decl_attributes (node, attributes, flags) if (spec->type_required && DECL_P (*anode)) { anode = &TREE_TYPE (*anode); - flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE; + /* Allow ATTR_FLAG_TYPE_IN_PLACE for the type's naming decl. */ + if (!(TREE_CODE (*anode) == TYPE_DECL + && *anode == TYPE_NAME (TYPE_MAIN_VARIANT + (TREE_TYPE (*anode))))) + flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE; } if (spec->function_type_required && TREE_CODE (*anode) != FUNCTION_TYPE @@ -352,9 +345,19 @@ decl_attributes (node, attributes, flags) && (TREE_CODE (TREE_TYPE (*anode)) == FUNCTION_TYPE || TREE_CODE (TREE_TYPE (*anode)) == METHOD_TYPE)) { - if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) - *anode = build_type_copy (*anode); - anode = &TREE_TYPE (*anode); + /* OK, this is a bit convoluted. We can't just make a copy + of the pointer type and modify its TREE_TYPE, because if + we change the attributes of the target type the pointer + type needs to have a different TYPE_MAIN_VARIANT. So we + pull out the target type now, frob it as appropriate, and + rebuild the pointer type later. + + This would all be simpler if attributes were part of the + declarator, grumble grumble. */ + fn_ptr_tmp = TREE_TYPE (*anode); + fn_ptr_quals = TYPE_QUALS (*anode); + anode = &fn_ptr_tmp; + flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE; } else if (flags & (int) ATTR_FLAG_FUNCTION_NEXT) { @@ -366,12 +369,21 @@ decl_attributes (node, attributes, flags) if (TREE_CODE (*anode) != FUNCTION_TYPE && TREE_CODE (*anode) != METHOD_TYPE) { - warning ("`%s' attribute only applies to function types", - IDENTIFIER_POINTER (name)); + warning (OPT_Wattributes, + "%qE attribute only applies to function types", + name); continue; } } + if (TYPE_P (*anode) + && (flags & (int) ATTR_FLAG_TYPE_IN_PLACE) + && TYPE_SIZE (*anode) != NULL_TREE) + { + warning (OPT_Wattributes, "type attributes ignored after type is already defined"); + continue; + } + if (spec->handler != NULL) returned_attrs = chainon ((*spec->handler) (anode, name, args, flags, &no_add_attrs), @@ -382,13 +394,7 @@ decl_attributes (node, attributes, flags) && (TREE_CODE (*node) == VAR_DECL || TREE_CODE (*node) == PARM_DECL || TREE_CODE (*node) == RESULT_DECL)) - { - /* Force a recalculation of mode and size. */ - DECL_MODE (*node) = VOIDmode; - DECL_SIZE (*node) = 0; - - layout_decl (*node, 0); - } + relayout_decl (*node); if (!no_add_attrs) { @@ -414,1108 +420,49 @@ decl_attributes (node, attributes, flags) if (DECL_P (*anode)) DECL_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs); else if (flags & (int) ATTR_FLAG_TYPE_IN_PLACE) - TYPE_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs); + { + TYPE_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs); + /* If this is the main variant, also push the attributes + out to the other variants. */ + if (*anode == TYPE_MAIN_VARIANT (*anode)) + { + tree variant; + for (variant = *anode; variant; + variant = TYPE_NEXT_VARIANT (variant)) + { + if (TYPE_ATTRIBUTES (variant) == old_attrs) + TYPE_ATTRIBUTES (variant) + = TYPE_ATTRIBUTES (*anode); + else if (!lookup_attribute + (spec->name, TYPE_ATTRIBUTES (variant))) + TYPE_ATTRIBUTES (variant) = tree_cons + (name, args, TYPE_ATTRIBUTES (variant)); + } + } + } else *anode = build_type_attribute_variant (*anode, tree_cons (name, args, old_attrs)); } } - } - - return returned_attrs; -} - -/* Handle a "packed" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_packed_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name; - tree args ATTRIBUTE_UNUSED; - int flags; - bool *no_add_attrs; -{ - tree *type = NULL; - if (DECL_P (*node)) - { - if (TREE_CODE (*node) == TYPE_DECL) - type = &TREE_TYPE (*node); - } - else - type = node; - - if (type) - { - if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) - *type = build_type_copy (*type); - TYPE_PACKED (*type) = 1; - } - else if (TREE_CODE (*node) == FIELD_DECL) - DECL_PACKED (*node) = 1; - /* We can't set DECL_PACKED for a VAR_DECL, because the bit is - used for DECL_REGISTER. It wouldn't mean anything anyway. */ - else - { - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "nocommon" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_nocommon_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name; - tree args ATTRIBUTE_UNUSED; - int flags ATTRIBUTE_UNUSED; - bool *no_add_attrs; -{ - if (TREE_CODE (*node) == VAR_DECL) - DECL_COMMON (*node) = 0; - else - { - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "common" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_common_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name; - tree args ATTRIBUTE_UNUSED; - int flags ATTRIBUTE_UNUSED; - bool *no_add_attrs; -{ - if (TREE_CODE (*node) == VAR_DECL) - DECL_COMMON (*node) = 1; - else - { - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "noreturn" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_noreturn_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name; - tree args ATTRIBUTE_UNUSED; - int flags ATTRIBUTE_UNUSED; - bool *no_add_attrs; -{ - tree type = TREE_TYPE (*node); - - /* See FIXME comment in c_common_attribute_table. */ - if (TREE_CODE (*node) == FUNCTION_DECL) - TREE_THIS_VOLATILE (*node) = 1; - else if (TREE_CODE (type) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) - TREE_TYPE (*node) - = build_pointer_type - (build_type_variant (TREE_TYPE (type), - TREE_READONLY (TREE_TYPE (type)), 1)); - else - { - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "noinline" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_noinline_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name; - tree args ATTRIBUTE_UNUSED; - int flags ATTRIBUTE_UNUSED; - bool *no_add_attrs; -{ - if (TREE_CODE (*node) == FUNCTION_DECL) - DECL_UNINLINABLE (*node) = 1; - else - { - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "always_inline" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_always_inline_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name; - tree args ATTRIBUTE_UNUSED; - int flags ATTRIBUTE_UNUSED; - bool *no_add_attrs; -{ - if (TREE_CODE (*node) == FUNCTION_DECL) - { - /* Do nothing else, just set the attribute. We'll get at - it later with lookup_attribute. */ - } - else - { - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "used" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_used_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name; - tree args ATTRIBUTE_UNUSED; - int flags ATTRIBUTE_UNUSED; - bool *no_add_attrs; -{ - if (TREE_CODE (*node) == FUNCTION_DECL) - TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (*node)) - = TREE_USED (*node) = 1; - else - { - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "unused" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_unused_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name; - tree args ATTRIBUTE_UNUSED; - int flags; - bool *no_add_attrs; -{ - if (DECL_P (*node)) - { - tree decl = *node; - - if (TREE_CODE (decl) == PARM_DECL - || TREE_CODE (decl) == VAR_DECL - || TREE_CODE (decl) == FUNCTION_DECL - || TREE_CODE (decl) == LABEL_DECL - || TREE_CODE (decl) == TYPE_DECL) - TREE_USED (decl) = 1; - else - { - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - *no_add_attrs = true; - } - } - else - { - if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) - *node = build_type_copy (*node); - TREE_USED (*node) = 1; - } - - return NULL_TREE; -} - -/* Handle a "const" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_const_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name; - tree args ATTRIBUTE_UNUSED; - int flags ATTRIBUTE_UNUSED; - bool *no_add_attrs; -{ - tree type = TREE_TYPE (*node); - - /* See FIXME comment on noreturn in c_common_attribute_table. */ - if (TREE_CODE (*node) == FUNCTION_DECL) - TREE_READONLY (*node) = 1; - else if (TREE_CODE (type) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) - TREE_TYPE (*node) - = build_pointer_type - (build_type_variant (TREE_TYPE (type), 1, - TREE_THIS_VOLATILE (TREE_TYPE (type)))); - else - { - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "transparent_union" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_transparent_union_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name; - tree args ATTRIBUTE_UNUSED; - int flags; - bool *no_add_attrs; -{ - tree decl = NULL_TREE; - tree *type = NULL; - int is_type = 0; - - if (DECL_P (*node)) - { - decl = *node; - type = &TREE_TYPE (decl); - is_type = TREE_CODE (*node) == TYPE_DECL; - } - else if (TYPE_P (*node)) - type = node, is_type = 1; - - if (is_type - && TREE_CODE (*type) == UNION_TYPE - && (decl == 0 - || (TYPE_FIELDS (*type) != 0 - && TYPE_MODE (*type) == DECL_MODE (TYPE_FIELDS (*type))))) - { - if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) - *type = build_type_copy (*type); - TYPE_TRANSPARENT_UNION (*type) = 1; - } - else if (decl != 0 && TREE_CODE (decl) == PARM_DECL - && TREE_CODE (*type) == UNION_TYPE - && TYPE_MODE (*type) == DECL_MODE (TYPE_FIELDS (*type))) - DECL_TRANSPARENT_UNION (decl) = 1; - else - { - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "constructor" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_constructor_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name; - tree args ATTRIBUTE_UNUSED; - int flags ATTRIBUTE_UNUSED; - bool *no_add_attrs; -{ - tree decl = *node; - tree type = TREE_TYPE (decl); - - if (TREE_CODE (decl) == FUNCTION_DECL - && TREE_CODE (type) == FUNCTION_TYPE - && decl_function_context (decl) == 0) - { - DECL_STATIC_CONSTRUCTOR (decl) = 1; - TREE_USED (decl) = 1; - } - else - { - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "destructor" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_destructor_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name; - tree args ATTRIBUTE_UNUSED; - int flags ATTRIBUTE_UNUSED; - bool *no_add_attrs; -{ - tree decl = *node; - tree type = TREE_TYPE (decl); - - if (TREE_CODE (decl) == FUNCTION_DECL - && TREE_CODE (type) == FUNCTION_TYPE - && decl_function_context (decl) == 0) - { - DECL_STATIC_DESTRUCTOR (decl) = 1; - TREE_USED (decl) = 1; - } - else - { - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "mode" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_mode_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name; - tree args; - int flags ATTRIBUTE_UNUSED; - bool *no_add_attrs; -{ - tree type = *node; - - *no_add_attrs = true; - - if (TREE_CODE (TREE_VALUE (args)) != IDENTIFIER_NODE) - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - else - { - int j; - const char *p = IDENTIFIER_POINTER (TREE_VALUE (args)); - int len = strlen (p); - enum machine_mode mode = VOIDmode; - tree typefm; - - if (len > 4 && p[0] == '_' && p[1] == '_' - && p[len - 1] == '_' && p[len - 2] == '_') - { - char *newp = (char *) alloca (len - 1); - - strcpy (newp, &p[2]); - newp[len - 4] = '\0'; - p = newp; - } - - /* Change this type to have a type with the specified mode. - First check for the special modes. */ - if (! strcmp (p, "byte")) - mode = byte_mode; - else if (!strcmp (p, "word")) - mode = word_mode; - else if (! strcmp (p, "pointer")) - mode = ptr_mode; - else - for (j = 0; j < NUM_MACHINE_MODES; j++) - if (!strcmp (p, GET_MODE_NAME (j))) - mode = (enum machine_mode) j; - - if (mode == VOIDmode) - error ("unknown machine mode `%s'", p); - else if (0 == (typefm = (*lang_hooks.types.type_for_mode) - (mode, TREE_UNSIGNED (type)))) - error ("no data type for mode `%s'", p); - else - *node = typefm; - /* No need to layout the type here. The caller should do this. */ - } - - return NULL_TREE; -} - -/* Handle a "section" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_section_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name ATTRIBUTE_UNUSED; - tree args; - int flags ATTRIBUTE_UNUSED; - bool *no_add_attrs; -{ - tree decl = *node; - - if (targetm.have_named_sections) - { - if ((TREE_CODE (decl) == FUNCTION_DECL - || TREE_CODE (decl) == VAR_DECL) - && TREE_CODE (TREE_VALUE (args)) == STRING_CST) - { - if (TREE_CODE (decl) == VAR_DECL - && current_function_decl != NULL_TREE - && ! TREE_STATIC (decl)) - { - error_with_decl (decl, - "section attribute cannot be specified for local variables"); - *no_add_attrs = true; - } - - /* The decl may have already been given a section attribute - from a previous declaration. Ensure they match. */ - else if (DECL_SECTION_NAME (decl) != NULL_TREE - && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)), - TREE_STRING_POINTER (TREE_VALUE (args))) != 0) - { - error_with_decl (*node, - "section of `%s' conflicts with previous declaration"); - *no_add_attrs = true; - } - else - DECL_SECTION_NAME (decl) = TREE_VALUE (args); - } - else - { - error_with_decl (*node, - "section attribute not allowed for `%s'"); - *no_add_attrs = true; - } - } - else - { - error_with_decl (*node, - "section attributes are not supported for this target"); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "aligned" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_aligned_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name ATTRIBUTE_UNUSED; - tree args; - int flags; - bool *no_add_attrs; -{ - tree decl = NULL_TREE; - tree *type = NULL; - int is_type = 0; - tree align_expr = (args ? TREE_VALUE (args) - : size_int (BIGGEST_ALIGNMENT / BITS_PER_UNIT)); - int i; - - if (DECL_P (*node)) - { - decl = *node; - type = &TREE_TYPE (decl); - is_type = TREE_CODE (*node) == TYPE_DECL; - } - else if (TYPE_P (*node)) - type = node, is_type = 1; - - /* Strip any NOPs of any kind. */ - while (TREE_CODE (align_expr) == NOP_EXPR - || TREE_CODE (align_expr) == CONVERT_EXPR - || TREE_CODE (align_expr) == NON_LVALUE_EXPR) - align_expr = TREE_OPERAND (align_expr, 0); - - if (TREE_CODE (align_expr) != INTEGER_CST) - { - error ("requested alignment is not a constant"); - *no_add_attrs = true; - } - else if ((i = tree_log2 (align_expr)) == -1) - { - error ("requested alignment is not a power of 2"); - *no_add_attrs = true; - } - else if (i > HOST_BITS_PER_INT - 2) - { - error ("requested alignment is too large"); - *no_add_attrs = true; - } - else if (is_type) - { - /* If we have a TYPE_DECL, then copy the type, so that we - don't accidentally modify a builtin type. See pushdecl. */ - if (decl && TREE_TYPE (decl) != error_mark_node - && DECL_ORIGINAL_TYPE (decl) == NULL_TREE) - { - tree tt = TREE_TYPE (decl); - *type = build_type_copy (*type); - DECL_ORIGINAL_TYPE (decl) = tt; - TYPE_NAME (*type) = decl; - TREE_USED (*type) = TREE_USED (decl); - TREE_TYPE (decl) = *type; - } - else if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) - *type = build_type_copy (*type); - - TYPE_ALIGN (*type) = (1 << i) * BITS_PER_UNIT; - TYPE_USER_ALIGN (*type) = 1; - } - else if (TREE_CODE (decl) != VAR_DECL - && TREE_CODE (decl) != FIELD_DECL) - { - error_with_decl (decl, - "alignment may not be specified for `%s'"); - *no_add_attrs = true; - } - else - { - DECL_ALIGN (decl) = (1 << i) * BITS_PER_UNIT; - DECL_USER_ALIGN (decl) = 1; - } - - return NULL_TREE; -} - -/* Handle a "weak" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_weak_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name ATTRIBUTE_UNUSED; - tree args ATTRIBUTE_UNUSED; - int flags ATTRIBUTE_UNUSED; - bool *no_add_attrs ATTRIBUTE_UNUSED; -{ - declare_weak (*node); - - return NULL_TREE; -} - -/* Handle an "alias" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_alias_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name; - tree args; - int flags ATTRIBUTE_UNUSED; - bool *no_add_attrs; -{ - tree decl = *node; - - if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl)) - || (TREE_CODE (decl) != FUNCTION_DECL && ! DECL_EXTERNAL (decl))) - { - error_with_decl (decl, - "`%s' defined both normally and as an alias"); - *no_add_attrs = true; - } - else if (decl_function_context (decl) == 0) - { - tree id; - - id = TREE_VALUE (args); - if (TREE_CODE (id) != STRING_CST) - { - error ("alias arg not a string"); - *no_add_attrs = true; - return NULL_TREE; - } - id = get_identifier (TREE_STRING_POINTER (id)); - /* This counts as a use of the object pointed to. */ - TREE_USED (id) = 1; - - if (TREE_CODE (decl) == FUNCTION_DECL) - DECL_INITIAL (decl) = error_mark_node; - else - DECL_EXTERNAL (decl) = 0; - } - else - { - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle an "visibility" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_visibility_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name; - tree args; - int flags ATTRIBUTE_UNUSED; - bool *no_add_attrs; -{ - tree decl = *node; - - if (decl_function_context (decl) != 0 || ! TREE_PUBLIC (decl)) - { - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - *no_add_attrs = true; - } - else - { - tree id; - - id = TREE_VALUE (args); - if (TREE_CODE (id) != STRING_CST) - { - error ("visibility arg not a string"); - *no_add_attrs = true; - return NULL_TREE; - } - if (strcmp (TREE_STRING_POINTER (id), "hidden") - && strcmp (TREE_STRING_POINTER (id), "protected") - && strcmp (TREE_STRING_POINTER (id), "internal")) - { - error ("visibility arg must be one of \"hidden\", \"protected\" or \"internal\""); - *no_add_attrs = true; - return NULL_TREE; - } - } - - return NULL_TREE; -} - -/* Handle a "no_instrument_function" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_no_instrument_function_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name; - tree args ATTRIBUTE_UNUSED; - int flags ATTRIBUTE_UNUSED; - bool *no_add_attrs; -{ - tree decl = *node; - - if (TREE_CODE (decl) != FUNCTION_DECL) - { - error_with_decl (decl, - "`%s' attribute applies only to functions", - IDENTIFIER_POINTER (name)); - *no_add_attrs = true; - } - else if (DECL_INITIAL (decl)) - { - error_with_decl (decl, - "can't set `%s' attribute after definition", - IDENTIFIER_POINTER (name)); - *no_add_attrs = true; - } - else - DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1; - - return NULL_TREE; -} - -/* Handle a "malloc" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_malloc_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name; - tree args ATTRIBUTE_UNUSED; - int flags ATTRIBUTE_UNUSED; - bool *no_add_attrs; -{ - if (TREE_CODE (*node) == FUNCTION_DECL) - DECL_IS_MALLOC (*node) = 1; - /* ??? TODO: Support types. */ - else - { - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "no_limit_stack" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_no_limit_stack_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name; - tree args ATTRIBUTE_UNUSED; - int flags ATTRIBUTE_UNUSED; - bool *no_add_attrs; -{ - tree decl = *node; - - if (TREE_CODE (decl) != FUNCTION_DECL) - { - error_with_decl (decl, - "`%s' attribute applies only to functions", - IDENTIFIER_POINTER (name)); - *no_add_attrs = true; - } - else if (DECL_INITIAL (decl)) - { - error_with_decl (decl, - "can't set `%s' attribute after definition", - IDENTIFIER_POINTER (name)); - *no_add_attrs = true; - } - else - DECL_NO_LIMIT_STACK (decl) = 1; - - return NULL_TREE; -} - -/* Handle a "pure" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_pure_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name; - tree args ATTRIBUTE_UNUSED; - int flags ATTRIBUTE_UNUSED; - bool *no_add_attrs; -{ - if (TREE_CODE (*node) == FUNCTION_DECL) - DECL_IS_PURE (*node) = 1; - /* ??? TODO: Support types. */ - else - { - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - *no_add_attrs = true; - } - - return NULL_TREE; -} - -/* Handle a "deprecated" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_deprecated_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name; - tree args ATTRIBUTE_UNUSED; - int flags; - bool *no_add_attrs; -{ - tree type = NULL_TREE; - int warn = 0; - const char *what = NULL; - - if (DECL_P (*node)) - { - tree decl = *node; - type = TREE_TYPE (decl); - - if (TREE_CODE (decl) == TYPE_DECL - || TREE_CODE (decl) == PARM_DECL - || TREE_CODE (decl) == VAR_DECL - || TREE_CODE (decl) == FUNCTION_DECL - || TREE_CODE (decl) == FIELD_DECL) - TREE_DEPRECATED (decl) = 1; - else - warn = 1; - } - else if (TYPE_P (*node)) - { - if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) - *node = build_type_copy (*node); - TREE_DEPRECATED (*node) = 1; - type = *node; - } - else - warn = 1; - - if (warn) - { - *no_add_attrs = true; - if (type && TYPE_NAME (type)) - { - if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) - what = IDENTIFIER_POINTER (TYPE_NAME (*node)); - else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL - && DECL_NAME (TYPE_NAME (type))) - what = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))); - } - if (what) - warning ("`%s' attribute ignored for `%s'", - IDENTIFIER_POINTER (name), what); - else - warning ("`%s' attribute ignored", - IDENTIFIER_POINTER (name)); - } - - return NULL_TREE; -} - -/* Handle a "vector_size" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_vector_size_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name; - tree args; - int flags ATTRIBUTE_UNUSED; - bool *no_add_attrs; -{ - unsigned HOST_WIDE_INT vecsize, nunits; - enum machine_mode mode, orig_mode, new_mode; - tree type = *node, new_type; - - *no_add_attrs = true; - - if (! host_integerp (TREE_VALUE (args), 1)) - { - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - return NULL_TREE; - } - - /* Get the vector size (in bytes). */ - vecsize = tree_low_cst (TREE_VALUE (args), 1); - - /* We need to provide for vector pointers, vector arrays, and - functions returning vectors. For example: - - __attribute__((vector_size(16))) short *foo; - - In this case, the mode is SI, but the type being modified is - HI, so we need to look further. */ - - while (POINTER_TYPE_P (type) - || TREE_CODE (type) == FUNCTION_TYPE - || TREE_CODE (type) == ARRAY_TYPE) - type = TREE_TYPE (type); - - /* Get the mode of the type being modified. */ - orig_mode = TYPE_MODE (type); - - if (TREE_CODE (type) == RECORD_TYPE - || (GET_MODE_CLASS (orig_mode) != MODE_FLOAT - && GET_MODE_CLASS (orig_mode) != MODE_INT) - || ! host_integerp (TYPE_SIZE_UNIT (type), 1)) - { - error ("invalid vector type for attribute `%s'", - IDENTIFIER_POINTER (name)); - return NULL_TREE; - } - - /* Calculate how many units fit in the vector. */ - nunits = vecsize / tree_low_cst (TYPE_SIZE_UNIT (type), 1); - - /* Find a suitably sized vector. */ - new_mode = VOIDmode; - for (mode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (orig_mode) == MODE_INT - ? MODE_VECTOR_INT - : MODE_VECTOR_FLOAT); - mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) - if (vecsize == GET_MODE_SIZE (mode) - && nunits == (unsigned HOST_WIDE_INT) GET_MODE_NUNITS (mode)) - { - new_mode = mode; - break; - } - - if (new_mode == VOIDmode) - error ("no vector mode with the size and type specified could be found"); - else - { - tree index, array, rt; - - new_type = (*lang_hooks.types.type_for_mode) (new_mode, - TREE_UNSIGNED (type)); - - if (!new_type) - { - error ("no vector mode with the size and type specified could be found"); - return NULL_TREE; - } - - new_type = build_type_copy (new_type); - - /* Set the debug information here, because this is the only - place where we know the underlying type for a vector made - with vector_size. For debugging purposes we pretend a vector - is an array within a structure. */ - index = build_int_2 (TYPE_VECTOR_SUBPARTS (new_type) - 1, 0); - array = build_array_type (type, build_index_type (index)); - rt = make_node (RECORD_TYPE); - TYPE_FIELDS (rt) = build_decl (FIELD_DECL, get_identifier ("f"), array); - DECL_CONTEXT (TYPE_FIELDS (rt)) = rt; - layout_type (rt); - TYPE_DEBUG_REPRESENTATION_TYPE (new_type) = rt; - - /* Build back pointers if needed. */ - *node = vector_size_helper (*node, new_type); - } - - return NULL_TREE; -} - -/* HACK. GROSS. This is absolutely disgusting. I wish there was a - better way. - - If we requested a pointer to a vector, build up the pointers that - we stripped off while looking for the inner type. Similarly for - return values from functions. - - The argument "type" is the top of the chain, and "bottom" is the - new type which we will point to. */ - -static tree -vector_size_helper (type, bottom) - tree type, bottom; -{ - tree inner, outer; - - if (POINTER_TYPE_P (type)) - { - inner = vector_size_helper (TREE_TYPE (type), bottom); - outer = build_pointer_type (inner); - } - else if (TREE_CODE (type) == ARRAY_TYPE) - { - inner = vector_size_helper (TREE_TYPE (type), bottom); - outer = build_array_type (inner, TYPE_VALUES (type)); - } - else if (TREE_CODE (type) == FUNCTION_TYPE) - { - inner = vector_size_helper (TREE_TYPE (type), bottom); - outer = build_function_type (inner, TYPE_VALUES (type)); - } - else - return bottom; - - TREE_READONLY (outer) = TREE_READONLY (type); - TREE_THIS_VOLATILE (outer) = TREE_THIS_VOLATILE (type); - - return outer; -} - -/* Split SPECS_ATTRS, a list of declspecs and prefix attributes, into two - lists. SPECS_ATTRS may also be just a typespec (eg: RECORD_TYPE). - - The head of the declspec list is stored in DECLSPECS. - The head of the attribute list is stored in PREFIX_ATTRIBUTES. - - Note that attributes in SPECS_ATTRS are stored in the TREE_PURPOSE of - the list elements. We drop the containing TREE_LIST nodes and link the - resulting attributes together the way decl_attributes expects them. */ - -void -split_specs_attrs (specs_attrs, declspecs, prefix_attributes) - tree specs_attrs; - tree *declspecs, *prefix_attributes; -{ - tree t, s, a, next, specs, attrs; - - /* This can happen after an __extension__ in pedantic mode. */ - if (specs_attrs != NULL_TREE - && TREE_CODE (specs_attrs) == INTEGER_CST) - { - *declspecs = NULL_TREE; - *prefix_attributes = NULL_TREE; - return; - } - - /* This can happen in c++ (eg: decl: typespec initdecls ';'). */ - if (specs_attrs != NULL_TREE - && TREE_CODE (specs_attrs) != TREE_LIST) - { - *declspecs = specs_attrs; - *prefix_attributes = NULL_TREE; - return; - } - - /* Remember to keep the lists in the same order, element-wise. */ - - specs = s = NULL_TREE; - attrs = a = NULL_TREE; - for (t = specs_attrs; t; t = next) - { - next = TREE_CHAIN (t); - /* Declspecs have a non-NULL TREE_VALUE. */ - if (TREE_VALUE (t) != NULL_TREE) + if (fn_ptr_tmp) { - if (specs == NULL_TREE) - specs = s = t; + /* Rebuild the function pointer type and put it in the + appropriate place. */ + fn_ptr_tmp = build_pointer_type (fn_ptr_tmp); + if (fn_ptr_quals) + fn_ptr_tmp = build_qualified_type (fn_ptr_tmp, fn_ptr_quals); + if (DECL_P (*node)) + TREE_TYPE (*node) = fn_ptr_tmp; else { - TREE_CHAIN (s) = t; - s = t; + gcc_assert (TREE_CODE (*node) == POINTER_TYPE); + *node = fn_ptr_tmp; } } - /* The TREE_PURPOSE may also be empty in the case of - __attribute__(()). */ - else if (TREE_PURPOSE (t) != NULL_TREE) - { - if (attrs == NULL_TREE) - attrs = a = TREE_PURPOSE (t); - else - { - TREE_CHAIN (a) = TREE_PURPOSE (t); - a = TREE_PURPOSE (t); - } - /* More attrs can be linked here, move A to the end. */ - while (TREE_CHAIN (a) != NULL_TREE) - a = TREE_CHAIN (a); - } } - /* Terminate the lists. */ - if (s != NULL_TREE) - TREE_CHAIN (s) = NULL_TREE; - if (a != NULL_TREE) - TREE_CHAIN (a) = NULL_TREE; - - /* All done. */ - *declspecs = specs; - *prefix_attributes = attrs; -} - -/* Strip attributes from SPECS_ATTRS, a list of declspecs and attributes. - This function is used by the parser when a rule will accept attributes - in a particular position, but we don't want to support that just yet. - - A warning is issued for every ignored attribute. */ - -tree -strip_attrs (specs_attrs) - tree specs_attrs; -{ - tree specs, attrs; - - split_specs_attrs (specs_attrs, &specs, &attrs); - - while (attrs) - { - warning ("`%s' attribute ignored", - IDENTIFIER_POINTER (TREE_PURPOSE (attrs))); - attrs = TREE_CHAIN (attrs); - } - - return specs; + return returned_attrs; } -