Commit 4e03c3a7 by Joseph Myers Committed by Joseph Myers

Support C2x [[]] attributes for C.

This patch adds support for the C2x [[]] attribute syntax to the C
front end.  Support is only added for C at this point, not for
Objective-C; I intend to add the unbounded lookahead required to
support it for Objective-C in a followup patch, but maybe not in
development stage 1.

The syntax is supported in all relevant places where the standard says
it is supported, but support is not added for the individual
attributes specified in C2x (all of which are optional to support).  I
expect to add support for some of them in followup patches; all except
nodiscard can be mapped directly to the semantics of an existing GNU
attribute (subject to extra checks for invalid usages such as the same
attribute being used more than once inside a single [[]]), and the
fallthrough attribute already works after this patch because of
existing special-case code handling it (but without some of the checks
for invalid usage being present).

Note that the four functions c_token_starts_declspecs,
c_token_starts_declaration, c_parser_next_token_starts_declspecs and
c_parser_next_tokens_start_declaration do *not* accept "[[".  This is
analogous with the handling of __extension__: both cases have the
property that they can start either a declaration or some other
statements and so need an unbounded number of tokens to be parsed in
the caller before it can find out what kind of syntactic construct
follows.  Note also that, while I updated all places calling those
functions for standard C syntax to handle attributes if applicable, I
did not do anything regarding calls to such functions for OpenMP or
OpenACC constructs.  Thus, if there are such constructs using such
functions where "[[" *should* be accepted as a possible start to a
declaration, the code for parsing those constructs should be updated
accordingly.

