On Mon, Sep 23, 2024 at 03:46:36PM -0400, Jason Merrill wrote:
> > -frange-based-for-ext-temps
> > or do you have better suggestion?
> 
> I'd probably drop "based", "range-for" seems enough.
> 
> > Shall we allow also disabling it in C++23 or later modes, or override
> > user choice unconditionally for C++23+ and only allow users to
> > enable/disable it in C++11-C++20?
> 
> Hmm, I think the latter.
> 
> > What about the __cpp_range_based_for predefined macro?
> > Shall it be defined to the C++23 202211L value if the switch is on?
> > While that could be done in theory for C++17 and later code, for C++11/14
> > __cpp_range_based_for is 200907L and doesn't include the C++17
> > 201603L step.  Or keep the macro only for C++23 and later?
> 
> I think update the macro for 17 and later.

Ok.

Here is a new patch.

> > > > @@ -44600,11 +44609,14 @@ cp_convert_omp_range_for (tree &this_pre
> > > >          else
> > > >         {
> > > >           range_temp = build_range_temp (init);
> > > > +         tree name = DECL_NAME (range_temp);
> > > >           DECL_NAME (range_temp) = NULL_TREE;
> > > >           pushdecl (range_temp);
> > > > +         DECL_NAME (range_temp) = name;
> > > >           cp_finish_decl (range_temp, init,
> > > >                           /*is_constant_init*/false, NULL_TREE,
> > > >                           LOOKUP_ONLYCONVERTING);
> > > > +         DECL_NAME (range_temp) = NULL_TREE;
> > > 
> > > This messing with the name needs a rationale.  What wants it to be null?
> > 
> > I'll add comments.  The first = NULL_TREE; is needed so that pushdecl
> > doesn't register the temporary for name lookup, the = name now is so that
> > cp_finish_decl recognizes the temporary as range based for temporary
> > for the lifetime extension, and the last one is just to preserve previous
> > behavior, not have it visible in debug info etc.
> 
> But cp_convert_range_for doesn't ever set the name to NULL_TREE, why should
> the OMP variant be different?
> 
> Having it visible to name lookup in the debugger seems beneficial. Having it
> visible to the code seems less useful, but not important to prevent.

So, in the end it works fine even for the OpenMP case when not inside of a
template, all I had to add is the renaming of the symbol at the end after
pop_scope from "__for_range " to "__for_range" etc.
It doesn't work unfortunately during instantiation, we only create a single
scope in that case for the whole loop nest rather than one for each loop in
it and changing that isn't easy.  With the "__for_range " name in, if there
are 2+ range based for loops in the OpenMP loop nest (collapsed or ordered),
one gets then errors about defining it multiple times.
I'll try to fix that up at incrementally later, for now I just went with
a new flag to the function, so that it does the DECL_NAME dances only when
called from the instantiation (and confirmed actually all 3 spots are
needed, clearing before pushdecl, resetting back before cp_finish_decl and
clearing after cp_finish_decl, the last one so that pop_scope doesn't ICE
on seeing the name change).

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2024-09-24  Jakub Jelinek  <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.
        * doc/invoke.texi (frange-for-ext-temps): Document.  Add
        -fconcepts to the C++ option list.
gcc/c-family/
        * c.opt (frange-for-ext-temps): New option.
        * c-opts.cc (c_common_post_options): Set flag_range_for_ext_temps
        for C++23 or later or for C++11 or later in !flag_iso mode if
        the option wasn't set by user.
        * c-cppbuiltin.cc (c_cpp_builtins): Change __cpp_range_based_for
        value for flag_range_for_ext_temps from 201603L to 202212L in C++17
        or later.
        * c-omp.cc (c_find_nested_loop_xform_r): Handle CLEANUP_POINT_EXPR
        like TRY_FINALLY_EXPR.
gcc/cp/
        * cp-tree.h: Implement C++23 P2718R0 - Wording for P2644R1 Fix for
        Range-based for Loop.
        (cp_convert_omp_range_for): Add bool tmpl_p argument.
        (find_range_for_decls): Declare.
        * parser.cc (cp_convert_range_for): For flag_range_for_ext_temps call
        push_stmt_list () before cp_finish_decl for range_temp and save it
        temporarily to FOR_INIT_STMT.
        (cp_convert_omp_range_for): Add tmpl_p argument.  If set, remember
        DECL_NAME of range_temp and for cp_finish_decl call restore it before
        clearing it again, if unset, don't adjust DECL_NAME of range_temp at
        all.
        (cp_parser_omp_loop_nest): For flag_range_for_ext_temps range for add
        CLEANUP_POINT_EXPR around sl.  Call find_range_for_decls and adjust
        DECL_NAMEs for range fors if not processing_template_decl.  Adjust
        cp_convert_omp_range_for caller.  Remove superfluous backslash at the
        end of line.
        * decl.cc (initialize_local_var): For flag_range_for_ext_temps
        temporarily clear stmts_are_full_exprs_p rather than set for
        for_range__identifier decls.
        * call.cc (extend_ref_init_temps): For flag_range_for_ext_temps return
        init early for for_range__identifier decls.
        * semantics.cc (find_range_for_decls): New function.
        (finish_for_stmt): Use it.  For flag_range_for_ext_temps if
        cp_convert_range_for set FOR_INIT_STMT, pop_stmt_list it and wrap
        into CLEANUP_POINT_EXPR.
        * pt.cc (tsubst_omp_for_iterator): Adjust tsubst_omp_for_iterator
        caller.
        (tsubst_stmt) <case OMP_FOR>: For flag_range_for_ext_temps if there
        are any range fors in the loop nest, add push_stmt_list starting
        before the initializations, pop_stmt_list it after the body and wrap
        into CLEANUP_POINT_EXPR.  Change DECL_NAME of range for temps from
        NULL to for_range_identifier.
gcc/testsuite/
        * g++.dg/cpp23/range-for1.C: New test.
        * g++.dg/cpp23/range-for2.C: New test.
        * g++.dg/cpp23/range-for3.C: New test.
        * g++.dg/cpp23/range-for4.C: New test.
        * g++.dg/cpp23/range-for5.C: New test.
        * g++.dg/cpp23/range-for6.C: New test.
        * g++.dg/cpp23/range-for7.C: New test.
        * g++.dg/cpp23/range-for8.C: New test.
        * g++.dg/cpp23/feat-cxx2b.C (__cpp_range_based_for): Check for
        202212L rather than 201603L.
        * g++.dg/cpp26/feat-cxx26.C (__cpp_range_based_for): Likewise.
        * g++.dg/warn/Wdangling-reference4.C: Don't expect warning for C++23
        or newer.  Use dg-additional-options rather than dg-options.
libgomp/
        * testsuite/libgomp.c++/range-for-1.C: New test.
        * testsuite/libgomp.c++/range-for-2.C: New test.
        * testsuite/libgomp.c++/range-for-3.C: New test.
        * testsuite/libgomp.c++/range-for-4.C: New test.
        * testsuite/libgomp.c++/range-for-5.C: New test.

--- gcc/omp-general.cc.jj       2024-09-24 11:31:48.775621337 +0200
+++ gcc/omp-general.cc  2024-09-24 11:37:02.761332388 +0200
@@ -972,6 +972,7 @@ find_combined_omp_for (tree *tp, int *wa
       *walk_subtrees = 1;
       break;
     case TRY_FINALLY_EXPR:
+    case CLEANUP_POINT_EXPR:
       pdata[0] = tp;
       *walk_subtrees = 1;
       break;
@@ -4164,6 +4165,7 @@ find_nested_loop_xform (tree *tp, int *w
       *walk_subtrees = 1;
       break;
     case TRY_FINALLY_EXPR:
+    case CLEANUP_POINT_EXPR:
       pdata[0] = tp;
       *walk_subtrees = 1;
       break;
--- gcc/doc/invoke.texi.jj      2024-09-24 11:31:48.695622430 +0200
+++ gcc/doc/invoke.texi 2024-09-24 12:09:08.908039208 +0200
@@ -214,7 +214,7 @@ in the following sections.
 @xref{C++ Dialect Options,,Options Controlling C++ Dialect}.
 @gccoptlist{-fabi-version=@var{n}  -fno-access-control
 -faligned-new=@var{n}  -fargs-in-order=@var{n}  -fchar8_t  -fcheck-new
--fconstexpr-depth=@var{n}  -fconstexpr-cache-depth=@var{n}
+-fconcepts  -fconstexpr-depth=@var{n}  -fconstexpr-cache-depth=@var{n}
 -fconstexpr-loop-limit=@var{n}  -fconstexpr-ops-limit=@var{n}
 -fno-elide-constructors
 -fno-enforce-eh-specs
@@ -233,7 +233,7 @@ in the following sections.
 -fnew-ttp-matching
 -fno-nonansi-builtins  -fnothrow-opt  -fno-operator-names
 -fno-optional-diags
--fno-pretty-templates
+-fno-pretty-templates  -frange-for-ext-temps
 -fno-rtti  -fsized-deallocation
 -ftemplate-backtrace-limit=@var{n}
 -ftemplate-depth=@var{n}
@@ -3614,6 +3614,15 @@ the default template arguments for that
 behaviors make it harder to understand the error message rather than
 easier, you can use @option{-fno-pretty-templates} to disable them.
 
+@opindex frange-for-ext-temps
+@item -frange-for-ext-temps
+Enable lifetime extension of C++ range based for temporaries.
+With @option{-std=c++23} and above this is part of the language standard,
+so lifetime of the temporaries is extended until the end of the loop
+regardless of this option.  This option allows enabling that behavior also
+in earlier versions of the standard and is enabled by default in the
+GNU dialects, from @option{-std=gnu++11} until @option{-std=gnu++20}.
+
 @opindex fno-rtti
 @opindex frtti
 @item -fno-rtti
--- gcc/c-family/c.opt.jj       2024-09-24 11:31:37.380776989 +0200
+++ gcc/c-family/c.opt  2024-09-24 11:49:23.856220260 +0200
@@ -2209,6 +2209,10 @@ fprintf-return-value
 C ObjC C++ ObjC++ LTO Optimization Var(flag_printf_return_value) Init(1)
 Treat known sprintf return values as constants.
 
+frange-for-ext-temps
+C++ ObjC++ Var(flag_range_for_ext_temps)
+Enable lifetime extension of range based for temporaries.
+
 freplace-objc-classes
 ObjC ObjC++ LTO Var(flag_replace_objc_classes)
 Used in Fix-and-Continue mode to indicate that object files may be swapped in 
at runtime.
--- gcc/c-family/c-opts.cc.jj   2024-09-24 11:31:37.344777481 +0200
+++ gcc/c-family/c-opts.cc      2024-09-24 13:36:47.135322261 +0200
@@ -1160,6 +1160,16 @@ c_common_post_options (const char **pfil
   if (cxx_dialect >= cxx20)
     flag_concepts = 1;
 
+  /* Enable lifetime extension of range based for temporaries for C++23
+     regardless of command line setting.  */
+  if (cxx_dialect >= cxx23)
+    flag_range_for_ext_temps = 1;
+  /* Otherwise default to enabled in GNU modes but allow user to override.  */
+  else if (cxx_dialect >= cxx11
+          && !flag_iso
+          && !OPTION_SET_P (flag_range_for_ext_temps))
+    flag_range_for_ext_temps = 1;
+
   /* -fimmediate-escalation has no effect when immediate functions are not
      supported.  */
   if (flag_immediate_escalation && cxx_dialect < cxx20)
--- gcc/c-family/c-cppbuiltin.cc.jj     2024-09-24 11:31:37.312777918 +0200
+++ gcc/c-family/c-cppbuiltin.cc        2024-09-24 11:56:29.641414229 +0200
@@ -1034,7 +1034,11 @@ c_cpp_builtins (cpp_reader *pfile)
          cpp_define (pfile, "__cpp_fold_expressions=201603L");
          if (cxx_dialect <= cxx17)
            cpp_define (pfile, "__cpp_nontype_template_args=201411L");
-         cpp_define (pfile, "__cpp_range_based_for=201603L");
+         if (!flag_range_for_ext_temps)
+           cpp_define (pfile, "__cpp_range_based_for=201603L");
+          else
+           /* This is the C++23 or -std=c++17 -frange-for-ext-temps value.  */
+           cpp_define (pfile, "__cpp_range_based_for=202211L");
          if (cxx_dialect <= cxx17)
            cpp_define (pfile, "__cpp_constexpr=201603L");
          cpp_define (pfile, "__cpp_if_constexpr=201606L");
--- gcc/c-family/c-omp.cc.jj    2024-09-24 11:31:37.343777494 +0200
+++ gcc/c-family/c-omp.cc       2024-09-24 11:37:02.762332374 +0200
@@ -1617,6 +1617,7 @@ c_find_nested_loop_xform_r (tree *tp, in
       *walk_subtrees = 1;
       break;
     case TRY_FINALLY_EXPR:
+    case CLEANUP_POINT_EXPR:
       *walk_subtrees = 1;
       break;
     default:
--- gcc/cp/cp-tree.h.jj 2024-09-21 12:28:13.310942697 +0200
+++ gcc/cp/cp-tree.h    2024-09-24 14:41:32.378371615 +0200
@@ -7474,7 +7474,8 @@ extern bool maybe_clone_body                      (tree);
 extern tree cp_convert_range_for (tree, tree, tree, cp_decomp *, bool,
                                  tree, bool);
 extern void cp_convert_omp_range_for (tree &, tree &, tree &,
-                                     tree &, tree &, tree &, tree &, tree &);
+                                     tree &, tree &, tree &, tree &, tree &,
+                                     bool);
 extern void cp_finish_omp_range_for (tree, tree);
 extern bool cp_maybe_parse_omp_decl (tree, tree);
 extern bool parsing_nsdmi (void);
@@ -7809,6 +7810,7 @@ extern tree begin_for_stmt                        (tree, 
tree
 extern void finish_init_stmt                   (tree);
 extern void finish_for_cond            (tree, tree, bool, tree, bool);
 extern void finish_for_expr                    (tree, tree);
+extern void find_range_for_decls               (tree[3]);
 extern void finish_for_stmt                    (tree);
 extern tree begin_range_for_stmt               (tree, tree);
 extern void finish_range_for_decl              (tree, tree, tree);
--- gcc/cp/parser.cc.jj 2024-09-24 11:31:48.684622580 +0200
+++ gcc/cp/parser.cc    2024-09-24 14:41:01.505787999 +0200
@@ -14480,6 +14480,15 @@ cp_convert_range_for (tree statement, tr
        {
          range_temp = build_range_temp (range_expr);
          pushdecl (range_temp);
+         if (flag_range_for_ext_temps)
+           {
+             /* P2718R0 - put the range_temp declaration and everything
+                until end of the range for body into an extra STATEMENT_LIST
+                which will have CLEANUP_POINT_EXPR around it, so that all
+                temporaries are destroyed at the end of it.  */
+             gcc_assert (FOR_INIT_STMT (statement) == NULL_TREE);
+             FOR_INIT_STMT (statement) = push_stmt_list ();
+           }
          cp_finish_decl (range_temp, range_expr,
                          /*is_constant_init*/false, NULL_TREE,
                          LOOKUP_ONLYCONVERTING);
@@ -44629,7 +44638,8 @@ cp_parser_omp_for_loop_init (cp_parser *
 void
 cp_convert_omp_range_for (tree &this_pre_body, tree &sl,
                          tree &decl, tree &orig_decl, tree &init,
-                         tree &orig_init, tree &cond, tree &incr)
+                         tree &orig_init, tree &cond, tree &incr,
+                         bool tmpl_p)
 {
   tree begin, end, range_temp_decl = NULL_TREE;
   tree iter_type, begin_expr, end_expr;
@@ -44687,11 +44697,29 @@ cp_convert_omp_range_for (tree &this_pre
       else
        {
          range_temp = build_range_temp (init);
-         DECL_NAME (range_temp) = NULL_TREE;
+         tree name = DECL_NAME (range_temp);
+         /* Temporarily clear DECL_NAME of the __for_range temporary.
+            While it contains a space at the end and outside of templates
+            it works even without doing this, when cp_convert_omp_range_for
+            is called from tsubst_omp_for_iterator, all the associated loops
+            are in a single scope and so loop nests with 2 or more range
+            based for loops would error.  */
+         if (tmpl_p)
+           DECL_NAME (range_temp) = NULL_TREE;
          pushdecl (range_temp);
+         /* Restore the name back.  This is needed for cp_finish_decl
+            lifetime extension of temporaries, and can be helpful for user
+            during debugging after the DECL_NAME is changed to __for_range
+            without space at the end.  */
+         if (tmpl_p)
+           DECL_NAME (range_temp) = name;
          cp_finish_decl (range_temp, init,
                          /*is_constant_init*/false, NULL_TREE,
                          LOOKUP_ONLYCONVERTING);
+         /* And clear the name again.  pop_scope requires that the name
+            used during pushdecl didn't change.  */
+         if (tmpl_p)
+           DECL_NAME (range_temp) = NULL_TREE;
          range_temp_decl = range_temp;
          range_temp = convert_from_reference (range_temp);
        }
@@ -44791,7 +44819,7 @@ cp_convert_omp_range_for (tree &this_pre
      the whole loop nest.  The remaining elements are decls of derived
      decomposition variables that are bound inside the loop body.  This
      structure is further mangled by finish_omp_for into the form required
-     for the OMP_FOR_ORIG_DECLS field of the OMP_FOR tree node.  */\
+     for the OMP_FOR_ORIG_DECLS field of the OMP_FOR tree node.  */
   unsigned decomp_cnt = decomp ? decomp->count : 0;
   tree v = make_tree_vec (decomp_cnt + 3);
   TREE_VEC_ELT (v, 0) = range_temp_decl;
@@ -45360,7 +45388,7 @@ cp_parser_omp_loop_nest (cp_parser *pars
 
          cp_convert_omp_range_for (this_pre_body, sl, decl,
                                    orig_decl, init, orig_init,
-                                   cond, incr);
+                                   cond, incr, false);
 
          if (omp_for_parse_state->ordered_cl)
            error_at (OMP_CLAUSE_LOCATION (omp_for_parse_state->ordered_cl),
@@ -45623,11 +45651,30 @@ cp_parser_omp_loop_nest (cp_parser *pars
 
   /* Pop and remember the init block.  */
   if (sl)
-    add_stmt (pop_stmt_list (sl));
+    {
+      sl = pop_stmt_list (sl);
+      /* P2718R0 - Add CLEANUP_POINT_EXPR so that temporaries in
+        for-range-initializer whose lifetime is extended are destructed
+        here.  */
+      if (flag_range_for_ext_temps
+         && is_range_for
+         && !processing_template_decl)
+       sl = maybe_cleanup_point_expr_void (sl);
+      add_stmt (sl);
+    }
+  tree range_for_decl[3] = { NULL_TREE, NULL_TREE, NULL_TREE };
+  if (is_range_for && !processing_template_decl)
+    find_range_for_decls (range_for_decl);
   finish_compound_stmt (init_scope);
   init_block = pop_stmt_list (init_block);
   omp_for_parse_state->init_blockv[depth] = init_block;
 
+  if (is_range_for && !processing_template_decl)
+    for (int i = 0; i < 3; i++)
+      if (range_for_decl[i])
+       DECL_NAME (range_for_decl[i])
+         = cp_global_trees[CPTI_FOR_RANGE_IDENTIFIER + i];
+
   /* Return the init placeholder rather than the remembered init block.
      Again, this is just a unique cookie that will be used to reassemble
      code pieces when the entire omp for statement has been parsed.  */
--- gcc/cp/decl.cc.jj   2024-09-24 11:37:02.772332238 +0200
+++ gcc/cp/decl.cc      2024-09-24 11:38:20.535270020 +0200
@@ -8157,6 +8157,11 @@ initialize_local_var (tree decl, tree in
             code emitted by cp_finish_decomp.  */
          if (decomp)
            current_stmt_tree ()->stmts_are_full_exprs_p = 0;
+         /* P2718R0 - avoid CLEANUP_POINT_EXPR for range-for-initializer,
+            temporaries from there should have lifetime extended.  */
+         else if (DECL_NAME (decl) == for_range__identifier
+                  && flag_range_for_ext_temps)
+           current_stmt_tree ()->stmts_are_full_exprs_p = 0;
          else
            current_stmt_tree ()->stmts_are_full_exprs_p = 1;
          finish_expr_stmt (init);
--- gcc/cp/call.cc.jj   2024-09-24 11:31:37.386776907 +0200
+++ gcc/cp/call.cc      2024-09-24 11:37:02.774332211 +0200
@@ -14564,6 +14564,12 @@ extend_ref_init_temps (tree decl, tree i
   if (processing_template_decl)
     return init;
 
+  /* P2718R0 - ignore temporaries in C++23 for-range-initializer, those
+     have all extended lifetime.  */
+  if (DECL_NAME (decl) == for_range__identifier
+      && flag_range_for_ext_temps)
+    return init;
+
   maybe_warn_dangling_reference (decl, init);
 
   if (TYPE_REF_P (type))
--- gcc/cp/semantics.cc.jj      2024-09-24 11:31:37.516775131 +0200
+++ gcc/cp/semantics.cc 2024-09-24 12:20:35.083694190 +0200
@@ -1637,6 +1637,31 @@ finish_for_expr (tree expr, tree for_stm
   FOR_EXPR (for_stmt) = expr;
 }
 
+void
+find_range_for_decls (tree range_for_decl[3])
+{
+  /* During parsing of the body, range for uses "__for_{range,begin,end} "
+     decl names to make those unaccessible by code in the body.
+     Change it to ones with underscore instead of space, so that it can
+     be inspected in the debugger.  */
+  gcc_assert (CPTI_FOR_BEGIN__IDENTIFIER == CPTI_FOR_RANGE__IDENTIFIER + 1
+             && CPTI_FOR_END__IDENTIFIER == CPTI_FOR_RANGE__IDENTIFIER + 2
+             && CPTI_FOR_RANGE_IDENTIFIER == CPTI_FOR_RANGE__IDENTIFIER + 3
+             && CPTI_FOR_BEGIN_IDENTIFIER == CPTI_FOR_BEGIN__IDENTIFIER + 3
+             && CPTI_FOR_END_IDENTIFIER == CPTI_FOR_END__IDENTIFIER + 3);
+  for (int i = 0; i < 3; i++)
+    {
+      tree id = cp_global_trees[CPTI_FOR_RANGE__IDENTIFIER + i];
+      if (IDENTIFIER_BINDING (id)
+         && IDENTIFIER_BINDING (id)->scope == current_binding_level)
+       {
+         range_for_decl[i] = IDENTIFIER_BINDING (id)->value;
+         gcc_assert (VAR_P (range_for_decl[i])
+                     && DECL_ARTIFICIAL (range_for_decl[i]));
+       }
+    }
+}
+
 /* Finish the body of a for-statement, which may be given by
    FOR_STMT.  The increment-EXPR for the loop must be
    provided.
@@ -1670,21 +1695,20 @@ finish_for_stmt (tree for_stmt)
      Change it to ones with underscore instead of space, so that it can
      be inspected in the debugger.  */
   tree range_for_decl[3] = { NULL_TREE, NULL_TREE, NULL_TREE };
-  gcc_assert (CPTI_FOR_BEGIN__IDENTIFIER == CPTI_FOR_RANGE__IDENTIFIER + 1
-             && CPTI_FOR_END__IDENTIFIER == CPTI_FOR_RANGE__IDENTIFIER + 2
-             && CPTI_FOR_RANGE_IDENTIFIER == CPTI_FOR_RANGE__IDENTIFIER + 3
-             && CPTI_FOR_BEGIN_IDENTIFIER == CPTI_FOR_BEGIN__IDENTIFIER + 3
-             && CPTI_FOR_END_IDENTIFIER == CPTI_FOR_END__IDENTIFIER + 3);
-  for (int i = 0; i < 3; i++)
+  find_range_for_decls (range_for_decl);
+
+  /* P2718R0 - Add CLEANUP_POINT_EXPR so that temporaries in
+     for-range-initializer whose lifetime is extended are destructed
+     here.  */
+  if (flag_range_for_ext_temps
+      && range_for_decl[0]
+      && FOR_INIT_STMT (for_stmt))
     {
-      tree id = cp_global_trees[CPTI_FOR_RANGE__IDENTIFIER + i];
-      if (IDENTIFIER_BINDING (id)
-         && IDENTIFIER_BINDING (id)->scope == current_binding_level)
-       {
-         range_for_decl[i] = IDENTIFIER_BINDING (id)->value;
-         gcc_assert (VAR_P (range_for_decl[i])
-                     && DECL_ARTIFICIAL (range_for_decl[i]));
-       }
+      tree stmt = pop_stmt_list (FOR_INIT_STMT (for_stmt));
+      FOR_INIT_STMT (for_stmt) = NULL_TREE;
+      stmt = build_stmt (EXPR_LOCATION (for_stmt), EXPR_STMT, stmt);
+      stmt = maybe_cleanup_point_expr_void (stmt);
+      add_stmt (stmt);
     }
 
   add_stmt (do_poplevel (scope));
--- gcc/cp/pt.cc.jj     2024-09-24 11:31:37.495775418 +0200
+++ gcc/cp/pt.cc        2024-09-24 14:42:19.277739068 +0200
@@ -18127,7 +18127,7 @@ tsubst_omp_for_iterator (tree t, int i,
       tree orig_decl = NULL_TREE;
       tree init_sl = NULL_TREE;
       cp_convert_omp_range_for (this_pre_body, init_sl, decl, orig_decl, init,
-                               orig_init, cond, incr);
+                               orig_init, cond, incr, true);
       if (orig_decl)
        {
          if (orig_declv == NULL_TREE)
@@ -19156,6 +19156,18 @@ tsubst_stmt (tree t, tree args, tsubst_f
        RECUR (OMP_FOR_PRE_BODY (t));
        pre_body = pop_stmt_list (pre_body);
 
+       tree sl = NULL_TREE;
+       if (flag_range_for_ext_temps
+           && OMP_FOR_INIT (t) != NULL_TREE
+           && !processing_template_decl)
+         for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (t)); i++)
+           if (TREE_VEC_ELT (OMP_FOR_INIT (t), i)
+               && TREE_VEC_ELT (OMP_FOR_COND (t), i) == global_namespace)
+             {
+               sl = push_stmt_list ();
+               break;
+             }
+
        if (OMP_FOR_INIT (t) != NULL_TREE)
          for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (t)); i++)
            {
@@ -19211,9 +19223,34 @@ tsubst_stmt (tree t, tree args, tsubst_f
            add_stmt (t);
          }
 
+       if (sl)
+         {
+           /* P2718R0 - Add CLEANUP_POINT_EXPR so that temporaries in
+              for-range-initializer whose lifetime is extended are destructed
+              here.  */
+           sl = pop_stmt_list (sl);
+           sl = maybe_cleanup_point_expr_void (sl);
+           add_stmt (sl);
+         }
+
        add_stmt (finish_omp_for_block (finish_omp_structured_block (stmt),
                                        t));
        pop_omp_privatization_clauses (r);
+
+       if (any_range_for && !processing_template_decl && t)
+         for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (t)); i++)
+           if (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (t), i)
+               && TREE_CODE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (t),
+                                           i)) == TREE_LIST)
+             {
+               tree v = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (t), i);
+               if (TREE_CHAIN (v) == NULL_TREE
+                   || TREE_CODE (TREE_CHAIN (v)) != TREE_VEC)
+                 continue;
+               v = TREE_VEC_ELT (TREE_CHAIN (v), 0);
+               gcc_assert (VAR_P (v) && DECL_NAME (v) == NULL_TREE);
+               DECL_NAME (v) = for_range_identifier;
+             }
       }
       break;
 
--- gcc/testsuite/g++.dg/cpp23/range-for1.C.jj  2024-09-24 11:37:02.779332142 
+0200
+++ gcc/testsuite/g++.dg/cpp23/range-for1.C     2024-09-24 13:45:38.218063385 
+0200
@@ -0,0 +1,222 @@
+// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop
+// { dg-do run { target c++11 } }
+
+#ifndef RANGE_FOR_EXT_TEMPS
+#define RANGE_FOR_EXT_TEMPS (__cpp_range_based_for >= 202211L)
+#else
+#if __cplusplus >= 201703L
+#if RANGE_FOR_EXT_TEMPS
+static_assert (__cpp_range_based_for >= 202211L, "");
+#else
+static_assert (__cpp_range_based_for >= 201603L
+              && __cpp_range_based_for < 202211L, "");
+#endif
+#else
+static_assert (__cpp_range_based_for >= 200907L
+              && __cpp_range_based_for < 201603L, "");
+#endif
+#endif
+
+extern "C" void abort ();
+void check (bool);
+
+struct S
+{
+  S () { ++s; }
+  S (const S &) { ++s; }
+  ~S () { check (true); --s; }
+  static int s;
+};
+
+int S::s = -1;
+S sv;
+
+struct T
+{
+  T (const S &, const S &) { ++t; }
+  T (const T &) { ++t; }
+  ~T () { check (false); --t; }
+  static int t;
+};
+
+int T::t = -1;
+T tv (sv, sv);
+int a[4];
+int c;
+
+void
+check (bool is_s)
+{
+  if (c)
+    {
+      if (is_s)
+       {
+         if (T::t != (c == 1))
+           abort ();
+       }
+      else
+       {
+         if (S::s != (c == 1 ? 0 : 2))
+           abort ();
+       }
+    }
+}
+
+template <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 != RANGE_FOR_EXT_TEMPS)
+       abort ();
+    }
+  if (S::s != 0)
+    abort ();
+  if (T::t != 0)
+    abort ();
+  c = 1 + RANGE_FOR_EXT_TEMPS;
+  for (auto x : T (S (), S ()))
+    {
+      if (S::s != 2 * RANGE_FOR_EXT_TEMPS || T::t != 1)
+       abort ();
+    }
+  if (S::s != 0 || T::t != 0)
+    abort ();
+  c = 2;
+  for (auto x : foo (T (S (), S ())))
+    {
+      if (S::s != 2 * RANGE_FOR_EXT_TEMPS
+         || T::t != RANGE_FOR_EXT_TEMPS)
+       abort ();
+    }
+  if (S::s != 0 || T::t != 0)
+    abort ();
+  c = 0;
+}
+
+template <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 != RANGE_FOR_EXT_TEMPS)
+       abort ();
+    }
+  if (S::s != 0)
+    abort ();
+  if (T::t != 0)
+    abort ();
+  c = 1 + RANGE_FOR_EXT_TEMPS;
+  for (auto x : T (S (), S ()))
+    {
+      if (S::s != 2 * RANGE_FOR_EXT_TEMPS || T::t != 1)
+       abort ();
+    }
+  if (S::s != 0 || T::t != 0)
+    abort ();
+  c = 2;
+  for (auto x : foo (T (S (), S ())))
+    {
+      if (S::s != 2 * RANGE_FOR_EXT_TEMPS
+         || T::t != RANGE_FOR_EXT_TEMPS)
+       abort ();
+    }
+  if (S::s != 0 || T::t != 0)
+    abort ();
+  c = 0;
+}
+
+template <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 != RANGE_FOR_EXT_TEMPS)
+       abort ();
+    }
+  if (S::s != 0)
+    abort ();
+  if (T::t != 0)
+    abort ();
+  c = 1 + RANGE_FOR_EXT_TEMPS;
+  for (auto x : T (S (), S ()))
+    {
+      if (S::s != 2 * RANGE_FOR_EXT_TEMPS || T::t != 1)
+       abort ();
+    }
+  if (S::s != 0 || T::t != 0)
+    abort ();
+  c = 2;
+  for (auto x : foo (T (S (), S ())))
+    {
+      if (S::s != 2 * RANGE_FOR_EXT_TEMPS
+         || T::t != RANGE_FOR_EXT_TEMPS)
+       abort ();
+    }
+  if (S::s != 0 || T::t != 0)
+    abort ();
+  c = 0;
+}
+
+int
+main ()
+{
+  bar ();
+  baz <0> ();
+  qux <S, T> ();
+}
--- gcc/testsuite/g++.dg/cpp23/range-for2.C.jj  2024-09-24 11:37:02.779332142 
+0200
+++ gcc/testsuite/g++.dg/cpp23/range-for2.C     2024-09-24 13:46:31.802331179 
+0200
@@ -0,0 +1,231 @@
+// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop
+// { dg-do run { target c++11 } }
+
+#ifndef RANGE_FOR_EXT_TEMPS
+#define RANGE_FOR_EXT_TEMPS (__cpp_range_based_for >= 202211L)
+#endif
+
+extern "C" void abort ();
+
+int a[4];
+
+template <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 != RANGE_FOR_EXT_TEMPS)
+       abort ();
+    }
+  if (S::s != 0)
+    abort ();
+  for (auto x : (void) S (), a)
+    {
+      if (S::s != RANGE_FOR_EXT_TEMPS)
+       abort ();
+    }
+  if (S::s != 0)
+    abort ();
+  for (auto x : static_cast<void> (S ()), a)
+    {
+      if (S::s != RANGE_FOR_EXT_TEMPS)
+       abort ();
+    }
+  if (S::s != 0)
+    abort ();
+  for (auto x : foo <S> ().foo ().bar ().foo ().bar ().foo ().bar ())
+    {
+      if (S::s != 1 + 3 * RANGE_FOR_EXT_TEMPS)
+       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 * RANGE_FOR_EXT_TEMPS)
+       abort ();
+    }
+  if (S::s != 0)
+    abort ();
+  for (auto x : fred (fred (S {}, S {})))
+    {
+      if (S::s != 1 + 6 * RANGE_FOR_EXT_TEMPS)
+       abort ();
+    }
+  if (S::s != 0)
+    abort ();
+}
+
+template <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 != RANGE_FOR_EXT_TEMPS)
+       abort ();
+    }
+  if (S::s != 0)
+    abort ();
+  for (auto x : (void) S (), a)
+    {
+      if (S::s != RANGE_FOR_EXT_TEMPS)
+       abort ();
+    }
+  if (S::s != 0)
+    abort ();
+  for (auto x : static_cast<void> (S ()), a)
+    {
+      if (S::s != RANGE_FOR_EXT_TEMPS)
+       abort ();
+    }
+  if (S::s != 0)
+    abort ();
+  for (auto x : foo <S> ().foo ().bar ().foo ().bar ().foo ().bar ())
+    {
+      if (S::s != 1 + 3 * RANGE_FOR_EXT_TEMPS)
+       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 * RANGE_FOR_EXT_TEMPS)
+       abort ();
+    }
+  if (S::s != 0)
+    abort ();
+  for (auto x : fred (fred (S {}, S {})))
+    {
+      if (S::s != 1 + 6 * RANGE_FOR_EXT_TEMPS)
+       abort ();
+    }
+  if (S::s != 0)
+    abort ();
+}
+
+template <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 != RANGE_FOR_EXT_TEMPS)
+       abort ();
+    }
+  if (S::s != 0)
+    abort ();
+  for (auto x : (void) S (), a)
+    {
+      if (S::s != RANGE_FOR_EXT_TEMPS)
+       abort ();
+    }
+  if (S::s != 0)
+    abort ();
+  for (auto x : static_cast<void> (S ()), a)
+    {
+      if (S::s != RANGE_FOR_EXT_TEMPS)
+       abort ();
+    }
+  if (S::s != 0)
+    abort ();
+  for (auto x : foo <S> ().foo ().bar ().foo ().bar ().foo ().bar ())
+    {
+      if (S::s != 1 + 3 * RANGE_FOR_EXT_TEMPS)
+       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 * RANGE_FOR_EXT_TEMPS)
+       abort ();
+    }
+  if (S::s != 0)
+    abort ();
+  for (auto x : fred (fred (S {}, S {})))
+    {
+      if (S::s != 1 + 6 * RANGE_FOR_EXT_TEMPS)
+       abort ();
+    }
+  if (S::s != 0)
+    abort ();
+}
+
+int
+main ()
+{
+  bar ();
+  baz <0> ();
+  qux <S> ();
+}
--- gcc/testsuite/g++.dg/cpp23/range-for3.C.jj  2024-09-24 13:46:42.151189765 
+0200
+++ gcc/testsuite/g++.dg/cpp23/range-for3.C     2024-09-24 13:47:26.571582778 
+0200
@@ -0,0 +1,6 @@
+// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+#define RANGE_FOR_EXT_TEMPS 1
+#include "range-for1.C"
--- gcc/testsuite/g++.dg/cpp23/range-for4.C.jj  2024-09-24 13:47:35.949454632 
+0200
+++ gcc/testsuite/g++.dg/cpp23/range-for4.C     2024-09-24 13:47:47.078302564 
+0200
@@ -0,0 +1,6 @@
+// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+#define RANGE_FOR_EXT_TEMPS 1
+#include "range-for2.C"
--- gcc/testsuite/g++.dg/cpp23/range-for5.C.jj  2024-09-24 13:52:10.709700152 
+0200
+++ gcc/testsuite/g++.dg/cpp23/range-for5.C     2024-09-24 13:54:45.031591404 
+0200
@@ -0,0 +1,8 @@
+// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop
+// { dg-do run { target c++11 } }
+// { dg-options "-fno-range-for-ext-temps" }
+
+#if __cplusplus <= 202002L
+#define RANGE_FOR_EXT_TEMPS 0
+#endif
+#include "range-for1.C"
--- gcc/testsuite/g++.dg/cpp23/range-for6.C.jj  2024-09-24 13:54:53.146480511 
+0200
+++ gcc/testsuite/g++.dg/cpp23/range-for6.C     2024-09-24 13:54:59.713390778 
+0200
@@ -0,0 +1,8 @@
+// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop
+// { dg-do run { target c++11 } }
+// { dg-options "-fno-range-for-ext-temps" }
+
+#if __cplusplus <= 202002L
+#define RANGE_FOR_EXT_TEMPS 0
+#endif
+#include "range-for2.C"
--- gcc/testsuite/g++.dg/cpp23/range-for7.C.jj  2024-09-24 13:55:14.980182159 
+0200
+++ gcc/testsuite/g++.dg/cpp23/range-for7.C     2024-09-24 13:55:36.945882011 
+0200
@@ -0,0 +1,6 @@
+// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop
+// { dg-do run { target c++17_only } }
+// { dg-options "-std=c++17 -frange-for-ext-temps" }
+
+#define RANGE_FOR_EXT_TEMPS 1
+#include "range-for1.C"
--- gcc/testsuite/g++.dg/cpp23/range-for8.C.jj  2024-09-24 13:55:44.815774472 
+0200
+++ gcc/testsuite/g++.dg/cpp23/range-for8.C     2024-09-24 13:55:56.186619103 
+0200
@@ -0,0 +1,6 @@
+// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop
+// { dg-do run { target c++11_only } }
+// { dg-options "-std=c++11 -frange-for-ext-temps" }
+
+#define RANGE_FOR_EXT_TEMPS 1
+#include "range-for2.C"
--- gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C.jj  2024-09-24 11:31:37.555774598 
+0200
+++ gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C     2024-09-24 11:37:02.779332142 
+0200
@@ -43,8 +43,8 @@
 
 #ifndef __cpp_range_based_for
 #  error "__cpp_range_based_for"
