Revert "[Coroutines] [Clang] Look up coroutine component in std namespace first"

This reverts commit 2fbd254aa4, which broke the libc++ CI. I'm reverting
to get things stable again until we've figured out a way forward.

Differential Revision: https://reviews.llvm.org/D108696
This commit is contained in:
Louis Dionne 2021-09-03 16:01:09 -04:00
parent 40f1593558
commit 79f8b5f0d0
49 changed files with 350 additions and 1772 deletions

View File

@ -1,6 +1,7 @@
#pragma once
namespace std {
namespace experimental {
template <typename ret_t, typename... args_t>
struct coroutine_traits {
@ -12,6 +13,7 @@ struct coroutine_handle {
static constexpr coroutine_handle from_address(void *addr) noexcept { return {}; };
};
} // namespace experimental
} // namespace std
struct never_suspend {

View File

@ -2872,7 +2872,7 @@ C++ Coroutines support builtins
Clang provides experimental builtins to support C++ Coroutines as defined by
https://wg21.link/P0057. The following four are intended to be used by the
standard library to implement `std::coroutine_handle` type.
standard library to implement `std::experimental::coroutine_handle` type.
**Syntax**:

View File

@ -10957,20 +10957,19 @@ def err_coroutine_invalid_func_context : Error<
"|a function with a deduced return type|a varargs function"
"|a consteval function}0">;
def err_implied_coroutine_type_not_found : Error<
"%0 type was not found; include <coroutine> before defining "
"a coroutine; include <experimental/coroutine> if your version "
"of libcxx is less than 14.0">;
"%0 type was not found; include <experimental/coroutine> before defining "
"a coroutine">;
def err_implicit_coroutine_std_nothrow_type_not_found : Error<
"std::nothrow was not found; include <new> before defining a coroutine which "
"uses get_return_object_on_allocation_failure()">;
def err_malformed_std_nothrow : Error<
"std::nothrow must be a valid variable declaration">;
def err_malformed_std_coroutine_handle : Error<
"std::coroutine_handle must be a class template">;
"std::experimental::coroutine_handle must be a class template">;
def err_coroutine_handle_missing_member : Error<
"std::coroutine_handle missing a member named '%0'">;
"std::experimental::coroutine_handle missing a member named '%0'">;
def err_malformed_std_coroutine_traits : Error<
"'std::coroutine_traits' must be a class template">;
"'std::experimental::coroutine_traits' must be a class template">;
def err_implied_std_coroutine_traits_promise_type_not_found : Error<
"this function cannot be a coroutine: %q0 has no member named 'promise_type'">;
def err_implied_std_coroutine_traits_promise_type_not_class : Error<
@ -11012,10 +11011,6 @@ def note_await_ready_no_bool_conversion : Note<
def warn_coroutine_handle_address_invalid_return_type : Warning <
"return type of 'coroutine_handle<>::address should be 'void*' (have %0) in order to get capability with existing async C API.">,
InGroup<Coroutine>;
def warn_coroutine_in_legacy_experimental_space : Warning <
"coroutine_traits defined in std::experimental namespace is deprecated. "
"Consider updating libcxx and include <coroutine> instead of <experimental/coroutine>.">,
InGroup<Coroutine>;
def err_coroutine_promise_final_suspend_requires_nothrow : Error<
"the expression 'co_await __promise.final_suspend()' is required to be non-throwing"
>;

View File

@ -1128,10 +1128,6 @@ public:
/// The C++ "std::coroutine_traits" template, which is defined in
/// \<coroutine_traits>
ClassTemplateDecl *StdCoroutineTraitsCache;
/// The namespace where coroutine components are defined. In standard,
/// they are defined in std namespace. And in the previous implementation,
/// they are defined in std::experimental namespace.
NamespaceDecl *CoroTraitsNamespaceCache;
/// The C++ "type_info" declaration, which is defined in \<typeinfo>.
RecordDecl *CXXTypeInfoDecl;
@ -5666,7 +5662,6 @@ public:
NamespaceDecl *getOrCreateStdNamespace();
NamespaceDecl *lookupStdExperimentalNamespace();
NamespaceDecl *getCachedCoroNamespace() { return CoroTraitsNamespaceCache; }
CXXRecordDecl *getStdBadAlloc() const;
EnumDecl *getStdAlignValT() const;
@ -10223,11 +10218,8 @@ public:
bool buildCoroutineParameterMoves(SourceLocation Loc);
VarDecl *buildCoroutinePromise(SourceLocation Loc);
void CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body);
/// Lookup 'coroutine_traits' in std namespace and std::experimental
/// namespace. The namespace found would be recorded in Namespace.
ClassTemplateDecl *lookupCoroutineTraits(SourceLocation KwLoc,
SourceLocation FuncLoc,
NamespaceDecl *&Namespace);
SourceLocation FuncLoc);
/// Check that the expression co_await promise.final_suspend() shall not be
/// potentially-throwing.
bool checkFinalSuspendNoThrow(const Stmt *FinalSuspend);

View File

