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
This commit is contained in:
Dodji Seketeli 2012-10-08 09:29:05 +00:00 committed by Dodji Seketeli
parent f70308d411
commit e28d52cffb
74 changed files with 2089 additions and 142 deletions

View File

@ -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> 2012-10-08 Georg-Johann Lay <avr@gjlay.de>
PR target/54815 PR target/54815

View File

@ -38,9 +38,6 @@ along with GCC; see the file COPYING3. If not see
searched. */ searched. */
static const struct attribute_spec *attribute_tables[4]; static const struct attribute_spec *attribute_tables[4];
/* Hashtable mapping names (represented as substrings) to attribute specs. */
static htab_t attribute_hash;
/* Substring representation. */ /* Substring representation. */
struct substring struct substring
@ -49,6 +46,28 @@ struct substring
int length; 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; static bool attributes_initialized = false;
/* Default empty table of attributes. */ /* 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]); 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 /* Initialize attribute tables, and make some sanity checks
if --enable-checking. */ if --enable-checking. */
@ -109,7 +186,6 @@ void
init_attributes (void) init_attributes (void)
{ {
size_t i; size_t i;
int k;
if (attributes_initialized) if (attributes_initialized)
return; return;
@ -181,12 +257,10 @@ init_attributes (void)
} }
#endif #endif
attribute_hash = htab_create (200, hash_attr, eq_attr, NULL); for (i = 0; i < ARRAY_SIZE (attribute_tables); ++i)
for (i = 0; i < ARRAY_SIZE (attribute_tables); i++) /* Put all the GNU attributes into the "gnu" namespace. */
for (k = 0; attribute_tables[i][k].name != NULL; k++) register_scoped_attributes (attribute_tables[i], "gnu");
{
register_attribute (&attribute_tables[i][k]);
}
invoke_plugin_callbacks (PLUGIN_ATTRIBUTES, NULL); invoke_plugin_callbacks (PLUGIN_ATTRIBUTES, NULL);
attributes_initialized = true; attributes_initialized = true;
} }
@ -195,10 +269,24 @@ init_attributes (void)
void void
register_attribute (const struct attribute_spec *attr) 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; struct substring str;
void **slot; 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.str = attr->name;
str.length = strlen (str.str); str.length = strlen (str.str);
@ -206,27 +294,45 @@ register_attribute (const struct attribute_spec *attr)
in the form '__text__'. */ in the form '__text__'. */
gcc_assert (str.length > 0 && str.str[0] != '_'); 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), substring_hash (str.str, str.length),
INSERT); INSERT);
gcc_assert (!*slot || attr->name[0] == '*'); gcc_assert (!*slot || attr->name[0] == '*');
*slot = (void *) CONST_CAST (struct attribute_spec *, attr); *slot = (void *) CONST_CAST (struct attribute_spec *, attr);
} }
/* Return the spec for the scoped attribute with namespace NS and
name NAME. */
const struct attribute_spec *
lookup_scoped_attribute_spec (const_tree ns, const_tree name)
{
struct substring attr;
scoped_attributes *attrs;
const char *ns_str = (ns != NULL_TREE) ? IDENTIFIER_POINTER (ns): NULL;
attrs = find_attribute_namespace (ns_str);
if (attrs == NULL)
return NULL;
attr.str = IDENTIFIER_POINTER (name);
attr.length = IDENTIFIER_LENGTH (name);
extract_attribute_substring (&attr);
return (const struct attribute_spec *)
htab_find_with_hash (attrs->attribute_hash, &attr,
substring_hash (attr.str, attr.length));
}
/* Return the spec for the attribute named NAME. */ /* Return the spec for the attribute named NAME. */
const struct attribute_spec * const struct attribute_spec *
lookup_attribute_spec (const_tree name) lookup_attribute_spec (const_tree name)
{ {
struct substring attr; return lookup_scoped_attribute_spec (get_identifier ("gnu"), name);
attr.str = IDENTIFIER_POINTER (name);
attr.length = IDENTIFIER_LENGTH (name);
extract_attribute_substring (&attr);
return (const struct attribute_spec *)
htab_find_with_hash (attribute_hash, &attr,
substring_hash (attr.str, attr.length));
} }
/* Process the attributes listed in ATTRIBUTES and install them in *NODE, /* 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, 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 a;
tree returned_attrs = NULL_TREE; 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; return NULL_TREE;
if (!attributes_initialized) if (!attributes_initialized)
@ -302,10 +408,12 @@ decl_attributes (tree *node, tree attributes, int flags)
for (a = attributes; a; a = TREE_CHAIN (a)) 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 args = TREE_VALUE (a);
tree *anode = node; 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; bool no_add_attrs = 0;
int fn_ptr_quals = 0; int fn_ptr_quals = 0;
tree fn_ptr_tmp = NULL_TREE; tree fn_ptr_tmp = NULL_TREE;
@ -313,8 +421,15 @@ decl_attributes (tree *node, tree attributes, int flags)
if (spec == NULL) if (spec == NULL)
{ {
if (!(flags & (int) ATTR_FLAG_BUILT_IN)) if (!(flags & (int) ATTR_FLAG_BUILT_IN))
{
if (ns == NULL_TREE || !cxx11_attribute_p (a))
warning (OPT_Wattributes, "%qE attribute directive ignored", warning (OPT_Wattributes, "%qE attribute directive ignored",
name); name);
else
warning (OPT_Wattributes,
"%<%E::%E%> scoped attribute directive ignored",
ns, name);
}
continue; continue;
} }
else if (list_length (args) < spec->min_length 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)); 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 (spec->decl_required && !DECL_P (*anode))
{ {
if (flags & ((int) ATTR_FLAG_DECL_NEXT if (flags & ((int) ATTR_FLAG_DECL_NEXT
@ -406,9 +535,15 @@ decl_attributes (tree *node, tree attributes, int flags)
} }
if (spec->handler != NULL) if (spec->handler != NULL)
{
int cxx11_flag =
cxx11_attribute_p (a) ? ATTR_FLAG_CXX11 : 0;
returned_attrs = chainon ((*spec->handler) (anode, name, args, returned_attrs = chainon ((*spec->handler) (anode, name, args,
flags, &no_add_attrs), flags|cxx11_flag,
&no_add_attrs),
returned_attrs); returned_attrs);
}
/* Layout the decl in case anything changed. */ /* Layout the decl in case anything changed. */
if (spec->type_required && DECL_P (*node) if (spec->type_required && DECL_P (*node)
@ -488,6 +623,56 @@ decl_attributes (tree *node, tree attributes, int flags)
return returned_attrs; 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 /* Subroutine of set_method_tm_attributes. Apply TM attribute ATTR
to the method FNDECL. */ to the method FNDECL. */

View File

@ -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> 2012-10-04 Arnaud Charlet <charlet@adacore.com>
* c-ada-spec.c (print_ada_declaration): Remove handling of TDF_RAW. * c-ada-spec.c (print_ada_declaration): Remove handling of TDF_RAW.

View File

@ -484,6 +484,7 @@ const struct c_common_resword c_common_reswords[] =
{ "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY }, { "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY },
{ "__volatile", RID_VOLATILE, 0 }, { "__volatile", RID_VOLATILE, 0 },
{ "__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 }, { "alignof", RID_ALIGNOF, D_CXXONLY | D_CXX0X | D_CXXWARN },
{ "asm", RID_ASM, D_ASM }, { "asm", RID_ASM, D_ASM },
{ "auto", RID_AUTO, 0 }, { "auto", RID_AUTO, 0 },
@ -6665,7 +6666,9 @@ handle_transparent_union_attribute (tree *node, tree name,
*no_add_attrs = true; *no_add_attrs = true;
if (TREE_CODE (*node) == TYPE_DECL)
if (TREE_CODE (*node) == TYPE_DECL
&& ! (flags & ATTR_FLAG_CXX11))
node = &TREE_TYPE (*node); node = &TREE_TYPE (*node);
type = *node; type = *node;
@ -7137,6 +7140,89 @@ check_user_alignment (const_tree align, bool allow_zero)
return i; 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 /* Handle a "aligned" attribute; arguments as in
struct attribute_spec.handler. */ struct attribute_spec.handler. */
@ -7160,7 +7246,8 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args,
else if (TYPE_P (*node)) else if (TYPE_P (*node))
type = node, is_type = 1; 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; *no_add_attrs = true;
else if (is_type) 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); error ("alignment may not be specified for %q+D", decl);
*no_add_attrs = true; *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 else if (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_ALIGN (decl) > (1U << i) * BITS_PER_UNIT) && 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" #include "gt-c-family-c-common.h"

View File

@ -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_storage_class_specifier (enum rid);
extern bool keyword_is_type_qualifier (enum rid); extern bool keyword_is_type_qualifier (enum rid);
extern bool keyword_is_decl_specifier (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_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) #define c_alignof(LOC, T) c_sizeof_or_alignof_type (LOC, T, false, 1)

View File

@ -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> 2012-10-07 Paolo Carlini <paolo.carlini@oracle.com>
* pt.c (fold_non_dependent_expr_sfinae): Remove static specifier. * pt.c (fold_non_dependent_expr_sfinae): Remove static specifier.

View File

@ -418,7 +418,9 @@ typedef enum cpp0x_warn_str
/* user defined literals */ /* user defined literals */
CPP0X_USER_DEFINED_LITERALS, CPP0X_USER_DEFINED_LITERALS,
/* delegating constructors */ /* delegating constructors */
CPP0X_DELEGATING_CTORS CPP0X_DELEGATING_CTORS,
/* C++11 attributes */
CPP0X_ATTRIBUTES
} cpp0x_warn_str; } cpp0x_warn_str;
/* The various kinds of operation used by composite_pointer_type. */ /* The various kinds of operation used by composite_pointer_type. */
@ -4684,6 +4686,7 @@ typedef enum cp_decl_spec {
ds_type_spec, ds_type_spec,
ds_redefined_builtin_type_spec, ds_redefined_builtin_type_spec,
ds_attribute, ds_attribute,
ds_std_attribute,
ds_storage_class, ds_storage_class,
ds_long_long, ds_long_long,
ds_last /* This enumerator must always be the last one. */ ds_last /* This enumerator must always be the last one. */
@ -4702,6 +4705,8 @@ typedef struct cp_decl_specifier_seq {
tree type; tree type;
/* The attributes, if any, provided with the specifier sequence. */ /* The attributes, if any, provided with the specifier sequence. */
tree attributes; 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 /* If non-NULL, a built-in type that the user attempted to redefine
to some other type. */ to some other type. */
tree redefined_builtin_type; tree redefined_builtin_type;
@ -4770,8 +4775,14 @@ struct cp_declarator {
to indicate this is a parameter pack. */ to indicate this is a parameter pack. */
BOOL_BITFIELD parameter_pack_p : 1; BOOL_BITFIELD parameter_pack_p : 1;
location_t id_loc; /* Currently only set for cdk_id and cdk_function. */ 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; 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 /* For all but cdk_id and cdk_error, the contained declarator. For
cdk_id and cdk_error, guaranteed to be NULL. */ cdk_id and cdk_error, guaranteed to be NULL. */
cp_declarator *declarator; 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_library_fn (tree, tree, tree);
extern tree push_void_library_fn (tree, tree); extern tree push_void_library_fn (tree, tree);
extern tree push_throw_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 shadow_tag (cp_decl_specifier_seq *);
extern tree groktypename (cp_decl_specifier_seq *, const cp_declarator *, bool); 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 *); 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 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_expr (tree, enum tree_code, bool);
extern tree cxx_sizeof_or_alignof_type (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 cxx_sizeof_nowarn (tree);
extern tree is_bitfield_expr_with_lowered_type (const_tree); extern tree is_bitfield_expr_with_lowered_type (const_tree);
extern tree unlowered_expr_type (const_tree); extern tree unlowered_expr_type (const_tree);

View File

@ -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. /* Make sure that a declaration with no declarator is well-formed, i.e.
just declares a tagged type or anonymous union. just declares a tagged type or anonymous union.
Returns the type declared; or NULL_TREE if none. */ Returns the type declared; or NULL_TREE if none. */
tree 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_friend = decl_spec_seq_has_spec_p (declspecs, ds_friend);
int saw_typedef = decl_spec_seq_has_spec_p (declspecs, ds_typedef); 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 /* For a template class (an explicit instantiation), use the
current location. */ current location. */
loc = input_location; loc = input_location;
warning_at (loc, OPT_Wattributes, "attribute ignored in declaration "
"of %q#T", declared_type); if (explicit_type_instantiation_p)
inform (loc, "attribute for %q#T must follow the %qs keyword", /* [dcl.attr.grammar]/4:
declared_type, class_key_or_enum_as_string (declared_type));
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; return declared_type;
@ -4272,7 +4303,8 @@ check_tag_decl (cp_decl_specifier_seq *declspecs)
tree tree
shadow_tag (cp_decl_specifier_seq *declspecs) 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) if (!t)
return NULL_TREE; 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 /* Determine the type of the entity declared by recurring on the
declarator. */ declarator. */
for (; declarator; declarator = declarator->declarator) for (; declarator; declarator = declarator->declarator)
@ -9215,6 +9256,13 @@ grokdeclarator (const cp_declarator *declarator,
case cdk_array: case cdk_array:
type = create_array_type_for_decl (dname, type, type = create_array_type_for_decl (dname, type,
declarator->u.array.bounds); 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; break;
case cdk_function: case cdk_function:
@ -9411,6 +9459,13 @@ grokdeclarator (const cp_declarator *declarator,
} }
type = build_function_type (type, arg_types); 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; break;
@ -9573,6 +9628,17 @@ grokdeclarator (const cp_declarator *declarator,
declarator->u.pointer.qualifiers); declarator->u.pointer.qualifiers);
type_quals = cp_type_quals (type); 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; ctype = NULL_TREE;
break; break;
@ -9698,6 +9764,13 @@ grokdeclarator (const cp_declarator *declarator,
attrlist = &returned_attrs; 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. */ /* Handle parameter packs. */
if (parameter_pack_p) if (parameter_pack_p)
{ {

View File

@ -1091,7 +1091,7 @@ grokbitfield (const cp_declarator *declarator,
static bool static bool
is_late_template_attribute (tree attr, tree decl) is_late_template_attribute (tree attr, tree decl)
{ {
tree name = TREE_PURPOSE (attr); tree name = get_attribute_name (attr);
tree args = TREE_VALUE (attr); tree args = TREE_VALUE (attr);
const struct attribute_spec *spec = lookup_attribute_spec (name); const struct attribute_spec *spec = lookup_attribute_spec (name);
tree arg; tree arg;

View File

@ -3374,6 +3374,11 @@ maybe_warn_cpp0x (cpp0x_warn_str str)
"delegating constructors " "delegating constructors "
"only available with -std=c++11 or -std=gnu++11"); "only available with -std=c++11 or -std=gnu++11");
break; break;
case CPP0X_ATTRIBUTES:
pedwarn (input_location, 0,
"c++11 attributes "
"only available with -std=c++11 or -std=gnu++11");
break;
default: default:
gcc_unreachable (); gcc_unreachable ();
} }

File diff suppressed because it is too large Load Diff

View File

@ -1701,6 +1701,56 @@ cxx_sizeof_or_alignof_expr (tree e, enum tree_code op, bool complain)
else else
return cxx_alignof_expr (e, complain? tf_warning_or_error : tf_none); 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. /* EXPR is being used in a context that is not a function call.
Enforce: Enforce:

View File

@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see
#include "gcc-plugin.h" #include "gcc-plugin.h"
struct attribute_spec; struct attribute_spec;
struct scoped_attributes;
extern void add_new_plugin (const char *); extern void add_new_plugin (const char *);
extern void parse_plugin_arg_opt (const char *); extern void parse_plugin_arg_opt (const char *);
@ -64,5 +65,7 @@ invoke_plugin_callbacks (int event ATTRIBUTE_UNUSED,
/* In attribs.c. */ /* In attribs.c. */
extern void register_attribute (const struct attribute_spec *attr); 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 */ #endif /* PLUGIN_H */

View File

@ -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> 2012-10-08 Eric Botcazou <ebotcazou@adacore.com>
* gcc.dg/tree-ssa/slsr-30.c: Use correct cleanup directive. * gcc.dg/tree-ssa/slsr-30.c: Use correct cleanup directive.

View File

@ -0,0 +1,3 @@
// { dg-do compile { target c++11 } }
int **** [[gnu::format(printf, 1, 2)]] foo(const char *, ...); // { dg-warning "ignored" }

View File

@ -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 ();
}

View File

@ -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>;

View File

@ -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>;

View File

@ -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 ();

View File

@ -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); }

View File

@ -0,0 +1,9 @@
// { dg-do compile { target c++11 } }
// PR c++/15317
struct A
{
A(char);
};
A::A([[gnu::unused]] char i2)
{}

View File

@ -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))]];
};