-#elif __cpp_range_based_for != 201603
-#  error "__cpp_range_based_for != 201603"
+#elif __cpp_range_based_for != 202211
+#  error "__cpp_range_based_for != 202211"
 #endif
 
 #ifndef __cpp_decltype
--- gcc/testsuite/g++.dg/cpp26/feat-cxx26.C.jj  2024-09-24 11:31:37.555774598 
+0200
+++ gcc/testsuite/g++.dg/cpp26/feat-cxx26.C     2024-09-24 11:37:02.780332129 
+0200
@@ -43,8 +43,8 @@
 
 #ifndef __cpp_range_based_for
 #  error "__cpp_range_based_for"
-#elif __cpp_range_based_for != 201603
-#  error "__cpp_range_based_for != 201603"
+#elif __cpp_range_based_for != 202211
+#  error "__cpp_range_based_for != 202211"
 #endif
 
 #ifndef __cpp_decltype
--- gcc/testsuite/g++.dg/warn/Wdangling-reference4.C.jj 2024-09-24 
11:31:37.556774585 +0200
+++ gcc/testsuite/g++.dg/warn/Wdangling-reference4.C    2024-09-24 
11:37:02.780332129 +0200
@@ -1,5 +1,5 @@
 // { dg-do compile { target c++17 } }
