From patchwork Thu Aug 1 18:19:57 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 1967984 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=Mye4k1mS; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4WZchx2pxVz1yZv for ; Fri, 2 Aug 2024 04:20:48 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 111713858CD9 for ; Thu, 1 Aug 2024 18:20:47 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id F2E513858D20 for ; Thu, 1 Aug 2024 18:20:18 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org F2E513858D20 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org F2E513858D20 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1722536424; cv=none; b=DxVQ0T1Vo0fvBCdwHMwnBlco6ETEzD19N8YuKYYYEx3fzWJIZXIsKmMXFkEphDTvY7dJ0FNA+4O5yMMWAphSjgrqBnoP5X2OVSsShGe0IQE2n5BwAFvHQtJGRMwUFBUTE+rM3eSjYONjzqtW0XCEJSnN1hVmVqlQhOmOtbhF8Gc= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1722536424; c=relaxed/simple; bh=hNUeih1CM69nyYymwGJagOXZ45EV9tDZTCxis0E81CU=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=TBCq2kDLz+KmouNa0wu3bMOxxsUWojlNfa6331tvYFV9rveQrN4a2SNxyZpdxn1lzL5d02t9I8fmUG0piQC/dJg4iEudH6Hf77QRh1njqyRZJMo51LVWhpPSeyBkuVokdoG16XKxg47gFNiZSfzCSl/3m9Ji1+aMD6USQWXYDFQ= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1722536418; h=from:from:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:in-reply-to:in-reply-to: references:references; bh=c4sCuMG/NiKLdzRq9nzHtD5pyBA6xRVPr6pLmo0UBTQ=; b=Mye4k1mS/XxRqC/wqce2o8z55ULls6cGnQIZVkWKYLXfi/Vi+wr6r8k8NZrWfxsB4bYALO Qg+8kOU6AfN/2ZWguMznqYd+b0YYv/5jk2qvcyteYXMn7b5PC99/nxKGl7btztEyTpJQsH cOt6qWZpnKswDJEcEBlY+jlsmFccT9Q= Received: from mx-prod-mc-04.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-262-b4fdv3oePXOzEnBut8CSYA-1; Thu, 01 Aug 2024 14:20:10 -0400 X-MC-Unique: b4fdv3oePXOzEnBut8CSYA-1 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 635421944B2A; Thu, 1 Aug 2024 18:20:04 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.45.224.25]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 089681955D42; Thu, 1 Aug 2024 18:20:00 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.17.1/8.17.1) with ESMTPS id 471IJw1W1755806 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Thu, 1 Aug 2024 20:19:58 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 471IJvsZ1755805; Thu, 1 Aug 2024 20:19:57 +0200 Date: Thu, 1 Aug 2024 20:19:57 +0200 From: Jakub Jelinek To: "Joseph S. Myers" Cc: gcc-patches@gcc.gnu.org, Jan Hubicka Subject: [PATCH] c, v2: Add support for unsequenced and reproducible attributes Message-ID: References: MIME-Version: 1.0 In-Reply-To: X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SCC_10_SHORT_WORD_LINES, SCC_5_SHORT_WORD_LINES, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Jakub Jelinek Errors-To: gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org Hi! On Tue, Jul 30, 2024 at 07:04:05PM +0200, Jakub Jelinek wrote: > C23 added in N2956 ( https://open-std.org/JTC1/SC22/WG14/www/docs/n2956.htm ) > two new attributes Here is an updated version of the patch. Based on discussions with paper co-author the patch no longer looks into structs/unions or assumes there could be a pointer passed to ... through which the functions could modify memory and only allows a single level of indirection to be inspected (for [[unsequenced]]) or stored to (for both). The documentation is also clarified. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2024-08-01 Jakub Jelinek PR c/116130 gcc/ * doc/extend.texi (unsequenced, reproducible): Document new function type attributes. * calls.cc (flags_from_decl_or_type): Handle "unsequenced noptr" and "reproducible noptr" attributes. gcc/c-family/ * c-attribs.cc (c_common_gnu_attributes): Add entries for "unsequenced", "reproducible", "unsequenced noptr" and "reproducible noptr" attributes. (handle_unsequenced_attribute): New function. (handle_reproducible_attribute): Likewise. * c-common.h (handle_unsequenced_attribute): Declare. (handle_reproducible_attribute): Likewise. * c-lex.cc (c_common_has_attribute): Return 202311 for standard unsequenced and reproducible attributes. gcc/c/ * c-decl.cc (handle_std_unsequenced_attribute): New function. (handle_std_reproducible_attribute): Likewise. (std_attributes): Add entries for "unsequenced" and "reproducible" attributes. (c_warn_type_attributes): Add TYPE argument. Allow unsequenced or reproducible attributes if it is FUNCTION_TYPE. (groktypename): Adjust c_warn_type_attributes caller. (grokdeclarator): Likewise. (finish_declspecs): Likewise. * c-parser.cc (c_parser_declaration_or_fndef): Likewise. * c-tree.h (c_warn_type_attributes): Add TYPE argument. gcc/testsuite/ * c-c++-common/attr-reproducible-1.c: New test. * c-c++-common/attr-reproducible-2.c: New test. * c-c++-common/attr-unsequenced-1.c: New test. * c-c++-common/attr-unsequenced-2.c: New test. * gcc.dg/c23-attr-reproducible-1.c: New test. * gcc.dg/c23-attr-reproducible-2.c: New test. * gcc.dg/c23-attr-reproducible-3.c: New test. * gcc.dg/c23-attr-reproducible-4.c: New test. * gcc.dg/c23-attr-reproducible-5.c: New test. * gcc.dg/c23-attr-reproducible-6.c: New test. * gcc.dg/c23-attr-unsequenced-1.c: New test. * gcc.dg/c23-attr-unsequenced-2.c: New test. * gcc.dg/c23-attr-unsequenced-3.c: New test. * gcc.dg/c23-attr-unsequenced-4.c: New test. * gcc.dg/c23-attr-unsequenced-5.c: New test. * gcc.dg/c23-attr-unsequenced-6.c: New test. * gcc.dg/c23-has-c-attribute-2.c: Add tests for unsequenced and reproducible attributes. Jakub --- gcc/doc/extend.texi.jj 2024-08-01 10:30:35.437802437 +0200 +++ gcc/doc/extend.texi 2024-08-01 14:51:21.512248155 +0200 @@ -4024,6 +4024,69 @@ diagnosed. Because a pure function cann effects it does not make sense for such a function to return @code{void}. Declaring such a function is diagnosed. +@cindex @code{unsequenced} function type attribute +@cindex functions that have no side effects +@item unsequenced + +This attribute is a GNU counterpart of the C23 @code{[[unsequenced]]} +attribute, used to specify function pointers to effectless, idempotent, +stateless and independent functions according to the C23 definition. + +Unlike the standard C23 attribute it can be also specified in attributes +which appertain to function declarations and applies to the their function +type even in that case. + +Unsequenced functions without pointer or reference arguments are similar +to functions with the @code{const} attribute, except that @code{const} +attribute also requires finitness. So, both functions with @code{const} +and with @code{unsequenced} attributes can be optimized by common +subexpression elimination, but only functions with @code{const} +attribute can be optimized by dead code elimination if their result is +unused or is used only by dead code. Unsequenced functions without pointer +or reference arguments with @code{void} return type are diagnosed because +they can't store any results and don't have other observable side-effects +either. + +Unsequenced functions with pointer or reference arguments can inspect +objects through the passed pointers or references or references to pointers +or can store additional results through those pointers or references or +references to pointers. + +The @code{unsequenced} attribute imposes greater restrictions than +the similar @code{reproducible} attribute and fewer restrictions than +the @code{const} attribute, so during optimization @code{const} has +precedence over @code{unsequenced} which has precedence over +@code{reproducible}. + +@cindex @code{reproducible} function type attribute +@cindex functions that have no side effects +@item reproducible + +This attribute is a GNU counterpart of the C23 @code{[[reproducible]]} +attribute, used to specify function pointers to effectless and idempotent +functions according to the C23 definition. + +Unlike the standard C23 attribute it can be also specified in attributes +which appertain to function declarations and applies to the their function +type even in that case. + +Reproducible functions without pointer or reference arguments or which do +not modify objects referenced by those pointer/reference arguments are +similar to functions with the @code{pure} attribute, except that +@code{pure} attribute also requires finitness. So, both functions with +@code{pure} and with @code{reproducible} attributes can be optimized by common +subexpression elimination if the global state or anything reachable through +the pointer/reference arguments isn't modified, but only functions with +@code{pure} attribute can be optimized by dead code elimination if their result is +unused or is used only by dead code. Reproducible functions without pointer +or reference arguments with @code{void} return type are diagnosed because +they can't store any results and don't have other observable side-effects +either. + +Reproducible functions with pointer or reference arguments can store +additional results through those pointers or references or references to +pointers. + @cindex @code{retain} function attribute @item retain For ELF targets that support the GNU or FreeBSD OSABIs, this attribute --- gcc/calls.cc.jj 2024-08-01 10:30:35.430802527 +0200 +++ gcc/calls.cc 2024-08-01 14:37:23.941824448 +0200 @@ -852,6 +852,23 @@ flags_from_decl_or_type (const_tree exp) flags |= ECF_XTHROW; flags = special_function_p (exp, flags); + + if ((flags & ECF_CONST) == 0 + && lookup_attribute ("unsequenced noptr", + TYPE_ATTRIBUTES (TREE_TYPE (exp)))) + { + /* [[unsequenced]] with no pointers in arguments is like + [[gnu::const]] without finite guarantee. */ + flags |= ECF_CONST; + if ((flags & ECF_PURE) == 0) + flags |= ECF_LOOPING_CONST_OR_PURE; + } + if ((flags & (ECF_CONST | ECF_PURE)) == 0 + && lookup_attribute ("reproducible noptr", + TYPE_ATTRIBUTES (TREE_TYPE (exp)))) + /* [[reproducible]] with no pointers in arguments is like + [[gnu::pure]] without finite guarantee. */ + flags |= ECF_PURE | ECF_LOOPING_CONST_OR_PURE; } else if (TYPE_P (exp)) { @@ -862,6 +879,17 @@ flags_from_decl_or_type (const_tree exp) && ((flags & ECF_CONST) != 0 || lookup_attribute ("transaction_pure", TYPE_ATTRIBUTES (exp)))) flags |= ECF_TM_PURE; + + if ((flags & ECF_CONST) == 0 + && lookup_attribute ("unsequenced noptr", TYPE_ATTRIBUTES (exp))) + /* [[unsequenced]] with no pointers in arguments is like + [[gnu::const]] without finite guarantee. */ + flags |= ECF_CONST | ECF_LOOPING_CONST_OR_PURE; + if ((flags & ECF_CONST) == 0 + && lookup_attribute ("reproducible noptr", TYPE_ATTRIBUTES (exp))) + /* [[reproducible]] with no pointers in arguments is like + [[gnu::pure]] without finite guarantee. */ + flags |= ECF_PURE | ECF_LOOPING_CONST_OR_PURE; } else gcc_unreachable (); --- gcc/c-family/c-attribs.cc.jj 2024-08-01 10:30:35.420802655 +0200 +++ gcc/c-family/c-attribs.cc 2024-08-01 14:43:28.775217639 +0200 @@ -444,6 +444,14 @@ const struct attribute_spec c_common_gnu { "pure", 0, 0, true, false, false, false, handle_pure_attribute, attr_const_pure_exclusions }, + { "reproducible", 0, 0, false, true, true, false, + handle_reproducible_attribute, NULL }, + { "unsequenced", 0, 0, false, true, true, false, + handle_unsequenced_attribute, NULL }, + { "reproducible noptr", 0, 0, false, true, true, false, + handle_reproducible_attribute, NULL }, + { "unsequenced noptr", 0, 0, false, true, true, false, + handle_unsequenced_attribute, NULL }, { "transaction_callable", 0, 0, false, true, false, false, handle_tm_attribute, NULL }, { "transaction_unsafe", 0, 0, false, true, false, true, @@ -4280,6 +4288,53 @@ handle_pure_attribute (tree *node, tree return NULL_TREE; } +/* Handle an "unsequenced" attribute; arguments as in + struct attribute_spec.handler. */ + +tree +handle_unsequenced_attribute (tree *node, tree name, tree ARG_UNUSED (args), + int flags, bool *no_add_attrs) +{ + tree fntype = *node; + for (tree argtype = TYPE_ARG_TYPES (fntype); argtype; + argtype = TREE_CHAIN (argtype)) + /* If any of the arguments have pointer or reference type, just + add the attribute alone. */ + if (POINTER_TYPE_P (TREE_VALUE (argtype))) + return NULL_TREE; + + if (VOID_TYPE_P (TREE_TYPE (fntype))) + warning (OPT_Wattributes, "%qE attribute on function type " + "without pointer arguments returning %", name); + const char *name2; + if (IDENTIFIER_LENGTH (name) == sizeof ("unsequenced") - 1) + name2 = "unsequenced noptr"; + else + name2 = "reproducible noptr"; + if (!lookup_attribute (name2, TYPE_ATTRIBUTES (fntype))) + { + *no_add_attrs = true; + gcc_assert ((flags & (int) ATTR_FLAG_TYPE_IN_PLACE) == 0); + tree attr = tree_cons (get_identifier (name2), NULL_TREE, + TYPE_ATTRIBUTES (fntype)); + if (!lookup_attribute (IDENTIFIER_POINTER (name), + TYPE_ATTRIBUTES (fntype))) + attr = tree_cons (name, NULL_TREE, attr); + *node = build_type_attribute_variant (*node, attr); + } + return NULL_TREE; +} + +/* Handle a "reproducible" attribute; arguments as in + struct attribute_spec.handler. */ + +tree +handle_reproducible_attribute (tree *node, tree name, tree args, int flags, + bool *no_add_attrs) +{ + return handle_unsequenced_attribute (node, name, args, flags, no_add_attrs); +} + /* Digest an attribute list destined for a transactional memory statement. ALLOWED is the set of attributes that are allowed for this statement; return the attribute we parsed. Multiple attributes are never allowed. */ --- gcc/c-family/c-common.h.jj 2024-08-01 10:30:35.421802642 +0200 +++ gcc/c-family/c-common.h 2024-08-01 14:37:23.942824435 +0200 @@ -864,6 +864,8 @@ extern void check_function_format (const extern bool attribute_fallthrough_p (tree); extern tree handle_format_attribute (tree *, tree, tree, int, bool *); extern tree handle_format_arg_attribute (tree *, tree, tree, int, bool *); +extern tree handle_unsequenced_attribute (tree *, tree, tree, int, bool *); +extern tree handle_reproducible_attribute (tree *, tree, tree, int, bool *); extern bool c_common_handle_option (size_t, const char *, HOST_WIDE_INT, int, location_t, const struct cl_option_handlers *); --- gcc/c-family/c-lex.cc.jj 2024-08-01 10:30:35.421802642 +0200 +++ gcc/c-family/c-lex.cc 2024-08-01 14:37:23.942824435 +0200 @@ -445,7 +445,9 @@ c_common_has_attribute (cpp_reader *pfil || is_attribute_p ("maybe_unused", attr_name) || is_attribute_p ("nodiscard", attr_name) || is_attribute_p ("noreturn", attr_name) - || is_attribute_p ("_Noreturn", attr_name)) + || is_attribute_p ("_Noreturn", attr_name) + || is_attribute_p ("reproducible", attr_name) + || is_attribute_p ("unsequenced", attr_name)) result = 202311; } if (result) --- gcc/c/c-decl.cc.jj 2024-08-01 10:30:35.424802604 +0200 +++ gcc/c/c-decl.cc 2024-08-01 14:37:23.944824410 +0200 @@ -4702,6 +4702,39 @@ handle_std_noreturn_attribute (tree *nod } } +/* Handle the standard [[unsequenced]] attribute. */ + +static tree +handle_std_unsequenced_attribute (tree *node, tree name, tree args, + int flags, bool *no_add_attrs) +{ + /* Unlike GNU __attribute__ ((unsequenced)), the standard [[unsequenced]] + should be only applied to function declarators or type specifiers which + have function type. */ + if (node[2]) + { + auto_diagnostic_group d; + if (pedwarn (input_location, OPT_Wattributes, + "standard %qE attribute can only be applied to function " + "declarators or type specifiers with function type", name)) + inform (input_location, "did you mean to specify it after %<)%> " + "following function parameters?"); + *no_add_attrs = true; + return NULL_TREE; + } + return handle_unsequenced_attribute (node, name, args, flags, no_add_attrs); +} + +/* Handle the standard [[reproducible]] attribute. */ + +static tree +handle_std_reproducible_attribute (tree *node, tree name, tree args, + int flags, bool *no_add_attrs) +{ + return handle_std_unsequenced_attribute (node, name, args, flags, + no_add_attrs); +} + /* Table of supported standard (C23) attributes. */ static const attribute_spec std_attributes[] = { @@ -4718,7 +4751,11 @@ static const attribute_spec std_attribut { "nodiscard", 0, 1, false, false, false, false, handle_nodiscard_attribute, NULL }, { "noreturn", 0, 0, false, false, false, false, - handle_std_noreturn_attribute, NULL } + handle_std_noreturn_attribute, NULL }, + { "reproducible", 0, 0, false, true, true, false, + handle_std_reproducible_attribute, NULL }, + { "unsequenced", 0, 0, false, true, true, false, + handle_std_unsequenced_attribute, NULL } }; const scoped_attribute_specs std_attribute_table = @@ -4911,12 +4948,24 @@ c_warn_unused_attributes (tree attrs) list of attributes with them removed. */ tree -c_warn_type_attributes (tree attrs) +c_warn_type_attributes (tree type, tree attrs) { tree *attr_ptr = &attrs; while (*attr_ptr) if (get_attribute_namespace (*attr_ptr) == NULL_TREE) { + if (TREE_CODE (type) == FUNCTION_TYPE) + { + tree name = get_attribute_name (*attr_ptr); + /* [[unsequenced]] and [[reproducible]] is fine on function + types that aren't being defined. */ + if (is_attribute_p ("unsequenced", name) + || is_attribute_p ("reproducible", name)) + { + attr_ptr = &TREE_CHAIN (*attr_ptr); + continue; + } + } pedwarn (input_location, OPT_Wattributes, "%qE attribute ignored", get_attribute_name (*attr_ptr)); *attr_ptr = TREE_CHAIN (*attr_ptr); @@ -5386,7 +5435,7 @@ groktypename (struct c_type_name *type_n DEPRECATED_NORMAL); /* Apply attributes. */ - attrs = c_warn_type_attributes (attrs); + attrs = c_warn_type_attributes (type, attrs); decl_attributes (&type, attrs, 0); return type; @@ -7196,7 +7245,7 @@ grokdeclarator (const struct c_declarato else if (inner_decl->kind == cdk_array) attr_flags |= (int) ATTR_FLAG_ARRAY_NEXT; } - attrs = c_warn_type_attributes (attrs); + attrs = c_warn_type_attributes (type, attrs); returned_attrs = decl_attributes (&type, chainon (returned_attrs, attrs), attr_flags); @@ -13433,7 +13482,8 @@ finish_declspecs (struct c_declspecs *sp handle_postfix_attrs: if (specs->type != NULL) { - specs->postfix_attrs = c_warn_type_attributes (specs->postfix_attrs); + specs->postfix_attrs + = c_warn_type_attributes (specs->type, specs->postfix_attrs); decl_attributes (&specs->type, specs->postfix_attrs, 0); specs->postfix_attrs = NULL_TREE; } --- gcc/c/c-parser.cc.jj 2024-08-01 10:30:35.429802539 +0200 +++ gcc/c/c-parser.cc 2024-08-01 14:37:23.947824372 +0200 @@ -2677,8 +2677,9 @@ c_parser_declaration_or_fndef (c_parser /* Postfix [[]] attributes are valid with C23 auto, although not with __auto_type, and modify the type given by the initializer. */ - specs->postfix_attrs = - c_warn_type_attributes (specs->postfix_attrs); + specs->postfix_attrs + = c_warn_type_attributes (specs->type, + specs->postfix_attrs); decl_attributes (&specs->type, specs->postfix_attrs, 0); specs->postfix_attrs = NULL_TREE; } --- gcc/c/c-tree.h.jj 2024-08-01 10:30:35.429802539 +0200 +++ gcc/c/c-tree.h 2024-08-01 14:37:23.947824372 +0200 @@ -680,7 +680,7 @@ extern tree c_builtin_function (tree); extern tree c_builtin_function_ext_scope (tree); extern tree c_simulate_builtin_function_decl (tree); extern void c_warn_unused_attributes (tree); -extern tree c_warn_type_attributes (tree); +extern tree c_warn_type_attributes (tree, tree); extern void shadow_tag (const struct c_declspecs *); extern void shadow_tag_warned (const struct c_declspecs *, int); extern tree start_enum (location_t, struct c_enum_contents *, tree, tree, --- gcc/testsuite/c-c++-common/attr-reproducible-1.c.jj 2024-08-01 14:37:23.947824372 +0200 +++ gcc/testsuite/c-c++-common/attr-reproducible-1.c 2024-08-01 14:37:23.947824372 +0200 @@ -0,0 +1,80 @@ +/* Test gnu::reproducible attribute: valid uses. */ +/* { dg-do compile { target { c || c++11 } } } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-additional-options "-std=gnu23" { target c } } */ +/* { dg-final { scan-tree-dump-times " f1 \\\(\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f2 \\\(\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f3 \\\(42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f5 \\\(42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f7 \\\(42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f8 \\\(42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f9 \\\(42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f3 \\\(-42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f5 \\\(-42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f7 \\\(-42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f8 \\\(-42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f9 \\\(-42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump " f3 \\\(52\\\);" "optimized" } } */ +/* { dg-final { scan-tree-dump-times " fp1\.\[0-9]*_\[0-9]* \\\(14\\\);" 2 "optimized" } } */ + +int f1 () [[gnu::reproducible]]; +int f2 () [[gnu::reproducible]], f3 (int) [[__gnu__::__reproducible__]]; +int f4 (int, int *) [[gnu::reproducible]]; +int f5 (int) [[gnu::reproducible]]; +int f6 (int); +int (*fp1) (int) [[gnu::reproducible]] = f6; +typedef int ft1 (int) [[gnu::reproducible]]; +typedef int ft2 (int); +#ifndef __cplusplus +extern __typeof (f6) [[gnu::reproducible]] f7; +extern ft2 [[__gnu__::__reproducible__]] f8; +#else +int f7 (int) [[gnu::reproducible, gnu::reproducible]]; +int f8 (int) [[__gnu__::reproducible, gnu::__reproducible__]]; +#endif +int f1 (); +int f9 (int); +int f9 (int) [[__gnu__::__reproducible__]]; +extern int x; + +int +f10 (int w) [[gnu::reproducible]] +{ + return w + 42 + x; +} + +int +f11 (int *w, long long y[1], int z) [[__gnu__::__reproducible__]] +{ + w[0] = z + x; + w[1] = z + x + 1; + w[2] = z + x + 2; + *y = z + x + 3; + return z + 4 + f10 (-42); +} + +int +g () +{ + int a = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42); + int b = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42); + int c = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42); + int d = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42); + int e = fp1 (14) + fp1 (14); + x++; + int f = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42); + int g = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42); + int h = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42); + int i = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42); + int j = fp1 (14) + fp1 (14); + return a + b + c + d + e + f + g + h + i + j; +} + +int +h () +{ + f3 (52); + f3 (52); + f3 (52); + return 0; +} --- gcc/testsuite/c-c++-common/attr-reproducible-2.c.jj 2024-08-01 14:37:23.947824372 +0200 +++ gcc/testsuite/c-c++-common/attr-reproducible-2.c 2024-08-01 14:37:23.947824372 +0200 @@ -0,0 +1,74 @@ +/* Test reproducible attribute: valid uses. */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-final { scan-tree-dump-times " f1 \\\(\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f2 \\\(\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f3 \\\(42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f5 \\\(42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f7 \\\(42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f8 \\\(42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f9 \\\(42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f3 \\\(-42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f5 \\\(-42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f7 \\\(-42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f8 \\\(-42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f9 \\\(-42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump " f3 \\\(52\\\);" "optimized" } } */ +/* { dg-final { scan-tree-dump-times " fp1\.\[0-9]*_\[0-9]* \\\(14\\\);" 2 "optimized" } } */ + +__attribute__((reproducible)) int f1 (void); +__attribute__((__reproducible__)) int f2 (void), f3 (int); +int f4 (int, int *) __attribute__((reproducible)); +int f5 (int) __attribute__((reproducible)); +int f6 (int); +int (*fp1) (int) __attribute__((reproducible)) = f6; +typedef int ft1 (int) __attribute__((reproducible)); +typedef int ft2 (int); +extern __typeof (f6) __attribute__((reproducible)) f7; +extern ft2 __attribute__((__reproducible__)) f8; +int f1 (void); +int f9 (int); +int f9 (int) __attribute__((__reproducible__)); +extern int x; + +__attribute__((reproducible)) int +f10 (int w) +{ + return w + 42 + x; +} + +__attribute__((reproducible)) int +f11 (int *w, long long y[1], int z) +{ + w[0] = z + x; + w[1] = z + x + 1; + w[2] = z + x + 2; + *y = z + x + 3; + return z + 4 + f10 (-42); +} + +int +g (void) +{ + int a = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42); + int b = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42); + int c = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42); + int d = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42); + int e = fp1 (14) + fp1 (14); + x++; + int f = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42); + int g = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42); + int h = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42); + int i = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42); + int j = fp1 (14) + fp1 (14); + return a + b + c + d + e + f + g + h + i + j; +} + +int +h (void) +{ + f3 (52); + f3 (52); + f3 (52); + return 0; +} --- gcc/testsuite/c-c++-common/attr-unsequenced-1.c.jj 2024-08-01 14:37:23.948824359 +0200 +++ gcc/testsuite/c-c++-common/attr-unsequenced-1.c 2024-08-01 14:37:23.947824372 +0200 @@ -0,0 +1,87 @@ +/* Test gnu::unsequenced attribute: valid uses. */ +/* { dg-do compile { target { c || c++11 } } } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-additional-options "-std=gnu23" { target c } } */ +/* { dg-final { scan-tree-dump-times " f1 \\\(\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f2 \\\(\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f12 \\\(\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f13 \\\(\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f3 \\\(42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f5 \\\(42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f7 \\\(42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f8 \\\(42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f9 \\\(42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f3 \\\(-42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f5 \\\(-42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f7 \\\(-42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f8 \\\(-42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f9 \\\(-42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump " f3 \\\(52\\\);" "optimized" } } */ +/* { dg-final { scan-tree-dump-times " fp1\.\[0-9]*_\[0-9]* \\\(14\\\);" 1 "optimized" } } */ + +[[gnu::unsequenced]] int f1 (); +[[gnu::unsequenced]] int f2 (), f3 (int); +int f4 (int, int *) [[gnu::unsequenced]]; +int f5 (int) [[gnu::unsequenced]]; +int f6 (int); +int (*fp1) (int) [[gnu::unsequenced]] = f6; +typedef int ft1 (int) [[gnu::unsequenced]]; +typedef int ft2 (int); +#ifndef __cplusplus +extern __typeof (f6) [[gnu::unsequenced]] f7; +extern ft2 [[__gnu__::__unsequenced__]] f8; +#else +int f7 (int) [[gnu::unsequenced, gnu::unsequenced]]; +int f8 (int) [[__gnu__::unsequenced, gnu::__unsequenced__]]; +#endif +int f1 (); +int f9 (int); +int f9 (int) [[__gnu__::__unsequenced__]]; +extern int x; + +int +f10 (int x) [[gnu::unsequenced]] +{ + return x + 42; +} + +int +f11 (int *x, long long y[1], int z) [[__gnu__::__unsequenced__]] +{ + x[0] = z; + x[1] = z + 1; + x[2] = z + 2; + *y = z + 3; + return z + 4 + f10 (-42); +} + +int f12 () [[gnu::unsequenced]]; +int f12 () [[gnu::reproducible]]; +int f13 () [[gnu::reproducible]]; +int f13 () [[gnu::unsequenced]]; + +int +g () +{ + int a = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 (); + int b = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 (); + int c = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42); + int d = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42); + int e = fp1 (14) + fp1 (14); + x++; + int f = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 (); + int g = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 (); + int h = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42); + int i = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42); + int j = fp1 (14) + fp1 (14); + return a + b + c + d + e + f + g + h + i + j; +} + +int +h () +{ + f3 (52); + f3 (52); + f3 (52); + return 0; +} --- gcc/testsuite/c-c++-common/attr-unsequenced-2.c.jj 2024-08-01 14:37:23.948824359 +0200 +++ gcc/testsuite/c-c++-common/attr-unsequenced-2.c 2024-08-01 14:37:23.948824359 +0200 @@ -0,0 +1,81 @@ +/* Test unsequenced attribute: valid uses. */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-final { scan-tree-dump-times " f1 \\\(\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f2 \\\(\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f12 \\\(\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f13 \\\(\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f3 \\\(42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f5 \\\(42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f7 \\\(42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f8 \\\(42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f9 \\\(42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f3 \\\(-42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f5 \\\(-42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f7 \\\(-42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f8 \\\(-42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f9 \\\(-42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump " f3 \\\(52\\\);" "optimized" } } */ +/* { dg-final { scan-tree-dump-times " fp1\.\[0-9]*_\[0-9]* \\\(14\\\);" 1 "optimized" } } */ + +__attribute__((unsequenced)) int f1 (void); +__attribute__((unsequenced)) int f2 (void), f3 (int); +int f4 (int, int *) __attribute__((unsequenced)); +int f5 (int) __attribute__((unsequenced)); +int f6 (int); +int (*fp1) (int) __attribute__((unsequenced)) = f6; +typedef int ft1 (int) __attribute__((unsequenced)); +typedef int ft2 (int); +extern __typeof (f6) __attribute__((unsequenced)) f7; +extern ft2 __attribute__((__unsequenced__)) f8; +int f1 (void); +int f9 (int); +int f9 (int) __attribute__((__unsequenced__)); +extern int x; + +__attribute__((unsequenced)) int +f10 (int x) +{ + return x + 42; +} + +__attribute__((__unsequenced__)) int +f11 (int *x, long long y[1], int z) +{ + x[0] = z; + x[1] = z + 1; + x[2] = z + 2; + *y = z + 3; + return z + 4 + f10 (-42); +} + +int f12 (void) __attribute__((unsequenced)); +int f12 (void) __attribute__((reproducible)); +int f13 (void) __attribute__((reproducible)); +int f13 (void) __attribute__((unsequenced)); + +int +g (void) +{ + int a = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 (); + int b = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 (); + int c = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42); + int d = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42); + int e = fp1 (14) + fp1 (14); + x++; + int f = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 (); + int g = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 (); + int h = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42); + int i = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42); + int j = fp1 (14) + fp1 (14); + return a + b + c + d + e + f + g + h + i + j; +} + +int +h (void) +{ + f3 (52); + f3 (52); + f3 (52); + return 0; +} --- gcc/testsuite/gcc.dg/c23-attr-reproducible-1.c.jj 2024-08-01 14:37:23.948824359 +0200 +++ gcc/testsuite/gcc.dg/c23-attr-reproducible-1.c 2024-08-01 14:37:23.948824359 +0200 @@ -0,0 +1,74 @@ +/* Test C23 reproducible attribute: valid uses. */ +/* { dg-do compile } */ +/* { dg-options "-std=c23 -pedantic-errors -O2 -fdump-tree-optimized" } */ +/* { dg-final { scan-tree-dump-times " f1 \\\(\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f2 \\\(\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f3 \\\(42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f5 \\\(42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f7 \\\(42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f8 \\\(42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f9 \\\(42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f3 \\\(-42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f5 \\\(-42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f7 \\\(-42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f8 \\\(-42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f9 \\\(-42\\\);" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump " f3 \\\(52\\\);" "optimized" } } */ +/* { dg-final { scan-tree-dump-times " fp1\.\[0-9]*_\[0-9]* \\\(14\\\);" 2 "optimized" } } */ + +int f1 () [[reproducible]]; +int f2 () [[reproducible]], f3 (int) [[__reproducible__]]; +int f4 (int, int *restrict) [[reproducible]]; +int f5 (int) [[reproducible]]; +int f6 (int); +int (*fp1) (int) [[reproducible]] = f6; +typedef int ft1 (int) [[reproducible]]; +typedef int ft2 (int); +extern typeof (f6) [[reproducible]] f7; +extern ft2 [[__reproducible__]] f8; +int f1 (); +int f9 (int); +int f9 (int) [[__reproducible__]]; +extern int x; + +int +f10 (int w) [[reproducible]] +{ + return w + 42 + x; +} + +int +f11 (int *restrict w, long long y[restrict static 1], int z) [[__reproducible__]] +{ + w[0] = z + x; + w[1] = z + x + 1; + w[2] = z + x + 2; + *y = z + x + 3; + return z + 4 + f10 (-42); +} + +int +g () +{ + int a = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42); + int b = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42); + int c = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42); + int d = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42); + int e = fp1 (14) + fp1 (14); + x++; + int f = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42); + int g = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42); + int h = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42); + int i = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42); + int j = fp1 (14) + fp1 (14); + return a + b + c + d + e + f + g + h + i + j; +} + +int +h () +{ + f3 (52); + f3 (52); + f3 (52); + return 0; +} --- gcc/testsuite/gcc.dg/c23-attr-reproducible-2.c.jj 2024-08-01 14:37:23.948824359 +0200 +++ gcc/testsuite/gcc.dg/c23-attr-reproducible-2.c 2024-08-01 14:37:23.948824359 +0200 @@ -0,0 +1,47 @@ +/* Test C23 reproducible attribute: invalid contexts. */ +/* { dg-do compile } */ +/* { dg-options "-std=c23 -pedantic-errors" } */ + +/* This attribute is not valid in most cases on types other than + type specifiers with function type or function declarators. */ + +[[reproducible]]; /* { dg-error "ignored" } */ + +int [[reproducible]] var; /* { dg-error "ignored" } */ + +int array_with_dep_type[2] [[reproducible]]; /* { dg-error "ignored" } */ + +[[reproducible]] int fn1 (); /* { dg-error "standard 'reproducible' attribute can only be applied to function declarators or type specifiers with function type" } */ + +[[reproducible]] int fn2 (), fn3 (); /* { dg-error "standard 'reproducible' attribute can only be applied to function declarators or type specifiers with function type" } */ + +int var2 [[reproducible]]; /* { dg-warning "'reproducible' attribute only applies to function types" } */ + +int fn4 [[reproducible]] (); /* { dg-error "standard 'reproducible' attribute can only be applied to function declarators or type specifiers with function type" } */ + +int [[reproducible]] fn5 (); /* { dg-error "ignored" } */ + +int z = sizeof (int [[__reproducible__]]); /* { dg-error "ignored" } */ + +/* This is valid, but not really useful, as it can't return results + in return type nor has any pointer arguments to store results into. */ +void +fn6 (int x, double y) [[reproducible]] +{ /* { dg-warning "reproducible' attribute on function type without pointer arguments returning 'void'" } */ + y = x; + (void) y; +} + +void +f (void) +{ + int a; + [[reproducible]]; /* { dg-error "ignored" } */ + [[reproducible]] a = 1; /* { dg-error "ignored" } */ + [[reproducible]] label: ; /* { dg-warning "'reproducible' attribute only applies to function types" } */ + switch (var) + { + [[reproducible]] case 1: ; /* { dg-warning "'reproducible' attribute only applies to function types" } */ + [[reproducible]] default: ; /* { dg-warning "'reproducible' attribute only applies to function types" } */ + } +} --- gcc/testsuite/gcc.dg/c23-attr-reproducible-3.c.jj 2024-08-01 14:37:23.948824359 +0200 +++ gcc/testsuite/gcc.dg/c23-attr-reproducible-3.c 2024-08-01 14:37:23.948824359 +0200 @@ -0,0 +1,14 @@ +/* Test C23 reproducible attribute: invalid syntax. */ +/* { dg-do compile } */ +/* { dg-options "-std=c23 -pedantic-errors" } */ + +int a () [[reproducible()]]; /* { dg-error "'reproducible' attribute does not take any arguments" } */ + +int b () [[reproducible(0)]]; /* { dg-error "expected" } */ + /* { dg-error "'reproducible' attribute does not take any arguments" "" { target *-*-* } .-1 } */ + +int c () [[reproducible("", 123)]]; /* { dg-error "expected" } */ + /* { dg-error "'reproducible' attribute does not take any arguments" "" { target *-*-* } .-1 } */ + +int d () [[reproducible((""))]]; /* { dg-error "expected" } */ + /* { dg-error "'reproducible' attribute does not take any arguments" "" { target *-*-* } .-1 } */ --- gcc/testsuite/gcc.dg/c23-attr-reproducible-4.c.jj 2024-08-01 14:37:23.948824359 +0200 +++ gcc/testsuite/gcc.dg/c23-attr-reproducible-4.c 2024-08-01 14:37:23.948824359 +0200 @@ -0,0 +1,12 @@ +/* Test C23 reproducible attribute: duplicates (allowed after N2557). */ +/* { dg-do compile } */ +/* { dg-options "-std=c23 -pedantic-errors" } */ + +int a () [[reproducible, __reproducible__]]; +int b () [[__reproducible__, reproducible]]; +int c () [[reproducible, reproducible]]; +int d () [[__reproducible__, __reproducible__]]; +int d () [[reproducible]]; +int d () [[__reproducible__]]; +[[reproducible, reproducible]]; +/* { dg-error "ignored" "ignored" { target *-*-* } .-1 } */ --- gcc/testsuite/gcc.dg/c23-attr-reproducible-5.c.jj 2024-08-01 14:37:23.948824359 +0200 +++ gcc/testsuite/gcc.dg/c23-attr-reproducible-5.c 2024-08-01 14:37:23.948824359 +0200 @@ -0,0 +1,44 @@ +/* Test C23 reproducible attribute: composite type on ?:. */ +/* { dg-do run } */ +/* { dg-options "-std=c23 -pedantic-errors" } */ +/* { dg-additional-sources "c23-attr-reproducible-6.c" } */ + +int f1 () [[reproducible]]; +int f2 (); +int f3 (); +int (*fp1) () [[reproducible]] = f2; +int (*fp2) () [[reproducible]] = f3; +extern void abort (); + +int +foo (int x) +{ + return __builtin_has_attribute (*(x ? f1 : f3), reproducible); +} + +int +bar (int x) +{ + return __builtin_has_attribute (*(x ? fp1 : fp2), reproducible); +} + +int +baz (int x) +{ + return __builtin_has_attribute (*(x ? f3 : f1), reproducible); +} + +int +qux (int x) +{ + return __builtin_has_attribute (*(x ? fp2 : fp1), reproducible); +} + +int +main () +{ + if (!foo (0) || !bar (0) || !baz (0) || !qux (0)) + abort (); + if (!foo (1) || !bar (1) || !baz (1) || !qux (1)) + abort (); +} --- gcc/testsuite/gcc.dg/c23-attr-reproducible-6.c.jj 2024-08-01 14:37:23.948824359 +0200 +++ gcc/testsuite/gcc.dg/c23-attr-reproducible-6.c 2024-08-01 14:37:23.948824359 +0200 @@ -0,0 +1,21 @@ +/* Test C23 reproducible attribute: composite type on ?:. */ +/* { dg-do compile } */ +/* { dg-options "-std=c23 -pedantic-errors" } */ + +int +f1 () [[reproducible]] +{ + return 42; +} + +int +f2 () +{ + return 43; +} + +int +f3 () +{ + return 44; +} --- gcc/testsuite/gcc.dg/c23-attr-unsequenced-1.c.jj 2024-08-01 14:37:23.948824359 +0200 +++ gcc/testsuite/gcc.dg/c23-attr-unsequenced-1.c 2024-08-01 14:37:23.948824359 +0200 @@ -0,0 +1,81 @@ +/* Test C23 unsequenced attribute: valid uses. */ +/* { dg-do compile } */ +/* { dg-options "-std=c23 -pedantic-errors -O2 -fdump-tree-optimized" } */ +/* { dg-final { scan-tree-dump-times " f1 \\\(\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f2 \\\(\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f12 \\\(\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f13 \\\(\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f3 \\\(42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f5 \\\(42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f7 \\\(42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f8 \\\(42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f9 \\\(42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f3 \\\(-42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f5 \\\(-42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f7 \\\(-42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f8 \\\(-42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " f9 \\\(-42\\\);" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump " f3 \\\(52\\\);" "optimized" } } */ +/* { dg-final { scan-tree-dump-times " fp1\.\[0-9]*_\[0-9]* \\\(14\\\);" 1 "optimized" } } */ + +int f1 () [[unsequenced]]; +int f2 () [[unsequenced]], f3 (int) [[__unsequenced__]]; +int f4 (int, int *restrict) [[unsequenced]]; +int f5 (int) [[unsequenced]]; +int f6 (int); +int (*fp1) (int) [[unsequenced]] = f6; +typedef int ft1 (int) [[unsequenced]]; +typedef int ft2 (int); +extern typeof (f6) [[unsequenced]] f7; +extern ft2 [[__unsequenced__]] f8; +int f1 (); +int f9 (int); +int f9 (int) [[__unsequenced__]]; +extern int x; + +int +f10 (int x) [[unsequenced]] +{ + return x + 42; +} + +int +f11 (int *restrict x, long long y[restrict static 1], int z) [[__unsequenced__]] +{ + x[0] = z; + x[1] = z + 1; + x[2] = z + 2; + *y = z + 3; + return z + 4 + f10 (-42); +} + +int f12 () [[unsequenced]]; +int f12 () [[reproducible]]; +int f13 () [[reproducible]]; +int f13 () [[unsequenced]]; + +int +g () +{ + int a = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 (); + int b = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 (); + int c = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42); + int d = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42); + int e = fp1 (14) + fp1 (14); + x++; + int f = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 (); + int g = f1 () + f2 () + f3 (42) + f5 (42) + f7 (42) + f8 (42) + f9 (42) + f12 () + f13 (); + int h = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42); + int i = f3 (-42) + f5 (-42) + f7 (-42) + f8 (-42) + f9 (-42); + int j = fp1 (14) + fp1 (14); + return a + b + c + d + e + f + g + h + i + j; +} + +int +h () +{ + f3 (52); + f3 (52); + f3 (52); + return 0; +} --- gcc/testsuite/gcc.dg/c23-attr-unsequenced-2.c.jj 2024-08-01 14:37:23.948824359 +0200 +++ gcc/testsuite/gcc.dg/c23-attr-unsequenced-2.c 2024-08-01 14:37:23.948824359 +0200 @@ -0,0 +1,47 @@ +/* Test C23 unsequenced attribute: invalid contexts. */ +/* { dg-do compile } */ +/* { dg-options "-std=c23 -pedantic-errors" } */ + +/* This attribute is not valid in most cases on types other than + type specifiers with function type or function declarators. */ + +[[unsequenced]]; /* { dg-error "ignored" } */ + +int [[unsequenced]] var; /* { dg-error "ignored" } */ + +int array_with_dep_type[2] [[unsequenced]]; /* { dg-error "ignored" } */ + +[[unsequenced]] int fn1 (); /* { dg-error "standard 'unsequenced' attribute can only be applied to function declarators or type specifiers with function type" } */ + +[[unsequenced]] int fn2 (), fn3 (); /* { dg-error "standard 'unsequenced' attribute can only be applied to function declarators or type specifiers with function type" } */ + +int var2 [[unsequenced]]; /* { dg-warning "'unsequenced' attribute only applies to function types" } */ + +int fn4 [[unsequenced]] (); /* { dg-error "standard 'unsequenced' attribute can only be applied to function declarators or type specifiers with function type" } */ + +int [[unsequenced]] fn5 (); /* { dg-error "ignored" } */ + +int z = sizeof (int [[__unsequenced__]]); /* { dg-error "ignored" } */ + +/* This is valid, but not really useful, as it can't return results + in return type nor has any pointer arguments to store results into. */ +void +fn6 (int x, double y) [[unsequenced]] +{ /* { dg-warning "unsequenced' attribute on function type without pointer arguments returning 'void'" } */ + y = x; + (void) y; +} + +void +f (void) +{ + int a; + [[unsequenced]]; /* { dg-error "ignored" } */ + [[unsequenced]] a = 1; /* { dg-error "ignored" } */ + [[unsequenced]] label: ; /* { dg-warning "'unsequenced' attribute only applies to function types" } */ + switch (var) + { + [[unsequenced]] case 1: ; /* { dg-warning "'unsequenced' attribute only applies to function types" } */ + [[unsequenced]] default: ; /* { dg-warning "'unsequenced' attribute only applies to function types" } */ + } +} --- gcc/testsuite/gcc.dg/c23-attr-unsequenced-3.c.jj 2024-08-01 14:37:23.949824346 +0200 +++ gcc/testsuite/gcc.dg/c23-attr-unsequenced-3.c 2024-08-01 14:37:23.949824346 +0200 @@ -0,0 +1,14 @@ +/* Test C23 unsequenced attribute: invalid syntax. */ +/* { dg-do compile } */ +/* { dg-options "-std=c23 -pedantic-errors" } */ + +int a () [[unsequenced()]]; /* { dg-error "'unsequenced' attribute does not take any arguments" } */ + +int b () [[unsequenced(0)]]; /* { dg-error "expected" } */ + /* { dg-error "'unsequenced' attribute does not take any arguments" "" { target *-*-* } .-1 } */ + +int c () [[unsequenced("", 123)]]; /* { dg-error "expected" } */ + /* { dg-error "'unsequenced' attribute does not take any arguments" "" { target *-*-* } .-1 } */ + +int d () [[unsequenced((""))]]; /* { dg-error "expected" } */ + /* { dg-error "'unsequenced' attribute does not take any arguments" "" { target *-*-* } .-1 } */ --- gcc/testsuite/gcc.dg/c23-attr-unsequenced-4.c.jj 2024-08-01 14:37:23.949824346 +0200 +++ gcc/testsuite/gcc.dg/c23-attr-unsequenced-4.c 2024-08-01 14:37:23.949824346 +0200 @@ -0,0 +1,12 @@ +/* Test C23 unsequenced attribute: duplicates (allowed after N2557). */ +/* { dg-do compile } */ +/* { dg-options "-std=c23 -pedantic-errors" } */ + +int a () [[unsequenced, __unsequenced__]]; +int b () [[__unsequenced__, unsequenced]]; +int c () [[unsequenced, unsequenced]]; +int d () [[__unsequenced__, __unsequenced__]]; +int d () [[unsequenced]]; +int d () [[__unsequenced__]]; +[[unsequenced, unsequenced]]; +/* { dg-error "ignored" "ignored" { target *-*-* } .-1 } */ --- gcc/testsuite/gcc.dg/c23-attr-unsequenced-5.c.jj 2024-08-01 14:37:23.949824346 +0200 +++ gcc/testsuite/gcc.dg/c23-attr-unsequenced-5.c 2024-08-01 14:37:23.949824346 +0200 @@ -0,0 +1,44 @@ +/* Test C23 unsequenced attribute: composite type on ?:. */ +/* { dg-do run } */ +/* { dg-options "-std=c23 -pedantic-errors" } */ +/* { dg-additional-sources "c23-attr-unsequenced-6.c" } */ + +int f1 () [[unsequenced]]; +int f2 (); +int f3 (); +int (*fp1) () [[unsequenced]] = f2; +int (*fp2) () [[unsequenced]] = f3; +extern void abort (); + +int +foo (int x) +{ + return __builtin_has_attribute (*(x ? f1 : f3), unsequenced); +} + +int +bar (int x) +{ + return __builtin_has_attribute (*(x ? fp1 : fp2), unsequenced); +} + +int +baz (int x) +{ + return __builtin_has_attribute (*(x ? f3 : f1), unsequenced); +} + +int +qux (int x) +{ + return __builtin_has_attribute (*(x ? fp2 : fp1), unsequenced); +} + +int +main () +{ + if (!foo (0) || !bar (0) || !baz (0) || !qux (0)) + abort (); + if (!foo (1) || !bar (1) || !baz (1) || !qux (1)) + abort (); +} --- gcc/testsuite/gcc.dg/c23-attr-unsequenced-6.c.jj 2024-08-01 14:37:23.949824346 +0200 +++ gcc/testsuite/gcc.dg/c23-attr-unsequenced-6.c 2024-08-01 14:37:23.949824346 +0200 @@ -0,0 +1,21 @@ +/* Test C23 unsequenced attribute: composite type on ?:. */ +/* { dg-do compile } */ +/* { dg-options "-std=c23 -pedantic-errors" } */ + +int +f1 () [[unsequenced]] +{ + return 42; +} + +int +f2 () +{ + return 43; +} + +int +f3 () +{ + return 44; +} --- gcc/testsuite/gcc.dg/c23-has-c-attribute-2.c.jj 2024-08-01 10:30:35.438802424 +0200 +++ gcc/testsuite/gcc.dg/c23-has-c-attribute-2.c 2024-08-01 14:37:24.355819220 +0200 @@ -50,6 +50,22 @@ #error "bad result for ___Noreturn__" #endif +#if __has_c_attribute (unsequenced) != 202311L +#error "bad result for unsequenced" +#endif + +#if __has_c_attribute (__unsequenced__) != 202311L +#error "bad result for __unsequenced__" +#endif + +#if __has_c_attribute (reproducible) != 202311L +#error "bad result for reproducible" +#endif + +#if __has_c_attribute (__reproducible__) != 202311L +#error "bad result for __reproducible__" +#endif + /* Macros in the attribute name are expanded. */ #define foo deprecated #if __has_c_attribute (foo) != 202311L