diff --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/readability-identifier-naming/system/coroutines.h b/clang-tools-extra/test/clang-tidy/checkers/Inputs/readability-identifier-naming/system/coroutines.h --- a/clang-tools-extra/test/clang-tidy/checkers/Inputs/readability-identifier-naming/system/coroutines.h +++ b/clang-tools-extra/test/clang-tidy/checkers/Inputs/readability-identifier-naming/system/coroutines.h @@ -1,6 +1,7 @@ #pragma once namespace std { +namespace experimental { template struct coroutine_traits { @@ -12,6 +13,7 @@ static constexpr coroutine_handle from_address(void *addr) noexcept { return {}; }; }; +} // namespace experimental } // namespace std struct never_suspend { diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -2872,7 +2872,7 @@ 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**: diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10957,20 +10957,19 @@ "|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 before defining " - "a coroutine; include if your version " - "of libcxx is less than 14.0">; + "%0 type was not found; include before defining " + "a coroutine">; def err_implicit_coroutine_std_nothrow_type_not_found : Error< "std::nothrow was not found; include 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 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; -def warn_coroutine_in_legacy_experimental_space : Warning < - "coroutine_traits defined in std::experimental namespace is deprecated. " - "Consider updating libcxx and include instead of .">, - InGroup; def err_coroutine_promise_final_suspend_requires_nothrow : Error< "the expression 'co_await __promise.final_suspend()' is required to be non-throwing" >; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1128,10 +1128,6 @@ /// The C++ "std::coroutine_traits" template, which is defined in /// \ 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 \. RecordDecl *CXXTypeInfoDecl; @@ -5666,7 +5662,6 @@ NamespaceDecl *getOrCreateStdNamespace(); NamespaceDecl *lookupStdExperimentalNamespace(); - NamespaceDecl *getCachedCoroNamespace() { return CoroTraitsNamespaceCache; } CXXRecordDecl *getStdBadAlloc() const; EnumDecl *getStdAlignValT() const; @@ -10223,11 +10218,8 @@ 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); diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -53,10 +53,15 @@ SourceLocation KwLoc) { const FunctionProtoType *FnType = FD->getType()->castAs(); 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 @@ 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 @@ return PromiseType; } -/// Look up the std::coroutine_handle. +/// Look up the std::experimental::coroutine_handle. 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 @@ LookupResult Result(S, &S.PP.getIdentifierTable().get("nothrow"), Loc, Sema::LookupOrdinaryName); if (!S.LookupQualifiedName(Result, Std)) { - // FIXME: should have been included already. + // FIXME: should have been included already. // If we require it to include then this diagnostic is no longer // needed. S.Diag(Loc, diag::err_implicit_coroutine_std_nothrow_type_not_found); @@ -1658,32 +1663,25 @@ } 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())) { + 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())) { - Result.suppressDiagnostics(); - NamedDecl *Found = *Result.begin(); - Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits); - return nullptr; } - CoroTraitsNamespaceCache = CoroNamespace; } - Namespace = CoroTraitsNamespaceCache; return StdCoroutineTraitsCache; } diff --git a/clang/test/AST/Inputs/std-coroutine.h b/clang/test/AST/Inputs/std-coroutine.h --- a/clang/test/AST/Inputs/std-coroutine.h +++ b/clang/test/AST/Inputs/std-coroutine.h @@ -3,6 +3,7 @@ #define STD_COROUTINE_H namespace std { +namespace experimental { template struct coroutine_traits { using promise_type = typename R::promise_type; @@ -66,6 +67,7 @@ void await_resume() noexcept {} }; +} // namespace experimental } // namespace std #endif // STD_COROUTINE_H diff --git a/clang/test/AST/coroutine-locals-cleanup.cpp b/clang/test/AST/coroutine-locals-cleanup.cpp --- a/clang/test/AST/coroutine-locals-cleanup.cpp +++ b/clang/test/AST/coroutine-locals-cleanup.cpp @@ -2,7 +2,7 @@ #include "Inputs/std-coroutine.h" -using namespace std; +using namespace std::experimental; struct Task { struct promise_type { diff --git a/clang/test/AST/coroutine-source-location-crash.cpp b/clang/test/AST/coroutine-source-location-crash.cpp --- a/clang/test/AST/coroutine-source-location-crash.cpp +++ b/clang/test/AST/coroutine-source-location-crash.cpp @@ -11,7 +11,7 @@ #include "Inputs/std-coroutine.h" -using namespace std; +using namespace std::experimental; struct A { bool await_ready(); diff --git a/clang/test/Analysis/more-dtors-cfg-output.cpp b/clang/test/Analysis/more-dtors-cfg-output.cpp --- a/clang/test/Analysis/more-dtors-cfg-output.cpp +++ b/clang/test/Analysis/more-dtors-cfg-output.cpp @@ -275,32 +275,32 @@ #if CXX2A // Boilerplate needed to test co_return: -namespace std { -template -struct coroutine_handle { - static coroutine_handle from_address(void *) noexcept; -}; -} // namespace std +namespace std::experimental { + template + 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 &) noexcept; + void await_suspend(const std::experimental::coroutine_handle &) noexcept; void await_resume() noexcept; Foo return_value(const Bar &); Bar get_return_object(); void unhandled_exception(); }; -namespace std { -template -struct coroutine_traits; -template <> -struct coroutine_traits { - using promise_type = TestPromise; -}; -} // namespace std +namespace std::experimental { + template + struct coroutine_traits; + template <> + struct coroutine_traits { + using promise_type = TestPromise; + }; +} Bar coreturn() { co_return get_bar(); diff --git a/clang/test/CodeGenCXX/ubsan-coroutines.cpp b/clang/test/CodeGenCXX/ubsan-coroutines.cpp --- a/clang/test/CodeGenCXX/ubsan-coroutines.cpp +++ b/clang/test/CodeGenCXX/ubsan-coroutines.cpp @@ -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 struct coroutine_traits { using promise_type = typename R::promise_type; }; @@ -20,11 +20,11 @@ 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 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; } }; diff --git a/clang/test/CodeGenCoroutines/Inputs/coroutine.h b/clang/test/CodeGenCoroutines/Inputs/coroutine.h --- a/clang/test/CodeGenCoroutines/Inputs/coroutine.h +++ b/clang/test/CodeGenCoroutines/Inputs/coroutine.h @@ -1,6 +1,6 @@ #pragma once -namespace std { +namespace std { namespace experimental { inline namespace coroutines_v1 { template struct coroutine_traits { using promise_type = typename R::promise_type; @@ -77,4 +77,4 @@ void await_resume() noexcept {} }; -} // namespace std +}}} diff --git a/clang/test/CodeGenCoroutines/coro-alloc.cpp b/clang/test/CodeGenCoroutines/coro-alloc.cpp --- a/clang/test/CodeGenCoroutines/coro-alloc.cpp +++ b/clang/test/CodeGenCoroutines/coro-alloc.cpp @@ -3,6 +3,7 @@ // RUN: | FileCheck %s namespace std { +namespace experimental { template struct coroutine_traits; // expected-note {{declared here}} @@ -20,6 +21,8 @@ coroutine_handle(coroutine_handle) noexcept {} }; +} // end namespace experimental + struct nothrow_t {}; constexpr nothrow_t nothrow = {}; @@ -34,14 +37,14 @@ 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 { +template<> +struct std::experimental::coroutine_traits { struct promise_type { void get_return_object() {} suspend_always initial_suspend() { return {}; } @@ -80,8 +83,8 @@ struct promise_new_tag {}; -template <> -struct std::coroutine_traits { +template<> +struct std::experimental::coroutine_traits { struct promise_type { void *operator new(unsigned long); void get_return_object() {} @@ -95,7 +98,7 @@ 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 @@ struct promise_matching_placement_new_tag {}; -template <> -struct std::coroutine_traits { +template<> +struct std::experimental::coroutine_traits { struct promise_type { void *operator new(unsigned long, promise_matching_placement_new_tag, int, float, double); @@ -127,7 +130,7 @@ // 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 @@ struct promise_matching_global_placement_new_tag {}; struct dummy {}; -template <> -struct std::coroutine_traits { +template<> +struct std::experimental::coroutine_traits { struct promise_type { void get_return_object() {} suspend_always initial_suspend() { return {}; } @@ -159,8 +162,8 @@ struct promise_delete_tag {}; -template <> -struct std::coroutine_traits { +template<> +struct std::experimental::coroutine_traits { struct promise_type { void operator delete(void*); void get_return_object() {} @@ -178,14 +181,14 @@ // 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 { +template<> +struct std::experimental::coroutine_traits { struct promise_type { void operator delete(void*, unsigned long); void get_return_object() {} @@ -204,14 +207,14 @@ // 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 { +template<> +struct std::experimental::coroutine_traits { struct promise_type { int get_return_object() { return 0; } suspend_always initial_suspend() { return {}; } @@ -232,12 +235,12 @@ // 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]] diff --git a/clang/test/CodeGenCoroutines/coro-always-inline.cpp b/clang/test/CodeGenCoroutines/coro-always-inline.cpp --- a/clang/test/CodeGenCoroutines/coro-always-inline.cpp +++ b/clang/test/CodeGenCoroutines/coro-always-inline.cpp @@ -9,6 +9,7 @@ // RUN: -fno-inline -O0 %s -o - | FileCheck %s namespace std { +namespace experimental { struct handle {}; @@ -34,17 +35,18 @@ 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; } diff --git a/clang/test/CodeGenCoroutines/coro-await-domination.cpp b/clang/test/CodeGenCoroutines/coro-await-domination.cpp --- a/clang/test/CodeGenCoroutines/coro-await-domination.cpp +++ b/clang/test/CodeGenCoroutines/coro-await-domination.cpp @@ -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 { diff --git a/clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp b/clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp --- a/clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp +++ b/clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp @@ -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 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 @@ 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 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() {} }; diff --git a/clang/test/CodeGenCoroutines/coro-await.cpp b/clang/test/CodeGenCoroutines/coro-await.cpp --- a/clang/test/CodeGenCoroutines/coro-await.cpp +++ b/clang/test/CodeGenCoroutines/coro-await.cpp @@ -2,6 +2,7 @@ // RUN: -emit-llvm %s -o - -disable-llvm-passes -Wno-coroutine -Wno-unused | FileCheck %s namespace std { +namespace experimental { template struct coroutine_traits; @@ -19,28 +20,29 @@ 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 { +template<> +struct std::experimental::coroutine_traits { struct promise_type { void get_return_object(); init_susp initial_suspend(); @@ -55,7 +57,7 @@ // 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 @@ // --------------------------- // 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 @@ // 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 @@ 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 { + +template<> +struct std::experimental::coroutine_traits { struct promise_type { void get_return_object(); init_susp initial_suspend(); @@ -124,10 +127,10 @@ // CHECK-LABEL: f1( extern "C" void f1(int) { - // CHECK: %[[PROMISE:.+]] = alloca %"struct.std::coroutine_traits::promise_type" + // CHECK: %[[PROMISE:.+]] = alloca %"struct.std::experimental::coroutine_traits::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::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::promise_type"* {{[^,]*}} %[[PROMISE]], i32 42) // See if we need to suspend: // -------------------------- @@ -141,10 +144,10 @@ // --------------------------- // 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 @@ // 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 @@ // 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 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 { + +template<> +struct std::experimental::coroutine_traits { struct promise_type { void get_return_object(); init_susp initial_suspend(); @@ -334,7 +338,7 @@ 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 @@ 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]]) } diff --git a/clang/test/CodeGenCoroutines/coro-cleanup.cpp b/clang/test/CodeGenCoroutines/coro-cleanup.cpp --- a/clang/test/CodeGenCoroutines/coro-cleanup.cpp +++ b/clang/test/CodeGenCoroutines/coro-cleanup.cpp @@ -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 struct coroutine_traits; template struct coroutine_handle { @@ -14,15 +14,15 @@ template coroutine_handle(coroutine_handle) 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 { +template <> struct std::experimental::coroutine_traits { struct promise_type { void get_return_object() noexcept; suspend_always initial_suspend() noexcept; @@ -43,7 +43,7 @@ // 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 @@ // 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 @@ // 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 @@ 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 } diff --git a/clang/test/CodeGenCoroutines/coro-dest-slot.cpp b/clang/test/CodeGenCoroutines/coro-dest-slot.cpp --- a/clang/test/CodeGenCoroutines/coro-dest-slot.cpp +++ b/clang/test/CodeGenCoroutines/coro-dest-slot.cpp @@ -2,7 +2,7 @@ #include "Inputs/coroutine.h" -using namespace std; +using namespace std::experimental; struct coro { struct promise_type { @@ -30,7 +30,7 @@ // 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( diff --git a/clang/test/CodeGenCoroutines/coro-dwarf.cpp b/clang/test/CodeGenCoroutines/coro-dwarf.cpp --- a/clang/test/CodeGenCoroutines/coro-dwarf.cpp +++ b/clang/test/CodeGenCoroutines/coro-dwarf.cpp @@ -3,7 +3,7 @@ // RUN: -emit-llvm -o - %s | \ // RUN: FileCheck %s --implicit-check-not=DILocalVariable -namespace std { +namespace std::experimental { template struct coroutine_traits; template struct coroutine_handle { @@ -16,15 +16,15 @@ template coroutine_handle(coroutine_handle) 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 { +template struct std::experimental::coroutine_traits { struct promise_type { void get_return_object() noexcept; suspend_always initial_suspend() noexcept; diff --git a/clang/test/CodeGenCoroutines/coro-eh-cleanup.cpp b/clang/test/CodeGenCoroutines/coro-eh-cleanup.cpp --- a/clang/test/CodeGenCoroutines/coro-eh-cleanup.cpp +++ b/clang/test/CodeGenCoroutines/coro-eh-cleanup.cpp @@ -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 struct coroutine_traits { using promise_type = typename R::promise_type; }; @@ -18,11 +18,11 @@ 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; }; diff --git a/clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp b/clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp --- a/clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp +++ b/clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp @@ -2,7 +2,7 @@ #include "Inputs/coroutine.h" -using namespace std; +using namespace std::experimental; namespace std { diff --git a/clang/test/CodeGenCoroutines/coro-gro.cpp b/clang/test/CodeGenCoroutines/coro-gro.cpp --- a/clang/test/CodeGenCoroutines/coro-gro.cpp +++ b/clang/test/CodeGenCoroutines/coro-gro.cpp @@ -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 struct coroutine_traits; template struct coroutine_handle { @@ -15,11 +15,11 @@ template coroutine_handle(coroutine_handle) 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 @@ operator int() noexcept; }; -template <> struct std::coroutine_traits { +template <> struct std::experimental::coroutine_traits { struct promise_type { GroType get_return_object() noexcept; suspend_always initial_suspend() noexcept; @@ -51,8 +51,8 @@ // 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 @@ 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]]) diff --git a/clang/test/CodeGenCoroutines/coro-lambda.cpp b/clang/test/CodeGenCoroutines/coro-lambda.cpp --- a/clang/test/CodeGenCoroutines/coro-lambda.cpp +++ b/clang/test/CodeGenCoroutines/coro-lambda.cpp @@ -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 struct coroutine_traits { using promise_type = typename R::promise_type; }; @@ -17,11 +17,11 @@ 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; }; diff --git a/clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp b/clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp --- a/clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp +++ b/clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp @@ -16,6 +16,7 @@ // CHECK-ALL: Running pass:{{.*}}CoroCleanupPass namespace std { +namespace experimental { struct handle {}; @@ -38,6 +39,7 @@ void unhandled_exception() {} }; }; +} // namespace experimental } // namespace std void foo() { co_return; } diff --git a/clang/test/CodeGenCoroutines/coro-params.cpp b/clang/test/CodeGenCoroutines/coro-params.cpp --- a/clang/test/CodeGenCoroutines/coro-params.cpp +++ b/clang/test/CodeGenCoroutines/coro-params.cpp @@ -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 struct coroutine_traits; template struct coroutine_handle { @@ -17,15 +17,15 @@ template coroutine_handle(coroutine_handle) 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 { +template struct std::experimental::coroutine_traits { struct promise_type { void get_return_object() noexcept; suspend_always initial_suspend() noexcept; @@ -73,9 +73,9 @@ // 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::promise_type"* %__promise to i8* + // CHECK-NEXT: bitcast %"struct.std::experimental::coroutine_traits::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 @@ 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::promise_type"* {{[^,]*}} %__promise) - // CHECK-NEXT: bitcast %"struct.std::coroutine_traits::promise_type"* %__promise to i8* + // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvi8MoveOnly11MoveAndCopyEE12promise_typeD1Ev(%"struct.std::experimental::coroutine_traits::promise_type"* {{[^,]*}} %__promise) + // CHECK-NEXT: bitcast %"struct.std::experimental::coroutine_traits::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 @@ // 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::promise_type"* %__promise to i8* + // CHECK-NEXT: bitcast %"struct.std::experimental::coroutine_traits::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 @@ struct promise_matching_constructor {}; -template <> -struct std::coroutine_traits { +template<> +struct std::experimental::coroutine_traits { struct promise_type { promise_type(promise_matching_constructor, int, float, double) {} promise_type() = delete; @@ -173,7 +173,7 @@ // 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::promise_type"* {{[^,]*}} %__promise, i32 %[[INT]], float %[[FLOAT]], double %[[DOUBLE]]) + // CHECK: invoke void @_ZNSt12experimental16coroutine_traitsIJv28promise_matching_constructorifdEE12promise_typeC1ES1_ifd(%"struct.std::experimental::coroutine_traits::promise_type"* {{[^,]*}} %__promise, i32 %[[INT]], float %[[FLOAT]], double %[[DOUBLE]]) co_return; } @@ -181,7 +181,7 @@ struct method {}; -template struct std::coroutine_traits { +template struct std::experimental::coroutine_traits { struct promise_type { promise_type(some_class&, float); method get_return_object(); @@ -198,6 +198,6 @@ // 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::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::promise_type"* {{[^,]*}} %__promise, %struct.some_class* nonnull align 1 dereferenceable(1) %{{.+}}, float co_return; } diff --git a/clang/test/CodeGenCoroutines/coro-promise-dtor.cpp b/clang/test/CodeGenCoroutines/coro-promise-dtor.cpp --- a/clang/test/CodeGenCoroutines/coro-promise-dtor.cpp +++ b/clang/test/CodeGenCoroutines/coro-promise-dtor.cpp @@ -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(); diff --git a/clang/test/CodeGenCoroutines/coro-ret-void.cpp b/clang/test/CodeGenCoroutines/coro-ret-void.cpp --- a/clang/test/CodeGenCoroutines/coro-ret-void.cpp +++ b/clang/test/CodeGenCoroutines/coro-ret-void.cpp @@ -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 @@ 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 @@ } // 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) diff --git a/clang/test/CodeGenCoroutines/coro-return-voidtype-initlist.cpp b/clang/test/CodeGenCoroutines/coro-return-voidtype-initlist.cpp --- a/clang/test/CodeGenCoroutines/coro-return-voidtype-initlist.cpp +++ b/clang/test/CodeGenCoroutines/coro-return-voidtype-initlist.cpp @@ -5,6 +5,7 @@ struct b { b(int, a); }; template struct c {}; +namespace experimental { template struct coroutine_traits : d {}; template @@ -20,6 +21,7 @@ void await_suspend(coroutine_handle<>); void await_resume(); }; +} // namespace experimental } // namespace std template auto ah(ag) { return ag().ah(0); } @@ -29,10 +31,10 @@ struct h { int await_ready() noexcept; template - void await_suspend(std::coroutine_handle) noexcept; + void await_suspend(std::experimental::coroutine_handle) noexcept; void await_resume() noexcept; }; - std::e initial_suspend(); + std::experimental::e initial_suspend(); h final_suspend() noexcept; template auto await_transform(ag) { return ah(ag()); } @@ -43,20 +45,20 @@ void unhandled_exception(); }; struct k { - k(std::coroutine_handle<>); + k(std::experimental::coroutine_handle<>); int await_ready(); }; template 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); } diff --git a/clang/test/CodeGenCoroutines/coro-return.cpp b/clang/test/CodeGenCoroutines/coro-return.cpp --- a/clang/test/CodeGenCoroutines/coro-return.cpp +++ b/clang/test/CodeGenCoroutines/coro-return.cpp @@ -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 struct coroutine_traits; template struct coroutine_handle { @@ -13,15 +13,15 @@ template coroutine_handle(coroutine_handle) 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 { +template <> struct std::experimental::coroutine_traits { struct promise_type { void get_return_object(); suspend_always initial_suspend(); @@ -32,15 +32,15 @@ // CHECK-LABEL: f0( extern "C" void f0() { - // CHECK: %__promise = alloca %"struct.std::coroutine_traits::promise_type" + // CHECK: %__promise = alloca %"struct.std::experimental::coroutine_traits::promise_type" // CHECK: %call = call noalias nonnull i8* @_Znwm( - // CHECK: call void @_ZNSt16coroutine_traitsIJvEE12promise_type11return_voidEv(%"struct.std::coroutine_traits::promise_type"* {{[^,]*}} %__promise) + // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type11return_voidEv(%"struct.std::experimental::coroutine_traits::promise_type"* {{[^,]*}} %__promise) // CHECK: call void @_ZdlPv co_return; } -template <> -struct std::coroutine_traits { +template<> +struct std::experimental::coroutine_traits { struct promise_type { int get_return_object(); suspend_always initial_suspend(); @@ -51,9 +51,9 @@ // CHECK-LABEL: f1( extern "C" int f1() { - // CHECK: %__promise = alloca %"struct.std::coroutine_traits::promise_type" + // CHECK: %__promise = alloca %"struct.std::experimental::coroutine_traits::promise_type" // CHECK: %call = call noalias nonnull i8* @_Znwm( - // CHECK: call void @_ZNSt16coroutine_traitsIJiEE12promise_type12return_valueEi(%"struct.std::coroutine_traits::promise_type"* {{[^,]*}} %__promise, i32 42) + // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJiEE12promise_type12return_valueEi(%"struct.std::experimental::coroutine_traits::promise_type"* {{[^,]*}} %__promise, i32 42) // CHECK: call void @_ZdlPv co_return 42; } diff --git a/clang/test/CodeGenCoroutines/coro-symmetric-transfer-01.cpp b/clang/test/CodeGenCoroutines/coro-symmetric-transfer-01.cpp --- a/clang/test/CodeGenCoroutines/coro-symmetric-transfer-01.cpp +++ b/clang/test/CodeGenCoroutines/coro-symmetric-transfer-01.cpp @@ -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::from_promise(*this)}; + return detached_task{coro::coroutine_handle::from_promise(*this)}; } void return_void() noexcept {} struct final_awaiter { bool await_ready() noexcept { return false; } - std::coroutine_handle<> await_suspend(std::coroutine_handle h) noexcept { + coro::coroutine_handle<> await_suspend(coro::coroutine_handle h) noexcept { h.destroy(); return {}; } @@ -24,7 +26,7 @@ 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 @@ tmp.resume(); } - std::coroutine_handle coro_; + coro::coroutine_handle coro_; }; detached_task foo() { @@ -50,12 +52,12 @@ // 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]]) diff --git a/clang/test/CodeGenCoroutines/coro-symmetric-transfer-02.cpp b/clang/test/CodeGenCoroutines/coro-symmetric-transfer-02.cpp --- a/clang/test/CodeGenCoroutines/coro-symmetric-transfer-02.cpp +++ b/clang/test/CodeGenCoroutines/coro-symmetric-transfer-02.cpp @@ -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::from_promise(*this)}; + return Task{coro::coroutine_handle::from_promise(*this)}; } void return_void() noexcept {} struct final_awaiter { bool await_ready() noexcept { return false; } - std::coroutine_handle<> await_suspend(std::coroutine_handle h) noexcept { + coro::coroutine_handle<> await_suspend(coro::coroutine_handle h) noexcept { h.destroy(); return {}; } @@ -23,7 +25,7 @@ final_awaiter final_suspend() noexcept { return {}; } - std::suspend_always initial_suspend() noexcept { return {}; } + coro::suspend_always initial_suspend() noexcept { return {}; } template auto await_transform(Awaitable &&awaitable) { @@ -31,7 +33,7 @@ } }; - using handle_t = std::coroutine_handle; + using handle_t = coro::coroutine_handle; class Awaiter { public: @@ -41,7 +43,7 @@ ~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 @@ // 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 @@ // 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 diff --git a/clang/test/CodeGenCoroutines/coro-unhandled-exception.cpp b/clang/test/CodeGenCoroutines/coro-unhandled-exception.cpp --- a/clang/test/CodeGenCoroutines/coro-unhandled-exception.cpp +++ b/clang/test/CodeGenCoroutines/coro-unhandled-exception.cpp @@ -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 @@ struct coro_t { struct promise_type { coro_t get_return_object() { - std::coroutine_handle{}; + coro::coroutine_handle{}; 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 @@ // 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 @@ // 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( diff --git a/clang/test/CoverageMapping/coroutine.cpp b/clang/test/CoverageMapping/coroutine.cpp --- a/clang/test/CoverageMapping/coroutine.cpp +++ b/clang/test/CoverageMapping/coroutine.cpp @@ -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 struct coroutine_traits; @@ -16,16 +16,16 @@ template coroutine_handle(coroutine_handle) 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 { +struct std::experimental::coroutine_traits { struct promise_type { int get_return_object(); suspend_always initial_suspend(); diff --git a/clang/test/Index/coroutines.cpp b/clang/test/Index/coroutines.cpp --- a/clang/test/Index/coroutines.cpp +++ b/clang/test/Index/coroutines.cpp @@ -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 @@ }; template <> -struct std::coroutine_traits { using promise_type = promise_void; }; +struct std::experimental::coroutine_traits { using promise_type = promise_void; }; void CoroutineTestRet() { co_return; diff --git a/clang/test/PCH/coroutines.cpp b/clang/test/PCH/coroutines.cpp --- a/clang/test/PCH/coroutines.cpp +++ b/clang/test/PCH/coroutines.cpp @@ -8,7 +8,7 @@ #ifndef HEADER #define HEADER -namespace std { +namespace std::experimental { template struct coroutine_traits; template struct coroutine_handle { @@ -21,15 +21,15 @@ template coroutine_handle(coroutine_handle) 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 { +template struct std::experimental::coroutine_traits { struct promise_type { void get_return_object() noexcept; suspend_always initial_suspend() noexcept; @@ -42,7 +42,7 @@ }; }; -template struct std::coroutine_traits { +template struct std::experimental::coroutine_traits { struct promise_type { int get_return_object() noexcept; suspend_always initial_suspend() noexcept; diff --git a/clang/test/SemaCXX/Inputs/std-coroutine.h b/clang/test/SemaCXX/Inputs/std-coroutine.h --- a/clang/test/SemaCXX/Inputs/std-coroutine.h +++ b/clang/test/SemaCXX/Inputs/std-coroutine.h @@ -3,6 +3,7 @@ #define STD_COROUTINE_H namespace std { +namespace experimental { template struct coroutine_traits { using promise_type = typename Ret::promise_type; }; @@ -30,6 +31,7 @@ void await_resume() noexcept {} }; +} // namespace experimental } // namespace std #endif // STD_COROUTINE_H diff --git a/clang/test/SemaCXX/co_await-range-for.cpp b/clang/test/SemaCXX/co_await-range-for.cpp --- a/clang/test/SemaCXX/co_await-range-for.cpp +++ b/clang/test/SemaCXX/co_await-range-for.cpp @@ -3,7 +3,8 @@ // RUN: -fblocks #include "Inputs/std-coroutine.h" -using namespace std; +using namespace std::experimental; + template struct Awaiter { diff --git a/clang/test/SemaCXX/coreturn-eh.cpp b/clang/test/SemaCXX/coreturn-eh.cpp --- a/clang/test/SemaCXX/coreturn-eh.cpp +++ b/clang/test/SemaCXX/coreturn-eh.cpp @@ -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 @@ }; template -struct std::coroutine_traits { using promise_type = promise_void_return_value; }; +struct std::experimental::coroutine_traits { using promise_type = promise_void_return_value; }; VoidTagReturnValue test() { object x = {}; diff --git a/clang/test/SemaCXX/coreturn.cpp b/clang/test/SemaCXX/coreturn.cpp --- a/clang/test/SemaCXX/coreturn.cpp +++ b/clang/test/SemaCXX/coreturn.cpp @@ -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 @@ }; template <> -struct std::coroutine_traits { using promise_type = promise_void; }; +struct std::experimental::coroutine_traits { using promise_type = promise_void; }; template -struct std::coroutine_traits { using promise_type = promise_void_return_value; }; +struct std::experimental::coroutine_traits { using promise_type = promise_void_return_value; }; template -struct std::coroutine_traits { using promise_type = promise_float; }; +struct std::experimental::coroutine_traits { using promise_type = promise_float; }; template -struct std::coroutine_traits { using promise_type = promise_int; }; +struct std::experimental::coroutine_traits { using promise_type = promise_int; }; void test0() { co_await a; } float test1() { co_await a; } diff --git a/clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp b/clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp --- a/clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp +++ b/clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp @@ -4,6 +4,7 @@ // RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -verify %s -fcxx-exceptions -fexceptions -Wunused-result namespace std { +namespace experimental { template struct coroutine_traits { using promise_type = typename Ret::promise_type; }; @@ -33,9 +34,10 @@ ~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(); diff --git a/clang/test/SemaCXX/coroutine-rvo.cpp b/clang/test/SemaCXX/coroutine-rvo.cpp --- a/clang/test/SemaCXX/coroutine-rvo.cpp +++ b/clang/test/SemaCXX/coroutine-rvo.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -verify -std=c++17 -fcoroutines-ts -fsyntax-only %s -namespace std { +namespace std::experimental { template struct coroutine_handle { coroutine_handle() = default; static coroutine_handle from_address(void *) noexcept; @@ -30,11 +30,11 @@ template struct coroutine_traits : public traits_sfinae_base {}; -} // 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; }; diff --git a/clang/test/SemaCXX/coroutine-seh.cpp b/clang/test/SemaCXX/coroutine-seh.cpp --- a/clang/test/SemaCXX/coroutine-seh.cpp +++ b/clang/test/SemaCXX/coroutine-seh.cpp @@ -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 struct coroutine_traits; template struct coroutine_handle { @@ -12,15 +12,15 @@ template coroutine_handle(coroutine_handle) 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 { +template <> struct std::experimental::coroutine_traits { struct promise_type { void get_return_object() noexcept; suspend_always initial_suspend() noexcept; diff --git a/clang/test/SemaCXX/coroutine-traits-undefined-template.cpp b/clang/test/SemaCXX/coroutine-traits-undefined-template.cpp --- a/clang/test/SemaCXX/coroutine-traits-undefined-template.cpp +++ b/clang/test/SemaCXX/coroutine-traits-undefined-template.cpp @@ -4,14 +4,15 @@ // RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -verify %s -fcxx-exceptions -fexceptions -Wunused-result namespace std { +namespace experimental { template struct coroutine_traits { struct promise_type {}; }; -template <> struct coroutine_traits; // expected-note {{forward declaration of 'std::coroutine_traits'}} -} // namespace std +template<> struct coroutine_traits; // expected-note {{forward declaration of 'std::experimental::coroutine_traits'}} +}} // namespace std::experimental void uses_forward_declaration() { co_return; // expected-error {{this function cannot be a coroutine: missing definition of specialization 'coroutine_traits'}} diff --git a/clang/test/SemaCXX/coroutine-unhandled_exception-warning.cpp b/clang/test/SemaCXX/coroutine-unhandled_exception-warning.cpp --- a/clang/test/SemaCXX/coroutine-unhandled_exception-warning.cpp +++ b/clang/test/SemaCXX/coroutine-unhandled_exception-warning.cpp @@ -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 @@ }; template -struct std::coroutine_traits { using promise_type = promise_void; }; +struct std::experimental::coroutine_traits { 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}} diff --git a/clang/test/SemaCXX/coroutine-uninitialized-warning-crash.cpp b/clang/test/SemaCXX/coroutine-uninitialized-warning-crash.cpp --- a/clang/test/SemaCXX/coroutine-uninitialized-warning-crash.cpp +++ b/clang/test/SemaCXX/coroutine-uninitialized-warning-crash.cpp @@ -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; } diff --git a/clang/test/SemaCXX/coroutine_handle-addres-return-type.cpp b/clang/test/SemaCXX/coroutine_handle-addres-return-type.cpp --- a/clang/test/SemaCXX/coroutine_handle-addres-return-type.cpp +++ b/clang/test/SemaCXX/coroutine_handle-addres-return-type.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -verify %s -stdlib=libc++ -std=c++1z -fcoroutines-ts -fsyntax-only -namespace std { +namespace std::experimental { template struct coroutine_handle; @@ -32,11 +32,11 @@ template struct coroutine_traits : public traits_sfinae_base {}; -} // 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 @@ }; }; -namespace std { +namespace std::experimental { template <> struct coroutine_handle : public coroutine_handle<> { coroutine_handle *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 - await_suspend(std::coroutine_handle<> handle); + std::experimental::coroutine_handle + await_suspend(std::experimental::coroutine_handle<> handle); void await_resume(); } a; diff --git a/clang/test/SemaCXX/coroutines-exp-namespace.cpp b/clang/test/SemaCXX/coroutines-exp-namespace.cpp deleted file mode 100644 --- a/clang/test/SemaCXX/coroutines-exp-namespace.cpp +++ /dev/null @@ -1,1450 +0,0 @@ -// This file is the same with coroutines.cpp except the coroutine components are defined in std::experimental namespace. -// This intention of this test is to make sure the legacy imeplementation in std::experimental namespace could work. -// TODO: Remove this test once we didn't support - -// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify=expected,cxx20_2b,cxx2b %s -fcxx-exceptions -fexceptions -Wunused-result -// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx14_20,cxx20_2b %s -fcxx-exceptions -fexceptions -Wunused-result -// 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 }} - // expected-error@-1 {{use of undeclared identifier 'a'}} -} - -void no_coroutine_traits_bad_arg_yield() { - co_yield a; // expected-error {{include }} - // expected-error@-1 {{use of undeclared identifier 'a'}} -} - -void no_coroutine_traits_bad_arg_return() { - co_return a; // expected-error {{include }} - // 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 before defining a coroutine; include if your version of libcxx is less than 14.0}} -} - -namespace std { -namespace experimental { - -template -struct void_t_imp { - using type = void; -}; -template -using void_t = typename void_t_imp::type; - -template -struct traits_sfinae_base {}; - -template -struct traits_sfinae_base> { - using promise_type = typename T::promise_type; -}; - -template -struct coroutine_traits : public traits_sfinae_base {}; -} // namespace experimental -} // namespace std - -template struct coro {}; -template -struct std::experimental::coroutine_traits, Ps...> { - using promise_type = Promise; -}; - -struct awaitable { - bool await_ready() noexcept; - template - void await_suspend(F) noexcept; - void await_resume() noexcept; -} a; - -struct suspend_always { - bool await_ready() noexcept { return false; } - template - void await_suspend(F) noexcept; - void await_resume() noexcept {} -}; - -struct suspend_never { - bool await_ready() noexcept { return true; } - template - void await_suspend(F) noexcept; - void await_resume() noexcept {} -}; - -struct auto_await_suspend { - bool await_ready(); - template auto await_suspend(F) {} - void await_resume(); -}; - -struct DummyVoidTag {}; -DummyVoidTag no_specialization() { // expected-error {{this function cannot be a coroutine: 'std::experimental::coroutine_traits' has no member named 'promise_type'}} - co_await a; // expected-warning {{coroutine_traits defined in std::experimental namespace is deprecated. Consider updating libcxx and include instead of }} -} - -template -struct std::experimental::coroutine_traits {}; - -int no_promise_type() { // expected-error {{this function cannot be a coroutine: 'std::experimental::coroutine_traits' 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::experimental::coroutine_traits' has no member named 'promise_type'}} - co_await a; - co_await a; -} - -template <> -struct std::experimental::coroutine_traits { typedef int promise_type; }; -double bad_promise_type(double) { // expected-error {{this function cannot be a coroutine: 'experimental::coroutine_traits::promise_type' (aka 'int') is not a class}} - co_await a; -} - -template <> -struct std::experimental::coroutine_traits { - 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::experimental::coroutine_traits::promise_type'}} -} - -struct promise; // expected-note {{forward declaration}} -struct promise_void; -struct void_tag {}; -template -struct std::experimental::coroutine_traits { using promise_type = promise; }; -template -struct std::experimental::coroutine_traits { using promise_type = promise_void; }; - -// FIXME: This diagnostic is terrible. -void undefined_promise() { // expected-error {{this function cannot be a coroutine: 'experimental::coroutine_traits::promise_type' (aka 'promise') is an incomplete type}} - co_await a; -} - -struct yielded_thing { - const char *p; - short a, b; -}; - -struct not_awaitable {}; - -struct promise { - void get_return_object(); - suspend_always initial_suspend(); - suspend_always final_suspend() noexcept; - awaitable yield_value(int); // expected-note 2{{candidate}} - awaitable yield_value(yielded_thing); // expected-note 2{{candidate}} - not_awaitable yield_value(void()); // expected-note 2{{candidate}} - void return_value(int); // expected-note 2{{here}} - void unhandled_exception(); -}; - -struct promise_void { - void get_return_object(); - suspend_always initial_suspend(); - suspend_always final_suspend() noexcept; - void return_void(); - void unhandled_exception(); -}; - -void no_coroutine_handle() { // expected-error {{std::coroutine_handle type was not found; include before defining a coroutine; include if your version of libcxx is less than 14.0}} - //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 -struct coroutine_handle { - static coroutine_handle from_address(void *) noexcept; -}; -template <> -struct coroutine_handle { - template - coroutine_handle(coroutine_handle) noexcept; - static coroutine_handle from_address(void *) noexcept; -}; -} // namespace experimental -} // namespace std - -void yield() { - co_yield 0; - co_yield {"foo", 1, 2}; - co_yield {1e100}; // expected-error {{cannot be narrowed}} expected-note {{explicit cast}} expected-warning {{implicit conversion}} expected-warning {{braces around scalar}} - co_yield {"foo", __LONG_LONG_MAX__}; // expected-error {{cannot be narrowed}} expected-note {{explicit cast}} expected-warning {{changes value}} - co_yield {"foo"}; - co_yield "foo"; // expected-error {{no matching}} - co_yield 1.0; - co_yield yield; // expected-error {{no member named 'await_ready' in 'not_awaitable'}} -} - -void check_auto_await_suspend() { - co_await auto_await_suspend{}; // Should compile successfully. -} - -void coreturn(int n) { - co_await a; - if (n == 0) - co_return 3; - if (n == 1) - co_return {4}; // expected-warning {{braces around scalar initializer}} - if (n == 2) - co_return "foo"; // expected-error {{cannot initialize a parameter of type 'int' with an lvalue of type 'const char [4]'}} - co_return 42; -} - -template -void co_await_non_dependent_arg(T) { - co_await a; -} -template void co_await_non_dependent_arg(int); - -void mixed_yield() { - co_yield 0; // expected-note {{use of 'co_yield'}} - return; // expected-error {{not allowed in coroutine}} -} - -void mixed_yield_invalid() { - co_yield blah; // expected-error {{use of undeclared identifier}} - // expected-note@-1 {{function is a coroutine due to use of 'co_yield'}} - return; // expected-error {{return statement not allowed in coroutine}} -} - -template -void mixed_yield_template(T) { - co_yield blah; // expected-error {{use of undeclared identifier}} - // expected-note@-1 {{function is a coroutine due to use of 'co_yield'}} - return; // expected-error {{return statement not allowed in coroutine}} -} - -template -void mixed_yield_template2(T) { - co_yield 42; - // expected-note@-1 {{function is a coroutine due to use of 'co_yield'}} - return; // expected-error {{return statement not allowed in coroutine}} -} - -template -void mixed_yield_template3(T v) { - co_yield blah(v); - // expected-note@-1 {{function is a coroutine due to use of 'co_yield'}} - return; // expected-error {{return statement not allowed in coroutine}} -} - -void mixed_await() { - co_await a; // expected-note {{use of 'co_await'}} - return; // expected-error {{not allowed in coroutine}} -} - -void mixed_await_invalid() { - co_await 42; // expected-error {{'int' is not a structure or union}} - // expected-note@-1 {{function is a coroutine due to use of 'co_await'}} - return; // expected-error {{not allowed in coroutine}} -} - -template -void mixed_await_template(T) { - co_await 42; - // expected-note@-1 {{function is a coroutine due to use of 'co_await'}} - return; // expected-error {{not allowed in coroutine}} -} - -template -void mixed_await_template2(T v) { - co_await v; // expected-error {{'long' is not a structure or union}} - // expected-note@-1 {{function is a coroutine due to use of 'co_await'}} - return; // expected-error {{not allowed in coroutine}} -} -template void mixed_await_template2(long); // expected-note {{requested here}} - -void only_coreturn(void_tag) { - co_return; // OK -} - -void mixed_coreturn(void_tag, bool b) { - if (b) - co_return; // expected-note {{use of 'co_return'}} - else - return; // expected-error {{not allowed in coroutine}} -} - -void mixed_coreturn_invalid(bool b) { - if (b) - co_return; // expected-note {{use of 'co_return'}} - // expected-error@-1 {{no member named 'return_void' in 'promise'}} - else - return; // expected-error {{not allowed in coroutine}} -} - -template -void mixed_coreturn_template(void_tag, bool b, T v) { - if (b) - co_return v; // expected-note {{use of 'co_return'}} - // expected-error@-1 {{no member named 'return_value' in 'promise_void'}} - else - return; // expected-error {{not allowed in coroutine}} -} -template void mixed_coreturn_template(void_tag, bool, int); // expected-note {{requested here}} - -template -void mixed_coreturn_template2(bool b, T) { - if (b) - co_return v; // expected-note {{use of 'co_return'}} - // expected-error@-1 {{use of undeclared identifier 'v'}} - else - return; // expected-error {{not allowed in coroutine}} -} - -struct CtorDtor { - CtorDtor() { - co_yield 0; // expected-error {{'co_yield' cannot be used in a constructor}} - } - CtorDtor(awaitable a) { - // The spec doesn't say this is ill-formed, but it must be. - co_await a; // expected-error {{'co_await' cannot be used in a constructor}} - } - ~CtorDtor() { - co_return 0; // expected-error {{'co_return' cannot be used in a destructor}} - } - void operator=(CtorDtor &) { - co_yield 0; // OK. - } - void operator=(CtorDtor const &) { - co_yield 0; // OK. - } - void operator=(CtorDtor &&) { - co_await a; // OK. - } - void operator=(CtorDtor const &&) { - co_await a; // OK. - } - void operator=(int) { - co_await a; // OK. Not a special member - } -}; - -namespace std { -class type_info; -} - -void unevaluated() { - decltype(co_await a); // expected-error {{'co_await' cannot be used in an unevaluated context}} - // expected-warning@-1 {{declaration does not declare anything}} - sizeof(co_await a); // expected-error {{'co_await' cannot be used in an unevaluated context}} - // expected-error@-1 {{invalid application of 'sizeof' to an incomplete type 'void'}} - // expected-warning@-2 {{expression with side effects has no effect in an unevaluated context}} - typeid(co_await a); // expected-error {{'co_await' cannot be used in an unevaluated context}} - // expected-warning@-1 {{expression with side effects has no effect in an unevaluated context}} - // expected-warning@-2 {{expression result unused}} - decltype(co_yield 1); // expected-error {{'co_yield' cannot be used in an unevaluated context}} - // expected-warning@-1 {{declaration does not declare anything}} - sizeof(co_yield 2); // expected-error {{'co_yield' cannot be used in an unevaluated context}} - // expected-error@-1 {{invalid application of 'sizeof' to an incomplete type 'void'}} - // expected-warning@-2 {{expression with side effects has no effect in an unevaluated context}} - typeid(co_yield 3); // expected-error {{'co_yield' cannot be used in an unevaluated context}} - // expected-warning@-1 {{expression with side effects has no effect in an unevaluated context}} - // expected-warning@-2 {{expression result unused}} -} - -// [expr.await]p2: "An await-expression shall not appear in a default argument." -// FIXME: A better diagnostic would explicitly state that default arguments are -// not allowed. A user may not understand that this is "outside a function." -void default_argument(int arg = co_await 0) {} // expected-error {{'co_await' cannot be used outside a function}} - -void await_in_catch_coroutine() { - try { - } catch (...) { // FIXME: Emit a note diagnostic pointing out the try handler on this line. - []() -> void { co_await a; }(); // OK - co_await a; // expected-error {{'co_await' cannot be used in the handler of a try block}} - } -} - -void await_nested_in_catch_coroutine() { - try { - } catch (...) { // FIXME: Emit a note diagnostic pointing out the try handler on this line. - try { - co_await a; // expected-error {{'co_await' cannot be used in the handler of a try block}} - []() -> void { co_await a; }(); // OK - } catch (...) { - co_return 123; - } - } -} - -void await_in_lambda_in_catch_coroutine() { - try { - } catch (...) { - []() -> void { co_await a; }(); // OK - } -} - -void yield_in_catch_coroutine() { - try { - } catch (...) { - co_yield 1; // expected-error {{'co_yield' cannot be used in the handler of a try block}} - } -} - -void return_in_catch_coroutine() { - try { - } catch (...) { - co_return 123; // OK - } -} - -constexpr auto constexpr_deduced_return_coroutine() { - co_yield 0; // expected-error {{'co_yield' cannot be used in a constexpr function}} - // expected-error@-1 {{'co_yield' cannot be used in a function with a deduced return type}} -} - -void varargs_coroutine(const char *, ...) { - co_await a; // expected-error {{'co_await' cannot be used in a varargs function}} -} - -auto deduced_return_coroutine() { - co_await a; // expected-error {{'co_await' cannot be used in a function with a deduced return type}} -} - -struct outer {}; -struct await_arg_1 {}; -struct await_arg_2 {}; - -namespace adl_ns { -struct coawait_arg_type {}; -awaitable operator co_await(coawait_arg_type) noexcept; -} // namespace adl_ns - -namespace dependent_operator_co_await_lookup { -template void await_template(T t) { - // no unqualified lookup results - co_await t; // expected-error {{no member named 'await_ready' in 'dependent_operator_co_await_lookup::not_awaitable'}} - // expected-error@-1 {{call to function 'operator co_await' that is neither visible in the template definition nor found by argument-dependent lookup}} -}; -template void await_template(awaitable); - -struct indirectly_awaitable { - indirectly_awaitable(outer); -}; -awaitable operator co_await(indirectly_awaitable); // expected-note {{should be declared prior to}} -template void await_template(indirectly_awaitable); - -struct not_awaitable {}; -template void await_template(not_awaitable); // expected-note {{instantiation}} - -template void await_template_2(T t) { - // one unqualified lookup result - co_await t; -}; -template void await_template(outer); // expected-note {{instantiation}} -template void await_template_2(outer); - -struct transform_awaitable {}; -struct transformed {}; - -struct transform_promise { - typedef transform_awaitable await_arg; - coro get_return_object(); - transformed initial_suspend(); - ::adl_ns::coawait_arg_type final_suspend() noexcept; - transformed await_transform(transform_awaitable); - void unhandled_exception(); - void return_void(); -}; -template -struct basic_promise { - typedef AwaitArg await_arg; - coro get_return_object(); - awaitable initial_suspend(); - awaitable final_suspend() noexcept; - void unhandled_exception(); - void return_void(); -}; - -awaitable operator co_await(await_arg_1); - -template -coro await_template_3(U t) { - co_await t; -} - -template coro> await_template_3>(await_arg_1); - -template -struct dependent_member { - coro mem_fn() const { - co_await typename T::await_arg{}; // expected-error {{call to function 'operator co_await'}}} - } - template - coro dep_mem_fn(U t) { - co_await t; - } -}; - -template <> -struct dependent_member { - // FIXME this diagnostic is terrible - coro mem_fn() const { // expected-error {{no member named 'await_ready' in 'dependent_operator_co_await_lookup::transformed'}} - // expected-note@-1 {{call to 'initial_suspend' implicitly required by the initial suspend point}} - // expected-note@+1 {{function is a coroutine due to use of 'co_await' here}} - co_await transform_awaitable{}; - // expected-error@-1 {{no member named 'await_ready'}} - } - template - coro dep_mem_fn(U u) { co_await u; } -}; - -awaitable operator co_await(await_arg_2); // expected-note {{'operator co_await' should be declared prior to the call site}} - -template struct dependent_member, 0>; -template struct dependent_member, 0>; // expected-note {{in instantiation}} - -template <> -coro -// FIXME this diagnostic is terrible -dependent_member::dep_mem_fn(int) { // expected-error {{no member named 'await_ready' in 'dependent_operator_co_await_lookup::transformed'}} - //expected-note@-1 {{call to 'initial_suspend' implicitly required by the initial suspend point}} - //expected-note@+1 {{function is a coroutine due to use of 'co_await' here}} - co_await transform_awaitable{}; - // expected-error@-1 {{no member named 'await_ready'}} -} - -void operator co_await(transform_awaitable) = delete; -awaitable operator co_await(transformed); - -template coro - dependent_member::dep_mem_fn(transform_awaitable); - -template <> -coro dependent_member::dep_mem_fn(long) { - co_await transform_awaitable{}; -} - -template <> -struct dependent_member { - coro mem_fn() const { - co_await transform_awaitable{}; - } -}; - -template coro await_template_3(transform_awaitable); -template struct dependent_member; -template coro dependent_member::dep_mem_fn(transform_awaitable); -} // namespace dependent_operator_co_await_lookup - -struct yield_fn_tag {}; -template <> -struct std::experimental::coroutine_traits { - struct promise_type { - // FIXME: add an await_transform overload for functions - awaitable yield_value(int()); - void return_value(int()); - - suspend_never initial_suspend(); - suspend_never final_suspend() noexcept; - void get_return_object(); - void unhandled_exception(); - }; -}; - -namespace placeholder { -awaitable f(), f(int); // expected-note 4{{possible target}} -int g(), g(int); // expected-note 2{{candidate}} -void x() { - co_await f; // expected-error {{reference to overloaded function}} -} -void y() { - co_yield g; // expected-error {{no matching member function for call to 'yield_value'}} -} -void z() { - co_await a; - co_return g; // expected-error {{address of overloaded function 'g' does not match required type 'int'}} -} - -void x(yield_fn_tag) { - co_await f; // expected-error {{reference to overloaded function}} -} -void y(yield_fn_tag) { - co_yield g; -} -void z(yield_fn_tag) { - co_await a; - co_return g; -} -} // namespace placeholder - -struct bad_promise_1 { - suspend_always initial_suspend(); - suspend_always final_suspend() noexcept; - void unhandled_exception(); - void return_void(); -}; -coro missing_get_return_object() { // expected-error {{no member named 'get_return_object' in 'bad_promise_1'}} - co_await a; -} - -struct bad_promise_2 { - coro get_return_object(); - suspend_always final_suspend() noexcept; - void unhandled_exception(); - void return_void(); -}; -// FIXME: This shouldn't happen twice -coro missing_initial_suspend() { // expected-error {{no member named 'initial_suspend' in 'bad_promise_2'}} - co_await a; -} - -struct bad_promise_3 { - coro get_return_object(); - suspend_always initial_suspend(); - void unhandled_exception(); - void return_void(); -}; -coro missing_final_suspend() noexcept { // expected-error {{no member named 'final_suspend' in 'bad_promise_3'}} - co_await a; -} - -struct bad_promise_4 { - coro get_return_object(); - not_awaitable initial_suspend(); - suspend_always final_suspend() noexcept; - void return_void(); -}; -// FIXME: This diagnostic is terrible. -coro bad_initial_suspend() { // expected-error {{no member named 'await_ready' in 'not_awaitable'}} - // expected-note@-1 {{call to 'initial_suspend' implicitly required by the initial suspend point}} - co_await a; // expected-note {{function is a coroutine due to use of 'co_await' here}} -} - -struct bad_promise_5 { - coro get_return_object(); - suspend_always initial_suspend(); - not_awaitable final_suspend() noexcept; - void return_void(); -}; -// FIXME: This diagnostic is terrible. -coro bad_final_suspend() { // expected-error {{no member named 'await_ready' in 'not_awaitable'}} - // expected-note@-1 {{call to 'final_suspend' implicitly required by the final suspend point}} - co_await a; // expected-note {{function is a coroutine due to use of 'co_await' here}} -} - -struct bad_promise_6 { - coro get_return_object(); - suspend_always initial_suspend(); - suspend_always final_suspend() noexcept; - void unhandled_exception(); - void return_void(); // expected-note 2 {{member 'return_void' first declared here}} - void return_value(int) const; // expected-note 2 {{member 'return_value' first declared here}} - void return_value(int); -}; -coro bad_implicit_return() { // expected-error {{'bad_promise_6' declares both 'return_value' and 'return_void'}} - co_await a; -} - -template -coro bad_implicit_return_dependent(T) { // expected-error {{'bad_promise_6' declares both 'return_value' and 'return_void'}} - co_await a; -} -template coro bad_implicit_return_dependent(bad_promise_6); // expected-note {{in instantiation}} - -struct bad_promise_7 { // expected-note 2 {{defined here}} - coro get_return_object(); - suspend_always initial_suspend(); - suspend_always final_suspend() noexcept; - void return_void(); -}; -coro no_unhandled_exception() { // expected-error {{'bad_promise_7' is required to declare the member 'unhandled_exception()'}} - co_await a; -} - -template -coro no_unhandled_exception_dependent(T) { // expected-error {{'bad_promise_7' is required to declare the member 'unhandled_exception()'}} - co_await a; -} -template coro no_unhandled_exception_dependent(bad_promise_7); // expected-note {{in instantiation}} - -struct bad_promise_base { -private: - void return_void(); // expected-note 2 {{declared private here}} -}; -struct bad_promise_8 : bad_promise_base { - coro get_return_object(); - suspend_always initial_suspend(); - suspend_always final_suspend() noexcept; - void unhandled_exception() __attribute__((unavailable)); // expected-note 2 {{marked unavailable here}} - void unhandled_exception() const; - void unhandled_exception(void *) const; -}; -coro calls_unhandled_exception() { - // expected-error@-1 {{'unhandled_exception' is unavailable}} - // expected-error@-2 {{'return_void' is a private member}} - co_await a; -} - -template -coro calls_unhandled_exception_dependent(T) { - // expected-error@-1 {{'unhandled_exception' is unavailable}} - // expected-error@-2 {{'return_void' is a private member}} - co_await a; -} -template coro calls_unhandled_exception_dependent(bad_promise_8); // expected-note {{in instantiation}} - -struct bad_promise_9 { - coro get_return_object(); - suspend_always initial_suspend(); - suspend_always final_suspend() noexcept; - void await_transform(void *); - awaitable await_transform(int) __attribute__((unavailable)); // expected-note {{explicitly marked unavailable}} - void return_void(); - void unhandled_exception(); -}; -coro calls_await_transform() { - co_await 42; // expected-error {{'await_transform' is unavailable}} -} - -struct bad_promise_10 { - coro get_return_object(); - suspend_always initial_suspend(); - suspend_always final_suspend() noexcept; - int await_transform; - void return_void(); - void unhandled_exception(); -}; -coro bad_coawait() { - // FIXME this diagnostic is terrible - co_await 42; // expected-error {{called object type 'int' is not a function or function pointer}} - // expected-note@-1 {{call to 'await_transform' implicitly required by 'co_await' here}} -} - -struct call_operator { - template - awaitable operator()(Args...) const { return a; } -}; -void ret_void(); -struct good_promise_1 { - coro get_return_object(); - suspend_always initial_suspend(); - suspend_always final_suspend() noexcept; - void unhandled_exception(); - static const call_operator await_transform; - using Fn = void (*)(); - Fn return_void = ret_void; -}; -const call_operator good_promise_1::await_transform; -coro ok_static_coawait() { - // FIXME this diagnostic is terrible - co_await 42; -} - -template void ok_generic_lambda_coawait_PR41909() { - [](auto &arg) -> coro { // expected-warning {{expression result unused}} - co_await 12; - }; - [](auto &arg) -> coro { - co_await 24; - }("argument"); - [](auto &arg) -> coro { // expected-warning {{expression result unused}} - []() -> coro { - co_await 36; - }; - co_await 48; - }; -} -template void ok_generic_lambda_coawait_PR41909(); // expected-note {{in instantiation of function template specialization 'ok_generic_lambda_coawait_PR41909' requested here}} - -template <> struct std::experimental::coroutine_traits { using promise_type = promise; }; - -int main(int, const char **) { - co_await a; // expected-error {{'co_await' cannot be used in the 'main' function}} -} - -struct good_promise_2 { - float get_return_object(); - suspend_always initial_suspend(); - suspend_always final_suspend() noexcept; - void return_void(); - void unhandled_exception(); -}; -template <> struct std::experimental::coroutine_handle {}; - -template <> struct std::experimental::coroutine_traits { using promise_type = good_promise_2; }; - -float badly_specialized_coro_handle() { // expected-error {{std::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}} -} - -namespace std { -struct nothrow_t {}; -constexpr nothrow_t nothrow = {}; -} // namespace std - -using SizeT = decltype(sizeof(int)); - -void *operator new(SizeT __sz, const std::nothrow_t &) noexcept; -void operator delete(void *__p, const std::nothrow_t &)noexcept; - -struct promise_on_alloc_failure_tag {}; - -template <> -struct std::experimental::coroutine_traits { - struct promise_type { - int get_return_object() {} - suspend_always initial_suspend() { return {}; } - suspend_always final_suspend() noexcept { return {}; } - void return_void() {} - int get_return_object_on_allocation_failure(); // expected-error{{'promise_type': 'get_return_object_on_allocation_failure()' must be a static member function}} - void unhandled_exception(); - }; -}; - -extern "C" int f(promise_on_alloc_failure_tag) { - co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}} -} - -struct bad_promise_11 { - coro get_return_object(); - suspend_always initial_suspend(); - suspend_always final_suspend() noexcept; - void unhandled_exception(); - void return_void(); - -private: - static coro get_return_object_on_allocation_failure(); // expected-note 2 {{declared private here}} -}; -coro private_alloc_failure_handler() { - // expected-error@-1 {{'get_return_object_on_allocation_failure' is a private member of 'bad_promise_11'}} - co_return; // FIXME: Add a "declared coroutine here" note. -} - -template -coro dependent_private_alloc_failure_handler(T) { - // expected-error@-1 {{'get_return_object_on_allocation_failure' is a private member of 'bad_promise_11'}} - co_return; // FIXME: Add a "declared coroutine here" note. -} -template coro dependent_private_alloc_failure_handler(bad_promise_11); -// expected-note@-1 {{requested here}} - -struct bad_promise_12 { - coro get_return_object(); - suspend_always initial_suspend(); - suspend_always final_suspend() noexcept; - void unhandled_exception(); - void return_void(); - static coro get_return_object_on_allocation_failure(); - - static void *operator new(SizeT); - // expected-error@-1 2 {{'operator new' is required to have a non-throwing noexcept specification when the promise type declares 'get_return_object_on_allocation_failure()'}} -}; -coro throwing_in_class_new() { // expected-note {{call to 'operator new' implicitly required by coroutine function here}} - co_return; -} - -template -coro dependent_throwing_in_class_new(T) { // expected-note {{call to 'operator new' implicitly required by coroutine function here}} - co_return; -} -template coro dependent_throwing_in_class_new(bad_promise_12); // expected-note {{requested here}} - -struct good_promise_13 { - coro get_return_object(); - suspend_always initial_suspend(); - suspend_always final_suspend() noexcept; - void unhandled_exception(); - void return_void(); - static coro get_return_object_on_allocation_failure(); -}; -coro uses_nothrow_new() { - co_return; -} - -template -coro dependent_uses_nothrow_new(T) { - co_return; -} -template coro dependent_uses_nothrow_new(good_promise_13); - -struct good_promise_custom_new_operator { - coro get_return_object(); - suspend_always initial_suspend(); - suspend_always final_suspend() noexcept; - void return_void(); - void unhandled_exception(); - void *operator new(SizeT, double, float, int); -}; - -coro -good_coroutine_calls_custom_new_operator(double, float, int) { - co_return; -} - -struct coroutine_nonstatic_member_struct; - -struct good_promise_nonstatic_member_custom_new_operator { - coro get_return_object(); - suspend_always initial_suspend(); - suspend_always final_suspend() noexcept; - void return_void(); - void unhandled_exception(); - void *operator new(SizeT, coroutine_nonstatic_member_struct &, double); -}; - -struct good_promise_noexcept_custom_new_operator { - static coro get_return_object_on_allocation_failure(); - coro get_return_object(); - suspend_always initial_suspend(); - suspend_always final_suspend() noexcept; - void return_void(); - void unhandled_exception(); - void *operator new(SizeT, double, float, int) noexcept; -}; - -coro -good_coroutine_calls_noexcept_custom_new_operator(double, float, int) { - co_return; -} - -struct mismatch_gro_type_tag1 {}; -template <> -struct std::experimental::coroutine_traits { - struct promise_type { - void get_return_object() {} //expected-note {{member 'get_return_object' declared here}} - suspend_always initial_suspend() { return {}; } - suspend_always final_suspend() noexcept { return {}; } - void return_void() {} - void unhandled_exception(); - }; -}; - -extern "C" int f(mismatch_gro_type_tag1) { - // expected-error@-1 {{cannot initialize return object of type 'int' with an rvalue of type 'void'}} - co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}} -} - -struct mismatch_gro_type_tag2 {}; -template <> -struct std::experimental::coroutine_traits { - struct promise_type { - void *get_return_object() {} //expected-note {{member 'get_return_object' declared here}} - suspend_always initial_suspend() { return {}; } - suspend_always final_suspend() noexcept { return {}; } - void return_void() {} - void unhandled_exception(); - }; -}; - -extern "C" int f(mismatch_gro_type_tag2) { - // cxx2b-error@-1 {{cannot initialize return object of type 'int' with an rvalue of type 'void *'}} - // cxx14_20-error@-2 {{cannot initialize return object of type 'int' with an lvalue of type 'void *'}} - co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}} -} - -struct mismatch_gro_type_tag3 {}; -template <> -struct std::experimental::coroutine_traits { - 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}} - suspend_always initial_suspend() { return {}; } - suspend_always final_suspend() noexcept { return {}; } - void return_void() {} - void unhandled_exception(); - }; -}; - -extern "C" int f(mismatch_gro_type_tag3) { - // expected-error@-1 {{cannot initialize return object of type 'int' with an rvalue of type 'void'}} - co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}} -} - -struct mismatch_gro_type_tag4 {}; -template <> -struct std::experimental::coroutine_traits { - 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}} - suspend_always initial_suspend() { return {}; } - suspend_always final_suspend() noexcept { return {}; } - void return_void() {} - void unhandled_exception(); - }; -}; - -extern "C" int f(mismatch_gro_type_tag4) { - // expected-error@-1 {{cannot initialize return object of type 'int' with an rvalue of type 'char *'}} - co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}} -} - -struct bad_promise_no_return_func { // expected-note {{'bad_promise_no_return_func' defined here}} - coro get_return_object(); - suspend_always initial_suspend(); - suspend_always final_suspend() noexcept; - void unhandled_exception(); -}; -// FIXME: The PDTS currently specifies this as UB, technically forbidding a -// diagnostic. -coro no_return_value_or_return_void() { - // expected-error@-1 {{'bad_promise_no_return_func' must declare either 'return_value' or 'return_void'}} - co_await a; -} - -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::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::experimental::coroutine_handle<>); - void await_resume(); -}; -struct await_ready_explicit_bool { - struct BoolT { - explicit operator bool() const; - }; - BoolT await_ready(); - void await_suspend(std::experimental::coroutine_handle<>); - void await_resume(); -}; -template -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::experimental::coroutine_handle<>); - // cxx20_2b-warning@-1 {{volatile-qualified return type 'const volatile bool' is deprecated}} - void await_resume(); -}; -void test_bad_suspend() { - { - // FIXME: The actual error emitted here is terrible, and no number of notes can save it. - bad_await_ready_return a; - // expected-error@+1 {{value of type 'void' is not contextually convertible to 'bool'}} - co_await a; // expected-note {{call to 'await_ready' implicitly required by coroutine function here}} - } - { - bad_await_suspend_return b; - co_await b; // expected-note {{call to 'await_suspend' implicitly required by coroutine function here}} - } - { - await_ready_explicit_bool c; - co_await c; // OK - } - { - await_suspend_type_test a; - await_suspend_type_test b; - await_suspend_type_test c; - await_suspend_type_test d; // cxx20_2b-note {{in instantiation of template class}} - co_await a; // expected-note {{call to 'await_suspend' implicitly required by coroutine function here}} - co_await b; // expected-note {{call to 'await_suspend' implicitly required by coroutine function here}} - co_await c; // OK - co_await d; // OK - } -} - -template -struct NoCopy { - NoCopy(NoCopy const &) = delete; // expected-note 2 {{deleted here}} -}; -template -void test_dependent_param(T t, U) { - // expected-error@-1 {{call to deleted constructor of 'NoCopy<0>'}} - // expected-error@-2 {{call to deleted constructor of 'NoCopy<1>'}} - ((void)t); - co_return 42; -} -template void test_dependent_param(NoCopy<0>, NoCopy<1>); // expected-note {{requested here}} - -namespace CoroHandleMemberFunctionTest { -struct CoroMemberTag {}; -struct BadCoroMemberTag {}; - -template -constexpr bool IsSameV = false; -template -constexpr bool IsSameV = true; - -template -struct TypeTest { - template - static constexpr bool IsSame = IsSameV; - - template - static constexpr bool MatchesArgs = IsSameV>; -}; - -template -struct AwaitReturnsType { - bool await_ready() const; - void await_suspend(...) const; - T await_resume() const; -}; - -template -struct CoroMemberPromise { - using TraitsT = std::experimental::coroutine_traits; - using TypeTestT = TypeTest; - using AwaitTestT = AwaitReturnsType; - - CoroMemberTag get_return_object(); - suspend_always initial_suspend(); - suspend_always final_suspend() noexcept; - - AwaitTestT yield_value(int); - - void return_void(); - void unhandled_exception(); -}; - -} // namespace CoroHandleMemberFunctionTest - -template -struct ::std::experimental::coroutine_traits { - using promise_type = CoroHandleMemberFunctionTest::CoroMemberPromise; -}; - -namespace CoroHandleMemberFunctionTest { -struct TestType { - - CoroMemberTag test_qual() { - auto TC = co_yield 0; - static_assert(TC.MatchesArgs, ""); - static_assert(!TC.MatchesArgs, ""); - static_assert(!TC.MatchesArgs, ""); - } - - CoroMemberTag test_sanity(int *) const { - auto TC = co_yield 0; - static_assert(TC.MatchesArgs, ""); // expected-error {{static_assert failed}} - static_assert(TC.MatchesArgs, ""); // expected-error {{static_assert failed}} - static_assert(TC.MatchesArgs, ""); - } - - CoroMemberTag test_qual(int *, const float &&, volatile void *volatile) const { - // cxx20_2b-warning@-1 {{volatile-qualified parameter type}} - auto TC = co_yield 0; - static_assert(TC.MatchesArgs, ""); - } - - CoroMemberTag test_qual() const volatile { - auto TC = co_yield 0; - static_assert(TC.MatchesArgs, ""); - } - - CoroMemberTag test_ref_qual() & { - auto TC = co_yield 0; - static_assert(TC.MatchesArgs, ""); - } - CoroMemberTag test_ref_qual() const & { - auto TC = co_yield 0; - static_assert(TC.MatchesArgs, ""); - } - CoroMemberTag test_ref_qual() && { - auto TC = co_yield 0; - static_assert(TC.MatchesArgs, ""); - } - CoroMemberTag test_ref_qual(const char *&) const volatile && { - auto TC = co_yield 0; - static_assert(TC.MatchesArgs, ""); - } - - CoroMemberTag test_args(int) { - auto TC = co_yield 0; - static_assert(TC.MatchesArgs, ""); - } - CoroMemberTag test_args(int, long &, void *) const { - auto TC = co_yield 0; - static_assert(TC.MatchesArgs, ""); - } - - template - CoroMemberTag test_member_template(Args...) const && { - auto TC = co_yield 0; - static_assert(TC.template MatchesArgs, ""); - } - - static CoroMemberTag test_static() { - auto TC = co_yield 0; - static_assert(TC.MatchesArgs<>, ""); - static_assert(!TC.MatchesArgs, ""); - static_assert(!TC.MatchesArgs, ""); - static_assert(!TC.MatchesArgs, ""); - } - - static CoroMemberTag test_static(volatile void *const, char &&) { - auto TC = co_yield 0; - static_assert(TC.MatchesArgs, ""); - } - - template - static CoroMemberTag test_static_template(const char *volatile &, unsigned) { - auto TC = co_yield 0; - using TCT = decltype(TC); - static_assert(TCT::MatchesArgs, ""); - static_assert(!TCT::MatchesArgs, ""); - } - - BadCoroMemberTag test_diagnostics() { - // expected-error@-1 {{this function cannot be a coroutine: 'std::experimental::coroutine_traits' has no member named 'promise_type'}} - co_return; - } - BadCoroMemberTag test_diagnostics(int) const && { - // expected-error@-1 {{this function cannot be a coroutine: 'std::experimental::coroutine_traits' has no member named 'promise_type'}} - co_return; - } - - static BadCoroMemberTag test_static_diagnostics(long *) { - // expected-error@-1 {{this function cannot be a coroutine: 'std::experimental::coroutine_traits' has no member named 'promise_type'}} - co_return; - } -}; - -template CoroMemberTag TestType::test_member_template(long, const char *) const &&; -template CoroMemberTag TestType::test_static_template(const char *volatile &, unsigned); - -template -struct DepTestType { - - CoroMemberTag test_sanity(int *) const { - auto TC = co_yield 0; - static_assert(TC.template MatchesArgs, ""); // expected-error {{static_assert failed}} - static_assert(TC.template MatchesArgs<>, ""); // expected-error {{static_assert failed}} - static_assert(TC.template MatchesArgs, ""); - } - - CoroMemberTag test_qual() { - auto TC = co_yield 0; - static_assert(TC.template MatchesArgs, ""); - static_assert(!TC.template MatchesArgs, ""); - static_assert(!TC.template MatchesArgs, ""); - } - - CoroMemberTag test_qual(int *, const float &&, volatile void *volatile) const { - // cxx20_2b-warning@-1 {{volatile-qualified parameter type}} - auto TC = co_yield 0; - static_assert(TC.template MatchesArgs, ""); - } - - CoroMemberTag test_qual() const volatile { - auto TC = co_yield 0; - static_assert(TC.template MatchesArgs, ""); - } - - CoroMemberTag test_ref_qual() & { - auto TC = co_yield 0; - static_assert(TC.template MatchesArgs, ""); - } - CoroMemberTag test_ref_qual() const & { - auto TC = co_yield 0; - static_assert(TC.template MatchesArgs, ""); - } - CoroMemberTag test_ref_qual() && { - auto TC = co_yield 0; - static_assert(TC.template MatchesArgs, ""); - } - CoroMemberTag test_ref_qual(const char *&) const volatile && { - auto TC = co_yield 0; - static_assert(TC.template MatchesArgs, ""); - } - - CoroMemberTag test_args(int) { - auto TC = co_yield 0; - static_assert(TC.template MatchesArgs, ""); - } - CoroMemberTag test_args(int, long &, void *) const { - auto TC = co_yield 0; - static_assert(TC.template MatchesArgs, ""); - } - - template - CoroMemberTag test_member_template(UArgs...) const && { - auto TC = co_yield 0; - static_assert(TC.template MatchesArgs, ""); - } - - static CoroMemberTag test_static() { - auto TC = co_yield 0; - using TCT = decltype(TC); - static_assert(TCT::MatchesArgs<>, ""); - static_assert(!TCT::MatchesArgs, ""); - static_assert(!TCT::MatchesArgs, ""); - static_assert(!TCT::MatchesArgs, ""); - - // Ensure diagnostics are actually being generated here - static_assert(TCT::MatchesArgs, ""); // expected-error {{static_assert failed}} - } - - static CoroMemberTag test_static(volatile void *const, char &&) { - auto TC = co_yield 0; - using TCT = decltype(TC); - static_assert(TCT::MatchesArgs, ""); - } - - template - static CoroMemberTag test_static_template(const char *volatile &, unsigned) { - auto TC = co_yield 0; - using TCT = decltype(TC); - static_assert(TCT::MatchesArgs, ""); - static_assert(!TCT::MatchesArgs, ""); - } -}; - -template struct DepTestType; // expected-note {{requested here}} -template CoroMemberTag DepTestType::test_member_template(long, const char *) const &&; - -template CoroMemberTag DepTestType::test_static_template(const char *volatile &, unsigned); - -struct bad_promise_deleted_constructor { - // expected-note@+1 {{'bad_promise_deleted_constructor' has been explicitly marked deleted here}} - bad_promise_deleted_constructor() = delete; - coro get_return_object(); - suspend_always initial_suspend(); - suspend_always final_suspend() noexcept; - void return_void(); - void unhandled_exception(); -}; - -coro -bad_coroutine_calls_deleted_promise_constructor() { - // expected-error@-1 {{call to deleted constructor of 'std::experimental::coroutine_traits>::promise_type' (aka 'CoroHandleMemberFunctionTest::bad_promise_deleted_constructor')}} - co_return; -} - -// Test that, when the promise type has a constructor whose signature matches -// that of the coroutine function, that constructor is used. If no matching -// constructor exists, the default constructor is used as a fallback. If no -// matching constructors exist at all, an error is emitted. This is an -// experimental feature that will be proposed for the Coroutines TS. - -struct good_promise_default_constructor { - good_promise_default_constructor(double, float, int); - good_promise_default_constructor() = default; - coro get_return_object(); - suspend_always initial_suspend(); - suspend_always final_suspend() noexcept; - void return_void(); - void unhandled_exception(); -}; - -coro -good_coroutine_calls_default_constructor() { - co_return; -} - -struct some_class; - -struct good_promise_custom_constructor { - good_promise_custom_constructor(some_class &, float, int); - good_promise_custom_constructor(double, float, int); - good_promise_custom_constructor() = delete; - coro get_return_object(); - suspend_always initial_suspend(); - suspend_always final_suspend() noexcept; - void return_void(); - void unhandled_exception(); -}; - -coro -good_coroutine_calls_custom_constructor(double, float, int) { - co_return; -} - -struct some_class { - coro - good_coroutine_calls_custom_constructor(float, int) { - co_return; - } - coro static good_coroutine_calls_custom_constructor(double, float, int) { - co_return; - } -}; - -struct bad_promise_no_matching_constructor { - bad_promise_no_matching_constructor(int, int, int); - // expected-note@+1 2 {{'bad_promise_no_matching_constructor' has been explicitly marked deleted here}} - bad_promise_no_matching_constructor() = delete; - coro get_return_object(); - suspend_always initial_suspend(); - suspend_always final_suspend() noexcept; - void return_void(); - void unhandled_exception(); -}; - -coro -bad_coroutine_calls_with_no_matching_constructor(int, int) { - // expected-error@-1 {{call to deleted constructor of 'std::experimental::coroutine_traits, int, int>::promise_type' (aka 'CoroHandleMemberFunctionTest::bad_promise_no_matching_constructor')}} - co_return; -} - -struct some_class2 { - coro - bad_coroutine_calls_with_no_matching_constructor(int, int, int) { - // expected-error@-1 {{call to deleted constructor}} - co_return; - } -}; - -} // namespace CoroHandleMemberFunctionTest - -class awaitable_no_unused_warn { -public: - 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; } -}; - -class awaitable_unused_warn { -public: - 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; } -}; - -template -struct check_warning_promise { - coro get_return_object(); - Await initial_suspend(); - Await final_suspend() noexcept; - Await yield_value(int); - void return_void(); - void unhandled_exception(); -}; - -coro> -test_no_unused_warning() { - co_await awaitable_no_unused_warn(); - co_yield 42; -} - -coro> -test_unused_warning() { - co_await awaitable_unused_warn(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - co_yield 42; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} -} - -struct missing_await_ready { - void await_suspend(std::experimental::coroutine_handle<>); - void await_resume(); -}; -struct missing_await_suspend { - bool await_ready(); - void await_resume(); -}; -struct missing_await_resume { - bool await_ready(); - void await_suspend(std::experimental::coroutine_handle<>); -}; - -void test_missing_awaitable_members() { - co_await missing_await_ready{}; // expected-error {{no member named 'await_ready' in 'missing_await_ready'}} - co_await missing_await_suspend{}; // expected-error {{no member named 'await_suspend' in 'missing_await_suspend'}} - co_await missing_await_resume{}; // expected-error {{no member named 'await_resume' in 'missing_await_resume'}} -} diff --git a/clang/test/SemaCXX/coroutines.cpp b/clang/test/SemaCXX/coroutines.cpp --- a/clang/test/SemaCXX/coroutines.cpp +++ b/clang/test/SemaCXX/coroutines.cpp @@ -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 }} + co_await a; // expected-error {{include }} // expected-error@-1 {{use of undeclared identifier 'a'}} } void no_coroutine_traits_bad_arg_yield() { - co_yield a; // expected-error {{include }} + co_yield a; // expected-error {{include }} // expected-error@-1 {{use of undeclared identifier 'a'}} } void no_coroutine_traits_bad_arg_return() { - co_return a; // expected-error {{include }} + co_return a; // expected-error {{include }} // 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 }} + co_await 4; // expected-error {{std::experimental::coroutine_traits type was not found; include }} } namespace std { +namespace experimental { template struct void_t_imp { @@ -44,11 +45,11 @@ template struct coroutine_traits : public traits_sfinae_base {}; -} // end of namespace std +}} // namespace std::experimental template struct coro {}; template -struct std::coroutine_traits, Ps...> { +struct std::experimental::coroutine_traits, Ps...> { using promise_type = Promise; }; @@ -80,46 +81,47 @@ }; struct DummyVoidTag {}; -DummyVoidTag no_specialization() { // expected-error {{this function cannot be a coroutine: 'std::coroutine_traits' has no member named 'promise_type'}} +DummyVoidTag no_specialization() { // expected-error {{this function cannot be a coroutine: 'std::experimental::coroutine_traits' has no member named 'promise_type'}} co_await a; } template -struct std::coroutine_traits {}; +struct std::experimental::coroutine_traits {}; -int no_promise_type() { // expected-error {{this function cannot be a coroutine: 'std::coroutine_traits' has no member named 'promise_type'}} +int no_promise_type() { // expected-error {{this function cannot be a coroutine: 'std::experimental::coroutine_traits' 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' 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' has no member named 'promise_type'}} co_await a; co_await a; } template <> -struct std::coroutine_traits { typedef int promise_type; }; -double bad_promise_type(double) { // expected-error {{this function cannot be a coroutine: 'std::coroutine_traits::promise_type' (aka 'int') is not a class}} +struct std::experimental::coroutine_traits { typedef int promise_type; }; +double bad_promise_type(double) { // expected-error {{this function cannot be a coroutine: 'experimental::coroutine_traits::promise_type' (aka 'int') is not a class}} co_await a; } template <> -struct std::coroutine_traits { +struct std::experimental::coroutine_traits { 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::promise_type'}} + co_yield 0; // expected-error {{no member named 'yield_value' in 'std::experimental::coroutine_traits::promise_type'}} } struct promise; // expected-note {{forward declaration}} struct promise_void; struct void_tag {}; template -struct std::coroutine_traits { using promise_type = promise; }; +struct std::experimental::coroutine_traits { using promise_type = promise; }; template -struct std::coroutine_traits { using promise_type = promise_void; }; +struct std::experimental::coroutine_traits +{ using promise_type = promise_void; }; // FIXME: This diagnostic is terrible. -void undefined_promise() { // expected-error {{this function cannot be a coroutine: 'std::coroutine_traits::promise_type' (aka 'promise') is an incomplete type}} +void undefined_promise() { // expected-error {{this function cannot be a coroutine: 'experimental::coroutine_traits::promise_type' (aka 'promise') is an incomplete type}} co_await a; } @@ -146,12 +148,13 @@ void unhandled_exception(); }; -void no_coroutine_handle() { // expected-error {{std::coroutine_handle type was not found; include before defining a coroutine}} +void no_coroutine_handle() { // expected-error {{std::experimental::coroutine_handle type was not found; include 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 struct coroutine_handle { static coroutine_handle from_address(void *) noexcept; @@ -162,7 +165,7 @@ coroutine_handle(coroutine_handle) noexcept; static coroutine_handle from_address(void *) noexcept; }; -} // namespace std +}} // namespace std::experimental void yield() { co_yield 0; @@ -526,7 +529,7 @@ struct yield_fn_tag {}; template <> -struct std::coroutine_traits { +struct std::experimental::coroutine_traits { struct promise_type { // FIXME: add an await_transform overload for functions awaitable yield_value(int()); @@ -744,7 +747,8 @@ } template void ok_generic_lambda_coawait_PR41909(); // expected-note {{in instantiation of function template specialization 'ok_generic_lambda_coawait_PR41909' requested here}} -template <> struct std::coroutine_traits { using promise_type = promise; }; +template<> struct std::experimental::coroutine_traits +{ 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 @@ void return_void(); void unhandled_exception(); }; -template <> struct std::coroutine_handle {}; +template<> struct std::experimental::coroutine_handle {}; -template <> struct std::coroutine_traits { using promise_type = good_promise_2; }; +template<> struct std::experimental::coroutine_traits +{ 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 @@ struct promise_on_alloc_failure_tag {}; -template <> -struct std::coroutine_traits { +template<> +struct std::experimental::coroutine_traits { struct promise_type { int get_return_object() {} suspend_always initial_suspend() { return {}; } @@ -900,8 +905,8 @@ } struct mismatch_gro_type_tag1 {}; -template <> -struct std::coroutine_traits { +template<> +struct std::experimental::coroutine_traits { struct promise_type { void get_return_object() {} //expected-note {{member 'get_return_object' declared here}} suspend_always initial_suspend() { return {}; } @@ -917,8 +922,8 @@ } struct mismatch_gro_type_tag2 {}; -template <> -struct std::coroutine_traits { +template<> +struct std::experimental::coroutine_traits { struct promise_type { void *get_return_object() {} //expected-note {{member 'get_return_object' declared here}} suspend_always initial_suspend() { return {}; } @@ -935,8 +940,8 @@ } struct mismatch_gro_type_tag3 {}; -template <> -struct std::coroutine_traits { +template<> +struct std::experimental::coroutine_traits { 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 @@ struct mismatch_gro_type_tag4 {}; -template <> -struct std::coroutine_traits { +template<> +struct std::experimental::coroutine_traits { 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 @@ 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 @@ explicit operator bool() const; }; BoolT await_ready(); - void await_suspend(std::coroutine_handle<>); + void await_suspend(std::experimental::coroutine_handle<>); void await_resume(); }; template @@ -1009,7 +1014,7 @@ 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 @@ template static constexpr bool MatchesArgs = IsSameV>; + std::experimental::coroutine_traits>; }; template @@ -1081,7 +1086,7 @@ template struct CoroMemberPromise { - using TraitsT = std::coroutine_traits; + using TraitsT = std::experimental::coroutine_traits; using TypeTestT = TypeTest; using AwaitTestT = AwaitReturnsType; @@ -1098,7 +1103,7 @@ } // namespace CoroHandleMemberFunctionTest template -struct ::std::coroutine_traits { +struct ::std::experimental::coroutine_traits { using promise_type = CoroHandleMemberFunctionTest::CoroMemberPromise; }; @@ -1184,16 +1189,16 @@ } BadCoroMemberTag test_diagnostics() { - // expected-error@-1 {{this function cannot be a coroutine: 'std::coroutine_traits' has no member named 'promise_type'}} + // expected-error@-1 {{this function cannot be a coroutine: 'std::experimental::coroutine_traits' 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' has no member named 'promise_type'}} + // expected-error@-1 {{this function cannot be a coroutine: 'std::experimental::coroutine_traits' 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' has no member named 'promise_type'}} + // expected-error@-1 {{this function cannot be a coroutine: 'std::experimental::coroutine_traits' has no member named 'promise_type'}} co_return; } }; @@ -1305,7 +1310,7 @@ coro bad_coroutine_calls_deleted_promise_constructor() { - // expected-error@-1 {{call to deleted constructor of 'std::coroutine_traits>::promise_type' (aka 'CoroHandleMemberFunctionTest::bad_promise_deleted_constructor')}} + // expected-error@-1 {{call to deleted constructor of 'std::experimental::coroutine_traits>::promise_type' (aka 'CoroHandleMemberFunctionTest::bad_promise_deleted_constructor')}} co_return; } @@ -1372,7 +1377,7 @@ coro bad_coroutine_calls_with_no_matching_constructor(int, int) { - // expected-error@-1 {{call to deleted constructor of 'std::coroutine_traits, int, int>::promise_type' (aka 'CoroHandleMemberFunctionTest::bad_promise_no_matching_constructor')}} + // expected-error@-1 {{call to deleted constructor of 'std::experimental::coroutine_traits, int, int>::promise_type' (aka 'CoroHandleMemberFunctionTest::bad_promise_no_matching_constructor')}} co_return; } @@ -1388,7 +1393,7 @@ 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 @@ 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 @@ } 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_resume { bool await_ready(); - void await_suspend(std::coroutine_handle<>); + void await_suspend(std::experimental::coroutine_handle<>); }; void test_missing_awaitable_members() { diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -623,6 +623,7 @@ FileContentMappings M; M.push_back(std::make_pair("/coro_header", R"cpp( namespace std { +namespace experimental { template struct void_t_imp { @@ -641,7 +642,7 @@ template struct coroutine_traits : public traits_sfinae_base {}; -} // namespace std +}} // namespace std::experimental struct awaitable { bool await_ready() noexcept; template @@ -657,13 +658,14 @@ void unhandled_exception(); }; template -struct std::coroutine_traits { using promise_type = promise; }; +struct std::experimental::coroutine_traits { using promise_type = promise; }; namespace std { +namespace experimental { template struct coroutine_handle { static coroutine_handle from_address(void *) noexcept; }; -} // namespace std +}} // namespace std::experimental )cpp")); StringRef CoReturnCode = R"cpp( #include