[gcc r15-3637] c++: Fix g++.dg/ext/sve-sizeless-1.C regression
https://gcc.gnu.org/g:bec1f2ce4ad3fe56906d6429b542a290e574b3eb commit r15-3637-gbec1f2ce4ad3fe56906d6429b542a290e574b3eb Author: Jonathan Wakely Date: Fri Sep 13 08:18:53 2024 +0100 c++: Fix g++.dg/ext/sve-sizeless-1.C regression This aarch64-*-* test needs an update for the diagnostic I changed in r15-3614-g9fe57e4879de93. gcc/testsuite/ChangeLog: * g++.dg/ext/sve-sizeless-1.C: Adjust dg-error string. Diff: --- gcc/testsuite/g++.dg/ext/sve-sizeless-1.C | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gcc/testsuite/g++.dg/ext/sve-sizeless-1.C b/gcc/testsuite/g++.dg/ext/sve-sizeless-1.C index 9f05ca5a855a..adee37a0551e 100644 --- a/gcc/testsuite/g++.dg/ext/sve-sizeless-1.C +++ b/gcc/testsuite/g++.dg/ext/sve-sizeless-1.C @@ -301,7 +301,7 @@ statements (int n) // Other built-ins - __builtin_launder (sve_sc1); // { dg-error {non-pointer argument to '__builtin_launder'} } + __builtin_launder (sve_sc1); // { dg-error {not a pointer to object type} } __builtin_memcpy (&sve_sc1, &sve_sc2, 2); // Lambdas
[gcc r15-3638] testsuite: adjust pragma-diag-17.c diagnostics
https://gcc.gnu.org/g:49cb7150f0e93e8332f4b78753675b255a5c58f2 commit r15-3638-g49cb7150f0e93e8332f4b78753675b255a5c58f2 Author: Jason Merrill Date: Fri Sep 13 15:52:02 2024 +0200 testsuite: adjust pragma-diag-17.c diagnostics The Linaro CI runs of this testcase pointed out that I need to check for DFP support, as well. gcc/testsuite/ChangeLog: * c-c++-common/pragma-diag-17.c: Handle !dfp targets. Diff: --- gcc/testsuite/c-c++-common/pragma-diag-17.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gcc/testsuite/c-c++-common/pragma-diag-17.c b/gcc/testsuite/c-c++-common/pragma-diag-17.c index a38841bc48d2..a44ce90f98b1 100644 --- a/gcc/testsuite/c-c++-common/pragma-diag-17.c +++ b/gcc/testsuite/c-c++-common/pragma-diag-17.c @@ -12,7 +12,7 @@ void f() 0b0100; /* { dg-error "binary constant" "" { target { ! c++14 } } } */ #pragma GCC diagnostic ignored "-Wpedantic" 2.0j; - 1.0dd; + 1.0dd; /* { dg-error "decimal floating-point" "" { target { ! dfp } } } */ 1.0d; #ifdef __cplusplus
[gcc r15-3640] libstdc++: Tweak localized formatting for floating-point types
https://gcc.gnu.org/g:99b8be43d7c548db127ee4f4d0918c55edc68b3f commit r15-3640-g99b8be43d7c548db127ee4f4d0918c55edc68b3f Author: Jonathan Wakely Date: Mon Apr 29 18:16:29 2024 +0100 libstdc++: Tweak localized formatting for floating-point types libstdc++-v3/ChangeLog: * include/std/format (__formatter_fp::_M_localize): Add comments and micro-optimize string copy. Diff: --- libstdc++-v3/include/std/format | 17 ++--- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format index 52243eb54792..e963d7f79b33 100644 --- a/libstdc++-v3/include/std/format +++ b/libstdc++-v3/include/std/format @@ -1886,25 +1886,28 @@ namespace __format if (__grp.empty() && __point == __dot) return __lstr; // Locale uses '.' and no grouping. - size_t __d = __str.find(__dot); - size_t __e = min(__d, __str.find(__exp)); + size_t __d = __str.find(__dot); // Index of radix character (if any). + size_t __e = min(__d, __str.find(__exp)); // First of radix or exponent if (__e == __str.npos) __e = __str.size(); - const size_t __r = __str.size() - __e; + const size_t __r = __str.size() - __e; // Length of remainder. auto __overwrite = [&](_CharT* __p, size_t) { + // Apply grouping to the digits before the radix or exponent. auto __end = std::__add_grouping(__p, __np.thousands_sep(), __grp.data(), __grp.size(), __str.data(), __str.data() + __e); - if (__r) + if (__r) // If there's a fractional part or exponent { if (__d != __str.npos) { - *__end = __point; + *__end = __point; // Add the locale's radix character. ++__end; ++__e; } - if (__r > 1) - __end += __str.copy(__end, __str.npos, __e); + const size_t __rlen = __str.size() - __e; + // Append fractional digits and/or exponent: + char_traits<_CharT>::copy(__end, __str.data() + __e, __rlen); + __end += __rlen; } return (__end - __p); };
[gcc r15-3639] libstdc++: Refactor loops in std::__platform_semaphore
https://gcc.gnu.org/g:01670a4095791733e0389acead832e3da757c9d7 commit r15-3639-g01670a4095791733e0389acead832e3da757c9d7 Author: Jonathan Wakely Date: Mon Sep 2 12:29:04 2024 +0100 libstdc++: Refactor loops in std::__platform_semaphore Refactor the loops to all use the same form, and to not need explicit 'break' or 'continue' jumps. This also avoids a -Wunused-variable warning with -Wsystem-headers. Also fix a bug for absolute timeouts specified with a time that isn't implicitly convertible to __clock_t::time_point, e.g. one with a higher resolution such as picoseconds. Use chrono::ceil to round up to the next time point representable by the clock. libstdc++-v3/ChangeLog: * include/bits/semaphore_base.h (__platform_semaphore): Refactor loops to all use similar forms. (__platform_semaphore::_M_try_acquire_until): Use chrono::ceil to explicitly convert to __clock_t::time_point. * testsuite/30_threads/semaphore/try_acquire_for.cc: Check that using a very high resolution timeout compiles. * testsuite/30_threads/semaphore/platform_try_acquire_for.cc: New test. Diff: --- libstdc++-v3/include/bits/semaphore_base.h | 58 -- .../semaphore/platform_try_acquire_for.cc | 7 +++ .../30_threads/semaphore/try_acquire_for.cc| 13 + 3 files changed, 40 insertions(+), 38 deletions(-) diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h index 44a68645e477..2b19c9c6c6ac 100644 --- a/libstdc++-v3/include/bits/semaphore_base.h +++ b/libstdc++-v3/include/bits/semaphore_base.h @@ -73,52 +73,37 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_ALWAYS_INLINE void _M_acquire() noexcept { - for (;;) - { - auto __err = sem_wait(&_M_semaphore); - if (__err && (errno == EINTR)) - continue; - else if (__err) - std::__terminate(); - else - break; - } + while (sem_wait(&_M_semaphore)) + if (errno != EINTR) + std::__terminate(); } _GLIBCXX_ALWAYS_INLINE bool _M_try_acquire() noexcept { - for (;;) + while (sem_trywait(&_M_semaphore)) { - auto __err = sem_trywait(&_M_semaphore); - if (__err && (errno == EINTR)) - continue; - else if (__err && (errno == EAGAIN)) + if (errno == EAGAIN) // already locked return false; - else if (__err) + else if (errno != EINTR) std::__terminate(); - else - break; + // else got EINTR so retry } return true; } _GLIBCXX_ALWAYS_INLINE void -_M_release(std::ptrdiff_t __update) noexcept +_M_release(ptrdiff_t __update) noexcept { for(; __update != 0; --__update) - { - auto __err = sem_post(&_M_semaphore); - if (__err) -std::__terminate(); - } + if (sem_post(&_M_semaphore)) + std::__terminate(); } bool _M_try_acquire_until_impl(const chrono::time_point<__clock_t>& __atime) noexcept { - auto __s = chrono::time_point_cast(__atime); auto __ns = chrono::duration_cast(__atime - __s); @@ -128,19 +113,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_cast(__ns.count()) }; - for (;;) + while (sem_timedwait(&_M_semaphore, &__ts)) { - if (auto __err = sem_timedwait(&_M_semaphore, &__ts)) - { - if (errno == EINTR) - continue; - else if (errno == ETIMEDOUT || errno == EINVAL) - return false; - else - std::__terminate(); - } - else - break; + if (errno == ETIMEDOUT) + return false; + else if (errno != EINTR) + std::__terminate(); } return true; } @@ -152,10 +130,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { if constexpr (std::is_same_v<__clock_t, _Clock>) { - return _M_try_acquire_until_impl(__atime); + using _Dur = __clock_t::duration; + return _M_try_acquire_until_impl(chrono::ceil<_Dur>(__atime)); } else { + // TODO: if _Clock is monotonic_clock we could use + // sem_clockwait with CLOCK_MONOTONIC. + const typename _Clock::time_point __c_entry = _Clock::now(); const auto __s_entry = __clock_t::now(); const auto __delta = __atime - __c_entry; diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/platform_try_acquire_for.cc b/libstdc++-v3/testsuite/30_threads/semaphore/platform_try_acquire_for.cc new file mode 100644 index ..bf6cd142bf01 --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/semaphore/platform_try_acquire_for.
[gcc r15-3641] AVR: Use rtx code copysign.
https://gcc.gnu.org/g:a900349485cc4753084527bf0234f173967979b0 commit r15-3641-ga900349485cc4753084527bf0234f173967979b0 Author: Georg-Johann Lay Date: Sat Sep 14 10:12:54 2024 +0200 AVR: Use rtx code copysign. gcc/ * config/avr/avr.md (UNSPEC_COPYSIGN): Remove define_enum. (copysignsf3): Use copysign instead of UNSPEC_COPYSIGN. Allow const_double for operand 2. Diff: --- gcc/config/avr/avr.md | 17 +++-- 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index 429f537b7d4f..2abf3c38d836 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -87,7 +87,6 @@ UNSPEC_FMUL UNSPEC_FMULS UNSPEC_FMULSU - UNSPEC_COPYSIGN UNSPEC_INSERT_BITS UNSPEC_ROUND ]) @@ -9272,12 +9271,18 @@ ;; Copysign (define_insn "copysignsf3" - [(set (match_operand:SF 0 "register_operand" "=r") -(unspec:SF [(match_operand:SF 1 "register_operand" "0") -(match_operand:SF 2 "register_operand" "r")] - UNSPEC_COPYSIGN))] + [(set (match_operand:SF 0 "register_operand" "=r") +(copysign:SF (match_operand:SF 1 "register_operand" "0") + (match_operand:SF 2 "nonmemory_operand" "rF")))] "" - "bst %D2,7\;bld %D0,7" + { +if (const_double_operand (operands[2], SFmode)) + { +rtx xmsb = simplify_gen_subreg (QImode, operands[2], SFmode, 3); +return INTVAL (xmsb) < 0 ? "set\;bld %D0,7" : "clt\;bld %D0,7"; + } +return "bst %D2,7\;bld %D0,7"; + } [(set_attr "length" "2")]) ;; Swap Bytes (change byte-endianness)
[gcc r15-3642] c++: Don't mix timevar_start and auto_cond_timevar for TV_NAME_LOOKUP [PR116681]
https://gcc.gnu.org/g:005f7176e0f457a1e1a7398ddcb4a4972da28c62 commit r15-3642-g005f7176e0f457a1e1a7398ddcb4a4972da28c62 Author: Simon Martin Date: Fri Sep 13 16:40:22 2024 +0200 c++: Don't mix timevar_start and auto_cond_timevar for TV_NAME_LOOKUP [PR116681] We currently ICE upon the following testcase when using -ftime-report === cut here === template < int> using __conditional_t = int; template < typename _Iter > concept random_access_iterator = requires { new _Iter; }; template < typename _Iterator > struct reverse_iterator { using iterator_concept = __conditional_t< random_access_iterator< _Iterator>>; }; void RemoveBottom() { int iter; for (reverse_iterator< int > iter;;) ; } === cut here === The problem is that qualified_namespace_lookup does a plain start() of the TV_NAME_LOOKUP timer (that asserts that the timer is not already started). However this timer has already been cond_start()'d in the call stack - by pushdecl - so the assert fails. This patch simply ensures that we always conditionally start this timer (which is done in all other places that use it). PR c++/116681 gcc/cp/ChangeLog: * name-lookup.cc (qualified_namespace_lookup): Use an auto_cond_timer instead of using timevar_start and timevar_stop. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-pr116681.C: New test. Diff: --- gcc/cp/name-lookup.cc | 3 +-- gcc/testsuite/g++.dg/cpp2a/concepts-pr116681.C | 20 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index bfe17b7cb2fc..c7a693e02d59 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -7421,10 +7421,9 @@ tree lookup_qualified_name (tree t, const char *p, LOOK_want w, bool c) static bool qualified_namespace_lookup (tree scope, name_lookup *lookup) { - timevar_start (TV_NAME_LOOKUP); + auto_cond_timevar tv (TV_NAME_LOOKUP); query_oracle (lookup->name); bool found = lookup->search_qualified (ORIGINAL_NAMESPACE (scope)); - timevar_stop (TV_NAME_LOOKUP); return found; } diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr116681.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr116681.C new file mode 100644 index ..f1b47797f1ed --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr116681.C @@ -0,0 +1,20 @@ +// PR c++/116681 +// { dg-do compile { target c++20 } } +// { dg-additional-options "-ftime-report" } +// { dg-allow-blank-lines-in-output 1 } +// { dg-prune-output "Time variable" } +// { dg-prune-output "k" } +// { dg-prune-output "\[0-9\]+%" } + +template < int> using __conditional_t = int; +template < typename _Iter > +concept random_access_iterator = requires { new _Iter; }; +template < typename _Iterator > struct reverse_iterator { + using iterator_concept = __conditional_t< random_access_iterator< _Iterator >>; +}; +void RemoveBottom() +{ + int iter; + for (reverse_iterator< int > iter;;) + ; +}
[gcc r15-3643] c++: avoid init_priority warning in system header
https://gcc.gnu.org/g:8b5e54712a1efd1bf0c08a3d9523ab0c265e344a commit r15-3643-g8b5e54712a1efd1bf0c08a3d9523ab0c265e344a Author: Jason Merrill Date: Sat Sep 14 11:46:22 2024 +0200 c++: avoid init_priority warning in system header We don't want a warning about a reserved init_priority in a system header even with -Wsystem-headers. gcc/cp/ChangeLog: * tree.cc (handle_init_priority_attribute): Check in_system_header_at. Diff: --- gcc/cp/tree.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index 99088da9cee0..f43febed124c 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -5196,7 +5196,8 @@ handle_init_priority_attribute (tree* node, /* Check for init_priorities that are reserved for language and runtime support implementations.*/ - if (pri <= MAX_RESERVED_INIT_PRIORITY) + if (pri <= MAX_RESERVED_INIT_PRIORITY + && !in_system_header_at (input_location)) { warning (0, "requested % %i is reserved for internal use",
[gcc r15-3644] testsuite; Fix execute/pr52286.c for 16bit
https://gcc.gnu.org/g:1dd6dd18783c3a7411b494f8b9d911cea784a270 commit r15-3644-g1dd6dd18783c3a7411b494f8b9d911cea784a270 Author: Andrew Pinski Date: Sat Sep 14 12:55:07 2024 -0700 testsuite; Fix execute/pr52286.c for 16bit The code path which was added for 16bit had a broken inline-asm which would only assign maybe half of the registers for the `long` type to 0. Adding L to the input operand of the inline-asm fixes the issue by now assigning the full 32bit value of the input register that would match up with the output register. Fixes r0-115223-gb0408f13d4b317 which added the 16bit code path to fix the testcase for 16bit. Pushed as obvious. PR testsuite/116716 gcc/testsuite/ChangeLog: * gcc.c-torture/execute/pr52286.c: Fix inline-asm for 16bit case. Diff: --- gcc/testsuite/gcc.c-torture/execute/pr52286.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gcc/testsuite/gcc.c-torture/execute/pr52286.c b/gcc/testsuite/gcc.c-torture/execute/pr52286.c index bb56295ab529..4fd5d6ac813d 100644 --- a/gcc/testsuite/gcc.c-torture/execute/pr52286.c +++ b/gcc/testsuite/gcc.c-torture/execute/pr52286.c @@ -11,7 +11,7 @@ main () b = (~a | 1) & -2038094497; #else long a, b; - asm ("" : "=r" (a) : "0" (0)); + asm ("" : "=r" (a) : "0" (0L)); b = (~a | 1) & -2038094497L; #endif if (b >= 0)
[gcc r15-3646] Mark the copy/move constructor/operator= of auto_bitmap as delete
https://gcc.gnu.org/g:d2f10fc934c3a425cf31979b1cf41fdc0f57c6d6 commit r15-3646-gd2f10fc934c3a425cf31979b1cf41fdc0f57c6d6 Author: Andrew Pinski Date: Fri Sep 13 20:17:15 2024 -0700 Mark the copy/move constructor/operator= of auto_bitmap as delete Since we are written in C++11, these should be marked as delete rather than just private. Bootstrapped and tested on x86_64-linux-gnu. gcc/ChangeLog: * bitmap.h (class auto_bitmap): Mark copy/move constructor/operator= as deleted. Signed-off-by: Andrew Pinski Diff: --- gcc/bitmap.h | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gcc/bitmap.h b/gcc/bitmap.h index 4cad1b4d6c6a..451edcfc5907 100644 --- a/gcc/bitmap.h +++ b/gcc/bitmap.h @@ -959,10 +959,10 @@ class auto_bitmap private: // Prevent making a copy that references our bitmap. - auto_bitmap (const auto_bitmap &); - auto_bitmap &operator = (const auto_bitmap &); - auto_bitmap (auto_bitmap &&); - auto_bitmap &operator = (auto_bitmap &&); + auto_bitmap (const auto_bitmap &) = delete; + auto_bitmap &operator = (const auto_bitmap &) = delete; + auto_bitmap (auto_bitmap &&) = delete; + auto_bitmap &operator = (auto_bitmap &&) = delete; bitmap_head m_bits; };
[gcc r15-3647] vect: release defs of removed statement
https://gcc.gnu.org/g:0b3133572edbd2b382e160ac78d7caf321f7f05b commit r15-3647-g0b3133572edbd2b382e160ac78d7caf321f7f05b Author: Andrew Pinski Date: Fri Sep 13 20:27:32 2024 -0700 vect: release defs of removed statement While trying to add use of simple_dce_from_worklist to the vectorizer so we don't need to run a full blown DCE pass after the vectorizer, there was a crash noticed due to a ssa name which has a stmt without a bb. This was due to not calling release_defs after the call to gsi_remove. Note the code to remove zero use statements should be able to remove once the use of simple_dce_from_worklist has been added. But in the meantime, fixing this bug will also improve memory usage and a few other things which look through all ssa names. gcc/ChangeLog: * tree-vect-loop.cc (optimize_mask_stores): Call release_defs after the call to gsi_remove with last argument of true. Signed-off-by: Andrew Pinski Diff: --- gcc/tree-vect-loop.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc index cc15492f6a01..62c7f90779fa 100644 --- a/gcc/tree-vect-loop.cc +++ b/gcc/tree-vect-loop.cc @@ -12803,6 +12803,7 @@ optimize_mask_stores (class loop *loop) if (has_zero_uses (lhs)) { gsi_remove (&gsi_from, true); + release_defs (stmt1); continue; } }
[gcc r15-3648] phi-opt: Improve heuristics for factoring out with constant (again) [PR116699]
https://gcc.gnu.org/g:6e4244e8ceac939fe8a24470b4ff31c82e8bff21 commit r15-3648-g6e4244e8ceac939fe8a24470b4ff31c82e8bff21 Author: Andrew Pinski Date: Fri Sep 13 10:47:29 2024 -0700 phi-opt: Improve heuristics for factoring out with constant (again) [PR116699] The heuristics for factoring out with a constant checks that the assignment statement is the last statement of the basic block but sometimes there is a predicate or a nop statement after the assignment. Rejecting this case does not make sense since both predicates and nop statements are removed and don't contribute any instructions. So we should skip over them when checking if the assignment statement was the last statement in the basic block. phi-opt-factor-1.c's f0 is such an example where it should catch it at phiopt1 (before predicates are removed) and should happen in a similar way as f1 (which uses a temporary variable rather than return). Bootstrapped and tested on x86_64-linux-gnu. PR tree-optimization/116699 gcc/ChangeLog: * tree-ssa-phiopt.cc (factor_out_conditional_operation): Skip over nop/predicates for seeing the assignment is the last statement. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/phi-opt-factor-1.c: New test. Signed-off-by: Andrew Pinski Diff: --- gcc/testsuite/gcc.dg/tree-ssa/phi-opt-factor-1.c | 26 gcc/tree-ssa-phiopt.cc | 6 ++ 2 files changed, 32 insertions(+) diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-factor-1.c b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-factor-1.c new file mode 100644 index ..12b846b9337f --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-factor-1.c @@ -0,0 +1,26 @@ +/* { dg-options "-O2 -fdump-tree-phiopt" } */ + +/* PR tree-optimization/116699 + Make sure the return PREDICT has no factor in deciding + if we factor out the conversion. */ + +short f0(int a, int b, int c) +{ + int t1 = 4; + if (c < t1) return (c > -1 ? c : -1); + return t1; +} + + +short f1(int a, int b, int c) +{ + int t1 = 4; + short t = t1; + if (c < t1) t = (c > -1 ? c : -1); + return t; +} + +/* Both f1 and f0 should be optimized at phiopt1 to the same thing. */ +/* { dg-final { scan-tree-dump-times "MAX_EXPR " 2 "phiopt1" } } */ +/* { dg-final { scan-tree-dump-times "MIN_EXPR " 2 "phiopt1" } } */ +/* { dg-final { scan-tree-dump-not "if " "phiopt1" } } */ diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc index e5413e405722..7b12692237e5 100644 --- a/gcc/tree-ssa-phiopt.cc +++ b/gcc/tree-ssa-phiopt.cc @@ -360,6 +360,12 @@ factor_out_conditional_operation (edge e0, edge e1, gphi *phi, } gsi = gsi_for_stmt (arg0_def_stmt); gsi_next_nondebug (&gsi); + /* Skip past nops and predicates. */ + while (!gsi_end_p (gsi) + && (gimple_code (gsi_stmt (gsi)) == GIMPLE_NOP + || gimple_code (gsi_stmt (gsi)) == GIMPLE_PREDICT)) + gsi_next_nondebug (&gsi); + /* Reject if the statement was not at the end of the block. */ if (!gsi_end_p (gsi)) return NULL; }
[gcc r15-3649] c++, coroutines: Fix handling of bool await_suspend() [PR115905].
https://gcc.gnu.org/g:368ba7aed46d57d093c0180baae4dc0e0ba468b6 commit r15-3649-g368ba7aed46d57d093c0180baae4dc0e0ba468b6 Author: Iain Sandoe Date: Fri Sep 6 20:59:43 2024 +0100 c++, coroutines: Fix handling of bool await_suspend() [PR115905]. As noted in the PR the action of the existing implementation was to treat a false value from await_suspend () as equivalent to "do not suspend". Actually it needs to be the equivalent of "resume" - and we need to restart the dispatcher - since the await_suspend() body could have already resumed the coroutine. See also https://github.com/cplusplus/CWG/issues/601 (NAD) for more discussion. Since we need to amend the await expansion and the actor build, take the opportunity to clean up and modernise the code there. Note that we need to make the jump back to the dispatcher without any scope exit cleanups (so we have to use the .CO_SUSPN IFN to do this). PR c++/115905 gcc/cp/ChangeLog: * coroutines.cc (struct coro_aw_data): Add a member for the restart dispatch label. (expand_one_await_expression): Rework to modernise and to handle the boolean await_suspend() case. (build_actor_fn): Rework the dispatcher and allow for a jump back to the dispatcher. gcc/testsuite/ChangeLog: * g++.dg/coroutines/torture/pr115905.C: New test. Signed-off-by: Iain Sandoe Diff: --- gcc/cp/coroutines.cc | 215 +++-- gcc/testsuite/g++.dg/coroutines/torture/pr115905.C | 64 ++ 2 files changed, 174 insertions(+), 105 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index d6acf09326f9..002d575f3324 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -1780,6 +1780,7 @@ struct coro_aw_data tree cleanup;/* This is where to go once we complete local destroy. */ tree cororet;/* This is where to go if we suspend. */ tree corocont; /* This is where to go if we continue. */ + tree dispatch; /* This is where we go if we restart the dispatch. */ tree conthand; /* This is the handle for a continuation. */ unsigned index; /* This is our current resume index. */ }; @@ -1824,42 +1825,44 @@ co_await_find_in_subtree (tree *stmt, int *, void *d) in either. */ static tree * -expand_one_await_expression (tree *stmt, tree *await_expr, void *d) +expand_one_await_expression (tree *expr, tree *await_expr, void *d) { coro_aw_data *data = (coro_aw_data *) d; - tree saved_statement = *stmt; + tree saved_statement = *expr; tree saved_co_await = *await_expr; tree actor = data->actor_fn; - location_t loc = EXPR_LOCATION (*stmt); + location_t loc = EXPR_LOCATION (*expr); tree var = TREE_OPERAND (saved_co_await, 1); /* frame slot. */ - tree expr = TREE_OPERAND (saved_co_await, 2); /* initializer. */ + tree init_expr = TREE_OPERAND (saved_co_await, 2); /* initializer. */ tree awaiter_calls = TREE_OPERAND (saved_co_await, 3); tree source = TREE_OPERAND (saved_co_await, 4); bool is_final = (source && TREE_INT_CST_LOW (source) == (int) FINAL_SUSPEND_POINT); - bool needs_dtor = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (var)); + + /* Build labels for the destinations of the control flow when we are resuming + or destroying. */ int resume_point = data->index; - size_t bufsize = sizeof ("destroy.") + 10; - char *buf = (char *) alloca (bufsize); - snprintf (buf, bufsize, "destroy.%d", resume_point); + char *buf = xasprintf ("destroy.%d", resume_point); tree destroy_label = create_named_label_with_ctx (loc, buf, actor); - snprintf (buf, bufsize, "resume.%d", resume_point); + free (buf); + buf = xasprintf ("resume.%d", resume_point); tree resume_label = create_named_label_with_ctx (loc, buf, actor); - tree empty_list = build_empty_stmt (loc); + free (buf); - tree stmt_list = NULL; - tree r; + /* This will contain our expanded expression and replace the original + expression. */ + tree stmt_list = push_stmt_list (); tree *await_init = NULL; - if (!expr) + bool needs_dtor = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (var)); + if (!init_expr) needs_dtor = false; /* No need, the var's lifetime is managed elsewhere. */ else { - r = coro_build_cvt_void_expr_stmt (expr, loc); - append_to_statement_list_force (r, &stmt_list); + finish_expr_stmt (init_expr); /* We have an initializer, which might itself contain await exprs. */ await_init = tsi_stmt_ptr (tsi_last (stmt_list)); } @@ -1870,18 +1873,15 @@ expand_one_await_expression (tree *stmt, tree *await_expr, void *d) if (TREE_CODE (TREE_TYPE (ready_cond)) != BOOLEAN_TYPE) ready_cond = cp_convert (boolean_type_node, ready_cond, tf_warning_or_error); + tree susp_if = begin_if_stmt ();