aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite/g++.dg/cpp23
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2024-09-24 20:19:50 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2024-09-24 20:24:57 +0200
commit650e91566561870f3d1c8d5b92e6613296ee1a8d (patch)
treee5e1060cfa73ceb13d6cb590ef441b00838c31c9 /gcc/testsuite/g++.dg/cpp23
parentd9cafa0c4f0a81304d9b95a78ccc8e9003c6d7a3 (diff)
downloadgcc-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.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp23/range-for1.C222
-rw-r--r--gcc/testsuite/g++.dg/cpp23/range-for2.C231
-rw-r--r--gcc/testsuite/g++.dg/cpp23/range-for3.C7
-rw-r--r--gcc/testsuite/g++.dg/cpp23/range-for4.C7
-rw-r--r--gcc/testsuite/g++.dg/cpp23/range-for5.C8
-rw-r--r--gcc/testsuite/g++.dg/cpp23/range-for6.C8
-rw-r--r--gcc/testsuite/g++.dg/cpp23/range-for7.C6
-rw-r--r--gcc/testsuite/g++.dg/cpp23/range-for8.C6
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"