llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-libcxx Author: Yexuan Xiao (YexuanXiao) <details> <summary>Changes</summary> [Part1](https://github.com/llvm/llvm-project/pull/179189) addresses the code generation issue. When user code relies on Part1, this patch will issue a warning to indicate that the code requires improvement or contains defects, as HALO may not take effect and unexpected execution results may occur. This is achieved by introducing a new warning "-Winitial-suspend-throw". A considerable amount of existing code will indeed trigger this warning, but in most cases, marking a few functions as noexcept is sufficient to resolve the warning without affecting the behavior of the code itself. If users genuinely need to throw exceptions, they can disable the warning, though this scenario is typically rare. Note: This patch must be merged after Part1. Additionally, after merging Part1, the new warnings generated by Part1's tests need to be suppressed to avoid CI failures. --- Patch is 54.13 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/179192.diff 38 Files Affected: - (modified) clang/include/clang/Basic/DiagnosticGroups.td (+7-3) - (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+6) - (modified) clang/include/clang/Sema/Sema.h (+1) - (modified) clang/lib/Sema/SemaCoroutine.cpp (+42-13) - (modified) clang/test/CodeGenCoroutines/coro-halo.cpp (+1-1) - (modified) clang/test/CodeGenCoroutines/coro-init-await-nontrivial-return.cpp (+1-1) - (modified) clang/test/CodeGenCoroutines/pr56919.cpp (+1-1) - (modified) clang/test/SemaCXX/addr-label-in-coroutines.cpp (+1-1) - (modified) clang/test/SemaCXX/co_await-range-for.cpp (+4-4) - (modified) clang/test/SemaCXX/coreturn-eh.cpp (+2-2) - (modified) clang/test/SemaCXX/coreturn.cpp (+7-7) - (modified) clang/test/SemaCXX/coro-lifetimebound.cpp (+2-2) - (modified) clang/test/SemaCXX/coro-return-type-and-wrapper.cpp (+1-1) - (modified) clang/test/SemaCXX/coroutine-alloc-2.cpp (+1-1) - (modified) clang/test/SemaCXX/coroutine-alloc-3.cpp (+1-1) - (modified) clang/test/SemaCXX/coroutine-alloc-4.cpp (+6-6) - (modified) clang/test/SemaCXX/coroutine-allocs.cpp (+2-2) - (modified) clang/test/SemaCXX/coroutine-dealloc.cpp (+2-2) - (modified) clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp (+9-3) - (modified) clang/test/SemaCXX/coroutine-no-move-ctor.cpp (+1-1) - (modified) clang/test/SemaCXX/coroutine-no-valid-dealloc.cpp (+1-1) - (modified) clang/test/SemaCXX/coroutine-rvo.cpp (+2-2) - (modified) clang/test/SemaCXX/coroutine-unevaluate.cpp (+1-1) - (modified) clang/test/SemaCXX/coroutine-unhandled_exception-warning.cpp (+1-1) - (modified) clang/test/SemaCXX/coroutine-unreachable-warning.cpp (+1-1) - (modified) clang/test/SemaCXX/coroutine_handle-address-return-type.cpp (+1-1) - (added) clang/test/SemaCXX/coroutine_initial_suspend_exception_warning.cpp (+62) - (modified) clang/test/SemaCXX/coroutines.cpp (+36-36) - (modified) clang/test/SemaCXX/cxx2b-deducing-this-coro.cpp (+1-1) - (modified) clang/test/SemaCXX/type-aware-coroutines.cpp (+5-5) - (modified) clang/test/SemaCXX/warn-unsequenced-coro.cpp (+1-1) - (modified) libcxx/test/std/language.support/support.coroutines/coroutine.handle/coroutine.handle.prom/promise.pass.cpp (+1-1) - (modified) libcxx/test/std/language.support/support.coroutines/end.to.end/await_result.pass.cpp (+1-1) - (modified) libcxx/test/std/language.support/support.coroutines/end.to.end/bool_await_suspend.pass.cpp (+1-1) - (modified) libcxx/test/std/language.support/support.coroutines/end.to.end/expected.pass.cpp (+1-1) - (modified) libcxx/test/std/language.support/support.coroutines/end.to.end/fullexpr-dtor.pass.cpp (+1-1) - (modified) libcxx/test/std/language.support/support.coroutines/end.to.end/generator.pass.cpp (+2-2) - (modified) libcxx/test/std/language.support/support.coroutines/end.to.end/go.pass.cpp (+1-3) ``````````diff diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index d36ee57fe7651..1872a26f3cf09 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -69,9 +69,13 @@ def CoroNonAlignedAllocationFunction : DiagGroup<"coro-non-aligned-allocation-function">; def CoroTypeAwareAllocationFunction : DiagGroup<"coro-type-aware-allocation-function">; -def Coroutine : DiagGroup<"coroutine", [CoroutineMissingUnhandledException, DeprecatedCoroutine, - AlwaysInlineCoroutine, CoroNonAlignedAllocationFunction, - CoroTypeAwareAllocationFunction]>; +def InitialSuspendThrowing : DiagGroup<"initial-suspend-throw">; +def Coroutine + : DiagGroup<"coroutine", [CoroutineMissingUnhandledException, + DeprecatedCoroutine, AlwaysInlineCoroutine, + CoroNonAlignedAllocationFunction, + CoroTypeAwareAllocationFunction, + InitialSuspendThrowing]>; def ObjCBoolConstantConversion : DiagGroup<"objc-bool-constant-conversion">; def ConstantConversion : DiagGroup<"constant-conversion", [BitFieldConstantConversion, diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 807440c107897..c67fd393ecfe3 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12755,6 +12755,12 @@ def warn_coroutine_handle_address_invalid_return_type : Warning < def err_coroutine_promise_final_suspend_requires_nothrow : Error< "the expression 'co_await __promise.final_suspend()' is required to be non-throwing" >; +def warn_coroutine_promise_initial_suspend_throw + : Warning<"a potentially throwing 'co_await __promise.initial_suspend()' " + "may disable heap allocation elision; " + "if it throws, the coroutine return value and state are " + "destroyed in the reverse order of their construction">, + InGroup<InitialSuspendThrowing>; def note_coroutine_function_declare_noexcept : Note< "must be declared with 'noexcept'" >; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 0ba3daab764b7..4e88b77c26641 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3199,6 +3199,7 @@ class Sema final : public SemaBase { /// Check that the expression co_await promise.final_suspend() shall not be /// potentially-throwing. bool checkFinalSuspendNoThrow(const Stmt *FinalSuspend); + void warnInitialSuspendThrow(const Stmt *InitialSuspend); ///@} diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp index c0aba832dba94..a9b289e3c0b67 100644 --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -594,8 +594,12 @@ static FunctionScopeInfo *checkCoroutineContext(Sema &S, SourceLocation Loc, /// Recursively check \p E and all its children to see if any call target /// (including constructor call) is declared noexcept. Also any value returned /// from the call has a noexcept destructor. +/// +/// \param DiagID The error diagnostic ID to emit if a throwing function is +/// found. static void checkNoThrow(Sema &S, const Stmt *E, - llvm::SmallPtrSetImpl<const Decl *> &ThrowingDecls) { + llvm::SmallPtrSetImpl<const Decl *> &ThrowingDecls, + unsigned DiagID, bool InitialSuspend = false) { auto checkDeclNoexcept = [&](const Decl *D, bool IsDtor = false) { // In the case of dtor, the call to dtor is implicit and hence we should // pass nullptr to canCalleeThrow. @@ -608,17 +612,19 @@ static void checkNoThrow(Sema &S, const Stmt *E, // coroutine that just suspended, but rather throws back out from // whoever called coroutine_handle::resume(), hence we claim that // logically it does not throw. - if (FD->getBuiltinID() == Builtin::BI__builtin_coro_resume) + if (!InitialSuspend && + (FD->getBuiltinID() == Builtin::BI__builtin_coro_resume)) + return; + // the call to initial-suspend-resume is not part of the coroutine + // startup phase, so any exception thrown by it will be handled by + // unhandled_exception. Therefore, it need to be excluded. + if (InitialSuspend && FD->getIdentifier() && + (FD->getIdentifier()->getName() == "await_resume")) return; } if (ThrowingDecls.empty()) { - // [dcl.fct.def.coroutine]p15 - // The expression co_await promise.final_suspend() shall not be - // potentially-throwing ([except.spec]). - // // First time seeing an error, emit the error message. - S.Diag(cast<FunctionDecl>(S.CurContext)->getLocation(), - diag::err_coroutine_promise_final_suspend_requires_nothrow); + S.Diag(cast<FunctionDecl>(S.CurContext)->getLocation(), DiagID); } ThrowingDecls.insert(D); } @@ -648,28 +654,49 @@ static void checkNoThrow(Sema &S, const Stmt *E, for (const auto *Child : E->children()) { if (!Child) continue; - checkNoThrow(S, Child, ThrowingDecls); + checkNoThrow(S, Child, ThrowingDecls, DiagID, InitialSuspend); } } -bool Sema::checkFinalSuspendNoThrow(const Stmt *FinalSuspend) { +static bool checkSuspendNoThrow(Sema &S, const Stmt *SuspendExpr, + unsigned DiagID, bool InitialSuspend = false) { llvm::SmallPtrSet<const Decl *, 4> ThrowingDecls; // We first collect all declarations that should not throw but not declared // with noexcept. We then sort them based on the location before printing. // This is to avoid emitting the same note multiple times on the same // declaration, and also provide a deterministic order for the messages. - checkNoThrow(*this, FinalSuspend, ThrowingDecls); + checkNoThrow(S, SuspendExpr, ThrowingDecls, DiagID, InitialSuspend); + auto SortedDecls = llvm::SmallVector<const Decl *, 4>{ThrowingDecls.begin(), ThrowingDecls.end()}; sort(SortedDecls, [](const Decl *A, const Decl *B) { return A->getEndLoc() < B->getEndLoc(); }); for (const auto *D : SortedDecls) { - Diag(D->getEndLoc(), diag::note_coroutine_function_declare_noexcept); + S.Diag(D->getEndLoc(), diag::note_coroutine_function_declare_noexcept); } return ThrowingDecls.empty(); } +bool Sema::checkFinalSuspendNoThrow(const Stmt *FinalSuspend) { + // [dcl.fct.def.coroutine]p15 + // The expression co_await promise.final_suspend() shall not be + // potentially-throwing ([except.spec]). + return checkSuspendNoThrow( + *this, FinalSuspend, + diag::err_coroutine_promise_final_suspend_requires_nothrow); +} + +void Sema::warnInitialSuspendThrow(const Stmt *InitialSuspend) { + // CWG2935/PR177628 + // If a potentially thrown exception occurs before the call to + // initial-await-resume and the return value of the coroutine is constructed + // in-place, it prevents HALO and causes both the return value and the + // coroutine state to be destroyed in the reverse order of their construction. + checkSuspendNoThrow(*this, InitialSuspend, + diag::warn_coroutine_promise_initial_suspend_throw, true); +} + // [stmt.return.coroutine]p1: // A coroutine shall not enclose a return statement ([stmt.return]). static void checkReturnStmtInCoroutine(Sema &S, FunctionScopeInfo *FSI) { @@ -731,8 +758,10 @@ bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc, }; StmtResult InitSuspend = buildSuspends("initial_suspend"); - if (InitSuspend.isInvalid()) + if (InitSuspend.isInvalid()) { return true; + } + warnInitialSuspendThrow(InitSuspend.get()); StmtResult FinalSuspend = buildSuspends("final_suspend"); if (FinalSuspend.isInvalid() || !checkFinalSuspendNoThrow(FinalSuspend.get())) diff --git a/clang/test/CodeGenCoroutines/coro-halo.cpp b/clang/test/CodeGenCoroutines/coro-halo.cpp index e75bedaf81fa2..915e0efa9bbea 100644 --- a/clang/test/CodeGenCoroutines/coro-halo.cpp +++ b/clang/test/CodeGenCoroutines/coro-halo.cpp @@ -13,7 +13,7 @@ template <typename T> struct generator { this->current_value = value; return {}; } - std::suspend_always initial_suspend() { return {}; } + std::suspend_always initial_suspend() noexcept { return {}; } std::suspend_always final_suspend() noexcept { return {}; } generator get_return_object() { return generator{this}; }; void unhandled_exception() {} diff --git a/clang/test/CodeGenCoroutines/coro-init-await-nontrivial-return.cpp b/clang/test/CodeGenCoroutines/coro-init-await-nontrivial-return.cpp index 052b4e235e739..a6c8becf00fd4 100644 --- a/clang/test/CodeGenCoroutines/coro-init-await-nontrivial-return.cpp +++ b/clang/test/CodeGenCoroutines/coro-init-await-nontrivial-return.cpp @@ -69,7 +69,7 @@ struct NoexceptResumeTask { struct promise_type { void return_void() {} void unhandled_exception() {} - initial_suspend_awaiter initial_suspend() { return {}; } + initial_suspend_awaiter initial_suspend() noexcept { return {}; } std::suspend_never final_suspend() noexcept { return {}; } NoexceptResumeTask get_return_object() { return NoexceptResumeTask{handle_type::from_promise(*this)}; diff --git a/clang/test/CodeGenCoroutines/pr56919.cpp b/clang/test/CodeGenCoroutines/pr56919.cpp index baa8c27ce6649..84a27a302e607 100644 --- a/clang/test/CodeGenCoroutines/pr56919.cpp +++ b/clang/test/CodeGenCoroutines/pr56919.cpp @@ -30,7 +30,7 @@ class Task final { void unhandled_exception() {} - std::suspend_always initial_suspend() { return {}; } + std::suspend_always initial_suspend() noexcept { return {}; } auto await_transform(Task<void> co) { return await_transform(std::move(co.handle_.promise())); diff --git a/clang/test/SemaCXX/addr-label-in-coroutines.cpp b/clang/test/SemaCXX/addr-label-in-coroutines.cpp index 65d78636e5cdd..aa354a24c8525 100644 --- a/clang/test/SemaCXX/addr-label-in-coroutines.cpp +++ b/clang/test/SemaCXX/addr-label-in-coroutines.cpp @@ -5,7 +5,7 @@ struct resumable { struct promise_type { resumable get_return_object() { return {}; } - auto initial_suspend() { return std::suspend_always(); } + auto initial_suspend() noexcept { return std::suspend_always(); } auto final_suspend() noexcept { return std::suspend_always(); } void unhandled_exception() {} void return_void(){}; diff --git a/clang/test/SemaCXX/co_await-range-for.cpp b/clang/test/SemaCXX/co_await-range-for.cpp index 064a35038e1c7..898d042f4729e 100644 --- a/clang/test/SemaCXX/co_await-range-for.cpp +++ b/clang/test/SemaCXX/co_await-range-for.cpp @@ -42,7 +42,7 @@ struct MyForLoopArrayAwaiter { MyForLoopArrayAwaiter get_return_object() { return {}; } void return_void(); void unhandled_exception(); - suspend_never initial_suspend(); + suspend_never initial_suspend() noexcept; suspend_never final_suspend() noexcept; template <class T> Awaiter<T *> await_transform(T *) = delete; // expected-note {{explicitly deleted}} @@ -60,7 +60,7 @@ struct ForLoopAwaiterBadBeginTransform { ForLoopAwaiterBadBeginTransform get_return_object(); void return_void(); void unhandled_exception(); - suspend_never initial_suspend(); + suspend_never initial_suspend() noexcept; suspend_never final_suspend() noexcept; template <class T> @@ -94,7 +94,7 @@ struct ForLoopAwaiterBadIncTransform { ForLoopAwaiterBadIncTransform get_return_object(); void return_void(); void unhandled_exception(); - suspend_never initial_suspend(); + suspend_never initial_suspend() noexcept; suspend_never final_suspend() noexcept; template <class T> @@ -135,7 +135,7 @@ struct ForLoopAwaiterCoawaitLookup { ForLoopAwaiterCoawaitLookup get_return_object(); void return_void(); void unhandled_exception(); - suspend_never initial_suspend(); + suspend_never initial_suspend() noexcept; suspend_never final_suspend() noexcept; template <class T> CoawaitTag<T, false> await_transform(BeginTag<T> e); diff --git a/clang/test/SemaCXX/coreturn-eh.cpp b/clang/test/SemaCXX/coreturn-eh.cpp index 0d409b9b99bb6..e844df43a2626 100644 --- a/clang/test/SemaCXX/coreturn-eh.cpp +++ b/clang/test/SemaCXX/coreturn-eh.cpp @@ -16,7 +16,7 @@ struct object { ~object() {} }; struct promise_void_return_value { void get_return_object(); - suspend_always initial_suspend(); + suspend_always initial_suspend() noexcept; suspend_always final_suspend() noexcept; void unhandled_exception(); void return_value(object); @@ -25,7 +25,7 @@ struct promise_void_return_value { struct VoidTagReturnValue { struct promise_type { VoidTagReturnValue get_return_object(); - suspend_always initial_suspend(); + suspend_always initial_suspend() noexcept; suspend_always final_suspend() noexcept; void unhandled_exception(); void return_value(object); diff --git a/clang/test/SemaCXX/coreturn.cpp b/clang/test/SemaCXX/coreturn.cpp index 7069a1040db23..1a9be6c58e72e 100644 --- a/clang/test/SemaCXX/coreturn.cpp +++ b/clang/test/SemaCXX/coreturn.cpp @@ -12,7 +12,7 @@ struct awaitable { struct promise_void { void get_return_object(); - suspend_always initial_suspend(); + suspend_always initial_suspend() noexcept; suspend_always final_suspend() noexcept; void return_void(); void unhandled_exception(); @@ -20,7 +20,7 @@ struct promise_void { struct promise_void_return_value { void get_return_object(); - suspend_always initial_suspend(); + suspend_always initial_suspend() noexcept; suspend_always final_suspend() noexcept; void unhandled_exception(); void return_value(int); @@ -29,7 +29,7 @@ struct promise_void_return_value { struct VoidTagNoReturn { struct promise_type { VoidTagNoReturn get_return_object(); - suspend_always initial_suspend(); + suspend_always initial_suspend() noexcept; suspend_always final_suspend() noexcept; void unhandled_exception(); }; @@ -38,7 +38,7 @@ struct VoidTagNoReturn { struct VoidTagReturnValue { struct promise_type { VoidTagReturnValue get_return_object(); - suspend_always initial_suspend(); + suspend_always initial_suspend() noexcept; suspend_always final_suspend() noexcept; void unhandled_exception(); void return_value(int); @@ -48,7 +48,7 @@ struct VoidTagReturnValue { struct VoidTagReturnVoid { struct promise_type { VoidTagReturnVoid get_return_object(); - suspend_always initial_suspend(); + suspend_always initial_suspend() noexcept; suspend_always final_suspend() noexcept; void unhandled_exception(); void return_void(); @@ -57,7 +57,7 @@ struct VoidTagReturnVoid { struct promise_float { float get_return_object(); - suspend_always initial_suspend(); + suspend_always initial_suspend() noexcept; suspend_always final_suspend() noexcept; void return_void(); void unhandled_exception(); @@ -65,7 +65,7 @@ struct promise_float { struct promise_int { int get_return_object(); - suspend_always initial_suspend(); + suspend_always initial_suspend() noexcept; suspend_always final_suspend() noexcept; void return_value(int); void unhandled_exception(); diff --git a/clang/test/SemaCXX/coro-lifetimebound.cpp b/clang/test/SemaCXX/coro-lifetimebound.cpp index 9e96a296562a0..897dd8140050d 100644 --- a/clang/test/SemaCXX/coro-lifetimebound.cpp +++ b/clang/test/SemaCXX/coro-lifetimebound.cpp @@ -10,7 +10,7 @@ template <typename T> struct [[clang::coro_lifetimebound, clang::coro_return_typ Co<T> get_return_object() { return {}; } - suspend_always initial_suspend(); + suspend_always initial_suspend() noexcept; suspend_always final_suspend() noexcept; void unhandled_exception(); void return_value(const T &t); @@ -151,7 +151,7 @@ template <typename T> struct [[clang::coro_lifetimebound]] CoNoCRT { CoNoCRT<T> get_return_object() { return {}; } - suspend_always initial_suspend(); + suspend_always initial_suspend() noexcept; suspend_always final_suspend() noexcept; void unhandled_exception(); void return_value(const T &t); diff --git a/clang/test/SemaCXX/coro-return-type-and-wrapper.cpp b/clang/test/SemaCXX/coro-return-type-and-wrapper.cpp index b08e1c9c065a0..c111906f3c5c9 100644 --- a/clang/test/SemaCXX/coro-return-type-and-wrapper.cpp +++ b/clang/test/SemaCXX/coro-return-type-and-wrapper.cpp @@ -22,7 +22,7 @@ template <typename T> struct [[clang::coro_return_type]] Gen { static Gen<T> get_return_object_on_allocation_failure() { return {}; } - suspend_always initial_suspend(); + suspend_always initial_suspend() noexcept; suspend_always final_suspend() noexcept; void unhandled_exception(); void return_value(T t); diff --git a/clang/test/SemaCXX/coroutine-alloc-2.cpp b/clang/test/SemaCXX/coroutine-alloc-2.cpp index bcebadc0a1f53..b8697cbad9437 100644 --- a/clang/test/SemaCXX/coroutine-alloc-2.cpp +++ b/clang/test/SemaCXX/coroutine-alloc-2.cpp @@ -38,7 +38,7 @@ template <> struct std::coroutine_traits<int, promise_on_alloc_failure_tag> { struct promise_type { int get_return_object() { return 0; } - std::suspend_always initial_suspend() { return {}; } + std::suspend_always initial_suspend() noexcept { return {}; } std::suspend_always final_suspend() noexcept { return {}; } void return_void() {} void unhandled_exception() {} diff --git a/clang/test/SemaCXX/coroutine-alloc-3.cpp b/clang/test/SemaCXX/coroutine-alloc-3.cpp index 629ac88a3df8e..0eb5f94cd274e 100644 --- a/clang/test/SemaCXX/coroutine-alloc-3.cpp +++ b/clang/test/SemaCXX/coroutine-alloc-3.cpp @@ -38,7 +38,7 @@ template <> struct std::coroutine_traits<int, promise_on_alloc_failure_tag> { struct promise_type { int get_return_object() { return 0; } - std::suspend_always initial_suspend() { return {}; } + std::suspend_always initial_suspend() noexcept { return {}; } std::suspend_always final_suspend() noexcept { return {}; } void return_void() {} void unhandled_exception() {} diff --git a/clang/test/SemaCXX/coroutine-alloc-4.cpp b/clang/test/SemaCXX/coroutine-alloc-4.cpp index 262c163fb1789..84383b99ed1c7 100644 --- a/clang/test/SemaCXX/coroutine-alloc-4.cpp +++ b/clang/test/SemaCXX/coroutine-alloc-4.cpp @@ -10,7 +10,7 @@ namespace std { struct task { struct promise_type { - auto initial_suspend() { return std::suspend_always{}; } + auto initial_suspend() noexcept { return std::suspend_always{}; } auto final_suspend() noexcept { return std::suspend_always{}; } auto get_return_object() { return task{}; } void unhandled_exception() {} @@ -25,7 +25,7 @@ task f() { struct task2 { struct promise_type { - auto initial_suspend() { return std::suspend_always{}; } + auto initial_suspend() noexcept { return std::suspend_always{}; } auto final_suspend() noexcept { return std::suspend_always{}; } auto get_return_object() { return task2{}; } void unhandled_exception() {} @@ -41,7 +41,7 @@ task2 f1() { struct task3 { struct promise_type { - auto initial_suspend() { return std::suspend_always{}; } + auto initial_suspend() noexcept { return std::suspend_always{}; } auto final_suspend() noexcept { return std::suspend_always{}; } auto get_return_object() { return task3{}; } void unhandled_exception() {} @@ -59,7 +59,7 @@ task3 f2() { struct task4 { struct promise_type { - auto initial_suspend() { return std::suspend_always{}; } + auto initial_suspend() noexcept { return std::suspend_always{}; } auto final_suspend() noexcept { return std::suspend_always{}; } auto get_return_object() { return task4{}; } void unhandled_exception() {} @@ -75,7 +75,7 @@ task4 f3(int, double, int) { struct task5 { struct promise_type { - auto initial_suspend() { return std::suspend_always{}; } + auto initial_suspend() noexcept { re... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/179192 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
