From ffcdbf9cfa1e6df483fc5aa5885eb3121cd60638 Mon Sep 17 00:00:00 2001 From: dodji Date: Mon, 8 Oct 2012 09:29:05 +0000 Subject: PR c++/53528 C++11 attribute support This patch implements the c++-11 generalized attributes, described in the N2761 paper[1]. The idea is to modify the front-end to accept the new attribute syntax (including alignas expressions) and to build an internal representation similar to the one we already have for GNU attributes. This lets us re-use our existing GNU attribute mechanisms to support the generalized c++11 attributes. The patch does change the existing internal representation to support scoped attribute (aka attributes with namespaces), which is a concept that doesn't exist in GNU attributes. I have thus put all existing GNU extension attributes into the "gnu" namespace. For instance, in C++-11, the "unused" attribute would be represented as "[[gnu::unused]]". Because there is no syntax for scoped attributes in C, writting "__attribute__((unused))" unconditionnally refers to the "unused" attribute in the "gnu" namespace. Note that this patch follows a conservative understanding of the specification by disallowing attributes appertaining to types, unless they apply to a type definition. Tested on x86_64-unknown-linux-gnu and powerpc64-unknown-linux-gnu. [1]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2761.pdf gcc/ * plugin.h (register_scoped_attributes): Declare new function. * tree.h (enu attribute_flags::ATTR_FLAG_CXX_11): New flag. (lookup_scoped_attribute_spec, cxx_11_attribute_p) (get_attribute_name, get_attribute_namespace): Declare new functions. (struct attribute_spec): Remove const qualifier from the members. * tree.c (comp_type_attributes, private_lookup_attribute) (lookup_ident_attribute, remove_attribute, merge_attribute) (attribute_hash_list, attribute_list_contained): Use get_attribute_name. * attribs.c (decl_attributes): Don't crash on error_mark_node. Forbid c++11 attributes appertaining to type-specifiers. (attribute_hash): Remove global variable. (attributes_table): New global variable. (find_attribute_namespace, register_scoped_attribute): New static functions. (register_scoped_attributes, lookup_scoped_attribute_spec) (cxx11_attribute_p, get_attribute_name, get_attribute_namespace): New public functions. (init_attributes): Register all the GNU attributes into the "gnu" namespace. (register_attribute): Use register_scoped_attribute to register the attribute into the "gnu" namespace. (lookup_attribute_spec): Use lookup_scoped_attribute_spec to lookup the attribute in the "gnu" namespace. (decl_attributes): Use new get_attribute_namespace and lookup_scoped_attribute_spec to consider attribute namespaces when looking up attributes. When operating in c++-11 mode, pass flag ATTR_FLAG_CXX11 to the spec handler. gcc/c-family/ * c-common.h (bitfield_p, cxx_fundamental_alignment_p): Declare new functions. * c-common.c (check_cxx_fundamental_alignment_constraints): New static function. (handle_aligned_attribute): In choose strictest alignment among many. Use new check_cxx_fundamental_alignment_constraints. (handle_transparent_union_attribute): In c++11 attribute syntax, don't look through typedefs. gcc/cp/ * cp-tree.h (enum cpp0x_warn_str::CPP0X_ATTRIBUTES): New member. (enum cp_decl_spec::ds_std_attribute): New enumerator. (struct cp_decl_specifier_seq::std_attributes): New field. (cxx_alignas_expr, warn_misplaced_attr_for_class_type): Declare new functions. (check_tag_decl): Take an extra parameter for explicit instantiations. * decl.c (warn_misplaced_attr_for_class_type): Extract from ... (check_tag_decl): ... here. Add check for c++11 attributes being applied to an explicit instantiation. Take an extra parameter for explicit instantiations. (grokdeclarator): Make sure a c++11 attribute after an array declarator appertains to the array, an attribute after a function declarator appertains to the function type, an attribute after a declarator-id appertains to the entity being declared, and an attribute after a pointer declarator appertains to the pointer. * decl2.c (is_late_template_attribute): Use get_attribute_name. * error.c (maybe_warn_cpp0x): Support CPP0X_GENERALIZED_ATTRIBUTES. * parser.c (cp_next_tokens_can_be_attribute_p) (cp_next_tokens_can_be_gnu_attribute_p) (cp_next_tokens_can_be_std_attribute_p) (cp_nth_tokens_can_be_attribute_p) (cp_nth_tokens_can_be_gnu_attribute_p) (cp_nth_tokens_can_be_std_attribute_p) (cp_parser_gnu_attribute_list, cp_parser_std_attribute) (cp_parser_std_attribute_spec, cp_parser_std_attribute_spec_seq) (cp_parser_attributes_opt, cp_parser_std_attribute_list): New static functions. (cp_parser_gnu_attributes_opt): Replace cp_parser_attributes_opt. (cp_parser_gnu_attribute_list): Replace cp_parser_attribute_list. (cp_parser_postfix_expression): Disallow "[[" tokens here. (cp_parser_label_for_labeled_statement): Use take an extra parameter for attributes. (cp_parser_block_declaration): Use cp_nth_tokens_can_be_std_attribute_p here. (cp_parser_decl_specifier_seq): Likewise. Store C++11 attributes that appears in in decl specifiers in cp_decl_specifier_seq::std_attributes. declaration. Emit proper warning about misplaced c++11 attributes for class type. (cp_parser_explicit_instantiation): Adjust call to check_tag_decl. (cp_parser_init_declarator): Parsing attributes here is no more a GNU extension in c++-11. (cp_parser_type_specifier_seq): Use cp_next_tokens_can_be_attribute_p. (cp_parser_direct_declarator): Likewise. Hang c++11 attributes following the declarator to its syntactic construct. It'll later be applied to the proper appertaining entity by grokdeclarator. (cp_parser_ptr_operator): Likewise. (make_declarator): Initialize cp_declarator::std_attribute. (make_pointer_declarator, make_reference_declarator) (make_ptrmem_declarator, cp_parser_make_indirect_declarator): Take attributes that appertain to the pointer/reference in argument. (cp_parser_ptr_operator): Take an out parameter for c++11 attributes. Update comments. (cp_parser_new_declarator_opt) (cp_parser_conversion_declarator_opt): Adjust. (cp_parser_declarator): Likewise. Handle C++11 attributes. Rename attributes to gnu_attribute for better legibility. (cp_parser_simple_declaration): Update comment. (cp_parser_class_specifier_1): Parse GNU attributes specifically (cp_parser_enum_specifier): Accept only gnu attributes after the specifier. (cp_parser_member_declaration): Don't clear attributes -- intended for the entity being declared -- too early because check_tag_decl needs them. (cp_parser_statement): Update comment. Parse optional c++11 attributes at the beginning of the relevant kind of statements and ignore them, for now, unless when calling cp_parser_label_for_labeled_statement. (cp_parser_label_for_labeled_statement): Take c++11 attributes in parameter. * semantics.c (potential_constant_expression_1): Likewise. * typeck.c (fundamental_alignment_p, cxx_alignas_expr): New public functions. gcc/testsuite/ * g++.dg/cpp0x/gen-attrs-1.C: New test. * g++.dg/cpp0x/gen-attrs-2.C: Likewise. * g++.dg/cpp0x/gen-attrs-2-1.C: Likewise. * g++.dg/cpp0x/gen-attrs-3.C: Likewise. * g++.dg/cpp0x/gen-attrs-4.C: Likewise. * g++.dg/cpp0x/gen-attrs-5.C: Likewise. * g++.dg/cpp0x/gen-attrs-6.C: Likewise. * g++.dg/cpp0x/gen-attrs-7.C: Likewise. * g++.dg/cpp0x/gen-attrs-8.C: Likewise. * g++.dg/cpp0x/gen-attrs-9.C: Likewise. * g++.dg/cpp0x/gen-attrs-10.C: Likewise. * g++.dg/cpp0x/gen-attrs-11.C: Likewise. * g++.dg/cpp0x/gen-attrs-12.C: Likewise. * g++.dg/cpp0x/gen-attrs-13.C: Likewise. * g++.dg/cpp0x/gen-attrs-14.C: Likewise. * g++.dg/cpp0x/gen-attrs-15.C: Likewise. * g++.dg/cpp0x/gen-attrs-16.C: Likewise. * g++.dg/cpp0x/gen-attrs-17.C: Likewise. * g++.dg/cpp0x/gen-attrs-18.C: Likewise. * g++.dg/cpp0x/gen-attrs-19.C: Likewise. * g++.dg/cpp0x/gen-attrs-20.C: Likewise. * g++.dg/cpp0x/gen-attrs-21.C: Likewise. * g++.dg/cpp0x/gen-attrs-22.C: Likewise. * g++.dg/cpp0x/gen-attrs-23.C: Likewise. * g++.dg/cpp0x/gen-attrs-24.C: Likewise. * g++.dg/cpp0x/gen-attrs-25.C: Likewise. * g++.dg/cpp0x/gen-attrs-26.C: Likewise. * g++.dg/cpp0x/gen-attrs-27.C: Likewise. * g++.dg/cpp0x/gen-attrs-28.C: Likewise. * g++.dg/cpp0x/gen-attrs-29.C: Likewise. * g++.dg/cpp0x/gen-attrs-30.C: Likewise. * g++.dg/cpp0x/gen-attrs-31.C: Likewise. * g++.dg/cpp0x/gen-attrs-32.C: Likewise. * g++.dg/cpp0x/gen-attrs-33.C: Likewise. * g++.dg/cpp0x/gen-attrs-34.C: Likewise. * g++.dg/cpp0x/gen-attrs-35.C: Likewise. * g++.dg/cpp0x/gen-attrs-36.C: Likewise. * g++.dg/cpp0x/gen-attrs-36-1.C: Likewise. * g++.dg/cpp0x/gen-attrs-37.C: Likewise. * g++.dg/cpp0x/gen-attrs-38.C: Likewise. * g++.dg/cpp0x/gen-attrs-39.C: Likewise. * g++.dg/cpp0x/gen-attrs-39-1.C: Likewise. * g++.dg/cpp0x/gen-attrs-40.C: Likewise. * g++.dg/cpp0x/gen-attrs-41.C: Likewise. * g++.dg/cpp0x/gen-attrs-42.C: Likewise. * g++.dg/cpp0x/gen-attrs-43.C: Likewise. * g++.dg/cpp0x/gen-attrs-44.C: Likewise. * g++.dg/cpp0x/gen-attrs-45.C: Likewise. * g++.dg/cpp0x/gen-attrs-46.C: Likewise. * g++.dg/cpp0x/gen-attrs-47.C: Likewise. * g++.dg/cpp0x/gen-attrs-47-1.C: Likewise. * g++.dg/cpp0x/gen-attrs-48.C: Likewise. * g++.dg/cpp0x/gen-attrs-49.C: Likewise. * g++.dg/cpp0x/gen-attrs-50.C: Likewise. * g++.dg/cpp0x/gen-attrs-51.C: Likewise. * g++.dg/cpp0x/gen-attrs-52.C: Likewise. * g++.dg/cpp0x/gen-attrs-53.C: Likewise. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@192199 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/attribs.c | 229 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 207 insertions(+), 22 deletions(-) (limited to 'gcc/attribs.c') diff --git a/gcc/attribs.c b/gcc/attribs.c index d3af4141f4e..b330f27d89d 100644 --- a/gcc/attribs.c +++ b/gcc/attribs.c @@ -38,9 +38,6 @@ along with GCC; see the file COPYING3. If not see 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 @@ -49,6 +46,28 @@ struct substring int length; }; +DEF_VEC_O (attribute_spec); +DEF_VEC_ALLOC_O (attribute_spec, heap); + +/* Scoped attribute name representation. */ + +struct scoped_attributes +{ + const char *ns; + VEC (attribute_spec, heap) *attributes; + htab_t attribute_hash; +}; + +DEF_VEC_O (scoped_attributes); +DEF_VEC_ALLOC_O (scoped_attributes, heap); + +/* The table of scope attributes. */ +static VEC(scoped_attributes, heap) *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. */ @@ -102,6 +121,64 @@ eq_attr (const void *p, const void *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 == NULL) + attributes_table = VEC_alloc (scoped_attributes, heap, 64); + + memset (&sa, 0, sizeof (sa)); + sa.ns = ns; + sa.attributes = VEC_alloc (attribute_spec, heap, 64); + result = VEC_safe_push (scoped_attributes, heap, attributes_table, sa); + } + + /* Really add the attributes to their namespace now. */ + for (unsigned i = 0; attributes[i].name != NULL; ++i) + { + VEC_safe_push (attribute_spec, heap, + result->attributes, 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 (scoped_attributes, 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. */ @@ -109,7 +186,6 @@ void init_attributes (void) { size_t i; - int k; if (attributes_initialized) return; @@ -181,12 +257,10 @@ init_attributes (void) } #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]); - } + 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; } @@ -195,10 +269,24 @@ init_attributes (void) 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); + + if (name_space->attribute_hash == NULL) + name_space->attribute_hash = htab_create (200, hash_attr, eq_attr, NULL); + str.str = attr->name; str.length = strlen (str.str); @@ -206,27 +294,45 @@ register_attribute (const struct attribute_spec *attr) in the form '__text__'. */ gcc_assert (str.length > 0 && str.str[0] != '_'); - slot = htab_find_slot_with_hash (attribute_hash, &str, + 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 attribute named NAME. */ +/* Return the spec for the scoped attribute with namespace NS and + name NAME. */ const struct attribute_spec * -lookup_attribute_spec (const_tree name) +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 (attribute_hash, &attr, + htab_find_with_hash (attrs->attribute_hash, &attr, substring_hash (attr.str, attr.length)); } + +/* Return the spec for the attribute named NAME. */ + +const struct attribute_spec * +lookup_attribute_spec (const_tree name) +{ + return lookup_scoped_attribute_spec (get_identifier ("gnu"), 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, @@ -243,7 +349,7 @@ decl_attributes (tree *node, tree attributes, int flags) tree a; tree returned_attrs = NULL_TREE; - if (TREE_TYPE (*node) == error_mark_node) + if (TREE_TYPE (*node) == error_mark_node || attributes == error_mark_node) return NULL_TREE; if (!attributes_initialized) @@ -302,10 +408,12 @@ decl_attributes (tree *node, tree attributes, int flags) for (a = attributes; a; a = TREE_CHAIN (a)) { - tree name = TREE_PURPOSE (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_attribute_spec (name); + 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; @@ -313,8 +421,15 @@ decl_attributes (tree *node, tree attributes, int flags) if (spec == NULL) { if (!(flags & (int) ATTR_FLAG_BUILT_IN)) - warning (OPT_Wattributes, "%qE attribute directive ignored", - name); + { + 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 @@ -327,6 +442,20 @@ decl_attributes (tree *node, tree attributes, int flags) } 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 @@ -406,9 +535,15 @@ decl_attributes (tree *node, tree attributes, int flags) } if (spec->handler != NULL) - returned_attrs = chainon ((*spec->handler) (anode, name, args, - flags, &no_add_attrs), - returned_attrs); + { + 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) @@ -488,6 +623,56 @@ decl_attributes (tree *node, tree attributes, int flags) 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. */ -- cgit v1.2.1