diff options
Diffstat (limited to 'test/CodeGenCoroutines')
-rw-r--r-- | test/CodeGenCoroutines/coro-alloc.cpp | 61 | ||||
-rw-r--r-- | test/CodeGenCoroutines/coro-await-resume-eh.cpp | 108 | ||||
-rw-r--r-- | test/CodeGenCoroutines/coro-builtins.c | 3 | ||||
-rw-r--r-- | test/CodeGenCoroutines/coro-eh-cleanup.cpp | 8 | ||||
-rw-r--r-- | test/CodeGenCoroutines/coro-gro-nrvo.cpp | 87 | ||||
-rw-r--r-- | test/CodeGenCoroutines/coro-params.cpp | 58 | ||||
-rw-r--r-- | test/CodeGenCoroutines/coro-promise-dtor.cpp | 8 | ||||
-rw-r--r-- | test/CodeGenCoroutines/coro-unhandled-exception.cpp | 14 | ||||
-rw-r--r-- | test/CodeGenCoroutines/microsoft-abi-operator-coawait.cpp | 4 |
9 files changed, 333 insertions, 18 deletions
diff --git a/test/CodeGenCoroutines/coro-alloc.cpp b/test/CodeGenCoroutines/coro-alloc.cpp index 820201db357fd..20b00d4fec21c 100644 --- a/test/CodeGenCoroutines/coro-alloc.cpp +++ b/test/CodeGenCoroutines/coro-alloc.cpp @@ -106,6 +106,60 @@ extern "C" void f1(promise_new_tag ) { co_return; } +struct promise_matching_placement_new_tag {}; + +template<> +struct std::experimental::coroutine_traits<void, promise_matching_placement_new_tag, int, float, double> { + struct promise_type { + void *operator new(unsigned long, promise_matching_placement_new_tag, + int, float, double); + void get_return_object() {} + suspend_always initial_suspend() { return {}; } + suspend_always final_suspend() { return {}; } + void return_void() {} + }; +}; + +// CHECK-LABEL: f1a( +extern "C" void f1a(promise_matching_placement_new_tag, int x, float y , double z) { + // CHECK: store i32 %x, i32* %x.addr, align 4 + // CHECK: store float %y, float* %y.addr, align 4 + // CHECK: store double %z, double* %z.addr, align 8 + // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16 + // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64() + // 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* @_ZNSt12experimental16coroutine_traitsIJv34promise_matching_placement_new_tagifdEE12promise_typenwEmS1_ifd(i64 %[[SIZE]], i32 %[[INT]], float %[[FLOAT]], double %[[DOUBLE]]) + co_return; +} + +// Declare a placement form operator new, such as the one described in +// C++ 18.6.1.3.1, which takes a void* argument. +void* operator new(SizeT __sz, void *__p) noexcept; + +struct promise_matching_global_placement_new_tag {}; +struct dummy {}; +template<> +struct std::experimental::coroutine_traits<void, promise_matching_global_placement_new_tag, dummy*> { + struct promise_type { + void get_return_object() {} + suspend_always initial_suspend() { return {}; } + suspend_always final_suspend() { return {}; } + void return_void() {} + }; +}; + +// A coroutine that takes a single pointer argument should not invoke this +// placement form operator. [dcl.fct.def.coroutine]/7 dictates that lookup for +// allocation functions matching the coroutine function's signature be done +// within the scope of the promise type's class. +// CHECK-LABEL: f1b( +extern "C" void f1b(promise_matching_global_placement_new_tag, dummy *) { + // CHECK: call i8* @_Znwm(i64 + co_return; +} + struct promise_delete_tag {}; template<> @@ -173,6 +227,7 @@ struct std::experimental::coroutine_traits<int, promise_on_alloc_failure_tag> { // CHECK-LABEL: f4( extern "C" int f4(promise_on_alloc_failure_tag) { // CHECK: %[[RetVal:.+]] = alloca i32 + // CHECK: %[[Gro:.+]] = alloca i32 // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16 // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64() // CHECK: %[[MEM:.+]] = call i8* @_ZnwmRKSt9nothrow_t(i64 %[[SIZE]], %"struct.std::nothrow_t"* dereferenceable(1) @_ZStL7nothrow) @@ -186,7 +241,11 @@ extern "C" int f4(promise_on_alloc_failure_tag) { // CHECK: [[OKBB]]: // CHECK: %[[OkRet:.+]] = call i32 @_ZNSt12experimental16coroutine_traitsIJi28promise_on_alloc_failure_tagEE12promise_type17get_return_objectEv( - // CHECK: store i32 %[[OkRet]], i32* %[[RetVal]] + // CHECK: store i32 %[[OkRet]], i32* %[[Gro]] + + // CHECK: %[[Tmp1:.*]] = load i32, i32* %[[Gro]] + // CHECK-NEXT: store i32 %[[Tmp1]], i32* %[[RetVal]] + // CHECK-NEXT: br label %[[RetBB]] // CHECK: [[RetBB]]: // CHECK: %[[LoadRet:.+]] = load i32, i32* %[[RetVal]], align 4 diff --git a/test/CodeGenCoroutines/coro-await-resume-eh.cpp b/test/CodeGenCoroutines/coro-await-resume-eh.cpp new file mode 100644 index 0000000000000..f0f8855fbd4d3 --- /dev/null +++ b/test/CodeGenCoroutines/coro-await-resume-eh.cpp @@ -0,0 +1,108 @@ +// Test the behavior of http://wg21.link/P0664, a proposal to catch any +// exceptions thrown after the initial suspend point of a coroutine by +// executing the handler specified by the promise type's 'unhandled_exception' +// member function. +// +// RUN: %clang_cc1 -std=c++14 -fcoroutines-ts \ +// RUN: -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s \ +// RUN: -fexceptions -fcxx-exceptions -disable-llvm-passes \ +// RUN: | FileCheck %s + +#include "Inputs/coroutine.h" + +namespace coro = std::experimental::coroutines_v1; + +struct throwing_awaitable { + bool await_ready() { return true; } + void await_suspend(coro::coroutine_handle<>) {} + void await_resume() { throw 42; } +}; + +struct throwing_task { + struct promise_type { + auto get_return_object() { return throwing_task{}; } + auto initial_suspend() { return throwing_awaitable{}; } + auto final_suspend() { return coro::suspend_never{}; } + void return_void() {} + void unhandled_exception() {} + }; +}; + +// CHECK-LABEL: define void @_Z1fv() +throwing_task f() { + // A variable RESUMETHREW is used to keep track of whether the body + // of 'await_resume' threw an exception. Exceptions thrown in + // 'await_resume' are unwound to RESUMELPAD. + // CHECK: init.ready: + // CHECK-NEXT: store i1 true, i1* %[[RESUMETHREW:.+]], align 1 + // CHECK-NEXT: invoke void @_ZN18throwing_awaitable12await_resumeEv + // CHECK-NEXT: to label %[[RESUMECONT:.+]] unwind label %[[RESUMELPAD:.+]] + + // If 'await_resume' does not throw an exception, 'false' is stored in + // variable RESUMETHREW. + // CHECK: [[RESUMECONT]]: + // CHECK-NEXT: store i1 false, i1* %[[RESUMETHREW]] + // CHECK-NEXT: br label %[[RESUMETRYCONT:.+]] + + // 'unhandled_exception' is called for the exception thrown in + // 'await_resume'. The variable RESUMETHREW is never set to false, + // and a jump is made to RESUMETRYCONT. + // CHECK: [[RESUMELPAD]]: + // CHECK: br label %[[RESUMECATCH:.+]] + // CHECK: [[RESUMECATCH]]: + // CHECK: invoke void @_ZN13throwing_task12promise_type19unhandled_exceptionEv + // CHECK-NEXT: to label %[[RESUMEENDCATCH:.+]] unwind label + // CHECK: [[RESUMEENDCATCH]]: + // CHECK-NEXT: invoke void @__cxa_end_catch() + // CHECK-NEXT: to label %[[RESUMEENDCATCHCONT:.+]] unwind label + // CHECK: [[RESUMEENDCATCHCONT]]: + // CHECK-NEXT: br label %[[RESUMETRYCONT]] + + // The variable RESUMETHREW is loaded and if true, then 'await_resume' + // threw an exception and the coroutine body is skipped, and the final + // suspend is executed immediately. Otherwise, the coroutine body is + // executed, and then the final suspend. + // CHECK: [[RESUMETRYCONT]]: + // CHECK-NEXT: %[[RESUMETHREWLOAD:.+]] = load i1, i1* %[[RESUMETHREW]] + // CHECK-NEXT: br i1 %[[RESUMETHREWLOAD]], label %[[RESUMEDCONT:.+]], label %[[RESUMEDBODY:.+]] + + // CHECK: [[RESUMEDBODY]]: + // CHECK: invoke void @_ZN13throwing_task12promise_type11return_voidEv + // CHECK-NEXT: to label %[[REDUMEDBODYCONT:.+]] unwind label + // CHECK: [[REDUMEDBODYCONT]]: + // CHECK-NEXT: br label %[[COROFINAL:.+]] + + // CHECK: [[RESUMEDCONT]]: + // CHECK-NEXT: br label %[[COROFINAL]] + + // CHECK: [[COROFINAL]]: + // CHECK-NEXT: invoke void @_ZN13throwing_task12promise_type13final_suspendEv + co_return; +} + +struct noexcept_awaitable { + bool await_ready() { return true; } + void await_suspend(coro::coroutine_handle<>) {} + void await_resume() noexcept {} +}; + +struct noexcept_task { + struct promise_type { + auto get_return_object() { return noexcept_task{}; } + auto initial_suspend() { return noexcept_awaitable{}; } + auto final_suspend() { return coro::suspend_never{}; } + void return_void() {} + void unhandled_exception() {} + }; +}; + +// CHECK-LABEL: define void @_Z1gv() +noexcept_task g() { + // If the await_resume function is marked as noexcept, none of the additional + // conditions that are present in f() above are added to the IR. + // This means that no i1 are stored before or after calling await_resume: + // CHECK: init.ready: + // CHECK-NEXT: call void @_ZN18noexcept_awaitable12await_resumeEv + // CHECK-NOT: store i1 false, i1* + co_return; +} diff --git a/test/CodeGenCoroutines/coro-builtins.c b/test/CodeGenCoroutines/coro-builtins.c index 9ec2147642588..9800eef0ed819 100644 --- a/test/CodeGenCoroutines/coro-builtins.c +++ b/test/CodeGenCoroutines/coro-builtins.c @@ -17,6 +17,9 @@ void f(int n) { // CHECK-NEXT: call i1 @llvm.coro.alloc(token %[[COROID]]) __builtin_coro_alloc(); + // CHECK-NEXT: call i8* @llvm.coro.noop() + __builtin_coro_noop(); + // CHECK-NEXT: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64() // CHECK-NEXT: %[[MEM:.+]] = call i8* @myAlloc(i64 %[[SIZE]]) // CHECK-NEXT: %[[FRAME:.+]] = call i8* @llvm.coro.begin(token %[[COROID]], i8* %[[MEM]]) diff --git a/test/CodeGenCoroutines/coro-eh-cleanup.cpp b/test/CodeGenCoroutines/coro-eh-cleanup.cpp index 5a3ecd1da4949..9801151b4f140 100644 --- a/test/CodeGenCoroutines/coro-eh-cleanup.cpp +++ b/test/CodeGenCoroutines/coro-eh-cleanup.cpp @@ -45,18 +45,18 @@ coro_t f() { co_return; } -// CHECK: @"\01?f@@YA?AUcoro_t@@XZ"( -// CHECK: invoke void @"\01?may_throw@@YAXXZ"() +// CHECK: @"?f@@YA?AUcoro_t@@XZ"( +// CHECK: invoke void @"?may_throw@@YAXXZ"() // CHECK: to label %[[CONT:.+]] unwind label %[[EHCLEANUP:.+]] // CHECK: [[EHCLEANUP]]: // CHECK: %[[INNERPAD:.+]] = cleanuppad within none [] -// CHECK: call void @"\01??_DCleanup@@QEAAXXZ"( +// CHECK: call void @"??1Cleanup@@QEAA@XZ"( // CHECK: cleanupret from %{{.+}} unwind label %[[CATCHDISPATCH:.+]] // CHECK: [[CATCHDISPATCH]]: // CHECK: catchswitch within none [label %[[CATCHPAD:.+]]] unwind label %[[COROENDBB:.+]] // CHECK: [[CATCHPAD]]: -// CHECK: call void @"\01?unhandled_exception@promise_type@coro_t@@QEAAXXZ" +// CHECK: call void @"?unhandled_exception@promise_type@coro_t@@QEAAXXZ" // CHECK: [[COROENDBB]]: // CHECK-NEXT: %[[CLPAD:.+]] = cleanuppad within none diff --git a/test/CodeGenCoroutines/coro-gro-nrvo.cpp b/test/CodeGenCoroutines/coro-gro-nrvo.cpp new file mode 100644 index 0000000000000..48931cbf0dbc8 --- /dev/null +++ b/test/CodeGenCoroutines/coro-gro-nrvo.cpp @@ -0,0 +1,87 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s + +#include "Inputs/coroutine.h" + +using namespace std::experimental; + +namespace std { + +struct nothrow_t {}; +constexpr nothrow_t nothrow = {}; + +} // end namespace std + +// Required when get_return_object_on_allocation_failure() is defined by +// the promise. +void* operator new(__SIZE_TYPE__ __sz, const std::nothrow_t&) noexcept; +void operator delete(void* __p, const std::nothrow_t&) noexcept; + + +template <class RetObject> +struct promise_type { + RetObject get_return_object(); + suspend_always initial_suspend(); + suspend_never final_suspend(); + void return_void(); + static void unhandled_exception(); +}; + +struct coro { + using promise_type = promise_type<coro>; + coro(coro const&); + struct Impl; + Impl *impl; +}; + +// Verify that the NRVO is applied to the Gro object. +// CHECK-LABEL: define void @_Z1fi(%struct.coro* noalias sret %agg.result, i32) +coro f(int) { +// CHECK: %call = call i8* @_Znwm( +// CHECK-NEXT: br label %[[CoroInit:.*]] + +// CHECK: {{.*}}[[CoroInit]]: +// CHECK: store i1 false, i1* %gro.active +// CHECK: call void @{{.*get_return_objectEv}}(%struct.coro* sret %agg.result +// CHECK-NEXT: store i1 true, i1* %gro.active + co_return; +} + + +template <class RetObject> +struct promise_type_with_on_alloc_failure { + static RetObject get_return_object_on_allocation_failure(); + RetObject get_return_object(); + suspend_always initial_suspend(); + suspend_never final_suspend(); + void return_void(); + static void unhandled_exception(); +}; + +struct coro_two { + using promise_type = promise_type_with_on_alloc_failure<coro_two>; + coro_two(coro_two const&); + struct Impl; + Impl *impl; +}; + +// Verify that the NRVO is applied to the Gro object. +// CHECK-LABEL: define void @_Z1hi(%struct.coro_two* noalias sret %agg.result, i32) + coro_two h(int) { + +// CHECK: %call = call i8* @_ZnwmRKSt9nothrow_t +// CHECK-NEXT: %[[CheckNull:.*]] = icmp ne i8* %call, null +// CHECK-NEXT: br i1 %[[CheckNull]], label %[[InitOnSuccess:.*]], label %[[InitOnFailure:.*]] + +// CHECK: {{.*}}[[InitOnFailure]]: +// CHECK-NEXT: call void @{{.*get_return_object_on_allocation_failureEv}}(%struct.coro_two* sret %agg.result +// CHECK-NEXT: br label %[[RetLabel:.*]] + +// CHECK: {{.*}}[[InitOnSuccess]]: +// CHECK: store i1 false, i1* %gro.active +// CHECK: call void @{{.*get_return_objectEv}}(%struct.coro_two* sret %agg.result +// CHECK-NEXT: store i1 true, i1* %gro.active + +// CHECK: [[RetLabel]]: +// CHECK-NEXT: ret void + co_return; +} diff --git a/test/CodeGenCoroutines/coro-params.cpp b/test/CodeGenCoroutines/coro-params.cpp index 540f84585c8ea..d15286a52cb98 100644 --- a/test/CodeGenCoroutines/coro-params.cpp +++ b/test/CodeGenCoroutines/coro-params.cpp @@ -1,6 +1,7 @@ // Verifies that parameters are copied with move constructors // Verifies that parameter copies are destroyed // Vefifies that parameter copies are used in the body of the coroutine +// 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::experimental { @@ -68,12 +69,12 @@ void f(int val, MoveOnly moParam, MoveAndCopy mcParam) { // CHECK: store i32 %val, i32* %[[ValAddr:.+]] // CHECK: call i8* @llvm.coro.begin( - // CHECK-NEXT: call void @_ZN8MoveOnlyC1EOS_(%struct.MoveOnly* %[[MoCopy]], %struct.MoveOnly* dereferenceable(4) %[[MoParam]]) + // CHECK: call void @_ZN8MoveOnlyC1EOS_(%struct.MoveOnly* %[[MoCopy]], %struct.MoveOnly* dereferenceable(4) %[[MoParam]]) // CHECK-NEXT: call void @_ZN11MoveAndCopyC1EOS_(%struct.MoveAndCopy* %[[McCopy]], %struct.MoveAndCopy* dereferenceable(4) %[[McParam]]) # // CHECK-NEXT: invoke void @_ZNSt12experimental16coroutine_traitsIJvi8MoveOnly11MoveAndCopyEE12promise_typeC1Ev( // CHECK: call void @_ZN14suspend_always12await_resumeEv( - // CHECK: %[[IntParam:.+]] = load i32, i32* %val.addr + // CHECK: %[[IntParam:.+]] = load i32, i32* %val1 // CHECK: %[[MoGep:.+]] = getelementptr inbounds %struct.MoveOnly, %struct.MoveOnly* %[[MoCopy]], i32 0, i32 0 // CHECK: %[[MoVal:.+]] = load i32, i32* %[[MoGep]] // CHECK: %[[McGep:.+]] = getelementptr inbounds %struct.MoveAndCopy, %struct.MoveAndCopy* %[[McCopy]], i32 0, i32 0 @@ -127,3 +128,56 @@ struct B { void call_dependent_params() { dependent_params(A{}, B{}, B{}); } + +// Test that, when the promise type has a constructor whose signature matches +// that of the coroutine function, that constructor is used. This is an +// experimental feature that will be proposed for the Coroutines TS. + +struct promise_matching_constructor {}; + +template<> +struct std::experimental::coroutine_traits<void, promise_matching_constructor, int, float, double> { + struct promise_type { + promise_type(promise_matching_constructor, int, float, double) {} + promise_type() = delete; + void get_return_object() {} + suspend_always initial_suspend() { return {}; } + suspend_always final_suspend() { return {}; } + void return_void() {} + void unhandled_exception() {} + }; +}; + +// CHECK-LABEL: void @_Z38coroutine_matching_promise_constructor28promise_matching_constructorifd(i32, float, double) +void coroutine_matching_promise_constructor(promise_matching_constructor, int, float, double) { + // 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 @_ZNSt12experimental16coroutine_traitsIJv28promise_matching_constructorifdEE12promise_typeC1ES1_ifd(%"struct.std::experimental::coroutine_traits<void, promise_matching_constructor, int, float, double>::promise_type"* %__promise, i32 %[[INT]], float %[[FLOAT]], double %[[DOUBLE]]) + co_return; +} + +struct some_class; + +struct method {}; + +template <typename... Args> struct std::experimental::coroutine_traits<method, Args...> { + struct promise_type { + promise_type(some_class&, float); + method get_return_object(); + suspend_always initial_suspend(); + suspend_always final_suspend(); + void return_void(); + void unhandled_exception(); + }; +}; + +struct some_class { + method good_coroutine_calls_custom_constructor(float); +}; + +// 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 @_ZNSt12experimental16coroutine_traitsIJ6methodR10some_classfEE12promise_typeC1ES3_f(%"struct.std::experimental::coroutine_traits<method, some_class &, float>::promise_type"* %__promise, %struct.some_class* dereferenceable(1) %{{.+}}, float + co_return; +} diff --git a/test/CodeGenCoroutines/coro-promise-dtor.cpp b/test/CodeGenCoroutines/coro-promise-dtor.cpp index 4142cebe6132f..bc190c9d1cb52 100644 --- a/test/CodeGenCoroutines/coro-promise-dtor.cpp +++ b/test/CodeGenCoroutines/coro-promise-dtor.cpp @@ -28,12 +28,12 @@ coro_t f() { co_return; } -// CHECK-LABEL: define void @"\01?f@@YA?AUcoro_t@@XZ"( +// CHECK-LABEL: define dso_local void @"?f@@YA?AUcoro_t@@XZ"( // CHECK: %gro.active = alloca i1 // CHECK: store i1 false, i1* %gro.active -// CHECK: invoke %"struct.coro_t::promise_type"* @"\01??0promise_type@coro_t@@QEAA@XZ"( -// CHECK: invoke void @"\01?get_return_object@promise_type@coro_t@@QEAA?AU2@XZ"( +// CHECK: invoke %"struct.coro_t::promise_type"* @"??0promise_type@coro_t@@QEAA@XZ"( +// CHECK: invoke void @"?get_return_object@promise_type@coro_t@@QEAA?AU2@XZ"( // CHECK: store i1 true, i1* %gro.active // CHECK: %[[IS_ACTIVE:.+]] = load i1, i1* %gro.active @@ -44,4 +44,4 @@ coro_t f() { // CHECK: br i1 %[[NRVO]], label %{{.+}}, label %[[DTOR:.+]] // CHECK: [[DTOR]]: -// CHECK: call void @"\01??_Dcoro_t@@QEAAXXZ"( +// CHECK: call void @"??1coro_t@@QEAA@XZ"( diff --git a/test/CodeGenCoroutines/coro-unhandled-exception.cpp b/test/CodeGenCoroutines/coro-unhandled-exception.cpp index e26a51861d9f2..039f02352cfca 100644 --- a/test/CodeGenCoroutines/coro-unhandled-exception.cpp +++ b/test/CodeGenCoroutines/coro-unhandled-exception.cpp @@ -32,25 +32,27 @@ coro_t f() { co_return; } -// CHECK: @"\01?f@@YA?AUcoro_t@@XZ"( -// CHECK: invoke void @"\01?may_throw@@YAXXZ"() +// CHECK: @"?f@@YA?AUcoro_t@@XZ"( +// CHECK: invoke void @"?may_throw@@YAXXZ"() // CHECK: to label %{{.+}} unwind label %[[EHCLEANUP:.+]] // CHECK: [[EHCLEANUP]]: // CHECK: %[[INNERPAD:.+]] = cleanuppad within none [] -// CHECK: call void @"\01??_DCleanup@@QEAAXXZ"( +// CHECK: call void @"??1Cleanup@@QEAA@XZ"( // CHECK: cleanupret from %[[INNERPAD]] unwind label %[[CATCHSW:.+]] // CHECK: [[CATCHSW]]: // CHECK: %[[CATCHSWTOK:.+]] = catchswitch within none [label %[[CATCH:.+]]] unwind label // CHECK: [[CATCH]]: // CHECK: %[[CATCHTOK:.+]] = catchpad within [[CATCHSWTOK:.+]] -// CHECK: call void @"\01?unhandled_exception@promise_type@coro_t@@QEAAXXZ" +// CHECK: call void @"?unhandled_exception@promise_type@coro_t@@QEAAXXZ" // CHECK: catchret from %[[CATCHTOK]] to label %[[CATCHRETDEST:.+]] // CHECK: [[CATCHRETDEST]]: // CHECK-NEXT: br label %[[TRYCONT:.+]] // CHECK: [[TRYCONT]]: +// CHECK-NEXT: br label %[[RESUMECONT:.+]] +// CHECK: [[RESUMECONT]]: // CHECK-NEXT: br label %[[COROFIN:.+]] // CHECK: [[COROFIN]]: -// CHECK-NEXT: invoke void @"\01?final_suspend@promise_type@coro_t@@QEAA?AUsuspend_never@coroutines_v1@experimental@std@@XZ"( +// CHECK-NEXT: invoke void @"?final_suspend@promise_type@coro_t@@QEAA?AUsuspend_never@coroutines_v1@experimental@std@@XZ"( // CHECK-LPAD: @_Z1fv( // CHECK-LPAD: invoke void @_Z9may_throwv() @@ -67,6 +69,8 @@ coro_t f() { // CHECK-LPAD: [[CATCHRETDEST]]: // CHECK-LPAD-NEXT: br label %[[TRYCONT:.+]] // CHECK-LPAD: [[TRYCONT]]: +// CHECK-LPAD: br label %[[RESUMECONT:.+]] +// CHECK-LPAD: [[RESUMECONT]]: // CHECK-LPAD-NEXT: br label %[[COROFIN:.+]] // CHECK-LPAD: [[COROFIN]]: // CHECK-LPAD-NEXT: invoke void @_ZN6coro_t12promise_type13final_suspendEv( diff --git a/test/CodeGenCoroutines/microsoft-abi-operator-coawait.cpp b/test/CodeGenCoroutines/microsoft-abi-operator-coawait.cpp index 1921c06e5af03..26e3794930882 100644 --- a/test/CodeGenCoroutines/microsoft-abi-operator-coawait.cpp +++ b/test/CodeGenCoroutines/microsoft-abi-operator-coawait.cpp @@ -17,9 +17,9 @@ no_suspend operator co_await(B const&) { return {}; } extern "C" void f() { A a; B b; - // CHECK: call void @"\01??__LA@@QEAA?AUno_suspend@@XZ"( + // CHECK: call void @"??__LA@@QEAA?AUno_suspend@@XZ"( a.operator co_await(); - // CHECK-NEXT: call i8 @"\01??__L@YA?AUno_suspend@@AEBUB@@@Z"( + // CHECK-NEXT: call i8 @"??__L@YA?AUno_suspend@@AEBUB@@@Z"( operator co_await(b); } |