Although all cases of the syntax are handled, and attributes applied
to the constructs the standard says they should be (with less laxity
than there is for GNU attributes to allow an attribute applied to one
construct to be moved automatically to another one), there is a major
limitation in the existing language-independent code in attribs.c
preventing most cases of type attributes from working.  The following
code has been present with minor changes since the first support for
[[]] attributes for C++ was added:

      if (TYPE_P (*node)
          && cxx11_attr_p
          && !(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.  */
          auto_diagnostic_group d;
          if (warning (OPT_Wattributes, "attribute ignored"))
            inform (input_location,
                    "an attribute that appertains to a type-specifier "
                    "is ignored");
          continue;
        }

I see no justification for this in general for either C or C++ and so
propose to remove or restrict it in a followup bug-fix patch.  Both C
and C++ are clear about attributes in certain places (at the end of
declaration specifiers, or after function or array declarators)
appertaining to a specific type (and explicitly say, in the case of
attributes at the end of declaration specifiers, that they only apply
for that particular use of that type, not for subsequent uses of the
same type without the attributes).  Thus it seems clear to me that,
for example,

int [[gnu::mode(DI)]] x;

ought to be accepted as an analogue in [[]] syntax for

int __attribute__((mode(DI))) x;

(or strictly as an analogue for a version of that with extra
parentheses to make the GNU attribute bind properly to the type rather
than being automatically moved from the declaration to the type).
There are certain cases where an attribute *does* only make sense for
the definition of a type (e.g. "packed" on structure types), but those
should already be handled in the individual attribute handlers (such
as handle_packed_attribute, which already has code to deal with that
issue).  So my inclination is that the above-quoted check in attribs.c
should simply be removed, but failing that it should be restricted to
structure and union types (and such a change would be a bug-fix).
That would then allow various cases of [[]] attributes on types to
work properly.

Bootstrapped with no regressions on x86_64-pc-linux-gnu.

gcc/c:
	* c-tree.h (enum c_typespec_kind): Add ctsk_tagref_attrs and
	ctsk_tagfirstref_attrs.
	(struct c_declspecs): Update description of attrs.  Add
	postfix_attrs and non_std_attrs_seen_p.  Increase size of
	typespec_kind bit-field.
	(c_warn_unused_attributes): New declaration.
	(parser_xref_tag): Update prototype.
	* c-decl.c (c_warn_unused_attributes): New function.
	(shadow_tag_warned): Handle ctsk_tagfirstref_attrs and
	ctsk_tagref_attrs.  Handle attribute declarations.
	(check_compound_literal_type): Handle ctsk_tagfirstref_attrs.
	(grokdeclarator): Handle standard attributes.
	(parser_xref_tag): Add arguments have_std_attrs and attrs.  Apply
	attributes to incomplete type reference.
	(xref_tag): Update call to parser_xref_tag.
	(declspecs_add_addrspace, declspecs_add_type)
	(declspecs_add_scspec, declspecs_add_attrs): Set
	non_std_attrs_seen_p.
	(finish_declspecs): Apply postfix standard attributes to type.
	* c-parser.c (c_token_starts_declspecs)
	(c_token_starts_declaration, c_parser_next_token_starts_declspecs)
	(c_parser_next_tokens_start_declaration): Update comments.
	(c_parser_consume_token, c_parser_consume_pragma): Handle moving
	parser->tokens[2] to parser->tokens[1].
	(c_parser_nth_token_starts_std_attributes)
	(c_parser_std_attribute_specifier_sequence): New functions.
	(c_parser_declaration_or_fndef): Add arguments have_attrs and
	attrs.  All callers changed.  Handle standard attributes.
	(c_parser_parms_declarator, c_parser_parms_list_declarator)
	(c_parser_parameter_declaration): Add argument have_gnu_attrs.
	All callers changed.
	(c_parser_declspecs): Add arguments start_std_attr_ok and
	end_std_attr_ok.  All callers changed.  Handle standard
	attributes.
	(c_parser_enum_specifier, c_parser_struct_or_union_specifier)
	(c_parser_direct_declarator, c_parser_direct_declarator_inner)
	(c_parser_compound_statement_nostart, c_parser_all_labels)
	(c_parser_label, c_parser_statement, c_parser_for_statement):
	Handle standard attributes.
	* c-parser.h (c_parser_declspecs): Update prototype.
	* gimple-parser.c (c_parser_gimple_declaration): Update call to
	c_parser_declspecs.

gcc/testsuite:
	* gcc.dg/c2x-attr-fallthrough-1.c, gcc.dg/c2x-attr-syntax-1.c,
	gcc.dg/c2x-attr-syntax-2.c, gcc.dg/c2x-attr-syntax-3.c,
	gcc.dg/gnu2x-attr-syntax-1.c, gcc.dg/gnu2x-attr-syntax-2.c,
	gcc.dg/gnu2x-attrs-1.c: New tests.

From-SVN: r278194
parent eb270950
2019-11-14 Joseph Myers <joseph@codesourcery.com>
* c-tree.h (enum c_typespec_kind): Add ctsk_tagref_attrs and
ctsk_tagfirstref_attrs.
(struct c_declspecs): Update description of attrs. Add
postfix_attrs and non_std_attrs_seen_p. Increase size of
typespec_kind bit-field.
(c_warn_unused_attributes): New declaration.
(parser_xref_tag): Update prototype.
* c-decl.c (c_warn_unused_attributes): New function.
(shadow_tag_warned): Handle ctsk_tagfirstref_attrs and
ctsk_tagref_attrs. Handle attribute declarations.
(check_compound_literal_type): Handle ctsk_tagfirstref_attrs.
(grokdeclarator): Handle standard attributes.
(parser_xref_tag): Add arguments have_std_attrs and attrs. Apply
attributes to incomplete type reference.
(xref_tag): Update call to parser_xref_tag.
(declspecs_add_addrspace, declspecs_add_type)
(declspecs_add_scspec, declspecs_add_attrs): Set
non_std_attrs_seen_p.
(finish_declspecs): Apply postfix standard attributes to type.
* c-parser.c (c_token_starts_declspecs)
(c_token_starts_declaration, c_parser_next_token_starts_declspecs)
(c_parser_next_tokens_start_declaration): Update comments.
(c_parser_consume_token, c_parser_consume_pragma): Handle moving
parser->tokens[2] to parser->tokens[1].
(c_parser_nth_token_starts_std_attributes)
(c_parser_std_attribute_specifier_sequence): New functions.
(c_parser_declaration_or_fndef): Add arguments have_attrs and
attrs. All callers changed. Handle standard attributes.
(c_parser_parms_declarator, c_parser_parms_list_declarator)
(c_parser_parameter_declaration): Add argument have_gnu_attrs.
All callers changed.
(c_parser_declspecs): Add arguments start_std_attr_ok and
end_std_attr_ok. All callers changed. Handle standard
attributes.
(c_parser_enum_specifier, c_parser_struct_or_union_specifier)
(c_parser_direct_declarator, c_parser_direct_declarator_inner)
(c_parser_compound_statement_nostart, c_parser_all_labels)
(c_parser_label, c_parser_statement, c_parser_for_statement):
Handle standard attributes.
* c-parser.h (c_parser_declspecs): Update prototype.
* gimple-parser.c (c_parser_gimple_declaration): Update call to
c_parser_declspecs.
2019-11-12 Martin Liska <mliska@suse.cz>
* gimple-parser.c: Do not include params.h.
......
......@@ -4491,6 +4491,18 @@ c_simulate_builtin_function_decl (tree decl)
C_DECL_BUILTIN_PROTOTYPE (decl) = prototype_p (type);
return pushdecl (decl);
}
/* Warn about attributes in a context where they are unused
(attribute-declarations, except for the "fallthrough" case, and
attributes on statements). */
void
c_warn_unused_attributes (tree attrs)
{
for (tree t = attrs; t != NULL_TREE; t = TREE_CHAIN (t))
warning (OPT_Wattributes, "%qE attribute ignored",
get_attribute_name (t));
}
/* Called when a declaration is seen that contains no names to declare.
If its type is a reference to a structure, union or enum inherited
......@@ -4545,6 +4557,7 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
}
else if (declspecs->typespec_kind != ctsk_tagdef
&& declspecs->typespec_kind != ctsk_tagfirstref
&& declspecs->typespec_kind != ctsk_tagfirstref_attrs
&& declspecs->storage_class != csc_none)
{
if (warned != 1)
......@@ -4556,6 +4569,7 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
}
else if (declspecs->typespec_kind != ctsk_tagdef
&& declspecs->typespec_kind != ctsk_tagfirstref
&& declspecs->typespec_kind != ctsk_tagfirstref_attrs
&& (declspecs->const_p
|| declspecs->volatile_p
|| declspecs->atomic_p
......@@ -4571,6 +4585,7 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
}
else if (declspecs->typespec_kind != ctsk_tagdef
&& declspecs->typespec_kind != ctsk_tagfirstref
&& declspecs->typespec_kind != ctsk_tagfirstref_attrs
&& declspecs->alignas_p)
{
if (warned != 1)
......@@ -4668,9 +4683,34 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
warned = 2;
}
if (found_tag
&& warned == 2
&& (declspecs->typespec_kind == ctsk_tagref_attrs
|| declspecs->typespec_kind == ctsk_tagfirstref_attrs))
{
/* Standard attributes after the "struct" or "union" keyword are
only permitted when the contents of the type are defined, or
in the form "struct-or-union attribute-specifier-sequence
identifier;". If the ';' was not present, attributes were
diagnosed in the parser. Here, ensure that any other useless
elements of the declaration result in a pedwarn, not just a
warning. Forward declarations of enum types are not part of
standard C, but handle them the same. */
pedwarn (input_location, 0,
"invalid use of attributes in empty declaration");
warned = 1;
}
if (warned != 1)
{
if (!found_tag)
if (declspecs->declspecs_seen_p
&& !declspecs->non_std_attrs_seen_p)
/* An attribute declaration (but not a fallthrough attribute
declaration, which was handled separately); warn if there
are any attributes being ignored (but not if the attributes
were empty). */
c_warn_unused_attributes (declspecs->attrs);
else if (!found_tag)
pedwarn (input_location, 0, "empty declaration");
}
}
......@@ -5605,7 +5645,8 @@ check_compound_literal_type (location_t loc, struct c_type_name *type_name)
{
if (warn_cxx_compat
&& (type_name->specs->typespec_kind == ctsk_tagdef
|| type_name->specs->typespec_kind == ctsk_tagfirstref))
|| type_name->specs->typespec_kind == ctsk_tagfirstref
|| type_name->specs->typespec_kind == ctsk_tagfirstref_attrs))
warning_at (loc, OPT_Wc___compat,
"defining a type in a compound literal is invalid in C++");
}
......@@ -6210,18 +6251,32 @@ grokdeclarator (const struct c_declarator *declarator,
const struct c_declarator *inner_decl;
int attr_flags = 0;
declarator = declarator->declarator;
/* Standard attribute syntax precisely defines what entity
an attribute in each position appertains to, so only
apply laxity about positioning to GNU attribute syntax.
Standard attributes applied to a function or array
declarator apply exactly to that type; standard
attributes applied to the identifier apply to the
declaration rather than to the type. */
inner_decl = declarator;
while (inner_decl->kind == cdk_attrs)
inner_decl = inner_decl->declarator;
if (inner_decl->kind == cdk_id)
attr_flags |= (int) ATTR_FLAG_DECL_NEXT;
else if (inner_decl->kind == cdk_function)
attr_flags |= (int) ATTR_FLAG_FUNCTION_NEXT;
else if (inner_decl->kind == cdk_array)
attr_flags |= (int) ATTR_FLAG_ARRAY_NEXT;
returned_attrs = decl_attributes (&type,
chainon (returned_attrs, attrs),
attr_flags);
if (!cxx11_attribute_p (attrs))
{
if (inner_decl->kind == cdk_id)
attr_flags |= (int) ATTR_FLAG_DECL_NEXT;
else if (inner_decl->kind == cdk_function)
attr_flags |= (int) ATTR_FLAG_FUNCTION_NEXT;
else if (inner_decl->kind == cdk_array)
attr_flags |= (int) ATTR_FLAG_ARRAY_NEXT;
}
if (cxx11_attribute_p (attrs) && inner_decl->kind == cdk_id)
returned_attrs = chainon (returned_attrs, attrs);
else
returned_attrs = decl_attributes (&type,
chainon (returned_attrs,
attrs),
attr_flags);
break;
}
case cdk_array:
......@@ -7686,11 +7741,14 @@ get_parm_info (bool ellipsis, tree expr)
/* Get the struct, enum or union (CODE says which) with tag NAME.
Define the tag as a forward-reference with location LOC if it is
not defined. Return a c_typespec structure for the type
specifier. */
not defined. HAVE_STD_ATTRS says whether any standard attributes
were present after the struct, union or enum keyword; ATTRS are the
standard attributes present there. Return a c_typespec structure
for the type specifier. */
struct c_typespec
parser_xref_tag (location_t loc, enum tree_code code, tree name)
parser_xref_tag (location_t loc, enum tree_code code, tree name,
bool have_std_attrs, tree attrs)
{
struct c_typespec ret;
tree ref;
......@@ -7714,9 +7772,12 @@ parser_xref_tag (location_t loc, enum tree_code code, tree name)
this would not work properly if we return the reference found.
(For example, with "struct foo" in an outer scope, "union foo;"
must shadow that tag with a new one of union type.) */
ret.kind = (ref ? ctsk_tagref : ctsk_tagfirstref);
ret.kind = (ref
? (have_std_attrs ? ctsk_tagref_attrs : ctsk_tagref)
: (have_std_attrs ? ctsk_tagfirstref_attrs : ctsk_tagfirstref));
if (ref && TREE_CODE (ref) == code)
{
decl_attributes (&ref, attrs, (int) ATTR_FLAG_TYPE_IN_PLACE);
if (C_TYPE_DEFINED_IN_STRUCT (ref)
&& loc != UNKNOWN_LOCATION
&& warn_cxx_compat)
......@@ -7770,6 +7831,7 @@ parser_xref_tag (location_t loc, enum tree_code code, tree name)
}
pushtag (loc, name, ref);
decl_attributes (&ref, attrs, (int) ATTR_FLAG_TYPE_IN_PLACE);
ret.spec = ref;
return ret;
......@@ -7782,7 +7844,7 @@ parser_xref_tag (location_t loc, enum tree_code code, tree name)
tree
xref_tag (enum tree_code code, tree name)
{
return parser_xref_tag (input_location, code, name).spec;
return parser_xref_tag (input_location, code, name, false, NULL_TREE).spec;
}
/* Make sure that the tag NAME is defined *in the current scope*
......@@ -10214,6 +10276,7 @@ declspecs_add_addrspace (location_t location,
{
specs->non_sc_seen_p = true;
specs->declspecs_seen_p = true;
specs->non_std_attrs_seen_p = true;
if (!ADDR_SPACE_GENERIC_P (specs->address_space)
&& specs->address_space != as)
......@@ -10239,6 +10302,7 @@ declspecs_add_qual (location_t loc,
bool dupe = false;
specs->non_sc_seen_p = true;
specs->declspecs_seen_p = true;
specs->non_std_attrs_seen_p = true;
gcc_assert (TREE_CODE (qual) == IDENTIFIER_NODE
&& C_IS_RESERVED_WORD (qual));
i = C_RID_CODE (qual);
......@@ -10297,6 +10361,7 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
tree type = spec.spec;
specs->non_sc_seen_p = true;
specs->declspecs_seen_p = true;
specs->non_std_attrs_seen_p = true;
specs->typespec_kind = spec.kind;
if (TREE_DEPRECATED (type))
specs->deprecated_p = true;
......@@ -11162,6 +11227,7 @@ declspecs_add_scspec (location_t loc,
enum c_storage_class n = csc_none;
bool dupe = false;
specs->declspecs_seen_p = true;
specs->non_std_attrs_seen_p = true;
gcc_assert (TREE_CODE (scspec) == IDENTIFIER_NODE
&& C_IS_RESERVED_WORD (scspec));
i = C_RID_CODE (scspec);
......@@ -11278,6 +11344,9 @@ declspecs_add_attrs (location_t loc, struct c_declspecs *specs, tree attrs)
specs->attrs = chainon (attrs, specs->attrs);
specs->locations[cdw_attributes] = loc;
specs->declspecs_seen_p = true;
/* In the case of standard attributes at the start of the
declaration, the caller will reset this. */
specs->non_std_attrs_seen_p = true;
return specs;
}
......@@ -11306,7 +11375,7 @@ declspecs_add_alignas (location_t loc,
specifiers with any other type specifier to determine the resulting
type. This is where ISO C checks on complex types are made, since
"_Complex long" is a prefix of the valid ISO C type "_Complex long
double". */
double". Also apply postfix standard attributes to modify the type. */
struct c_declspecs *
finish_declspecs (struct c_declspecs *specs)
......@@ -11376,6 +11445,8 @@ finish_declspecs (struct c_declspecs *specs)
&& !specs->signed_p && !specs->unsigned_p
&& !specs->complex_p);
/* Type to be filled in later. */
if (specs->postfix_attrs)
error ("%<__auto_type%> followed by %<[[]]%> attributes");
break;
case cts_void:
gcc_assert (!specs->long_p && !specs->short_p
......@@ -11581,6 +11652,11 @@ finish_declspecs (struct c_declspecs *specs)
default:
gcc_unreachable ();
}
if (specs->type != NULL)
{
decl_attributes (&specs->type, specs->postfix_attrs, 0);
specs->postfix_attrs = NULL_TREE;
}
return specs;
}
......
......@@ -190,7 +190,8 @@ extern struct c_declarator *
c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
bool *seen_id);
extern void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool,
bool, bool, bool, enum c_lookahead_kind);
bool, bool, bool, bool, bool,
enum c_lookahead_kind);
extern struct c_type_name *c_parser_type_name (c_parser *, bool = false);
#endif
......@@ -186,9 +186,13 @@ enum c_typespec_kind {
kind of tag, in which case this is only valid if shadowing that
tag in an inner scope. */
ctsk_tagref,
/* Likewise, with standard attributes present in the reference. */
ctsk_tagref_attrs,
/* A reference to a tag, not previously declared in a visible
scope. */
ctsk_tagfirstref,
/* Likewise, with standard attributes present in the reference. */
ctsk_tagfirstref_attrs,
/* A definition of a tag such as "struct foo { int a; }". */
ctsk_tagdef,
/* A typedef name. */
......@@ -311,10 +315,15 @@ struct c_declspecs {
tree expr;
/* The attributes from a typedef decl. */
tree decl_attr;
/* When parsing, the attributes. Outside the parser, this will be
NULL; attributes (possibly from multiple lists) will be passed
separately. */
/* When parsing, the GNU attributes and prefix standard attributes.
Outside the parser, this will be NULL; attributes (possibly from
multiple lists) will be passed separately. */
tree attrs;
/* When parsing, postfix standard attributes (which appertain to the
type specified by the preceding declaration specifiers, unlike
prefix standard attributes which appertain to the declaration or
declarations as a whole). */
tree postfix_attrs;
/* The pass to start compiling a __GIMPLE or __RTL function with. */
char *gimple_or_rtl_pass;
/* ENTRY BB count. */
......@@ -335,13 +344,17 @@ struct c_declspecs {
ENUM_BITFIELD (c_typespec_keyword) typespec_word : 8;
/* The kind of type specifier if one has been seen, ctsk_none
otherwise. */
ENUM_BITFIELD (c_typespec_kind) typespec_kind : 3;
ENUM_BITFIELD (c_typespec_kind) typespec_kind : 4;
ENUM_BITFIELD (c_declspec_il) declspec_il : 3;
/* Whether any expressions in typeof specifiers may appear in
constant expressions. */
BOOL_BITFIELD expr_const_operands : 1;
/* Whether any declaration specifiers have been seen at all. */
BOOL_BITFIELD declspecs_seen_p : 1;
/* Whether any declaration specifiers other than standard attributes
have been seen at all. If only standard attributes have been
seen, this is an attribute-declaration. */
BOOL_BITFIELD non_std_attrs_seen_p : 1;
/* Whether something other than a storage class specifier or
attribute has been seen. This is used to warn for the
obsolescent usage of storage class specifiers other than at the
......@@ -582,6 +595,7 @@ extern struct c_declarator *set_array_declarator_inner (struct c_declarator *,
extern tree c_builtin_function (tree);
extern tree c_builtin_function_ext_scope (tree);
extern tree c_simulate_builtin_function_decl (tree);
extern void c_warn_unused_attributes (tree);
extern void shadow_tag (const struct c_declspecs *);
extern void shadow_tag_warned (const struct c_declspecs *, int);
extern tree start_enum (location_t, struct c_enum_contents *, tree);
......@@ -595,7 +609,8 @@ extern void store_parm_decls_from (struct c_arg_info *);
extern void temp_store_parm_decls (tree, tree);
extern void temp_pop_parm_decls (void);
extern tree xref_tag (enum tree_code, tree);
extern struct c_typespec parser_xref_tag (location_t, enum tree_code, tree);
extern struct c_typespec parser_xref_tag (location_t, enum tree_code, tree,
bool, tree);
extern struct c_parm *build_c_parm (struct c_declspecs *, tree,
struct c_declarator *, location_t);
extern struct c_declarator *build_attrs_declarator (tree,
......
......@@ -2014,7 +2014,7 @@ c_parser_gimple_declaration (gimple_parser &parser)
struct c_declarator *declarator;
struct c_declspecs *specs = build_null_declspecs ();
c_parser_declspecs (parser, specs, true, true, true,
true, true, cla_nonabstract_decl);
true, true, true, true, cla_nonabstract_decl);
finish_declspecs (specs);
/* Provide better error recovery. Note that a type name here is usually
......
2019-11-14 Joseph Myers <joseph@codesourcery.com>
* gcc.dg/c2x-attr-fallthrough-1.c, gcc.dg/c2x-attr-syntax-1.c,
gcc.dg/c2x-attr-syntax-2.c, gcc.dg/c2x-attr-syntax-3.c,
gcc.dg/gnu2x-attr-syntax-1.c, gcc.dg/gnu2x-attr-syntax-2.c,
gcc.dg/gnu2x-attrs-1.c: New tests.
2019-11-14 Feng Xue <fxue@os.amperecomputing.com>
PR ipa/91682
......
/* Test C2x attribute syntax. Valid use of fallthrough attribute. */
/* { dg-do compile } */
/* { dg-options "-std=c2x -pedantic-errors -Wextra" } */
int
f (int a)
{
int b = 2;
switch (a)
{
case 1:
b = 1; /* { dg-warning "may fall through" } */
case 2:
b = 2;
[[fallthrough]];
case 3:
b += 7;
break;
}
return b;
}
/* Test C2x attribute syntax. Basic tests of valid uses of empty
attributes. */
/* { dg-do compile } */
/* { dg-options "-std=c2x -pedantic-errors" } */
[ [ ] ] [[]];
[[]] int [[]] a [[]] = 123;
int f([[]] int x [[]], [[]] long [[]], short [[]] *[[]] [3] [[]],
int [[]] (int)[[]], int (*)(int)[[]]) [[]] [[]];
int g [[]] [2] [[]] [3] [[]];
int *[[]] const *[[]] volatile *[[]] *const p;
int *[[]][[]] q = 0;
struct [[]] s;
union [[]][[]] u;
struct [[]] s2 { [[]] long [[]] *a[[]] [3] [[]] [4], b[[]]; };
union [[]] u2 { [[]] long [[]] *a[[]] [3] [[]] [4]; };
int z = sizeof (int [[]]);
enum [[]] { E1 [[]][[]], E2[[]][[]] = 3 };
enum [[]] e { E3 = 4, E4 [[]] };
void
func (void) [[]]
{
[[]] int var;
[[]] { }
[[]] switch (a) { [[]] case 1: [[]] case 2: [[]] default: [[]] var = 3; }
[[]] x : [[]] y: [[]] var = 1;
[[]];
int [[]] var2;
[[]] if (a) [[]] (void) 0; else [[]] (void) 1;
[[]] while (0) [[]] var = 2;
[[]] do [[]] var = 3; while (0);
for ([[]] int zz = 1; zz < 10; zz++)
{
[[]] var2 = 8;
[[]] continue;
[[]] break;
}
if (a) [[]] goto x;
[[]] return;
}
void func2 () [[]];
void func3 () [[]] { }
/* Test C2x attribute syntax. Test ignored attributes diagnosed. */
/* { dg-do compile } */
/* { dg-options "-std=c2x -pedantic-errors" } */
/* A GNU attribute that is valid in some contexts, but should be
diagnosed in contexts where all attributes are ignored (attribute
declarations, except for fallthrough attributes, and
statements). */
#define CTX [[gnu::const]]
/* An attribute that is unknown, so ignored with a warning. */
#define UNK [[gnu::no_such_attribute(![!(!)!]!,;;)]]
CTX; /* { dg-warning "ignored" } */
UNK; /* { dg-warning "ignored" } */
UNK extern int a; /* { dg-warning "ignored" } */
extern int UNK a; /* { dg-warning "ignored" } */
extern int a UNK; /* { dg-warning "ignored" } */
int f () UNK; /* { dg-warning "ignored" } */
int f (void) UNK; /* { dg-warning "ignored" } */
int g (UNK int a); /* { dg-warning "ignored" } */
int g (int UNK a); /* { dg-warning "ignored" } */
int g (int a UNK); /* { dg-warning "ignored" } */
int g (UNK int); /* { dg-warning "ignored" } */
int g (int UNK); /* { dg-warning "ignored" } */
int g (int) UNK; /* { dg-warning "ignored" } */
int *UNK p; /* { dg-warning "ignored" } */
int b[3] UNK; /* { dg-warning "ignored" } */
int h (int () UNK); /* { dg-warning "ignored" } */
struct UNK s; /* { dg-warning "ignored" } */
union UNK u; /* { dg-warning "ignored" } */
struct UNK s2 { int a; }; /* { dg-warning "ignored" } */
union UNK u2 { int a; }; /* { dg-warning "ignored" } */
struct s3 { UNK int a; }; /* { dg-warning "ignored" } */
struct s4 { int UNK a; }; /* { dg-warning "ignored" } */
union u3 { UNK int a; }; /* { dg-warning "ignored" } */
union u4 { int UNK a; }; /* { dg-warning "ignored" } */
int z = sizeof (int UNK); /* { dg-warning "ignored" } */
enum UNK { E1 }; /* { dg-warning "ignored" } */
enum { E2 UNK }; /* { dg-warning "ignored" } */
enum { E3 UNK = 4 }; /* { dg-warning "ignored" } */
void
func (void) UNK { /* { dg-warning "ignored" } */
UNK int var; /* { dg-warning "ignored" } */
CTX { } /* { dg-warning "ignored" } */
CTX; /* { dg-warning "ignored" } */
CTX var = 1; /* { dg-warning "ignored" } */
CTX x: var = 2; /* { dg-warning "ignored" } */
for (UNK int zz = 1; zz < 10; zz++) ; /* { dg-warning "ignored" } */
}
/* Test C2x attribute syntax. Invalid uses of attributes. */
/* { dg-do compile } */
/* { dg-options "-std=c2x -pedantic-errors" } */
/* Prefix attributes not allowed on declarations without declarators. */
[[]] struct s { int a; }; /* { dg-error "empty declaration" } */
[[]] union u { int a; }; /* { dg-error "empty declaration" } */
void
f1 (void)
{
[[]] struct t { int a; }; /* { dg-error "empty declaration" } */
}
/* Prefix attributes not allowed on _Static_assert. */
[[]] _Static_assert (1); /* { dg-error "expected" } */
void
f2 (void)
{
[[]] _Static_assert (1); /* { dg-error "expected" } */
}
/* Declarations, including attribute declarations, cannot appear after
labels. */
void
f3 (void)
{
x: [[]];; /* { dg-error "can only be part of a statement" } */
}
/* Prefix attributes cannot appear on type names. */
int z = sizeof ([[]] int); /* { dg-error "expected" } */
/* Attributes are not allowed after struct, union or enum, except when
the type contents are being defined or the declaration is just
"struct-or-union atribute-specifier-sequence identifier;". */
const struct [[]] s2; /* { dg-warning "useless type qualifier" } */
/* { dg-error "invalid use of attributes in empty declaration" "invalid" { target *-*-* } .-1 } */
const union [[]] u2; /* { dg-warning "useless type qualifier" } */
/* { dg-error "invalid use of attributes in empty declaration" "invalid" { target *-*-* } .-1 } */
struct [[]] s3 *sv; /* { dg-error "expected" } */
union [[]] u3 *uv; /* { dg-error "expected" } */
enum e { E1 };
enum [[]] e *ev; /* { dg-error "expected" } */
/* Test C2x attribute syntax. Basic tests of valid uses of empty
attributes with GNU C features. */
/* { dg-do compile } */
/* { dg-options "-std=gnu2x" } */
/* Attributes can be used in declarations after __extension__, and
before asm statements. */
__extension__ [[]] int a;
void
f (void)
{
__extension__ [[]] int b;
[[]] asm ("");
}
/* Test C2x attribute syntax. Invalid uses of attributes with GNU C
features. */
/* { dg-do compile } */
/* { dg-options "-std=gnu2x -w" } */
/* Attributes cannot be used as prefix attributes on old-style
parameter declarations or on function declarators with identifier
lists (removed from C2x). */
void (*f(a, b) [[]])() int a, b; { } /* { dg-error "expected" } */
void f(x, y) int x; [[]] int y; { } /* { dg-error "expected" } */
/* Nonempty attributes cannot be used as postfix attributes with
__auto_type. */
__auto_type [[gnu::no_such_attr]] x = 1; /* { dg-error "'__auto_type' followed by" } */
/* Test C2x attribute syntax. Test GNU attributes appertain to
appropriate constructs. */
/* { dg-do compile } */
/* { dg-options "-std=gnu2x" } */
void f (void) {};
[[gnu::alias("f")]] void g (void);
void [[gnu::alias("f")]] h (void); /* { dg-warning "ignored" } */
/* { dg-message "that appertains to a type-specifier" "appertains" { target *-*-* } .-1 } */
struct [[gnu::packed]] s { int a; char b; };
_Static_assert (sizeof (struct s) == (sizeof (int) + sizeof (char)));
int
f2 (void)
{
[[gnu::deprecated]] int a = 1;
return a; /* { dg-warning "deprecated" } */
}
int
f3 (void)
{
int a [[gnu::deprecated]] = 1;
return a; /* { dg-warning "deprecated" } */
}
struct s2 { [[gnu::deprecated]] int a; int b [[gnu::deprecated]]; } x;
int
f4 (void)
{
return x.a; /* { dg-warning "deprecated" } */
}
int
f5 (void)
{
return x.b; /* { dg-warning "deprecated" } */
}
enum e { E1 [[gnu::deprecated]] };
enum e
f6 (void)
{
return E1; /* { dg-warning "deprecated" } */
}
int
f7 ([[gnu::deprecated]] int y)
{
return y; /* { dg-warning "deprecated" } */
}
union [[gnu::deprecated]] u { int x; };
void
f8 (void)
{
union u var; /* { dg-warning "deprecated" } */
}
enum [[gnu::deprecated]] edep { E2 };
void
f9 (void)
{
enum edep var; /* { dg-warning "deprecated" } */
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment