Files
clang-p2996/clang/test/CodeGenCoroutines/coro-symmetric-transfer-02.cpp
Chuanqi Xu ec117158a3 [Coroutines] [Frontend] Lookup in std namespace first
Now in libcxx and clang, all the coroutine components are defined in
std::experimental namespace.
And now the coroutine TS is merged into C++20. So in the working draft
like N4892, we could find the coroutine components is defined in std
namespace instead of std::experimental namespace.
And the coroutine support in clang seems to be relatively stable. So I
think it may be suitable to move the coroutine component into the
experiment namespace now.

This patch would make clang lookup coroutine_traits in std namespace
first. For the compatibility consideration, clang would lookup in
std::experimental namespace if it can't find definitions in std
namespace. So the existing codes wouldn't be break after update
compiler.

And in case the compiler found std::coroutine_traits and
std::experimental::coroutine_traits at the same time, it would emit an
error for it.

The support for looking up std::experimental::coroutine_traits would be
removed in Clang16.

Reviewed By: lxfind, Quuxplusone

Differential Revision: https://reviews.llvm.org/D108696
2021-11-04 11:53:47 +08:00

125 lines
4.0 KiB
C++

// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -O1 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
#include "Inputs/coroutine.h"
struct Task {
struct promise_type {
Task get_return_object() noexcept {
return Task{std::coroutine_handle<promise_type>::from_promise(*this)};
}
void return_void() noexcept {}
struct final_awaiter {
bool await_ready() noexcept { return false; }
std::coroutine_handle<> await_suspend(std::coroutine_handle<promise_type> h) noexcept {
h.destroy();
return {};
}
void await_resume() noexcept {}
};
void unhandled_exception() noexcept {}
final_awaiter final_suspend() noexcept { return {}; }
std::suspend_always initial_suspend() noexcept { return {}; }
template <typename Awaitable>
auto await_transform(Awaitable &&awaitable) {
return awaitable.co_viaIfAsync();
}
};
using handle_t = std::coroutine_handle<promise_type>;
class Awaiter {
public:
explicit Awaiter(handle_t coro) noexcept;
Awaiter(Awaiter &&other) noexcept;
Awaiter(const Awaiter &) = delete;
~Awaiter();
bool await_ready() noexcept { return false; }
handle_t await_suspend(std::coroutine_handle<> continuation) noexcept;
void await_resume();
private:
handle_t coro_;
};
Task(handle_t coro) noexcept : coro_(coro) {}
handle_t coro_;
Task(const Task &t) = delete;
Task(Task &&t) noexcept;
~Task();
Task &operator=(Task t) noexcept;
Awaiter co_viaIfAsync();
};
static Task foo() {
co_return;
}
Task bar() {
auto mode = 2;
switch (mode) {
case 1:
co_await foo();
break;
case 2:
co_await foo();
break;
default:
break;
}
}
// CHECK-LABEL: define{{.*}} void @_Z3barv
// CHECK: %[[MODE:.+]] = load i32, i32* %mode
// CHECK-NEXT: switch i32 %[[MODE]], label %{{.+}} [
// CHECK-NEXT: i32 1, label %[[CASE1:.+]]
// CHECK-NEXT: i32 2, label %[[CASE2:.+]]
// CHECK-NEXT: ]
// CHECK: [[CASE1]]:
// CHECK: br i1 %{{.+}}, label %[[CASE1_AWAIT_READY:.+]], label %[[CASE1_AWAIT_SUSPEND:.+]]
// CHECK: [[CASE1_AWAIT_SUSPEND]]:
// CHECK-NEXT: %{{.+}} = call token @llvm.coro.save(i8* null)
// CHECK-NEXT: %[[HANDLE11:.+]] = bitcast %"struct.std::coroutine_handle"* %[[TMP1:.+]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* %[[HANDLE11]])
// CHECK: %[[HANDLE12:.+]] = bitcast %"struct.std::coroutine_handle"* %[[TMP1]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* %[[HANDLE12]])
// CHECK-NEXT: call void @llvm.coro.resume
// CHECK-NEXT: %{{.+}} = call i8 @llvm.coro.suspend
// CHECK-NEXT: switch i8 %{{.+}}, label %coro.ret [
// CHECK-NEXT: i8 0, label %[[CASE1_AWAIT_READY]]
// CHECK-NEXT: i8 1, label %[[CASE1_AWAIT_CLEANUP:.+]]
// CHECK-NEXT: ]
// CHECK: [[CASE1_AWAIT_CLEANUP]]:
// make sure that the awaiter eventually gets cleaned up.
// CHECK: call void @{{.+Awaiter.+}}
// CHECK: [[CASE2]]:
// CHECK: br i1 %{{.+}}, label %[[CASE2_AWAIT_READY:.+]], label %[[CASE2_AWAIT_SUSPEND:.+]]
// CHECK: [[CASE2_AWAIT_SUSPEND]]:
// CHECK-NEXT: %{{.+}} = call token @llvm.coro.save(i8* null)
// CHECK-NEXT: %[[HANDLE21:.+]] = bitcast %"struct.std::coroutine_handle"* %[[TMP2:.+]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* %[[HANDLE21]])
// CHECK: %[[HANDLE22:.+]] = bitcast %"struct.std::coroutine_handle"* %[[TMP2]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* %[[HANDLE22]])
// CHECK-NEXT: call void @llvm.coro.resume
// CHECK-NEXT: %{{.+}} = call i8 @llvm.coro.suspend
// CHECK-NEXT: switch i8 %{{.+}}, label %coro.ret [
// CHECK-NEXT: i8 0, label %[[CASE2_AWAIT_READY]]
// CHECK-NEXT: i8 1, label %[[CASE2_AWAIT_CLEANUP:.+]]
// CHECK-NEXT: ]
// CHECK: [[CASE2_AWAIT_CLEANUP]]:
// make sure that the awaiter eventually gets cleaned up.
// CHECK: call void @{{.+Awaiter.+}}