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?

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)
+      {
+       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;
+      }
+    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

Reply via email to