From patchwork Tue Sep 24 16:53:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 1989007 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=UBKmdeTP; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; 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 [IPv6:2620:52:3:1:0:246e:9693:128c]) (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 4XCmCv4R95z1xsn for ; Wed, 25 Sep 2024 02:54:03 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 474BB3858404 for ; Tue, 24 Sep 2024 16:54:01 +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 C90CD3858D20 for ; Tue, 24 Sep 2024 16:53:31 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org C90CD3858D20 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 C90CD3858D20 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=1727196817; cv=none; b=uj/qhgvfLcx/z3HtkqTN1+nNbC9z9eORJTjIDx/r4J0M+aGUYrD0+ZRCpPjMsPK0/KIHHEJhMERljBA8zAA4t+0aWgpjSVb/9xOADeX2skfGsoW2QJl6bDCeahfHct35Eiz8KpEeWovEi9E/+wZD1FnD0A5ARL+ygsisY3pitD0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1727196817; c=relaxed/simple; bh=J23nR12G1d5UG4HCIhVbqnRRh9+EIG+GERHA5kY4Yik=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=KU55DLReemDKkCC57UInWLsAvhQWBON1NnOi7OtuE1We2Yg2hCRYCVpM15cEwfcRVMtpwtTXdjTqP+Yn58lHTdp0euCwi5iZhl2M/A4JrUzcpL5A0ykqOFPrzToE7cXaDRIEKb7rAFNyTZ3AxKt73UEjY4ERmcM7O8FHeJPVGoM= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1727196811; 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=OWoBtWhx9Ag0PlZtyAxuzLpYjRDLYTJC2d6iiTRR6/E=; b=UBKmdeTPRcKitIFuIinYf+inOXekQ6xv9XD01jG+pFt9TKAug1xtqT2yWMvn6z/SSQGRfA 9dO54LHQ9J8N9mZUmUhS6AI436EWtUOG7a7GfRYotjolUDs36ukqWea0buFtScmnOYri5V RN38gPRa6slubi0qWHqd6vItBveusNY= Received: from mx-prod-mc-01.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-5-g1Mn-_kMOS-JRUoXyATXUg-1; Tue, 24 Sep 2024 12:53:27 -0400 X-MC-Unique: g1Mn-_kMOS-JRUoXyATXUg-1 Received: from mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (unknown [10.30.177.40]) (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-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 456931936104 for ; Tue, 24 Sep 2024 16:53:26 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.45.224.61]) by mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 4BAF0196BFE7; Tue, 24 Sep 2024 16:53:25 +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 48OGrMqV1118116 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Tue, 24 Sep 2024 18:53:22 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 48OGrMEF1118115; Tue, 24 Sep 2024 18:53:22 +0200 Date: Tue, 24 Sep 2024 18:53:22 +0200 From: Jakub Jelinek To: Jason Merrill Cc: gcc-patches@gcc.gnu.org Subject: [PATCH] c++, v2: Implement C++23 P2718R0 - Wording for P2644R1 Fix for Range-based for Loop [PR107637] Message-ID: References: <19263a8f-82c9-4dc0-a7d1-5f4c78872370@redhat.com> MIME-Version: 1.0 In-Reply-To: X-Scanned-By: MIMEDefang 3.0 on 10.30.177.40 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-3.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_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP 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~incoming=patchwork.ozlabs.org@gcc.gnu.org On Mon, Sep 23, 2024 at 03:46:36PM -0400, Jason Merrill wrote: > > -frange-based-for-ext-temps > > or do you have better suggestion? > > I'd probably drop "based", "range-for" seems enough. > > > Shall we allow also disabling it in C++23 or later modes, or override > > user choice unconditionally for C++23+ and only allow users to > > enable/disable it in C++11-C++20? > > Hmm, I think the latter. > > > What about the __cpp_range_based_for predefined macro? > > Shall it be defined to the C++23 202211L value if the switch is on? > > While that could be done in theory for C++17 and later code, for C++11/14 > > __cpp_range_based_for is 200907L and doesn't include the C++17 > > 201603L step. Or keep the macro only for C++23 and later? > > I think update the macro for 17 and later. Ok. Here is a new patch. > > > > @@ -44600,11 +44609,14 @@ cp_convert_omp_range_for (tree &this_pre > > > > else > > > > { > > > > range_temp = build_range_temp (init); > > > > + tree name = DECL_NAME (range_temp); > > > > DECL_NAME (range_temp) = NULL_TREE; > > > > pushdecl (range_temp); > > > > + DECL_NAME (range_temp) = name; > > > > cp_finish_decl (range_temp, init, > > > > /*is_constant_init*/false, NULL_TREE, > > > > LOOKUP_ONLYCONVERTING); > > > > + DECL_NAME (range_temp) = NULL_TREE; > > > > > > This messing with the name needs a rationale. What wants it to be null? > > > > I'll add comments. The first = NULL_TREE; is needed so that pushdecl > > doesn't register the temporary for name lookup, the = name now is so that > > cp_finish_decl recognizes the temporary as range based for temporary > > for the lifetime extension, and the last one is just to preserve previous > > behavior, not have it visible in debug info etc. > > But cp_convert_range_for doesn't ever set the name to NULL_TREE, why should > the OMP variant be different? > > Having it visible to name lookup in the debugger seems beneficial. Having it > visible to the code seems less useful, but not important to prevent. So, in the end it works fine even for the OpenMP case when not inside of a template, all I had to add is the renaming of the symbol at the end after pop_scope from "__for_range " to "__for_range" etc. It doesn't work unfortunately during instantiation, we only create a single scope in that case for the whole loop nest rather than one for each loop in it and changing that isn't easy. With the "__for_range " name in, if there are 2+ range based for loops in the OpenMP loop nest (collapsed or ordered), one gets then errors about defining it multiple times. I'll try to fix that up at incrementally later, for now I just went with a new flag to the function, so that it does the DECL_NAME dances only when called from the instantiation (and confirmed actually all 3 spots are needed, clearing before pushdecl, resetting back before cp_finish_decl and clearing after cp_finish_decl, the last one so that pop_scope doesn't ICE on seeing the name change). Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2024-09-24 Jakub Jelinek PR c++/107637 gcc/ * omp-general.cc (find_combined_omp_for, find_nested_loop_xform): Handle CLEANUP_POINT_EXPR like TRY_FINALLY_EXPR. * doc/invoke.texi (frange-for-ext-temps): Document. Add -fconcepts to the C++ option list. gcc/c-family/ * c.opt (frange-for-ext-temps): New option. * c-opts.cc (c_common_post_options): Set flag_range_for_ext_temps for C++23 or later or for C++11 or later in !flag_iso mode if the option wasn't set by user. * c-cppbuiltin.cc (c_cpp_builtins): Change __cpp_range_based_for value for flag_range_for_ext_temps from 201603L to 202212L in C++17 or later. * c-omp.cc (c_find_nested_loop_xform_r): Handle CLEANUP_POINT_EXPR like TRY_FINALLY_EXPR. gcc/cp/ * cp-tree.h: Implement C++23 P2718R0 - Wording for P2644R1 Fix for Range-based for Loop. (cp_convert_omp_range_for): Add bool tmpl_p argument. (find_range_for_decls): Declare. * parser.cc (cp_convert_range_for): For flag_range_for_ext_temps call push_stmt_list () before cp_finish_decl for range_temp and save it temporarily to FOR_INIT_STMT. (cp_convert_omp_range_for): Add tmpl_p argument. If set, remember DECL_NAME of range_temp and for cp_finish_decl call restore it before clearing it again, if unset, don't adjust DECL_NAME of range_temp at all. (cp_parser_omp_loop_nest): For flag_range_for_ext_temps range for add CLEANUP_POINT_EXPR around sl. Call find_range_for_decls and adjust DECL_NAMEs for range fors if not processing_template_decl. Adjust cp_convert_omp_range_for caller. Remove superfluous backslash at the end of line. * decl.cc (initialize_local_var): For flag_range_for_ext_temps temporarily clear stmts_are_full_exprs_p rather than set for for_range__identifier decls. * call.cc (extend_ref_init_temps): For flag_range_for_ext_temps return init early for for_range__identifier decls. * semantics.cc (find_range_for_decls): New function. (finish_for_stmt): Use it. For flag_range_for_ext_temps if cp_convert_range_for set FOR_INIT_STMT, pop_stmt_list it and wrap into CLEANUP_POINT_EXPR. * pt.cc (tsubst_omp_for_iterator): Adjust tsubst_omp_for_iterator caller. (tsubst_stmt) : For flag_range_for_ext_temps if there are any range fors in the loop nest, add push_stmt_list starting before the initializations, pop_stmt_list it after the body and wrap into CLEANUP_POINT_EXPR. Change DECL_NAME of range for temps from NULL to for_range_identifier. gcc/testsuite/ * g++.dg/cpp23/range-for1.C: New test. * g++.dg/cpp23/range-for2.C: New test. * g++.dg/cpp23/range-for3.C: New test. * g++.dg/cpp23/range-for4.C: New test. * g++.dg/cpp23/range-for5.C: New test. * g++.dg/cpp23/range-for6.C: New test. * g++.dg/cpp23/range-for7.C: New test. * g++.dg/cpp23/range-for8.C: New test. * g++.dg/cpp23/feat-cxx2b.C (__cpp_range_based_for): Check for 202212L rather than 201603L. * g++.dg/cpp26/feat-cxx26.C (__cpp_range_based_for): Likewise. * g++.dg/warn/Wdangling-reference4.C: Don't expect warning for C++23 or newer. Use dg-additional-options rather than dg-options. libgomp/ * testsuite/libgomp.c++/range-for-1.C: New test. * testsuite/libgomp.c++/range-for-2.C: New test. * testsuite/libgomp.c++/range-for-3.C: New test. * testsuite/libgomp.c++/range-for-4.C: New test. * testsuite/libgomp.c++/range-for-5.C: New test. Jakub --- gcc/omp-general.cc.jj 2024-09-24 11:31:48.775621337 +0200 +++ gcc/omp-general.cc 2024-09-24 11:37:02.761332388 +0200 @@ -972,6 +972,7 @@ find_combined_omp_for (tree *tp, int *wa *walk_subtrees = 1; break; case TRY_FINALLY_EXPR: + case CLEANUP_POINT_EXPR: pdata[0] = tp; *walk_subtrees = 1; break; @@ -4164,6 +4165,7 @@ find_nested_loop_xform (tree *tp, int *w *walk_subtrees = 1; break; case TRY_FINALLY_EXPR: + case CLEANUP_POINT_EXPR: pdata[0] = tp; *walk_subtrees = 1; break; --- gcc/doc/invoke.texi.jj 2024-09-24 11:31:48.695622430 +0200 +++ gcc/doc/invoke.texi 2024-09-24 12:09:08.908039208 +0200 @@ -214,7 +214,7 @@ in the following sections. @xref{C++ Dialect Options,,Options Controlling C++ Dialect}. @gccoptlist{-fabi-version=@var{n} -fno-access-control -faligned-new=@var{n} -fargs-in-order=@var{n} -fchar8_t -fcheck-new --fconstexpr-depth=@var{n} -fconstexpr-cache-depth=@var{n} +-fconcepts -fconstexpr-depth=@var{n} -fconstexpr-cache-depth=@var{n} -fconstexpr-loop-limit=@var{n} -fconstexpr-ops-limit=@var{n} -fno-elide-constructors -fno-enforce-eh-specs @@ -233,7 +233,7 @@ in the following sections. -fnew-ttp-matching -fno-nonansi-builtins -fnothrow-opt -fno-operator-names -fno-optional-diags --fno-pretty-templates +-fno-pretty-templates -frange-for-ext-temps -fno-rtti -fsized-deallocation -ftemplate-backtrace-limit=@var{n} -ftemplate-depth=@var{n} @@ -3614,6 +3614,15 @@ the default template arguments for that behaviors make it harder to understand the error message rather than easier, you can use @option{-fno-pretty-templates} to disable them. +@opindex frange-for-ext-temps +@item -frange-for-ext-temps +Enable lifetime extension of C++ range based for temporaries. +With @option{-std=c++23} and above this is part of the language standard, +so lifetime of the temporaries is extended until the end of the loop +regardless of this option. This option allows enabling that behavior also +in earlier versions of the standard and is enabled by default in the +GNU dialects, from @option{-std=gnu++11} until @option{-std=gnu++20}. + @opindex fno-rtti @opindex frtti @item -fno-rtti --- gcc/c-family/c.opt.jj 2024-09-24 11:31:37.380776989 +0200 +++ gcc/c-family/c.opt 2024-09-24 11:49:23.856220260 +0200 @@ -2209,6 +2209,10 @@ fprintf-return-value C ObjC C++ ObjC++ LTO Optimization Var(flag_printf_return_value) Init(1) Treat known sprintf return values as constants. +frange-for-ext-temps +C++ ObjC++ Var(flag_range_for_ext_temps) +Enable lifetime extension of range based for temporaries. + freplace-objc-classes ObjC ObjC++ LTO Var(flag_replace_objc_classes) Used in Fix-and-Continue mode to indicate that object files may be swapped in at runtime. --- gcc/c-family/c-opts.cc.jj 2024-09-24 11:31:37.344777481 +0200 +++ gcc/c-family/c-opts.cc 2024-09-24 13:36:47.135322261 +0200 @@ -1160,6 +1160,16 @@ c_common_post_options (const char **pfil if (cxx_dialect >= cxx20) flag_concepts = 1; + /* Enable lifetime extension of range based for temporaries for C++23 + regardless of command line setting. */ + if (cxx_dialect >= cxx23) + flag_range_for_ext_temps = 1; + /* Otherwise default to enabled in GNU modes but allow user to override. */ + else if (cxx_dialect >= cxx11 + && !flag_iso + && !OPTION_SET_P (flag_range_for_ext_temps)) + flag_range_for_ext_temps = 1; + /* -fimmediate-escalation has no effect when immediate functions are not supported. */ if (flag_immediate_escalation && cxx_dialect < cxx20) --- gcc/c-family/c-cppbuiltin.cc.jj 2024-09-24 11:31:37.312777918 +0200 +++ gcc/c-family/c-cppbuiltin.cc 2024-09-24 11:56:29.641414229 +0200 @@ -1034,7 +1034,11 @@ c_cpp_builtins (cpp_reader *pfile) cpp_define (pfile, "__cpp_fold_expressions=201603L"); if (cxx_dialect <= cxx17) cpp_define (pfile, "__cpp_nontype_template_args=201411L"); - cpp_define (pfile, "__cpp_range_based_for=201603L"); + if (!flag_range_for_ext_temps) + cpp_define (pfile, "__cpp_range_based_for=201603L"); + else + /* This is the C++23 or -std=c++17 -frange-for-ext-temps value. */ + cpp_define (pfile, "__cpp_range_based_for=202211L"); if (cxx_dialect <= cxx17) cpp_define (pfile, "__cpp_constexpr=201603L"); cpp_define (pfile, "__cpp_if_constexpr=201606L"); --- gcc/c-family/c-omp.cc.jj 2024-09-24 11:31:37.343777494 +0200 +++ gcc/c-family/c-omp.cc 2024-09-24 11:37:02.762332374 +0200 @@ -1617,6 +1617,7 @@ c_find_nested_loop_xform_r (tree *tp, in *walk_subtrees = 1; break; case TRY_FINALLY_EXPR: + case CLEANUP_POINT_EXPR: *walk_subtrees = 1; break; default: --- gcc/cp/cp-tree.h.jj 2024-09-21 12:28:13.310942697 +0200 +++ gcc/cp/cp-tree.h 2024-09-24 14:41:32.378371615 +0200 @@ -7474,7 +7474,8 @@ extern bool maybe_clone_body (tree); extern tree cp_convert_range_for (tree, tree, tree, cp_decomp *, bool, tree, bool); extern void cp_convert_omp_range_for (tree &, tree &, tree &, - tree &, tree &, tree &, tree &, tree &); + tree &, tree &, tree &, tree &, tree &, + bool); extern void cp_finish_omp_range_for (tree, tree); extern bool cp_maybe_parse_omp_decl (tree, tree); extern bool parsing_nsdmi (void); @@ -7809,6 +7810,7 @@ extern tree begin_for_stmt (tree, tree extern void finish_init_stmt (tree); extern void finish_for_cond (tree, tree, bool, tree, bool); extern void finish_for_expr (tree, tree); +extern void find_range_for_decls (tree[3]); extern void finish_for_stmt (tree); extern tree begin_range_for_stmt (tree, tree); extern void finish_range_for_decl (tree, tree, tree); --- gcc/cp/parser.cc.jj 2024-09-24 11:31:48.684622580 +0200 +++ gcc/cp/parser.cc 2024-09-24 14:41:01.505787999 +0200 @@ -14480,6 +14480,15 @@ cp_convert_range_for (tree statement, tr { range_temp = build_range_temp (range_expr); pushdecl (range_temp); + if (flag_range_for_ext_temps) + { + /* P2718R0 - put the range_temp declaration and everything + until end of the range for body into an extra STATEMENT_LIST + which will have CLEANUP_POINT_EXPR around it, so that all + temporaries are destroyed at the end of it. */ + gcc_assert (FOR_INIT_STMT (statement) == NULL_TREE); + FOR_INIT_STMT (statement) = push_stmt_list (); + } cp_finish_decl (range_temp, range_expr, /*is_constant_init*/false, NULL_TREE, LOOKUP_ONLYCONVERTING); @@ -44629,7 +44638,8 @@ cp_parser_omp_for_loop_init (cp_parser * void cp_convert_omp_range_for (tree &this_pre_body, tree &sl, tree &decl, tree &orig_decl, tree &init, - tree &orig_init, tree &cond, tree &incr) + tree &orig_init, tree &cond, tree &incr, + bool tmpl_p) { tree begin, end, range_temp_decl = NULL_TREE; tree iter_type, begin_expr, end_expr; @@ -44687,11 +44697,29 @@ cp_convert_omp_range_for (tree &this_pre else { range_temp = build_range_temp (init); - DECL_NAME (range_temp) = NULL_TREE; + tree name = DECL_NAME (range_temp); + /* Temporarily clear DECL_NAME of the __for_range temporary. + While it contains a space at the end and outside of templates + it works even without doing this, when cp_convert_omp_range_for + is called from tsubst_omp_for_iterator, all the associated loops + are in a single scope and so loop nests with 2 or more range + based for loops would error. */ + if (tmpl_p) + DECL_NAME (range_temp) = NULL_TREE; pushdecl (range_temp); + /* Restore the name back. This is needed for cp_finish_decl + lifetime extension of temporaries, and can be helpful for user + during debugging after the DECL_NAME is changed to __for_range + without space at the end. */ + if (tmpl_p) + DECL_NAME (range_temp) = name; cp_finish_decl (range_temp, init, /*is_constant_init*/false, NULL_TREE, LOOKUP_ONLYCONVERTING); + /* And clear the name again. pop_scope requires that the name + used during pushdecl didn't change. */ + if (tmpl_p) + DECL_NAME (range_temp) = NULL_TREE; range_temp_decl = range_temp; range_temp = convert_from_reference (range_temp); } @@ -44791,7 +44819,7 @@ cp_convert_omp_range_for (tree &this_pre the whole loop nest. The remaining elements are decls of derived decomposition variables that are bound inside the loop body. This structure is further mangled by finish_omp_for into the form required - for the OMP_FOR_ORIG_DECLS field of the OMP_FOR tree node. */\ + for the OMP_FOR_ORIG_DECLS field of the OMP_FOR tree node. */ unsigned decomp_cnt = decomp ? decomp->count : 0; tree v = make_tree_vec (decomp_cnt + 3); TREE_VEC_ELT (v, 0) = range_temp_decl; @@ -45360,7 +45388,7 @@ cp_parser_omp_loop_nest (cp_parser *pars cp_convert_omp_range_for (this_pre_body, sl, decl, orig_decl, init, orig_init, - cond, incr); + cond, incr, false); if (omp_for_parse_state->ordered_cl) error_at (OMP_CLAUSE_LOCATION (omp_for_parse_state->ordered_cl), @@ -45623,11 +45651,30 @@ cp_parser_omp_loop_nest (cp_parser *pars /* Pop and remember the init block. */ if (sl) - add_stmt (pop_stmt_list (sl)); + { + sl = pop_stmt_list (sl); + /* P2718R0 - Add CLEANUP_POINT_EXPR so that temporaries in + for-range-initializer whose lifetime is extended are destructed + here. */ + if (flag_range_for_ext_temps + && is_range_for + && !processing_template_decl) + sl = maybe_cleanup_point_expr_void (sl); + add_stmt (sl); + } + tree range_for_decl[3] = { NULL_TREE, NULL_TREE, NULL_TREE }; + if (is_range_for && !processing_template_decl) + find_range_for_decls (range_for_decl); finish_compound_stmt (init_scope); init_block = pop_stmt_list (init_block); omp_for_parse_state->init_blockv[depth] = init_block; + if (is_range_for && !processing_template_decl) + for (int i = 0; i < 3; i++) + if (range_for_decl[i]) + DECL_NAME (range_for_decl[i]) + = cp_global_trees[CPTI_FOR_RANGE_IDENTIFIER + i]; + /* Return the init placeholder rather than the remembered init block. Again, this is just a unique cookie that will be used to reassemble code pieces when the entire omp for statement has been parsed. */ --- gcc/cp/decl.cc.jj 2024-09-24 11:37:02.772332238 +0200 +++ gcc/cp/decl.cc 2024-09-24 11:38:20.535270020 +0200 @@ -8157,6 +8157,11 @@ initialize_local_var (tree decl, tree in code emitted by cp_finish_decomp. */ if (decomp) current_stmt_tree ()->stmts_are_full_exprs_p = 0; + /* P2718R0 - avoid CLEANUP_POINT_EXPR for range-for-initializer, + temporaries from there should have lifetime extended. */ + else if (DECL_NAME (decl) == for_range__identifier + && flag_range_for_ext_temps) + current_stmt_tree ()->stmts_are_full_exprs_p = 0; else current_stmt_tree ()->stmts_are_full_exprs_p = 1; finish_expr_stmt (init); --- gcc/cp/call.cc.jj 2024-09-24 11:31:37.386776907 +0200 +++ gcc/cp/call.cc 2024-09-24 11:37:02.774332211 +0200 @@ -14564,6 +14564,12 @@ extend_ref_init_temps (tree decl, tree i if (processing_template_decl) return init; + /* P2718R0 - ignore temporaries in C++23 for-range-initializer, those + have all extended lifetime. */ + if (DECL_NAME (decl) == for_range__identifier + && flag_range_for_ext_temps) + return init; + maybe_warn_dangling_reference (decl, init); if (TYPE_REF_P (type)) --- gcc/cp/semantics.cc.jj 2024-09-24 11:31:37.516775131 +0200 +++ gcc/cp/semantics.cc 2024-09-24 12:20:35.083694190 +0200 @@ -1637,6 +1637,31 @@ finish_for_expr (tree expr, tree for_stm FOR_EXPR (for_stmt) = expr; } +void +find_range_for_decls (tree range_for_decl[3]) +{ + /* During parsing of the body, range for uses "__for_{range,begin,end} " + decl names to make those unaccessible by code in the body. + Change it to ones with underscore instead of space, so that it can + be inspected in the debugger. */ + gcc_assert (CPTI_FOR_BEGIN__IDENTIFIER == CPTI_FOR_RANGE__IDENTIFIER + 1 + && CPTI_FOR_END__IDENTIFIER == CPTI_FOR_RANGE__IDENTIFIER + 2 + && CPTI_FOR_RANGE_IDENTIFIER == CPTI_FOR_RANGE__IDENTIFIER + 3 + && CPTI_FOR_BEGIN_IDENTIFIER == CPTI_FOR_BEGIN__IDENTIFIER + 3 + && CPTI_FOR_END_IDENTIFIER == CPTI_FOR_END__IDENTIFIER + 3); + for (int i = 0; i < 3; i++) + { + tree id = cp_global_trees[CPTI_FOR_RANGE__IDENTIFIER + i]; + if (IDENTIFIER_BINDING (id) + && IDENTIFIER_BINDING (id)->scope == current_binding_level) + { + range_for_decl[i] = IDENTIFIER_BINDING (id)->value; + gcc_assert (VAR_P (range_for_decl[i]) + && DECL_ARTIFICIAL (range_for_decl[i])); + } + } +} + /* Finish the body of a for-statement, which may be given by FOR_STMT. The increment-EXPR for the loop must be provided. @@ -1670,21 +1695,20 @@ finish_for_stmt (tree for_stmt) Change it to ones with underscore instead of space, so that it can be inspected in the debugger. */ tree range_for_decl[3] = { NULL_TREE, NULL_TREE, NULL_TREE }; - gcc_assert (CPTI_FOR_BEGIN__IDENTIFIER == CPTI_FOR_RANGE__IDENTIFIER + 1 - && CPTI_FOR_END__IDENTIFIER == CPTI_FOR_RANGE__IDENTIFIER + 2 - && CPTI_FOR_RANGE_IDENTIFIER == CPTI_FOR_RANGE__IDENTIFIER + 3 - && CPTI_FOR_BEGIN_IDENTIFIER == CPTI_FOR_BEGIN__IDENTIFIER + 3 - && CPTI_FOR_END_IDENTIFIER == CPTI_FOR_END__IDENTIFIER + 3); - for (int i = 0; i < 3; i++) + find_range_for_decls (range_for_decl); + + /* P2718R0 - Add CLEANUP_POINT_EXPR so that temporaries in + for-range-initializer whose lifetime is extended are destructed + here. */ + if (flag_range_for_ext_temps + && range_for_decl[0] + && FOR_INIT_STMT (for_stmt)) { - tree id = cp_global_trees[CPTI_FOR_RANGE__IDENTIFIER + i]; - if (IDENTIFIER_BINDING (id) - && IDENTIFIER_BINDING (id)->scope == current_binding_level) - { - range_for_decl[i] = IDENTIFIER_BINDING (id)->value; - gcc_assert (VAR_P (range_for_decl[i]) - && DECL_ARTIFICIAL (range_for_decl[i])); - } + tree stmt = pop_stmt_list (FOR_INIT_STMT (for_stmt)); + FOR_INIT_STMT (for_stmt) = NULL_TREE; + stmt = build_stmt (EXPR_LOCATION (for_stmt), EXPR_STMT, stmt); + stmt = maybe_cleanup_point_expr_void (stmt); + add_stmt (stmt); } add_stmt (do_poplevel (scope)); --- gcc/cp/pt.cc.jj 2024-09-24 11:31:37.495775418 +0200 +++ gcc/cp/pt.cc 2024-09-24 14:42:19.277739068 +0200 @@ -18127,7 +18127,7 @@ tsubst_omp_for_iterator (tree t, int i, tree orig_decl = NULL_TREE; tree init_sl = NULL_TREE; cp_convert_omp_range_for (this_pre_body, init_sl, decl, orig_decl, init, - orig_init, cond, incr); + orig_init, cond, incr, true); if (orig_decl) { if (orig_declv == NULL_TREE) @@ -19156,6 +19156,18 @@ tsubst_stmt (tree t, tree args, tsubst_f RECUR (OMP_FOR_PRE_BODY (t)); pre_body = pop_stmt_list (pre_body); + tree sl = NULL_TREE; + if (flag_range_for_ext_temps + && OMP_FOR_INIT (t) != NULL_TREE + && !processing_template_decl) + for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (t)); i++) + if (TREE_VEC_ELT (OMP_FOR_INIT (t), i) + && TREE_VEC_ELT (OMP_FOR_COND (t), i) == global_namespace) + { + sl = push_stmt_list (); + break; + } + if (OMP_FOR_INIT (t) != NULL_TREE) for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (t)); i++) { @@ -19211,9 +19223,34 @@ tsubst_stmt (tree t, tree args, tsubst_f add_stmt (t); } + if (sl) + { + /* P2718R0 - Add CLEANUP_POINT_EXPR so that temporaries in + for-range-initializer whose lifetime is extended are destructed + here. */ + sl = pop_stmt_list (sl); + sl = maybe_cleanup_point_expr_void (sl); + add_stmt (sl); + } + add_stmt (finish_omp_for_block (finish_omp_structured_block (stmt), t)); pop_omp_privatization_clauses (r); + + if (any_range_for && !processing_template_decl && t) + for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (t)); i++) + if (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (t), i) + && TREE_CODE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (t), + i)) == TREE_LIST) + { + tree v = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (t), i); + if (TREE_CHAIN (v) == NULL_TREE + || TREE_CODE (TREE_CHAIN (v)) != TREE_VEC) + continue; + v = TREE_VEC_ELT (TREE_CHAIN (v), 0); + gcc_assert (VAR_P (v) && DECL_NAME (v) == NULL_TREE); + DECL_NAME (v) = for_range_identifier; + } } break; --- gcc/testsuite/g++.dg/cpp23/range-for1.C.jj 2024-09-24 11:37:02.779332142 +0200 +++ gcc/testsuite/g++.dg/cpp23/range-for1.C 2024-09-24 13:45:38.218063385 +0200 @@ -0,0 +1,222 @@ +// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop +// { dg-do run { target c++11 } } + +#ifndef RANGE_FOR_EXT_TEMPS +#define RANGE_FOR_EXT_TEMPS (__cpp_range_based_for >= 202211L) +#else +#if __cplusplus >= 201703L +#if RANGE_FOR_EXT_TEMPS +static_assert (__cpp_range_based_for >= 202211L, ""); +#else +static_assert (__cpp_range_based_for >= 201603L + && __cpp_range_based_for < 202211L, ""); +#endif +#else +static_assert (__cpp_range_based_for >= 200907L + && __cpp_range_based_for < 201603L, ""); +#endif +#endif + +extern "C" void abort (); +void check (bool); + +struct S +{ + S () { ++s; } + S (const S &) { ++s; } + ~S () { check (true); --s; } + static int s; +}; + +int S::s = -1; +S sv; + +struct T +{ + T (const S &, const S &) { ++t; } + T (const T &) { ++t; } + ~T () { check (false); --t; } + static int t; +}; + +int T::t = -1; +T tv (sv, sv); +int a[4]; +int c; + +void +check (bool is_s) +{ + if (c) + { + if (is_s) + { + if (T::t != (c == 1)) + abort (); + } + else + { + if (S::s != (c == 1 ? 0 : 2)) + abort (); + } + } +} + +template +int * +begin (const T &) +{ + return &a[0]; +} + +template +int * +end (const T &) +{ + return &a[4]; +} + +const S & +foo (const S &) +{ + return sv; +} + +const T & +foo (const T &) +{ + return tv; +} + +void +bar () +{ + if (S::s != 0) + abort (); + for (auto x : S ()) + { + if (S::s != 1) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : foo (S ())) + { + if (S::s != RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0) + abort (); + if (T::t != 0) + abort (); + c = 1 + RANGE_FOR_EXT_TEMPS; + for (auto x : T (S (), S ())) + { + if (S::s != 2 * RANGE_FOR_EXT_TEMPS || T::t != 1) + abort (); + } + if (S::s != 0 || T::t != 0) + abort (); + c = 2; + for (auto x : foo (T (S (), S ()))) + { + if (S::s != 2 * RANGE_FOR_EXT_TEMPS + || T::t != RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0 || T::t != 0) + abort (); + c = 0; +} + +template +void +baz () +{ + if (S::s != 0) + abort (); + for (auto x : S ()) + { + if (S::s != 1) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : foo (S ())) + { + if (S::s != RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0) + abort (); + if (T::t != 0) + abort (); + c = 1 + RANGE_FOR_EXT_TEMPS; + for (auto x : T (S (), S ())) + { + if (S::s != 2 * RANGE_FOR_EXT_TEMPS || T::t != 1) + abort (); + } + if (S::s != 0 || T::t != 0) + abort (); + c = 2; + for (auto x : foo (T (S (), S ()))) + { + if (S::s != 2 * RANGE_FOR_EXT_TEMPS + || T::t != RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0 || T::t != 0) + abort (); + c = 0; +} + +template +void +qux () +{ + if (S::s != 0) + abort (); + for (auto x : S ()) + { + if (S::s != 1) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : foo (S ())) + { + if (S::s != RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0) + abort (); + if (T::t != 0) + abort (); + c = 1 + RANGE_FOR_EXT_TEMPS; + for (auto x : T (S (), S ())) + { + if (S::s != 2 * RANGE_FOR_EXT_TEMPS || T::t != 1) + abort (); + } + if (S::s != 0 || T::t != 0) + abort (); + c = 2; + for (auto x : foo (T (S (), S ()))) + { + if (S::s != 2 * RANGE_FOR_EXT_TEMPS + || T::t != RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0 || T::t != 0) + abort (); + c = 0; +} + +int +main () +{ + bar (); + baz <0> (); + qux (); +} --- gcc/testsuite/g++.dg/cpp23/range-for2.C.jj 2024-09-24 11:37:02.779332142 +0200 +++ gcc/testsuite/g++.dg/cpp23/range-for2.C 2024-09-24 13:46:31.802331179 +0200 @@ -0,0 +1,231 @@ +// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop +// { dg-do run { target c++11 } } + +#ifndef RANGE_FOR_EXT_TEMPS +#define RANGE_FOR_EXT_TEMPS (__cpp_range_based_for >= 202211L) +#endif + +extern "C" void abort (); + +int a[4]; + +template +int * +begin (const T &) +{ + return &a[0]; +} + +template +int * +end (const T &) +{ + return &a[4]; +} + +struct S +{ + S () { ++s; } + S (const S &) { ++s; } + ~S () { --s; } + static int s; +}; + +int S::s; + +template +struct U +{ + T t; + U () { ++u; } + U (const U &) { ++u; } + ~U () { --u; } + const int *begin () const { return ::begin (t); } + const int *end () const { return ::end (t); } + U &foo () { return *this; } + U bar () { return U (); } + static int u; +}; + +template +int U::u; + +template +U +foo () +{ + return U {}; +} + +template +T +fred (const T &, const T & = T{}, const T & = T{}) +{ + return T {}; +} + +void +bar () +{ + int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + if (S::s != 0) + abort (); + for (auto x : S (), a) + { + if (S::s != RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : (void) S (), a) + { + if (S::s != RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : static_cast (S ()), a) + { + if (S::s != RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : foo ().foo ().bar ().foo ().bar ().foo ().bar ()) + { + if (S::s != 1 + 3 * RANGE_FOR_EXT_TEMPS) + abort (); + if (U::u != S::s) + abort (); + } + if (S::s != 0 || U::u != 0) + abort (); + for (auto x : fred (S {})) + { + if (S::s != 1 + 3 * RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : fred (fred (S {}, S {}))) + { + if (S::s != 1 + 6 * RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0) + abort (); +} + +template +void +baz () +{ + int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + if (S::s != 0) + abort (); + for (auto x : S (), a) + { + if (S::s != RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : (void) S (), a) + { + if (S::s != RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : static_cast (S ()), a) + { + if (S::s != RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : foo ().foo ().bar ().foo ().bar ().foo ().bar ()) + { + if (S::s != 1 + 3 * RANGE_FOR_EXT_TEMPS) + abort (); + if (U::u != S::s) + abort (); + } + if (S::s != 0 || U::u != 0) + abort (); + for (auto x : fred (S {})) + { + if (S::s != 1 + 3 * RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : fred (fred (S {}, S {}))) + { + if (S::s != 1 + 6 * RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0) + abort (); +} + +template +void +qux () +{ + int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + if (S::s != 0) + abort (); + for (auto x : S (), a) + { + if (S::s != RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : (void) S (), a) + { + if (S::s != RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : static_cast (S ()), a) + { + if (S::s != RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : foo ().foo ().bar ().foo ().bar ().foo ().bar ()) + { + if (S::s != 1 + 3 * RANGE_FOR_EXT_TEMPS) + abort (); + if (U::u != S::s) + abort (); + } + if (S::s != 0 || U::u != 0) + abort (); + for (auto x : fred (S {})) + { + if (S::s != 1 + 3 * RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : fred (fred (S {}, S {}))) + { + if (S::s != 1 + 6 * RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0) + abort (); +} + +int +main () +{ + bar (); + baz <0> (); + qux (); +} --- gcc/testsuite/g++.dg/cpp23/range-for3.C.jj 2024-09-24 13:46:42.151189765 +0200 +++ gcc/testsuite/g++.dg/cpp23/range-for3.C 2024-09-24 13:47:26.571582778 +0200 @@ -0,0 +1,6 @@ +// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop +// { dg-do run { target c++11 } } +// { dg-options "" } + +#define RANGE_FOR_EXT_TEMPS 1 +#include "range-for1.C" --- gcc/testsuite/g++.dg/cpp23/range-for4.C.jj 2024-09-24 13:47:35.949454632 +0200 +++ gcc/testsuite/g++.dg/cpp23/range-for4.C 2024-09-24 13:47:47.078302564 +0200 @@ -0,0 +1,6 @@ +// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop +// { dg-do run { target c++11 } } +// { dg-options "" } + +#define RANGE_FOR_EXT_TEMPS 1 +#include "range-for2.C" --- gcc/testsuite/g++.dg/cpp23/range-for5.C.jj 2024-09-24 13:52:10.709700152 +0200 +++ gcc/testsuite/g++.dg/cpp23/range-for5.C 2024-09-24 13:54:45.031591404 +0200 @@ -0,0 +1,8 @@ +// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop +// { dg-do run { target c++11 } } +// { dg-options "-fno-range-for-ext-temps" } + +#if __cplusplus <= 202002L +#define RANGE_FOR_EXT_TEMPS 0 +#endif +#include "range-for1.C" --- gcc/testsuite/g++.dg/cpp23/range-for6.C.jj 2024-09-24 13:54:53.146480511 +0200 +++ gcc/testsuite/g++.dg/cpp23/range-for6.C 2024-09-24 13:54:59.713390778 +0200 @@ -0,0 +1,8 @@ +// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop +// { dg-do run { target c++11 } } +// { dg-options "-fno-range-for-ext-temps" } + +#if __cplusplus <= 202002L +#define RANGE_FOR_EXT_TEMPS 0 +#endif +#include "range-for2.C" --- gcc/testsuite/g++.dg/cpp23/range-for7.C.jj 2024-09-24 13:55:14.980182159 +0200 +++ gcc/testsuite/g++.dg/cpp23/range-for7.C 2024-09-24 13:55:36.945882011 +0200 @@ -0,0 +1,6 @@ +// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop +// { dg-do run { target c++17_only } } +// { dg-options "-std=c++17 -frange-for-ext-temps" } + +#define RANGE_FOR_EXT_TEMPS 1 +#include "range-for1.C" --- gcc/testsuite/g++.dg/cpp23/range-for8.C.jj 2024-09-24 13:55:44.815774472 +0200 +++ gcc/testsuite/g++.dg/cpp23/range-for8.C 2024-09-24 13:55:56.186619103 +0200 @@ -0,0 +1,6 @@ +// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop +// { dg-do run { target c++11_only } } +// { dg-options "-std=c++11 -frange-for-ext-temps" } + +#define RANGE_FOR_EXT_TEMPS 1 +#include "range-for2.C" --- gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C.jj 2024-09-24 11:31:37.555774598 +0200 +++ gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C 2024-09-24 11:37:02.779332142 +0200 @@ -43,8 +43,8 @@ #ifndef __cpp_range_based_for # error "__cpp_range_based_for" -#elif __cpp_range_based_for != 201603 -# error "__cpp_range_based_for != 201603" +#elif __cpp_range_based_for != 202211 +# error "__cpp_range_based_for != 202211" #endif #ifndef __cpp_decltype --- gcc/testsuite/g++.dg/cpp26/feat-cxx26.C.jj 2024-09-24 11:31:37.555774598 +0200 +++ gcc/testsuite/g++.dg/cpp26/feat-cxx26.C 2024-09-24 11:37:02.780332129 +0200 @@ -43,8 +43,8 @@ #ifndef __cpp_range_based_for # error "__cpp_range_based_for" -#elif __cpp_range_based_for != 201603 -# error "__cpp_range_based_for != 201603" +#elif __cpp_range_based_for != 202211 +# error "__cpp_range_based_for != 202211" #endif #ifndef __cpp_decltype --- gcc/testsuite/g++.dg/warn/Wdangling-reference4.C.jj 2024-09-24 11:31:37.556774585 +0200 +++ gcc/testsuite/g++.dg/warn/Wdangling-reference4.C 2024-09-24 11:37:02.780332129 +0200 @@ -1,5 +1,5 @@ // { dg-do compile { target c++17 } } -// { dg-options "-Wdangling-reference" } +// { dg-additional-options "-Wdangling-reference" } // { dg-skip-if "requires hosted libstdc++ for string" { ! hostedlib } } // Check that we warn here even without -Wsystem-headers. @@ -11,5 +11,5 @@ auto f() -> std::optional; void g () { - for (char c : f().value()) { (void) c; } // { dg-warning "dangling reference" } + for (char c : f().value()) { (void) c; } // { dg-warning "dangling reference" "" { target c++20_down } } } --- libgomp/testsuite/libgomp.c++/range-for-1.C.jj 2024-09-24 11:37:02.780332129 +0200 +++ libgomp/testsuite/libgomp.c++/range-for-1.C 2024-09-24 14:00:52.214575429 +0200 @@ -0,0 +1,250 @@ +// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop +// { dg-do run } +// { dg-additional-options "-std=c++17" } +// { dg-require-effective-target tls_runtime } + +#ifndef RANGE_FOR_EXT_TEMPS +#define RANGE_FOR_EXT_TEMPS (__cpp_range_based_for >= 202211L) +#endif + +extern "C" void abort (); +void check (bool); + +struct S +{ + S () { ++s; } + S (const S &) { ++s; } + ~S () { check (true); --s; } + [[omp::decl (threadprivate)]] static int s; +}; +int S::s; +S sv; +struct T +{ + T (const S &, const S &) { ++t; } + T (const T &) { ++t; } + ~T () { check (false); --t; } + [[omp::decl (threadprivate)]] static int t; +}; +int T::t; +T tv (sv, sv); +int a[4]; +int c; + +void +check (bool is_s) +{ + if (c) + { + if (is_s) + { + if (T::t != (c == 1)) + abort (); + } + else + { + if (S::s != (c == 1 ? 0 : 2)) + abort (); + } + } +} + +template +int * +begin (const T &) +{ + return &a[0]; +} + +template +int * +end (const T &) +{ + return &a[4]; +} + +const S & +foo (const S &) +{ + return sv; +} + +const T & +foo (const T &) +{ + return tv; +} + +void +bar () +{ + #pragma omp parallel num_threads (4) + { + if (S::s != 0) + abort (); + #pragma omp for + for (auto x : S ()) + { + if (S::s != 1) + abort (); + } + if (S::s != 0) + abort (); + #pragma omp for + for (auto x : foo (S ())) + { + if (S::s != RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0) + abort (); + if (T::t != 0) + abort (); + } + c = 1 + RANGE_FOR_EXT_TEMPS; + #pragma omp parallel num_threads (4) + { + #pragma omp for + for (auto x : T (S (), S ())) + { + if (S::s != 2 * RANGE_FOR_EXT_TEMPS || T::t != 1) + abort (); + } + if (S::s != 0 || T::t != 0) + abort (); + } + c = 2; + #pragma omp parallel num_threads (4) + { + #pragma omp for + for (auto x : foo (T (S (), S ()))) + { + if (S::s != 2 * RANGE_FOR_EXT_TEMPS + || T::t != RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0 || T::t != 0) + abort (); + } + c = 0; +} + +template +void +baz () +{ + #pragma omp parallel num_threads (4) + { + if (S::s != 0) + abort (); + #pragma omp for + for (auto x : S ()) + { + if (S::s != 1) + abort (); + } + if (S::s != 0) + abort (); + #pragma omp for + for (auto x : foo (S ())) + { + if (S::s != RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0) + abort (); + if (T::t != 0) + abort (); + } + c = 1 + RANGE_FOR_EXT_TEMPS; + #pragma omp parallel num_threads (4) + { + #pragma omp for + for (auto x : T (S (), S ())) + { + if (S::s != 2 * RANGE_FOR_EXT_TEMPS || T::t != 1) + abort (); + } + if (S::s != 0 || T::t != 0) + abort (); + } + c = 2; + #pragma omp parallel num_threads (4) + { + #pragma omp for + for (auto x : foo (T (S (), S ()))) + { + if (S::s != 2 * RANGE_FOR_EXT_TEMPS + || T::t != RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0 || T::t != 0) + abort (); + } + c = 0; +} + +template +void +qux () +{ + #pragma omp parallel num_threads (4) + { + if (S::s != 0) + abort (); + #pragma omp for + for (auto x : S ()) + { + if (S::s != 1) + abort (); + } + if (S::s != 0) + abort (); + #pragma omp for + for (auto x : foo (S ())) + { + if (S::s != RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0) + abort (); + if (T::t != 0) + abort (); + } + c = 1 + RANGE_FOR_EXT_TEMPS; + #pragma omp parallel num_threads (4) + { + #pragma omp for + for (auto x : T (S (), S ())) + { + if (S::s != 2 * RANGE_FOR_EXT_TEMPS || T::t != 1) + abort (); + } + if (S::s != 0 || T::t != 0) + abort (); + } + c = 2; + #pragma omp parallel num_threads (4) + { + #pragma omp for + for (auto x : foo (T (S (), S ()))) + { + if (S::s != 2 * RANGE_FOR_EXT_TEMPS + || T::t != RANGE_FOR_EXT_TEMPS) + abort (); + } + if (S::s != 0 || T::t != 0) + abort (); + } + c = 0; +} + +int +main () +{ + S::s--; + T::t--; + bar (); + baz <0> (); + qux (); +} --- libgomp/testsuite/libgomp.c++/range-for-2.C.jj 2024-09-24 11:37:02.780332129 +0200 +++ libgomp/testsuite/libgomp.c++/range-for-2.C 2024-09-24 11:37:02.780332129 +0200 @@ -0,0 +1,6 @@ +// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop +// { dg-do run } +// { dg-additional-options "-std=c++23" } +// { dg-require-effective-target tls_runtime } + +#include "range-for-1.C" --- libgomp/testsuite/libgomp.c++/range-for-3.C.jj 2024-09-24 14:03:08.554714647 +0200 +++ libgomp/testsuite/libgomp.c++/range-for-3.C 2024-09-24 14:02:02.282619132 +0200 @@ -0,0 +1,7 @@ +// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop +// { dg-do run } +// { dg-additional-options "-std=c++17 -frange-for-ext-temps" } +// { dg-require-effective-target tls_runtime } + +#define RANGE_FOR_EXT_TEMPS 1 +#include "range-for-1.C" --- libgomp/testsuite/libgomp.c++/range-for-4.C.jj 2024-09-24 14:03:15.428620831 +0200 +++ libgomp/testsuite/libgomp.c++/range-for-4.C 2024-09-24 14:02:22.983336609 +0200 @@ -0,0 +1,7 @@ +// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop +// { dg-do run } +// { dg-additional-options "-std=gnu++17" } +// { dg-require-effective-target tls_runtime } + +#define RANGE_FOR_EXT_TEMPS 1 +#include "range-for-1.C" --- libgomp/testsuite/libgomp.c++/range-for-5.C.jj 2024-09-24 14:03:26.801465614 +0200 +++ libgomp/testsuite/libgomp.c++/range-for-5.C 2024-09-24 14:02:53.986913469 +0200 @@ -0,0 +1,7 @@ +// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop +// { dg-do run } +// { dg-additional-options "-std=gnu++17 -fno-range-for-ext-temps" } +// { dg-require-effective-target tls_runtime } + +#define RANGE_FOR_EXT_TEMPS 0 +#include "range-for-1.C"