Skip to content

[clang] [coroutines] impossible happens, incorrect behavior (bug) #102606

Open
@kelbon

Description

@kelbon

Appears, that compiler passes .done() handle into await_suspend, which should never happen.
Returning handle of coroutine from its final_suspend should be correct and may be used to "continue" coroutine and free memory

https://godbolt.org/z/oeh5Tooxb

#include <coroutine>
#include <iostream>

struct transfer_control_to {
  std::coroutine_handle<> waiter;

  bool await_ready() const noexcept { return false; }
  std::coroutine_handle<> await_suspend(std::coroutine_handle<> h) noexcept {
    if (h.done()) {
      std::cout << "IMPOSSIBLE HAPPEN" << std::endl;
      h.destroy();
      return std::noop_coroutine();
    }
    return waiter;
  }
  static void await_resume() noexcept {}
};

struct task_promise {
  std::coroutine_handle<void> waiter;

  static constexpr std::suspend_always initial_suspend() noexcept { return {}; }
  static void return_void() {}

  auto get_return_object() {
    return std::coroutine_handle<task_promise>::from_promise(*this);
  }
  void unhandled_exception() noexcept {}
  auto final_suspend() noexcept { return transfer_control_to{waiter}; }
};

struct task {
  using promise_type = task_promise;
  using handle_type = std::coroutine_handle<promise_type>;

  handle_type handle_;

  constexpr task(handle_type handle) noexcept : handle_(handle) {}

  void start_and_detach() {
    handle_.promise().waiter = handle_;
    handle_.resume();
    handle_ = nullptr;
  }
};

task foo() { co_return; }
void bar() {
  auto t = foo();
  t.start_and_detach();
}

int main() { bar(); }

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions