c, v2: Add support for unsequenced and reproducible attributes
Checks
Context |
Check |
Description |
linaro-tcwg-bot/tcwg_gcc_build--master-arm |
success
|
Build passed
|
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 |
success
|
Build passed
|
Commit Message
Hi!
On Tue, Jul 30, 2024 at 07:04:05PM +0200, Jakub Jelinek wrote:
> C23 added in N2956 ( https://open-std.org/JTC1/SC22/WG14/www/docs/n2956.htm )
> two new attributes
Here is an updated version of the patch. Based on discussions with paper
co-author the patch no longer looks into structs/unions or assumes there
could be a pointer passed to ... through which the functions could modify
memory and only allows a single level of indirection to be inspected (for
[[unsequenced]]) or stored to (for both).
The documentation is also clarified.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
2024-08-01 Jakub Jelinek <jakub@redhat.com>
PR c/116130
gcc/
* doc/extend.texi (unsequenced, reproducible): Document new function
type attributes.
* calls.cc (flags_from_decl_or_type): Handle "unsequenced noptr" and
"reproducible noptr" attributes.
gcc/c-family/
* c-attribs.cc (c_common_gnu_attributes): Add entries for
"unsequenced", "reproducible", "unsequenced noptr" and
"reproducible noptr" attributes.
(handle_unsequenced_attribute): New function.
(handle_reproducible_attribute): Likewise.
* c-common.h (handle_unsequenced_attribute): Declare.
(handle_reproducible_attribute): Likewise.
* c-lex.cc (c_common_has_attribute): Return 202311 for standard
unsequenced and reproducible attributes.
gcc/c/
* c-decl.cc (handle_std_unsequenced_attribute): New function.
(handle_std_reproducible_attribute): Likewise.
(std_attributes): Add entries for "unsequenced" and "reproducible"
attributes.
(c_warn_type_attributes): Add TYPE argument. Allow unsequenced
or reproducible attributes if it is FUNCTION_TYPE.
(groktypename): Adjust c_warn_type_attributes caller.
(grokdeclarator): Likewise.
(finish_declspecs): Likewise.
* c-parser.cc (c_parser_declaration_or_fndef): Likewise.
* c-tree.h (c_warn_type_attributes): Add TYPE argument.
gcc/testsuite/
* c-c++-common/attr-reproducible-1.c: New test.
* c-c++-common/attr-reproducible-2.c: New test.
* c-c++-common/attr-unsequenced-1.c: New test.
* c-c++-common/attr-unsequenced-2.c: New test.
* gcc.dg/c23-attr-reproducible-1.c: New test.
* gcc.dg/c23-attr-reproducible-2.c: New test.
* gcc.dg/c23-attr-reproducible-3.c: New test.
* gcc.dg/c23-attr-reproducible-4.c: New test.
* gcc.dg/c23-attr-reproducible-5.c: New test.
* gcc.dg/c23-attr-reproducible-6.c: New test.
* gcc.dg/c23-attr-unsequenced-1.c: New test.
* gcc.dg/c23-attr-unsequenced-2.c: New test.
* gcc.dg/c23-attr-unsequenced-3.c: New test.
* gcc.dg/c23-attr-unsequenced-4.c: New test.
* gcc.dg/c23-attr-unsequenced-5.c: New test.
* gcc.dg/c23-attr-unsequenced-6.c: New test.
* gcc.dg/c23-has-c-attribute-2.c: Add tests for unsequenced
and reproducible attributes.
Jakub
Comments
On Thu, 1 Aug 2024, Jakub Jelinek wrote:
> +Unsequenced functions without pointer or reference arguments are similar
> +to functions with the @code{const} attribute, except that @code{const}
> +attribute also requires finitness. So, both functions with @code{const}
s/finitness/finiteness/ (in all places).
> --- gcc/testsuite/gcc.dg/c23-attr-reproducible-4.c.jj 2024-08-01 14:37:23.948824359 +0200
> +++ gcc/testsuite/gcc.dg/c23-attr-reproducible-4.c 2024-08-01 14:37:23.948824359 +0200
> @@ -0,0 +1,12 @@
> +/* Test C23 reproducible attribute: duplicates (allowed after N2557). */
The reference to N2557 seems anachronistic here, since the restrictions on
duplicates were removed some time before the unsequenced and reproducible
attributes were added to the working draft; there never was a time when
C23 supported those attributes without allowing duplicates. (The test
itself is fine; testing duplicates is a good thing to do.)
> --- gcc/testsuite/gcc.dg/c23-attr-reproducible-6.c.jj 2024-08-01 14:37:23.948824359 +0200
> +++ gcc/testsuite/gcc.dg/c23-attr-reproducible-6.c 2024-08-01 14:37:23.948824359 +0200
> @@ -0,0 +1,21 @@
> +/* Test C23 reproducible attribute: composite type on ?:. */
> +/* { dg-do compile } */
> +/* { dg-options "-std=c23 -pedantic-errors" } */
> +
> +int
> +f1 () [[reproducible]]
> +{
> + return 42;
> +}
> +
> +int
> +f2 ()
> +{
> + return 43;
> +}
> +
> +int
> +f3 ()
> +{
> + return 44;
> +}
I don't see how this test relates to the "composite type on ?:" comment
(or that it's doing anything useful).
> --- gcc/testsuite/gcc.dg/c23-attr-unsequenced-4.c.jj 2024-08-01 14:37:23.949824346 +0200
> +++ gcc/testsuite/gcc.dg/c23-attr-unsequenced-4.c 2024-08-01 14:37:23.949824346 +0200
> @@ -0,0 +1,12 @@
> +/* Test C23 unsequenced attribute: duplicates (allowed after N2557). */
Likewise here.
> --- gcc/testsuite/gcc.dg/c23-attr-unsequenced-6.c.jj 2024-08-01 14:37:23.949824346 +0200
> +++ gcc/testsuite/gcc.dg/c23-attr-unsequenced-6.c 2024-08-01 14:37:23.949824346 +0200
> @@ -0,0 +1,21 @@
> +/* Test C23 unsequenced attribute: composite type on ?:. */
> +/* { dg-do compile } */
> +/* { dg-options "-std=c23 -pedantic-errors" } */
> +
> +int
> +f1 () [[unsequenced]]
> +{
> + return 42;
> +}
> +
> +int
> +f2 ()
> +{
> + return 43;
> +}
> +
> +int
> +f3 ()
> +{
> + return 44;
> +}
And likewise here.
The patch is OK with the above fixed in the absence of any objections
within a week. (I'm supposing fixed here means removing
c23-attr-reproducible-6.c and c23-attr-unsequenced-6.c; if there's some
different test meant to be there, or some reason those tests are in fact
useful, then the updated / new tests should be reviewed.)
On Wed, Aug 21, 2024 at 04:00:23PM +0000, Joseph Myers wrote:
> On Thu, 1 Aug 2024, Jakub Jelinek wrote:
>
> > +Unsequenced functions without pointer or reference arguments are similar
> > +to functions with the @code{const} attribute, except that @code{const}
> > +attribute also requires finitness. So, both functions with @code{const}
>
> s/finitness/finiteness/ (in all places).
Changed.
> > --- gcc/testsuite/gcc.dg/c23-attr-reproducible-4.c.jj 2024-08-01 14:37:23.948824359 +0200
> > +++ gcc/testsuite/gcc.dg/c23-attr-reproducible-4.c 2024-08-01 14:37:23.948824359 +0200
> > @@ -0,0 +1,12 @@
> > +/* Test C23 reproducible attribute: duplicates (allowed after N2557). */
>
> The reference to N2557 seems anachronistic here, since the restrictions on
> duplicates were removed some time before the unsequenced and reproducible
> attributes were added to the working draft; there never was a time when
> C23 supported those attributes without allowing duplicates. (The test
> itself is fine; testing duplicates is a good thing to do.)
Removed the " (allowed after N2557)" parts.
>
> > --- gcc/testsuite/gcc.dg/c23-attr-reproducible-6.c.jj 2024-08-01 14:37:23.948824359 +0200
> > +++ gcc/testsuite/gcc.dg/c23-attr-reproducible-6.c 2024-08-01 14:37:23.948824359 +0200
> > @@ -0,0 +1,21 @@
> > +/* Test C23 reproducible attribute: composite type on ?:. */
> > +/* { dg-do compile } */
> > +/* { dg-options "-std=c23 -pedantic-errors" } */
> > +
> > +int
> > +f1 () [[reproducible]]
> > +{
> > + return 42;
> > +}
> > +
> > +int
> > +f2 ()
> > +{
> > + return 43;
> > +}
> > +
> > +int
> > +f3 ()
> > +{
> > + return 44;
> > +}
>
> I don't see how this test relates to the "composite type on ?:" comment
> (or that it's doing anything useful).
This is an auxiliary file for c23-attr-reproducible-5.c, which uses:
/* { dg-additional-sources "c23-attr-reproducible-6.c" } */
I've renamed c23-attr-*-6.c to c23-attr-*-5-aux.c and adjusted comment.
> The patch is OK with the above fixed in the absence of any objections
> within a week. (I'm supposing fixed here means removing
> c23-attr-reproducible-6.c and c23-attr-unsequenced-6.c; if there's some
> different test meant to be there, or some reason those tests are in fact
> useful, then the updated / new tests should be reviewed.)
Here is the full updated patch.
2024-08-30 Jakub Jelinek <jakub@redhat.com>
PR c/116130
gcc/
* doc/extend.texi (unsequenced, reproducible): Document new function
type attributes.
* calls.cc (flags_from_decl_or_type): Handle "unsequenced noptr" and
"reproducible noptr" attributes.
gcc/c-family/
* c-attribs.cc (c_common_gnu_attributes): Add entries for
"unsequenced", "reproducible", "unsequenced noptr" and
"reproducible noptr" attributes.
(handle_unsequenced_attribute): New function.
(handle_reproducible_attribute): Likewise.
* c-common.h (handle_unsequenced_attribute): Declare.
(handle_reproducible_attribute): Likewise.
* c-lex.cc (c_common_has_attribute): Return 202311 for standard
unsequenced and reproducible attributes.
gcc/c/
* c-decl.cc (handle_std_unsequenced_attribute): New function.
(handle_std_reproducible_attribute): Likewise.
(std_attributes): Add entries for "unsequenced" and "reproducible"
attributes.
(c_warn_type_attributes): Add TYPE argument. Allow unsequenced
or reproducible attributes if it is FUNCTION_TYPE.
(groktypename): Adjust c_warn_type_attributes caller.
(grokdeclarator): Likewise.
(finish_declspecs): Likewise.
* c-parser.cc (c_parser_declaration_or_fndef): Likewise.
* c-tree.h (c_warn_type_attributes): Add TYPE argument.
gcc/testsuite/
* c-c++-common/attr-reproducible-1.c: New test.
* c-c++-common/attr-reproducible-2.c: New test.
* c-c++-common/attr-unsequenced-1.c: New test.
* c-c++-common/attr-unsequenced-2.c: New test.
* gcc.dg/c23-attr-reproducible-1.c: New test.
* gcc.dg/c23-attr-reproducible-2.c: New test.
* gcc.dg/c23-attr-reproducible-3.c: New test.
* gcc.dg/c23-attr-reproducible-4.c: New test.
* gcc.dg/c23-attr-reproducible-5.c: New test.
* gcc.dg/c23-attr-reproducible-5-aux.c: New test.
* gcc.dg/c23-attr-unsequenced-1.c: New test.
* gcc.dg/c23-attr-unsequenced-2.c: New test.
* gcc.dg/c23-attr-unsequenced-3.c: New test.
* gcc.dg/c23-attr-unsequenced-4.c: New test.
* gcc.dg/c23-attr-unsequenced-5.c: New test.
* gcc.dg/c23-attr-unsequenced-5-aux.c: New test.
* gcc.dg/c23-has-c-attribute-2.c: Add tests for unsequenced
and reproducible attributes.
--- gcc/doc/extend.texi.jj 2024-08-01 10:30:35.437802437 +0200
+++ gcc/doc/extend.texi 2024-08-01 14:51:21.512248155 +0200
@@ -4024,6 +4024,69 @@ diagnosed. Because a pure function cann
effects it does not make sense for such a function to return @code{void}.
Declaring such a function is diagnosed.
+@cindex @code{unsequenced} function type attribute
+@cindex functions that have no side effects
+@item unsequenced
+
+This attribute is a GNU counterpart of the C23 @code{[[unsequenced]]}
+attribute, used to specify function pointers to effectless, idempotent,
+stateless and independent functions according to the C23 definition.
+
+Unlike the standard C23 attribute it can be also specified in attributes
+which appertain to function declarations and applies to the their function
+type even in that case.
+
+Unsequenced functions without pointer or reference arguments are similar
+to functions with the @code{const} attribute, except that @code{const}
+attribute also requires finiteness. So, both functions with @code{const}
+and with @code{unsequenced} attributes can be optimized by common
+subexpression elimination, but only functions with @code{const}
+attribute can be optimized by dead code elimination if their result is
+unused or is used only by dead code. Unsequenced functions without pointer
+or reference arguments with @code{void} return type are diagnosed because
+they can't store any results and don't have other observable side-effects
+either.
+
+Unsequenced functions with pointer or reference arguments can inspect
+objects through the passed pointers or references or references to pointers
+or can store additional results through those pointers or references or
+references to pointers.
+
+The @code{unsequenced} attribute imposes greater restrictions than
+the similar @code{reproducible} attribute and fewer restrictions than
+the @code{const} attribute, so during optimization @code{const} has
+precedence over @code{unsequenced} which has precedence over
+@code{reproducible}.
+
+@cindex @code{reproducible} function type attribute
+@cindex functions that have no side effects
+@item reproducible
+
+This attribute is a GNU counterpart of the C23 @code{[[reproducible]]}
+attribute, used to specify function pointers to effectless and idempotent
+functions according to the C23 definition.
+
+Unlike the standard C23 attribute it can be also specified in attributes
+which appertain to function declarations and applies to the their function
+type even in that case.
+
+Reproducible functions without pointer or reference arguments or which do
+not modify objects referenced by those pointer/reference arguments are
+similar to functions with the @code{pure} attribute, except that
+@code{pure} attribute also requires finiteness. So, both functions with
+@code{pure} and with @code{reproducible} attributes can be optimized by common
+subexpression elimination if the global state or anything reachable through
+the pointer/reference arguments isn't modified, but only functions with
+@code{pure} attribute can be optimized by dead code elimination if their result is
+unused or is used only by dead code. Reproducible functions without pointer
+or reference arguments with @code{void} return type are diagnosed because
+they can't store any results and don't have other observable side-effects
+either.
+
+Reproducible functions with pointer or reference arguments can store
+additional results through those pointers or references or references to
+pointers.
+
@cindex @code{retain} function attribute
@item retain
For ELF targets that support the GNU or FreeBSD OSABIs, this attribute
--- gcc/calls.cc.jj 2024-08-01 10:30:35.430802527 +0200
+++ gcc/calls.cc 2024-08-01 14:37:23.941824448 +0200
@@ -852,6 +852,23 @@ flags_from_decl_or_type (const_tree exp)
flags |= ECF_XTHROW;
flags = special_function_p (exp, flags);
+
+ if ((flags & ECF_CONST) == 0
+ && lookup_attribute ("unsequenced noptr",
+ TYPE_ATTRIBUTES (TREE_TYPE (exp))))
+ {
+ /* [[unsequenced]] with no pointers in arguments is like
+ [[gnu::const]] without finite guarantee. */
+ flags |= ECF_CONST;
+ if ((flags & ECF_PURE) == 0)
+ flags |= ECF_LOOPING_CONST_OR_PURE;
+ }
+ if ((flags & (ECF_CONST | ECF_PURE)) == 0
+ && lookup_attribute ("reproducible noptr",
+ TYPE_ATTRIBUTES (TREE_TYPE (exp))))
+ /* [[reproducible]] with no pointers in arguments is like
+ [[gnu::pure]] without finite guarantee. */
+ flags |= ECF_PURE | ECF_LOOPING_CONST_OR_PURE;
}
else if (TYPE_P (exp))
{
@@ -862,6 +879,17 @@ flags_from_decl_or_type (const_tree exp)
&& ((flags & ECF_CONST) != 0
|| lookup_attribute ("transaction_pure", TYPE_ATTRIBUTES (exp))))
flags |= ECF_TM_PURE;
+
+ if ((flags & ECF_CONST) == 0
+ && lookup_attribute ("unsequenced noptr", TYPE_ATTRIBUTES (exp)))
+ /* [[unsequenced]] with no pointers in arguments is like
+ [[gnu::const]] without finite guarantee. */
+ flags |= ECF_CONST | ECF_LOOPING_CONST_OR_PURE;
+ if ((flags & ECF_CONST) == 0
+ && lookup_attribute ("reproducible noptr", TYPE_ATTRIBUTES (exp)))
+ /* [[reproducible]] with no pointers in arguments is like
+ [[gnu::pure]] without finite guarantee. */
+ flags |= ECF_PURE | ECF_LOOPING_CONST_OR_PURE;
}
else
gcc_unreachable ();
--- gcc/c-family/c-attribs.cc.jj 2024-08-01 10:30:35.420802655 +0200
+++ gcc/c-family/c-attribs.cc 2024-08-01 14:43:28.775217639 +0200
@@ -444,6 +444,14 @@ const struct attribute_spec c_common_gnu
{ "pure", 0, 0, true, false, false, false,
handle_pure_attribute,
attr_const_pure_exclusions },
+ { "reproducible", 0, 0, false, true, true, false,
+ handle_reproducible_attribute, NULL },
+ { "unsequenced", 0, 0, false, true, true, false,
+ handle_unsequenced_attribute, NULL },
+ { "reproducible noptr", 0, 0, false, true, true, false,
+ handle_reproducible_attribute, NULL },
+ { "unsequenced noptr", 0, 0, false, true, true, false,
+ handle_unsequenced_attribute, NULL },
{ "transaction_callable", 0, 0, false, true, false, false,
handle_tm_attribute, NULL },
{ "transaction_unsafe", 0, 0, false, true, false, true,
@@ -4280,6 +4288,53 @@ handle_pure_attribute (tree *node, tree
return NULL_TREE;
}
+/* Handle an "unsequenced" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+tree
+handle_unsequenced_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int flags, bool *no_add_attrs)
+{
+ tree fntype = *node;
+ for (tree argtype = TYPE_ARG_TYPES (fntype); argtype;
+ argtype = TREE_CHAIN (argtype))
+ /* If any of the arguments have pointer or reference type, just
+ add the attribute alone. */
+ if (POINTER_TYPE_P (TREE_VALUE (argtype)))
+ return NULL_TREE;
+
+ if (VOID_TYPE_P (TREE_TYPE (fntype)))
+ warning (OPT_Wattributes, "%qE attribute on function type "
+ "without pointer arguments returning %<void%>", name);
+ const char *name2;
+ if (IDENTIFIER_LENGTH (name) == sizeof ("unsequenced") - 1)
+ name2 = "unsequenced noptr";
+ else
+ name2 = "reproducible noptr";
+ if (!lookup_attribute (name2, TYPE_ATTRIBUTES (fntype)))
+ {
+ *no_add_attrs = true;
+ gcc_assert ((flags & (int) ATTR_FLAG_TYPE_IN_PLACE) == 0);
+ tree attr = tree_cons (get_identifier (name2), NULL_TREE,
+ TYPE_ATTRIBUTES (fntype));
+ if (!lookup_attribute (IDENTIFIER_POINTER (name),
+ TYPE_ATTRIBUTES (fntype)))
+ attr = tree_cons (name, NULL_TREE, attr);
+ *node = build_type_attribute_variant (*node, attr);
+ }
+ return NULL_TREE;
+}
+
+/* Handle a "reproducible" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+tree
+handle_reproducible_attribute (tree *node, tree name, tree args, int flags,
+ bool *no_add_attrs)
+{
+ return handle_unsequenced_attribute (node, name, args, flags, no_add_attrs);
+}
+
/* Digest an attribute list destined for a transactional memory statement.
ALLOWED is the set of attributes that are allowed for this statement;
return the attribute we parsed. Multiple attributes are never allowed. */
--- gcc/c-family/c-common.h.jj 2024-08-01 10:30:35.421802642 +0200
+++ gcc/c-family/c-common.h 2024-08-01 14:37:23.942824435 +0200
@@ -864,6 +864,8 @@ extern void check_function_format (const
extern bool attribute_fallthrough_p (tree);
extern tree handle_format_attribute (tree *, tree, tree, int, bool *);
extern tree handle_format_arg_attribute (tree *, tree, tree, int, bool *);
+extern tree handle_unsequenced_attribute (tree *, tree, tree, int, bool *);
+extern tree handle_reproducible_attribute (tree *, tree, tree, int, bool *);
extern bool c_common_handle_option (size_t, const char *, HOST_WIDE_INT, int,
location_t,
const struct cl_option_handlers *);
--- gcc/c-family/c-lex.cc.jj 2024-08-01 10:30:35.421802642 +0200
+++ gcc/c-family/c-lex.cc 2024-08-01 14:37:23.942824435 +0200
@@ -445,7 +445,9 @@ c_common_has_attribute (cpp_reader *pfil
|| is_attribute_p ("maybe_unused", attr_name)
|| is_attribute_p ("nodiscard", attr_name)
|| is_attribute_p ("noreturn", attr_name)
- || is_attribute_p ("_Noreturn", attr_name))
+ || is_attribute_p ("_Noreturn", attr_name)
+ || is_attribute_p ("reproducible", attr_name)
+ || is_attribute_p ("unsequenced", attr_name))
result = 202311;
}
if (result)
--- gcc/c/c-decl.cc.jj 2024-08-01 10:30:35.424802604 +0200
+++ gcc/c/c-decl.cc 2024-08-01 14:37:23.944824410 +0200
@@ -4702,6 +4702,39 @@ handle_std_noreturn_attribute (tree *nod
}
}
+/* Handle the standard [[unsequenced]] attribute. */
+
+static tree
+handle_std_unsequenced_attribute (tree *node, tree name, tree args,
+ int flags, bool *no_add_attrs)
+{
+ /* Unlike GNU __attribute__ ((unsequenced)), the standard [[unsequenced]]
+ should be only applied to function declarators or type specifiers which
+ have function type. */
+ if (node[2])
+ {
+ auto_diagnostic_group d;
+ if (pedwarn (input_location, OPT_Wattributes,
+ "standard %qE attribute can only be applied to function "
+ "declarators or type specifiers with function type", name))
+ inform (input_location, "did you mean to specify it after %<)%> "
+ "following function parameters?");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ return handle_unsequenced_attribute (node, name, args, flags, no_add_attrs);
+}
+
+/* Handle the standard [[reproducible]] attribute. */
+
+static tree
+handle_std_reproducible_attribute (tree *node, tree name, tree args,
+ int flags, bool *no_add_attrs)
+{
+ return handle_std_unsequenced_attribute (node, name, args, flags,
+ no_add_attrs);
+}
+
/* Table of supported standard (C23) attributes. */
static const attribute_spec std_attributes[] =
{
@@ -4718,7 +4751,11 @@ static const attribute_spec std_attribut
{ "nodiscard", 0, 1, false, false, false, false,
handle_nodiscard_attribute, NULL },
{ "noreturn", 0, 0, false, false, false, false,
- handle_std_noreturn_attribute, NULL }
+ handle_std_noreturn_attribute, NULL },
+ { "reproducible", 0, 0, false, true, true, false,
+ handle_std_reproducible_attribute, NULL },
+ { "unsequenced", 0, 0, false, true, true, false,
+ handle_std_unsequenced_attribute, NULL }
};
const scoped_attribute_specs std_attribute_table =
@@ -4911,12 +4948,24 @@ c_warn_unused_attributes (tree attrs)
list of attributes with them removed. */
tree
-c_warn_type_attributes (tree attrs)
+c_warn_type_attributes (tree type, tree attrs)
{
tree *attr_ptr = &attrs;
while (*attr_ptr)
if (get_attribute_namespace (*attr_ptr) == NULL_TREE)
{
+ if (TREE_CODE (type) == FUNCTION_TYPE)
+ {
+ tree name = get_attribute_name (*attr_ptr);
+ /* [[unsequenced]] and [[reproducible]] is fine on function
+ types that aren't being defined. */
+ if (is_attribute_p ("unsequenced", name)
+ || is_attribute_p ("reproducible", name))
+ {
+ attr_ptr = &TREE_CHAIN (*attr_ptr);
+ continue;
+ }
+ }
pedwarn (input_location, OPT_Wattributes, "%qE attribute ignored",
get_attribute_name (*attr_ptr));
*attr_ptr = TREE_CHAIN (*attr_ptr);
@@ -5386,7 +5435,7 @@ groktypename (struct c_type_name *type_n
DEPRECATED_NORMAL);
/* Apply attributes. */
- attrs = c_warn_type_attributes (attrs);
+ attrs = c_warn_type_attributes (type, attrs);
decl_attributes (&type, attrs, 0);
return type;
@@ -7196,7 +7245,7 @@ grokdeclarator (const struct c_declarato
else if (inner_decl->kind == cdk_array)
attr_flags |= (int) ATTR_FLAG_ARRAY_NEXT;
}
- attrs = c_warn_type_attributes (attrs);
+ attrs = c_warn_type_attributes (type, attrs);
returned_attrs = decl_attributes (&type,
chainon (returned_attrs, attrs),
attr_flags);
@@ -13433,7 +13482,8 @@ finish_declspecs (struct c_declspecs *sp
handle_postfix_attrs:
if (specs->type != NULL)
{
- specs->postfix_attrs = c_warn_type_attributes (specs->postfix_attrs);
+ specs->postfix_attrs
+ = c_warn_type_attributes (specs->type, specs->postfix_attrs);
decl_attributes (&specs->type, specs->postfix_attrs, 0);
specs->postfix_attrs = NULL_TREE;
}
--- gcc/c/c-parser.cc.jj 2024-08-01 10:30:35.429802539 +0200
+++ gcc/c/c-parser.cc 2024-08-01 14:37:23.947824372 +0200
@@ -2677,8 +2677,9 @@ c_parser_declaration_or_fndef (c_parser
/* Postfix [[]] attributes are valid with C23
auto, although not with __auto_type, and
modify the type given by the initializer. */
- specs->postfix_attrs =
- c_warn_type_attributes (specs->postfix_attrs);
+ specs->postfix_attrs
+ = c_warn_type_attributes (specs->type,
+ specs->postfix_attrs);
decl_attributes (&specs->type, specs->postfix_attrs, 0);
specs->postfix_attrs = NULL_TREE;
}
--- gcc/c/c-tree.h.jj 2024-08-01 10:30:35.429802539 +0200
+++ gcc/c/c-tree.h 2024-08-01 14:37:23.947824372 +0200
@@ -680,7 +680,7 @@ 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 tree c_warn_type_attributes (tree);
+extern tree c_warn_type_attributes (tree, 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, tree,
--- gcc/testsuite/c-c++-common/attr-reproducible-1.c.jj 2024-08-01 14:37:23.947824372 +0200
+++ gcc/testsuite/c-c++-common/attr-reproducible-1.c 2024-08-01 14:37:23.947824372 +0200
@@ -0,0 +1,80 @@
+/* Test gnu::reproducible attribute: valid uses. */
+/* { dg-do compile { target { c || c++11 } } } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-additional-options "-std=gnu23" { target c } } */
+/* { dg-final { scan-tree-dump-times " f1 \\\(\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f2 \\\(\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f3 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f5 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f7 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f8 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f9 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f3 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f5 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f7 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f8 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f9 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump " f3 \\\(52\\\);" "optimized" } } */
+/* { dg-final { scan-tree-dump-times " fp1\.\[0-9]*_\[0-9]* \\\(14\\\);" 2 "optimized" } } */
+
+int f1 () [[gnu::reproducible]];
+int f2 () [[gnu::reproducible]], f3 (int) [[__gnu__::__reproducible__]];
+int f4 (int, int *) [[gnu::reproducible]];
+int f5 (int) [[gnu::reproducible]];
+int f6 (int);
+int (*fp1) (int) [[gnu::reproducible]] = f6;
+typedef int ft1 (int) [[gnu::reproducible]];
+typedef int ft2 (int);
+#ifndef __cplusplus
+extern __typeof (f6) [[gnu::reproducible]] f7;
+extern ft2 [[__gnu__::__reproducible__]] f8;
+#else
+int f7 (int) [[gnu::reproducible, gnu::reproducible]];
+int f8 (int) [[__gnu__::reproducible, gnu::__reproducible__]];
+#endif
+int f1 ();
+int f9 (int);
+int f9 (int) [[__gnu__::__reproducible__]];
+extern int x;
+
+int
+f10 (int w) [[gnu::reproducible]]
+{
+ return w + 42 + x;
+}
+
+int
+f11 (int *w, long long y[1], int z) [[__gnu__::__reproducible__]]
+{
+ w[0] = z + x;
+ w[1] = z + x + 1;
+ w[2] = z + x + 2;
+ *y = z + x + 3;
+ return z + 4 + f10 (-42);
+}
+
+int
+g ()
+{
+ int a = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42);
+ int b = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42);
+ int c = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int d = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int e = fp1 (14) + fp1 (14);
+ x++;
+ int f = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42);
+ int g = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42);
+ int h = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int i = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int j = fp1 (14) + fp1 (14);
+ return a + b + c + d + e + f + g + h + i + j;
+}
+
+int
+h ()
+{
+ f3 (52);
+ f3 (52);
+ f3 (52);
+ return 0;
+}
--- gcc/testsuite/c-c++-common/attr-reproducible-2.c.jj 2024-08-01 14:37:23.947824372 +0200
+++ gcc/testsuite/c-c++-common/attr-reproducible-2.c 2024-08-01 14:37:23.947824372 +0200
@@ -0,0 +1,74 @@
+/* Test reproducible attribute: valid uses. */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-times " f1 \\\(\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f2 \\\(\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f3 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f5 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f7 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f8 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f9 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f3 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f5 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f7 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f8 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f9 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump " f3 \\\(52\\\);" "optimized" } } */
+/* { dg-final { scan-tree-dump-times " fp1\.\[0-9]*_\[0-9]* \\\(14\\\);" 2 "optimized" } } */
+
+__attribute__((reproducible)) int f1 (void);
+__attribute__((__reproducible__)) int f2 (void), f3 (int);
+int f4 (int, int *) __attribute__((reproducible));
+int f5 (int) __attribute__((reproducible));
+int f6 (int);
+int (*fp1) (int) __attribute__((reproducible)) = f6;
+typedef int ft1 (int) __attribute__((reproducible));
+typedef int ft2 (int);
+extern __typeof (f6) __attribute__((reproducible)) f7;
+extern ft2 __attribute__((__reproducible__)) f8;
+int f1 (void);
+int f9 (int);
+int f9 (int) __attribute__((__reproducible__));
+extern int x;
+
+__attribute__((reproducible)) int
+f10 (int w)
+{
+ return w + 42 + x;
+}
+
+__attribute__((reproducible)) int
+f11 (int *w, long long y[1], int z)
+{
+ w[0] = z + x;
+ w[1] = z + x + 1;
+ w[2] = z + x + 2;
+ *y = z + x + 3;
+ return z + 4 + f10 (-42);
+}
+
+int
+g (void)
+{
+ int a = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42);
+ int b = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42);
+ int c = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int d = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int e = fp1 (14) + fp1 (14);
+ x++;
+ int f = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42);
+ int g = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42);
+ int h = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int i = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int j = fp1 (14) + fp1 (14);
+ return a + b + c + d + e + f + g + h + i + j;
+}
+
+int
+h (void)
+{
+ f3 (52);
+ f3 (52);
+ f3 (52);
+ return 0;
+}
--- gcc/testsuite/c-c++-common/attr-unsequenced-1.c.jj 2024-08-01 14:37:23.948824359 +0200
+++ gcc/testsuite/c-c++-common/attr-unsequenced-1.c 2024-08-01 14:37:23.947824372 +0200
@@ -0,0 +1,87 @@
+/* Test gnu::unsequenced attribute: valid uses. */
+/* { dg-do compile { target { c || c++11 } } } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-additional-options "-std=gnu23" { target c } } */
+/* { dg-final { scan-tree-dump-times " f1 \\\(\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f2 \\\(\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f12 \\\(\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f13 \\\(\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f3 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f5 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f7 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f8 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f9 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f3 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f5 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f7 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f8 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f9 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump " f3 \\\(52\\\);" "optimized" } } */
+/* { dg-final { scan-tree-dump-times " fp1\.\[0-9]*_\[0-9]* \\\(14\\\);" 1 "optimized" } } */
+
+[[gnu::unsequenced]] int f1 ();
+[[gnu::unsequenced]] int f2 (), f3 (int);
+int f4 (int, int *) [[gnu::unsequenced]];
+int f5 (int) [[gnu::unsequenced]];
+int f6 (int);
+int (*fp1) (int) [[gnu::unsequenced]] = f6;
+typedef int ft1 (int) [[gnu::unsequenced]];
+typedef int ft2 (int);
+#ifndef __cplusplus
+extern __typeof (f6) [[gnu::unsequenced]] f7;
+extern ft2 [[__gnu__::__unsequenced__]] f8;
+#else
+int f7 (int) [[gnu::unsequenced, gnu::unsequenced]];
+int f8 (int) [[__gnu__::unsequenced, gnu::__unsequenced__]];
+#endif
+int f1 ();
+int f9 (int);
+int f9 (int) [[__gnu__::__unsequenced__]];
+extern int x;
+
+int
+f10 (int x) [[gnu::unsequenced]]
+{
+ return x + 42;
+}
+
+int
+f11 (int *x, long long y[1], int z) [[__gnu__::__unsequenced__]]
+{
+ x[0] = z;
+ x[1] = z + 1;
+ x[2] = z + 2;
+ *y = z + 3;
+ return z + 4 + f10 (-42);
+}
+
+int f12 () [[gnu::unsequenced]];
+int f12 () [[gnu::reproducible]];
+int f13 () [[gnu::reproducible]];
+int f13 () [[gnu::unsequenced]];
+
+int
+g ()
+{
+ int a = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 ();
+ int b = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 ();
+ int c = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int d = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int e = fp1 (14) + fp1 (14);
+ x++;
+ int f = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 ();
+ int g = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 ();
+ int h = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int i = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int j = fp1 (14) + fp1 (14);
+ return a + b + c + d + e + f + g + h + i + j;
+}
+
+int
+h ()
+{
+ f3 (52);
+ f3 (52);
+ f3 (52);
+ return 0;
+}
--- gcc/testsuite/c-c++-common/attr-unsequenced-2.c.jj 2024-08-01 14:37:23.948824359 +0200
+++ gcc/testsuite/c-c++-common/attr-unsequenced-2.c 2024-08-01 14:37:23.948824359 +0200
@@ -0,0 +1,81 @@
+/* Test unsequenced attribute: valid uses. */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-times " f1 \\\(\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f2 \\\(\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f12 \\\(\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f13 \\\(\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f3 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f5 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f7 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f8 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f9 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f3 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f5 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f7 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f8 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f9 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump " f3 \\\(52\\\);" "optimized" } } */
+/* { dg-final { scan-tree-dump-times " fp1\.\[0-9]*_\[0-9]* \\\(14\\\);" 1 "optimized" } } */
+
+__attribute__((unsequenced)) int f1 (void);
+__attribute__((unsequenced)) int f2 (void), f3 (int);
+int f4 (int, int *) __attribute__((unsequenced));
+int f5 (int) __attribute__((unsequenced));
+int f6 (int);
+int (*fp1) (int) __attribute__((unsequenced)) = f6;
+typedef int ft1 (int) __attribute__((unsequenced));
+typedef int ft2 (int);
+extern __typeof (f6) __attribute__((unsequenced)) f7;
+extern ft2 __attribute__((__unsequenced__)) f8;
+int f1 (void);
+int f9 (int);
+int f9 (int) __attribute__((__unsequenced__));
+extern int x;
+
+__attribute__((unsequenced)) int
+f10 (int x)
+{
+ return x + 42;
+}
+
+__attribute__((__unsequenced__)) int
+f11 (int *x, long long y[1], int z)
+{
+ x[0] = z;
+ x[1] = z + 1;
+ x[2] = z + 2;
+ *y = z + 3;
+ return z + 4 + f10 (-42);
+}
+
+int f12 (void) __attribute__((unsequenced));
+int f12 (void) __attribute__((reproducible));
+int f13 (void) __attribute__((reproducible));
+int f13 (void) __attribute__((unsequenced));
+
+int
+g (void)
+{
+ int a = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 ();
+ int b = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 ();
+ int c = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int d = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int e = fp1 (14) + fp1 (14);
+ x++;
+ int f = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 ();
+ int g = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 ();
+ int h = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int i = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int j = fp1 (14) + fp1 (14);
+ return a + b + c + d + e + f + g + h + i + j;
+}
+
+int
+h (void)
+{
+ f3 (52);
+ f3 (52);
+ f3 (52);
+ return 0;
+}
--- gcc/testsuite/gcc.dg/c23-attr-reproducible-1.c.jj 2024-08-01 14:37:23.948824359 +0200
+++ gcc/testsuite/gcc.dg/c23-attr-reproducible-1.c 2024-08-01 14:37:23.948824359 +0200
@@ -0,0 +1,74 @@
+/* Test C23 reproducible attribute: valid uses. */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors -O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-times " f1 \\\(\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f2 \\\(\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f3 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f5 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f7 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f8 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f9 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f3 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f5 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f7 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f8 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f9 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump " f3 \\\(52\\\);" "optimized" } } */
+/* { dg-final { scan-tree-dump-times " fp1\.\[0-9]*_\[0-9]* \\\(14\\\);" 2 "optimized" } } */
+
+int f1 () [[reproducible]];
+int f2 () [[reproducible]], f3 (int) [[__reproducible__]];
+int f4 (int, int *restrict) [[reproducible]];
+int f5 (int) [[reproducible]];
+int f6 (int);
+int (*fp1) (int) [[reproducible]] = f6;
+typedef int ft1 (int) [[reproducible]];
+typedef int ft2 (int);
+extern typeof (f6) [[reproducible]] f7;
+extern ft2 [[__reproducible__]] f8;
+int f1 ();
+int f9 (int);
+int f9 (int) [[__reproducible__]];
+extern int x;
+
+int
+f10 (int w) [[reproducible]]
+{
+ return w + 42 + x;
+}
+
+int
+f11 (int *restrict w, long long y[restrict static 1], int z) [[__reproducible__]]
+{
+ w[0] = z + x;
+ w[1] = z + x + 1;
+ w[2] = z + x + 2;
+ *y = z + x + 3;
+ return z + 4 + f10 (-42);
+}
+
+int
+g ()
+{
+ int a = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42);
+ int b = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42);
+ int c = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int d = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int e = fp1 (14) + fp1 (14);
+ x++;
+ int f = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42);
+ int g = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42);
+ int h = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int i = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int j = fp1 (14) + fp1 (14);
+ return a + b + c + d + e + f + g + h + i + j;
+}
+
+int
+h ()
+{
+ f3 (52);
+ f3 (52);
+ f3 (52);
+ return 0;
+}
--- gcc/testsuite/gcc.dg/c23-attr-reproducible-2.c.jj 2024-08-01 14:37:23.948824359 +0200
+++ gcc/testsuite/gcc.dg/c23-attr-reproducible-2.c 2024-08-01 14:37:23.948824359 +0200
@@ -0,0 +1,47 @@
+/* Test C23 reproducible attribute: invalid contexts. */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+/* This attribute is not valid in most cases on types other than
+ type specifiers with function type or function declarators. */
+
+[[reproducible]]; /* { dg-error "ignored" } */
+
+int [[reproducible]] var; /* { dg-error "ignored" } */
+
+int array_with_dep_type[2] [[reproducible]]; /* { dg-error "ignored" } */
+
+[[reproducible]] int fn1 (); /* { dg-error "standard 'reproducible' attribute can only be applied to function declarators or type specifiers with function type" } */
+
+[[reproducible]] int fn2 (), fn3 (); /* { dg-error "standard 'reproducible' attribute can only be applied to function declarators or type specifiers with function type" } */
+
+int var2 [[reproducible]]; /* { dg-warning "'reproducible' attribute only applies to function types" } */
+
+int fn4 [[reproducible]] (); /* { dg-error "standard 'reproducible' attribute can only be applied to function declarators or type specifiers with function type" } */
+
+int [[reproducible]] fn5 (); /* { dg-error "ignored" } */
+
+int z = sizeof (int [[__reproducible__]]); /* { dg-error "ignored" } */
+
+/* This is valid, but not really useful, as it can't return results
+ in return type nor has any pointer arguments to store results into. */
+void
+fn6 (int x, double y) [[reproducible]]
+{ /* { dg-warning "reproducible' attribute on function type without pointer arguments returning 'void'" } */
+ y = x;
+ (void) y;
+}
+
+void
+f (void)
+{
+ int a;
+ [[reproducible]]; /* { dg-error "ignored" } */
+ [[reproducible]] a = 1; /* { dg-error "ignored" } */
+ [[reproducible]] label: ; /* { dg-warning "'reproducible' attribute only applies to function types" } */
+ switch (var)
+ {
+ [[reproducible]] case 1: ; /* { dg-warning "'reproducible' attribute only applies to function types" } */
+ [[reproducible]] default: ; /* { dg-warning "'reproducible' attribute only applies to function types" } */
+ }
+}
--- gcc/testsuite/gcc.dg/c23-attr-reproducible-3.c.jj 2024-08-01 14:37:23.948824359 +0200
+++ gcc/testsuite/gcc.dg/c23-attr-reproducible-3.c 2024-08-01 14:37:23.948824359 +0200
@@ -0,0 +1,14 @@
+/* Test C23 reproducible attribute: invalid syntax. */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+int a () [[reproducible()]]; /* { dg-error "'reproducible' attribute does not take any arguments" } */
+
+int b () [[reproducible(0)]]; /* { dg-error "expected" } */
+ /* { dg-error "'reproducible' attribute does not take any arguments" "" { target *-*-* } .-1 } */
+
+int c () [[reproducible("", 123)]]; /* { dg-error "expected" } */
+ /* { dg-error "'reproducible' attribute does not take any arguments" "" { target *-*-* } .-1 } */
+
+int d () [[reproducible((""))]]; /* { dg-error "expected" } */
+ /* { dg-error "'reproducible' attribute does not take any arguments" "" { target *-*-* } .-1 } */
--- gcc/testsuite/gcc.dg/c23-attr-reproducible-4.c.jj 2024-08-01 14:37:23.948824359 +0200
+++ gcc/testsuite/gcc.dg/c23-attr-reproducible-4.c 2024-08-01 14:37:23.948824359 +0200
@@ -0,0 +1,12 @@
+/* Test C23 reproducible attribute: duplicates. */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+int a () [[reproducible, __reproducible__]];
+int b () [[__reproducible__, reproducible]];
+int c () [[reproducible, reproducible]];
+int d () [[__reproducible__, __reproducible__]];
+int d () [[reproducible]];
+int d () [[__reproducible__]];
+[[reproducible, reproducible]];
+/* { dg-error "ignored" "ignored" { target *-*-* } .-1 } */
--- gcc/testsuite/gcc.dg/c23-attr-reproducible-5.c.jj 2024-08-01 14:37:23.948824359 +0200
+++ gcc/testsuite/gcc.dg/c23-attr-reproducible-5.c 2024-08-01 14:37:23.948824359 +0200
@@ -0,0 +1,44 @@
+/* Test C23 reproducible attribute: composite type on ?:. */
+/* { dg-do run } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+/* { dg-additional-sources "c23-attr-reproducible-5-aux.c" } */
+
+int f1 () [[reproducible]];
+int f2 ();
+int f3 ();
+int (*fp1) () [[reproducible]] = f2;
+int (*fp2) () [[reproducible]] = f3;
+extern void abort ();
+
+int
+foo (int x)
+{
+ return __builtin_has_attribute (*(x ? f1 : f3), reproducible);
+}
+
+int
+bar (int x)
+{
+ return __builtin_has_attribute (*(x ? fp1 : fp2), reproducible);
+}
+
+int
+baz (int x)
+{
+ return __builtin_has_attribute (*(x ? f3 : f1), reproducible);
+}
+
+int
+qux (int x)
+{
+ return __builtin_has_attribute (*(x ? fp2 : fp1), reproducible);
+}
+
+int
+main ()
+{
+ if (!foo (0) || !bar (0) || !baz (0) || !qux (0))
+ abort ();
+ if (!foo (1) || !bar (1) || !baz (1) || !qux (1))
+ abort ();
+}
--- gcc/testsuite/gcc.dg/c23-attr-reproducible-5-aux.c.jj 2024-08-01 14:37:23.948824359 +0200
+++ gcc/testsuite/gcc.dg/c23-attr-reproducible-5-aux.c 2024-08-01 14:37:23.948824359 +0200
@@ -0,0 +1,21 @@
+/* Auxiliary source for c23-attr-reproducible-5.c test. */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+int
+f1 () [[reproducible]]
+{
+ return 42;
+}
+
+int
+f2 ()
+{
+ return 43;
+}
+
+int
+f3 ()
+{
+ return 44;
+}
--- gcc/testsuite/gcc.dg/c23-attr-unsequenced-1.c.jj 2024-08-01 14:37:23.948824359 +0200
+++ gcc/testsuite/gcc.dg/c23-attr-unsequenced-1.c 2024-08-01 14:37:23.948824359 +0200
@@ -0,0 +1,81 @@
+/* Test C23 unsequenced attribute: valid uses. */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors -O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-times " f1 \\\(\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f2 \\\(\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f12 \\\(\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f13 \\\(\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f3 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f5 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f7 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f8 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f9 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f3 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f5 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f7 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f8 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f9 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump " f3 \\\(52\\\);" "optimized" } } */
+/* { dg-final { scan-tree-dump-times " fp1\.\[0-9]*_\[0-9]* \\\(14\\\);" 1 "optimized" } } */
+
+int f1 () [[unsequenced]];
+int f2 () [[unsequenced]], f3 (int) [[__unsequenced__]];
+int f4 (int, int *restrict) [[unsequenced]];
+int f5 (int) [[unsequenced]];
+int f6 (int);
+int (*fp1) (int) [[unsequenced]] = f6;
+typedef int ft1 (int) [[unsequenced]];
+typedef int ft2 (int);
+extern typeof (f6) [[unsequenced]] f7;
+extern ft2 [[__unsequenced__]] f8;
+int f1 ();
+int f9 (int);
+int f9 (int) [[__unsequenced__]];
+extern int x;
+
+int
+f10 (int x) [[unsequenced]]
+{
+ return x + 42;
+}
+
+int
+f11 (int *restrict x, long long y[restrict static 1], int z) [[__unsequenced__]]
+{
+ x[0] = z;
+ x[1] = z + 1;
+ x[2] = z + 2;
+ *y = z + 3;
+ return z + 4 + f10 (-42);
+}
+
+int f12 () [[unsequenced]];
+int f12 () [[reproducible]];
+int f13 () [[reproducible]];
+int f13 () [[unsequenced]];
+
+int
+g ()
+{
+ int a = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 ();
+ int b = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 ();
+ int c = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int d = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int e = fp1 (14) + fp1 (14);
+ x++;
+ int f = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 ();
+ int g = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 ();
+ int h = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int i = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int j = fp1 (14) + fp1 (14);
+ return a + b + c + d + e + f + g + h + i + j;
+}
+
+int
+h ()
+{
+ f3 (52);
+ f3 (52);
+ f3 (52);
+ return 0;
+}
--- gcc/testsuite/gcc.dg/c23-attr-unsequenced-2.c.jj 2024-08-01 14:37:23.948824359 +0200
+++ gcc/testsuite/gcc.dg/c23-attr-unsequenced-2.c 2024-08-01 14:37:23.948824359 +0200
@@ -0,0 +1,47 @@
+/* Test C23 unsequenced attribute: invalid contexts. */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+/* This attribute is not valid in most cases on types other than
+ type specifiers with function type or function declarators. */
+
+[[unsequenced]]; /* { dg-error "ignored" } */
+
+int [[unsequenced]] var; /* { dg-error "ignored" } */
+
+int array_with_dep_type[2] [[unsequenced]]; /* { dg-error "ignored" } */
+
+[[unsequenced]] int fn1 (); /* { dg-error "standard 'unsequenced' attribute can only be applied to function declarators or type specifiers with function type" } */
+
+[[unsequenced]] int fn2 (), fn3 (); /* { dg-error "standard 'unsequenced' attribute can only be applied to function declarators or type specifiers with function type" } */
+
+int var2 [[unsequenced]]; /* { dg-warning "'unsequenced' attribute only applies to function types" } */
+
+int fn4 [[unsequenced]] (); /* { dg-error "standard 'unsequenced' attribute can only be applied to function declarators or type specifiers with function type" } */
+
+int [[unsequenced]] fn5 (); /* { dg-error "ignored" } */
+
+int z = sizeof (int [[__unsequenced__]]); /* { dg-error "ignored" } */
+
+/* This is valid, but not really useful, as it can't return results
+ in return type nor has any pointer arguments to store results into. */
+void
+fn6 (int x, double y) [[unsequenced]]
+{ /* { dg-warning "unsequenced' attribute on function type without pointer arguments returning 'void'" } */
+ y = x;
+ (void) y;
+}
+
+void
+f (void)
+{
+ int a;
+ [[unsequenced]]; /* { dg-error "ignored" } */
+ [[unsequenced]] a = 1; /* { dg-error "ignored" } */
+ [[unsequenced]] label: ; /* { dg-warning "'unsequenced' attribute only applies to function types" } */
+ switch (var)
+ {
+ [[unsequenced]] case 1: ; /* { dg-warning "'unsequenced' attribute only applies to function types" } */
+ [[unsequenced]] default: ; /* { dg-warning "'unsequenced' attribute only applies to function types" } */
+ }
+}
--- gcc/testsuite/gcc.dg/c23-attr-unsequenced-3.c.jj 2024-08-01 14:37:23.949824346 +0200
+++ gcc/testsuite/gcc.dg/c23-attr-unsequenced-3.c 2024-08-01 14:37:23.949824346 +0200
@@ -0,0 +1,14 @@
+/* Test C23 unsequenced attribute: invalid syntax. */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+int a () [[unsequenced()]]; /* { dg-error "'unsequenced' attribute does not take any arguments" } */
+
+int b () [[unsequenced(0)]]; /* { dg-error "expected" } */
+ /* { dg-error "'unsequenced' attribute does not take any arguments" "" { target *-*-* } .-1 } */
+
+int c () [[unsequenced("", 123)]]; /* { dg-error "expected" } */
+ /* { dg-error "'unsequenced' attribute does not take any arguments" "" { target *-*-* } .-1 } */
+
+int d () [[unsequenced((""))]]; /* { dg-error "expected" } */
+ /* { dg-error "'unsequenced' attribute does not take any arguments" "" { target *-*-* } .-1 } */
--- gcc/testsuite/gcc.dg/c23-attr-unsequenced-4.c.jj 2024-08-01 14:37:23.949824346 +0200
+++ gcc/testsuite/gcc.dg/c23-attr-unsequenced-4.c 2024-08-01 14:37:23.949824346 +0200
@@ -0,0 +1,12 @@
+/* Test C23 unsequenced attribute: duplicates. */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+int a () [[unsequenced, __unsequenced__]];
+int b () [[__unsequenced__, unsequenced]];
+int c () [[unsequenced, unsequenced]];
+int d () [[__unsequenced__, __unsequenced__]];
+int d () [[unsequenced]];
+int d () [[__unsequenced__]];
+[[unsequenced, unsequenced]];
+/* { dg-error "ignored" "ignored" { target *-*-* } .-1 } */
--- gcc/testsuite/gcc.dg/c23-attr-unsequenced-5.c.jj 2024-08-01 14:37:23.949824346 +0200
+++ gcc/testsuite/gcc.dg/c23-attr-unsequenced-5.c 2024-08-01 14:37:23.949824346 +0200
@@ -0,0 +1,44 @@
+/* Test C23 unsequenced attribute: composite type on ?:. */
+/* { dg-do run } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+/* { dg-additional-sources "c23-attr-unsequenced-5-aux.c" } */
+
+int f1 () [[unsequenced]];
+int f2 ();
+int f3 ();
+int (*fp1) () [[unsequenced]] = f2;
+int (*fp2) () [[unsequenced]] = f3;
+extern void abort ();
+
+int
+foo (int x)
+{
+ return __builtin_has_attribute (*(x ? f1 : f3), unsequenced);
+}
+
+int
+bar (int x)
+{
+ return __builtin_has_attribute (*(x ? fp1 : fp2), unsequenced);
+}
+
+int
+baz (int x)
+{
+ return __builtin_has_attribute (*(x ? f3 : f1), unsequenced);
+}
+
+int
+qux (int x)
+{
+ return __builtin_has_attribute (*(x ? fp2 : fp1), unsequenced);
+}
+
+int
+main ()
+{
+ if (!foo (0) || !bar (0) || !baz (0) || !qux (0))
+ abort ();
+ if (!foo (1) || !bar (1) || !baz (1) || !qux (1))
+ abort ();
+}
--- gcc/testsuite/gcc.dg/c23-attr-unsequenced-5-aux.c.jj 2024-08-01 14:37:23.949824346 +0200
+++ gcc/testsuite/gcc.dg/c23-attr-unsequenced-5-aux.c 2024-08-01 14:37:23.949824346 +0200
@@ -0,0 +1,21 @@
+/* Auxiliary source for c23-attr-unsequenced-5.c test. */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+int
+f1 () [[unsequenced]]
+{
+ return 42;
+}
+
+int
+f2 ()
+{
+ return 43;
+}
+
+int
+f3 ()
+{
+ return 44;
+}
--- gcc/testsuite/gcc.dg/c23-has-c-attribute-2.c.jj 2024-08-01 10:30:35.438802424 +0200
+++ gcc/testsuite/gcc.dg/c23-has-c-attribute-2.c 2024-08-01 14:37:24.355819220 +0200
@@ -50,6 +50,22 @@
#error "bad result for ___Noreturn__"
#endif
+#if __has_c_attribute (unsequenced) != 202311L
+#error "bad result for unsequenced"
+#endif
+
+#if __has_c_attribute (__unsequenced__) != 202311L
+#error "bad result for __unsequenced__"
+#endif
+
+#if __has_c_attribute (reproducible) != 202311L
+#error "bad result for reproducible"
+#endif
+
+#if __has_c_attribute (__reproducible__) != 202311L
+#error "bad result for __reproducible__"
+#endif
+
/* Macros in the attribute name are expanded. */
#define foo deprecated
#if __has_c_attribute (foo) != 202311L
Jakub
On Fri, 30 Aug 2024, Jakub Jelinek wrote:
> Here is the full updated patch.
This patch is OK.
@@ -4024,6 +4024,69 @@ diagnosed. Because a pure function cann
effects it does not make sense for such a function to return @code{void}.
Declaring such a function is diagnosed.
+@cindex @code{unsequenced} function type attribute
+@cindex functions that have no side effects
+@item unsequenced
+
+This attribute is a GNU counterpart of the C23 @code{[[unsequenced]]}
+attribute, used to specify function pointers to effectless, idempotent,
+stateless and independent functions according to the C23 definition.
+
+Unlike the standard C23 attribute it can be also specified in attributes
+which appertain to function declarations and applies to the their function
+type even in that case.
+
+Unsequenced functions without pointer or reference arguments are similar
+to functions with the @code{const} attribute, except that @code{const}
+attribute also requires finitness. So, both functions with @code{const}
+and with @code{unsequenced} attributes can be optimized by common
+subexpression elimination, but only functions with @code{const}
+attribute can be optimized by dead code elimination if their result is
+unused or is used only by dead code. Unsequenced functions without pointer
+or reference arguments with @code{void} return type are diagnosed because
+they can't store any results and don't have other observable side-effects
+either.
+
+Unsequenced functions with pointer or reference arguments can inspect
+objects through the passed pointers or references or references to pointers
+or can store additional results through those pointers or references or
+references to pointers.
+
+The @code{unsequenced} attribute imposes greater restrictions than
+the similar @code{reproducible} attribute and fewer restrictions than
+the @code{const} attribute, so during optimization @code{const} has
+precedence over @code{unsequenced} which has precedence over
+@code{reproducible}.
+
+@cindex @code{reproducible} function type attribute
+@cindex functions that have no side effects
+@item reproducible
+
+This attribute is a GNU counterpart of the C23 @code{[[reproducible]]}
+attribute, used to specify function pointers to effectless and idempotent
+functions according to the C23 definition.
+
+Unlike the standard C23 attribute it can be also specified in attributes
+which appertain to function declarations and applies to the their function
+type even in that case.
+
+Reproducible functions without pointer or reference arguments or which do
+not modify objects referenced by those pointer/reference arguments are
+similar to functions with the @code{pure} attribute, except that
+@code{pure} attribute also requires finitness. So, both functions with
+@code{pure} and with @code{reproducible} attributes can be optimized by common
+subexpression elimination if the global state or anything reachable through
+the pointer/reference arguments isn't modified, but only functions with
+@code{pure} attribute can be optimized by dead code elimination if their result is
+unused or is used only by dead code. Reproducible functions without pointer
+or reference arguments with @code{void} return type are diagnosed because
+they can't store any results and don't have other observable side-effects
+either.
+
+Reproducible functions with pointer or reference arguments can store
+additional results through those pointers or references or references to
+pointers.
+
@cindex @code{retain} function attribute
@item retain
For ELF targets that support the GNU or FreeBSD OSABIs, this attribute
@@ -852,6 +852,23 @@ flags_from_decl_or_type (const_tree exp)
flags |= ECF_XTHROW;
flags = special_function_p (exp, flags);
+
+ if ((flags & ECF_CONST) == 0
+ && lookup_attribute ("unsequenced noptr",
+ TYPE_ATTRIBUTES (TREE_TYPE (exp))))
+ {
+ /* [[unsequenced]] with no pointers in arguments is like
+ [[gnu::const]] without finite guarantee. */
+ flags |= ECF_CONST;
+ if ((flags & ECF_PURE) == 0)
+ flags |= ECF_LOOPING_CONST_OR_PURE;
+ }
+ if ((flags & (ECF_CONST | ECF_PURE)) == 0
+ && lookup_attribute ("reproducible noptr",
+ TYPE_ATTRIBUTES (TREE_TYPE (exp))))
+ /* [[reproducible]] with no pointers in arguments is like
+ [[gnu::pure]] without finite guarantee. */
+ flags |= ECF_PURE | ECF_LOOPING_CONST_OR_PURE;
}
else if (TYPE_P (exp))
{
@@ -862,6 +879,17 @@ flags_from_decl_or_type (const_tree exp)
&& ((flags & ECF_CONST) != 0
|| lookup_attribute ("transaction_pure", TYPE_ATTRIBUTES (exp))))
flags |= ECF_TM_PURE;
+
+ if ((flags & ECF_CONST) == 0
+ && lookup_attribute ("unsequenced noptr", TYPE_ATTRIBUTES (exp)))
+ /* [[unsequenced]] with no pointers in arguments is like
+ [[gnu::const]] without finite guarantee. */
+ flags |= ECF_CONST | ECF_LOOPING_CONST_OR_PURE;
+ if ((flags & ECF_CONST) == 0
+ && lookup_attribute ("reproducible noptr", TYPE_ATTRIBUTES (exp)))
+ /* [[reproducible]] with no pointers in arguments is like
+ [[gnu::pure]] without finite guarantee. */
+ flags |= ECF_PURE | ECF_LOOPING_CONST_OR_PURE;
}
else
gcc_unreachable ();
@@ -444,6 +444,14 @@ const struct attribute_spec c_common_gnu
{ "pure", 0, 0, true, false, false, false,
handle_pure_attribute,
attr_const_pure_exclusions },
+ { "reproducible", 0, 0, false, true, true, false,
+ handle_reproducible_attribute, NULL },
+ { "unsequenced", 0, 0, false, true, true, false,
+ handle_unsequenced_attribute, NULL },
+ { "reproducible noptr", 0, 0, false, true, true, false,
+ handle_reproducible_attribute, NULL },
+ { "unsequenced noptr", 0, 0, false, true, true, false,
+ handle_unsequenced_attribute, NULL },
{ "transaction_callable", 0, 0, false, true, false, false,
handle_tm_attribute, NULL },
{ "transaction_unsafe", 0, 0, false, true, false, true,
@@ -4280,6 +4288,53 @@ handle_pure_attribute (tree *node, tree
return NULL_TREE;
}
+/* Handle an "unsequenced" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+tree
+handle_unsequenced_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int flags, bool *no_add_attrs)
+{
+ tree fntype = *node;
+ for (tree argtype = TYPE_ARG_TYPES (fntype); argtype;
+ argtype = TREE_CHAIN (argtype))
+ /* If any of the arguments have pointer or reference type, just
+ add the attribute alone. */
+ if (POINTER_TYPE_P (TREE_VALUE (argtype)))
+ return NULL_TREE;
+
+ if (VOID_TYPE_P (TREE_TYPE (fntype)))
+ warning (OPT_Wattributes, "%qE attribute on function type "
+ "without pointer arguments returning %<void%>", name);
+ const char *name2;
+ if (IDENTIFIER_LENGTH (name) == sizeof ("unsequenced") - 1)
+ name2 = "unsequenced noptr";
+ else
+ name2 = "reproducible noptr";
+ if (!lookup_attribute (name2, TYPE_ATTRIBUTES (fntype)))
+ {
+ *no_add_attrs = true;
+ gcc_assert ((flags & (int) ATTR_FLAG_TYPE_IN_PLACE) == 0);
+ tree attr = tree_cons (get_identifier (name2), NULL_TREE,
+ TYPE_ATTRIBUTES (fntype));
+ if (!lookup_attribute (IDENTIFIER_POINTER (name),
+ TYPE_ATTRIBUTES (fntype)))
+ attr = tree_cons (name, NULL_TREE, attr);
+ *node = build_type_attribute_variant (*node, attr);
+ }
+ return NULL_TREE;
+}
+
+/* Handle a "reproducible" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+tree
+handle_reproducible_attribute (tree *node, tree name, tree args, int flags,
+ bool *no_add_attrs)
+{
+ return handle_unsequenced_attribute (node, name, args, flags, no_add_attrs);
+}
+
/* Digest an attribute list destined for a transactional memory statement.
ALLOWED is the set of attributes that are allowed for this statement;
return the attribute we parsed. Multiple attributes are never allowed. */
@@ -864,6 +864,8 @@ extern void check_function_format (const
extern bool attribute_fallthrough_p (tree);
extern tree handle_format_attribute (tree *, tree, tree, int, bool *);
extern tree handle_format_arg_attribute (tree *, tree, tree, int, bool *);
+extern tree handle_unsequenced_attribute (tree *, tree, tree, int, bool *);
+extern tree handle_reproducible_attribute (tree *, tree, tree, int, bool *);
extern bool c_common_handle_option (size_t, const char *, HOST_WIDE_INT, int,
location_t,
const struct cl_option_handlers *);
@@ -445,7 +445,9 @@ c_common_has_attribute (cpp_reader *pfil
|| is_attribute_p ("maybe_unused", attr_name)
|| is_attribute_p ("nodiscard", attr_name)
|| is_attribute_p ("noreturn", attr_name)
- || is_attribute_p ("_Noreturn", attr_name))
+ || is_attribute_p ("_Noreturn", attr_name)
+ || is_attribute_p ("reproducible", attr_name)
+ || is_attribute_p ("unsequenced", attr_name))
result = 202311;
}
if (result)
@@ -4702,6 +4702,39 @@ handle_std_noreturn_attribute (tree *nod
}
}
+/* Handle the standard [[unsequenced]] attribute. */
+
+static tree
+handle_std_unsequenced_attribute (tree *node, tree name, tree args,
+ int flags, bool *no_add_attrs)
+{
+ /* Unlike GNU __attribute__ ((unsequenced)), the standard [[unsequenced]]
+ should be only applied to function declarators or type specifiers which
+ have function type. */
+ if (node[2])
+ {
+ auto_diagnostic_group d;
+ if (pedwarn (input_location, OPT_Wattributes,
+ "standard %qE attribute can only be applied to function "
+ "declarators or type specifiers with function type", name))
+ inform (input_location, "did you mean to specify it after %<)%> "
+ "following function parameters?");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ return handle_unsequenced_attribute (node, name, args, flags, no_add_attrs);
+}
+
+/* Handle the standard [[reproducible]] attribute. */
+
+static tree
+handle_std_reproducible_attribute (tree *node, tree name, tree args,
+ int flags, bool *no_add_attrs)
+{
+ return handle_std_unsequenced_attribute (node, name, args, flags,
+ no_add_attrs);
+}
+
/* Table of supported standard (C23) attributes. */
static const attribute_spec std_attributes[] =
{
@@ -4718,7 +4751,11 @@ static const attribute_spec std_attribut
{ "nodiscard", 0, 1, false, false, false, false,
handle_nodiscard_attribute, NULL },
{ "noreturn", 0, 0, false, false, false, false,
- handle_std_noreturn_attribute, NULL }
+ handle_std_noreturn_attribute, NULL },
+ { "reproducible", 0, 0, false, true, true, false,
+ handle_std_reproducible_attribute, NULL },
+ { "unsequenced", 0, 0, false, true, true, false,
+ handle_std_unsequenced_attribute, NULL }
};
const scoped_attribute_specs std_attribute_table =
@@ -4911,12 +4948,24 @@ c_warn_unused_attributes (tree attrs)
list of attributes with them removed. */
tree
-c_warn_type_attributes (tree attrs)
+c_warn_type_attributes (tree type, tree attrs)
{
tree *attr_ptr = &attrs;
while (*attr_ptr)
if (get_attribute_namespace (*attr_ptr) == NULL_TREE)
{
+ if (TREE_CODE (type) == FUNCTION_TYPE)
+ {
+ tree name = get_attribute_name (*attr_ptr);
+ /* [[unsequenced]] and [[reproducible]] is fine on function
+ types that aren't being defined. */
+ if (is_attribute_p ("unsequenced", name)
+ || is_attribute_p ("reproducible", name))
+ {
+ attr_ptr = &TREE_CHAIN (*attr_ptr);
+ continue;
+ }
+ }
pedwarn (input_location, OPT_Wattributes, "%qE attribute ignored",
get_attribute_name (*attr_ptr));
*attr_ptr = TREE_CHAIN (*attr_ptr);
@@ -5386,7 +5435,7 @@ groktypename (struct c_type_name *type_n
DEPRECATED_NORMAL);
/* Apply attributes. */
- attrs = c_warn_type_attributes (attrs);
+ attrs = c_warn_type_attributes (type, attrs);
decl_attributes (&type, attrs, 0);
return type;
@@ -7196,7 +7245,7 @@ grokdeclarator (const struct c_declarato
else if (inner_decl->kind == cdk_array)
attr_flags |= (int) ATTR_FLAG_ARRAY_NEXT;
}
- attrs = c_warn_type_attributes (attrs);
+ attrs = c_warn_type_attributes (type, attrs);
returned_attrs = decl_attributes (&type,
chainon (returned_attrs, attrs),
attr_flags);
@@ -13433,7 +13482,8 @@ finish_declspecs (struct c_declspecs *sp
handle_postfix_attrs:
if (specs->type != NULL)
{
- specs->postfix_attrs = c_warn_type_attributes (specs->postfix_attrs);
+ specs->postfix_attrs
+ = c_warn_type_attributes (specs->type, specs->postfix_attrs);
decl_attributes (&specs->type, specs->postfix_attrs, 0);
specs->postfix_attrs = NULL_TREE;
}
@@ -2677,8 +2677,9 @@ c_parser_declaration_or_fndef (c_parser
/* Postfix [[]] attributes are valid with C23
auto, although not with __auto_type, and
modify the type given by the initializer. */
- specs->postfix_attrs =
- c_warn_type_attributes (specs->postfix_attrs);
+ specs->postfix_attrs
+ = c_warn_type_attributes (specs->type,
+ specs->postfix_attrs);
decl_attributes (&specs->type, specs->postfix_attrs, 0);
specs->postfix_attrs = NULL_TREE;
}
@@ -680,7 +680,7 @@ 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 tree c_warn_type_attributes (tree);
+extern tree c_warn_type_attributes (tree, 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, tree,
@@ -0,0 +1,80 @@
+/* Test gnu::reproducible attribute: valid uses. */
+/* { dg-do compile { target { c || c++11 } } } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-additional-options "-std=gnu23" { target c } } */
+/* { dg-final { scan-tree-dump-times " f1 \\\(\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f2 \\\(\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f3 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f5 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f7 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f8 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f9 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f3 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f5 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f7 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f8 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f9 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump " f3 \\\(52\\\);" "optimized" } } */
+/* { dg-final { scan-tree-dump-times " fp1\.\[0-9]*_\[0-9]* \\\(14\\\);" 2 "optimized" } } */
+
+int f1 () [[gnu::reproducible]];
+int f2 () [[gnu::reproducible]], f3 (int) [[__gnu__::__reproducible__]];
+int f4 (int, int *) [[gnu::reproducible]];
+int f5 (int) [[gnu::reproducible]];
+int f6 (int);
+int (*fp1) (int) [[gnu::reproducible]] = f6;
+typedef int ft1 (int) [[gnu::reproducible]];
+typedef int ft2 (int);
+#ifndef __cplusplus
+extern __typeof (f6) [[gnu::reproducible]] f7;
+extern ft2 [[__gnu__::__reproducible__]] f8;
+#else
+int f7 (int) [[gnu::reproducible, gnu::reproducible]];
+int f8 (int) [[__gnu__::reproducible, gnu::__reproducible__]];
+#endif
+int f1 ();
+int f9 (int);
+int f9 (int) [[__gnu__::__reproducible__]];
+extern int x;
+
+int
+f10 (int w) [[gnu::reproducible]]
+{
+ return w + 42 + x;
+}
+
+int
+f11 (int *w, long long y[1], int z) [[__gnu__::__reproducible__]]
+{
+ w[0] = z + x;
+ w[1] = z + x + 1;
+ w[2] = z + x + 2;
+ *y = z + x + 3;
+ return z + 4 + f10 (-42);
+}
+
+int
+g ()
+{
+ int a = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42);
+ int b = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42);
+ int c = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int d = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int e = fp1 (14) + fp1 (14);
+ x++;
+ int f = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42);
+ int g = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42);
+ int h = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int i = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int j = fp1 (14) + fp1 (14);
+ return a + b + c + d + e + f + g + h + i + j;
+}
+
+int
+h ()
+{
+ f3 (52);
+ f3 (52);
+ f3 (52);
+ return 0;
+}
@@ -0,0 +1,74 @@
+/* Test reproducible attribute: valid uses. */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-times " f1 \\\(\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f2 \\\(\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f3 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f5 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f7 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f8 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f9 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f3 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f5 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f7 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f8 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f9 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump " f3 \\\(52\\\);" "optimized" } } */
+/* { dg-final { scan-tree-dump-times " fp1\.\[0-9]*_\[0-9]* \\\(14\\\);" 2 "optimized" } } */
+
+__attribute__((reproducible)) int f1 (void);
+__attribute__((__reproducible__)) int f2 (void), f3 (int);
+int f4 (int, int *) __attribute__((reproducible));
+int f5 (int) __attribute__((reproducible));
+int f6 (int);
+int (*fp1) (int) __attribute__((reproducible)) = f6;
+typedef int ft1 (int) __attribute__((reproducible));
+typedef int ft2 (int);
+extern __typeof (f6) __attribute__((reproducible)) f7;
+extern ft2 __attribute__((__reproducible__)) f8;
+int f1 (void);
+int f9 (int);
+int f9 (int) __attribute__((__reproducible__));
+extern int x;
+
+__attribute__((reproducible)) int
+f10 (int w)
+{
+ return w + 42 + x;
+}
+
+__attribute__((reproducible)) int
+f11 (int *w, long long y[1], int z)
+{
+ w[0] = z + x;
+ w[1] = z + x + 1;
+ w[2] = z + x + 2;
+ *y = z + x + 3;
+ return z + 4 + f10 (-42);
+}
+
+int
+g (void)
+{
+ int a = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42);
+ int b = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42);
+ int c = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int d = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int e = fp1 (14) + fp1 (14);
+ x++;
+ int f = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42);
+ int g = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42);
+ int h = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int i = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int j = fp1 (14) + fp1 (14);
+ return a + b + c + d + e + f + g + h + i + j;
+}
+
+int
+h (void)
+{
+ f3 (52);
+ f3 (52);
+ f3 (52);
+ return 0;
+}
@@ -0,0 +1,87 @@
+/* Test gnu::unsequenced attribute: valid uses. */
+/* { dg-do compile { target { c || c++11 } } } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-additional-options "-std=gnu23" { target c } } */
+/* { dg-final { scan-tree-dump-times " f1 \\\(\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f2 \\\(\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f12 \\\(\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f13 \\\(\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f3 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f5 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f7 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f8 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f9 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f3 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f5 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f7 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f8 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f9 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump " f3 \\\(52\\\);" "optimized" } } */
+/* { dg-final { scan-tree-dump-times " fp1\.\[0-9]*_\[0-9]* \\\(14\\\);" 1 "optimized" } } */
+
+[[gnu::unsequenced]] int f1 ();
+[[gnu::unsequenced]] int f2 (), f3 (int);
+int f4 (int, int *) [[gnu::unsequenced]];
+int f5 (int) [[gnu::unsequenced]];
+int f6 (int);
+int (*fp1) (int) [[gnu::unsequenced]] = f6;
+typedef int ft1 (int) [[gnu::unsequenced]];
+typedef int ft2 (int);
+#ifndef __cplusplus
+extern __typeof (f6) [[gnu::unsequenced]] f7;
+extern ft2 [[__gnu__::__unsequenced__]] f8;
+#else
+int f7 (int) [[gnu::unsequenced, gnu::unsequenced]];
+int f8 (int) [[__gnu__::unsequenced, gnu::__unsequenced__]];
+#endif
+int f1 ();
+int f9 (int);
+int f9 (int) [[__gnu__::__unsequenced__]];
+extern int x;
+
+int
+f10 (int x) [[gnu::unsequenced]]
+{
+ return x + 42;
+}
+
+int
+f11 (int *x, long long y[1], int z) [[__gnu__::__unsequenced__]]
+{
+ x[0] = z;
+ x[1] = z + 1;
+ x[2] = z + 2;
+ *y = z + 3;
+ return z + 4 + f10 (-42);
+}
+
+int f12 () [[gnu::unsequenced]];
+int f12 () [[gnu::reproducible]];
+int f13 () [[gnu::reproducible]];
+int f13 () [[gnu::unsequenced]];
+
+int
+g ()
+{
+ int a = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 ();
+ int b = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 ();
+ int c = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int d = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int e = fp1 (14) + fp1 (14);
+ x++;
+ int f = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 ();
+ int g = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 ();
+ int h = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int i = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int j = fp1 (14) + fp1 (14);
+ return a + b + c + d + e + f + g + h + i + j;
+}
+
+int
+h ()
+{
+ f3 (52);
+ f3 (52);
+ f3 (52);
+ return 0;
+}
@@ -0,0 +1,81 @@
+/* Test unsequenced attribute: valid uses. */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-times " f1 \\\(\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f2 \\\(\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f12 \\\(\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f13 \\\(\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f3 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f5 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f7 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f8 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f9 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f3 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f5 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f7 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f8 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f9 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump " f3 \\\(52\\\);" "optimized" } } */
+/* { dg-final { scan-tree-dump-times " fp1\.\[0-9]*_\[0-9]* \\\(14\\\);" 1 "optimized" } } */
+
+__attribute__((unsequenced)) int f1 (void);
+__attribute__((unsequenced)) int f2 (void), f3 (int);
+int f4 (int, int *) __attribute__((unsequenced));
+int f5 (int) __attribute__((unsequenced));
+int f6 (int);
+int (*fp1) (int) __attribute__((unsequenced)) = f6;
+typedef int ft1 (int) __attribute__((unsequenced));
+typedef int ft2 (int);
+extern __typeof (f6) __attribute__((unsequenced)) f7;
+extern ft2 __attribute__((__unsequenced__)) f8;
+int f1 (void);
+int f9 (int);
+int f9 (int) __attribute__((__unsequenced__));
+extern int x;
+
+__attribute__((unsequenced)) int
+f10 (int x)
+{
+ return x + 42;
+}
+
+__attribute__((__unsequenced__)) int
+f11 (int *x, long long y[1], int z)
+{
+ x[0] = z;
+ x[1] = z + 1;
+ x[2] = z + 2;
+ *y = z + 3;
+ return z + 4 + f10 (-42);
+}
+
+int f12 (void) __attribute__((unsequenced));
+int f12 (void) __attribute__((reproducible));
+int f13 (void) __attribute__((reproducible));
+int f13 (void) __attribute__((unsequenced));
+
+int
+g (void)
+{
+ int a = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 ();
+ int b = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 ();
+ int c = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int d = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int e = fp1 (14) + fp1 (14);
+ x++;
+ int f = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 ();
+ int g = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 ();
+ int h = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int i = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int j = fp1 (14) + fp1 (14);
+ return a + b + c + d + e + f + g + h + i + j;
+}
+
+int
+h (void)
+{
+ f3 (52);
+ f3 (52);
+ f3 (52);
+ return 0;
+}
@@ -0,0 +1,74 @@
+/* Test C23 reproducible attribute: valid uses. */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors -O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-times " f1 \\\(\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f2 \\\(\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f3 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f5 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f7 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f8 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f9 \\\(42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f3 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f5 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f7 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f8 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f9 \\\(-42\\\);" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump " f3 \\\(52\\\);" "optimized" } } */
+/* { dg-final { scan-tree-dump-times " fp1\.\[0-9]*_\[0-9]* \\\(14\\\);" 2 "optimized" } } */
+
+int f1 () [[reproducible]];
+int f2 () [[reproducible]], f3 (int) [[__reproducible__]];
+int f4 (int, int *restrict) [[reproducible]];
+int f5 (int) [[reproducible]];
+int f6 (int);
+int (*fp1) (int) [[reproducible]] = f6;
+typedef int ft1 (int) [[reproducible]];
+typedef int ft2 (int);
+extern typeof (f6) [[reproducible]] f7;
+extern ft2 [[__reproducible__]] f8;
+int f1 ();
+int f9 (int);
+int f9 (int) [[__reproducible__]];
+extern int x;
+
+int
+f10 (int w) [[reproducible]]
+{
+ return w + 42 + x;
+}
+
+int
+f11 (int *restrict w, long long y[restrict static 1], int z) [[__reproducible__]]
+{
+ w[0] = z + x;
+ w[1] = z + x + 1;
+ w[2] = z + x + 2;
+ *y = z + x + 3;
+ return z + 4 + f10 (-42);
+}
+
+int
+g ()
+{
+ int a = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42);
+ int b = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42);
+ int c = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int d = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int e = fp1 (14) + fp1 (14);
+ x++;
+ int f = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42);
+ int g = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42);
+ int h = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int i = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int j = fp1 (14) + fp1 (14);
+ return a + b + c + d + e + f + g + h + i + j;
+}
+
+int
+h ()
+{
+ f3 (52);
+ f3 (52);
+ f3 (52);
+ return 0;
+}
@@ -0,0 +1,47 @@
+/* Test C23 reproducible attribute: invalid contexts. */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+/* This attribute is not valid in most cases on types other than
+ type specifiers with function type or function declarators. */
+
+[[reproducible]]; /* { dg-error "ignored" } */
+
+int [[reproducible]] var; /* { dg-error "ignored" } */
+
+int array_with_dep_type[2] [[reproducible]]; /* { dg-error "ignored" } */
+
+[[reproducible]] int fn1 (); /* { dg-error "standard 'reproducible' attribute can only be applied to function declarators or type specifiers with function type" } */
+
+[[reproducible]] int fn2 (), fn3 (); /* { dg-error "standard 'reproducible' attribute can only be applied to function declarators or type specifiers with function type" } */
+
+int var2 [[reproducible]]; /* { dg-warning "'reproducible' attribute only applies to function types" } */
+
+int fn4 [[reproducible]] (); /* { dg-error "standard 'reproducible' attribute can only be applied to function declarators or type specifiers with function type" } */
+
+int [[reproducible]] fn5 (); /* { dg-error "ignored" } */
+
+int z = sizeof (int [[__reproducible__]]); /* { dg-error "ignored" } */
+
+/* This is valid, but not really useful, as it can't return results
+ in return type nor has any pointer arguments to store results into. */
+void
+fn6 (int x, double y) [[reproducible]]
+{ /* { dg-warning "reproducible' attribute on function type without pointer arguments returning 'void'" } */
+ y = x;
+ (void) y;
+}
+
+void
+f (void)
+{
+ int a;
+ [[reproducible]]; /* { dg-error "ignored" } */
+ [[reproducible]] a = 1; /* { dg-error "ignored" } */
+ [[reproducible]] label: ; /* { dg-warning "'reproducible' attribute only applies to function types" } */
+ switch (var)
+ {
+ [[reproducible]] case 1: ; /* { dg-warning "'reproducible' attribute only applies to function types" } */
+ [[reproducible]] default: ; /* { dg-warning "'reproducible' attribute only applies to function types" } */
+ }
+}
@@ -0,0 +1,14 @@
+/* Test C23 reproducible attribute: invalid syntax. */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+int a () [[reproducible()]]; /* { dg-error "'reproducible' attribute does not take any arguments" } */
+
+int b () [[reproducible(0)]]; /* { dg-error "expected" } */
+ /* { dg-error "'reproducible' attribute does not take any arguments" "" { target *-*-* } .-1 } */
+
+int c () [[reproducible("", 123)]]; /* { dg-error "expected" } */
+ /* { dg-error "'reproducible' attribute does not take any arguments" "" { target *-*-* } .-1 } */
+
+int d () [[reproducible((""))]]; /* { dg-error "expected" } */
+ /* { dg-error "'reproducible' attribute does not take any arguments" "" { target *-*-* } .-1 } */
@@ -0,0 +1,12 @@
+/* Test C23 reproducible attribute: duplicates (allowed after N2557). */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+int a () [[reproducible, __reproducible__]];
+int b () [[__reproducible__, reproducible]];
+int c () [[reproducible, reproducible]];
+int d () [[__reproducible__, __reproducible__]];
+int d () [[reproducible]];
+int d () [[__reproducible__]];
+[[reproducible, reproducible]];
+/* { dg-error "ignored" "ignored" { target *-*-* } .-1 } */
@@ -0,0 +1,44 @@
+/* Test C23 reproducible attribute: composite type on ?:. */
+/* { dg-do run } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+/* { dg-additional-sources "c23-attr-reproducible-6.c" } */
+
+int f1 () [[reproducible]];
+int f2 ();
+int f3 ();
+int (*fp1) () [[reproducible]] = f2;
+int (*fp2) () [[reproducible]] = f3;
+extern void abort ();
+
+int
+foo (int x)
+{
+ return __builtin_has_attribute (*(x ? f1 : f3), reproducible);
+}
+
+int
+bar (int x)
+{
+ return __builtin_has_attribute (*(x ? fp1 : fp2), reproducible);
+}
+
+int
+baz (int x)
+{
+ return __builtin_has_attribute (*(x ? f3 : f1), reproducible);
+}
+
+int
+qux (int x)
+{
+ return __builtin_has_attribute (*(x ? fp2 : fp1), reproducible);
+}
+
+int
+main ()
+{
+ if (!foo (0) || !bar (0) || !baz (0) || !qux (0))
+ abort ();
+ if (!foo (1) || !bar (1) || !baz (1) || !qux (1))
+ abort ();
+}
@@ -0,0 +1,21 @@
+/* Test C23 reproducible attribute: composite type on ?:. */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+int
+f1 () [[reproducible]]
+{
+ return 42;
+}
+
+int
+f2 ()
+{
+ return 43;
+}
+
+int
+f3 ()
+{
+ return 44;
+}
@@ -0,0 +1,81 @@
+/* Test C23 unsequenced attribute: valid uses. */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors -O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-times " f1 \\\(\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f2 \\\(\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f12 \\\(\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f13 \\\(\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f3 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f5 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f7 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f8 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f9 \\\(42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f3 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f5 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f7 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f8 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " f9 \\\(-42\\\);" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump " f3 \\\(52\\\);" "optimized" } } */
+/* { dg-final { scan-tree-dump-times " fp1\.\[0-9]*_\[0-9]* \\\(14\\\);" 1 "optimized" } } */
+
+int f1 () [[unsequenced]];
+int f2 () [[unsequenced]], f3 (int) [[__unsequenced__]];
+int f4 (int, int *restrict) [[unsequenced]];
+int f5 (int) [[unsequenced]];
+int f6 (int);
+int (*fp1) (int) [[unsequenced]] = f6;
+typedef int ft1 (int) [[unsequenced]];
+typedef int ft2 (int);
+extern typeof (f6) [[unsequenced]] f7;
+extern ft2 [[__unsequenced__]] f8;
+int f1 ();
+int f9 (int);
+int f9 (int) [[__unsequenced__]];
+extern int x;
+
+int
+f10 (int x) [[unsequenced]]
+{
+ return x + 42;
+}
+
+int
+f11 (int *restrict x, long long y[restrict static 1], int z) [[__unsequenced__]]
+{
+ x[0] = z;
+ x[1] = z + 1;
+ x[2] = z + 2;
+ *y = z + 3;
+ return z + 4 + f10 (-42);
+}
+
+int f12 () [[unsequenced]];
+int f12 () [[reproducible]];
+int f13 () [[reproducible]];
+int f13 () [[unsequenced]];
+
+int
+g ()
+{
+ int a = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 ();
+ int b = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 ();
+ int c = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int d = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int e = fp1 (14) + fp1 (14);
+ x++;
+ int f = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 ();
+ int g = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 ();
+ int h = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int i = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42);
+ int j = fp1 (14) + fp1 (14);
+ return a + b + c + d + e + f + g + h + i + j;
+}
+
+int
+h ()
+{
+ f3 (52);
+ f3 (52);
+ f3 (52);
+ return 0;
+}
@@ -0,0 +1,47 @@
+/* Test C23 unsequenced attribute: invalid contexts. */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+/* This attribute is not valid in most cases on types other than
+ type specifiers with function type or function declarators. */
+
+[[unsequenced]]; /* { dg-error "ignored" } */
+
+int [[unsequenced]] var; /* { dg-error "ignored" } */
+
+int array_with_dep_type[2] [[unsequenced]]; /* { dg-error "ignored" } */
+
+[[unsequenced]] int fn1 (); /* { dg-error "standard 'unsequenced' attribute can only be applied to function declarators or type specifiers with function type" } */
+
+[[unsequenced]] int fn2 (), fn3 (); /* { dg-error "standard 'unsequenced' attribute can only be applied to function declarators or type specifiers with function type" } */
+
+int var2 [[unsequenced]]; /* { dg-warning "'unsequenced' attribute only applies to function types" } */
+
+int fn4 [[unsequenced]] (); /* { dg-error "standard 'unsequenced' attribute can only be applied to function declarators or type specifiers with function type" } */
+
+int [[unsequenced]] fn5 (); /* { dg-error "ignored" } */
+
+int z = sizeof (int [[__unsequenced__]]); /* { dg-error "ignored" } */
+
+/* This is valid, but not really useful, as it can't return results
+ in return type nor has any pointer arguments to store results into. */
+void
+fn6 (int x, double y) [[unsequenced]]
+{ /* { dg-warning "unsequenced' attribute on function type without pointer arguments returning 'void'" } */
+ y = x;
+ (void) y;
+}
+
+void
+f (void)
+{
+ int a;
+ [[unsequenced]]; /* { dg-error "ignored" } */
+ [[unsequenced]] a = 1; /* { dg-error "ignored" } */
+ [[unsequenced]] label: ; /* { dg-warning "'unsequenced' attribute only applies to function types" } */
+ switch (var)
+ {
+ [[unsequenced]] case 1: ; /* { dg-warning "'unsequenced' attribute only applies to function types" } */
+ [[unsequenced]] default: ; /* { dg-warning "'unsequenced' attribute only applies to function types" } */
+ }
+}
@@ -0,0 +1,14 @@
+/* Test C23 unsequenced attribute: invalid syntax. */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+int a () [[unsequenced()]]; /* { dg-error "'unsequenced' attribute does not take any arguments" } */
+
+int b () [[unsequenced(0)]]; /* { dg-error "expected" } */
+ /* { dg-error "'unsequenced' attribute does not take any arguments" "" { target *-*-* } .-1 } */
+
+int c () [[unsequenced("", 123)]]; /* { dg-error "expected" } */
+ /* { dg-error "'unsequenced' attribute does not take any arguments" "" { target *-*-* } .-1 } */
+
+int d () [[unsequenced((""))]]; /* { dg-error "expected" } */
+ /* { dg-error "'unsequenced' attribute does not take any arguments" "" { target *-*-* } .-1 } */
@@ -0,0 +1,12 @@
+/* Test C23 unsequenced attribute: duplicates (allowed after N2557). */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+int a () [[unsequenced, __unsequenced__]];
+int b () [[__unsequenced__, unsequenced]];
+int c () [[unsequenced, unsequenced]];
+int d () [[__unsequenced__, __unsequenced__]];
+int d () [[unsequenced]];
+int d () [[__unsequenced__]];
+[[unsequenced, unsequenced]];
+/* { dg-error "ignored" "ignored" { target *-*-* } .-1 } */
@@ -0,0 +1,44 @@
+/* Test C23 unsequenced attribute: composite type on ?:. */
+/* { dg-do run } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+/* { dg-additional-sources "c23-attr-unsequenced-6.c" } */
+
+int f1 () [[unsequenced]];
+int f2 ();
+int f3 ();
+int (*fp1) () [[unsequenced]] = f2;
+int (*fp2) () [[unsequenced]] = f3;
+extern void abort ();
+
+int
+foo (int x)
+{
+ return __builtin_has_attribute (*(x ? f1 : f3), unsequenced);
+}
+
+int
+bar (int x)
+{
+ return __builtin_has_attribute (*(x ? fp1 : fp2), unsequenced);
+}
+
+int
+baz (int x)
+{
+ return __builtin_has_attribute (*(x ? f3 : f1), unsequenced);
+}
+
+int
+qux (int x)
+{
+ return __builtin_has_attribute (*(x ? fp2 : fp1), unsequenced);
+}
+
+int
+main ()
+{
+ if (!foo (0) || !bar (0) || !baz (0) || !qux (0))
+ abort ();
+ if (!foo (1) || !bar (1) || !baz (1) || !qux (1))
+ abort ();
+}
@@ -0,0 +1,21 @@
+/* Test C23 unsequenced attribute: composite type on ?:. */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+int
+f1 () [[unsequenced]]
+{
+ return 42;
+}
+
+int
+f2 ()
+{
+ return 43;
+}
+
+int
+f3 ()
+{
+ return 44;
+}
@@ -50,6 +50,22 @@
#error "bad result for ___Noreturn__"
#endif
+#if __has_c_attribute (unsequenced) != 202311L
+#error "bad result for unsequenced"
+#endif
+
+#if __has_c_attribute (__unsequenced__) != 202311L
+#error "bad result for __unsequenced__"
+#endif
+
+#if __has_c_attribute (reproducible) != 202311L
+#error "bad result for reproducible"
+#endif
+
+#if __has_c_attribute (__reproducible__) != 202311L
+#error "bad result for __reproducible__"
+#endif
+
/* Macros in the attribute name are expanded. */
#define foo deprecated
#if __has_c_attribute (foo) != 202311L