diff options
author | Jakub Jelinek <jakub@redhat.com> | 2024-09-24 20:19:50 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2024-09-24 20:24:57 +0200 |
commit | 650e91566561870f3d1c8d5b92e6613296ee1a8d (patch) | |
tree | e5e1060cfa73ceb13d6cb590ef441b00838c31c9 /gcc/testsuite/g++.dg/cpp23 | |
parent | d9cafa0c4f0a81304d9b95a78ccc8e9003c6d7a3 (diff) | |
download | gcc-650e91566561870f3d1c8d5b92e6613296ee1a8d.zip gcc-650e91566561870f3d1c8d5b92e6613296ee1a8d.tar.gz gcc-650e91566561870f3d1c8d5b92e6613296ee1a8d.tar.bz2 |
c++: Implement C++23 P2718R0 - Wording for P2644R1 Fix for Range-based for Loop [PR107637]
The following patch implements the C++23 P2718R0 paper
- Wording for P2644R1 Fix for Range-based for Loop.
The patch introduces a new option, -f{,no-}range-for-ext-temps so that
user can control the behavior even in older C++ versions.
The option is on by default in C++23 and later (-fno-range-for-ext-temps
is an error in that case) and in the -std=gnu++11 ... -std=gnu++20 modes
(one can use -fno-range-for-ext-temps to request previous behavior in that
case), and is not enabled by default in -std=c++11 ... -std=c++20 modes
but one can explicitly enable it with -frange-for-ext-temps.
As all the temporaries from __for_range initialization should have life
extended until the end of __for_range scope, this patch disables (for
-frange-for-ext-temps 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.
2024-09-24 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.
* 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.
Diffstat (limited to 'gcc/testsuite/g++.dg/cpp23')
-rw-r--r-- | gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C | 4 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp23/range-for1.C | 222 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp23/range-for2.C | 231 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp23/range-for3.C | 7 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp23/range-for4.C | 7 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp23/range-for5.C | 8 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp23/range-for6.C | 8 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp23/range-for7.C | 6 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp23/range-for8.C | 6 |
9 files changed, 497 insertions, 2 deletions
diff --git a/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C b/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C index a1ddc81..4033552 100644 --- a/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C +++ b/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C @@ -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 diff --git a/gcc/testsuite/g++.dg/cpp23/range-for1.C b/gcc/testsuite/g++.dg/cpp23/range-for1.C new file mode 100644 index 0000000..2aa8a5e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/range-for1.C @@ -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> (); +} diff --git a/gcc/testsuite/g++.dg/cpp23/range-for2.C b/gcc/testsuite/g++.dg/cpp23/range-for2.C new file mode 100644 index 0000000..e40e6d3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/range-for2.C @@ -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> (); +} diff --git a/gcc/testsuite/g++.dg/cpp23/range-for3.C b/gcc/testsuite/g++.dg/cpp23/range-for3.C new file mode 100644 index 0000000..301e258 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/range-for3.C @@ -0,0 +1,7 @@ +// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop +// { dg-do run { target c++11 } } +// Verify -frange-for-ext-temps is set by default in -std=gnu++* modes. +// { dg-options "" } + +#define RANGE_FOR_EXT_TEMPS 1 +#include "range-for1.C" diff --git a/gcc/testsuite/g++.dg/cpp23/range-for4.C b/gcc/testsuite/g++.dg/cpp23/range-for4.C new file mode 100644 index 0000000..f8c380d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/range-for4.C @@ -0,0 +1,7 @@ +// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop +// { dg-do run { target c++11 } } +// Verify -frange-for-ext-temps is set by default in -std=gnu++* modes. +// { dg-options "" } + +#define RANGE_FOR_EXT_TEMPS 1 +#include "range-for2.C" diff --git a/gcc/testsuite/g++.dg/cpp23/range-for5.C b/gcc/testsuite/g++.dg/cpp23/range-for5.C new file mode 100644 index 0000000..c2cd124 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/range-for5.C @@ -0,0 +1,8 @@ +// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop +// { dg-do run { target { c++11 && c++20_down } } } +// { dg-options "-fno-range-for-ext-temps" } + +#if __cplusplus <= 202002L +#define RANGE_FOR_EXT_TEMPS 0 +#endif +#include "range-for1.C" diff --git a/gcc/testsuite/g++.dg/cpp23/range-for6.C b/gcc/testsuite/g++.dg/cpp23/range-for6.C new file mode 100644 index 0000000..8bf8656 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/range-for6.C @@ -0,0 +1,8 @@ +// P2718R0 - Wording for P2644R1 Fix for Range-based for Loop +// { dg-do run { target { c++11 && c++20_down } } } +// { dg-options "-fno-range-for-ext-temps" } + +#if __cplusplus <= 202002L +#define RANGE_FOR_EXT_TEMPS 0 +#endif +#include "range-for2.C" diff --git a/gcc/testsuite/g++.dg/cpp23/range-for7.C b/gcc/testsuite/g++.dg/cpp23/range-for7.C new file mode 100644 index 0000000..99d9bd8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/range-for7.C @@ -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" diff --git a/gcc/testsuite/g++.dg/cpp23/range-for8.C b/gcc/testsuite/g++.dg/cpp23/range-for8.C new file mode 100644 index 0000000..3b2efbc --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/range-for8.C @@ -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" |