brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.0 KiB · deb19b4 Raw
128 lines · cpp
1// This file tests the coro_await_elidable attribute semantics.2// RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -std=c++20 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s3 4#include "Inputs/coroutine.h"5#include "Inputs/utility.h"6 7template <typename T>8struct [[clang::coro_await_elidable]] Task {9  struct promise_type {10    struct FinalAwaiter {11      bool await_ready() const noexcept { return false; }12 13      template <typename P>14      std::coroutine_handle<> await_suspend(std::coroutine_handle<P> coro) noexcept {15        if (!coro)16          return std::noop_coroutine();17        return coro.promise().continuation;18      }19      void await_resume() noexcept {}20    };21 22    Task get_return_object() noexcept {23      return std::coroutine_handle<promise_type>::from_promise(*this);24    }25 26    std::suspend_always initial_suspend() noexcept { return {}; }27    FinalAwaiter final_suspend() noexcept { return {}; }28    void unhandled_exception() noexcept {}29    void return_value(T x) noexcept {30      value = x;31    }32 33    std::coroutine_handle<> continuation;34    T value;35  };36 37  Task(std::coroutine_handle<promise_type> handle) : handle(handle) {}38  ~Task() {39    if (handle)40      handle.destroy();41  }42 43  struct Awaiter {44    Awaiter(Task *t) : task(t) {}45    bool await_ready() const noexcept { return false; }46    void await_suspend(std::coroutine_handle<void> continuation) noexcept {}47    T await_resume() noexcept {48      return task->handle.promise().value;49    }50 51    Task *task;52  };53 54  auto operator co_await() {55    return Awaiter{this};56  }57 58private:59  std::coroutine_handle<promise_type> handle;60};61 62// CHECK-LABEL: define{{.*}} @_Z6calleev{{.*}} {63Task<int> callee() {64  co_return 1;65}66 67// CHECK-LABEL: define{{.*}} @_Z8elidablev{{.*}} {68Task<int> elidable() {69  // CHECK: %[[TASK_OBJ:.+]] = alloca %struct.Task70  // CHECK: call void @_Z6calleev(ptr dead_on_unwind writable sret(%struct.Task) align 8 %[[TASK_OBJ]]) #[[ELIDE_SAFE:.+]]71  co_return co_await callee();72}73 74// CHECK-LABEL: define{{.*}} @_Z11nonelidablev{{.*}} {75Task<int> nonelidable() {76  // CHECK: %[[TASK_OBJ:.+]] = alloca %struct.Task77  auto t = callee();78  // Because we aren't co_awaiting a prvalue, we cannot elide here.79  // CHECK: call void @_Z6calleev(ptr dead_on_unwind writable sret(%struct.Task) align 8 %[[TASK_OBJ]])80  // CHECK-NOT: #[[ELIDE_SAFE]]81  co_await t;82  co_await std::move(t);83 84  co_return 1;85}86 87// CHECK-LABEL: define{{.*}} @_Z8addTasksO4TaskIiES1_{{.*}} {88Task<int> addTasks([[clang::coro_await_elidable_argument]] Task<int> &&t1, Task<int> &&t2) {89  int i1 = co_await t1;90  int i2 = co_await t2;91  co_return i1 + i2;92}93 94// CHECK-LABEL: define{{.*}} @_Z10returnSamei{{.*}} {95Task<int> returnSame(int i) {96  co_return i;97}98 99// CHECK-LABEL: define{{.*}} @_Z21elidableWithMustAwaitv{{.*}} {100Task<int> elidableWithMustAwait() {101  // CHECK: call void @_Z10returnSamei(ptr {{.*}}, i32 noundef 2) #[[ELIDE_SAFE]]102  // CHECK: call void @_Z10returnSamei(ptr {{.*}}, i32 noundef 3){{$}}103  co_return co_await addTasks(returnSame(2), returnSame(3));104}105 106template <typename... Args>107Task<int> sumAll([[clang::coro_await_elidable_argument]] Args && ... tasks);108 109// CHECK-LABEL: define{{.*}} @_Z16elidableWithPackv{{.*}} {110Task<int> elidableWithPack() {111  // CHECK: call void @_Z10returnSamei(ptr {{.*}}, i32 noundef 1){{$}}112  // CHECK: call void @_Z10returnSamei(ptr {{.*}}, i32 noundef 2) #[[ELIDE_SAFE]]113  // CHECK: call void @_Z10returnSamei(ptr {{.*}}, i32 noundef 3) #[[ELIDE_SAFE]]114  auto t = returnSame(1);115  co_return co_await sumAll(t, returnSame(2), returnSame(3));116}117 118 119// CHECK-LABEL: define{{.*}} @_Z25elidableWithPackRecursivev{{.*}} {120Task<int> elidableWithPackRecursive() {121  // CHECK: call void @_Z10returnSamei(ptr {{.*}}, i32 noundef 1) #[[ELIDE_SAFE]]122  // CHECK: call void @_Z10returnSamei(ptr {{.*}}, i32 noundef 2){{$}}123  // CHECK: call void @_Z10returnSamei(ptr {{.*}}, i32 noundef 3) #[[ELIDE_SAFE]]124  co_return co_await sumAll(addTasks(returnSame(1), returnSame(2)), returnSame(3));125}126 127// CHECK: attributes #[[ELIDE_SAFE]] = { coro_elide_safe }128