From patchwork Sat Dec 2 10:51:35 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 172805 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:bcd1:0:b0:403:3b70:6f57 with SMTP id r17csp1693610vqy; Sat, 2 Dec 2023 02:52:09 -0800 (PST) X-Google-Smtp-Source: AGHT+IFean9T+LsoLdCkYa6+AiaSnmMPP5T/HCiyIKrvLm50/Urh7fiKFXGEhm5nS/HU7pNgX66G X-Received: by 2002:a05:620a:e08:b0:77d:88eb:d722 with SMTP id y8-20020a05620a0e0800b0077d88ebd722mr406767qkm.35.1701514329180; Sat, 02 Dec 2023 02:52:09 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1701514329; cv=pass; d=google.com; s=arc-20160816; b=XZsIAah0suKo/5DIuai/MvM4VaoMmbk5MNh0NHrjfN4T4sUW0MKrNxC6B9S1P3A+UF iHaoiUT91HY2G1dunsZvvukoGBCFzDV2Tbfyu0wQP/xfh3SekCL9ZfCf5j4ApAXWqd0t gNWfv6ufDImpPwzcb1FeVjGNPPxUpsECIYsI+U/vL8NGDBJWRV2xwSvaYuu7Z8CfoPhW PmqvIKJNmKHg+5D7191GSLGU/BfwK2hIQozuVMD3tBLxO2cm6ADwAr9E9ytQpnzokcC2 9BOK5yMznZdD9Xe03WRKrNXfxGyYNTMpyIkWYCxNHus55iOT/+PA4G8MQGsqvC3G/3PW WcLA== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=errors-to:reply-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-disposition :mime-version:message-id:subject:cc:to:from:date:dkim-signature :arc-filter:dmarc-filter:delivered-to; bh=fnyTSeo6j35LZzKugSkh5IloB5IVynQoepWzoy9lw0g=; fh=0xZT+NBKSeH8qOu04/61f1ZGePpF4jF/gxp331YE14k=; b=Pi2RMnWy0uD1/p+kCnIKAodZRsLNA8hRPkn02JrpfAWKzv8SKwTzKIX217EhcyGlyM aSyiZfEzPs5yAvZNektK0QGR7J4NYrLX3tZ8y2DLraD6vnbiFd0kk3Gry995CJdtAX/a t80BCx8LFxzS44TCKFrqRXNc6CryPLGDO6ShvDzarBmu9iMPlKUCC6cSvvhi0XB2Pd0Z CrxDEEl+5PLhhjNSigmoQPvsQjxu41vBdDHLtEpXKVBQJkWDiPgaKN50ktpn4tSa1vd6 Ywb0f9ZiR474Mbb8HOZ7hcSx0XsD1gUeLi0/DgW5c5uQ5WioPRAzpCTq3KKepwTg6mF8 MItw== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=UejyHwbC; arc=pass (i=1); spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from server2.sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id bl31-20020a05620a1a9f00b0077f01c246aesi258265qkb.304.2023.12.02.02.52.09 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 02 Dec 2023 02:52:09 -0800 (PST) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=UejyHwbC; arc=pass (i=1); spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D8A0D3861882 for ; Sat, 2 Dec 2023 10:52:08 +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 ESMTPS id 1C0AF385840D for ; Sat, 2 Dec 2023 10:51:43 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1C0AF385840D 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 1C0AF385840D 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=1701514305; cv=none; b=FNcnpvf5SYnUGGIwtpx5QyMP5EgQcO0EjjKXRleaPwm+49U+32bZQs3v0K84CKjX4StauFY1C8XmSHQBeKs+EmqzoAk8O037slLFwMeeYUunht+GqJ881e55z9NSHF+dNwAGBJRitf1bu8lrfTl911nQ9XnOH81IRQeDSFZJfGU= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1701514305; c=relaxed/simple; bh=MwOe9ixrtnbfxrF5r4Ht1xq0QJbRkyhNWVInOTUk9m4=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=XvPtUghJF/B6Et87/P9qBT58A0CcyEHQuIjPLjIP+sxdneGod3+ibZK+71KlCRaXM8BI1qeEC5wQH3TPTkLqOBZjVeuFoau/YspSesbuKnAFZ7ukGTVCQyvdHnL1wwWfvGxU75be96Qzh2vS5k7e8zfIKyWuQDR+LT7zAKIVxN8= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1701514302; 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=fnyTSeo6j35LZzKugSkh5IloB5IVynQoepWzoy9lw0g=; b=UejyHwbCVNuaoe2fON/13ESP1gai3k1+D/uQzSUTxnAQcNHsjsHksWfayJm5y7fd9gIL8U T+xYu98LoZ8PzdH7G1b4kfP7fBt0bRXRJ17UPpfmGiLCXq2IiO7e4KV20mBSy3T+PC7wAA eg/R68nHgh5KeBDSxLEXxwW1C12lh2E= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-329-x7Ilv27mOQmkLe9l5yx_Cw-1; Sat, 02 Dec 2023 05:51:39 -0500 X-MC-Unique: x7Ilv27mOQmkLe9l5yx_Cw-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (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 mimecast-mx02.redhat.com (Postfix) with ESMTPS id 1848485A58C for ; Sat, 2 Dec 2023 10:51:39 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.39.195.157]) by smtp.corp.redhat.com (Postfix) with ESMTPS id B4C972026D4C; Sat, 2 Dec 2023 10:51:38 +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 3B2Apang3605205 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Sat, 2 Dec 2023 11:51:36 +0100 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 3B2ApZsV3605204; Sat, 2 Dec 2023 11:51:35 +0100 Date: Sat, 2 Dec 2023 11:51:35 +0100 From: Jakub Jelinek To: Jason Merrill Cc: gcc-patches@gcc.gnu.org Subject: [PATCH] c++: #pragma GCC unroll C++ fixes [PR112795] Message-ID: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.4 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-3.4 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, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham 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+ouuuleilei=gmail.com@gcc.gnu.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1784167089597398309 X-GMAIL-MSGID: 1784167089597398309 Hi! foo in the unroll-5.C testcase ICEs because cp_parser_pragma_unroll during parsing calls maybe_constant_value unconditionally, which is fine if !processing_template_decl, but can ICE otherwise. While just calling fold_non_dependent_expr there instead could be enough to fix the ICE (and I guess the right thing to do for backports if any), I don't see a reason why we couldn't handle a dependent #pragma GCC unroll argument as well, the unrolling isn't done in the FE and all the middle-end cares about is that ANNOTATE_EXPR has a 1..65534 last operand when it is annot_expr_unroll_kind. So, the following patch changes all the unsigned short unroll arguments to tree unroll (and thus avoids the tree -> unsigned short -> tree conversions), does the type and value checking during parsing only if the argument isn't dependent and repeats it during instantiation. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2023-12-02 Jakub Jelinek PR c++/112795 gcc/cp/ * cp-tree.h (cp_convert_range_for): Change UNROLL type from unsigned short to tree. (finish_while_stmt_cond, finish_do_stmt, finish_for_cond): Likewise. * parser.cc (cp_parser_statement): Pass NULL_TREE rather than 0 to cp_parser_iteration_statement UNROLL argument. (cp_parser_for, cp_parser_c_for): Change UNROLL type from unsigned short to tree. (cp_parser_range_for): Likewise. Set RANGE_FOR_UNROLL to just UNROLL rather than build_int_cst from it. (cp_convert_range_for, cp_parser_iteration_statement): Change UNROLL type from unsigned short to tree. (cp_parser_omp_loop_nest): Pass NULL_TREE rather than 0 to cp_parser_range_for UNROLL argument. (cp_parser_pragma_unroll): Return tree rather than unsigned short. If parsed expression is type dependent, just return it, don't diagnose issues with value if it is value dependent. (cp_parser_pragma): Change UNROLL type from unsigned short to tree. * semantics.cc (finish_while_stmt_cond): Change UNROLL type from unsigned short to tree. Build ANNOTATE_EXPR with UNROLL as its last operand rather than build_int_cst from it. (finish_do_stmt, finish_for_cond): Likewise. * pt.cc (tsubst_stmt) : Change UNROLL type from unsigned short to tree and set it to RECUR on RANGE_FOR_UNROLL (t). (tsubst_expr) : For annot_expr_unroll_kind repeat checks on UNROLL value from cp_parser_pragma_unroll. gcc/testsuite/ * g++.dg/ext/unroll-5.C: New test. * g++.dg/ext/unroll-6.C: New test. Jakub --- gcc/cp/cp-tree.h.jj 2023-12-01 08:10:42.707324577 +0100 +++ gcc/cp/cp-tree.h 2023-12-01 16:08:20.152165244 +0100 @@ -7371,7 +7371,7 @@ extern bool maybe_clone_body (tree); /* In parser.cc */ extern tree cp_convert_range_for (tree, tree, tree, cp_decomp *, bool, - unsigned short, bool); + tree, bool); extern void cp_convert_omp_range_for (tree &, tree &, tree &, tree &, tree &, tree &, tree &, tree &); extern void cp_finish_omp_range_for (tree, tree); @@ -7692,19 +7692,16 @@ extern void begin_else_clause (tree); extern void finish_else_clause (tree); extern void finish_if_stmt (tree); extern tree begin_while_stmt (void); -extern void finish_while_stmt_cond (tree, tree, bool, unsigned short, - bool); +extern void finish_while_stmt_cond (tree, tree, bool, tree, bool); extern void finish_while_stmt (tree); extern tree begin_do_stmt (void); extern void finish_do_body (tree); -extern void finish_do_stmt (tree, tree, bool, unsigned short, - bool); +extern void finish_do_stmt (tree, tree, bool, tree, bool); extern tree finish_return_stmt (tree); extern tree begin_for_scope (tree *); extern tree begin_for_stmt (tree, tree); extern void finish_init_stmt (tree); -extern void finish_for_cond (tree, tree, bool, unsigned short, - bool); +extern void finish_for_cond (tree, tree, bool, tree, bool); extern void finish_for_expr (tree, tree); extern void finish_for_stmt (tree); extern tree begin_range_for_stmt (tree, tree); --- gcc/cp/parser.cc.jj 2023-12-01 08:10:42.800323262 +0100 +++ gcc/cp/parser.cc 2023-12-02 08:52:45.254387503 +0100 @@ -2391,15 +2391,15 @@ static tree cp_parser_selection_statemen static tree cp_parser_condition (cp_parser *); static tree cp_parser_iteration_statement - (cp_parser *, bool *, bool, unsigned short, bool); + (cp_parser *, bool *, bool, tree, bool); static bool cp_parser_init_statement (cp_parser *, tree *decl); static tree cp_parser_for - (cp_parser *, bool, unsigned short, bool); + (cp_parser *, bool, tree, bool); static tree cp_parser_c_for - (cp_parser *, tree, tree, bool, unsigned short, bool); + (cp_parser *, tree, tree, bool, tree, bool); static tree cp_parser_range_for - (cp_parser *, tree, tree, tree, bool, unsigned short, bool, bool); + (cp_parser *, tree, tree, tree, bool, tree, bool, bool); static void do_range_for_auto_deduction (tree, tree, cp_decomp *); static tree cp_parser_perform_range_for_lookup @@ -12521,8 +12521,8 @@ cp_parser_statement (cp_parser* parser, case RID_DO: case RID_FOR: std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc); - statement = cp_parser_iteration_statement (parser, if_p, false, 0, - false); + statement = cp_parser_iteration_statement (parser, if_p, false, + NULL_TREE, false); break; case RID_BREAK: @@ -13806,8 +13806,7 @@ cp_parser_condition (cp_parser* parser) not included. */ static tree -cp_parser_for (cp_parser *parser, bool ivdep, unsigned short unroll, - bool novector) +cp_parser_for (cp_parser *parser, bool ivdep, tree unroll, bool novector) { tree init, scope, decl; bool is_range_for; @@ -13844,7 +13843,7 @@ cp_parser_for (cp_parser *parser, bool i static tree cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep, - unsigned short unroll, bool novector) + tree unroll, bool novector) { /* Normal for loop */ tree condition = NULL_TREE; @@ -13895,8 +13894,7 @@ cp_parser_c_for (cp_parser *parser, tree static tree cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, - bool ivdep, unsigned short unroll, bool novector, - bool is_omp) + bool ivdep, tree unroll, bool novector, bool is_omp) { tree stmt, range_expr; auto_vec bindings; @@ -13969,7 +13967,7 @@ cp_parser_range_for (cp_parser *parser, if (ivdep) RANGE_FOR_IVDEP (stmt) = 1; if (unroll) - RANGE_FOR_UNROLL (stmt) = build_int_cst (integer_type_node, unroll); + RANGE_FOR_UNROLL (stmt) = unroll; if (novector) RANGE_FOR_NOVECTOR (stmt) = 1; finish_range_for_decl (stmt, range_decl, range_expr); @@ -14158,7 +14156,7 @@ warn_for_range_copy (tree decl, tree exp tree cp_convert_range_for (tree statement, tree range_decl, tree range_expr, - cp_decomp *decomp, bool ivdep, unsigned short unroll, + cp_decomp *decomp, bool ivdep, tree unroll, bool novector) { tree begin, end; @@ -14383,7 +14381,7 @@ cp_parser_range_for_member_function (tre static tree cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep, - unsigned short unroll, bool novector) + tree unroll, bool novector) { cp_token *token; enum rid keyword; @@ -44303,7 +44301,7 @@ cp_parser_omp_loop_nest (cp_parser *pars cp_parser_require (parser, CPP_COLON, RT_COLON); init = cp_parser_range_for (parser, NULL_TREE, NULL_TREE, decl, - false, 0, false, true); + false, NULL_TREE, false, true); cp_convert_omp_range_for (this_pre_body, sl, decl, orig_decl, init, orig_init, @@ -50240,29 +50238,31 @@ cp_parser_pragma_ivdep (cp_parser *parse /* Parse a pragma GCC unroll. */ -static unsigned short +static tree cp_parser_pragma_unroll (cp_parser *parser, cp_token *pragma_tok) { location_t location = cp_lexer_peek_token (parser->lexer)->location; - tree expr = cp_parser_constant_expression (parser); - unsigned short unroll; - expr = maybe_constant_value (expr); + tree unroll = cp_parser_constant_expression (parser); + unroll = fold_non_dependent_expr (unroll); HOST_WIDE_INT lunroll = 0; - if (!INTEGRAL_TYPE_P (TREE_TYPE (expr)) - || TREE_CODE (expr) != INTEGER_CST - || (lunroll = tree_to_shwi (expr)) < 0 - || lunroll >= USHRT_MAX) + if (type_dependent_expression_p (unroll)) + ; + else if (!INTEGRAL_TYPE_P (TREE_TYPE (unroll)) + || (!value_dependent_expression_p (unroll) + && (!tree_fits_shwi_p (unroll) + || (lunroll = tree_to_shwi (unroll)) < 0 + || lunroll >= USHRT_MAX))) { error_at (location, "%<#pragma GCC unroll%> requires an" " assignment-expression that evaluates to a non-negative" " integral constant less than %u", USHRT_MAX); - unroll = 0; + unroll = NULL_TREE; } - else + else if (TREE_CODE (unroll) == INTEGER_CST) { - unroll = (unsigned short)lunroll; - if (unroll == 0) - unroll = 1; + unroll = fold_convert (integer_type_node, unroll); + if (integer_zerop (unroll)) + unroll = integer_one_node; } cp_parser_skip_to_pragma_eol (parser, pragma_tok); return unroll; @@ -50597,7 +50597,7 @@ cp_parser_pragma (cp_parser *parser, enu case PRAGMA_NOVECTOR: { bool ivdep; - unsigned short unroll = 0; + tree unroll = NULL_TREE; bool novector = false; const char *pragma_str; --- gcc/cp/semantics.cc.jj 2023-12-01 08:10:42.826322894 +0100 +++ gcc/cp/semantics.cc 2023-12-01 15:55:58.998529436 +0100 @@ -1166,7 +1166,7 @@ begin_while_stmt (void) void finish_while_stmt_cond (tree cond, tree while_stmt, bool ivdep, - unsigned short unroll, bool novector) + tree unroll, bool novector) { cond = maybe_convert_cond (cond); finish_cond (&WHILE_COND (while_stmt), cond); @@ -1184,8 +1184,7 @@ finish_while_stmt_cond (tree cond, tree WHILE_COND (while_stmt), build_int_cst (integer_type_node, annot_expr_unroll_kind), - build_int_cst (integer_type_node, - unroll)); + unroll); if (novector && cond != error_mark_node) WHILE_COND (while_stmt) = build3 (ANNOTATE_EXPR, TREE_TYPE (WHILE_COND (while_stmt)), @@ -1237,7 +1236,7 @@ finish_do_body (tree do_stmt) COND is as indicated. */ void -finish_do_stmt (tree cond, tree do_stmt, bool ivdep, unsigned short unroll, +finish_do_stmt (tree cond, tree do_stmt, bool ivdep, tree unroll, bool novector) { cond = maybe_convert_cond (cond); @@ -1254,7 +1253,7 @@ finish_do_stmt (tree cond, tree do_stmt, if (unroll && cond != error_mark_node) cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, build_int_cst (integer_type_node, annot_expr_unroll_kind), - build_int_cst (integer_type_node, unroll)); + unroll); if (novector && cond != error_mark_node) cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, build_int_cst (integer_type_node, annot_expr_no_vector_kind), @@ -1357,7 +1356,8 @@ finish_init_stmt (tree for_stmt) FOR_STMT. */ void -finish_for_cond (tree cond, tree for_stmt, bool ivdep, unsigned short unroll, bool novector) +finish_for_cond (tree cond, tree for_stmt, bool ivdep, tree unroll, + bool novector) { cond = maybe_convert_cond (cond); finish_cond (&FOR_COND (for_stmt), cond); @@ -1375,8 +1375,7 @@ finish_for_cond (tree cond, tree for_stm FOR_COND (for_stmt), build_int_cst (integer_type_node, annot_expr_unroll_kind), - build_int_cst (integer_type_node, - unroll)); + unroll); if (novector && cond != error_mark_node) FOR_COND (for_stmt) = build3 (ANNOTATE_EXPR, TREE_TYPE (FOR_COND (for_stmt)), --- gcc/cp/pt.cc.jj 2023-12-01 08:10:42.819322994 +0100 +++ gcc/cp/pt.cc 2023-12-01 16:43:26.589676880 +0100 @@ -18418,8 +18418,7 @@ tsubst_stmt (tree t, tree args, tsubst_f } else { - unsigned short unroll = (RANGE_FOR_UNROLL (t) - ? tree_to_uhwi (RANGE_FOR_UNROLL (t)) : 0); + tree unroll = RECUR (RANGE_FOR_UNROLL (t)); stmt = cp_convert_range_for (stmt, decl, expr, decomp, RANGE_FOR_IVDEP (t), unroll, RANGE_FOR_NOVECTOR (t)); @@ -21501,11 +21500,39 @@ tsubst_expr (tree t, tree args, tsubst_f } case ANNOTATE_EXPR: - op1 = RECUR (TREE_OPERAND (t, 0)); - RETURN (build3_loc (EXPR_LOCATION (t), ANNOTATE_EXPR, - TREE_TYPE (op1), op1, - RECUR (TREE_OPERAND (t, 1)), - RECUR (TREE_OPERAND (t, 2)))); + { + op1 = RECUR (TREE_OPERAND (t, 0)); + tree op2 = RECUR (TREE_OPERAND (t, 1)); + tree op3 = RECUR (TREE_OPERAND (t, 2)); + if (TREE_CODE (op2) == INTEGER_CST + && wi::to_widest (op2) == (int) annot_expr_unroll_kind) + { + HOST_WIDE_INT lunroll; + if (type_dependent_expression_p (op3)) + ; + else if (!INTEGRAL_TYPE_P (TREE_TYPE (op3)) + || (!value_dependent_expression_p (op3) + && (!tree_fits_shwi_p (op3) + || (lunroll = tree_to_shwi (op3)) < 0 + || lunroll >= USHRT_MAX))) + { + error_at (EXPR_LOCATION (TREE_OPERAND (t, 2)), + "%<#pragma GCC unroll%> requires an " + "assignment-expression that evaluates to a " + "non-negative integral constant less than %u", + USHRT_MAX); + op3 = integer_one_node; + } + else if (TREE_CODE (op3) == INTEGER_CST) + { + op3 = fold_convert (integer_type_node, op3); + if (integer_zerop (op3)) + op3 = integer_one_node; + } + } + RETURN (build3_loc (EXPR_LOCATION (t), ANNOTATE_EXPR, + TREE_TYPE (op1), op1, op2, op3)); + } default: /* Handle Objective-C++ constructs, if appropriate. */ --- gcc/testsuite/g++.dg/ext/unroll-5.C.jj 2023-12-01 16:26:10.507186363 +0100 +++ gcc/testsuite/g++.dg/ext/unroll-5.C 2023-12-01 16:32:52.341560326 +0100 @@ -0,0 +1,36 @@ +// PR c++/112795 +// { dg-do compile { target c++11 } } +// { dg-options "-O2 -fdump-tree-cunrolli-details" } + +void baz (int); +constexpr int n = 3; + +template +void +foo () +{ +#pragma GCC unroll(n) + for (int i = 0; i != n; ++i) + baz (i); +} + +template +void +bar () +{ +#pragma GCC unroll(N) + for (int i = 0; i != N; ++i) + baz (i); +} + +void +qux () +{ + foo <2> (); + bar <6> (); + bar <10> (); +} + +// { dg-final { scan-tree-dump "loop with 3 iterations completely unrolled" "cunrolli" } } +// { dg-final { scan-tree-dump "loop with 6 iterations completely unrolled" "cunrolli" } } +// { dg-final { scan-tree-dump "loop with 10 iterations completely unrolled" "cunrolli" } } --- gcc/testsuite/g++.dg/ext/unroll-6.C.jj 2023-12-01 16:28:13.738461284 +0100 +++ gcc/testsuite/g++.dg/ext/unroll-6.C 2023-12-01 16:45:40.599799896 +0100 @@ -0,0 +1,85 @@ +// PR c++/112795 +// { dg-do compile { target c++11 } } + +void +foo () +{ + #pragma GCC unroll 1.0f // { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" } + for (int i = 0; i < 2; ++i) + ; + #pragma GCC unroll 0xffffffffffffffffULL // { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" } + for (int i = 0; i < 2; ++i) + ; + #pragma GCC unroll -42 // { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" } + for (int i = 0; i < 2; ++i) + ; +} + +template +void +bar () +{ + #pragma GCC unroll 1.0f // { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" } + for (int i = 0; i < 2; ++i) + ; + #pragma GCC unroll 0xffffffffffffffffULL // { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" } + for (int i = 0; i < 2; ++i) + ; + #pragma GCC unroll -42 // { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" } + for (int i = 0; i < 2; ++i) + ; +} + +template +void +baz () +{ + #pragma GCC unroll (N + 1.0f) // { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" } + for (int i = 0; i < 2; ++i) + ; + #pragma GCC unroll (N + 0xffffffffffffffffULL) + for (int i = 0; i < 2; ++i) + ; + #pragma GCC unroll (N - 42) + for (int i = 0; i < 2; ++i) + ; + #pragma GCC unroll ((T) 1.0f) + for (int i = 0; i < 2; ++i) + ; + #pragma GCC unroll ((T) 0xffffffffffffffffULL) + for (int i = 0; i < 2; ++i) + ; + #pragma GCC unroll ((T) -42) + for (int i = 0; i < 2; ++i) + ; +} + +template +void +qux () +{ + #pragma GCC unroll (N + 1.0f) // { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" } + for (int i = 0; i < 2; ++i) + ; + #pragma GCC unroll (N + 0xffffffffffffffffULL)// { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" } + for (int i = 0; i < 2; ++i) + ; + #pragma GCC unroll (N - 42) // { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" } + for (int i = 0; i < 2; ++i) + ; + #pragma GCC unroll ((T) 1.0f) // { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" } + for (int i = 0; i < 2; ++i) + ; + #pragma GCC unroll ((T) 0xffffffffffffffffULL)// { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" } + for (int i = 0; i < 2; ++i) + ; + #pragma GCC unroll ((T) -42) // { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" } + for (int i = 0; i < 2; ++i) + ; +} + +void +corge () +{ + qux (); +}