@ -53,10 +53,15 @@ static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD,
SourceLocation KwLoc) {
const FunctionProtoType *FnType = FD->getType()->castAs<FunctionProtoType>();
const SourceLocation FuncLoc = FD->getLocation();
// FIXME: Cache std::coroutine_traits once we've found it.
NamespaceDecl *StdExp = S.lookupStdExperimentalNamespace();
if (!StdExp) {
S.Diag(KwLoc, diag::err_implied_coroutine_type_not_found)
<< "std::experimental::coroutine_traits";
return QualType();
}
NamespaceDecl *CoroNamespace = nullptr;
ClassTemplateDecl *CoroTraits =
S.lookupCoroutineTraits(KwLoc, FuncLoc, CoroNamespace);
ClassTemplateDecl *CoroTraits = S.lookupCoroutineTraits(KwLoc, FuncLoc);
if (!CoroTraits) {
return QualType();
}
@ -117,7 +122,7 @@ static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD,
QualType PromiseType = S.Context.getTypeDeclType(Promise);
auto buildElaboratedType = [&]() {
auto *NNS = NestedNameSpecifier::Create(S.Context, nullptr, CoroNamespace);
auto *NNS = NestedNameSpecifier::Create(S.Context, nullptr, StdExp);
NNS = NestedNameSpecifier::Create(S.Context, NNS, false,
CoroTrait.getTypePtr());
return S.Context.getElaboratedType(ETK_None, NNS, PromiseType);
@ -136,20 +141,20 @@ static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD,
return PromiseType;
}
/// Look up the std::coroutine_handle<PromiseType>.
/// Look up the std::experimental::coroutine_handle<PromiseType>.
static QualType lookupCoroutineHandleType(Sema &S, QualType PromiseType,
SourceLocation Loc) {
if (PromiseType.isNull())
return QualType();
NamespaceDecl *CoroNamespace = S.getCachedCoroNamespace();
assert(CoroNamespace && "Should already be diagnosed");
NamespaceDecl *StdExp = S.lookupStdExperimentalNamespace();
assert(StdExp && "Should already be diagnosed");
LookupResult Result(S, &S.PP.getIdentifierTable().get("coroutine_handle"),
Loc, Sema::LookupOrdinaryName);
if (!S.LookupQualifiedName(Result, CoroNamespace)) {
if (!S.LookupQualifiedName(Result, StdExp)) {
S.Diag(Loc, diag::err_implied_coroutine_type_not_found)
<< "std::coroutine_handle";
<< "std::experimental::coroutine_handle";
return QualType();
}
@ -995,7 +1000,7 @@ static Expr *buildStdNoThrowDeclRef(Sema &S, SourceLocation Loc) {
LookupResult Result(S, &S.PP.getIdentifierTable().get("nothrow"), Loc,
Sema::LookupOrdinaryName);
if (!S.LookupQualifiedName(Result, Std)) {
// FIXME: <coroutine> should have been included already.
// FIXME: <experimental/coroutine> should have been included already.
// If we require it to include <new> then this diagnostic is no longer
// needed.
S.Diag(Loc, diag::err_implicit_coroutine_std_nothrow_type_not_found);
@ -1658,32 +1663,25 @@ StmtResult Sema::BuildCoroutineBodyStmt(CoroutineBodyStmt::CtorArgs Args) {
}
ClassTemplateDecl *Sema::lookupCoroutineTraits(SourceLocation KwLoc,
SourceLocation FuncLoc,
NamespaceDecl *&Namespace) {
SourceLocation FuncLoc) {
if (!StdCoroutineTraitsCache) {
NamespaceDecl *CoroNamespace = getStdNamespace();
LookupResult Result(*this, &PP.getIdentifierTable().get("coroutine_traits"),
FuncLoc, LookupOrdinaryName);
if (!CoroNamespace || !LookupQualifiedName(Result, CoroNamespace)) {
/// TODO: lookup in std::expeirmental namespace for compability.
/// Remove this once users get familiar with coroutine under std
/// namespace.
CoroNamespace = lookupStdExperimentalNamespace();
if (!CoroNamespace || !LookupQualifiedName(Result, CoroNamespace)) {
if (auto StdExp = lookupStdExperimentalNamespace()) {
LookupResult Result(*this,
&PP.getIdentifierTable().get("coroutine_traits"),
FuncLoc, LookupOrdinaryName);
if (!LookupQualifiedName(Result, StdExp)) {
Diag(KwLoc, diag::err_implied_coroutine_type_not_found)
<< "std::coroutine_traits";
<< "std::experimental::coroutine_traits";
return nullptr;
}
if (!(StdCoroutineTraitsCache =
Result.getAsSingle<ClassTemplateDecl>())) {
Result.suppressDiagnostics();
NamedDecl *Found = *Result.begin();
Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits);
return nullptr;
}
Diag(KwLoc, diag::warn_coroutine_in_legacy_experimental_space);
}
if (!(StdCoroutineTraitsCache = Result.getAsSingle<ClassTemplateDecl>())) {
Result.suppressDiagnostics();
NamedDecl *Found = *Result.begin();
Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits);
return nullptr;
}
CoroTraitsNamespaceCache = CoroNamespace;
}
Namespace = CoroTraitsNamespaceCache;
return StdCoroutineTraitsCache;
}

View File

@ -3,6 +3,7 @@
#define STD_COROUTINE_H
namespace std {
namespace experimental {
template <typename R, typename...> struct coroutine_traits {
using promise_type = typename R::promise_type;
@ -66,6 +67,7 @@ struct suspend_never {
void await_resume() noexcept {}
};
} // namespace experimental
} // namespace std
#endif // STD_COROUTINE_H

View File

@ -2,7 +2,7 @@
#include "Inputs/std-coroutine.h"
using namespace std;
using namespace std::experimental;
struct Task {
struct promise_type {

View File

@ -11,7 +11,7 @@
#include "Inputs/std-coroutine.h"
using namespace std;
using namespace std::experimental;
struct A {
bool await_ready();

View File

@ -275,32 +275,32 @@ void new_default_ctor_with_default_arg(long count) {
#if CXX2A
// Boilerplate needed to test co_return:
namespace std {
template <typename Promise>
struct coroutine_handle {
static coroutine_handle from_address(void *) noexcept;
};
} // namespace std
namespace std::experimental {
template <typename Promise>
struct coroutine_handle {
static coroutine_handle from_address(void *) noexcept;
};
}
struct TestPromise {
TestPromise initial_suspend();
TestPromise final_suspend() noexcept;
bool await_ready() noexcept;
void await_suspend(const std::coroutine_handle<TestPromise> &) noexcept;
void await_suspend(const std::experimental::coroutine_handle<TestPromise> &) noexcept;
void await_resume() noexcept;
Foo return_value(const Bar &);
Bar get_return_object();
void unhandled_exception();
};
namespace std {
template <typename Ret, typename... Args>
struct coroutine_traits;
template <>
struct coroutine_traits<Bar> {
using promise_type = TestPromise;
};
} // namespace std
namespace std::experimental {
template <typename Ret, typename... Args>
struct coroutine_traits;
template <>
struct coroutine_traits<Bar> {
using promise_type = TestPromise;
};
}
Bar coreturn() {
co_return get_bar();

View File

@ -4,7 +4,7 @@
// llvm.coro.* intrinsics have not yet been ported.
// RUN: %clang_cc1 -fno-experimental-new-pass-manager -emit-obj -std=c++2a -fsanitize=null %s -o %t.o
namespace std {
namespace std::experimental {
template <typename R, typename... T> struct coroutine_traits {
using promise_type = typename R::promise_type;
};
@ -20,11 +20,11 @@ template <class Promise> struct coroutine_handle : coroutine_handle<void> {
coroutine_handle() = default;
static coroutine_handle from_address(void *) noexcept;
};
} // namespace std
}
struct suspend_always {
bool await_ready() noexcept;
void await_suspend(std::coroutine_handle<>) noexcept;
void await_suspend(std::experimental::coroutine_handle<>) noexcept;
void await_resume() noexcept;
};
@ -41,7 +41,7 @@ struct task {
struct awaitable {
task await() { (void)co_await *this; }
bool await_ready() { return false; }
bool await_suspend(std::coroutine_handle<> awaiter) { return false; }
bool await_suspend(std::experimental::coroutine_handle<> awaiter) { return false; }
bool await_resume() { return false; }
};

View File

@ -1,6 +1,6 @@
#pragma once
namespace std {
namespace std { namespace experimental { inline namespace coroutines_v1 {
template <typename R, typename...> struct coroutine_traits {
using promise_type = typename R::promise_type;
@ -77,4 +77,4 @@ struct suspend_never {
void await_resume() noexcept {}
};
} // namespace std
}}}

View File

@ -3,6 +3,7 @@
// RUN: | FileCheck %s
namespace std {
namespace experimental {
template <typename... T>
struct coroutine_traits; // expected-note {{declared here}}
@ -20,6 +21,8 @@ struct coroutine_handle<void> {
coroutine_handle(coroutine_handle<PromiseType>) noexcept {}
};
} // end namespace experimental
struct nothrow_t {};
constexpr nothrow_t nothrow = {};
@ -34,14 +37,14 @@ void operator delete(void* __p, const std::nothrow_t&) noexcept;
struct suspend_always {
bool await_ready() noexcept { return false; }
void await_suspend(std::coroutine_handle<>) noexcept {}
void await_suspend(std::experimental::coroutine_handle<>) noexcept {}
void await_resume() noexcept {}
};
struct global_new_delete_tag {};
template <>
struct std::coroutine_traits<void, global_new_delete_tag> {
template<>
struct std::experimental::coroutine_traits<void, global_new_delete_tag> {
struct promise_type {
void get_return_object() {}
suspend_always initial_suspend() { return {}; }
@ -80,8 +83,8 @@ extern "C" void f0(global_new_delete_tag) {
struct promise_new_tag {};
template <>
struct std::coroutine_traits<void, promise_new_tag> {
template<>
struct std::experimental::coroutine_traits<void, promise_new_tag> {
struct promise_type {
void *operator new(unsigned long);
void get_return_object() {}
@ -95,7 +98,7 @@ struct std::coroutine_traits<void, promise_new_tag> {
extern "C" void f1(promise_new_tag ) {
// CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
// CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
// CHECK: call i8* @_ZNSt16coroutine_traitsIJv15promise_new_tagEE12promise_typenwEm(i64 %[[SIZE]])
// CHECK: call i8* @_ZNSt12experimental16coroutine_traitsIJv15promise_new_tagEE12promise_typenwEm(i64 %[[SIZE]])
// CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin(
// CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]])
@ -105,8 +108,8 @@ extern "C" void f1(promise_new_tag ) {
struct promise_matching_placement_new_tag {};
template <>
struct std::coroutine_traits<void, promise_matching_placement_new_tag, int, float, double> {
template<>
struct std::experimental::coroutine_traits<void, promise_matching_placement_new_tag, int, float, double> {
struct promise_type {
void *operator new(unsigned long, promise_matching_placement_new_tag,
int, float, double);
@ -127,7 +130,7 @@ extern "C" void f1a(promise_matching_placement_new_tag, int x, float y , double
// CHECK: %[[INT:.+]] = load i32, i32* %x.addr, align 4
// CHECK: %[[FLOAT:.+]] = load float, float* %y.addr, align 4
// CHECK: %[[DOUBLE:.+]] = load double, double* %z.addr, align 8
// CHECK: call i8* @_ZNSt16coroutine_traitsIJv34promise_matching_placement_new_tagifdEE12promise_typenwEmS0_ifd(i64 %[[SIZE]], i32 %[[INT]], float %[[FLOAT]], double %[[DOUBLE]])
// CHECK: call i8* @_ZNSt12experimental16coroutine_traitsIJv34promise_matching_placement_new_tagifdEE12promise_typenwEmS1_ifd(i64 %[[SIZE]], i32 %[[INT]], float %[[FLOAT]], double %[[DOUBLE]])
co_return;
}
@ -137,8 +140,8 @@ void* operator new(SizeT __sz, void *__p) noexcept;
struct promise_matching_global_placement_new_tag {};
struct dummy {};
template <>
struct std::coroutine_traits<void, promise_matching_global_placement_new_tag, dummy *> {
template<>
struct std::experimental::coroutine_traits<void, promise_matching_global_placement_new_tag, dummy*> {
struct promise_type {
void get_return_object() {}
suspend_always initial_suspend() { return {}; }
@ -159,8 +162,8 @@ extern "C" void f1b(promise_matching_global_placement_new_tag, dummy *) {
struct promise_delete_tag {};
template <>
struct std::coroutine_traits<void, promise_delete_tag> {
template<>
struct std::experimental::coroutine_traits<void, promise_delete_tag> {
struct promise_type {
void operator delete(void*);
void get_return_object() {}
@ -178,14 +181,14 @@ extern "C" void f2(promise_delete_tag) {
// CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin(
// CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]])
// CHECK: call void @_ZNSt16coroutine_traitsIJv18promise_delete_tagEE12promise_typedlEPv(i8* %[[MEM]])
// CHECK: call void @_ZNSt12experimental16coroutine_traitsIJv18promise_delete_tagEE12promise_typedlEPv(i8* %[[MEM]])
co_return;
}
struct promise_sized_delete_tag {};
template <>
struct std::coroutine_traits<void, promise_sized_delete_tag> {
template<>
struct std::experimental::coroutine_traits<void, promise_sized_delete_tag> {
struct promise_type {
void operator delete(void*, unsigned long);
void get_return_object() {}
@ -204,14 +207,14 @@ extern "C" void f3(promise_sized_delete_tag) {
// CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin(
// CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]])
// CHECK: %[[SIZE2:.+]] = call i64 @llvm.coro.size.i64()
// CHECK: call void @_ZNSt16coroutine_traitsIJv24promise_sized_delete_tagEE12promise_typedlEPvm(i8* %[[MEM]], i64 %[[SIZE2]])
// CHECK: call void @_ZNSt12experimental16coroutine_traitsIJv24promise_sized_delete_tagEE12promise_typedlEPvm(i8* %[[MEM]], i64 %[[SIZE2]])
co_return;
}
struct promise_on_alloc_failure_tag {};
template <>
struct std::coroutine_traits<int, promise_on_alloc_failure_tag> {
template<>
struct std::experimental::coroutine_traits<int, promise_on_alloc_failure_tag> {
struct promise_type {
int get_return_object() { return 0; }
suspend_always initial_suspend() { return {}; }
@ -232,12 +235,12 @@ extern "C" int f4(promise_on_alloc_failure_tag) {
// CHECK: br i1 %[[OK]], label %[[OKBB:.+]], label %[[ERRBB:.+]]
// CHECK: [[ERRBB]]:
// CHECK: %[[FailRet:.+]] = call i32 @_ZNSt16coroutine_traitsIJi28promise_on_alloc_failure_tagEE12promise_type39get_return_object_on_allocation_failureEv(
// CHECK: %[[FailRet:.+]] = call i32 @_ZNSt12experimental16coroutine_traitsIJi28promise_on_alloc_failure_tagEE12promise_type39get_return_object_on_allocation_failureEv(
// CHECK: store i32 %[[FailRet]], i32* %[[RetVal]]
// CHECK: br label %[[RetBB:.+]]
// CHECK: [[OKBB]]:
// CHECK: %[[OkRet:.+]] = call i32 @_ZNSt16coroutine_traitsIJi28promise_on_alloc_failure_tagEE12promise_type17get_return_objectEv(
// CHECK: %[[OkRet:.+]] = call i32 @_ZNSt12experimental16coroutine_traitsIJi28promise_on_alloc_failure_tagEE12promise_type17get_return_objectEv(
// CHECK: store i32 %[[OkRet]], i32* %[[Gro]]
// CHECK: %[[Tmp1:.*]] = load i32, i32* %[[Gro]]

View File

@ -9,6 +9,7 @@
// RUN: -fno-inline -O0 %s -o - | FileCheck %s
namespace std {
namespace experimental {
struct handle {};
@ -34,17 +35,18 @@ struct coroutine_traits {
void unhandled_exception() {}
};
};
} // namespace experimental
} // namespace std
// CHECK-LABEL: @_Z3foov
// CHECK-LABEL: entry:
// CHECK: [[CAST0:%[0-9]+]] = bitcast %"struct.std::awaitable"* %ref.tmp{{.*}} to i8*
// CHECK: [[CAST0:%[0-9]+]] = bitcast %"struct.std::experimental::awaitable"* %ref.tmp{{.*}} to i8*
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[CAST0]])
// CHECK: [[CAST1:%[0-9]+]] = bitcast %"struct.std::awaitable"* %ref.tmp{{.*}} to i8*
// CHECK: [[CAST1:%[0-9]+]] = bitcast %"struct.std::experimental::awaitable"* %ref.tmp{{.*}} to i8*
// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[CAST1]])
// CHECK: [[CAST2:%[0-9]+]] = bitcast %"struct.std::awaitable"* %ref.tmp{{.*}} to i8*
// CHECK: [[CAST2:%[0-9]+]] = bitcast %"struct.std::experimental::awaitable"* %ref.tmp{{.*}} to i8*
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[CAST2]])
// CHECK: [[CAST3:%[0-9]+]] = bitcast %"struct.std::awaitable"* %ref.tmp{{.*}} to i8*
// CHECK: [[CAST3:%[0-9]+]] = bitcast %"struct.std::experimental::awaitable"* %ref.tmp{{.*}} to i8*
// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[CAST3]])
void foo() { co_return; }

View File

@ -1,7 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm %s -o - | FileCheck %s
#include "Inputs/coroutine.h"
using namespace std;
using namespace std::experimental;
struct coro {
struct promise_type {

View File

@ -10,9 +10,11 @@
#include "Inputs/coroutine.h"
namespace coro = std::experimental::coroutines_v1;
struct throwing_awaitable {
bool await_ready() { return true; }
void await_suspend(std::coroutine_handle<>) {}
void await_suspend(coro::coroutine_handle<>) {}
void await_resume() { throw 42; }
};
@ -20,7 +22,7 @@ struct throwing_task {
struct promise_type {
auto get_return_object() { return throwing_task{}; }
auto initial_suspend() { return throwing_awaitable{}; }
auto final_suspend() noexcept { return std::suspend_never{}; }
auto final_suspend() noexcept { return coro::suspend_never{}; }
void return_void() {}
void unhandled_exception() {}
};
@ -86,7 +88,7 @@ throwing_task f() {
struct noexcept_awaitable {
bool await_ready() { return true; }
void await_suspend(std::coroutine_handle<>) {}
void await_suspend(coro::coroutine_handle<>) {}
void await_resume() noexcept {}
};
@ -94,7 +96,7 @@ struct noexcept_task {
struct promise_type {
auto get_return_object() { return noexcept_task{}; }
auto initial_suspend() { return noexcept_awaitable{}; }
auto final_suspend() noexcept { return std::suspend_never{}; }
auto final_suspend() noexcept { return coro::suspend_never{}; }
void return_void() {}
void unhandled_exception() {}
};

View File

@ -2,6 +2,7 @@
// RUN: -emit-llvm %s -o - -disable-llvm-passes -Wno-coroutine -Wno-unused | FileCheck %s
namespace std {
namespace experimental {
template <typename... T>
struct coroutine_traits;
@ -19,28 +20,29 @@ struct coroutine_handle : coroutine_handle<> {
static coroutine_handle from_address(void *) noexcept;
};
}
}
struct init_susp {
bool await_ready();
void await_suspend(std::coroutine_handle<>);
void await_suspend(std::experimental::coroutine_handle<>);
void await_resume();
};
struct final_susp {
bool await_ready() noexcept;
void await_suspend(std::coroutine_handle<>) noexcept;
void await_suspend(std::experimental::coroutine_handle<>) noexcept;
void await_resume() noexcept;
};
struct suspend_always {
int stuff;
bool await_ready();
void await_suspend(std::coroutine_handle<>);
void await_suspend(std::experimental::coroutine_handle<>);
void await_resume();
};
template <>
struct std::coroutine_traits<void> {
template<>
struct std::experimental::coroutine_traits<void> {
struct promise_type {
void get_return_object();
init_susp initial_suspend();
@ -55,7 +57,7 @@ extern "C" void f0() {
// See if initial_suspend was issued:
// ----------------------------------
// CHECK: call void @_ZNSt16coroutine_traitsIJvEE12promise_type15initial_suspendEv(
// CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type15initial_suspendEv(
// CHECK-NEXT: call zeroext i1 @_ZN9init_susp11await_readyEv(%struct.init_susp*
// CHECK: %[[INITSP_ID:.+]] = call token @llvm.coro.save(
// CHECK: call i8 @llvm.coro.suspend(token %[[INITSP_ID]], i1 false)
@ -73,10 +75,10 @@ extern "C" void f0() {
// ---------------------------
// Build the coroutine handle and pass it to await_suspend
// ---------------------------
// CHECK: call i8* @_ZNSt16coroutine_handleINSt16coroutine_traitsIJvEE12promise_typeEE12from_addressEPv(i8* %[[FRAME]])
// CHECK: call i8* @_ZNSt12experimental16coroutine_handleINS_16coroutine_traitsIJvEE12promise_typeEE12from_addressEPv(i8* %[[FRAME]])
// ... many lines of code to coerce coroutine_handle into an i8* scalar
// CHECK: %[[CH:.+]] = load i8*, i8** %{{.+}}
// CHECK: call void @_ZN14suspend_always13await_suspendESt16coroutine_handleIvE(%struct.suspend_always* {{[^,]*}} %[[AWAITABLE]], i8* %[[CH]])
// CHECK: call void @_ZN14suspend_always13await_suspendENSt12experimental16coroutine_handleIvEE(%struct.suspend_always* {{[^,]*}} %[[AWAITABLE]], i8* %[[CH]])
// -------------------------
// Generate a suspend point:
// -------------------------
@ -97,7 +99,7 @@ extern "C" void f0() {
// See if final_suspend was issued:
// ----------------------------------
// CHECK: call void @_ZNSt16coroutine_traitsIJvEE12promise_type13final_suspendEv(
// CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type13final_suspendEv(
// CHECK-NEXT: call zeroext i1 @_ZN10final_susp11await_readyEv(%struct.final_susp*
// CHECK: %[[FINALSP_ID:.+]] = call token @llvm.coro.save(
// CHECK: call i8 @llvm.coro.suspend(token %[[FINALSP_ID]], i1 true)
@ -107,12 +109,13 @@ struct suspend_maybe {
float stuff;
~suspend_maybe();
bool await_ready();
bool await_suspend(std::coroutine_handle<>);
bool await_suspend(std::experimental::coroutine_handle<>);
void await_resume();
};
template <>
struct std::coroutine_traits<void, int> {
template<>
struct std::experimental::coroutine_traits<void,int> {
struct promise_type {
void get_return_object();
init_susp initial_suspend();
@ -124,10 +127,10 @@ struct std::coroutine_traits<void, int> {
// CHECK-LABEL: f1(
extern "C" void f1(int) {
// CHECK: %[[PROMISE:.+]] = alloca %"struct.std::coroutine_traits<void, int>::promise_type"
// CHECK: %[[PROMISE:.+]] = alloca %"struct.std::experimental::coroutine_traits<void, int>::promise_type"
// CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin(
co_yield 42;
// CHECK: call void @_ZNSt16coroutine_traitsIJviEE12promise_type11yield_valueEi(%struct.suspend_maybe* sret(%struct.suspend_maybe) align 4 %[[AWAITER:.+]], %"struct.std::coroutine_traits<void, int>::promise_type"* {{[^,]*}} %[[PROMISE]], i32 42)
// CHECK: call void @_ZNSt12experimental16coroutine_traitsIJviEE12promise_type11yield_valueEi(%struct.suspend_maybe* sret(%struct.suspend_maybe) align 4 %[[AWAITER:.+]], %"struct.std::experimental::coroutine_traits<void, int>::promise_type"* {{[^,]*}} %[[PROMISE]], i32 42)
// See if we need to suspend:
// --------------------------
@ -141,10 +144,10 @@ extern "C" void f1(int) {
// ---------------------------
// Build the coroutine handle and pass it to await_suspend
// ---------------------------
// CHECK: call i8* @_ZNSt16coroutine_handleINSt16coroutine_traitsIJviEE12promise_typeEE12from_addressEPv(i8* %[[FRAME]])
// CHECK: call i8* @_ZNSt12experimental16coroutine_handleINS_16coroutine_traitsIJviEE12promise_typeEE12from_addressEPv(i8* %[[FRAME]])
// ... many lines of code to coerce coroutine_handle into an i8* scalar
// CHECK: %[[CH:.+]] = load i8*, i8** %{{.+}}
// CHECK: %[[YES:.+]] = call zeroext i1 @_ZN13suspend_maybe13await_suspendESt16coroutine_handleIvE(%struct.suspend_maybe* {{[^,]*}} %[[AWAITABLE]], i8* %[[CH]])
// CHECK: %[[YES:.+]] = call zeroext i1 @_ZN13suspend_maybe13await_suspendENSt12experimental16coroutine_handleIvEE(%struct.suspend_maybe* {{[^,]*}} %[[AWAITABLE]], i8* %[[CH]])
// -------------------------------------------
// See if await_suspend decided not to suspend
// -------------------------------------------
@ -261,7 +264,7 @@ extern "C" void EndlessLoop() {
// See if initial_suspend was issued:
// ----------------------------------
// CHECK: call void @_ZNSt16coroutine_traitsIJvEE12promise_type15initial_suspendEv(
// CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type15initial_suspendEv(
// CHECK-NEXT: call zeroext i1 @_ZN9init_susp11await_readyEv(%struct.init_susp*
for (;;)
@ -269,7 +272,7 @@ extern "C" void EndlessLoop() {
// Verify that final_suspend was NOT issued:
// ----------------------------------
// CHECK-NOT: call void @_ZNSt16coroutine_traitsIJvEE12promise_type13final_suspendEv(
// CHECK-NOT: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type13final_suspendEv(
// CHECK-NOT: call zeroext i1 @_ZN10final_susp11await_readyEv(%struct.final_susp*
}
@ -284,12 +287,13 @@ struct RefTag { };
struct AwaitResumeReturnsLValue {
bool await_ready();
void await_suspend(std::coroutine_handle<>);
void await_suspend(std::experimental::coroutine_handle<>);
RefTag& await_resume();
};
template <>
struct std::coroutine_traits<void, double> {
template<>
struct std::experimental::coroutine_traits<void,double> {
struct promise_type {
void get_return_object();
init_susp initial_suspend();
@ -334,7 +338,7 @@ void AwaitReturnsLValue(double) {
struct TailCallAwait {
bool await_ready();
std::coroutine_handle<> await_suspend(std::coroutine_handle<>);
std::experimental::coroutine_handle<> await_suspend(std::experimental::coroutine_handle<>);
void await_resume();
};
@ -342,9 +346,9 @@ struct TailCallAwait {
extern "C" void TestTailcall() {
co_await TailCallAwait{};
// CHECK: %[[RESULT:.+]] = call i8* @_ZN13TailCallAwait13await_suspendESt16coroutine_handleIvE(%struct.TailCallAwait*
// CHECK: %[[COERCE:.+]] = getelementptr inbounds %"struct.std::coroutine_handle", %"struct.std::coroutine_handle"* %[[TMP:.+]], i32 0, i32 0
// CHECK: %[[RESULT:.+]] = call i8* @_ZN13TailCallAwait13await_suspendENSt12experimental16coroutine_handleIvEE(%struct.TailCallAwait*
// CHECK: %[[COERCE:.+]] = getelementptr inbounds %"struct.std::experimental::coroutine_handle", %"struct.std::experimental::coroutine_handle"* %[[TMP:.+]], i32 0, i32 0
// CHECK: store i8* %[[RESULT]], i8** %[[COERCE]]
// CHECK: %[[ADDR:.+]] = call i8* @_ZNSt16coroutine_handleIvE7addressEv(%"struct.std::coroutine_handle"* {{[^,]*}} %[[TMP]])
// CHECK: %[[ADDR:.+]] = call i8* @_ZNSt12experimental16coroutine_handleIvE7addressEv(%"struct.std::experimental::coroutine_handle"* {{[^,]*}} %[[TMP]])
// CHECK: call void @llvm.coro.resume(i8* %[[ADDR]])
}

View File

@ -1,7 +1,7 @@
// Verify that coroutine promise and allocated memory are freed up on exception.
// RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -fexceptions -fcxx-exceptions -disable-llvm-passes | FileCheck %s
namespace std {
namespace std::experimental {
template <typename... T> struct coroutine_traits;
template <class Promise = void> struct coroutine_handle {
@ -14,15 +14,15 @@ template <> struct coroutine_handle<void> {
template <class PromiseType>
coroutine_handle(coroutine_handle<PromiseType>) noexcept;
};
} // namespace std
}
struct suspend_always {
bool await_ready() noexcept;
void await_suspend(std::coroutine_handle<>) noexcept;
void await_suspend(std::experimental::coroutine_handle<>) noexcept;
void await_resume() noexcept;
};
template <> struct std::coroutine_traits<void> {
template <> struct std::experimental::coroutine_traits<void> {
struct promise_type {
void get_return_object() noexcept;
suspend_always initial_suspend() noexcept;
@ -43,7 +43,7 @@ void f() {
// If promise constructor throws, check that we free the memory.
// CHECK: invoke void @_ZNSt16coroutine_traitsIJvEE12promise_typeC1Ev(
// CHECK: invoke void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_typeC1Ev(
// CHECK-NEXT: to label %{{.+}} unwind label %[[DeallocPad:.+]]
// CHECK: [[DeallocPad]]:
@ -67,7 +67,7 @@ void f() {
// CHECK: [[Catch]]:
// CHECK: call i8* @__cxa_begin_catch(
// CHECK: call void @_ZNSt16coroutine_traitsIJvEE12promise_type19unhandled_exceptionEv(
// CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type19unhandled_exceptionEv(
// CHECK: invoke void @__cxa_end_catch()
// CHECK-NEXT: to label %[[Cont:.+]] unwind
@ -77,7 +77,7 @@ void f() {
// CHECK-NEXT: br label %[[Cleanup:.+]]
// CHECK: [[Cleanup]]:
// CHECK: call void @_ZNSt16coroutine_traitsIJvEE12promise_typeD1Ev(
// CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_typeD1Ev(
// CHECK: %[[Mem0:.+]] = call i8* @llvm.coro.free(
// CHECK: call void @_ZdlPv(i8* %[[Mem0]]
@ -93,5 +93,5 @@ void g() {
for (;;)
co_await suspend_always{};
// Since this is the endless loop there should be no fallthrough handler (call to 'return_void').
// CHECK-NOT: call void @_ZNSt16coroutine_traitsIJvEE12promise_type11return_voidEv
// CHECK-NOT: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type11return_voidEv
}

View File

@ -2,7 +2,7 @@
#include "Inputs/coroutine.h"
using namespace std;
using namespace std::experimental;
struct coro {
struct promise_type {
@ -30,7 +30,7 @@ extern "C" coro f(int) { co_return; }
// CHECK-NEXT: i8 1, label %[[FINAL_CLEANUP:.+]]
// CHECK-NEXT: ]
// CHECK: call void @_ZNSt13suspend_never12await_resumeEv(
// CHECK: call void @_ZNSt12experimental13coroutines_v113suspend_never12await_resumeEv(
// CHECK: %[[CLEANUP_DEST1:.+]] = phi i32 [ 0, %[[FINAL_READY]] ], [ 2, %[[FINAL_CLEANUP]] ]
// CHECK: %[[CLEANUP_DEST2:.+]] = phi i32 [ %[[CLEANUP_DEST0]], %{{.+}} ], [ %[[CLEANUP_DEST1]], %{{.+}} ], [ 0, %{{.+}} ]
// CHECK: call i8* @llvm.coro.free(

View File

@ -3,7 +3,7 @@
// RUN: -emit-llvm -o - %s | \
// RUN: FileCheck %s --implicit-check-not=DILocalVariable
namespace std {
namespace std::experimental {
template <typename... T> struct coroutine_traits;
template <class Promise = void> struct coroutine_handle {
@ -16,15 +16,15 @@ template <> struct coroutine_handle<void> {
template <class PromiseType>
coroutine_handle(coroutine_handle<PromiseType>) noexcept;
};
} // namespace std
} // namespace std::experimental
struct suspend_always {
bool await_ready() noexcept;
void await_suspend(std::coroutine_handle<>) noexcept;
void await_suspend(std::experimental::coroutine_handle<>) noexcept;
void await_resume() noexcept;
};
template <typename... Args> struct std::coroutine_traits<void, Args...> {
template <typename... Args> struct std::experimental::coroutine_traits<void, Args...> {
struct promise_type {
void get_return_object() noexcept;
suspend_always initial_suspend() noexcept;

View File

@ -1,7 +1,7 @@
// RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -triple=x86_64-pc-windows-msvc18.0.0 -emit-llvm %s -o - -fexceptions -fcxx-exceptions -disable-llvm-passes | FileCheck %s
// RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -fexceptions -fcxx-exceptions -disable-llvm-passes | FileCheck --check-prefix=CHECK-LPAD %s
namespace std {
namespace std::experimental {
template <typename R, typename... T> struct coroutine_traits {
using promise_type = typename R::promise_type;
};
@ -18,11 +18,11 @@ template <class Promise> struct coroutine_handle: coroutine_handle<void> {
coroutine_handle() = default;
static coroutine_handle from_address(void *) noexcept;
};
} // namespace std
}
struct suspend_always {
bool await_ready() noexcept;
void await_suspend(std::coroutine_handle<>) noexcept;
void await_suspend(std::experimental::coroutine_handle<>) noexcept;
void await_resume() noexcept;
};

View File

@ -2,7 +2,7 @@
#include "Inputs/coroutine.h"
using namespace std;
using namespace std::experimental;
namespace std {

View File

@ -2,7 +2,7 @@
// Verify that coroutine promise and allocated memory are freed up on exception.
// RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -disable-llvm-passes | FileCheck %s
namespace std {
namespace std::experimental {
template <typename... T> struct coroutine_traits;
template <class Promise = void> struct coroutine_handle {
@ -15,11 +15,11 @@ template <> struct coroutine_handle<void> {
template <class PromiseType>
coroutine_handle(coroutine_handle<PromiseType>) noexcept;
};
} // namespace std
}
struct suspend_always {
bool await_ready() noexcept;
void await_suspend(std::coroutine_handle<>) noexcept;
void await_suspend(std::experimental::coroutine_handle<>) noexcept;
void await_resume() noexcept;
};
@ -28,7 +28,7 @@ struct GroType {
operator int() noexcept;
};
template <> struct std::coroutine_traits<int> {
template <> struct std::experimental::coroutine_traits<int> {
struct promise_type {
GroType get_return_object() noexcept;
suspend_always initial_suspend() noexcept;
@ -51,8 +51,8 @@ int f() {
// CHECK: %[[Size:.+]] = call i64 @llvm.coro.size.i64()
// CHECK: call noalias nonnull i8* @_Znwm(i64 %[[Size]])
// CHECK: store i1 false, i1* %[[GroActive]]
// CHECK: call void @_ZNSt16coroutine_traitsIJiEE12promise_typeC1Ev(
// CHECK: call void @_ZNSt16coroutine_traitsIJiEE12promise_type17get_return_objectEv(
// CHECK: call void @_ZNSt12experimental16coroutine_traitsIJiEE12promise_typeC1Ev(
// CHECK: call void @_ZNSt12experimental16coroutine_traitsIJiEE12promise_type17get_return_objectEv(
// CHECK: store i1 true, i1* %[[GroActive]]
Cleanup cleanup;
@ -60,12 +60,12 @@ int f() {
co_return;
// CHECK: call void @_Z11doSomethingv(
// CHECK: call void @_ZNSt16coroutine_traitsIJiEE12promise_type11return_voidEv(
// CHECK: call void @_ZNSt12experimental16coroutine_traitsIJiEE12promise_type11return_voidEv(
// CHECK: call void @_ZN7CleanupD1Ev(
// Destroy promise and free the memory.
// CHECK: call void @_ZNSt16coroutine_traitsIJiEE12promise_typeD1Ev(
// CHECK: call void @_ZNSt12experimental16coroutine_traitsIJiEE12promise_typeD1Ev(
// CHECK: %[[Mem:.+]] = call i8* @llvm.coro.free(
// CHECK: call void @_ZdlPv(i8* %[[Mem]])

View File

@ -1,7 +1,7 @@
// Verify that we synthesized the coroutine for a lambda inside of a function template.
// RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -fexceptions -fcxx-exceptions -disable-llvm-passes | FileCheck %s
namespace std {
namespace std::experimental {
template <typename R, typename... T> struct coroutine_traits {
using promise_type = typename R::promise_type;
};
@ -17,11 +17,11 @@ template <class Promise> struct coroutine_handle : coroutine_handle<void> {
coroutine_handle() = default;
static coroutine_handle from_address(void *) noexcept;
};
} // namespace std
}
struct suspend_always {
bool await_ready() noexcept;
void await_suspend(std::coroutine_handle<>) noexcept;
void await_suspend(std::experimental::coroutine_handle<>) noexcept;
void await_resume() noexcept;
};

View File

@ -16,6 +16,7 @@
// CHECK-ALL: Running pass:{{.*}}CoroCleanupPass
namespace std {
namespace experimental {
struct handle {};
@ -38,6 +39,7 @@ template <typename T = void> struct coroutine_traits {
void unhandled_exception() {}
};
};
} // namespace experimental
} // namespace std
void foo() { co_return; }

View File

@ -4,7 +4,7 @@
// Verifies that parameter copies are used to construct the promise type, if that type has a matching constructor
// RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -disable-llvm-passes -fexceptions | FileCheck %s
namespace std {
namespace std::experimental {
template <typename... T> struct coroutine_traits;
template <class Promise = void> struct coroutine_handle {
@ -17,15 +17,15 @@ template <> struct coroutine_handle<void> {
template <class PromiseType>
coroutine_handle(coroutine_handle<PromiseType>) noexcept;
};
} // namespace std
}
struct suspend_always {
bool await_ready() noexcept;
void await_suspend(std::coroutine_handle<>) noexcept;
void await_suspend(std::experimental::coroutine_handle<>) noexcept;
void await_resume() noexcept;
};
template <typename... Args> struct std::coroutine_traits<void, Args...> {
template <typename... Args> struct std::experimental::coroutine_traits<void, Args...> {
struct promise_type {
void get_return_object() noexcept;
suspend_always initial_suspend() noexcept;
@ -73,9 +73,9 @@ void f(int val, MoveOnly moParam, MoveAndCopy mcParam) {
// CHECK-NEXT: bitcast %struct.MoveAndCopy* %[[McCopy]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(
// CHECK-NEXT: call void @_ZN11MoveAndCopyC1EOS_(%struct.MoveAndCopy* {{[^,]*}} %[[McCopy]], %struct.MoveAndCopy* nonnull align 4 dereferenceable(4) %[[McParam]]) #
// CHECK-NEXT: bitcast %"struct.std::coroutine_traits<void, int, MoveOnly, MoveAndCopy>::promise_type"* %__promise to i8*
// CHECK-NEXT: bitcast %"struct.std::experimental::coroutine_traits<void, int, MoveOnly, MoveAndCopy>::promise_type"* %__promise to i8*
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(
// CHECK-NEXT: invoke void @_ZNSt16coroutine_traitsIJvi8MoveOnly11MoveAndCopyEE12promise_typeC1Ev(
// CHECK-NEXT: invoke void @_ZNSt12experimental16coroutine_traitsIJvi8MoveOnly11MoveAndCopyEE12promise_typeC1Ev(
// CHECK: call void @_ZN14suspend_always12await_resumeEv(
// CHECK: %[[IntParam:.+]] = load i32, i32* %{{.*}}
@ -89,12 +89,12 @@ void f(int val, MoveOnly moParam, MoveAndCopy mcParam) {
co_return;
// Skip to final suspend:
// CHECK: call void @_ZNSt16coroutine_traitsIJvi8MoveOnly11MoveAndCopyEE12promise_type13final_suspendEv(
// CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvi8MoveOnly11MoveAndCopyEE12promise_type13final_suspendEv(
// CHECK: call void @_ZN14suspend_always12await_resumeEv(
// Destroy promise, then parameter copies:
// CHECK: call void @_ZNSt16coroutine_traitsIJvi8MoveOnly11MoveAndCopyEE12promise_typeD1Ev(%"struct.std::coroutine_traits<void, int, MoveOnly, MoveAndCopy>::promise_type"* {{[^,]*}} %__promise)
// CHECK-NEXT: bitcast %"struct.std::coroutine_traits<void, int, MoveOnly, MoveAndCopy>::promise_type"* %__promise to i8*
// CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvi8MoveOnly11MoveAndCopyEE12promise_typeD1Ev(%"struct.std::experimental::coroutine_traits<void, int, MoveOnly, MoveAndCopy>::promise_type"* {{[^,]*}} %__promise)
// CHECK-NEXT: bitcast %"struct.std::experimental::coroutine_traits<void, int, MoveOnly, MoveAndCopy>::promise_type"* %__promise to i8*
// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(
// CHECK-NEXT: call void @_ZN11MoveAndCopyD1Ev(%struct.MoveAndCopy* {{[^,]*}} %[[McCopy]])
// CHECK-NEXT: bitcast %struct.MoveAndCopy* %[[McCopy]] to i8*
@ -124,9 +124,9 @@ void dependent_params(T x, U, U y) {
// CHECK-NEXT: bitcast %struct.B* %[[y_copy]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(
// CHECK-NEXT: call void @_ZN1BC1EOS_(%struct.B* {{[^,]*}} %[[y_copy]], %struct.B* nonnull align 4 dereferenceable(512) %y)
// CHECK-NEXT: bitcast %"struct.std::coroutine_traits<void, A, B, B>::promise_type"* %__promise to i8*
// CHECK-NEXT: bitcast %"struct.std::experimental::coroutine_traits<void, A, B, B>::promise_type"* %__promise to i8*
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(
// CHECK-NEXT: invoke void @_ZNSt16coroutine_traitsIJv1A1BS1_EE12promise_typeC1Ev(
// CHECK-NEXT: invoke void @_ZNSt12experimental16coroutine_traitsIJv1A1BS2_EE12promise_typeC1Ev(
co_return;
}
@ -155,8 +155,8 @@ void call_dependent_params() {
struct promise_matching_constructor {};
template <>
struct std::coroutine_traits<void, promise_matching_constructor, int, float, double> {
template<>
struct std::experimental::coroutine_traits<void, promise_matching_constructor, int, float, double> {
struct promise_type {
promise_type(promise_matching_constructor, int, float, double) {}
promise_type() = delete;
@ -173,7 +173,7 @@ void coroutine_matching_promise_constructor(promise_matching_constructor, int, f
// CHECK: %[[INT:.+]] = load i32, i32* %5, align 4
// CHECK: %[[FLOAT:.+]] = load float, float* %6, align 4
// CHECK: %[[DOUBLE:.+]] = load double, double* %7, align 8
// CHECK: invoke void @_ZNSt16coroutine_traitsIJv28promise_matching_constructorifdEE12promise_typeC1ES0_ifd(%"struct.std::coroutine_traits<void, promise_matching_constructor, int, float, double>::promise_type"* {{[^,]*}} %__promise, i32 %[[INT]], float %[[FLOAT]], double %[[DOUBLE]])
// CHECK: invoke void @_ZNSt12experimental16coroutine_traitsIJv28promise_matching_constructorifdEE12promise_typeC1ES1_ifd(%"struct.std::experimental::coroutine_traits<void, promise_matching_constructor, int, float, double>::promise_type"* {{[^,]*}} %__promise, i32 %[[INT]], float %[[FLOAT]], double %[[DOUBLE]])
co_return;
}
@ -181,7 +181,7 @@ struct some_class;
struct method {};
template <typename... Args> struct std::coroutine_traits<method, Args...> {
template <typename... Args> struct std::experimental::coroutine_traits<method, Args...> {
struct promise_type {
promise_type(some_class&, float);
method get_return_object();
@ -198,6 +198,6 @@ struct some_class {
// CHECK-LABEL: define{{.*}} void @_ZN10some_class39good_coroutine_calls_custom_constructorEf(%struct.some_class*
method some_class::good_coroutine_calls_custom_constructor(float) {
// CHECK: invoke void @_ZNSt16coroutine_traitsIJ6methodR10some_classfEE12promise_typeC1ES2_f(%"struct.std::coroutine_traits<method, some_class &, float>::promise_type"* {{[^,]*}} %__promise, %struct.some_class* nonnull align 1 dereferenceable(1) %{{.+}}, float
// CHECK: invoke void @_ZNSt12experimental16coroutine_traitsIJ6methodR10some_classfEE12promise_typeC1ES3_f(%"struct.std::experimental::coroutine_traits<method, some_class &, float>::promise_type"* {{[^,]*}} %__promise, %struct.some_class* nonnull align 1 dereferenceable(1) %{{.+}}, float
co_return;
}

View File

@ -3,13 +3,15 @@
#include "Inputs/coroutine.h"
namespace coro = std::experimental::coroutines_v1;
struct coro_t {
void* p;
~coro_t();
struct promise_type {
coro_t get_return_object();
std::suspend_never initial_suspend();
std::suspend_never final_suspend() noexcept;
coro::suspend_never initial_suspend();
coro::suspend_never final_suspend() noexcept;
void return_void();
promise_type();
~promise_type();

View File

@ -2,21 +2,23 @@
#include "Inputs/coroutine.h"
namespace coro = std::experimental::coroutines_v1;
struct coro1 {
struct promise_type {
coro1 get_return_object();
std::suspend_never initial_suspend();
std::suspend_never final_suspend() noexcept;
coro::suspend_never initial_suspend();
coro::suspend_never final_suspend() noexcept;
void return_void();
};
};
coro1 f() {
co_await std::suspend_never{};
co_await coro::suspend_never{};
}
// CHECK-LABEL: define{{.*}} void @_Z1fv(
// CHECK: call void @_ZNSt13suspend_never12await_resumeEv(%"struct.std::suspend_never"*
// CHECK: call void @_ZNSt12experimental13coroutines_v113suspend_never12await_resumeEv(%"struct.std::experimental::coroutines_v1::suspend_never"*
// CHECK: call void @_ZN5coro112promise_type11return_voidEv(%"struct.coro1::promise_type"* {{[^,]*}} %__promise)
struct A {
@ -36,8 +38,8 @@ coro1 f2() {
struct coro2 {
struct promise_type {
coro2 get_return_object();
std::suspend_never initial_suspend();
std::suspend_never final_suspend() noexcept;
coro::suspend_never initial_suspend();
coro::suspend_never final_suspend() noexcept;
void return_value(int);
};
};
@ -47,5 +49,5 @@ coro2 g() {
}
// CHECK-LABEL: define{{.*}} void @_Z1gv(
// CHECK: call void @_ZNSt13suspend_never12await_resumeEv(%"struct.std::suspend_never"*
// CHECK: call void @_ZNSt12experimental13coroutines_v113suspend_never12await_resumeEv(%"struct.std::experimental::coroutines_v1::suspend_never"*
// CHECK: call void @_ZN5coro212promise_type12return_valueEi(%"struct.coro2::promise_type"* {{[^,]*}} %__promise, i32 42)

View File

@ -5,6 +5,7 @@ template <typename a>
struct b { b(int, a); };
template <typename, typename = int>
struct c {};
namespace experimental {
template <typename d>
struct coroutine_traits : d {};
template <typename = void>
@ -20,6 +21,7 @@ struct e {
void await_suspend(coroutine_handle<>);
void await_resume();
};
} // namespace experimental
} // namespace std
template <typename ag>
auto ah(ag) { return ag().ah(0); }
@ -29,10 +31,10 @@ struct g {
struct h {
int await_ready() noexcept;
template <typename al>
void await_suspend(std::coroutine_handle<al>) noexcept;
void await_suspend(std::experimental::coroutine_handle<al>) noexcept;
void await_resume() noexcept;
};
std::e initial_suspend();
std::experimental::e initial_suspend();
h final_suspend() noexcept;
template <typename ag>
auto await_transform(ag) { return ah(ag()); }
@ -43,20 +45,20 @@ struct j : g {
void unhandled_exception();
};
struct k {
k(std::coroutine_handle<>);
k(std::experimental::coroutine_handle<>);
int await_ready();
};
template <typename am>
struct f {
using promise_type = j;
std::coroutine_handle<> ar;
std::experimental::coroutine_handle<> ar;
struct l : k {
using at = k;
l(std::coroutine_handle<> m) : at(m) {}
void await_suspend(std::coroutine_handle<>);
l(std::experimental::coroutine_handle<> m) : at(m) {}
void await_suspend(std::experimental::coroutine_handle<>);
};
struct n : l {
n(std::coroutine_handle<> m) : l(m) {}
n(std::experimental::coroutine_handle<> m) : l(m) {}
am await_resume();
};
auto ah(int) { return n(ar); }

View File

@ -1,6 +1,6 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++1z -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
namespace std {
namespace std::experimental {
template <typename... T> struct coroutine_traits;
template <class Promise = void> struct coroutine_handle {
@ -13,15 +13,15 @@ template <> struct coroutine_handle<void> {
template <class PromiseType>
coroutine_handle(coroutine_handle<PromiseType>) noexcept {}
};
} // namespace std
}
struct suspend_always {
bool await_ready() noexcept;
void await_suspend(std::coroutine_handle<>) noexcept;
void await_suspend(std::experimental::coroutine_handle<>) noexcept;
void await_resume() noexcept;
};
template <> struct std::coroutine_traits<void> {
template <> struct std::experimental::coroutine_traits<void> {
struct promise_type {
void get_return_object();
suspend_always initial_suspend();
@ -32,15 +32,15 @@ template <> struct std::coroutine_traits<void> {
// CHECK-LABEL: f0(
extern "C" void f0() {
// CHECK: %__promise = alloca %"struct.std::coroutine_traits<void>::promise_type"
// CHECK: %__promise = alloca %"struct.std::experimental::coroutine_traits<void>::promise_type"
// CHECK: %call = call noalias nonnull i8* @_Znwm(
// CHECK: call void @_ZNSt16coroutine_traitsIJvEE12promise_type11return_voidEv(%"struct.std::coroutine_traits<void>::promise_type"* {{[^,]*}} %__promise)
// CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type11return_voidEv(%"struct.std::experimental::coroutine_traits<void>::promise_type"* {{[^,]*}} %__promise)
// CHECK: call void @_ZdlPv
co_return;
}
template <>
struct std::coroutine_traits<int> {
template<>
struct std::experimental::coroutine_traits<int> {
struct promise_type {
int get_return_object();
suspend_always initial_suspend();
@ -51,9 +51,9 @@ struct std::coroutine_traits<int> {
// CHECK-LABEL: f1(
extern "C" int f1() {
// CHECK: %__promise = alloca %"struct.std::coroutine_traits<int>::promise_type"
// CHECK: %__promise = alloca %"struct.std::experimental::coroutine_traits<int>::promise_type"
// CHECK: %call = call noalias nonnull i8* @_Znwm(
// CHECK: call void @_ZNSt16coroutine_traitsIJiEE12promise_type12return_valueEi(%"struct.std::coroutine_traits<int>::promise_type"* {{[^,]*}} %__promise, i32 42)
// CHECK: call void @_ZNSt12experimental16coroutine_traitsIJiEE12promise_type12return_valueEi(%"struct.std::experimental::coroutine_traits<int>::promise_type"* {{[^,]*}} %__promise, i32 42)
// CHECK: call void @_ZdlPv
co_return 42;
}

View File

@ -3,17 +3,19 @@
#include "Inputs/coroutine.h"
namespace coro = std::experimental::coroutines_v1;
struct detached_task {
struct promise_type {
detached_task get_return_object() noexcept {
return detached_task{std::coroutine_handle<promise_type>::from_promise(*this)};
return detached_task{coro::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 {
coro::coroutine_handle<> await_suspend(coro::coroutine_handle<promise_type> h) noexcept {
h.destroy();
return {};
}
@ -24,7 +26,7 @@ struct detached_task {
final_awaiter final_suspend() noexcept { return {}; }
std::suspend_always initial_suspend() noexcept { return {}; }
coro::suspend_always initial_suspend() noexcept { return {}; }
};
~detached_task() {
@ -40,7 +42,7 @@ struct detached_task {
tmp.resume();
}
std::coroutine_handle<promise_type> coro_;
coro::coroutine_handle<promise_type> coro_;
};
detached_task foo() {
@ -50,12 +52,12 @@ detached_task foo() {
// check that the lifetime of the coroutine handle used to obtain the address is contained within single basic block, and hence does not live across suspension points.
// CHECK-LABEL: final.suspend:
// CHECK: %{{.+}} = call token @llvm.coro.save(i8* null)
// CHECK: %[[HDL_CAST1:.+]] = bitcast %"struct.std::coroutine_handle.0"* %[[HDL:.+]] to i8*
// CHECK: %[[HDL_CAST1:.+]] = bitcast %"struct.std::experimental::coroutines_v1::coroutine_handle.0"* %[[HDL:.+]] to i8*
// CHECK: call void @llvm.lifetime.start.p0i8(i64 8, i8* %[[HDL_CAST1]])
// CHECK: %[[CALL:.+]] = call i8* @_ZN13detached_task12promise_type13final_awaiter13await_suspendESt16coroutine_handleIS0_E(
// CHECK: %[[HDL_CAST2:.+]] = getelementptr inbounds %"struct.std::coroutine_handle.0", %"struct.std::coroutine_handle.0"* %[[HDL]], i32 0, i32 0
// CHECK: %[[CALL:.+]] = call i8* @_ZN13detached_task12promise_type13final_awaiter13await_suspendENSt12experimental13coroutines_v116coroutine_handleIS0_EE(
// CHECK: %[[HDL_CAST2:.+]] = getelementptr inbounds %"struct.std::experimental::coroutines_v1::coroutine_handle.0", %"struct.std::experimental::coroutines_v1::coroutine_handle.0"* %[[HDL]], i32 0, i32 0
// CHECK: store i8* %[[CALL]], i8** %[[HDL_CAST2]], align 8
// CHECK: %[[HDL_TRANSFER:.+]] = call i8* @_ZNKSt16coroutine_handleIvE7addressEv(%"struct.std::coroutine_handle.0"* nonnull align 8 dereferenceable(8) %[[HDL]])
// CHECK: %[[HDL_CAST3:.+]] = bitcast %"struct.std::coroutine_handle.0"* %[[HDL]] to i8*
// CHECK: %[[HDL_TRANSFER:.+]] = call i8* @_ZNKSt12experimental13coroutines_v116coroutine_handleIvE7addressEv(%"struct.std::experimental::coroutines_v1::coroutine_handle.0"* nonnull align 8 dereferenceable(8) %[[HDL]])
// CHECK: %[[HDL_CAST3:.+]] = bitcast %"struct.std::experimental::coroutines_v1::coroutine_handle.0"* %[[HDL]] to i8*
// CHECK: call void @llvm.lifetime.end.p0i8(i64 8, i8* %[[HDL_CAST3]])
// CHECK: call void @llvm.coro.resume(i8* %[[HDL_TRANSFER]])

View File

@ -2,17 +2,19 @@
#include "Inputs/coroutine.h"
namespace coro = std::experimental::coroutines_v1;
struct Task {
struct promise_type {
Task get_return_object() noexcept {
return Task{std::coroutine_handle<promise_type>::from_promise(*this)};
return Task{coro::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 {
coro::coroutine_handle<> await_suspend(coro::coroutine_handle<promise_type> h) noexcept {
h.destroy();
return {};
}
@ -23,7 +25,7 @@ struct Task {
final_awaiter final_suspend() noexcept { return {}; }
std::suspend_always initial_suspend() noexcept { return {}; }
coro::suspend_always initial_suspend() noexcept { return {}; }
template <typename Awaitable>
auto await_transform(Awaitable &&awaitable) {
@ -31,7 +33,7 @@ struct Task {
}
};
using handle_t = std::coroutine_handle<promise_type>;
using handle_t = coro::coroutine_handle<promise_type>;
class Awaiter {
public:
@ -41,7 +43,7 @@ struct Task {
~Awaiter();
bool await_ready() noexcept { return false; }
handle_t await_suspend(std::coroutine_handle<> continuation) noexcept;
handle_t await_suspend(coro::coroutine_handle<> continuation) noexcept;
void await_resume();
private:
@ -89,10 +91,10 @@ Task bar() {
// 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: %[[HANDLE11:.+]] = bitcast %"struct.std::experimental::coroutines_v1::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: %[[HANDLE12:.+]] = bitcast %"struct.std::experimental::coroutines_v1::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
@ -108,10 +110,10 @@ Task bar() {
// 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: %[[HANDLE21:.+]] = bitcast %"struct.std::experimental::coroutines_v1::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: %[[HANDLE22:.+]] = bitcast %"struct.std::experimental::coroutines_v1::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

View File

@ -3,6 +3,8 @@
#include "Inputs/coroutine.h"
namespace coro = std::experimental::coroutines_v1;
namespace std {
using exception_ptr = int;
exception_ptr current_exception();
@ -11,11 +13,11 @@ namespace std {
struct coro_t {
struct promise_type {
coro_t get_return_object() {
std::coroutine_handle<promise_type>{};
coro::coroutine_handle<promise_type>{};
return {};
}
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
coro::suspend_never initial_suspend() { return {}; }
coro::suspend_never final_suspend() noexcept { return {}; }
void return_void(){}
void unhandled_exception() noexcept;
};
@ -48,9 +50,9 @@ coro_t f() {
// CHECK: [[TRYCONT]]:
// CHECK-NEXT: br label %[[COROFIN:.+]]
// CHECK: [[COROFIN]]:
// CHECK-NEXT: bitcast %"struct.std::suspend_never"* %{{.+}} to i8*
// CHECK-NEXT: bitcast %"struct.std::experimental::coroutines_v1::suspend_never"* %{{.+}} to i8*
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(
// CHECK-NEXT: call void @"?final_suspend@promise_type@coro_t@@QEAA?AUsuspend_never@std@@XZ"(
// CHECK-NEXT: call void @"?final_suspend@promise_type@coro_t@@QEAA?AUsuspend_never@coroutines_v1@experimental@std@@XZ"(
// CHECK-LPAD: @_Z1fv(
// CHECK-LPAD: invoke void @_Z9may_throwv()
@ -69,6 +71,6 @@ coro_t f() {
// CHECK-LPAD: [[TRYCONT]]:
// CHECK-LPAD: br label %[[COROFIN:.+]]
// CHECK-LPAD: [[COROFIN]]:
// CHECK-LPAD-NEXT: bitcast %"struct.std::suspend_never"* %{{.+}} to i8*
// CHECK-LPAD-NEXT: bitcast %"struct.std::experimental::coroutines_v1::suspend_never"* %{{.+}} to i8*
// CHECK-LPAD-NEXT: call void @llvm.lifetime.start.p0i8(
// CHECK-LPAD-NEXT: call void @_ZN6coro_t12promise_type13final_suspendEv(

View File

@ -1,6 +1,6 @@
// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping %s -o - | FileCheck %s
namespace std {
namespace std::experimental {
template <typename... T>
struct coroutine_traits;
@ -16,16 +16,16 @@ struct coroutine_handle<void> {
template <class PromiseType>
coroutine_handle(coroutine_handle<PromiseType>) noexcept {}
};
} // namespace std
} // namespace std::experimental
struct suspend_always {
bool await_ready() noexcept;
void await_suspend(std::coroutine_handle<>) noexcept;
void await_suspend(std::experimental::coroutine_handle<>) noexcept;
void await_resume() noexcept;
};
template <>
struct std::coroutine_traits<int, int> {
struct std::experimental::coroutine_traits<int, int> {
struct promise_type {
int get_return_object();
suspend_always initial_suspend();

View File

@ -1,8 +1,8 @@
// RUN: c-index-test -test-load-source all -c %s -fsyntax-only -target x86_64-apple-darwin9 -fcoroutines-ts -std=c++1z -I%S/../SemaCXX/Inputs | FileCheck %s
#include "std-coroutine.h"
using std::suspend_always;
using std::suspend_never;
using std::experimental::suspend_always;
using std::experimental::suspend_never;
struct promise_void {
void get_return_object();
@ -13,7 +13,7 @@ struct promise_void {
};
template <>
struct std::coroutine_traits<void> { using promise_type = promise_void; };
struct std::experimental::coroutine_traits<void> { using promise_type = promise_void; };
void CoroutineTestRet() {
co_return;

View File

@ -8,7 +8,7 @@
#ifndef HEADER
#define HEADER
namespace std {
namespace std::experimental {
template <typename... T> struct coroutine_traits;
template <class Promise = void> struct coroutine_handle {
@ -21,15 +21,15 @@ template <> struct coroutine_handle<void> {
template <class PromiseType>
coroutine_handle(coroutine_handle<PromiseType>) noexcept;
};
} // namespace std
}
struct suspend_always {
bool await_ready() noexcept;
void await_suspend(std::coroutine_handle<>) noexcept;
void await_suspend(std::experimental::coroutine_handle<>) noexcept;
void await_resume() noexcept;
};
template <typename... Args> struct std::coroutine_traits<void, Args...> {
template <typename... Args> struct std::experimental::coroutine_traits<void, Args...> {
struct promise_type {
void get_return_object() noexcept;
suspend_always initial_suspend() noexcept;
@ -42,7 +42,7 @@ template <typename... Args> struct std::coroutine_traits<void, Args...> {
};
};
template <typename... Args> struct std::coroutine_traits<int, Args...> {
template <typename... Args> struct std::experimental::coroutine_traits<int, Args...> {
struct promise_type {
int get_return_object() noexcept;
suspend_always initial_suspend() noexcept;

View File

@ -3,6 +3,7 @@
#define STD_COROUTINE_H
namespace std {
namespace experimental {
template <class Ret, typename... T>
struct coroutine_traits { using promise_type = typename Ret::promise_type; };
@ -30,6 +31,7 @@ struct suspend_never {
void await_resume() noexcept {}
};
} // namespace experimental
} // namespace std
#endif // STD_COROUTINE_H

View File

@ -3,7 +3,8 @@
// RUN: -fblocks
#include "Inputs/std-coroutine.h"
using namespace std;
using namespace std::experimental;
template <class Begin>
struct Awaiter {

View File

@ -3,12 +3,12 @@
#include "Inputs/std-coroutine.h"
using std::suspend_always;
using std::suspend_never;
using std::experimental::suspend_always;
using std::experimental::suspend_never;
struct awaitable {
bool await_ready();
void await_suspend(std::coroutine_handle<>); // FIXME: coroutine_handle
void await_suspend(std::experimental::coroutine_handle<>); // FIXME: coroutine_handle
void await_resume();
} a;
@ -33,7 +33,7 @@ struct VoidTagReturnValue {
};
template <typename T1>
struct std::coroutine_traits<void, T1> { using promise_type = promise_void_return_value; };
struct std::experimental::coroutine_traits<void, T1> { using promise_type = promise_void_return_value; };
VoidTagReturnValue test() {
object x = {};

View File

@ -1,12 +1,12 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++14 -fcoroutines-ts -fsyntax-only -Wignored-qualifiers -Wno-error=return-type -verify -fblocks -Wall -Wextra -Wno-error=unreachable-code
#include "Inputs/std-coroutine.h"
using std::suspend_always;
using std::suspend_never;
using std::experimental::suspend_always;
using std::experimental::suspend_never;
struct awaitable {
bool await_ready();
void await_suspend(std::coroutine_handle<>); // FIXME: coroutine_handle
void await_suspend(std::experimental::coroutine_handle<>); // FIXME: coroutine_handle
void await_resume();
} a;
@ -72,16 +72,16 @@ struct promise_int {
};
template <>
struct std::coroutine_traits<void> { using promise_type = promise_void; };
struct std::experimental::coroutine_traits<void> { using promise_type = promise_void; };
template <typename T1>
struct std::coroutine_traits<void, T1> { using promise_type = promise_void_return_value; };
struct std::experimental::coroutine_traits<void, T1> { using promise_type = promise_void_return_value; };
template <typename... T>
struct std::coroutine_traits<float, T...> { using promise_type = promise_float; };
struct std::experimental::coroutine_traits<float, T...> { using promise_type = promise_float; };
template <typename... T>
struct std::coroutine_traits<int, T...> { using promise_type = promise_int; };
struct std::experimental::coroutine_traits<int, T...> { using promise_type = promise_int; };
void test0() { co_await a; }
float test1() { co_await a; }

View File

@ -4,6 +4,7 @@
// RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -verify %s -fcxx-exceptions -fexceptions -Wunused-result
namespace std {
namespace experimental {
template <class Ret, typename... T>
struct coroutine_traits { using promise_type = typename Ret::promise_type; };
@ -33,9 +34,10 @@ struct suspend_always {
~suspend_always() noexcept(false); // expected-note 2 {{must be declared with 'noexcept'}}
};
} // namespace experimental
} // namespace std
using namespace std;
using namespace std::experimental;
struct A {
bool await_ready();

View File

@ -1,6 +1,6 @@
// RUN: %clang_cc1 -verify -std=c++17 -fcoroutines-ts -fsyntax-only %s
namespace std {
namespace std::experimental {
template <class Promise = void> struct coroutine_handle {
coroutine_handle() = default;
static coroutine_handle from_address(void *) noexcept;
@ -30,11 +30,11 @@ struct traits_sfinae_base<T, void_t<typename T::promise_type>> {
template <class Ret, class... Args>
struct coroutine_traits : public traits_sfinae_base<Ret> {};
} // namespace std
}
struct suspend_never {
bool await_ready() noexcept;
void await_suspend(std::coroutine_handle<>) noexcept;
void await_suspend(std::experimental::coroutine_handle<>) noexcept;
void await_resume() noexcept;
};

View File

@ -1,5 +1,5 @@
// RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -verify %s -fcxx-exceptions -fexceptions -triple x86_64-windows-msvc -fms-extensions
namespace std {
namespace std::experimental {
template <typename... T> struct coroutine_traits;
template <class Promise = void> struct coroutine_handle {
@ -12,15 +12,15 @@ template <> struct coroutine_handle<void> {
template <class PromiseType>
coroutine_handle(coroutine_handle<PromiseType>) noexcept;
};
} // namespace std
}
struct suspend_always {
bool await_ready() noexcept;
void await_suspend(std::coroutine_handle<>) noexcept;
void await_suspend(std::experimental::coroutine_handle<>) noexcept;
void await_resume() noexcept;
};
template <> struct std::coroutine_traits<void> {
template <> struct std::experimental::coroutine_traits<void> {
struct promise_type {
void get_return_object() noexcept;
suspend_always initial_suspend() noexcept;

View File

@ -4,14 +4,15 @@
// RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -verify %s -fcxx-exceptions -fexceptions -Wunused-result
namespace std {
namespace experimental {
template<typename ...T>
struct coroutine_traits {
struct promise_type {};
};
template <> struct coroutine_traits<void>; // expected-note {{forward declaration of 'std::coroutine_traits<void>'}}
} // namespace std
template<> struct coroutine_traits<void>; // expected-note {{forward declaration of 'std::experimental::coroutine_traits<void>'}}
}} // namespace std::experimental
void uses_forward_declaration() {
co_return; // expected-error {{this function cannot be a coroutine: missing definition of specialization 'coroutine_traits<void>'}}

View File

@ -13,8 +13,8 @@
#include "Inputs/std-coroutine.h"
using std::suspend_always;
using std::suspend_never;
using std::experimental::suspend_always;
using std::experimental::suspend_never;
#ifndef DISABLE_WARNING
struct promise_void { // expected-note {{defined here}}
@ -28,7 +28,7 @@ struct promise_void {
};
template <typename... T>
struct std::coroutine_traits<void, T...> { using promise_type = promise_void; };
struct std::experimental::coroutine_traits<void, T...> { using promise_type = promise_void; };
#ifndef DISABLE_WARNING
void test0() { // expected-warning {{'promise_void' is required to declare the member 'unhandled_exception()' when exceptions are enabled}}

View File

@ -1,7 +1,8 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++14 -fcoroutines-ts -fsyntax-only -Wall -Wextra -Wuninitialized -fblocks
#include "Inputs/std-coroutine.h"
using namespace std;
using namespace std::experimental;
struct A {
bool await_ready() { return true; }

View File

@ -1,6 +1,6 @@
// RUN: %clang_cc1 -verify %s -stdlib=libc++ -std=c++1z -fcoroutines-ts -fsyntax-only
namespace std {
namespace std::experimental {
template <class Promise = void>
struct coroutine_handle;
@ -32,11 +32,11 @@ struct traits_sfinae_base<T, void_t<typename T::promise_type>> {
template <class Ret, class... Args>
struct coroutine_traits : public traits_sfinae_base<Ret> {};
} // namespace std
} // namespace std::experimental
struct suspend_never {
bool await_ready() noexcept;
void await_suspend(std::coroutine_handle<>) noexcept;
void await_suspend(std::experimental::coroutine_handle<>) noexcept;
void await_resume() noexcept;
};
@ -50,18 +50,18 @@ struct task {
};
};
namespace std {
namespace std::experimental {
template <>
struct coroutine_handle<task::promise_type> : public coroutine_handle<> {
coroutine_handle<task::promise_type> *address() const; // expected-warning {{return type of 'coroutine_handle<>::address should be 'void*'}}
};
} // namespace std
} // namespace std::experimental
struct awaitable {
bool await_ready();
std::coroutine_handle<task::promise_type>
await_suspend(std::coroutine_handle<> handle);
std::experimental::coroutine_handle<task::promise_type>
await_suspend(std::experimental::coroutine_handle<> handle);
void await_resume();
} a;

File diff suppressed because it is too large Load Diff

View File

@ -6,26 +6,27 @@
// RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -fsyntax-only -verify=expected,cxx14_20 %s -fcxx-exceptions -fexceptions -Wunused-result
void no_coroutine_traits_bad_arg_await() {
co_await a; // expected-error {{include <coroutine>}}
co_await a; // expected-error {{include <experimental/coroutine>}}
// expected-error@-1 {{use of undeclared identifier 'a'}}
}
void no_coroutine_traits_bad_arg_yield() {
co_yield a; // expected-error {{include <coroutine>}}
co_yield a; // expected-error {{include <experimental/coroutine>}}
// expected-error@-1 {{use of undeclared identifier 'a'}}
}
void no_coroutine_traits_bad_arg_return() {
co_return a; // expected-error {{include <coroutine>}}
co_return a; // expected-error {{include <experimental/coroutine>}}
// expected-error@-1 {{use of undeclared identifier 'a'}}
}
void no_coroutine_traits() {
co_await 4; // expected-error {{std::coroutine_traits type was not found; include <coroutine>}}
co_await 4; // expected-error {{std::experimental::coroutine_traits type was not found; include <experimental/coroutine>}}
}
namespace std {
namespace experimental {
template <class... Args>
struct void_t_imp {
@ -44,11 +45,11 @@ struct traits_sfinae_base<T, void_t<typename T::promise_type>> {
template <class Ret, class... Args>
struct coroutine_traits : public traits_sfinae_base<Ret> {};
} // end of namespace std
}} // namespace std::experimental
template<typename Promise> struct coro {};
template <typename Promise, typename... Ps>
struct std::coroutine_traits<coro<Promise>, Ps...> {
struct std::experimental::coroutine_traits<coro<Promise>, Ps...> {
using promise_type = Promise;
};
@ -80,46 +81,47 @@ struct auto_await_suspend {
};
struct DummyVoidTag {};
DummyVoidTag no_specialization() { // expected-error {{this function cannot be a coroutine: 'std::coroutine_traits<DummyVoidTag>' has no member named 'promise_type'}}
DummyVoidTag no_specialization() { // expected-error {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<DummyVoidTag>' has no member named 'promise_type'}}
co_await a;
}
template <typename... T>
struct std::coroutine_traits<int, T...> {};
struct std::experimental::coroutine_traits<int, T...> {};
int no_promise_type() { // expected-error {{this function cannot be a coroutine: 'std::coroutine_traits<int>' has no member named 'promise_type'}}
int no_promise_type() { // expected-error {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<int>' has no member named 'promise_type'}}
co_await a;
}
int no_promise_type_multiple_awaits(int) { // expected-error {{this function cannot be a coroutine: 'std::coroutine_traits<int, int>' has no member named 'promise_type'}}
int no_promise_type_multiple_awaits(int) { // expected-error {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<int, int>' has no member named 'promise_type'}}
co_await a;
co_await a;
}
template <>
struct std::coroutine_traits<double, double> { typedef int promise_type; };
double bad_promise_type(double) { // expected-error {{this function cannot be a coroutine: 'std::coroutine_traits<double, double>::promise_type' (aka 'int') is not a class}}
struct std::experimental::coroutine_traits<double, double> { typedef int promise_type; };
double bad_promise_type(double) { // expected-error {{this function cannot be a coroutine: 'experimental::coroutine_traits<double, double>::promise_type' (aka 'int') is not a class}}
co_await a;
}
template <>
struct std::coroutine_traits<double, int> {
struct std::experimental::coroutine_traits<double, int> {
struct promise_type {};
};
double bad_promise_type_2(int) { // expected-error {{no member named 'initial_suspend'}}
co_yield 0; // expected-error {{no member named 'yield_value' in 'std::coroutine_traits<double, int>::promise_type'}}
co_yield 0; // expected-error {{no member named 'yield_value' in 'std::experimental::coroutine_traits<double, int>::promise_type'}}
}
struct promise; // expected-note {{forward declaration}}
struct promise_void;
struct void_tag {};
template <typename... T>
struct std::coroutine_traits<void, T...> { using promise_type = promise; };
struct std::experimental::coroutine_traits<void, T...> { using promise_type = promise; };
template <typename... T>
struct std::coroutine_traits<void, void_tag, T...> { using promise_type = promise_void; };
struct std::experimental::coroutine_traits<void, void_tag, T...>
{ using promise_type = promise_void; };
// FIXME: This diagnostic is terrible.
void undefined_promise() { // expected-error {{this function cannot be a coroutine: 'std::coroutine_traits<void>::promise_type' (aka 'promise') is an incomplete type}}
void undefined_promise() { // expected-error {{this function cannot be a coroutine: 'experimental::coroutine_traits<void>::promise_type' (aka 'promise') is an incomplete type}}
co_await a;
}
@ -146,12 +148,13 @@ struct promise_void {
void unhandled_exception();
};
void no_coroutine_handle() { // expected-error {{std::coroutine_handle type was not found; include <coroutine> before defining a coroutine}}
void no_coroutine_handle() { // expected-error {{std::experimental::coroutine_handle type was not found; include <experimental/coroutine> before defining a coroutine}}
//expected-note@-1 {{call to 'initial_suspend' implicitly required by the initial suspend point}}
co_return 5; //expected-note {{function is a coroutine due to use of 'co_return' here}}
}
namespace std {
namespace experimental {
template <class PromiseType = void>
struct coroutine_handle {
static coroutine_handle from_address(void *) noexcept;
@ -162,7 +165,7 @@ struct coroutine_handle<void> {
coroutine_handle(coroutine_handle<PromiseType>) noexcept;
static coroutine_handle from_address(void *) noexcept;
};
} // namespace std
}} // namespace std::experimental
void yield() {
co_yield 0;
@ -526,7 +529,7 @@ namespace dependent_operator_co_await_lookup {
struct yield_fn_tag {};
template <>
struct std::coroutine_traits<void, yield_fn_tag> {
struct std::experimental::coroutine_traits<void, yield_fn_tag> {
struct promise_type {
// FIXME: add an await_transform overload for functions
awaitable yield_value(int());
@ -744,7 +747,8 @@ template<typename T> void ok_generic_lambda_coawait_PR41909() {
}
template void ok_generic_lambda_coawait_PR41909<int>(); // expected-note {{in instantiation of function template specialization 'ok_generic_lambda_coawait_PR41909<int>' requested here}}
template <> struct std::coroutine_traits<int, int, const char **> { using promise_type = promise; };
template<> struct std::experimental::coroutine_traits<int, int, const char**>
{ using promise_type = promise; };
int main(int, const char**) {
co_await a; // expected-error {{'co_await' cannot be used in the 'main' function}}
@ -757,11 +761,12 @@ struct good_promise_2 {
void return_void();
void unhandled_exception();
};
template <> struct std::coroutine_handle<good_promise_2> {};
template<> struct std::experimental::coroutine_handle<good_promise_2> {};
template <> struct std::coroutine_traits<float> { using promise_type = good_promise_2; };
template<> struct std::experimental::coroutine_traits<float>
{ using promise_type = good_promise_2; };
float badly_specialized_coro_handle() { // expected-error {{std::coroutine_handle missing a member named 'from_address'}}
float badly_specialized_coro_handle() { // expected-error {{std::experimental::coroutine_handle missing a member named 'from_address'}}
//expected-note@-1 {{call to 'initial_suspend' implicitly required by the initial suspend point}}
co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}}
}
@ -780,8 +785,8 @@ void operator delete(void* __p, const std::nothrow_t&) noexcept;
struct promise_on_alloc_failure_tag {};
template <>
struct std::coroutine_traits<int, promise_on_alloc_failure_tag> {
template<>
struct std::experimental::coroutine_traits<int, promise_on_alloc_failure_tag> {
struct promise_type {
int get_return_object() {}
suspend_always initial_suspend() { return {}; }
@ -900,8 +905,8 @@ good_coroutine_calls_noexcept_custom_new_operator(double, float, int) {
}
struct mismatch_gro_type_tag1 {};
template <>
struct std::coroutine_traits<int, mismatch_gro_type_tag1> {
template<>
struct std::experimental::coroutine_traits<int, mismatch_gro_type_tag1> {
struct promise_type {
void get_return_object() {} //expected-note {{member 'get_return_object' declared here}}
suspend_always initial_suspend() { return {}; }
@ -917,8 +922,8 @@ extern "C" int f(mismatch_gro_type_tag1) {
}
struct mismatch_gro_type_tag2 {};
template <>
struct std::coroutine_traits<int, mismatch_gro_type_tag2> {
template<>
struct std::experimental::coroutine_traits<int, mismatch_gro_type_tag2> {
struct promise_type {
void *get_return_object() {} //expected-note {{member 'get_return_object' declared here}}
suspend_always initial_suspend() { return {}; }
@ -935,8 +940,8 @@ extern "C" int f(mismatch_gro_type_tag2) {
}
struct mismatch_gro_type_tag3 {};
template <>
struct std::coroutine_traits<int, mismatch_gro_type_tag3> {
template<>
struct std::experimental::coroutine_traits<int, mismatch_gro_type_tag3> {
struct promise_type {
int get_return_object() {}
static void get_return_object_on_allocation_failure() {} //expected-note {{member 'get_return_object_on_allocation_failure' declared here}}
@ -954,8 +959,8 @@ extern "C" int f(mismatch_gro_type_tag3) {
struct mismatch_gro_type_tag4 {};
template <>
struct std::coroutine_traits<int, mismatch_gro_type_tag4> {
template<>
struct std::experimental::coroutine_traits<int, mismatch_gro_type_tag4> {
struct promise_type {
int get_return_object() {}
static char *get_return_object_on_allocation_failure() {} //expected-note {{member 'get_return_object_on_allocation_failure' declared}}
@ -987,13 +992,13 @@ coro<bad_promise_no_return_func> no_return_value_or_return_void() {
struct bad_await_suspend_return {
bool await_ready();
// expected-error@+1 {{return type of 'await_suspend' is required to be 'void' or 'bool' (have 'char')}}
char await_suspend(std::coroutine_handle<>);
char await_suspend(std::experimental::coroutine_handle<>);
void await_resume();
};
struct bad_await_ready_return {
// expected-note@+1 {{return type of 'await_ready' is required to be contextually convertible to 'bool'}}
void await_ready();
bool await_suspend(std::coroutine_handle<>);
bool await_suspend(std::experimental::coroutine_handle<>);
void await_resume();
};
struct await_ready_explicit_bool {
@ -1001,7 +1006,7 @@ struct await_ready_explicit_bool {
explicit operator bool() const;
};
BoolT await_ready();
void await_suspend(std::coroutine_handle<>);
void await_suspend(std::experimental::coroutine_handle<>);
void await_resume();
};
template <class SuspendTy>
@ -1009,7 +1014,7 @@ struct await_suspend_type_test {
bool await_ready();
// expected-error@+2 {{return type of 'await_suspend' is required to be 'void' or 'bool' (have 'bool &')}}
// expected-error@+1 {{return type of 'await_suspend' is required to be 'void' or 'bool' (have 'bool &&')}}
SuspendTy await_suspend(std::coroutine_handle<>);
SuspendTy await_suspend(std::experimental::coroutine_handle<>);
// cxx20_2b-warning@-1 {{volatile-qualified return type 'const volatile bool' is deprecated}}
void await_resume();
};
@ -1069,7 +1074,7 @@ struct TypeTest {
template <class... Args>
static constexpr bool MatchesArgs = IsSameV<T,
std::coroutine_traits<CoroMemberTag, Args...>>;
std::experimental::coroutine_traits<CoroMemberTag, Args...>>;
};
template <class T>
@ -1081,7 +1086,7 @@ struct AwaitReturnsType {
template <class... CoroTraitsArgs>
struct CoroMemberPromise {
using TraitsT = std::coroutine_traits<CoroTraitsArgs...>;
using TraitsT = std::experimental::coroutine_traits<CoroTraitsArgs...>;
using TypeTestT = TypeTest<TraitsT>;
using AwaitTestT = AwaitReturnsType<TypeTestT>;
@ -1098,7 +1103,7 @@ struct CoroMemberPromise {
} // namespace CoroHandleMemberFunctionTest
template <class... Args>
struct ::std::coroutine_traits<CoroHandleMemberFunctionTest::CoroMemberTag, Args...> {
struct ::std::experimental::coroutine_traits<CoroHandleMemberFunctionTest::CoroMemberTag, Args...> {
using promise_type = CoroHandleMemberFunctionTest::CoroMemberPromise<CoroHandleMemberFunctionTest::CoroMemberTag, Args...>;
};
@ -1184,16 +1189,16 @@ struct TestType {
}
BadCoroMemberTag test_diagnostics() {
// expected-error@-1 {{this function cannot be a coroutine: 'std::coroutine_traits<CoroHandleMemberFunctionTest::BadCoroMemberTag, CoroHandleMemberFunctionTest::TestType &>' has no member named 'promise_type'}}
// expected-error@-1 {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<CoroHandleMemberFunctionTest::BadCoroMemberTag, CoroHandleMemberFunctionTest::TestType &>' has no member named 'promise_type'}}
co_return;
}
BadCoroMemberTag test_diagnostics(int) const && {
// expected-error@-1 {{this function cannot be a coroutine: 'std::coroutine_traits<CoroHandleMemberFunctionTest::BadCoroMemberTag, const CoroHandleMemberFunctionTest::TestType &&, int>' has no member named 'promise_type'}}
// expected-error@-1 {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<CoroHandleMemberFunctionTest::BadCoroMemberTag, const CoroHandleMemberFunctionTest::TestType &&, int>' has no member named 'promise_type'}}
co_return;
}
static BadCoroMemberTag test_static_diagnostics(long *) {
// expected-error@-1 {{this function cannot be a coroutine: 'std::coroutine_traits<CoroHandleMemberFunctionTest::BadCoroMemberTag, long *>' has no member named 'promise_type'}}
// expected-error@-1 {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<CoroHandleMemberFunctionTest::BadCoroMemberTag, long *>' has no member named 'promise_type'}}
co_return;
}
};
@ -1305,7 +1310,7 @@ struct bad_promise_deleted_constructor {
coro<bad_promise_deleted_constructor>
bad_coroutine_calls_deleted_promise_constructor() {
// expected-error@-1 {{call to deleted constructor of 'std::coroutine_traits<coro<CoroHandleMemberFunctionTest::bad_promise_deleted_constructor>>::promise_type' (aka 'CoroHandleMemberFunctionTest::bad_promise_deleted_constructor')}}
// expected-error@-1 {{call to deleted constructor of 'std::experimental::coroutine_traits<coro<CoroHandleMemberFunctionTest::bad_promise_deleted_constructor>>::promise_type' (aka 'CoroHandleMemberFunctionTest::bad_promise_deleted_constructor')}}
co_return;
}
@ -1372,7 +1377,7 @@ struct bad_promise_no_matching_constructor {
coro<bad_promise_no_matching_constructor>
bad_coroutine_calls_with_no_matching_constructor(int, int) {
// expected-error@-1 {{call to deleted constructor of 'std::coroutine_traits<coro<CoroHandleMemberFunctionTest::bad_promise_no_matching_constructor>, int, int>::promise_type' (aka 'CoroHandleMemberFunctionTest::bad_promise_no_matching_constructor')}}
// expected-error@-1 {{call to deleted constructor of 'std::experimental::coroutine_traits<coro<CoroHandleMemberFunctionTest::bad_promise_no_matching_constructor>, int, int>::promise_type' (aka 'CoroHandleMemberFunctionTest::bad_promise_no_matching_constructor')}}
co_return;
}
@ -1388,7 +1393,7 @@ bad_coroutine_calls_with_no_matching_constructor(int, int, int) {
class awaitable_no_unused_warn {
public:
using handle_type = std::coroutine_handle<>;
using handle_type = std::experimental::coroutine_handle<>;
constexpr bool await_ready() noexcept { return false; }
void await_suspend(handle_type) noexcept {}
int await_resume() noexcept { return 1; }
@ -1397,7 +1402,7 @@ public:
class awaitable_unused_warn {
public:
using handle_type = std::coroutine_handle<>;
using handle_type = std::experimental::coroutine_handle<>;
constexpr bool await_ready() noexcept { return false; }
void await_suspend(handle_type) noexcept {}
[[nodiscard]] int await_resume() noexcept { return 1; }
@ -1427,7 +1432,7 @@ test_unused_warning() {
}
struct missing_await_ready {
void await_suspend(std::coroutine_handle<>);
void await_suspend(std::experimental::coroutine_handle<>);
void await_resume();
};
struct missing_await_suspend {
@ -1436,7 +1441,7 @@ struct missing_await_suspend {
};
struct missing_await_resume {
bool await_ready();
void await_suspend(std::coroutine_handle<>);
void await_suspend(std::experimental::coroutine_handle<>);
};
void test_missing_awaitable_members() {

View File

@ -623,6 +623,7 @@ TEST(Matcher, MatchesCoroutine) {
FileContentMappings M;
M.push_back(std::make_pair("/coro_header", R"cpp(
namespace std {
namespace experimental {
template <class... Args>
struct void_t_imp {
@ -641,7 +642,7 @@ struct traits_sfinae_base<T, void_t<typename T::promise_type>> {
template <class Ret, class... Args>
struct coroutine_traits : public traits_sfinae_base<Ret> {};
} // namespace std
}} // namespace std::experimental
struct awaitable {
bool await_ready() noexcept;
template <typename F>
@ -657,13 +658,14 @@ struct promise {
void unhandled_exception();
};
template <typename... T>
struct std::coroutine_traits<void, T...> { using promise_type = promise; };
struct std::experimental::coroutine_traits<void, T...> { using promise_type = promise; };
namespace std {
namespace experimental {
template <class PromiseType = void>
struct coroutine_handle {
static coroutine_handle from_address(void *) noexcept;
};
} // namespace std
}} // namespace std::experimental
)cpp"));
StringRef CoReturnCode = R"cpp(
#include <coro_header>