From patchwork Fri Aug 9 19:06:07 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 1971069 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=aywDVtM4; 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 4WgYLD0Zssz1yXs for ; Sat, 10 Aug 2024 05:06:40 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 925CC385DDD7 for ; Fri, 9 Aug 2024 19:06:38 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id E42AA385DDC1 for ; Fri, 9 Aug 2024 19:06:14 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E42AA385DDC1 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 E42AA385DDC1 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1723230378; cv=none; b=ppl2nMZ52I9jmAsJ6WFalXmDRdSaMDpvJwxv1T2SKjxt4DQIGULtw3GrmrLkHh7LOfa0vX/phF8XrZwWOrrPBMcrncr2T+flgbN09cd/pCCarMnQktx5kFnvE7/i3ThWdKunnPo+WR34xkD/SikwutsRY/SoZYB9NozhXrBxaXc= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1723230378; c=relaxed/simple; bh=mrCS3kLyMzz65BM5AMX/rG1+WHt+1s9x2zmcw3AIHWg=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=xhCj4EaXbYsg6p0Bszdh+012s1EvQIm18/C6YVRVnZyUO3In38i/DADKo3qLEdSHIO4CeIZ5OsW9qw8MaZMHBaTJmr6C3h0WvXi6papHQPOttXZN+0cRb1KcbrZ6ocoS7BdKRdP2gkN3BS+wxug5fkHMNj2bydrXaQpNvYqi/wk= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1723230374; 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=NF5QFHrNWfpQ4UX/ULlhVOdLmCpBMv602sPSaDq59Jw=; b=aywDVtM4G0Ollay4u/26g6sUEjcMWflpgP7nKhcUjXZUa1LGx+UkavPCVAVZoyDxaLBcHY MF3iySqO8gHvNMGO/AtHpuI+nmoQFlcWihWL1Ef+5TpCTR39XlOzDV5Qp6me/Rr8NvCaCZ nDVqbAWY9B9T+9TAtNRb8KcFh2kuvwA= 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-264-Ukn8tMHHP6edi8NWd21CWA-1; Fri, 09 Aug 2024 15:06:13 -0400 X-MC-Unique: Ukn8tMHHP6edi8NWd21CWA-1 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.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 mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 0C17F1955D59 for ; Fri, 9 Aug 2024 19:06:12 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.45.224.25]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id DD6053000199; Fri, 9 Aug 2024 19:06:10 +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 479J67D22963997 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Fri, 9 Aug 2024 21:06:07 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 479J67F12963996; Fri, 9 Aug 2024 21:06:07 +0200 Date: Fri, 9 Aug 2024 21:06:07 +0200 From: Jakub Jelinek To: Jason Merrill Cc: gcc-patches@gcc.gnu.org Subject: [PATCH] c++: Implement C++23 P2718R0 - Wording for P2644R1 Fix for Range-based for Loop [PR107637] Message-ID: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 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_H4, 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 Hi! The following patch implements the C++23 P2718R0 paper - Wording for P2644R1 Fix for Range-based for Loop. As all the temporaries from __for_range initialization should have life extended until the end of __for_range scope, this patch disables (for C++23 and later only and if !processing_template_decl) CLEANUP_POINT_EXPR wrapping of the __for_range declaration, also disables -Wdangling-reference warning as well as the rest of extend_ref_init_temps (we know the __for_range temporary is not TREE_STATIC and as all the temporaries from the initializer will be life extended, we shouldn't try to handle temporaries referenced by references any differently) and adds an extra push_stmt_list/pop_stmt_list before cp_finish_decl of __for_range and after end of the for body and wraps all that into CLEANUP_POINT_EXPR. I had to repeat that also for OpenMP range loops because those are handled differently. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2024-08-09 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. gcc/c-family/ * c-cppbuiltin.cc (c_cpp_builtins): Change __cpp_range_based_for value for C++23 and newer from 201603L to 202212L. * c-omp.cc (c_find_nested_loop_xform_r): Handle CLEANUP_POINT_EXPR like TRY_FINALLY_EXPR. gcc/cp/ * parser.cc: Implement C++23 P2718R0 - Wording for P2644R1 Fix for Range-based for Loop. (cp_convert_range_for): For C++23 call push_stmt_list () before cp_finish_decl for range_temp and save it temporarily to FOR_INIT_STMT. (cp_convert_omp_range_for): Remember DECL_NAME of range_temp and for cp_finish_decl call restore it before clearing it again. (cp_parser_omp_loop_nest): For C++23 range for add CLEANUP_POINT_EXPR around sl. * decl.cc (initialize_local_var): For C++23 temporarily clear stmts_are_full_exprs_p rather than set for for_range__identifier decls. * call.cc (extend_ref_init_temps): For C++23 return init early for for_range__identifier decls. * semantics.cc (finish_for_stmt): For C++23 if cp_convert_range_for set FOR_INIT_STMT, pop_stmt_list it and wrap into CLEANUP_POINT_EXPR. * pt.cc (tsubst_stmt) : For C++23 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. gcc/testsuite/ * g++.dg/cpp23/range-for1.C: New test. * g++.dg/cpp23/range-for2.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. libgomp/ * testsuite/libgomp.c++/range-for-1.C: New test. * testsuite/libgomp.c++/range-for-2.C: New test. Jakub --- gcc/omp-general.cc.jj 2024-06-05 19:09:54.052616928 +0200 +++ gcc/omp-general.cc 2024-08-09 17:01:01.641036347 +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; @@ -4105,6 +4106,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/c-family/c-cppbuiltin.cc.jj 2024-07-12 14:03:23.453732902 +0200 +++ gcc/c-family/c-cppbuiltin.cc 2024-08-08 20:03:17.503775789 +0200 @@ -1034,7 +1034,8 @@ 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 (cxx_dialect <= cxx20) + cpp_define (pfile, "__cpp_range_based_for=201603L"); if (cxx_dialect <= cxx17) cpp_define (pfile, "__cpp_constexpr=201603L"); cpp_define (pfile, "__cpp_if_constexpr=201606L"); @@ -1087,6 +1088,7 @@ c_cpp_builtins (cpp_reader *pfile) cpp_define (pfile, "__cpp_static_call_operator=202207L"); cpp_define (pfile, "__cpp_implicit_move=202207L"); cpp_define (pfile, "__cpp_explicit_this_parameter=202110L"); + cpp_define (pfile, "__cpp_range_based_for=202211L"); } if (cxx_dialect > cxx23) { --- gcc/c-family/c-omp.cc.jj 2024-06-05 19:09:54.054616902 +0200 +++ gcc/c-family/c-omp.cc 2024-08-09 17:13:40.653767553 +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/parser.cc.jj 2024-08-07 09:38:00.642810039 +0200 +++ gcc/cp/parser.cc 2024-08-09 17:11:36.756252734 +0200 @@ -14440,6 +14440,15 @@ cp_convert_range_for (tree statement, tr { range_temp = build_range_temp (range_expr); pushdecl (range_temp); + if (cxx_dialect >= cxx23) + { + /* 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); @@ -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; range_temp_decl = range_temp; range_temp = convert_from_reference (range_temp); } @@ -45538,7 +45550,15 @@ 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 (cxx_dialect >= cxx23 && is_range_for && !processing_template_decl) + sl = maybe_cleanup_point_expr_void (sl); + add_stmt (sl); + } finish_compound_stmt (init_scope); init_block = pop_stmt_list (init_block); omp_for_parse_state->init_blockv[depth] = init_block; --- gcc/cp/decl.cc.jj 2024-08-07 11:58:11.275368835 +0200 +++ gcc/cp/decl.cc 2024-08-08 19:08:07.393522430 +0200 @@ -8111,7 +8111,13 @@ initialize_local_var (tree decl, tree in gcc_assert (building_stmt_list_p ()); saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p (); - current_stmt_tree ()->stmts_are_full_exprs_p = 1; + /* P2718R0 - avoid CLEANUP_POINT_EXPR for range-for-initializer, + temporaries from there should have lifetime extended. */ + if (DECL_NAME (decl) == for_range__identifier + && cxx_dialect >= cxx23) + current_stmt_tree ()->stmts_are_full_exprs_p = 0; + else + current_stmt_tree ()->stmts_are_full_exprs_p = 1; finish_expr_stmt (init); current_stmt_tree ()->stmts_are_full_exprs_p = saved_stmts_are_full_exprs_p; --- gcc/cp/call.cc.jj 2024-08-06 11:05:29.098470099 +0200 +++ gcc/cp/call.cc 2024-08-08 19:02:29.619882199 +0200 @@ -14514,6 +14514,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 + && cxx_dialect >= cxx23) + return init; + maybe_warn_dangling_reference (decl, init); if (TYPE_REF_P (type)) --- gcc/cp/semantics.cc.jj 2024-08-06 11:05:29.211468580 +0200 +++ gcc/cp/semantics.cc 2024-08-09 11:29:12.553445065 +0200 @@ -1601,6 +1601,20 @@ finish_for_stmt (tree for_stmt) } } + /* P2718R0 - Add CLEANUP_POINT_EXPR so that temporaries in + for-range-initializer whose lifetime is extended are destructed + here. */ + if (cxx_dialect >= cxx23 + && range_for_decl[0] + && FOR_INIT_STMT (for_stmt)) + { + 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)); /* If we're being called from build_vec_init, don't mess with the names of --- gcc/cp/pt.cc.jj 2024-08-07 09:47:59.912769436 +0200 +++ gcc/cp/pt.cc 2024-08-09 17:11:03.082656385 +0200 @@ -19099,6 +19099,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 (cxx_dialect >= cxx23 + && 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++) { @@ -19154,6 +19166,16 @@ 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); --- gcc/testsuite/g++.dg/cpp23/range-for1.C.jj 2024-08-09 11:15:18.162167370 +0200 +++ gcc/testsuite/g++.dg/cpp23/range-for1.C 2024-08-09 20:29:14.084033001 +0200 @@ -0,0 +1,206 @@ +// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop +// { dg-do run { target c++11 } } + +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 != (__cpp_range_based_for >= 202211L)) + abort (); + } + if (S::s != 0) + abort (); + if (T::t != 0) + abort (); + c = 1 + (__cpp_range_based_for >= 202211L); + for (auto x : T (S (), S ())) + { + if (S::s != 2 * (__cpp_range_based_for >= 202211L) || 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 * (__cpp_range_based_for >= 202211L) + || T::t != (__cpp_range_based_for >= 202211L)) + 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 != (__cpp_range_based_for >= 202211L)) + abort (); + } + if (S::s != 0) + abort (); + if (T::t != 0) + abort (); + c = 1 + (__cpp_range_based_for >= 202211L); + for (auto x : T (S (), S ())) + { + if (S::s != 2 * (__cpp_range_based_for >= 202211L) || 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 * (__cpp_range_based_for >= 202211L) + || T::t != (__cpp_range_based_for >= 202211L)) + 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 != (__cpp_range_based_for >= 202211L)) + abort (); + } + if (S::s != 0) + abort (); + if (T::t != 0) + abort (); + c = 1 + (__cpp_range_based_for >= 202211L); + for (auto x : T (S (), S ())) + { + if (S::s != 2 * (__cpp_range_based_for >= 202211L) || 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 * (__cpp_range_based_for >= 202211L) + || T::t != (__cpp_range_based_for >= 202211L)) + 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-08-09 14:08:11.850733241 +0200 +++ gcc/testsuite/g++.dg/cpp23/range-for2.C 2024-08-09 14:07:41.638122308 +0200 @@ -0,0 +1,230 @@ +// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop +// { dg-do run { target c++11 } } + +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 != (__cpp_range_based_for >= 202211L)) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : (void) S (), a) + { + if (S::s != (__cpp_range_based_for >= 202211L)) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : static_cast (S ()), a) + { + if (S::s != (__cpp_range_based_for >= 202211L)) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : foo ().foo ().bar ().foo ().bar ().foo ().bar ()) + { + if (S::s != 1 + 3 * (__cpp_range_based_for >= 202211L)) + 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 * (__cpp_range_based_for >= 202211L)) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : fred (fred (S {}, S {}))) + { + __builtin_printf ("%d\n", S::s); + if (S::s != 1 + 6 * (__cpp_range_based_for >= 202211L)) + 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 != (__cpp_range_based_for >= 202211L)) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : (void) S (), a) + { + if (S::s != (__cpp_range_based_for >= 202211L)) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : static_cast (S ()), a) + { + if (S::s != (__cpp_range_based_for >= 202211L)) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : foo ().foo ().bar ().foo ().bar ().foo ().bar ()) + { + if (S::s != 1 + 3 * (__cpp_range_based_for >= 202211L)) + 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 * (__cpp_range_based_for >= 202211L)) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : fred (fred (S {}, S {}))) + { + __builtin_printf ("%d\n", S::s); + if (S::s != 1 + 6 * (__cpp_range_based_for >= 202211L)) + 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 != (__cpp_range_based_for >= 202211L)) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : (void) S (), a) + { + if (S::s != (__cpp_range_based_for >= 202211L)) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : static_cast (S ()), a) + { + if (S::s != (__cpp_range_based_for >= 202211L)) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : foo ().foo ().bar ().foo ().bar ().foo ().bar ()) + { + if (S::s != 1 + 3 * (__cpp_range_based_for >= 202211L)) + 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 * (__cpp_range_based_for >= 202211L)) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : fred (fred (S {}, S {}))) + { + __builtin_printf ("%d\n", S::s); + if (S::s != 1 + 6 * (__cpp_range_based_for >= 202211L)) + abort (); + } + if (S::s != 0) + abort (); +} + +int +main () +{ + bar (); + baz <0> (); + qux (); +} --- gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C.jj 2024-01-10 12:19:08.249673372 +0100 +++ gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C 2024-08-09 11:37:30.071130077 +0200 @@ -42,8 +42,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-07-03 14:47:27.948553918 +0200 +++ gcc/testsuite/g++.dg/cpp26/feat-cxx26.C 2024-08-09 11:37:52.637843641 +0200 @@ -42,8 +42,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 2022-10-31 08:57:35.914172738 +0100 +++ gcc/testsuite/g++.dg/warn/Wdangling-reference4.C 2024-08-09 16:19:09.613948149 +0200 @@ -10,5 +10,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-08-09 12:25:19.879101383 +0200 +++ libgomp/testsuite/libgomp.c++/range-for-1.C 2024-08-09 20:32:53.907321362 +0200 @@ -0,0 +1,246 @@ +// 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 } + +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 != (__cpp_range_based_for >= 202211L)) + abort (); + } + if (S::s != 0) + abort (); + if (T::t != 0) + abort (); + } + c = 1 + (__cpp_range_based_for >= 202211L); + #pragma omp parallel num_threads (4) + { + #pragma omp for + for (auto x : T (S (), S ())) + { + if (S::s != 2 * (__cpp_range_based_for >= 202211L) || 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 * (__cpp_range_based_for >= 202211L) + || T::t != (__cpp_range_based_for >= 202211L)) + 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 != (__cpp_range_based_for >= 202211L)) + abort (); + } + if (S::s != 0) + abort (); + if (T::t != 0) + abort (); + } + c = 1 + (__cpp_range_based_for >= 202211L); + #pragma omp parallel num_threads (4) + { + #pragma omp for + for (auto x : T (S (), S ())) + { + if (S::s != 2 * (__cpp_range_based_for >= 202211L) || 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 * (__cpp_range_based_for >= 202211L) + || T::t != (__cpp_range_based_for >= 202211L)) + 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 != (__cpp_range_based_for >= 202211L)) + abort (); + } + if (S::s != 0) + abort (); + if (T::t != 0) + abort (); + } + c = 1 + (__cpp_range_based_for >= 202211L); + #pragma omp parallel num_threads (4) + { + #pragma omp for + for (auto x : T (S (), S ())) + { + if (S::s != 2 * (__cpp_range_based_for >= 202211L) || 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 * (__cpp_range_based_for >= 202211L) + || T::t != (__cpp_range_based_for >= 202211L)) + 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-08-09 12:26:22.017300176 +0200 +++ libgomp/testsuite/libgomp.c++/range-for-2.C 2024-08-09 12:26:38.217091298 +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"