Message ID | ZqvRzY2skChYEVk1@tucnak |
---|---|
State | New |
Headers | show |
Series | c, v2: Add support for unsequenced and reproducible attributes | expand |
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.
--- 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 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 --- 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 (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 } */ --- 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-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 (); +} --- 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; +} --- 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 (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 } */ --- 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-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 (); +} --- 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; +} --- 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