From b9de1157289455b0ca26daff519d4a0ddcd1fa13 Mon Sep 17 00:00:00 2001 From: Dan Albert Date: Wed, 24 Feb 2016 13:48:45 -0800 Subject: Update 4.8.1 to 4.8.3. My previous drop was the wrong version. The platform mingw is currently using 4.8.3, not 4.8.1 (not sure how I got that wrong). From ftp://ftp.gnu.org/gnu/gcc/gcc-4.8.3/gcc-4.8.3.tar.bz2. Bug: http://b/26523949 Change-Id: Id85f1bdcbbaf78c7d0b5a69e74c798a08f341c35 --- gcc-4.8.3/gcc/attribs.c | 683 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 683 insertions(+) create mode 100644 gcc-4.8.3/gcc/attribs.c (limited to 'gcc-4.8.3/gcc/attribs.c') diff --git a/gcc-4.8.3/gcc/attribs.c b/gcc-4.8.3/gcc/attribs.c new file mode 100644 index 0000000..08ebfe1 --- /dev/null +++ b/gcc-4.8.3/gcc/attribs.c @@ -0,0 +1,683 @@ +/* Functions dealing with attribute handling, used by most front ends. + Copyright (C) 1992-2013 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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "flags.h" +#include "diagnostic-core.h" +#include "ggc.h" +#include "tm_p.h" +#include "cpplib.h" +#include "target.h" +#include "langhooks.h" +#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]; + +/* Substring representation. */ + +struct substring +{ + const char *str; + int length; +}; + +/* Scoped attribute name representation. */ + +struct scoped_attributes +{ + const char *ns; + vec attributes; + htab_t attribute_hash; +}; + +/* The table of scope attributes. */ +static vec attributes_table; + +static scoped_attributes* find_attribute_namespace (const char*); +static void register_scoped_attribute (const struct attribute_spec *, + scoped_attributes *); + +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, 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]); +} + +/* Insert an array of attributes ATTRIBUTES into a namespace. This + array must be NULL terminated. NS is the name of attribute + namespace. The function returns the namespace into which the + attributes have been registered. */ + +scoped_attributes* +register_scoped_attributes (const struct attribute_spec * attributes, + const char* ns) +{ + scoped_attributes *result = NULL; + + /* See if we already have attributes in the namespace NS. */ + result = find_attribute_namespace (ns); + + if (result == NULL) + { + /* We don't have any namespace NS yet. Create one. */ + scoped_attributes sa; + + if (!attributes_table.is_empty ()) + attributes_table.create (64); + + memset (&sa, 0, sizeof (sa)); + sa.ns = ns; + sa.attributes.create (64); + result = attributes_table.safe_push (sa); + result->attribute_hash = htab_create (200, hash_attr, eq_attr, NULL); + } + + /* Really add the attributes to their namespace now. */ + for (unsigned i = 0; attributes[i].name != NULL; ++i) + { + result->attributes.safe_push (attributes[i]); + register_scoped_attribute (&attributes[i], result); + } + + gcc_assert (result != NULL); + + return result; +} + +/* Return the namespace which name is NS, NULL if none exist. */ + +static scoped_attributes* +find_attribute_namespace (const char* ns) +{ + unsigned ix; + scoped_attributes *iter; + + FOR_EACH_VEC_ELT (attributes_table, ix, iter) + if (ns == iter->ns + || (iter->ns != NULL + && ns != NULL + && !strcmp (iter->ns, ns))) + return iter; + return NULL; +} + +/* Initialize attribute tables, and make some sanity checks + if --enable-checking. */ + +void +init_attributes (void) +{ + size_t i; + + if (attributes_initialized) + return; + + 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++) + { + int j; + + for (j = 0; attribute_tables[i][j].name != NULL; j++) + { + /* The name must not begin and end with __. */ + const char *name = attribute_tables[i][j].name; + int len = strlen (name); + + gcc_assert (!(name[0] == '_' && name[1] == '_' + && name[len - 1] == '_' && name[len - 2] == '_')); + + /* The minimum and maximum lengths must be consistent. */ + 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. */ + 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. */ + gcc_assert (!attribute_tables[i][j].function_type_required + || attribute_tables[i][j].type_required); + } + } + + /* Check that each name occurs just once in each table. */ + for (i = 0; i < ARRAY_SIZE (attribute_tables); i++) + { + int j, k; + for (j = 0; attribute_tables[i][j].name != NULL; j++) + for (k = j + 1; attribute_tables[i][k].name != NULL; k++) + gcc_assert (strcmp (attribute_tables[i][j].name, + attribute_tables[i][k].name)); + } + /* 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; + + 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++) + gcc_assert (attribute_tables[i][k].name[0] == '*' + || strcmp (attribute_tables[i][k].name, + attribute_tables[j][l].name)); + } +#endif + + for (i = 0; i < ARRAY_SIZE (attribute_tables); ++i) + /* Put all the GNU attributes into the "gnu" namespace. */ + register_scoped_attributes (attribute_tables[i], "gnu"); + + 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) +{ + register_scoped_attribute (attr, find_attribute_namespace ("gnu")); +} + +/* Insert a single attribute ATTR into a namespace of attributes. */ + +static void +register_scoped_attribute (const struct attribute_spec *attr, + scoped_attributes *name_space) +{ + struct substring str; + void **slot; + + gcc_assert (attr != NULL && name_space != NULL); + + gcc_assert (name_space->attribute_hash != NULL); + + 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 (name_space->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 scoped attribute with namespace NS and + name NAME. */ + +const struct attribute_spec * +lookup_scoped_attribute_spec (const_tree ns, const_tree name) +{ + struct substring attr; + scoped_attributes *attrs; + + const char *ns_str = (ns != NULL_TREE) ? IDENTIFIER_POINTER (ns): NULL; + + attrs = find_attribute_namespace (ns_str); + + if (attrs == NULL) + return NULL; + + attr.str = IDENTIFIER_POINTER (name); + attr.length = IDENTIFIER_LENGTH (name); + extract_attribute_substring (&attr); + return (const struct attribute_spec *) + htab_find_with_hash (attrs->attribute_hash, &attr, + substring_hash (attr.str, attr.length)); +} + +/* Return the spec for the attribute named NAME. If NAME is a TREE_LIST, + it also specifies the attribute namespace. */ + +const struct attribute_spec * +lookup_attribute_spec (const_tree name) +{ + tree ns; + if (TREE_CODE (name) == TREE_LIST) + { + ns = TREE_PURPOSE (name); + name = TREE_VALUE (name); + } + else + ns = get_identifier ("gnu"); + return lookup_scoped_attribute_spec (ns, name); +} + + +/* 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, + it should be modified in place; if a TYPE, a copy should be created + unless ATTR_FLAG_TYPE_IN_PLACE is set in FLAGS. FLAGS gives further + 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). */ + +tree +decl_attributes (tree *node, tree attributes, int flags) +{ + tree a; + tree returned_attrs = NULL_TREE; + + if (TREE_TYPE (*node) == error_mark_node || attributes == 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)) + { + tree ns = get_attribute_namespace (a); + tree name = get_attribute_name (a); + tree args = TREE_VALUE (a); + tree *anode = node; + const struct attribute_spec *spec = + lookup_scoped_attribute_spec (ns, name); + bool no_add_attrs = 0; + int fn_ptr_quals = 0; + tree fn_ptr_tmp = NULL_TREE; + + if (spec == NULL) + { + if (!(flags & (int) ATTR_FLAG_BUILT_IN)) + { + if (ns == NULL_TREE || !cxx11_attribute_p (a)) + warning (OPT_Wattributes, "%qE attribute directive ignored", + name); + else + warning (OPT_Wattributes, + "%<%E::%E%> scoped attribute directive ignored", + ns, 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 %qE attribute", + name); + continue; + } + gcc_assert (is_attribute_p (spec->name, name)); + + if (TYPE_P (*node) + && cxx11_attribute_p (a) + && !(flags & ATTR_FLAG_TYPE_IN_PLACE)) + { + /* This is a c++11 attribute that appertains to a + type-specifier, outside of the definition of, a class + type. Ignore it. */ + warning (OPT_Wattributes, "attribute ignored"); + inform (input_location, + "an attribute that appertains to a type-specifier " + "is ignored"); + continue; + } + + if (spec->decl_required && !DECL_P (*anode)) + { + if (flags & ((int) ATTR_FLAG_DECL_NEXT + | (int) ATTR_FLAG_FUNCTION_NEXT + | (int) ATTR_FLAG_ARRAY_NEXT)) + { + /* Pass on this attribute to be tried again. */ + returned_attrs = tree_cons (name, args, returned_attrs); + continue; + } + else + { + warning (OPT_Wattributes, "%qE attribute does not apply to types", + name); + continue; + } + } + + /* If we require a type, but were passed a decl, set up to make a + new type and update the one in the decl. ATTR_FLAG_TYPE_IN_PLACE + would have applied if we'd been passed a type, but we cannot modify + the decl's type in place here. */ + if (spec->type_required && DECL_P (*anode)) + { + anode = &TREE_TYPE (*anode); + /* 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 + && TREE_CODE (*anode) != METHOD_TYPE) + { + if (TREE_CODE (*anode) == POINTER_TYPE + && (TREE_CODE (TREE_TYPE (*anode)) == FUNCTION_TYPE + || TREE_CODE (TREE_TYPE (*anode)) == METHOD_TYPE)) + { + /* 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) + { + /* Pass on this attribute to be tried again. */ + returned_attrs = tree_cons (name, args, returned_attrs); + continue; + } + + if (TREE_CODE (*anode) != FUNCTION_TYPE + && TREE_CODE (*anode) != METHOD_TYPE) + { + 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) + { + int cxx11_flag = + cxx11_attribute_p (a) ? ATTR_FLAG_CXX11 : 0; + + returned_attrs = chainon ((*spec->handler) (anode, name, args, + flags|cxx11_flag, + &no_add_attrs), + returned_attrs); + } + + /* Layout the decl in case anything changed. */ + if (spec->type_required && DECL_P (*node) + && (TREE_CODE (*node) == VAR_DECL + || TREE_CODE (*node) == PARM_DECL + || TREE_CODE (*node) == RESULT_DECL)) + relayout_decl (*node); + + if (!no_add_attrs) + { + tree old_attrs; + tree a; + + if (DECL_P (*anode)) + old_attrs = DECL_ATTRIBUTES (*anode); + else + old_attrs = TYPE_ATTRIBUTES (*anode); + + for (a = lookup_attribute (spec->name, old_attrs); + a != NULL_TREE; + a = lookup_attribute (spec->name, TREE_CHAIN (a))) + { + if (simple_cst_equal (TREE_VALUE (a), args) == 1) + break; + } + + if (a == NULL_TREE) + { + /* This attribute isn't already in the list. */ + 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); + /* 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)); + } + } + + if (fn_ptr_tmp) + { + /* 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 + { + gcc_assert (TREE_CODE (*node) == POINTER_TYPE); + *node = fn_ptr_tmp; + } + } + } + + return returned_attrs; +} + +/* Return TRUE iff ATTR has been parsed by the front-end as a C++-11 + attribute. + + When G++ parses a C++11 attribute, it is represented as + a TREE_LIST which TREE_PURPOSE is itself a TREE_LIST. TREE_PURPOSE + (TREE_PURPOSE (ATTR)) is the namespace of the attribute, and the + TREE_VALUE (TREE_PURPOSE (ATTR)) is its non-qualified name. Please + use get_attribute_namespace and get_attribute_name to retrieve the + namespace and name of the attribute, as these accessors work with + GNU attributes as well. */ + +bool +cxx11_attribute_p (const_tree attr) +{ + if (attr == NULL_TREE + || TREE_CODE (attr) != TREE_LIST) + return false; + + return (TREE_CODE (TREE_PURPOSE (attr)) == TREE_LIST); +} + +/* Return the name of the attribute ATTR. This accessor works on GNU + and C++11 (scoped) attributes. + + Please read the comments of cxx11_attribute_p to understand the + format of attributes. */ + +tree +get_attribute_name (const_tree attr) +{ + if (cxx11_attribute_p (attr)) + return TREE_VALUE (TREE_PURPOSE (attr)); + return TREE_PURPOSE (attr); +} + +/* Return the namespace of the attribute ATTR. This accessor works on + GNU and C++11 (scoped) attributes. On GNU attributes, + it returns an identifier tree for the string "gnu". + + Please read the comments of cxx11_attribute_p to understand the + format of attributes. */ + +tree +get_attribute_namespace (const_tree attr) +{ + if (cxx11_attribute_p (attr)) + return TREE_PURPOSE (TREE_PURPOSE (attr)); + return get_identifier ("gnu"); +} + +/* Subroutine of set_method_tm_attributes. Apply TM attribute ATTR + to the method FNDECL. */ + +void +apply_tm_attr (tree fndecl, tree attr) +{ + decl_attributes (&TREE_TYPE (fndecl), tree_cons (attr, NULL, NULL), 0); +} -- cgit v1.1