luncliff/coroutine

clang ignores template functions for `co_await`?

Closed this issue · 2 comments

branch : dev/net

Note

As the error message notes, it seems that co_await operator searches only for member functions.

The following error is from clang 7.1.0 in WSL

clang version 7.1.0-svn353565-1~exp1~20190408084827.60 (branches/release_70)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

The message.

/mnt/d/coroutine/test/c2_socket_echo_tcp.cpp:139:20: error: no member named 'await_ready' in 'io_recv'
    rsz = co_await recv_stream(sd, storage, 0, work);
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/mnt/d/coroutine/test/c2_socket_echo_tcp.cpp:157:20: error: no member named 'await_ready' in 'io_send'
    ssz = co_await send_stream(sd, storage, 0, work);
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/mnt/d/coroutine/test/c2_socket_echo_tcp.cpp:176:20: error: no member named 'await_ready' in 'io_recv'
    rsz = co_await recv_stream(sd, buf = storage, 0, work);
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/mnt/d/coroutine/test/c2_socket_echo_udp.cpp:129:20: error: no member named 'await_ready' in 'io_recv_from'
    rsz = co_await recv_from(sd, remote, storage, work);
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/mnt/d/coroutine/test/c2_socket_echo_tcp.cpp:182:20: error: no member named 'await_ready' in 'io_send'
    ssz = co_await send_stream(sd, buf, 0, work);
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/mnt/d/coroutine/test/c2_socket_echo_udp.cpp:147:20: error: no member named 'await_ready' in 'io_send_to'
    ssz = co_await send_to(sd, remote, storage, work);
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/mnt/d/coroutine/test/c2_socket_echo_udp.cpp:164:24: error: no member named 'await_ready' in 'io_recv_from'
        rsz = co_await recv_from(sd, remote, buf = storage, work);
                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/mnt/d/coroutine/test/c2_socket_echo_udp.cpp:168:24: error: no member named 'await_ready' in 'io_send_to'
        ssz = co_await send_to(sd, remote, buf = {storage.data(), rsz}, work);
                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 errors generated.
make[2]: *** [test/CMakeFiles/coroutine_test.dir/c2_socket_echo_tcp.cpp.o] Error 1
make[2]: *** Waiting for unfinished jobs....
4 errors generated.
make[2]: *** [test/CMakeFiles/coroutine_test.dir/c2_socket_echo_udp.cpp.o] Error 1
make[1]: *** [test/CMakeFiles/coroutine_test.dir/all] Error 2
make: *** [all] Error 2

Tried this, but this handling can be complex.

//
//  Derived class of `io_work_t` will be used for `co_await`.
//  We can use template to generate functions for the operator
//   and perform some type check for given types
//
//  ToDo: C++ Concepts
//
template <typename IoStruct>
struct redirect_co_await {

    // clang requires await_* functions to be the member function
    //  of the awaitable type. instead of defining those functions
    //  in each derived types, we will use this template

    auto await_ready() noexcept {
        static_assert(std::is_base_of_v<io_work_t, IoStruct>);
        return this->ready();
    }

    // these functions is not the member of `io_work_t`.
    // its derived type must declare/define it...

    void await_suspend(io_task_t t) noexcept(false) {
        static_assert(std::is_base_of_v<io_work_t, IoStruct>);
        return this->suspend(t);
    }
    auto await_resume() noexcept {
        static_assert(std::is_base_of_v<io_work_t, IoStruct>);
        return this->resume();
    }
};

//  Type to perform `send` I/O request
class io_send final : public io_work_t, public redirect_co_await<io_send> {
  public:
    _INTERFACE_ void suspend(io_task_t t) noexcept(false);
    _INTERFACE_ int64_t resume() noexcept;
};
static_assert(sizeof(io_send) == sizeof(io_work_t));

Performing rollback to the member function scheme...

The standard document doesn't state that such an expression is possible.
I was confused with previous experiences...