diff options
author | Dodji Seketeli <dodji@redhat.com> | 2012-10-08 09:29:05 +0000 |
---|---|---|
committer | Dodji Seketeli <dodji@gcc.gnu.org> | 2012-10-08 11:29:05 +0200 |
commit | e28d52cffbb2abc7a5764ed4c97a25c376913fee (patch) | |
tree | 1a1442f932577112e42d0c3a2bb905d3ce01d5de | |
parent | f70308d411efebfce8f15b54fedd21c17d44740c (diff) | |
download | gcc-e28d52cffbb2abc7a5764ed4c97a25c376913fee.zip gcc-e28d52cffbb2abc7a5764ed4c97a25c376913fee.tar.gz gcc-e28d52cffbb2abc7a5764ed4c97a25c376913fee.tar.bz2 |
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.
From-SVN: r192199
74 files changed, 2084 insertions, 137 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e879031..460ed84 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,35 @@ +2012-10-08 Dodji Seketeli <dodji@redhat.com> + + PR c++/53528 C++11 attribute support + * 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. + 2012-10-08 Georg-Johann Lay <avr@gjlay.de> PR target/54815 diff --git a/gcc/attribs.c b/gcc/attribs.c index d3af414..b330f27 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; } @@ -196,9 +270,23 @@ 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. */ diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 0d112cf..b49388d 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,15 @@ +2012-10-08 Dodji Seketeli <dodji@redhat.com> + + PR c++/53528 C++11 attribute support + * 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. + 2012-10-04 Arnaud Charlet <charlet@adacore.com> * c-ada-spec.c (print_ada_declaration): Remove handling of TDF_RAW. diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 6de2f1c..e242789 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -484,6 +484,7 @@ const struct c_common_resword c_common_reswords[] = { "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY }, { "__volatile", RID_VOLATILE, 0 }, { "__volatile__", RID_VOLATILE, 0 }, + { "alignas", RID_ALIGNAS, D_CXXONLY | D_CXX0X | D_CXXWARN }, { "alignof", RID_ALIGNOF, D_CXXONLY | D_CXX0X | D_CXXWARN }, { "asm", RID_ASM, D_ASM }, { "auto", RID_AUTO, 0 }, @@ -6665,7 +6666,9 @@ handle_transparent_union_attribute (tree *node, tree name, *no_add_attrs = true; - if (TREE_CODE (*node) == TYPE_DECL) + + if (TREE_CODE (*node) == TYPE_DECL + && ! (flags & ATTR_FLAG_CXX11)) node = &TREE_TYPE (*node); type = *node; @@ -7137,6 +7140,89 @@ check_user_alignment (const_tree align, bool allow_zero) return i; } +/* + If in c++-11, check if the c++-11 alignment constraint with respect + to fundamental alignment (in [dcl.align]) are satisfied. If not in + c++-11 mode, does nothing. + + [dcl.align]2/ says: + + [* if the constant expression evaluates to a fundamental alignment, + the alignment requirement of the declared entity shall be the + specified fundamental alignment. + + * if the constant expression evaluates to an extended alignment + and the implementation supports that alignment in the context + of the declaration, the alignment of the declared entity shall + be that alignment + + * if the constant expression evaluates to an extended alignment + and the implementation does not support that alignment in the + context of the declaration, the program is ill-formed]. */ + +static bool +check_cxx_fundamental_alignment_constraints (tree node, + unsigned align_log, + int flags) +{ + bool alignment_too_large_p = false; + unsigned requested_alignment = 1U << align_log; + unsigned max_align = 0; + + if ((!(flags & ATTR_FLAG_CXX11) && !warn_cxx_compat) + || (node == NULL_TREE || node == error_mark_node)) + return true; + + if (cxx_fundamental_alignment_p (requested_alignment)) + return true; + + if (DECL_P (node)) + { + if (TREE_STATIC (node)) + { + /* For file scope variables and static members, the target + supports alignments that are at most + MAX_OFILE_ALIGNMENT. */ + if (requested_alignment > (max_align = MAX_OFILE_ALIGNMENT)) + alignment_too_large_p = true; + } + else + { +#ifdef BIGGEST_FIELD_ALIGNMENT +#define MAX_TARGET_FIELD_ALIGNMENT BIGGEST_FIELD_ALIGNMENT +#else +#define MAX_TARGET_FIELD_ALIGNMENT BIGGEST_ALIGNMENT +#endif + /* For non-static members, the target supports either + alignments that at most either BIGGEST_FIELD_ALIGNMENT + if it is defined or BIGGEST_ALIGNMENT. */ + max_align = MAX_TARGET_FIELD_ALIGNMENT; + if (TREE_CODE (node) == FIELD_DECL + && requested_alignment > (max_align = MAX_TARGET_FIELD_ALIGNMENT)) + alignment_too_large_p = true; +#undef MAX_TARGET_FIELD_ALIGNMENT + /* For stack variables, the target supports at most + MAX_STACK_ALIGNMENT. */ + else if (decl_function_context (node) != NULL + && requested_alignment > (max_align = MAX_STACK_ALIGNMENT)) + alignment_too_large_p = true; + } + } + else if (TYPE_P (node)) + { + /* Let's be liberal for types. */ + if (requested_alignment > (max_align = BIGGEST_ALIGNMENT)) + alignment_too_large_p = true; + } + + if (alignment_too_large_p) + pedwarn (input_location, OPT_Wattributes, + "requested alignment %d is larger than %d", + requested_alignment, max_align); + + return !alignment_too_large_p; +} + /* Handle a "aligned" attribute; arguments as in struct attribute_spec.handler. */ @@ -7160,7 +7246,8 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args, else if (TYPE_P (*node)) type = node, is_type = 1; - if ((i = check_user_alignment (align_expr, false)) == -1) + if ((i = check_user_alignment (align_expr, false)) == -1 + || !check_cxx_fundamental_alignment_constraints (*node, i, flags)) *no_add_attrs = true; else if (is_type) { @@ -7190,6 +7277,17 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args, error ("alignment may not be specified for %q+D", decl); *no_add_attrs = true; } + else if (DECL_USER_ALIGN (decl) + && DECL_ALIGN (decl) > (1U << i) * BITS_PER_UNIT) + /* C++-11 [dcl.align/4]: + + When multiple alignment-specifiers are specified for an + entity, the alignment requirement shall be set to the + strictest specified alignment. + + This formally comes from the c++11 specification but we are + doing it for the GNU attribute syntax as well. */ + *no_add_attrs = true; else if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ALIGN (decl) > (1U << i) * BITS_PER_UNIT) { @@ -11154,4 +11252,22 @@ convert_vector_to_pointer_for_subscript (location_t loc, } } +/* Return true iff ALIGN is an integral constant that is a fundamental + alignment, as defined by [basic.align] in the c++-11 + specifications. + + That is: + + [A fundamental alignment is represented by an alignment less than or + equal to the greatest alignment supported by the implementation + in all contexts, which is equal to + alignof(max_align_t)]. */ + +bool +cxx_fundamental_alignment_p (unsigned align) +{ + return (align <= MAX (TYPE_ALIGN (long_long_integer_type_node), + TYPE_ALIGN (long_double_type_node))); +} + #include "gt-c-family-c-common.h" diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index cefe92d..5b23bd3 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -789,6 +789,7 @@ extern bool keyword_begins_type_specifier (enum rid); extern bool keyword_is_storage_class_specifier (enum rid); extern bool keyword_is_type_qualifier (enum rid); extern bool keyword_is_decl_specifier (enum rid); +extern bool cxx_fundamental_alignment_p (unsigned); #define c_sizeof(LOC, T) c_sizeof_or_alignof_type (LOC, T, true, 1) #define c_alignof(LOC, T) c_sizeof_or_alignof_type (LOC, T, false, 1) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 525efe4..660a219 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,82 @@ +2012-10-08 Dodji Seketeli <dodji@redhat.com> + + PR c++/53528 C++11 attribute support + * 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 appertain 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. + 2012-10-07 Paolo Carlini <paolo.carlini@oracle.com> * pt.c (fold_non_dependent_expr_sfinae): Remove static specifier. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 00f2d4a..a1d4424 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -418,7 +418,9 @@ typedef enum cpp0x_warn_str /* user defined literals */ CPP0X_USER_DEFINED_LITERALS, /* delegating constructors */ - CPP0X_DELEGATING_CTORS + CPP0X_DELEGATING_CTORS, + /* C++11 attributes */ + CPP0X_ATTRIBUTES } cpp0x_warn_str; /* The various kinds of operation used by composite_pointer_type. */ @@ -4684,6 +4686,7 @@ typedef enum cp_decl_spec { ds_type_spec, ds_redefined_builtin_type_spec, ds_attribute, + ds_std_attribute, ds_storage_class, ds_long_long, ds_last /* This enumerator must always be the last one. */ @@ -4702,6 +4705,8 @@ typedef struct cp_decl_specifier_seq { tree type; /* The attributes, if any, provided with the specifier sequence. */ tree attributes; + /* The c++11 attributes that follows the type specifier. */ + tree std_attributes; /* If non-NULL, a built-in type that the user attempted to redefine to some other type. */ tree redefined_builtin_type; @@ -4770,8 +4775,14 @@ struct cp_declarator { to indicate this is a parameter pack. */ BOOL_BITFIELD parameter_pack_p : 1; location_t id_loc; /* Currently only set for cdk_id and cdk_function. */ - /* Attributes that apply to this declarator. */ + /* GNU Attributes that apply to this declarator. If the declarator + is a pointer or a reference, these attribute apply to the type + pointed to. */ tree attributes; + /* Standard C++11 attributes that apply to this declarator. If the + declarator is a pointer or a reference, these attributes apply + to the pointer, rather than to the type pointed to. */ + tree std_attributes; /* For all but cdk_id and cdk_error, the contained declarator. For cdk_id and cdk_error, guaranteed to be NULL. */ cp_declarator *declarator; @@ -5068,7 +5079,9 @@ extern tree build_cp_library_fn_ptr (const char *, tree); extern tree push_library_fn (tree, tree, tree); extern tree push_void_library_fn (tree, tree); extern tree push_throw_library_fn (tree, tree); -extern tree check_tag_decl (cp_decl_specifier_seq *); +extern void warn_misplaced_attr_for_class_type (source_location location, + tree class_type); +extern tree check_tag_decl (cp_decl_specifier_seq *, bool); extern tree shadow_tag (cp_decl_specifier_seq *); extern tree groktypename (cp_decl_specifier_seq *, const cp_declarator *, bool); extern tree start_decl (const cp_declarator *, cp_decl_specifier_seq *, int, tree, tree, tree *); @@ -5829,6 +5842,7 @@ extern int comp_cv_qualification (const_tree, const_tree); extern int comp_cv_qual_signature (tree, tree); extern tree cxx_sizeof_or_alignof_expr (tree, enum tree_code, bool); extern tree cxx_sizeof_or_alignof_type (tree, enum tree_code, bool); +extern tree cxx_alignas_expr (tree); extern tree cxx_sizeof_nowarn (tree); extern tree is_bitfield_expr_with_lowered_type (const_tree); extern tree unlowered_expr_type (const_tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index c162734..2848ad5 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4132,13 +4132,32 @@ fixup_anonymous_aggr (tree t) } } +/* Warn for an attribute located at LOCATION that appertains to the + class type CLASS_TYPE that has not been properly placed after its + class-key, in it class-specifier. */ + +void +warn_misplaced_attr_for_class_type (source_location location, + tree class_type) +{ + gcc_assert (TAGGED_TYPE_P (class_type)); + + warning_at (location, OPT_Wattributes, + "attribute ignored in declaration " + "of %q#T", class_type); + inform (location, + "attribute for %q#T must follow the %qs keyword", + class_type, class_key_or_enum_as_string (class_type)); +} + /* Make sure that a declaration with no declarator is well-formed, i.e. just declares a tagged type or anonymous union. Returns the type declared; or NULL_TREE if none. */ tree -check_tag_decl (cp_decl_specifier_seq *declspecs) +check_tag_decl (cp_decl_specifier_seq *declspecs, + bool explicit_type_instantiation_p) { int saw_friend = decl_spec_seq_has_spec_p (declspecs, ds_friend); int saw_typedef = decl_spec_seq_has_spec_p (declspecs, ds_typedef); @@ -4247,10 +4266,22 @@ check_tag_decl (cp_decl_specifier_seq *declspecs) /* For a template class (an explicit instantiation), use the current location. */ loc = input_location; - warning_at (loc, OPT_Wattributes, "attribute ignored in declaration " - "of %q#T", declared_type); - inform (loc, "attribute for %q#T must follow the %qs keyword", - declared_type, class_key_or_enum_as_string (declared_type)); + + if (explicit_type_instantiation_p) + /* [dcl.attr.grammar]/4: + + No attribute-specifier-seq shall appertain to an explicit + instantiation. */ + { + warning_at (loc, OPT_Wattributes, + "attribute ignored in explicit instantiation %q#T", + declared_type); + inform (loc, + "no attribute can be applied to " + "an explicit instantiation"); + } + else + warn_misplaced_attr_for_class_type (loc, declared_type); } return declared_type; @@ -4272,7 +4303,8 @@ check_tag_decl (cp_decl_specifier_seq *declspecs) tree shadow_tag (cp_decl_specifier_seq *declspecs) { - tree t = check_tag_decl (declspecs); + tree t = check_tag_decl (declspecs, + /*explicit_type_instantiation_p=*/false); if (!t) return NULL_TREE; @@ -9178,6 +9210,15 @@ grokdeclarator (const cp_declarator *declarator, } } + if (declspecs->std_attributes) + { + /* Apply the c++11 attributes to the type preceding them. */ + source_location saved_loc = input_location; + input_location = declspecs->locations[ds_std_attribute]; + decl_attributes (&type, declspecs->std_attributes, 0); + input_location = saved_loc; + } + /* Determine the type of the entity declared by recurring on the declarator. */ for (; declarator; declarator = declarator->declarator) @@ -9215,6 +9256,13 @@ grokdeclarator (const cp_declarator *declarator, case cdk_array: type = create_array_type_for_decl (dname, type, declarator->u.array.bounds); + if (declarator->std_attributes) + /* [dcl.array]/1: + + The optional attribute-specifier-seq appertains to the + array. */ + returned_attrs = chainon (returned_attrs, + declarator->std_attributes); break; case cdk_function: @@ -9411,6 +9459,13 @@ grokdeclarator (const cp_declarator *declarator, } type = build_function_type (type, arg_types); + if (declarator->std_attributes) + /* [dcl.fct]/2: + + The optional attribute-specifier-seq appertains to + the function type. */ + decl_attributes (&type, declarator->std_attributes, + 0); } break; @@ -9573,6 +9628,17 @@ grokdeclarator (const cp_declarator *declarator, declarator->u.pointer.qualifiers); type_quals = cp_type_quals (type); } + + /* Apply C++11 attributes to the pointer, and not to the + type pointed to. This is unlike what is done for GNU + attributes above. It is to comply with [dcl.ptr]/1: + + [the optional attribute-specifier-seq (7.6.1) appertains + to the pointer and not to the object pointed to]. */ + if (declarator->std_attributes) + decl_attributes (&type, declarator->std_attributes, + 0); + ctype = NULL_TREE; break; @@ -9698,6 +9764,13 @@ grokdeclarator (const cp_declarator *declarator, attrlist = &returned_attrs; } + if (declarator + && declarator->kind == cdk_id + && declarator->std_attributes) + /* [dcl.meaning]/1: The optional attribute-specifier-seq following + a declarator-id appertains to the entity that is declared. */ + *attrlist = chainon (*attrlist, declarator->std_attributes); + /* Handle parameter packs. */ if (parameter_pack_p) { diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 87e38d3..aad3d0b 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1091,7 +1091,7 @@ grokbitfield (const cp_declarator *declarator, static bool is_late_template_attribute (tree attr, tree decl) { - tree name = TREE_PURPOSE (attr); + tree name = get_attribute_name (attr); tree args = TREE_VALUE (attr); const struct attribute_spec *spec = lookup_attribute_spec (name); tree arg; diff --git a/gcc/cp/error.c b/gcc/cp/error.c index e1aa938..2934c9b 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -3374,6 +3374,11 @@ maybe_warn_cpp0x (cpp0x_warn_str str) "delegating constructors " "only available with -std=c++11 or -std=gnu++11"); break; + case CPP0X_ATTRIBUTES: + pedwarn (input_location, 0, + "c++11 attributes " + "only available with -std=c++11 or -std=gnu++11"); + break; default: gcc_unreachable (); } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index baaa809..07f76e3 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1197,13 +1197,13 @@ static cp_declarator *make_call_declarator static cp_declarator *make_array_declarator (cp_declarator *, tree); static cp_declarator *make_pointer_declarator - (cp_cv_quals, cp_declarator *); + (cp_cv_quals, cp_declarator *, tree); static cp_declarator *make_reference_declarator - (cp_cv_quals, cp_declarator *, bool); + (cp_cv_quals, cp_declarator *, bool, tree); static cp_parameter_declarator *make_parameter_declarator (cp_decl_specifier_seq *, cp_declarator *, tree); static cp_declarator *make_ptrmem_declarator - (cp_cv_quals, tree, cp_declarator *); + (cp_cv_quals, tree, cp_declarator *, tree); /* An erroneous declarator. */ static cp_declarator *cp_error_declarator; @@ -1231,6 +1231,7 @@ make_declarator (cp_declarator_kind kind) declarator = (cp_declarator *) alloc_declarator (sizeof (cp_declarator)); declarator->kind = kind; declarator->attributes = NULL_TREE; + declarator->std_attributes = NULL_TREE; declarator->declarator = NULL; declarator->parameter_pack_p = false; declarator->id_loc = UNKNOWN_LOCATION; @@ -1277,10 +1278,12 @@ make_id_declarator (tree qualifying_scope, tree unqualified_name, /* Make a declarator for a pointer to TARGET. CV_QUALIFIERS is a list of modifiers such as const or volatile to apply to the pointer - type, represented as identifiers. */ + type, represented as identifiers. ATTRIBUTES represent the attributes that + appertain to the pointer or reference. */ cp_declarator * -make_pointer_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target) +make_pointer_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target, + tree attributes) { cp_declarator *declarator; @@ -1297,14 +1300,18 @@ make_pointer_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target) else declarator->parameter_pack_p = false; + declarator->std_attributes = attributes; + return declarator; } -/* Like make_pointer_declarator -- but for references. */ +/* Like make_pointer_declarator -- but for references. ATTRIBUTES + represent the attributes that appertain to the pointer or + reference. */ cp_declarator * make_reference_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target, - bool rvalue_ref) + bool rvalue_ref, tree attributes) { cp_declarator *declarator; @@ -1321,15 +1328,19 @@ make_reference_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target, else declarator->parameter_pack_p = false; + declarator->std_attributes = attributes; + return declarator; } /* Like make_pointer_declarator -- but for a pointer to a non-static - member of CLASS_TYPE. */ + member of CLASS_TYPE. ATTRIBUTES represent the attributes that + appertain to the pointer or reference. */ cp_declarator * make_ptrmem_declarator (cp_cv_quals cv_qualifiers, tree class_type, - cp_declarator *pointee) + cp_declarator *pointee, + tree attributes) { cp_declarator *declarator; @@ -1346,6 +1357,8 @@ make_ptrmem_declarator (cp_cv_quals cv_qualifiers, tree class_type, else declarator->parameter_pack_p = false; + declarator->std_attributes = attributes; + return declarator; } @@ -1853,7 +1866,7 @@ static void cp_parser_lambda_body static void cp_parser_statement (cp_parser *, tree, bool, bool *); static void cp_parser_label_for_labeled_statement - (cp_parser *); +(cp_parser *, tree); static tree cp_parser_expression_statement (cp_parser *, tree); static tree cp_parser_compound_statement @@ -1957,7 +1970,7 @@ static cp_declarator *cp_parser_declarator static cp_declarator *cp_parser_direct_declarator (cp_parser *, cp_parser_declarator_kind, int *, bool); static enum tree_code cp_parser_ptr_operator - (cp_parser *, tree *, cp_cv_quals *); + (cp_parser *, tree *, cp_cv_quals *, tree *); static cp_cv_quals cp_parser_cv_qualifier_seq_opt (cp_parser *); static cp_virt_specifiers cp_parser_virt_specifier_seq_opt @@ -2099,9 +2112,29 @@ static tree cp_parser_asm_clobber_list (cp_parser *); static tree cp_parser_asm_label_list (cp_parser *); +static bool cp_next_tokens_can_be_attribute_p + (cp_parser *); +static bool cp_next_tokens_can_be_gnu_attribute_p + (cp_parser *); +static bool cp_next_tokens_can_be_std_attribute_p + (cp_parser *); +static bool cp_nth_tokens_can_be_std_attribute_p + (cp_parser *, size_t); +static bool cp_nth_tokens_can_be_gnu_attribute_p + (cp_parser *, size_t); +static bool cp_nth_tokens_can_be_attribute_p + (cp_parser *, size_t); static tree cp_parser_attributes_opt (cp_parser *); -static tree cp_parser_attribute_list +static tree cp_parser_gnu_attributes_opt + (cp_parser *); +static tree cp_parser_gnu_attribute_list + (cp_parser *); +static tree cp_parser_std_attribute + (cp_parser *); +static tree cp_parser_std_attribute_spec + (cp_parser *); +static tree cp_parser_std_attribute_spec_seq (cp_parser *); static bool cp_parser_extension_opt (cp_parser *, int *); @@ -2308,7 +2341,7 @@ static bool cp_parser_is_keyword static tree cp_parser_make_typename_type (cp_parser *, tree, tree, location_t location); static cp_declarator * cp_parser_make_indirect_declarator - (enum tree_code, tree, cp_cv_quals, cp_declarator *); + (enum tree_code, tree, cp_cv_quals, cp_declarator *, tree); /* Returns nonzero if we are parsing tentatively. */ @@ -3178,24 +3211,30 @@ cp_parser_make_typename_type (cp_parser *parser, tree scope, make_{pointer,ptrmem,reference}_declarator functions that decides which one to call based on the CODE and CLASS_TYPE arguments. The CODE argument should be one of the values returned by - cp_parser_ptr_operator. */ + cp_parser_ptr_operator. ATTRIBUTES represent the attributes that + appertain to the pointer or reference. */ + static cp_declarator * cp_parser_make_indirect_declarator (enum tree_code code, tree class_type, cp_cv_quals cv_qualifiers, - cp_declarator *target) + cp_declarator *target, + tree attributes) { if (code == ERROR_MARK) return cp_error_declarator; if (code == INDIRECT_REF) if (class_type == NULL_TREE) - return make_pointer_declarator (cv_qualifiers, target); + return make_pointer_declarator (cv_qualifiers, target, attributes); else - return make_ptrmem_declarator (cv_qualifiers, class_type, target); + return make_ptrmem_declarator (cv_qualifiers, class_type, + target, attributes); else if (code == ADDR_EXPR && class_type == NULL_TREE) - return make_reference_declarator (cv_qualifiers, target, false); + return make_reference_declarator (cv_qualifiers, target, + false, attributes); else if (code == NON_LVALUE_EXPR && class_type == NULL_TREE) - return make_reference_declarator (cv_qualifiers, target, true); + return make_reference_declarator (cv_qualifiers, target, + true, attributes); gcc_unreachable (); } @@ -5605,6 +5644,13 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, switch (token->type) { case CPP_OPEN_SQUARE: + if (cp_next_tokens_can_be_std_attribute_p (parser)) + { + cp_parser_error (parser, + "two consecutive %<[%> shall " + "only introduce an attribute"); + return error_mark_node; + } postfix_expression = cp_parser_postfix_open_square_expression (parser, postfix_expression, @@ -6873,13 +6919,13 @@ static cp_declarator * cp_parser_new_declarator_opt (cp_parser* parser) { enum tree_code code; - tree type; - cp_cv_quals cv_quals; + tree type, std_attributes = NULL_TREE; + cp_cv_quals cv_quals; /* We don't know if there's a ptr-operator next, or not. */ cp_parser_parse_tentatively (parser); /* Look for a ptr-operator. */ - code = cp_parser_ptr_operator (parser, &type, &cv_quals); + code = cp_parser_ptr_operator (parser, &type, &cv_quals, &std_attributes); /* If that worked, look for more new-declarators. */ if (cp_parser_parse_definitely (parser)) { @@ -6888,8 +6934,10 @@ cp_parser_new_declarator_opt (cp_parser* parser) /* Parse another optional declarator. */ declarator = cp_parser_new_declarator_opt (parser); - return cp_parser_make_indirect_declarator - (code, type, cv_quals, declarator); + declarator = cp_parser_make_indirect_declarator + (code, type, cv_quals, declarator, std_attributes); + + return declarator; } /* If the next token is a `[', there is a direct-new-declarator. */ @@ -8628,6 +8676,18 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr) declaration-statement try-block + C++11: + + statement: + labeled-statement + attribute-specifier-seq (opt) expression-statement + attribute-specifier-seq (opt) compound-statement + attribute-specifier-seq (opt) selection-statement + attribute-specifier-seq (opt) iteration-statement + attribute-specifier-seq (opt) jump-statement + declaration-statement + attribute-specifier-seq (opt) try-block + TM Extension: statement: @@ -8644,15 +8704,20 @@ static void cp_parser_statement (cp_parser* parser, tree in_statement_expr, bool in_compound, bool *if_p) { - tree statement; + tree statement, std_attrs = NULL_TREE; cp_token *token; - location_t statement_location; + location_t statement_location, attrs_location; restart: if (if_p != NULL) *if_p = false; /* There is no statement yet. */ statement = NULL_TREE; + + cp_lexer_save_tokens (parser->lexer); + attrs_location = cp_lexer_peek_token (parser->lexer)->location; + std_attrs = cp_parser_std_attribute_spec_seq (parser); + /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); /* Remember the location of the first token in the statement. */ @@ -8670,7 +8735,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, /* Looks like a labeled-statement with a case label. Parse the label, and then use tail recursion to parse the statement. */ - cp_parser_label_for_labeled_statement (parser); + cp_parser_label_for_labeled_statement (parser, std_attrs); goto restart; case RID_IF: @@ -8733,7 +8798,8 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, /* Looks like a labeled-statement with an ordinary label. Parse the label, and then use tail recursion to parse the statement. */ - cp_parser_label_for_labeled_statement (parser); + + cp_parser_label_for_labeled_statement (parser, std_attrs); goto restart; } } @@ -8769,6 +8835,14 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, { if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) { + if (std_attrs != NULL_TREE) + { + /* Attributes should be parsed as part of the the + declaration, so let's un-parse them. */ + cp_lexer_rollback_tokens (parser->lexer); + std_attrs = NULL_TREE; + } + cp_parser_parse_tentatively (parser); /* Try to parse the declaration-statement. */ cp_parser_declaration_statement (parser); @@ -8783,6 +8857,13 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, /* Set the line number for the statement. */ if (statement && STATEMENT_CODE_P (TREE_CODE (statement))) SET_EXPR_LOCATION (statement, statement_location); + + /* Note that for now, we don't do anything with c++11 statements + parsed at this level. */ + if (std_attrs != NULL_TREE) + warning_at (attrs_location, + OPT_Wattributes, + "attributes at the beginning of statement are ignored"); } /* Parse the label for a labeled-statement, i.e. @@ -8799,7 +8880,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, have to return the label. */ static void -cp_parser_label_for_labeled_statement (cp_parser* parser) +cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes) { cp_token *token; tree label = NULL_TREE; @@ -8879,21 +8960,23 @@ cp_parser_label_for_labeled_statement (cp_parser* parser) lab: __attribute__ ((unused)) int i; we want the attribute to attach to "i", not "lab". */ if (label != NULL_TREE - && cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE)) + && cp_next_tokens_can_be_gnu_attribute_p (parser)) { tree attrs; - cp_parser_parse_tentatively (parser); - attrs = cp_parser_attributes_opt (parser); + attrs = cp_parser_gnu_attributes_opt (parser); if (attrs == NULL_TREE || cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) cp_parser_abort_tentative_parse (parser); else if (!cp_parser_parse_definitely (parser)) ; else - cplus_decl_attributes (&label, attrs, 0); + attributes = chainon (attributes, attrs); } + if (attributes != NULL_TREE) + cplus_decl_attributes (&label, attributes, 0); + parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; } @@ -10319,8 +10402,7 @@ cp_parser_block_declaration (cp_parser *parser, else if (cxx_dialect >= cxx0x && token2->type == CPP_NAME && ((cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_EQ) - || (cp_lexer_peek_nth_token (parser->lexer, 3)->keyword - == RID_ATTRIBUTE))) + || (cp_nth_tokens_can_be_attribute_p (parser, 3)))) cp_parser_alias_declaration (parser); /* Otherwise, it's a using-declaration. */ else @@ -10550,6 +10632,7 @@ cp_parser_simple_declaration (cp_parser* parser, decl-specifier-seq: decl-specifier-seq [opt] decl-specifier + decl-specifier attribute-specifier-seq [opt] (C++11) decl-specifier: storage-class-specifier @@ -10584,6 +10667,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser, int* declares_class_or_enum) { bool constructor_possible_p = !parser->in_declarator_p; + bool found_decl_spec = false; cp_token *start_token = NULL; cp_decl_spec ds; @@ -10597,7 +10681,6 @@ cp_parser_decl_specifier_seq (cp_parser* parser, while (true) { bool constructor_p; - bool found_decl_spec; cp_token *token; ds = ds_last; @@ -10609,12 +10692,55 @@ cp_parser_decl_specifier_seq (cp_parser* parser, if (!start_token) start_token = token; /* Handle attributes. */ - if (token->keyword == RID_ATTRIBUTE) + if (cp_next_tokens_can_be_attribute_p (parser)) { /* Parse the attributes. */ - decl_specs->attributes - = chainon (decl_specs->attributes, - cp_parser_attributes_opt (parser)); + tree attrs = cp_parser_attributes_opt (parser); + + /* In a sequence of declaration specifiers, c++11 attributes + appertain to the type that precede them. In that case + [dcl.spec]/1 says: + + The attribute-specifier-seq affects the type only for + the declaration it appears in, not other declarations + involving the same type. + + But for now let's force the user to position the + attribute either at the beginning of the declaration or + after the declarator-id, which would clearly mean that it + applies to the declarator. */ + if (cxx11_attribute_p (attrs)) + { + if (!found_decl_spec) + /* The c++11 attribute is at the beginning of the + declaration. It appertains to the entity being + declared. */; + else + { + if (decl_specs->type && CLASS_TYPE_P (decl_specs->type)) + { + /* This is an attribute following a + class-specifier. */ + if (decl_specs->type_definition_p) + warn_misplaced_attr_for_class_type (token->location, + decl_specs->type); + attrs = NULL_TREE; + } + else + { + decl_specs->std_attributes + = chainon (decl_specs->std_attributes, + attrs); + if (decl_specs->locations[ds_std_attribute] == 0) + decl_specs->locations[ds_std_attribute] = token->location; + } + continue; + } + } + + decl_specs->attributes + = chainon (decl_specs->attributes, + attrs); if (decl_specs->locations[ds_attribute] == 0) decl_specs->locations[ds_attribute] = token->location; continue; @@ -11341,13 +11467,14 @@ static cp_declarator * cp_parser_conversion_declarator_opt (cp_parser* parser) { enum tree_code code; - tree class_type; + tree class_type, std_attributes = NULL_TREE; cp_cv_quals cv_quals; /* We don't know if there's a ptr-operator next, or not. */ cp_parser_parse_tentatively (parser); /* Try the ptr-operator. */ - code = cp_parser_ptr_operator (parser, &class_type, &cv_quals); + code = cp_parser_ptr_operator (parser, &class_type, &cv_quals, + &std_attributes); /* If it worked, look for more conversion-declarators. */ if (cp_parser_parse_definitely (parser)) { @@ -11356,8 +11483,10 @@ cp_parser_conversion_declarator_opt (cp_parser* parser) /* Parse another optional declarator. */ declarator = cp_parser_conversion_declarator_opt (parser); - return cp_parser_make_indirect_declarator - (code, class_type, cv_quals, declarator); + declarator = cp_parser_make_indirect_declarator + (code, class_type, cv_quals, declarator, std_attributes); + + return declarator; } return NULL; @@ -13188,7 +13317,8 @@ cp_parser_explicit_instantiation (cp_parser* parser) { tree type; - type = check_tag_decl (&decl_specifiers); + type = check_tag_decl (&decl_specifiers, + /*explicit_type_instantiation_p=*/true); /* Turn access control back on for names used during template instantiation. */ pop_deferring_access_checks (); @@ -14619,7 +14749,7 @@ cp_parser_enum_specifier (cp_parser* parser) apply them if appropriate. */ if (cp_parser_allow_gnu_extensions_p (parser)) { - tree trailing_attr = cp_parser_attributes_opt (parser); + tree trailing_attr = cp_parser_gnu_attributes_opt (parser); trailing_attr = chainon (trailing_attr, attributes); cplus_decl_attributes (&type, trailing_attr, @@ -15521,7 +15651,7 @@ cp_parser_init_declarator (cp_parser* parser, *attributes_start_token = NULL; cp_declarator *declarator; tree prefix_attributes; - tree attributes; + tree attributes = NULL; tree asm_specification; tree initializer; tree decl = NULL_TREE; @@ -15587,22 +15717,20 @@ cp_parser_init_declarator (cp_parser* parser, decl_specifiers->type = maybe_update_decl_type (decl_specifiers->type, scope); - /* If we're allowing GNU extensions, look for an asm-specification - and attributes. */ + /* If we're allowing GNU extensions, look for an + asm-specification. */ if (cp_parser_allow_gnu_extensions_p (parser)) { /* Look for an asm-specification. */ asm_spec_start_token = cp_lexer_peek_token (parser->lexer); asm_specification = cp_parser_asm_specification_opt (parser); - /* And attributes. */ - attributes_start_token = cp_lexer_peek_token (parser->lexer); - attributes = cp_parser_attributes_opt (parser); } else - { - asm_specification = NULL_TREE; - attributes = NULL_TREE; - } + asm_specification = NULL_TREE; + + /* Look for attributes. */ + attributes_start_token = cp_lexer_peek_token (parser->lexer); + attributes = cp_parser_attributes_opt (parser); /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); @@ -15931,7 +16059,7 @@ cp_parser_declarator (cp_parser* parser, enum tree_code code; cp_cv_quals cv_quals; tree class_type; - tree attributes = NULL_TREE; + tree gnu_attributes = NULL_TREE, std_attributes = NULL_TREE; /* Assume this is not a constructor, destructor, or type-conversion operator. */ @@ -15939,14 +16067,16 @@ cp_parser_declarator (cp_parser* parser, *ctor_dtor_or_conv_p = 0; if (cp_parser_allow_gnu_extensions_p (parser)) - attributes = cp_parser_attributes_opt (parser); + gnu_attributes = cp_parser_gnu_attributes_opt (parser); /* Check for the ptr-operator production. */ cp_parser_parse_tentatively (parser); /* Parse the ptr-operator. */ code = cp_parser_ptr_operator (parser, &class_type, - &cv_quals); + &cv_quals, + &std_attributes); + /* If that worked, then we have a ptr-operator. */ if (cp_parser_parse_definitely (parser)) { @@ -15972,7 +16102,7 @@ cp_parser_declarator (cp_parser* parser, declarator = NULL; declarator = cp_parser_make_indirect_declarator - (code, class_type, cv_quals, declarator); + (code, class_type, cv_quals, declarator, std_attributes); } /* Everything else is a direct-declarator. */ else @@ -15985,9 +16115,8 @@ cp_parser_declarator (cp_parser* parser, member_p); } - if (attributes && declarator && declarator != cp_error_declarator) - declarator->attributes = attributes; - + if (gnu_attributes && declarator && declarator != cp_error_declarator) + declarator->attributes = gnu_attributes; return declarator; } @@ -16127,6 +16256,7 @@ cp_parser_direct_declarator (cp_parser* parser, cp_virt_specifiers virt_specifiers; tree exception_specification; tree late_return; + tree attrs; is_declarator = true; @@ -16140,6 +16270,8 @@ cp_parser_direct_declarator (cp_parser* parser, exception_specification = cp_parser_exception_specification_opt (parser); + attrs = cp_parser_std_attribute_spec_seq (parser); + late_return = (cp_parser_late_return_type_opt (parser, member_p ? cv_quals : -1)); @@ -16153,6 +16285,7 @@ cp_parser_direct_declarator (cp_parser* parser, virt_specifiers, exception_specification, late_return); + declarator->std_attributes = attrs; /* Any subsequent parameter lists are to do with return type, so are not those of the declared function. */ @@ -16202,10 +16335,11 @@ cp_parser_direct_declarator (cp_parser* parser, break; } else if ((!first || dcl_kind != CP_PARSER_DECLARATOR_NAMED) - && token->type == CPP_OPEN_SQUARE) + && token->type == CPP_OPEN_SQUARE + && !cp_next_tokens_can_be_attribute_p (parser)) { /* Parse an array-declarator. */ - tree bounds; + tree bounds, attrs; if (ctor_dtor_or_conv_p) *ctor_dtor_or_conv_p = 0; @@ -16258,13 +16392,16 @@ cp_parser_direct_declarator (cp_parser* parser, break; } + attrs = cp_parser_std_attribute_spec_seq (parser); declarator = make_array_declarator (declarator, bounds); + declarator->std_attributes = attrs; } else if (first && dcl_kind != CP_PARSER_DECLARATOR_ABSTRACT) { { tree qualifying_scope; tree unqualified_name; + tree attrs; special_function_kind sfk; bool abstract_ok; bool pack_expansion_p = false; @@ -16331,6 +16468,8 @@ cp_parser_direct_declarator (cp_parser* parser, break; } + attrs = cp_parser_std_attribute_spec_seq (parser); + if (qualifying_scope && at_namespace_scope_p () && TREE_CODE (qualifying_scope) == TYPENAME_TYPE) { @@ -16445,6 +16584,7 @@ cp_parser_direct_declarator (cp_parser* parser, declarator = make_id_declarator (qualifying_scope, unqualified_name, sfk); + declarator->std_attributes = attrs; declarator->id_loc = token->location; declarator->parameter_pack_p = pack_expansion_p; @@ -16492,9 +16632,11 @@ cp_parser_direct_declarator (cp_parser* parser, /* Parse a ptr-operator. ptr-operator: + * attribute-specifier-seq [opt] cv-qualifier-seq [opt] (C++11) * cv-qualifier-seq [opt] & :: [opt] nested-name-specifier * cv-qualifier-seq [opt] + nested-name-specifier * attribute-specifier-seq [opt] cv-qualifier-seq [opt] (C++11) GNU Extension: @@ -16514,10 +16656,12 @@ cp_parser_direct_declarator (cp_parser* parser, static enum tree_code cp_parser_ptr_operator (cp_parser* parser, tree* type, - cp_cv_quals *cv_quals) + cp_cv_quals *cv_quals, + tree *attributes) { enum tree_code code = ERROR_MARK; cp_token *token; + tree attrs = NULL_TREE; /* Assume that it's not a pointer-to-member. */ *type = NULL_TREE; @@ -16548,6 +16692,10 @@ cp_parser_ptr_operator (cp_parser* parser, if (code == INDIRECT_REF || cp_parser_allow_gnu_extensions_p (parser)) *cv_quals = cp_parser_cv_qualifier_seq_opt (parser); + + attrs = cp_parser_std_attribute_spec_seq (parser); + if (attributes != NULL) + *attributes = attrs; } else { @@ -16585,6 +16733,10 @@ cp_parser_ptr_operator (cp_parser* parser, parser->scope = NULL_TREE; parser->qualifying_scope = NULL_TREE; parser->object_scope = NULL_TREE; + /* Look for optional c++11 attributes. */ + attrs = cp_parser_std_attribute_spec_seq (parser); + if (attributes != NULL) + *attributes = attrs; /* Look for the optional cv-qualifier-seq. */ *cv_quals = cp_parser_cv_qualifier_seq_opt (parser); } @@ -16944,7 +17096,7 @@ cp_parser_type_specifier_seq (cp_parser* parser, bool is_cv_qualifier; /* Check for attributes first. */ - if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE)) + if (cp_next_tokens_can_be_attribute_p (parser)) { type_specifier_seq->attributes = chainon (type_specifier_seq->attributes, @@ -18050,7 +18202,7 @@ cp_parser_class_specifier_1 (cp_parser* parser) closing_brace = cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); /* Look for trailing attributes to apply to this class. */ if (cp_parser_allow_gnu_extensions_p (parser)) - attributes = cp_parser_attributes_opt (parser); + attributes = cp_parser_gnu_attributes_opt (parser); if (type != error_mark_node) type = finish_struct (type, attributes); if (nested_name_specifier_p) @@ -18071,6 +18223,12 @@ cp_parser_class_specifier_1 (cp_parser* parser) cp_token *token = cp_lexer_peek_token (parser->lexer); bool want_semicolon = true; + if (cp_next_tokens_can_be_std_attribute_p (parser)) + /* Don't try to parse c++11 attributes here. As per the + grammar, that should be a task for + cp_parser_decl_specifier_seq. */ + want_semicolon = false; + switch (token->type) { case CPP_NAME: @@ -18921,8 +19079,6 @@ cp_parser_member_declaration (cp_parser* parser) CP_PARSER_FLAGS_OPTIONAL, &decl_specifiers, &declares_class_or_enum); - prefix_attributes = decl_specifiers.attributes; - decl_specifiers.attributes = NULL_TREE; /* Check for an invalid type-name. */ if (!decl_specifiers.any_type_specifiers_p && cp_parser_parse_and_diagnose_invalid_type_name (parser)) @@ -18954,7 +19110,8 @@ cp_parser_member_declaration (cp_parser* parser) friend_p = cp_parser_friend_p (&decl_specifiers); /* If there were decl-specifiers, check to see if there was a class-declaration. */ - type = check_tag_decl (&decl_specifiers); + type = check_tag_decl (&decl_specifiers, + /*explicit_type_instantiation_p=*/false); /* Nested classes have already been added to the class, but a `friend' needs to be explicitly registered. */ if (friend_p) @@ -19021,6 +19178,12 @@ cp_parser_member_declaration (cp_parser* parser) { bool assume_semicolon = false; + /* Clear attributes from the decl_specifiers but keep them + around as prefix attributes that apply them to the entity + being declared. */ + prefix_attributes = decl_specifiers.attributes; + decl_specifiers.attributes = NULL_TREE; + /* See if these declarations will be friends. */ friend_p = cp_parser_friend_p (&decl_specifiers); @@ -20127,6 +20290,80 @@ cp_parser_asm_label_list (cp_parser* parser) return nreverse (labels); } +/* Return TRUE iff the next tokens in the stream are possibly the + beginning of a GNU extension attribute. */ + +static bool +cp_next_tokens_can_be_gnu_attribute_p (cp_parser *parser) +{ + return cp_nth_tokens_can_be_gnu_attribute_p (parser, 1); +} + +/* Return TRUE iff the next tokens in the stream are possibly the + beginning of a standard C++-11 attribute. */ + +static bool +cp_next_tokens_can_be_std_attribute_p (cp_parser *parser) +{ + return cp_nth_tokens_can_be_std_attribute_p (parser, 1); +} + +/* Return TRUE iff the next Nth tokens in the stream are possibly the + beginning of a standard C++-11 attribute. */ + +static bool +cp_nth_tokens_can_be_std_attribute_p (cp_parser *parser, size_t n) +{ + cp_token *token = cp_lexer_peek_nth_token (parser->lexer, n); + + return (cxx_dialect >= cxx0x + && token->type == CPP_OPEN_SQUARE + && (token = cp_lexer_peek_nth_token (parser->lexer, n + 1)) + && token->type == CPP_OPEN_SQUARE); +} + +/* Return TRUE iff the next Nth tokens in the stream are possibly the + beginning of a GNU extension attribute. */ + +static bool +cp_nth_tokens_can_be_gnu_attribute_p (cp_parser *parser, size_t n) +{ + cp_token *token = cp_lexer_peek_nth_token (parser->lexer, n); + + return token->type == CPP_KEYWORD && token->keyword == RID_ATTRIBUTE; +} + +/* Return true iff the next tokens can be the beginning of either a + GNU attribute list, or a standard C++11 attribute sequence. */ + +static bool +cp_next_tokens_can_be_attribute_p (cp_parser *parser) +{ + return (cp_next_tokens_can_be_gnu_attribute_p (parser) + || cp_next_tokens_can_be_std_attribute_p (parser)); +} + +/* Return true iff the next Nth tokens can be the beginning of either + a GNU attribute list, or a standard C++11 attribute sequence. */ + +static bool +cp_nth_tokens_can_be_attribute_p (cp_parser *parser, size_t n) +{ + return (cp_nth_tokens_can_be_gnu_attribute_p (parser, n) + || cp_nth_tokens_can_be_std_attribute_p (parser, n)); +} + +/* Parse either a standard C++-11 attribute-specifier-seq, or a series + of GNU attributes, or return NULL. */ + +static tree +cp_parser_attributes_opt (cp_parser *parser) +{ + if (cp_next_tokens_can_be_gnu_attribute_p (parser)) + return cp_parser_gnu_attributes_opt (parser); + return cp_parser_std_attribute_spec_seq (parser); +} + /* Parse an (optional) series of attributes. attributes: @@ -20135,10 +20372,10 @@ cp_parser_asm_label_list (cp_parser* parser) attribute: __attribute__ (( attribute-list [opt] )) - The return value is as for cp_parser_attribute_list. */ + The return value is as for cp_parser_gnu_attribute_list. */ static tree -cp_parser_attributes_opt (cp_parser* parser) +cp_parser_gnu_attributes_opt (cp_parser* parser) { tree attributes = NULL_TREE; @@ -20164,7 +20401,7 @@ cp_parser_attributes_opt (cp_parser* parser) token = cp_lexer_peek_token (parser->lexer); if (token->type != CPP_CLOSE_PAREN) /* Parse the attribute-list. */ - attribute_list = cp_parser_attribute_list (parser); + attribute_list = cp_parser_gnu_attribute_list (parser); else /* If the next token is a `)', then there is no attribute list. */ @@ -20185,7 +20422,7 @@ cp_parser_attributes_opt (cp_parser* parser) return attributes; } -/* Parse an attribute-list. +/* Parse a GNU attribute-list. attribute-list: attribute @@ -20203,7 +20440,7 @@ cp_parser_attributes_opt (cp_parser* parser) the arguments, if any. */ static tree -cp_parser_attribute_list (cp_parser* parser) +cp_parser_gnu_attribute_list (cp_parser* parser) { tree attribute_list = NULL_TREE; bool save_translate_strings_p = parser->translate_strings_p; @@ -20282,6 +20519,277 @@ cp_parser_attribute_list (cp_parser* parser) return nreverse (attribute_list); } +/* Parse a standard C++11 attribute. + + The returned representation is a TREE_LIST which TREE_PURPOSE is + the scoped name of the attribute, and the TREE_VALUE is its + arguments list. + + Note that the scoped name of the attribute is itself a TREE_LIST + which TREE_PURPOSE is the namespace of the attribute, and + TREE_VALUE its name. This is unlike a GNU attribute -- as parsed + by cp_parser_gnu_attribute_list -- that doesn't have any namespace + and which TREE_PURPOSE is directly the attribute name. + + Clients of the attribute code should use get_attribute_namespace + and get_attribute_name to get the actual namespace and name of + attributes, regardless of their being GNU or C++11 attributes. + + attribute: + attribute-token attribute-argument-clause [opt] + + attribute-token: + identifier + attribute-scoped-token + + attribute-scoped-token: + attribute-namespace :: identifier + + attribute-namespace: + identifier + + attribute-argument-clause: + ( balanced-token-seq ) + + balanced-token-seq: + balanced-token [opt] + balanced-token-seq balanced-token + + balanced-token: + ( balanced-token-seq ) + [ balanced-token-seq ] + { balanced-token-seq }. */ + +static tree +cp_parser_std_attribute (cp_parser *parser) +{ + tree attribute, attr_ns = NULL_TREE, attr_id = NULL_TREE, arguments; + cp_token *token; + + /* First, parse name of the the attribute, a.k.a + attribute-token. */ + + token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_NAME) + attr_id = token->u.value; + else if (token->type == CPP_KEYWORD) + attr_id = ridpointers[(int) token->keyword]; + else if (token->flags & NAMED_OP) + attr_id = get_identifier (cpp_type2name (token->type, token->flags)); + + if (attr_id == NULL_TREE) + return NULL_TREE; + + cp_lexer_consume_token (parser->lexer); + + token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_SCOPE) + { + /* We are seeing a scoped attribute token. */ + + cp_lexer_consume_token (parser->lexer); + attr_ns = attr_id; + + token = cp_lexer_consume_token (parser->lexer); + if (token->type == CPP_NAME) + attr_id = token->u.value; + else if (token->type == CPP_KEYWORD) + attr_id = ridpointers[(int) token->keyword]; + else + { + error_at (token->location, + "expected an identifier for the attribute name"); + return error_mark_node; + } + attribute = build_tree_list (build_tree_list (attr_ns, attr_id), + NULL_TREE); + token = cp_lexer_peek_token (parser->lexer); + } + else + attribute = build_tree_list (build_tree_list (NULL_TREE, attr_id), + NULL_TREE); + + /* Now parse the optional argument clause of the attribute. */ + + if (token->type != CPP_OPEN_PAREN) + return attribute; + + { + VEC(tree, gc) *vec; + int attr_flag = normal_attr; + + if (attr_ns == get_identifier ("gnu") + && attribute_takes_identifier_p (attr_id)) + /* A GNU attribute that takes an identifier in parameter. */ + attr_flag = id_attr; + + vec = cp_parser_parenthesized_expression_list + (parser, attr_flag, /*cast_p=*/false, + /*allow_expansion_p=*/true, + /*non_constant_p=*/NULL); + if (vec == NULL) + arguments = error_mark_node; + else + { + arguments = build_tree_list_vec (vec); + release_tree_vector (vec); + } + + if (arguments == error_mark_node) + attribute = error_mark_node; + else + TREE_VALUE (attribute) = arguments; + } + + return attribute; +} + +/* Parse a list of standard C++-11 attributes. + + attribute-list: + attribute [opt] + attribute-list , attribute[opt] + attribute ... + attribute-list , attribute ... +*/ + +static tree +cp_parser_std_attribute_list (cp_parser *parser) +{ + tree attributes = NULL_TREE, attribute = NULL_TREE; + cp_token *token = NULL; + + while (true) + { + attribute = cp_parser_std_attribute (parser); + if (attribute == error_mark_node) + break; + if (attribute != NULL_TREE) + { + TREE_CHAIN (attribute) = attributes; + attributes = attribute; + } + token = cp_lexer_peek_token (parser->lexer); + if (token->type != CPP_COMMA) + break; + cp_lexer_consume_token (parser->lexer); + } + attributes = nreverse (attributes); + return attributes; +} + +/* Parse a standard C++-11 attribute specifier. + + attribute-specifier: + [ [ attribute-list ] ] + alignment-specifier + + alignment-specifier: + alignas ( type-id ... [opt] ) + alignas ( alignment-expression ... [opt] ). */ + +static tree +cp_parser_std_attribute_spec (cp_parser *parser) +{ + tree attributes = NULL_TREE; + cp_token *token = cp_lexer_peek_token (parser->lexer); + + if (token->type == CPP_OPEN_SQUARE + && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_OPEN_SQUARE) + { + cp_lexer_consume_token (parser->lexer); + maybe_warn_cpp0x (CPP0X_ATTRIBUTES); + cp_lexer_consume_token (parser->lexer); + + attributes = cp_parser_std_attribute_list (parser); + + if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE) + || !cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE)) + cp_parser_skip_to_end_of_statement (parser); + } + else + { + tree alignas_expr; + + /* Look for an alignment-specifier. */ + + token = cp_lexer_peek_token (parser->lexer); + + if (token->type != CPP_KEYWORD + || token->keyword != RID_ALIGNAS) + return NULL_TREE; + + cp_lexer_consume_token (parser->lexer); + maybe_warn_cpp0x (CPP0X_ATTRIBUTES); + + if (cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN) == NULL) + { + cp_parser_error (parser, "expected %<(%>"); + return error_mark_node; + } + + cp_parser_parse_tentatively (parser); + alignas_expr = cp_parser_type_id (parser); + + if (!cp_parser_parse_definitely (parser)) + { + gcc_assert (alignas_expr == error_mark_node + || alignas_expr == NULL_TREE); + + alignas_expr = + cp_parser_assignment_expression (parser, /*cast_p=*/false, + /**cp_id_kind=*/NULL); + if (alignas_expr == NULL_TREE + || alignas_expr == error_mark_node) + return alignas_expr; + } + + if (cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN) == NULL) + { + cp_parser_error (parser, "expected %<)%>"); + return error_mark_node; + } + + alignas_expr = cxx_alignas_expr (alignas_expr); + + /* Build the C++-11 representation of an 'aligned' + attribute. */ + attributes = + build_tree_list (build_tree_list (get_identifier ("gnu"), + get_identifier ("aligned")), + build_tree_list (NULL_TREE, alignas_expr)); + } + + return attributes; +} + +/* Parse a standard C++-11 attribute-specifier-seq. + + attribute-specifier-seq: + attribute-specifier-seq [opt] attribute-specifier + */ + +static tree +cp_parser_std_attribute_spec_seq (cp_parser *parser) +{ + tree attr_specs = NULL; + + while (true) + { + tree attr_spec = cp_parser_std_attribute_spec (parser); + if (attr_spec == NULL_TREE) + break; + if (attr_spec == error_mark_node) + return error_mark_node; + + TREE_CHAIN (attr_spec) = attr_specs; + attr_specs = attr_spec; + } + + attr_specs = nreverse (attr_specs); + return attr_specs; +} + /* Parse an optional `__extension__' keyword. Returns TRUE if it is present, and FALSE otherwise. *SAVED_PEDANTIC is set to the current value of the PEDANTIC flag, regardless of whether or not diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index ce77907..ae4d0a4 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1701,6 +1701,56 @@ cxx_sizeof_or_alignof_expr (tree e, enum tree_code op, bool complain) else return cxx_alignof_expr (e, complain? tf_warning_or_error : tf_none); } + +/* Build a representation of an expression 'alignas(E).' Return the + folded integer value of E if it is an integral constant expression + that resolves to a valid alignment. If E depends on a template + parameter, return a syntactic representation tree of kind + ALIGNOF_EXPR. Otherwise, return an error_mark_node if the + expression is ill formed, or NULL_TREE if E is NULL_TREE. */ + +tree +cxx_alignas_expr (tree e) +{ + if (e == NULL_TREE || e == error_mark_node + || (!TYPE_P (e) && !require_potential_rvalue_constant_expression (e))) + return e; + + if (TYPE_P (e)) + /* [dcl.align]/3: + + When the alignment-specifier is of the form + alignas(type-id ), it shall have the same effect as + alignas( alignof(type-id )). */ + + return cxx_sizeof_or_alignof_type (e, ALIGNOF_EXPR, false); + + + /* If we reach this point, it means the alignas expression if of + the form "alignas(assignment-expression)", so we should follow + what is stated by [dcl.align]/2. */ + + e = mark_rvalue_use (e); + + /* [dcl.align]/2 says: + + the assignment-expression shall be an integral constant + expression. */ + + e = fold_non_dependent_expr (e); + if (value_dependent_expression_p (e)) + /* Leave value-dependent expression alone for now. */; + else + e = cxx_constant_value (e); + + if (e == NULL_TREE + || e == error_mark_node + || TREE_CODE (e) != INTEGER_CST) + return error_mark_node; + + return e; +} + /* EXPR is being used in a context that is not a function call. Enforce: diff --git a/gcc/plugin.h b/gcc/plugin.h index 4d2d12a..c514e67 100644 --- a/gcc/plugin.h +++ b/gcc/plugin.h @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see #include "gcc-plugin.h" struct attribute_spec; +struct scoped_attributes; extern void add_new_plugin (const char *); extern void parse_plugin_arg_opt (const char *); @@ -64,5 +65,7 @@ invoke_plugin_callbacks (int event ATTRIBUTE_UNUSED, /* In attribs.c. */ extern void register_attribute (const struct attribute_spec *attr); +extern struct scoped_attributes* register_scoped_attributes (const struct attribute_spec *, + const char *); #endif /* PLUGIN_H */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4d58edf..d20a9e8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,64 @@ +2012-10-08 Dodji Seketeli <dodji@redhat.com> + + PR c++/53528 C++11 attribute support + * 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. + 2012-10-08 Eric Botcazou <ebotcazou@adacore.com> * gcc.dg/tree-ssa/slsr-30.c: Use correct cleanup directive. diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-1.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-1.C new file mode 100644 index 0000000..a55698c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-1.C @@ -0,0 +1,3 @@ +// { dg-do compile { target c++11 } } + +int **** [[gnu::format(printf, 1, 2)]] foo(const char *, ...); // { dg-warning "ignored" } diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-10.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-10.C new file mode 100644 index 0000000..cac568e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-10.C @@ -0,0 +1,9 @@ +// PR c++/12795 +// { dg-do compile { target c++11 } } +// { dg-require-alias "" } + +void foo() +{ + extern void bar [[gnu::__alias__ ("BAR")]] (); // { dg-warning "ignored" } + bar (); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-11.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-11.C new file mode 100644 index 0000000..504b456 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-11.C @@ -0,0 +1,17 @@ +// { dg-do compile { target c++11 } } +// PR c++/13791 + +template <typename T> struct O { + struct [[gnu::packed]] I { + int i; + char c; + }; + + I* foo(); +}; + +template <typename T> +typename O<T>::I* +O<T>::foo() { return 0; } + +template class O<int>; diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-12.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-12.C new file mode 100644 index 0000000..504b456 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-12.C @@ -0,0 +1,17 @@ +// { dg-do compile { target c++11 } } +// PR c++/13791 + +template <typename T> struct O { + struct [[gnu::packed]] I { + int i; + char c; + }; + + I* foo(); +}; + +template <typename T> +typename O<T>::I* +O<T>::foo() { return 0; } + +template class O<int>; diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-13.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-13.C new file mode 100644 index 0000000..a1b4a84 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-13.C @@ -0,0 +1,5 @@ +// { dg-do compile { target c++11 } } +// PR c++/13854 + +extern char *rindex [[gnu::__pure__]] (__const char *__s, int __c) throw (); +extern char *rindex [[gnu::__pure__]] (__const char *__s, int __c) throw (); diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-14.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-14.C new file mode 100644 index 0000000..d646d27 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-14.C @@ -0,0 +1,14 @@ +// { dg-do compile { target c++11 } } +// PR c++/13170 +// The bogus attribute is ignored, but was in TYPE_ATTRIBUTES during +// parsing of the class, causing some variants to have it and some not. + +struct [[gnu::bogus]] A // { dg-warning "ignored" "" } +{ + virtual ~A(); + void foo(const A&); + void bar(const A&); +}; + +void A::foo(const A&) {} +void A::bar(const A& a) { foo(a); } diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-15.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-15.C new file mode 100644 index 0000000..bf05dbe --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-15.C @@ -0,0 +1,9 @@ +// { dg-do compile { target c++11 } } +// PR c++/15317 + +struct A +{ + A(char); +}; +A::A([[gnu::unused]] char i2) +{} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-16.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-16.C new file mode 100644 index 0000000..4adefdb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-16.C @@ -0,0 +1,8 @@ +// { dg-do compile { target c++11 } } +// Origin: <rguenth at tat dot physik dot uni-tuebingen dot de> +// PR c++/10479: use of non dependent expressions in attributes in templates + +template <int i> +struct foo2 { + float bar [[gnu::aligned(alignof(double))]]; +}; diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-17.2.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-17.2.C new file mode 100644 index 0000000..636f9a9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-17.2.C @@ -0,0 +1,19 @@ +// { dg-do compile { target c++11 } } +// Origin: Benjamin Kosnik <bkoz at gcc dot gnu dot org> +// PR c++/17743: Attributes applied to typedefs. + +struct A { + typedef char layout_type[sizeof(double)] + [[gnu::aligned(alignof(double)]]); // { dg-error "expected" } + layout_type data; +}; + +struct B { + typedef char layout_type[sizeof(double)]; + layout_type data [[gnu::aligned(alignof(double))]]; +}; + +template<bool> struct StaticAssert; +template<> struct StaticAssert<true> {}; + +StaticAssert<alignof(A) == alignof(B)> a1;// { dg-error "incomplete type and cannot be defined" } diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-17.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-17.C new file mode 100644 index 0000000..566461b0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-17.C @@ -0,0 +1,19 @@ +// { dg-do compile { target c++11 } } +// Origin: Benjamin Kosnik <bkoz at gcc dot gnu dot org> +// PR c++/17743: Attributes applied to typedefs. + +struct A { + typedef char layout_type[sizeof(double)] + [[gnu::aligned(alignof(double))]]; + layout_type data; +}; + +struct B { + typedef char layout_type[sizeof(double)]; + layout_type data [[gnu::aligned(alignof(double))]]; +}; + +template<bool> struct StaticAssert; +template<> struct StaticAssert<true> {}; + +StaticAssert<alignof(A) == alignof(B)> a1; diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-18.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-18.C new file mode 100644 index 0000000..3df13e6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-18.C @@ -0,0 +1,10 @@ +// PR c++/17542 +// Test that we warn when an attribute preceding the class-key is ignored. +// { dg-do compile { target c++11 } } + +[[gnu::packed]] struct A // { dg-warning "attribute" } +{ + char c; + int x; + void f(); +}; diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-19.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-19.C new file mode 100644 index 0000000..5ac93d8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-19.C @@ -0,0 +1,11 @@ +// PR c++/19739 +// { dg-do compile { target c++11 } } + +void Dummy() [[ , ]]; +void Dummy() {} + +int main (int argc, char **argv) +{ + Dummy(); + return 0; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-2-1.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-2-1.C new file mode 100644 index 0000000..2f47b32 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-2-1.C @@ -0,0 +1,3 @@ +// { dg-do compile { target c++11 } } + +struct [[gnu::unused]] A {}; diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-2.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-2.C new file mode 100644 index 0000000..8c777c1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-2.C @@ -0,0 +1,11 @@ +// { dg-do compile { target c++11 } } + +struct [[gnu::packed]] A +{ + void f () const; +}; + +void +A::f () const +{ +} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-20.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-20.C new file mode 100644 index 0000000..f989ab2 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-20.C @@ -0,0 +1,22 @@ +// { dg-do compile { target c++11 } } +// { dg-options "-g" } +// Origin: <jan at etpmod dot phys dot tue dot nl> +// PR c++/19508: avoid attributes for template parameters + +template <typename T> +struct BVector +{ + typedef T T2; + typedef T value_type [[gnu::aligned(8)]]; // { dg-bogus "attribute" "attribute" } + typedef T2 value_type2 [[gnu::aligned(8)]]; // { dg-bogus "attribute" "attribute" } + value_type v; +}; +BVector<int> m; + +template <template <class> class T> +struct BV2 +{ + typedef T<float> value_type [[gnu::aligned(8)]]; // { dg-bogus "attribute" "attribute" } + value_type v; +}; +BV2<BVector> m2; diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-21.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-21.C new file mode 100644 index 0000000..2d5ad04 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-21.C @@ -0,0 +1,21 @@ +// PR c++/20763 +// { dg-do compile { target c++11 } } + +typedef void *voidp; + +struct S +{ + char a; + voidp b [[gnu::aligned (16)]]; +}; + +struct T +{ + char a; + void * b [[gnu::aligned (16)]]; +}; + +static_assert (sizeof (S) == sizeof (T), + "struct S and T should have the same size"); + +static_assert (sizeof (S) == 32, "sizeof (S) == 8 + 16 + 8"); diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-22.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-22.C new file mode 100644 index 0000000..4c07df9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-22.C @@ -0,0 +1,7 @@ +// PR c++/27648 +// { dg-do compile { target c++11 } } + +void f() +{ + static_cast<float *[[gnu::unused]]>(0); // { dg-warning "ignored" } +} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-23.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-23.C new file mode 100644 index 0000000..57ea6b8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-23.C @@ -0,0 +1,11 @@ +// PR c++/28112 +// { dg-do compile { target c++11 } } + +int i [[gnu::init_priority(;)]]; // { dg-error "before" } +int j [[gnu::vector_size(;)]]; // { dg-error "before" } +int k [[gnu::visibility(;)]]; // { dg-error "before" } +struct A {} [[gnu::aligned(;)]]; // { dg-error "before" } +struct B {} [[gnu::mode(;)]]; // { dg-error "before" } +void foo() [[gnu::alias(;)]]; // { dg-error "before" } +void bar() [[gnu::nonnull(;)]]; // { dg-error "before" } +void baz() [[gnu::section(;)]]; // { dg-error "before" } diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-24.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-24.C new file mode 100644 index 0000000..e1f26c3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-24.C @@ -0,0 +1,4 @@ +// PR c++/28387 +// { dg-do compile { target c++11 } } + +enum [[gnu::unused]] E; // { dg-error "without previous declaration" } diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-25.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-25.C new file mode 100644 index 0000000..09486d6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-25.C @@ -0,0 +1,12 @@ +// PR c++/28559 +// { dg-do compile { target c++11 } } + +template<typename T> struct A +{ + struct B; +}; + +struct C +{ + template<typename T> friend struct [[gnu::packed]] A<T>::B; // { dg-warning "uninstantiated" } +}; diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-26.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-26.C new file mode 100644 index 0000000..00069b8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-26.C @@ -0,0 +1,15 @@ +// PR c++/28659 +// The attribute was causing us to get confused in merge_types when +// combining the template type with an uninstantiated version. +// { dg-do compile { target c++11 } } + +template<class T> +struct [[gnu::aligned(1)]] A +{ + A& operator=(const A &t); +}; + +template<class T> +A<T>& A<T>::operator=(const A<T> &t) +{ +} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-27.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-27.C new file mode 100644 index 0000000..e38d8d3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-27.C @@ -0,0 +1,6 @@ +//PR c++/29980 +// { dg-do compile { target c++11 } } + +struct A { typedef int X; }; // { dg-message "previous declaration" } + +struct [[gnu::unused]] A::X; // { dg-error "typedef-name" } diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-28.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-28.C new file mode 100644 index 0000000..94f1756 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-28.C @@ -0,0 +1,13 @@ +// PR c++/28558 +// { dg-options "" } +// { dg-do compile { target c++11 } } + +struct A +{ + A(int) { } +}; + +int main() +{ + A a = (A [[gnu::unused]])0; // { dg-warning "attribute" } +} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-29.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-29.C new file mode 100644 index 0000000..f3da452 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-29.C @@ -0,0 +1,10 @@ +// PR c++/33506 +// { dg-do compile { target c++11 } } + +extern int f1 [[gnu::warn_unused_result]] (char *) ; +extern int f2 [[gnu::warn_unused_result]] (char *) throw () ; +extern int f2 (char *) throw (); + +extern int f3 [[gnu::nonnull (1)]] (char *) ; +extern int f4 [[gnu::nonnull (1)]] (char *) throw (); +extern int f4 (char *) throw (); diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-3.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-3.C new file mode 100644 index 0000000..edd1067 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-3.C @@ -0,0 +1,22 @@ +// Test that attributes work in a variety of situations. +// { dg-options "-O -ftrack-macro-expansion=0" } +// { dg-do run { target c++11 } } + +#define attrib [[gnu::mode (QI)]] +#define gnu_attrib __attribute((mode (QI))) + +attrib signed int a; +static unsigned int b attrib; + +int foo(attrib int o) +{ + return (sizeof (a) != 1 + || sizeof (b) != 1 + || sizeof (o) != 1 + || sizeof ((gnu_attrib signed int) b) != 1); +} + +int main () +{ + return foo (42); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-30.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-30.C new file mode 100644 index 0000000..537dec5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-30.C @@ -0,0 +1,9 @@ +// { dg-do compile { target c++11 } } +// PR c++/35074 + +template<typename T> struct A +{ + void foo() const; +} [[gnu::aligned(4)]]; // { dg-warning "ignored" } + +template<typename T> void A<T>::foo() const {} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-31.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-31.C new file mode 100644 index 0000000..ab58e6e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-31.C @@ -0,0 +1,16 @@ +// PR c++/35097 +// { dg-do compile { target c++11 } } + +template<int> struct A; + +template<> struct A<0> +{ + typedef int X [[gnu::aligned(4)]]; +}; + +template<typename T> void foo(const A<0>::X&, T); + +void bar() +{ + foo(A<0>::X(), 0); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-32.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-32.C new file mode 100644 index 0000000..f344661 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-32.C @@ -0,0 +1,37 @@ +// PR c++/35315 +// { dg-do compile { target c++11 } } + +typedef union { int i; } U [[gnu::transparent_union]]; // { dg-warning "ignored" } + +static void foo(U) {} +static void foo(int) {} + +void bar() +{ + foo(0); +} + +typedef union U1 { int i; } U2 [[gnu::transparent_union]]; // { dg-warning "ignored" } + +static void foo2(U1) {} // { dg-error "previously defined" } +static void foo2(U2) {} // { dg-error "redefinition" } + +void bar2(U1 u1, U2 u2) +{ + foo2(u1); + foo2(u2); +} + +// PR c++/36410 +struct A +{ + typedef union [[gnu::transparent_union]] + { + int i; + } B; +}; + +void foo(A::B b) +{ + b.i; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-33.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-33.C new file mode 100644 index 0000000..efb2a1a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-33.C @@ -0,0 +1,19 @@ +// PR c++/35546 +// { dg-do compile { target c++11 } } +// { dg-options "-g" } + +template <int N> +struct T +{ + void foo [[gnu::format (printf,2,3)]] (char const * ...); +}; + +template struct T<3>; + +template <typename T> +struct U +{ + typedef T V [[gnu::mode (SI)]]; +}; + +U<int>::V v; diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-34.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-34.C new file mode 100644 index 0000000..ae8e990 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-34.C @@ -0,0 +1,19 @@ +// PR c/37171 +// { dg-do compile { target c++11 } } +// { dg-options "-O2 -fdump-tree-optimized" } + +unsigned int f1 [[gnu::const]] (); +unsigned int f2 [[gnu::__const]] () ; +unsigned int f3 [[gnu::__const__]] () ; + +unsigned int f4 () +{ + return f1 () + f1 () + f1 () + f1 () + + f2 () + f2 () + f2 () + f2 () + + f3 () + f3 () + f3 () + f3 (); +} + +// { dg-final { scan-tree-dump-times "= f1 \\(\\)" 1 "optimized" } } +// { dg-final { scan-tree-dump-times "= f2 \\(\\)" 1 "optimized" } } +// { dg-final { scan-tree-dump-times "= f3 \\(\\)" 1 "optimized" } } +// { dg-final { cleanup-tree-dump "optimized" } } diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-35.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-35.C new file mode 100644 index 0000000..34f20cf --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-35.C @@ -0,0 +1,20 @@ +// { dg-do compile { target i?86-*-* x86_64-*-* } } +// { dg-options "-O3 -msse2 -std=c++11" } +// { dg-require-effective-target sse2 } + +// You can make NON-template typedefs with a large alignment. +typedef double AlignedDoubleType [[gnu::aligned(16)]]; + +template <typename RealType> +RealType f(const RealType* p) +{ + // But if you use a template parameter it complains. + typedef RealType AlignedRealType [[gnu::aligned(16)]]; + + return p[0]; +} + +double f2(const double* p) +{ + return f<double>(p); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-36-1.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-36-1.C new file mode 100644 index 0000000..2aae9ca --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-36-1.C @@ -0,0 +1,11 @@ +// { dg-do compile { target c++11 } } + +struct S; + +typedef int (*F [[gnu::warn_unused_result]]) (int); + +typedef int (*F2 [[gnu::warn_unused_result]]) (int); + +typedef int (S::*F3 [[gnu::warn_unused_result]]) (int); // { dg-warning "only applies to function types" } + +typedef int [[gnu::warn_unused_result]] (*F5) (int); // { dg-warning "ignored" } diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-36.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-36.C new file mode 100644 index 0000000..2665188 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-36.C @@ -0,0 +1,23 @@ +// PR c++/43031 +// { dg-options "-std=c++11 -pedantic" } +// { dg-do compile { target { { i?86-*-* x86_64-*-* } && ia32 } } } + +class T; +class L { }; +class P : public L +{ + typedef void (T::* [[gnu::__stdcall__]] F2) (L*); // { dg-warning "only applies to function types" } + typedef void (T::*F) (L*) [[gnu::__stdcall__]]; + void f(bool aAdd); +}; + +class T +{ +public: + virtual void A(L *listener) [[gnu::__stdcall__]] = 0; + virtual void R(L *listener) [[gnu::__stdcall__]] = 0; +}; +void P::f(bool aAdd) +{ + F addRemoveEventListener = (aAdd ? &T::A : &T::R); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-37.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-37.C new file mode 100644 index 0000000..15d69e8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-37.C @@ -0,0 +1,15 @@ +// PR c++/43093 +// { dg-options "-std=c++11 -pedantic" } +// { dg-do compile { target { { i?86-*-* x86_64-*-* } && ia32 } } } + +struct S { + int x; + S(const S &s) {} +}; + +S getS() [[gnu::__stdcall__]]; + +void test() +{ + S s = getS(); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-38.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-38.C new file mode 100644 index 0000000..3db981a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-38.C @@ -0,0 +1,12 @@ +// { dg-do compile { target c++11 } } +// PR c++/36625 + +template <int N> +struct A { + struct S { short f[3]; } [[gnu::aligned (N)]]; // { dg-warning "ignored" } +}; + +int main () +{ + A<4>::S s; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-39-1.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-39-1.C new file mode 100644 index 0000000..453fc01 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-39-1.C @@ -0,0 +1,10 @@ +// { dg-do compile { target c++11 } } + +int fragile_block(void) { + typedef + [[gnu::aligned (16)]] // { dg-warning "ignored" } + struct { + int i; + } XmmUint16; + return 0; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-39.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-39.C new file mode 100644 index 0000000..83fa8b5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-39.C @@ -0,0 +1,10 @@ +// PR debug/43370 +// { dg-do compile { target c++11 } } +// { dg-options "-g" } + +int fragile_block(void) { + typedef struct [[gnu::aligned (16)]] { + int i; + } XmmUint16; + return 0; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-4.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-4.C new file mode 100644 index 0000000..bad33d6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-4.C @@ -0,0 +1,30 @@ +// { dg-options "-std=c++11 -Wunused -pedantic-errors" } +// { dg-do compile } +// Test for syntax support of various attribute permutations. + +int +[[gnu::noreturn]] // { dg-warning "ignored" } +one +[[gnu::unused]] +(void); + +int one_third [[gnu::noreturn]] [[gnu::unused]] (void); + +int [[gnu::unused]] one_half(); // { dg-warning "ignored" } + +static +[[gnu::noreturn]] // { dg-warning "ignored" } +void two [[gnu::unused]] (void) {} + + + +[[gnu::unused]] +int +five(void) +[[gnu::noreturn]] // { dg-warning "ignored" } +{} + +[[gnu::noreturn]] +void +six (void) +; diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-40.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-40.C new file mode 100644 index 0000000..f3ccb72 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-40.C @@ -0,0 +1,5 @@ +// PR c++/46803 +// { dg-do compile { target c++11 } } + +int strftime(char *, int, const char *, const struct tm *) + [[gnu::__bounded__(__string__,1,2)]]; // { dg-warning "ignored" } diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-41.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-41.C new file mode 100644 index 0000000..6e47a1e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-41.C @@ -0,0 +1,20 @@ +// PR c++/45267 +// { dg-do compile { target c++11 } } +// { dg-options "-O" } + +template<typename T> struct Vector { + Vector(long long x); + inline Vector<T> operator<< [[gnu::always_inline]] (int x) const; +}; +long long bar (long long); +template<> inline Vector<int> Vector<int>::operator<<(int x) const { + return bar(x); +} +bool b; +int main() { + Vector<int> a(1); + if ((a << 2), b) { + a << 2; + throw 1; + } +} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-42.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-42.C new file mode 100644 index 0000000..7df63cf --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-42.C @@ -0,0 +1,13 @@ +// { dg-options "-std=c++11 -pedantic" } +// { dg-do compile { target { i?86-*-* && ilp32 } } } + +struct A { + [[gnu::fastcall]] + void f(); +}; + +int main() +{ + typedef void (A::*FP)(); + FP fp[] = {&A::f}; // { dg-error "cannot convert" } +} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-43.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-43.C new file mode 100644 index 0000000..c850622 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-43.C @@ -0,0 +1,4 @@ +// { dg-do compile { target c++11 } } +template <class T> struct A { }; + +template [[gnu::packed]] struct A<int>; // { dg-warning "ignored in explicit instantiation" } diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-44.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-44.C new file mode 100644 index 0000000..81d70e5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-44.C @@ -0,0 +1,3 @@ +// PR c++/52671 +// { dg-do compile { target c++11 } } +[[gnu::deprecated]] enum E { E0 }; // { dg-warning "ignored in declaration" } diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-45.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-45.C new file mode 100644 index 0000000..573a1ab --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-45.C @@ -0,0 +1,4 @@ +// PR c++/52906 +// { dg-do compile { target c++11 } } + +[[gnu::deprecated]]; // { dg-error "does not declare anything" } diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-46.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-46.C new file mode 100644 index 0000000..53fcb77 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-46.C @@ -0,0 +1,5 @@ +// PR c++/40821 +// { dg-do compile { target c++11 } } + +struct [[gnu::aligned(8)] S1 { int i; }; // { dg-error "" } +struct [aligned(8) S2 { int i; }; // { dg-error "" } diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-47-1.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-47-1.C new file mode 100644 index 0000000..4a5d73a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-47-1.C @@ -0,0 +1,8 @@ +// { dg-do compile { target c++11 } } +int +foo () +{ + int i [[and, bitor, xor_eq, compl, bitand]]; // { dg-warning "ignored" } + i = 0; + return i; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-47.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-47.C new file mode 100644 index 0000000..af74abd --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-47.C @@ -0,0 +1,13 @@ +// { dg-do compile { target c++11 } } +// Example taken from dcl.attr.grammar: + +int p[10]; +void f() +{ + int x = 42, y[5]; + /* Here, the '[[' should have introduced an attribute, on a + lambda invocation an array subscripting expression. */ + int(p[[x] { return x; }()]); // { dg-error "expected|consecutive" } + /* Likewise, the '[[gnu::' is invalid here. */ + y[[] { return 2; }()] = 2; // { dg-error "expected|consecutive" } +} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-48.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-48.C new file mode 100644 index 0000000..360c093 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-48.C @@ -0,0 +1,17 @@ +// { dg-do compile { target c++11 } } + +typedef char layout_type; + +struct A { + layout_type member alignas (double); +}; + +static_assert (alignof (A) == alignof (double), + "alignment of struct A must be alignof (double)"); + +struct alignas (alignof (long double)) B { + layout_type member; +}; + +static_assert (alignof (B) == alignof (long double), + "alignment of struct A must be alignof (double double)"); diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-49.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-49.C new file mode 100644 index 0000000..8b68f92 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-49.C @@ -0,0 +1,17 @@ +// { dg-do compile { target c++11 } } + +typedef char layout_type; + +template<class> struct A { + layout_type member alignas (double); +}; + +static_assert (alignof (A<int>) == alignof (double), + "alignment of struct A must be alignof (double)"); + +template<class> struct alignas (alignof (long double)) B { + layout_type member; +}; + +static_assert (alignof (B<int>) == alignof (long double), + "alignment of struct A must be alignof (double double)"); diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-5.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-5.C new file mode 100644 index 0000000..83de121 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-5.C @@ -0,0 +1,23 @@ +// { dg-do compile { target c++11 } } +// +// There were two related problems here, depending on the vintage. At +// one time: +// +// typedef struct A { ... } A [[gnu::aligned (16)]]; +// +// would cause original_types to go into an infinite loop. At other +// times, the attributes applied to an explicit typedef would be lost +// (check_b3 would have a negative size). + +// First check that the declaration is accepted and has an effect. +typedef struct A { int i; } A [[gnu::aligned (16)]]; +int check_A[alignof (A) >= 16 ? 1 : -1]; + +// Check that the alignment is only applied to the typedef. +struct B { int i; }; +struct B b1; +typedef struct B B [[gnu::aligned (16)]]; +struct B b2; +B b3; +int check_b1[__alignof__ (b1) == __alignof__ (b2) ? 1 : -1]; +int check_b3[__alignof__ (b3) >= 16 ? 1 : -1]; diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-50.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-50.C new file mode 100644 index 0000000..2479dfd --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-50.C @@ -0,0 +1,22 @@ +// { dg-do compile { target c++11 } } + +typedef char layout_type; + +template<class> struct A { + layout_type member alignas (double) alignas (int); +}; + +// Here, the spec says that A<int> should have the stricter alignment, +// so that would be the alignment of 'double', not 'int'. +static_assert (alignof (A<int>) == alignof (double), + "alignment of struct A must be alignof (double)"); + +template<class> struct alignas (1) alignas (alignof (long double)) B { + layout_type member; +}; + +// Similarly, the B<int> should have the stricter alignment, so that would +// so that would be the alignment of 'long double', not '1'. +static_assert (alignof (B<int>) == alignof (long double), + "alignment of struct A must be alignof (double double)"); + diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-51.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-51.C new file mode 100644 index 0000000..f2b6602 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-51.C @@ -0,0 +1,9 @@ +// { dg-do compile { target c++11 } } + +typedef char layout_type; +struct A +{ + layout_type member [[gnu::aligned (16)]]; +}; + +static_assert (sizeof (A) == 16, "Alignment should be 16"); diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-52.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-52.C new file mode 100644 index 0000000..0f87fd4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-52.C @@ -0,0 +1,21 @@ +// { dg-do compile { target c++11 } } + +struct A {int i;} a [[gnu::aligned(16)]]; +struct B {int i;} __attribute__((aligned(16))) b; + +int +main () +{ + A aa; + B bb; + + static_assert (sizeof (a) == 4, "sizeof (a) should be 4"); + static_assert (sizeof (b) == 16, "sizeof (b) should be 16"); + static_assert (sizeof (aa) == 4, "sizeof (aa) should be 4"); + static_assert (sizeof (bb) == 16, "sizeof (bb) should be 16"); + + static_assert (__alignof__ (a) == 16, "alignof (a) should be 16"); + static_assert (__alignof__ (b) == 16, "alignof (b) should be 16"); + static_assert (__alignof__ (aa) == 4, "alignof (aa) should be 4"); + static_assert (__alignof__ (bb) == 16, "alignof (bb) should be 16"); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-53.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-53.C new file mode 100644 index 0000000..723c8ef --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-53.C @@ -0,0 +1,39 @@ +// { dg-do compile { target c++11 } } + +int +toto () +{ + [[gnu::unused]] good: + return 0; +} + +int +foo () +{ + [[gnu::unused]] good: + int i = 0; + + // A C++11 attribute at the beginning of the return statement is + // syntactically correct, appertains to the return statement (not to + // the label) but is currently ignored by this implementation. + good_ignored : [[gnu::unused]] // { dg-warning "attributes at the beginning of statement are ignored" } + return i; +} + +int +bar () +{ + // A GNU attribute after the label appertains to the label. + good: __attribute__((unused)); + return 0; +} + +int +baz () +{ + // The c++ attribute after the label appertains to the (empty) + // statement. + bad: [[gnu::unused]]; // { dg-warning "attributes at the beginning of statement are ignored" } + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-6.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-6.C new file mode 100644 index 0000000..54071d5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-6.C @@ -0,0 +1,20 @@ +// Copyright (C) 2002 Free Software Foundation. +// +// Test that the nothrow attribute is working correctly. +// +// Written by Richard Henderson, 26 May 2002. + +// { dg-do link { target c++11} } +extern void foo [[gnu::nothrow]] (); +extern void link_error(); + +int main() +{ + try { + foo(); + } catch (...) { + link_error(); + } +} + +void foo() { } diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-7.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-7.C new file mode 100644 index 0000000..3341250 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-7.C @@ -0,0 +1,4 @@ +// { dg-do compile { target c++11 } } +// { dg-options "-Wunused-parameter" } + +void f (int i [[gnu::__unused__]]) {} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-8.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-8.C new file mode 100644 index 0000000..a842b53 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-8.C @@ -0,0 +1,6 @@ +// { dg-options "-std=c++11 -pedantic" } +// { dg-do compile { target { { i?86-*-* x86_64-*-* } && ia32 } } } + +extern int * ([[gnu::stdcall]] *fooPtr)( void); // { dg-error "expected" } +int * [[gnu::stdcall]] myFn01( void) { return 0; }// { dg-warning "attribute only applies to function types" } + diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-9.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-9.C new file mode 100644 index 0000000..3dc51ee --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-9.C @@ -0,0 +1,12 @@ +// { dg-do compile { target c++11 } } + +class C; +struct S; +union U; +enum e {}; +enum [[gnu::unused]] e; // { dg-warning "already defined" } + +struct [[gnu::unused]] B *p; // { dg-warning "attributes" } + +template <class T> struct A { }; +struct [[gnu::unused]] A<int>; // { dg-warning "attributes" } @@ -4350,7 +4350,7 @@ comp_type_attributes (const_tree type1, const_tree type2) const struct attribute_spec *as; const_tree attr; - as = lookup_attribute_spec (TREE_PURPOSE (a)); + as = lookup_attribute_spec (get_attribute_name (a)); if (!as || as->affects_type_identity == false) continue; @@ -4364,7 +4364,7 @@ comp_type_attributes (const_tree type1, const_tree type2) { const struct attribute_spec *as; - as = lookup_attribute_spec (TREE_PURPOSE (a)); + as = lookup_attribute_spec (get_attribute_name (a)); if (!as || as->affects_type_identity == false) continue; @@ -5287,11 +5287,12 @@ private_lookup_attribute (const char *attr_name, size_t attr_len, tree list) { while (list) { - size_t ident_len = IDENTIFIER_LENGTH (TREE_PURPOSE (list)); + size_t ident_len = IDENTIFIER_LENGTH (get_attribute_name (list)); if (ident_len == attr_len) { - if (strcmp (attr_name, IDENTIFIER_POINTER (TREE_PURPOSE (list))) == 0) + if (!strcmp (attr_name, + IDENTIFIER_POINTER (get_attribute_name (list)))) break; } /* TODO: If we made sure that attributes were stored in the @@ -5299,7 +5300,7 @@ private_lookup_attribute (const char *attr_name, size_t attr_len, tree list) to '__text__') then we could avoid the following case. */ else if (ident_len == attr_len + 4) { - const char *p = IDENTIFIER_POINTER (TREE_PURPOSE (list)); + const char *p = IDENTIFIER_POINTER (get_attribute_name (list)); if (p[0] == '_' && p[1] == '_' && p[ident_len - 2] == '_' && p[ident_len - 1] == '_' && strncmp (attr_name, p + 2, attr_len) == 0) @@ -5329,10 +5330,11 @@ lookup_ident_attribute (tree attr_identifier, tree list) while (list) { - gcc_checking_assert (TREE_CODE (TREE_PURPOSE (list)) == IDENTIFIER_NODE); + gcc_checking_assert (TREE_CODE (get_attribute_name (list)) + == IDENTIFIER_NODE); /* Identifiers can be compared directly for equality. */ - if (attr_identifier == TREE_PURPOSE (list)) + if (attr_identifier == get_attribute_name (list)) break; /* If they are not equal, they may still be one in the form @@ -5342,11 +5344,11 @@ lookup_ident_attribute (tree attr_identifier, tree list) the fact that we're comparing identifiers. :-) */ { size_t attr_len = IDENTIFIER_LENGTH (attr_identifier); - size_t ident_len = IDENTIFIER_LENGTH (TREE_PURPOSE (list)); + size_t ident_len = IDENTIFIER_LENGTH (get_attribute_name (list)); if (ident_len == attr_len + 4) { - const char *p = IDENTIFIER_POINTER (TREE_PURPOSE (list)); + const char *p = IDENTIFIER_POINTER (get_attribute_name (list)); const char *q = IDENTIFIER_POINTER (attr_identifier); if (p[0] == '_' && p[1] == '_' && p[ident_len - 2] == '_' && p[ident_len - 1] == '_' @@ -5355,7 +5357,7 @@ lookup_ident_attribute (tree attr_identifier, tree list) } else if (ident_len + 4 == attr_len) { - const char *p = IDENTIFIER_POINTER (TREE_PURPOSE (list)); + const char *p = IDENTIFIER_POINTER (get_attribute_name (list)); const char *q = IDENTIFIER_POINTER (attr_identifier); if (q[0] == '_' && q[1] == '_' && q[attr_len - 2] == '_' && q[attr_len - 1] == '_' @@ -5385,7 +5387,7 @@ remove_attribute (const char *attr_name, tree list) tree l = *p; /* TODO: If we were storing attributes in normalized form, here we could use a simple strcmp(). */ - if (private_is_attribute_p (attr_name, attr_len, TREE_PURPOSE (l))) + if (private_is_attribute_p (attr_name, attr_len, get_attribute_name (l))) *p = TREE_CHAIN (l); else p = &TREE_CHAIN (l); @@ -5422,9 +5424,11 @@ merge_attributes (tree a1, tree a2) for (; a2 != 0; a2 = TREE_CHAIN (a2)) { tree a; - for (a = lookup_ident_attribute (TREE_PURPOSE (a2), attributes); + for (a = lookup_ident_attribute (get_attribute_name (a2), + attributes); a != NULL_TREE && !attribute_value_equal (a, a2); - a = lookup_ident_attribute (TREE_PURPOSE (a2), TREE_CHAIN (a))) + a = lookup_ident_attribute (get_attribute_name (a2), + TREE_CHAIN (a))) ; if (a == NULL_TREE) { @@ -6346,7 +6350,7 @@ attribute_hash_list (const_tree list, hashval_t hashcode) for (tail = list; tail; tail = TREE_CHAIN (tail)) /* ??? Do we want to add in TREE_VALUE too? */ hashcode = iterative_hash_object - (IDENTIFIER_HASH_VALUE (TREE_PURPOSE (tail)), hashcode); + (IDENTIFIER_HASH_VALUE (get_attribute_name (tail)), hashcode); return hashcode; } @@ -6383,7 +6387,7 @@ attribute_list_contained (const_tree l1, const_tree l2) /* Maybe the lists are similar. */ for (t1 = l1, t2 = l2; t1 != 0 && t2 != 0 - && TREE_PURPOSE (t1) == TREE_PURPOSE (t2) + && get_attribute_name (t1) == get_attribute_name (t2) && TREE_VALUE (t1) == TREE_VALUE (t2); t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2)) ; @@ -6398,9 +6402,9 @@ attribute_list_contained (const_tree l1, const_tree l2) /* This CONST_CAST is okay because lookup_attribute does not modify its argument and the return value is assigned to a const_tree. */ - for (attr = lookup_ident_attribute (TREE_PURPOSE (t2), CONST_CAST_TREE(l1)); + for (attr = lookup_ident_attribute (get_attribute_name (t2), CONST_CAST_TREE(l1)); attr != NULL_TREE && !attribute_value_equal (t2, attr); - attr = lookup_ident_attribute (TREE_PURPOSE (t2), TREE_CHAIN (attr))) + attr = lookup_ident_attribute (get_attribute_name (t2), TREE_CHAIN (attr))) ; if (attr == NULL_TREE) @@ -4903,12 +4903,12 @@ struct attribute_spec { /* The name of the attribute (without any leading or trailing __), or NULL to mark the end of a table of attributes. */ - const char *const name; + const char *name; /* The minimum length of the list of arguments of the attribute. */ - const int min_length; + int min_length; /* The maximum length of the list of arguments of the attribute (-1 for no maximum). */ - const int max_length; + int max_length; /* Whether this attribute requires a DECL. If it does, it will be passed from types of DECLs, function return types and array element types to the DECLs, function types and array types respectively; but when @@ -4916,15 +4916,15 @@ struct attribute_spec a warning. (If greater control is desired for a given attribute, this should be false, and the flags argument to the handler may be used to gain greater control in that case.) */ - const bool decl_required; + bool decl_required; /* Whether this attribute requires a type. If it does, it will be passed from a DECL to the type of that DECL. */ - const bool type_required; + bool type_required; /* Whether this attribute requires a function (or method) type. If it does, it will be passed from a function pointer type to the target type, and from a function return type (which is not itself a function pointer type) to the function type. */ - const bool function_type_required; + bool function_type_required; /* Function to handle this attribute. NODE points to the node to which the attribute is to be applied. If a DECL, it should be modified in place; if a TYPE, a copy should be created. NAME is the name of the @@ -4939,10 +4939,10 @@ struct attribute_spec otherwise the return value should be NULL_TREE. This pointer may be NULL if no special handling is required beyond the checks implied by the rest of this structure. */ - tree (*const handler) (tree *node, tree name, tree args, - int flags, bool *no_add_attrs); + tree (*handler) (tree *node, tree name, tree args, + int flags, bool *no_add_attrs); /* Specifies if attribute affects type's identity. */ - const bool affects_type_identity; + bool affects_type_identity; }; /* Flags that may be passed in the third argument of decl_attributes, and @@ -4967,7 +4967,9 @@ enum attribute_flags /* The attributes are being applied by default to a library function whose name indicates known behavior, and should be silently ignored if they are not in fact compatible with the function type. */ - ATTR_FLAG_BUILT_IN = 16 + ATTR_FLAG_BUILT_IN = 16, + /* A given attribute has been parsed as a C++-11 attribute. */ + ATTR_FLAG_CXX11 = 32 }; /* Default versions of target-overridable functions. */ @@ -6054,6 +6056,8 @@ extern bool must_pass_in_stack_var_size_or_pad (enum machine_mode, const_tree); /* In attribs.c. */ extern const struct attribute_spec *lookup_attribute_spec (const_tree); +extern const struct attribute_spec *lookup_scoped_attribute_spec (const_tree, + const_tree); extern void init_attributes (void); @@ -6067,6 +6071,12 @@ extern void init_attributes (void); a decl attribute to the declaration rather than to its type). */ extern tree decl_attributes (tree *, tree, int); +extern bool cxx11_attribute_p (const_tree); + +extern tree get_attribute_name (const_tree); + +extern tree get_attribute_namespace (const_tree); + extern void apply_tm_attr (tree, tree); /* In stor-layout.c */ |