https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118074

            Bug ID: 118074
           Summary: [coroutine] Possible over optimization of co_return
           Product: gcc
           Version: 15.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: newsigma at 163 dot com
  Target Milestone: ---

Hi all,

I want to discuss an unusual usage of coroutine and CRTP. The following code
gives the expected result using MSVC, but a unpredictable result using GCC and
clang.

https://godbolt.org/z/r97MbdMhT

```
#include <cstdio>
#include <utility>
#include <coroutine>

template<class T>
struct CRCoro { // Curiously Recurring Coroutine
    struct RValueWrapper {
        T* p;

        operator T&&() const noexcept { return std::move(*p); }
    };

    using promise_type = T;

    T& getDerived() noexcept { return *static_cast<T*>(this); }

    auto get_return_object() noexcept { return RValueWrapper(&getDerived()); }
    std::suspend_never initial_suspend() noexcept { return {}; }
    std::suspend_never final_suspend() noexcept { return {}; }
    void return_value(T&& x) noexcept {
        getDerived() = std::move(x);
        //asm volatile("" : : "r,m"(getDerived()) : "memory"); // Forcing
assignment has observable side effect
    }
    void unhandled_exception() {}
};

struct A : public CRCoro<A> {
    int a;
};

A func() {
    A aa{};
    aa.a = 5;
    co_return std::move(aa);
}

int main() {
    printf("%d\n", func().a);
    return 0;
}
```
Expected result (MSVC): 5

Build option: -std=c++20 -fcoroutines
GCC 10.5, 11.4, 12.4, 13.3, 14.2: 5
GCC trunk: 0

Build option: -std=c++20 -fcoroutines -O2
GCC 10.5, 11.4, 12.4, 13.3, trunk: 0
GCC 14.2: 5

Forcing assignment has observable side effect is a workaround for me. But the
trick does not work for trunk. Is it the expected behavior or a bug?

Reply via email to