1 // RUN: %clang_cc1 -std=c++20 -triple=x86_64-pc-windows-msvc18.0.0 -emit-llvm %s -o - -fexceptions -fcxx-exceptions -disable-llvm-passes | FileCheck %s 2 // RUN: %clang_cc1 -std=c++20 -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -fexceptions -fcxx-exceptions -disable-llvm-passes | FileCheck --check-prefix=CHECK-LPAD %s 3 4 namespace std { 5 template <typename R, typename... T> struct coroutine_traits { 6 using promise_type = typename R::promise_type; 7 }; 8 9 template <class Promise = void> struct coroutine_handle; 10 11 template <> struct coroutine_handle<void> { 12 static coroutine_handle from_address(void *) noexcept; 13 coroutine_handle() = default; 14 template <class PromiseType> 15 coroutine_handle(coroutine_handle<PromiseType>) noexcept; 16 }; 17 template <class Promise> struct coroutine_handle: coroutine_handle<void> { 18 coroutine_handle() = default; 19 static coroutine_handle from_address(void *) noexcept; 20 }; 21 } // namespace std 22 23 struct suspend_always { 24 bool await_ready() noexcept; 25 void await_suspend(std::coroutine_handle<>) noexcept; 26 void await_resume() noexcept; 27 }; 28 29 struct coro_t { 30 struct promise_type { 31 coro_t get_return_object() noexcept; 32 suspend_always initial_suspend() noexcept; 33 suspend_always final_suspend() noexcept; 34 void return_void() noexcept; 35 void unhandled_exception() noexcept; 36 }; 37 }; 38 39 struct Cleanup { ~Cleanup(); }; 40 void may_throw(); 41 42 coro_t f() { 43 Cleanup x; 44 may_throw(); 45 co_return; 46 } 47 48 // CHECK: @"?f@@YA?AUcoro_t@@XZ"( 49 // CHECK: invoke void @"?may_throw@@YAXXZ"() 50 // CHECK: to label %[[CONT:.+]] unwind label %[[EHCLEANUP:.+]] 51 // CHECK: [[EHCLEANUP]]: 52 // CHECK: %[[INNERPAD:.+]] = cleanuppad within none [] 53 // CHECK: call void @"??1Cleanup@@QEAA@XZ"( 54 // CHECK: cleanupret from %{{.+}} unwind label %[[CATCHDISPATCH:.+]] 55 56 // CHECK: [[CATCHDISPATCH]]: 57 // CHECK: catchswitch within none [label %[[CATCHPAD:.+]]] unwind label %[[COROENDBB:.+]] 58 // CHECK: [[CATCHPAD]]: 59 // CHECK: call void @"?unhandled_exception@promise_type@coro_t@@QEAAXXZ" 60 61 // CHECK: [[COROENDBB]]: 62 // CHECK-NEXT: %[[CLPAD:.+]] = cleanuppad within none 63 // CHECK-NEXT: call i1 @llvm.coro.end(i8* null, i1 true) [ "funclet"(token %[[CLPAD]]) ] 64 // CHECK-NEXT: cleanupret from %[[CLPAD]] unwind label 65 66 // CHECK-LPAD: @_Z1fv( 67 // CHECK-LPAD: invoke void @_Z9may_throwv() 68 // CHECK-LPAD: to label %[[CONT:.+]] unwind label %[[EHCLEANUP:.+]] 69 // CHECK-LPAD: [[EHCLEANUP]]: 70 // CHECK-LPAD: landingpad { i8*, i32 } 71 // CHECK-LPAD: catch 72 // CHECK-LPAD: call void @_ZN7CleanupD1Ev( 73 // CHECK-LPAD: call i8* @__cxa_begin_catch 74 // CHECK-LPAD: call void @_ZN6coro_t12promise_type19unhandled_exceptionEv 75 // CHECK-LPAD: invoke void @__cxa_end_catch() 76 // CHECK-LPAD: to label %{{.+}} unwind label %[[UNWINDBB:.+]] 77 78 // CHECK-LPAD: [[UNWINDBB]]: 79 // CHECK-LPAD: %[[I1RESUME:.+]] = call i1 @llvm.coro.end(i8* null, i1 true) 80 // CHECK-LPAD: br i1 %[[I1RESUME]], label %[[EHRESUME:.+]], label 81 // CHECK-LPAD: [[EHRESUME]]: 82 // CHECK-LPAD-NEXT: %[[exn:.+]] = load i8*, i8** %exn.slot, align 8 83 // CHECK-LPAD-NEXT: %[[sel:.+]] = load i32, i32* %ehselector.slot, align 4 84 // CHECK-LPAD-NEXT: %[[val1:.+]] = insertvalue { i8*, i32 } undef, i8* %[[exn]], 0 85 // CHECK-LPAD-NEXT: %[[val2:.+]] = insertvalue { i8*, i32 } %[[val1]], i32 %[[sel]], 1 86 // CHECK-LPAD-NEXT: resume { i8*, i32 } %[[val2]] 87