View File

@ -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" }

View File

@ -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;

View File

@ -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();
};

View File

@ -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;
}

View File

@ -0,0 +1,3 @@
// { dg-do compile { target c++11 } }
struct [[gnu::unused]] A {};

View File

@ -0,0 +1,11 @@
// { dg-do compile { target c++11 } }
struct [[gnu::packed]] A
{
void f () const;
};
void
A::f () const
{
}

View File

@ -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;

View File

@ -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");

View File

@ -0,0 +1,7 @@
// PR c++/27648
// { dg-do compile { target c++11 } }
void f()
{
static_cast<float *[[gnu::unused]]>(0); // { dg-warning "ignored" }
}

View File

@ -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" }

View File

@ -0,0 +1,4 @@
// PR c++/28387
// { dg-do compile { target c++11 } }
enum [[gnu::unused]] E; // { dg-error "without previous declaration" }

View File

@ -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" }
};

View File

@ -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)
{
}

View File

@ -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" }

View File

@ -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" }
}

View File

@ -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 ();

View File

@ -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);
}

View File

@ -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 {}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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" } }

View File

@ -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);
}

View File

@ -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" }

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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)
;

View File

@ -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" }

View File

@ -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;
}
}

View File

@ -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" }
}

View File

@ -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" }

View File

