brintos

brintos / llvm-project-archived public Read only

0
0
Text · 2.7 KiB · cd851c0 Raw
86 lines · cpp
1// An end-to-end test to make sure things get processed correctly.2// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s -O3 | \3// RUN:     FileCheck %s4 5#include "Inputs/coroutine.h"6 7struct SomeAwaitable {8  // Resume the supplied handle once the awaitable becomes ready,9  // returning a handle that should be resumed now for the sake of symmetric transfer.10  // If the awaitable is already ready, return an empty handle without doing anything.11  //12  // Defined in another translation unit. Note that this may contain13  // code that synchronizees with another thread.14  std::coroutine_handle<> Register(std::coroutine_handle<>);15};16 17// Defined in another translation unit.18void DidntSuspend();19 20struct Awaiter {21  SomeAwaitable&& awaitable;22  bool suspended;23 24  bool await_ready() { return false; }25 26  std::coroutine_handle<> await_suspend(const std::coroutine_handle<> h) {27    // Assume we will suspend unless proven otherwise below. We must do28    // this *before* calling Register, since we may be destroyed by another29    // thread asynchronously as soon as we have registered.30    suspended = true;31 32    // Attempt to hand off responsibility for resuming/destroying the coroutine.33    const auto to_resume = awaitable.Register(h);34 35    if (!to_resume) {36      // The awaitable is already ready. In this case we know that Register didn't37      // hand off responsibility for the coroutine. So record the fact that we didn't38      // actually suspend, and tell the compiler to resume us inline.39      suspended = false;40      return h;41    }42 43    // Resume whatever Register wants us to resume.44    return to_resume;45  }46 47  void await_resume() {48    // If we didn't suspend, make note of that fact.49    if (!suspended) {50      DidntSuspend();51    }52  }53};54 55struct MyTask{56  struct promise_type {57    MyTask get_return_object() { return {}; }58    std::suspend_never initial_suspend() { return {}; }59    std::suspend_always final_suspend() noexcept { return {}; }60    void unhandled_exception();61 62    Awaiter await_transform(SomeAwaitable&& awaitable) {63      return Awaiter{static_cast<SomeAwaitable&&>(awaitable)};64    }65  };66};67 68MyTask FooBar() {69  co_await SomeAwaitable();70}71 72// CHECK-LABEL: @_Z6FooBarv73// CHECK: %[[to_resume:.*]] = {{.*}}call ptr @_ZN13SomeAwaitable8RegisterESt16coroutine_handleIvE74// CHECK-NEXT: %[[to_bool:.*]] = icmp eq ptr %[[to_resume]], null75// CHECK-NEXT: br i1 %[[to_bool]], label %[[then:.*]], label %[[else:.*]]76 77// CHECK: [[then]]:78// We only access the coroutine frame conditionally as the sources did.79// CHECK:   store i8 0,80// CHECK-NEXT: br label %[[else]]81 82// CHECK: [[else]]:83// No more access to the coroutine frame until suspended.84// CHECK-NOT: store85// CHECK: }86