summaryrefslogtreecommitdiff
path: root/test/CodeGenCoroutines
diff options
context:
space:
mode:
Diffstat (limited to 'test/CodeGenCoroutines')
-rw-r--r--test/CodeGenCoroutines/coro-alloc.cpp61
-rw-r--r--test/CodeGenCoroutines/coro-await-resume-eh.cpp108
-rw-r--r--test/CodeGenCoroutines/coro-builtins.c3
-rw-r--r--test/CodeGenCoroutines/coro-eh-cleanup.cpp8
-rw-r--r--test/CodeGenCoroutines/coro-gro-nrvo.cpp87
-rw-r--r--test/CodeGenCoroutines/coro-params.cpp58
-rw-r--r--test/CodeGenCoroutines/coro-promise-dtor.cpp8
-rw-r--r--test/CodeGenCoroutines/coro-unhandled-exception.cpp14
-rw-r--r--test/CodeGenCoroutines/microsoft-abi-operator-coawait.cpp4
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);
}