@ -0,0 +1,3 @@
// PR c++/52671
// { dg-do compile { target c++11 } }
[[gnu::deprecated]] enum E { E0 }; // { dg-warning "ignored in declaration" }

View File

@ -0,0 +1,4 @@
// PR c++/52906
// { dg-do compile { target c++11 } }
[[gnu::deprecated]]; // { dg-error "does not declare anything" }

View File

@ -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 "" }

View File

@ -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;
}

View File

@ -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" }
}

View File

@ -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)");

View File

@ -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)");

View File

@ -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];

View File

@ -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)");

View File

@ -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");

View File

@ -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");
}

View File

@ -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;
}

View File

@ -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() { }

View File

@ -0,0 +1,4 @@
// { dg-do compile { target c++11 } }
// { dg-options "-Wunused-parameter" }
void f (int i [[gnu::__unused__]]) {}

View File

@ -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" }

View File

@ -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" }

View File

@ -4350,7 +4350,7 @@ comp_type_attributes (const_tree type1, const_tree type2)
const struct attribute_spec *as; const struct attribute_spec *as;
const_tree attr; 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) if (!as || as->affects_type_identity == false)
continue; continue;
@ -4364,7 +4364,7 @@ comp_type_attributes (const_tree type1, const_tree type2)
{ {
const struct attribute_spec *as; 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) if (!as || as->affects_type_identity == false)
continue; continue;
@ -5287,11 +5287,12 @@ private_lookup_attribute (const char *attr_name, size_t attr_len, tree list)
{ {
while (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 (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; break;
} }
/* TODO: If we made sure that attributes were stored in the /* 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. */ to '__text__') then we could avoid the following case. */
else if (ident_len == attr_len + 4) 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] == '_' if (p[0] == '_' && p[1] == '_'
&& p[ident_len - 2] == '_' && p[ident_len - 1] == '_' && p[ident_len - 2] == '_' && p[ident_len - 1] == '_'
&& strncmp (attr_name, p + 2, attr_len) == 0) && strncmp (attr_name, p + 2, attr_len) == 0)
@ -5329,10 +5330,11 @@ lookup_ident_attribute (tree attr_identifier, tree list)
while (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. */ /* Identifiers can be compared directly for equality. */
if (attr_identifier == TREE_PURPOSE (list)) if (attr_identifier == get_attribute_name (list))
break; break;
/* If they are not equal, they may still be one in the form /* 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. :-) */ the fact that we're comparing identifiers. :-) */
{ {
size_t attr_len = IDENTIFIER_LENGTH (attr_identifier); 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) 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); const char *q = IDENTIFIER_POINTER (attr_identifier);
if (p[0] == '_' && p[1] == '_' if (p[0] == '_' && p[1] == '_'
&& p[ident_len - 2] == '_' && p[ident_len - 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) 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); const char *q = IDENTIFIER_POINTER (attr_identifier);
if (q[0] == '_' && q[1] == '_' if (q[0] == '_' && q[1] == '_'
&& q[attr_len - 2] == '_' && q[attr_len - 1] == '_' && q[attr_len - 2] == '_' && q[attr_len - 1] == '_'
@ -5385,7 +5387,7 @@ remove_attribute (const char *attr_name, tree list)
tree l = *p; tree l = *p;
/* TODO: If we were storing attributes in normalized form, here /* TODO: If we were storing attributes in normalized form, here
we could use a simple strcmp(). */ 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); *p = TREE_CHAIN (l);
else else
p = &TREE_CHAIN (l); p = &TREE_CHAIN (l);
@ -5422,9 +5424,11 @@ merge_attributes (tree a1, tree a2)
for (; a2 != 0; a2 = TREE_CHAIN (a2)) for (; a2 != 0; a2 = TREE_CHAIN (a2))
{ {
tree a; 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 != 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) 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)) for (tail = list; tail; tail = TREE_CHAIN (tail))
/* ??? Do we want to add in TREE_VALUE too? */ /* ??? Do we want to add in TREE_VALUE too? */
hashcode = iterative_hash_object hashcode = iterative_hash_object
(IDENTIFIER_HASH_VALUE (TREE_PURPOSE (tail)), hashcode); (IDENTIFIER_HASH_VALUE (get_attribute_name (tail)), hashcode);
return hashcode; return hashcode;
} }
@ -6383,7 +6387,7 @@ attribute_list_contained (const_tree l1, const_tree l2)
/* Maybe the lists are similar. */ /* Maybe the lists are similar. */
for (t1 = l1, t2 = l2; for (t1 = l1, t2 = l2;
t1 != 0 && t2 != 0 t1 != 0 && t2 != 0
&& TREE_PURPOSE (t1) == TREE_PURPOSE (t2) && get_attribute_name (t1) == get_attribute_name (t2)
&& TREE_VALUE (t1) == TREE_VALUE (t2); && TREE_VALUE (t1) == TREE_VALUE (t2);
t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (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 /* This CONST_CAST is okay because lookup_attribute does not
modify its argument and the return value is assigned to a modify its argument and the return value is assigned to a
const_tree. */ 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 != 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) if (attr == NULL_TREE)

View File

@ -4903,12 +4903,12 @@ struct attribute_spec
{ {
/* The name of the attribute (without any leading or trailing __), /* The name of the attribute (without any leading or trailing __),
or NULL to mark the end of a table of attributes. */ 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. */ /* 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 /* The maximum length of the list of arguments of the attribute
(-1 for no maximum). */ (-1 for no maximum). */
const int max_length; int max_length;
/* Whether this attribute requires a DECL. If it does, it will be passed /* 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 from types of DECLs, function return types and array element types to
the DECLs, function types and array types respectively; but when 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, a warning. (If greater control is desired for a given attribute,
this should be false, and the flags argument to the handler may be this should be false, and the flags argument to the handler may be
used to gain greater control in that case.) */ 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 /* Whether this attribute requires a type. If it does, it will be passed
from a DECL to the type of that DECL. */ 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, /* 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, 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 and from a function return type (which is not itself a function
pointer type) to the function type. */ 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 /* 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 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 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 otherwise the return value should be NULL_TREE. This pointer may be
NULL if no special handling is required beyond the checks implied NULL if no special handling is required beyond the checks implied
by the rest of this structure. */ by the rest of this structure. */
tree (*const handler) (tree *node, tree name, tree args, tree (*handler) (tree *node, tree name, tree args,
int flags, bool *no_add_attrs); int flags, bool *no_add_attrs);
/* Specifies if attribute affects type's identity. */ /* 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 /* 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 /* The attributes are being applied by default to a library function whose
name indicates known behavior, and should be silently ignored if they name indicates known behavior, and should be silently ignored if they
are not in fact compatible with the function type. */ 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. */ /* 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. */ /* In attribs.c. */
extern const struct attribute_spec *lookup_attribute_spec (const_tree); 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); 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). */ a decl attribute to the declaration rather than to its type). */
extern tree decl_attributes (tree *, tree, int); 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); extern void apply_tm_attr (tree, tree);
/* In stor-layout.c */ /* In stor-layout.c */