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 <ja...@redhat.com> 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) <case OMP_FOR>: 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. --- 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 <typename T> +int * +begin (const T &) +{ + return &a[0]; +} + +template <typename T> +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 <int N> +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 <typename S, typename T> +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 <S, T> (); +} --- 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 <typename T> +int * +begin (const T &) +{ + return &a[0]; +} + +template <typename T> +int * +end (const T &) +{ + return &a[4]; +} + +struct S +{ + S () { ++s; } + S (const S &) { ++s; } + ~S () { --s; } + static int s; +}; + +int S::s; + +template <typename T> +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 <typename T> +int U<T>::u; + +template <typename T> +U<T> +foo () +{ + return U<T> {}; +} + +template <typename T> +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<void> (S ()), a) + { + if (S::s != (__cpp_range_based_for >= 202211L)) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : foo <S> ().foo ().bar ().foo ().bar ().foo ().bar ()) + { + if (S::s != 1 + 3 * (__cpp_range_based_for >= 202211L)) + abort (); + if (U<S>::u != S::s) + abort (); + } + if (S::s != 0 || U<S>::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 <int N> +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<void> (S ()), a) + { + if (S::s != (__cpp_range_based_for >= 202211L)) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : foo <S> ().foo ().bar ().foo ().bar ().foo ().bar ()) + { + if (S::s != 1 + 3 * (__cpp_range_based_for >= 202211L)) + abort (); + if (U<S>::u != S::s) + abort (); + } + if (S::s != 0 || U<S>::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 <typename S> +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<void> (S ()), a) + { + if (S::s != (__cpp_range_based_for >= 202211L)) + abort (); + } + if (S::s != 0) + abort (); + for (auto x : foo <S> ().foo ().bar ().foo ().bar ().foo ().bar ()) + { + if (S::s != 1 + 3 * (__cpp_range_based_for >= 202211L)) + abort (); + if (U<S>::u != S::s) + abort (); + } + if (S::s != 0 || U<S>::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 <S> (); +} --- 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<std::string>; 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 <typename T> +int * +begin (const T &) +{ + return &a[0]; +} + +template <typename T> +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 <int N> +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 <typename S, typename T> +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 <S, T> (); +} --- 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" Jakub