-// { dg-options "-Wdangling-reference" }
+// { dg-additional-options "-Wdangling-reference" }
 // { dg-skip-if "requires hosted libstdc++ for string" { ! hostedlib } }
 // Check that we warn here even without -Wsystem-headers.
 
@@ -11,5 +11,5 @@ auto f() -> std::optional<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-09-24 
11:37:02.780332129 +0200
+++ libgomp/testsuite/libgomp.c++/range-for-1.C 2024-09-24 14:00:52.214575429 
+0200
@@ -0,0 +1,250 @@
+// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop
+// { dg-do run }
+// { dg-additional-options "-std=c++17" }
+// { dg-require-effective-target tls_runtime }
+
+#ifndef RANGE_FOR_EXT_TEMPS
+#define RANGE_FOR_EXT_TEMPS (__cpp_range_based_for >= 202211L)
+#endif
+
+extern "C" void abort ();
+void check (bool);
+
+struct S
+{
+  S () { ++s; }
+  S (const S &) { ++s; }
+  ~S () { check (true); --s; }
+  [[omp::decl (threadprivate)]] static int s;
+};
+int S::s;
+S sv;
+struct T
+{
+  T (const S &, const S &) { ++t; }
+  T (const T &) { ++t; }
+  ~T () { check (false); --t; }
+  [[omp::decl (threadprivate)]] static int t;
+};
+int T::t;
+T tv (sv, sv);
+int a[4];
+int c;
+
+void
+check (bool is_s)
+{
+  if (c)
+    {
+      if (is_s)
+       {
+         if (T::t != (c == 1))
+           abort ();
+       }
+      else
+       {
+         if (S::s != (c == 1 ? 0 : 2))
+           abort ();
+       }
+    }
+}
+
+template <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 != RANGE_FOR_EXT_TEMPS)
+         abort ();
+      }
+    if (S::s != 0)
+      abort ();
+    if (T::t != 0)
+      abort ();
+  }
+  c = 1 + RANGE_FOR_EXT_TEMPS;
+  #pragma omp parallel num_threads (4)
+  {
+    #pragma omp for
+    for (auto x : T (S (), S ()))
+      {
+       if (S::s != 2 * RANGE_FOR_EXT_TEMPS || T::t != 1)
+         abort ();
+      }
+    if (S::s != 0 || T::t != 0)
+      abort ();
+  }
+  c = 2;
+  #pragma omp parallel num_threads (4)
+  {
+    #pragma omp for
+    for (auto x : foo (T (S (), S ())))
+      {
+       if (S::s != 2 * RANGE_FOR_EXT_TEMPS
+           || T::t != RANGE_FOR_EXT_TEMPS)
+         abort ();
+      }
+    if (S::s != 0 || T::t != 0)
+      abort ();
+  }
+  c = 0;
+}
+
+template <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 != RANGE_FOR_EXT_TEMPS)
+         abort ();
+      }
+    if (S::s != 0)
+      abort ();
+    if (T::t != 0)
+      abort ();
+  }
+  c = 1 + RANGE_FOR_EXT_TEMPS;
+  #pragma omp parallel num_threads (4)
+  {
+    #pragma omp for
+    for (auto x : T (S (), S ()))
+      {
+       if (S::s != 2 * RANGE_FOR_EXT_TEMPS || T::t != 1)
+         abort ();
+      }
+    if (S::s != 0 || T::t != 0)
+      abort ();
+  }
+  c = 2;
+  #pragma omp parallel num_threads (4)
+  {
+    #pragma omp for
+    for (auto x : foo (T (S (), S ())))
+      {
+       if (S::s != 2 * RANGE_FOR_EXT_TEMPS
+           || T::t != RANGE_FOR_EXT_TEMPS)
+         abort ();
+      }
+    if (S::s != 0 || T::t != 0)
+      abort ();
+  }
+  c = 0;
+}
+
+template <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 != RANGE_FOR_EXT_TEMPS)
+         abort ();
+      }
+    if (S::s != 0)
+      abort ();
+    if (T::t != 0)
+      abort ();
+  }
+  c = 1 + RANGE_FOR_EXT_TEMPS;
+  #pragma omp parallel num_threads (4)
+  {
+    #pragma omp for
+    for (auto x : T (S (), S ()))
+      {
+       if (S::s != 2 * RANGE_FOR_EXT_TEMPS || T::t != 1)
+         abort ();
+      }
+    if (S::s != 0 || T::t != 0)
+      abort ();
+  }
+  c = 2;
+  #pragma omp parallel num_threads (4)
+  {
+    #pragma omp for
+    for (auto x : foo (T (S (), S ())))
+      {
+       if (S::s != 2 * RANGE_FOR_EXT_TEMPS
+           || T::t != RANGE_FOR_EXT_TEMPS)
+         abort ();
+      }
+    if (S::s != 0 || T::t != 0)
+      abort ();
+  }
+  c = 0;
+}
+
+int
+main ()
+{
+  S::s--;
+  T::t--;
+  bar ();
+  baz <0> ();
+  qux <S, T> ();
+}
--- libgomp/testsuite/libgomp.c++/range-for-2.C.jj      2024-09-24 
11:37:02.780332129 +0200
+++ libgomp/testsuite/libgomp.c++/range-for-2.C 2024-09-24 11:37:02.780332129 
+0200
@@ -0,0 +1,6 @@
+// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop
+// { dg-do run }
+// { dg-additional-options "-std=c++23" }
+// { dg-require-effective-target tls_runtime }
+
+#include "range-for-1.C"
--- libgomp/testsuite/libgomp.c++/range-for-3.C.jj      2024-09-24 
14:03:08.554714647 +0200
+++ libgomp/testsuite/libgomp.c++/range-for-3.C 2024-09-24 14:02:02.282619132 
+0200
@@ -0,0 +1,7 @@
+// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop
+// { dg-do run }
+// { dg-additional-options "-std=c++17 -frange-for-ext-temps" }
+// { dg-require-effective-target tls_runtime }
+
+#define RANGE_FOR_EXT_TEMPS 1
+#include "range-for-1.C"
--- libgomp/testsuite/libgomp.c++/range-for-4.C.jj      2024-09-24 
14:03:15.428620831 +0200
+++ libgomp/testsuite/libgomp.c++/range-for-4.C 2024-09-24 14:02:22.983336609 
+0200
@@ -0,0 +1,7 @@
+// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop
+// { dg-do run }
+// { dg-additional-options "-std=gnu++17" }
+// { dg-require-effective-target tls_runtime }
+
+#define RANGE_FOR_EXT_TEMPS 1
+#include "range-for-1.C"
--- libgomp/testsuite/libgomp.c++/range-for-5.C.jj      2024-09-24 
14:03:26.801465614 +0200
+++ libgomp/testsuite/libgomp.c++/range-for-5.C 2024-09-24 14:02:53.986913469 
+0200
@@ -0,0 +1,7 @@
+// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop
+// { dg-do run }
+// { dg-additional-options "-std=gnu++17 -fno-range-for-ext-temps" }
+// { dg-require-effective-target tls_runtime }
+
+#define RANGE_FOR_EXT_TEMPS 0
+#include "range-for-1.C"


        Jakub

Reply via email to