aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDodji Seketeli <dodji@redhat.com>2012-10-08 09:29:05 +0000
committerDodji Seketeli <dodji@gcc.gnu.org>2012-10-08 11:29:05 +0200
commite28d52cffbb2abc7a5764ed4c97a25c376913fee (patch)
tree1a1442f932577112e42d0c3a2bb905d3ce01d5de
parentf70308d411efebfce8f15b54fedd21c17d44740c (diff)
downloadgcc-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
-rw-r--r--gcc/ChangeLog32
-rw-r--r--gcc/attribs.c229
-rw-r--r--gcc/c-family/ChangeLog12
-rw-r--r--gcc/c-family/c-common.c120
-rw-r--r--gcc/c-family/c-common.h1
-rw-r--r--gcc/cp/ChangeLog79
-rw-r--r--gcc/cp/cp-tree.h20
-rw-r--r--gcc/cp/decl.c85
-rw-r--r--gcc/cp/decl2.c2
-rw-r--r--gcc/cp/error.c5
-rw-r--r--gcc/cp/parser.c660
-rw-r--r--gcc/cp/typeck.c50
-rw-r--r--gcc/plugin.h3
-rw-r--r--gcc/testsuite/ChangeLog61
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-1.C3
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-10.C9
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-11.C17
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-12.C17
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-13.C5
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-14.C14
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-15.C9
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-16.C8
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-17.2.C19
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-17.C19
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-18.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-19.C11
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-2-1.C3
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-2.C11
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-20.C22
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-21.C21
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-22.C7
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-23.C11
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-24.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-25.C12
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-26.C15
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-27.C6
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-28.C13
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-29.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-3.C22
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-30.C9
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-31.C16
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-32.C37
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-33.C19
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-34.C19
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-35.C20
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-36-1.C11
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-36.C23
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-37.C15
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-38.C12
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-39-1.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-39.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-4.C30
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-40.C5
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-41.C20
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-42.C13
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-43.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-44.C3
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-45.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-46.C5
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-47-1.C8
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-47.C13
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-48.C17
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-49.C17
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-5.C23
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-50.C22
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-51.C9
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-52.C21
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-53.C39
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-6.C20
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-7.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-8.C6
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/gen-attrs-9.C12
-rw-r--r--gcc/tree.c38
-rw-r--r--gcc/tree.h30
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" }
diff --git a/gcc/tree.c b/gcc/tree.c
index 7f620e5..8df1b86 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -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)
diff --git a/gcc/tree.h b/gcc/tree.h
index ff4ae52..e7cef18 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -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 */