1 // The output of O0 is highly redundant and hard to test. Also it is not good 2 // limit the output of O0. So we test the optimized output from O0. The idea 3 // is the optimizations shouldn't change the semantics of the program. 4 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 \ 5 // RUN: -O0 -emit-llvm %s -o - -disable-O0-optnone \ 6 // RUN: | opt -passes='sroa,mem2reg,simplifycfg' -S | FileCheck %s --check-prefix=CHECK-O0 7 8 #include "Inputs/coroutine.h" 9 10 // A simple awaiter type with an await_suspend method that can't be 11 // inlined. 12 struct Awaiter { 13 const int& x; 14 await_readyAwaiter15 bool await_ready() { return false; } 16 std::coroutine_handle<> await_suspend(const std::coroutine_handle<> h); await_resumeAwaiter17 void await_resume() {} 18 }; 19 20 struct MyTask { 21 // A lazy promise with an await_transform method that supports awaiting 22 // integer references using the Awaiter struct above. 23 struct promise_type { get_return_objectMyTask::promise_type24 MyTask get_return_object() { 25 return MyTask{ 26 std::coroutine_handle<promise_type>::from_promise(*this), 27 }; 28 } 29 initial_suspendMyTask::promise_type30 std::suspend_always initial_suspend() { return {}; } final_suspendMyTask::promise_type31 std::suspend_always final_suspend() noexcept { return {}; } 32 void unhandled_exception(); 33 await_transformMyTask::promise_type34 auto await_transform(const int& x) { return Awaiter{x}; } 35 }; 36 37 std::coroutine_handle<> h; 38 }; 39 40 // A global array of integers. 41 int g_array[32]; 42 43 // A coroutine that awaits each integer in the global array. FooBar()44MyTask FooBar() { 45 for (const int& x : g_array) { 46 co_await x; 47 } 48 } 49 50 // CHECK-O0: define{{.*}}@_Z6FooBarv.resume 51 // CHECK-O0: call{{.*}}@_Z6FooBarv.__await_suspend_wrapper__await( 52 // CHECK-O0-NOT: store 53 // CHECK-O0: ret void 54