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

Reply via email to