[PATCH] c++: Implement C++23 P2718R0 - Wording for P2644R1 Fix for Range-based for Loop [PR107637]

Jakub Jelinek jakub@redhat.com
Fri Aug 9 19:06:07 GMT 2024


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  <jakub@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



More information about the Gcc-patches mailing list