On Tue, Jul 30, 2024 at 7:05 PM Jakub Jelinek <ja...@redhat.com> wrote: > > Hi! > > C23 added in N2956 ( https://open-std.org/JTC1/SC22/WG14/www/docs/n2956.htm ) > two new attributes, which are described as similar to GCC const and pure > attributes, but they aren't really same and it seems that even the paper > is missing some of the differences. > The paper says unsequenced is the same as const on functions without pointer > arguments and reproducible is the same as pure on such functions (except > that they are function type attributes rather than function > declaration ones), but it seems the paper doesn't consider the finiteness GCC > relies on (aka non-DECL_LOOPING_CONST_OR_PURE_P) - the paper only talks > about using the attributes for CSE etc., not for DCE. > > The following patch introduces (for now limited) support for those > attributes, both as standard C23 attributes and as GNU extensions (the > difference is that the patch is then less strict on where it allows them, > like other function type attributes they can be specified on function > declarations as well and apply to the type, while C23 standard ones must > go on the function declarators (i.e. after closing paren after function > parameters) or in type specifiers of function type. > > If function doesn't have any pointer/reference arguments (I wasn't sure > whether it must be really just pure pointer arguments or whether say > struct S { int s; int *p; } passed by value, or unions, or perhaps just > transparent unions count, and whether variadic functions which can take > pointer va_arg count too, so the check punts on all of those), the patch > adds additional internal attribute with " noptr" suffix which then is used > by flags_from_decl_or_type to handle those easy cases as > ECF_CONST|ECF_LOOPING_CONST_OR_PURE or > ECF_PURE|ECF_LOOPING_CONST_OR_PURE > The harder cases aren't handled right now, I'd hope they can be handled > incrementally. > > I wonder whether we shouldn't emit a warning for the > gcc.dg/c23-attr-{reproducible,unsequenced}-5.c cases, while the standard > clearly specifies that composite types should union the attributes and it > is what GCC implements for decades, for ?: that feels dangerous for the > new attributes, it would be much better to be conservative on say > (cond ? unsequenced_function : normal_function) (args) > > There is no diagnostics on incorrect [[unsequenced]] or [[reproducible]] > function definitions, while I think diagnosing non-const static/TLS > declarations in the former could be easy, the rest feels hard. E.g. the > const/pure discovery can just punt on everything it doesn't understand, > but complete diagnostics would need to understand it. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
I wonder if int foo (uintrptr_t x) { *(int *)x = 1; return 1; } is considered "noptr" by the standard but then by making a pointer out of 'x' invokes UB? One more comment below. > 2024-07-30 Jakub Jelinek <ja...@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. > (c_maybe_contains_pointers_p): New function. > (handle_unsequenced_attribute): Likewise. > (handle_reproducible_attribute): Likewise. > * c-common.h (handle_unsequenced_attribute): Declare. > (handle_reproducible_attribute): Likewise. > * c-lex.cc (c_common_has_attribute): Return 202311 for standard > unsequenced and reproducible attributes. > gcc/c/ > * c-decl.cc (handle_std_unsequenced_attribute): New function. > (handle_std_reproducible_attribute): Likewise. > (std_attributes): Add entries for "unsequenced" and "reproducible" > attributes. > (c_warn_type_attributes): Add TYPE argument. Allow unsequenced > or reproducible attributes if it is FUNCTION_TYPE. > (groktypename): Adjust c_warn_type_attributes caller. > (grokdeclarator): Likewise. > (finish_declspecs): Likewise. > * c-parser.cc (c_parser_declaration_or_fndef): Likewise. > * c-tree.h (c_warn_type_attributes): Add TYPE argument. > gcc/testsuite/ > * c-c++-common/attr-reproducible-1.c: New test. > * c-c++-common/attr-reproducible-2.c: New test. > * c-c++-common/attr-unsequenced-1.c: New test. > * c-c++-common/attr-unsequenced-2.c: New test. > * gcc.dg/c23-attr-reproducible-1.c: New test. > * gcc.dg/c23-attr-reproducible-2.c: New test. > * gcc.dg/c23-attr-reproducible-3.c: New test. > * gcc.dg/c23-attr-reproducible-4.c: New test. > * gcc.dg/c23-attr-reproducible-5.c: New test. > * gcc.dg/c23-attr-reproducible-6.c: New test. > * gcc.dg/c23-attr-unsequenced-1.c: New test. > * gcc.dg/c23-attr-unsequenced-2.c: New test. > * gcc.dg/c23-attr-unsequenced-3.c: New test. > * gcc.dg/c23-attr-unsequenced-4.c: New test. > * gcc.dg/c23-attr-unsequenced-5.c: New test. > * gcc.dg/c23-attr-unsequenced-6.c: New test. > * gcc.dg/c23-has-c-attribute-2.c: Add tests for unsequenced > and reproducible attributes. > > --- gcc/doc/extend.texi.jj 2024-07-29 09:16:15.159636903 +0200 > +++ gcc/doc/extend.texi 2024-07-30 15:59:01.158715051 +0200 > @@ -4024,6 +4024,68 @@ 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 (in the > +declaration or through @code{va_arg} on variadic functions) 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/references or can store additional > +results through those pointers/references. > + > +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. > + > @cindex @code{retain} function attribute > @item retain > For ELF targets that support the GNU or FreeBSD OSABIs, this attribute > --- gcc/calls.cc.jj 2024-07-18 09:20:31.624543703 +0200 > +++ gcc/calls.cc 2024-07-30 13:18:34.350571711 +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-07-29 13:21:55.917705757 +0200 > +++ gcc/c-family/c-attribs.cc 2024-07-29 19:40:46.020519425 +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,101 @@ handle_pure_attribute (tree *node, tree > return NULL_TREE; > } > > +/* Return true if type TYPE contains or may contain any data pointers > + (may in case of C++ dependent types). */ > + > +static bool > +c_maybe_contains_pointers_p (tree type) > +{ > + switch (TREE_CODE (type)) > + { > + case POINTER_TYPE: > + case REFERENCE_TYPE: > + return true; > + > + case RECORD_TYPE: > + case UNION_TYPE: > + case QUAL_UNION_TYPE: > + if (COMPLETE_TYPE_P (type)) > + { > + for (tree fields = TYPE_FIELDS (type); fields; fields = DECL_CHAIN > (fields)) > + if (TREE_CODE (fields) == FIELD_DECL > + && c_maybe_contains_pointers_p (TREE_TYPE (fields))) > + return true; > + return false; > + } > + return false; > + > + case ARRAY_TYPE: > + return c_maybe_contains_pointers_p (TREE_TYPE (type)); > + > + case ENUMERAL_TYPE: > + case BOOLEAN_TYPE: > + case INTEGER_TYPE: > + case BITINT_TYPE: > + case REAL_TYPE: > + case NULLPTR_TYPE: > + case FIXED_POINT_TYPE: > + case COMPLEX_TYPE: > + case VECTOR_TYPE: > + case FUNCTION_TYPE: > + case METHOD_TYPE: > + return false; > + > + default: > + return true; > + } > +} > + > +/* 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 (argtype == void_list_node) I think this warrants a comment that the attribute on variadic functions is treated as receiving pointers. > + { > + 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; shouldn't you set *no_add_attrs also when the noptr attribute is already there? Because otherwise you'll get the non-noptr attr added? > + 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; > + } > + else if (c_maybe_contains_pointers_p (TREE_VALUE (argtype))) > + break; > + 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-07-24 15:47:15.122478781 +0200 > +++ gcc/c-family/c-common.h 2024-07-29 19:03:55.569066565 +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-07-29 13:21:55.935705521 +0200 > +++ gcc/c-family/c-lex.cc 2024-07-29 17:14:49.393945048 +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-07-29 13:21:55.943705415 +0200 > +++ gcc/c/c-decl.cc 2024-07-30 12:46:40.166828455 +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-07-24 17:55:57.388097924 +0200 > +++ gcc/c/c-parser.cc 2024-07-30 11:22:32.915821271 +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-07-24 15:47:15.129478691 +0200 > +++ gcc/c/c-tree.h 2024-07-30 11:22:04.963197642 +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-07-30 > 13:32:10.090796441 +0200 > +++ gcc/testsuite/c-c++-common/attr-reproducible-1.c 2024-07-30 > 13:43:41.088667213 +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-07-30 > 13:58:38.433861263 +0200 > +++ gcc/testsuite/c-c++-common/attr-reproducible-2.c 2024-07-30 > 14:26:47.293852999 +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-07-30 > 13:29:39.757782214 +0200 > +++ gcc/testsuite/c-c++-common/attr-unsequenced-1.c 2024-07-30 > 13:44:47.992783260 +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-07-30 > 13:45:58.221855370 +0200 > +++ gcc/testsuite/c-c++-common/attr-unsequenced-2.c 2024-07-30 > 14:03:45.395843298 +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-07-30 > 10:39:09.790803085 +0200 > +++ gcc/testsuite/gcc.dg/c23-attr-reproducible-1.c 2024-07-30 > 13:19:09.908102024 +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-07-30 > 10:39:12.632764961 +0200 > +++ gcc/testsuite/gcc.dg/c23-attr-reproducible-2.c 2024-07-30 > 13:09:35.803687498 +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-07-30 > 10:39:15.313728999 +0200 > +++ gcc/testsuite/gcc.dg/c23-attr-reproducible-3.c 2024-07-30 > 13:10:14.556175440 +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-07-30 > 10:39:18.168690708 +0200 > +++ gcc/testsuite/gcc.dg/c23-attr-reproducible-4.c 2024-07-30 > 13:10:26.005024168 +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-07-30 > 14:44:26.750009364 +0200 > +++ gcc/testsuite/gcc.dg/c23-attr-reproducible-5.c 2024-07-30 > 14:54:04.312467597 +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-07-30 > 14:50:39.070147636 +0200 > +++ gcc/testsuite/gcc.dg/c23-attr-reproducible-6.c 2024-07-30 > 14:51:28.339504281 +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-07-30 > 10:39:09.790803085 +0200 > +++ gcc/testsuite/gcc.dg/c23-attr-unsequenced-1.c 2024-07-30 > 13:07:48.585104231 +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-07-30 > 10:39:12.632764961 +0200 > +++ gcc/testsuite/gcc.dg/c23-attr-unsequenced-2.c 2024-07-30 > 13:04:18.566879305 +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-07-30 > 10:39:15.313728999 +0200 > +++ gcc/testsuite/gcc.dg/c23-attr-unsequenced-3.c 2024-07-30 > 12:59:47.146465073 +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-07-30 > 10:39:18.168690708 +0200 > +++ gcc/testsuite/gcc.dg/c23-attr-unsequenced-4.c 2024-07-30 > 12:45:58.298379802 +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-07-30 > 14:44:26.750009364 +0200 > +++ gcc/testsuite/gcc.dg/c23-attr-unsequenced-5.c 2024-07-30 > 14:53:55.734579606 +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-07-30 > 14:50:39.070147636 +0200 > +++ gcc/testsuite/gcc.dg/c23-attr-unsequenced-6.c 2024-07-30 > 14:52:50.354433341 +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 2023-11-09 > 09:04:19.505530809 +0100 > +++ gcc/testsuite/gcc.dg/c23-has-c-attribute-2.c 2024-07-30 > 09:52:19.525586926 +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 >