From patchwork Tue Jul 30 17:04:05 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 1966668 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=hzwo5b+t; 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 4WYM6v1qFQz1yZD for ; Wed, 31 Jul 2024 03:05:27 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 7C59D3857000 for ; Tue, 30 Jul 2024 17:05:25 +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.129.124]) by sourceware.org (Postfix) with ESMTP id D50993858C56 for ; Tue, 30 Jul 2024 17:04:14 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org D50993858C56 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 D50993858C56 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1722359061; cv=none; b=sJXA/oDePhj8pLcuLktSnXSLJ/IB9QMew4BZMVrW5WvYLOv7jt+DHXqr+DiCjvU07UFjKuupO/FXnALmbCUOnFmSheRNu/GR0QF/VTVRVa/oc9A2tds/G/FZuzJ12uvIE8oKCMvzd3L0eclRpzXZ0iUECzeaBFEnACyvqlJ4WnA= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1722359061; c=relaxed/simple; bh=ND2uibBT7UYEt7K5Oz+WvZ6ULgQXjxWR9WZuQUdRMgo=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=SyzABB8hMpOvIGgE3JdrG82O6t4RMqWcioFB9hsTZHp+wbK4xGLz2o0S/JdrQC3oKh1sH8XK9fXODHTobmevIRpr1uReTytzkbEy9bzTHnJJtkswR1yPDnfXC28b6/hr8LqlkJqTWl/qxeofo3CSojWeVECakNLwGaLaZVRMl7A= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1722359054; 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; bh=D3dy9QfLEljqcNRVapaZFv6xGuhnmyFR0kGIfsL+hAo=; b=hzwo5b+tr971r+aQg0+sCE8a3oH/wIXm2K7UytzQFmIMovw9CmALhYhypQv2lfCLkpLLEa nEVW4UDrg5o8rrUxdVY+9RaaaDhJjwNX96G8RBoIlVDlyR1dXcSPeuVKmg1ito4/ndSTcP PLJ7A8Yj6geM2kpb26Lzq56ZdBzPdRs= Received: from mx-prod-mc-02.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-29-e-Vo-OKaMjuzzYH2vRrYgA-1; Tue, 30 Jul 2024 13:04:11 -0400 X-MC-Unique: e-Vo-OKaMjuzzYH2vRrYgA-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-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 9902F1955D44; Tue, 30 Jul 2024 17:04:10 +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 CD2D71955D45; Tue, 30 Jul 2024 17:04:08 +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 46UH457G4062598 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Tue, 30 Jul 2024 19:04:06 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 46UH45wS4062597; Tue, 30 Jul 2024 19:04:05 +0200 Date: Tue, 30 Jul 2024 19:04:05 +0200 From: Jakub Jelinek To: "Joseph S. Myers" Cc: gcc-patches@gcc.gnu.org, Jan Hubicka Subject: [PATCH] c: Add support for unsequenced and reproducible attributes Message-ID: MIME-Version: 1.0 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.7 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_H3, 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! 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 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. Jakub --- 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 %", 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