X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fattribs.c;h=0e94fd29cb55da9b7be5f42e11e0a5b0427413ef;hp=671528ccacd2f2390f8ce26e2b736c64618c1292;hb=b64da4ff182b6bde9b96cc5cdbdfa3a955de4d03;hpb=316e17aef38913850104bf635ecbda834f7584ea diff --git a/gcc/attribs.c b/gcc/attribs.c index 671528ccacd..0e94fd29cb5 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, 2003, 2004 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,9 +16,8 @@ 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" @@ -25,37 +25,94 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "tm.h" #include "tree.h" #include "flags.h" -#include "toplev.h" -#include "output.h" -#include "rtl.h" +#include "diagnostic-core.h" #include "ggc.h" -#include "expr.h" #include "tm_p.h" #include "cpplib.h" #include "target.h" #include "langhooks.h" - -static void init_attributes (void); +#include "hashtab.h" +#include "plugin.h" /* Table of the tables of attributes (common, language, format, machine) searched. */ static const struct attribute_spec *attribute_tables[4]; +/* Hashtable mapping names (represented as substrings) to attribute specs. */ +static htab_t attribute_hash; + +/* Substring representation. */ + +struct substring +{ + 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 } + { NULL, 0, 0, false, false, false, NULL, false } }; +/* 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; +} + +/* Used for attribute_hash. */ + +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 +void init_attributes (void) { size_t i; + int k; + + if (attributes_initialized) + return; attribute_tables[0] = lang_hooks.common_attribute_table; attribute_tables[1] = lang_hooks.attribute_table; @@ -78,25 +135,25 @@ init_attributes (void) /* 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); } } @@ -106,11 +163,11 @@ init_attributes (void) 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. */ + /* Check that no name occurs in more than one table. Names that + begin with '*' are exempt, and may be overridden. */ for (i = 0; i < ARRAY_SIZE (attribute_tables); i++) { size_t j, k, l; @@ -118,14 +175,58 @@ init_attributes (void) 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 (attribute_tables[i][k].name[0] == '*' + || 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); + + /* Attribute names in the table must be in the form 'text' and not + in the form '__text__'. */ + gcc_assert (str.length > 0 && str.str[0] != '_'); + + slot = htab_find_slot_with_hash (attribute_hash, &str, + substring_hash (str.str, str.length), + INSERT); + gcc_assert (!*slot || attr->name[0] == '*'); + *slot = (void *) CONST_CAST (struct attribute_spec *, attr); +} + +/* Return the spec for the attribute named NAME. */ + +const struct attribute_spec * +lookup_attribute_spec (const_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, @@ -142,9 +243,61 @@ 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 (); + /* 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)); + } + + /* A "naked" function attribute implies "noinline" and "noclone" for + those targets that support it. */ + if (TREE_CODE (*node) == FUNCTION_DECL + && attributes + && lookup_attribute_spec (get_identifier ("naked")) + && lookup_attribute ("naked", attributes) != NULL) + { + if (lookup_attribute ("noinline", attributes) == NULL) + attributes = tree_cons (get_identifier ("noinline"), NULL, attributes); + + if (lookup_attribute ("noclone", attributes) == NULL) + attributes = tree_cons (get_identifier ("noclone"), NULL, attributes); + } + targetm.insert_attributes (*node, &attributes); for (a = attributes; a; a = TREE_CHAIN (a)) @@ -152,41 +305,26 @@ decl_attributes (tree *node, tree attributes, int flags) 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; + int fn_ptr_quals = 0; tree fn_ptr_tmp = NULL_TREE; - 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; - } 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)) { @@ -200,8 +338,8 @@ decl_attributes (tree *node, tree attributes, int 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; } } @@ -213,7 +351,11 @@ decl_attributes (tree *node, tree attributes, int 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 @@ -230,9 +372,10 @@ decl_attributes (tree *node, tree attributes, int flags) 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. */ + 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; } @@ -246,12 +389,21 @@ decl_attributes (tree *node, tree attributes, int 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), @@ -262,13 +414,7 @@ decl_attributes (tree *node, tree attributes, int 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) { @@ -326,116 +472,26 @@ decl_attributes (tree *node, tree attributes, int flags) /* 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 if (TREE_CODE (*node) == POINTER_TYPE) - *node = fn_ptr_tmp; - else - abort (); - } - } - - return returned_attrs; -} - -/* 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 (tree specs_attrs, tree *declspecs, tree *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 (specs == NULL_TREE) - specs = s = t; - else - { - TREE_CHAIN (s) = t; - s = t; - } - } - /* 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); + gcc_assert (TREE_CODE (*node) == POINTER_TYPE); + *node = fn_ptr_tmp; } - /* 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; + return returned_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. */ +/* Subroutine of set_method_tm_attributes. Apply TM attribute ATTR + to the method FNDECL. */ -tree -strip_attrs (tree specs_attrs) +void +apply_tm_attr (tree fndecl, tree attr) { - 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; + decl_attributes (&TREE_TYPE (fndecl), tree_cons (attr, NULL, NULL), 0); }