Index: clang/include/clang/Basic/DiagnosticGroups.td =================================================================== --- clang/include/clang/Basic/DiagnosticGroups.td +++ clang/include/clang/Basic/DiagnosticGroups.td @@ -58,7 +58,9 @@ DiagGroup<"deprecated-experimental-coroutine">; def DeprecatedCoroutine : DiagGroup<"deprecated-coroutine", [DeprecatedExperimentalCoroutine]>; -def Coroutine : DiagGroup<"coroutine", [CoroutineMissingUnhandledException, DeprecatedCoroutine]>; +def AlwaysInlineCoroutine : + DiagGroup<"always-inline-coroutine">; +def Coroutine : DiagGroup<"coroutine", [CoroutineMissingUnhandledException, DeprecatedCoroutine, AlwaysInlineCoroutine]>; def ObjCBoolConstantConversion : DiagGroup<"objc-bool-constant-conversion">; def ConstantConversion : DiagGroup<"constant-conversion", [BitFieldConstantConversion, Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -11107,6 +11107,11 @@ def note_coroutine_function_declare_noexcept : Note< "must be declared with 'noexcept'" >; +def warn_always_inline_coroutine : Warning< + "a coroutine would be splitted into pieces and not every piece of coroutine " + "would be guaranteed to be inlined" + >, + InGroup; } // end of coroutines issue category let CategoryName = "Documentation Issue" in { Index: clang/lib/Sema/SemaCoroutine.cpp =================================================================== --- clang/lib/Sema/SemaCoroutine.cpp +++ clang/lib/Sema/SemaCoroutine.cpp @@ -1062,6 +1062,15 @@ return; } + // The coroutine marked always inline might not be inlined properly in current + // compiler support. Since the coroutine would be splitted into pieces. And + // the call to resume() and destroy() functions might be indirect call. Also + // the ramp function wouldn't get inlined under O0 due to pipeline ordering + // problems. It might be different to what users expects to. Emit a warning to + // tell it. + if (FD->hasAttr()) + Diag(FD->getLocation(), diag::warn_always_inline_coroutine); + // Coroutines [stmt.return]p1: // A return statement shall not appear in a coroutine. if (Fn->FirstReturnLoc.isValid()) { Index: clang/test/SemaCXX/coroutines.cpp =================================================================== --- clang/test/SemaCXX/coroutines.cpp +++ clang/test/SemaCXX/coroutines.cpp @@ -1443,3 +1443,8 @@ co_await missing_await_suspend{}; // expected-error {{no member named 'await_suspend' in 'missing_await_suspend'}} co_await missing_await_resume{}; // expected-error {{no member named 'await_resume' in 'missing_await_resume'}} } + +__attribute__((__always_inline__)) +void warn_always_inline() { // expected-warning {{a coroutine would be splitted into pieces and not every piece of coroutine would be guaranteed to be inlined}} + co_await suspend_always{}; +}