[llvm] [clang-tools-extra] [clang] [RFC] Perform lifetime bound checks for arguments to coroutine (PR #69360)
https://github.com/usx95 closed https://github.com/llvm/llvm-project/pull/69360 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [RFC] Perform lifetime bound checks for arguments to coroutine (PR #69360)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/69360 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [RFC] Perform lifetime bound checks for arguments to coroutine (PR #69360)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/69360 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [RFC] Perform lifetime bound checks for arguments to coroutine (PR #69360)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/69360 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [RFC] Perform lifetime bound checks for arguments to coroutine (PR #69360)
https://github.com/ChuanqiXu9 commented: Thanks for bringing this! I didn't notice the post in discourse and I'll put higher level comments there. https://github.com/llvm/llvm-project/pull/69360 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [RFC] Perform lifetime bound checks for arguments to coroutine (PR #69360)
https://github.com/ChuanqiXu9 edited https://github.com/llvm/llvm-project/pull/69360 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [RFC] Perform lifetime bound checks for arguments to coroutine (PR #69360)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/69360 >From be3f5faa6cd17d76f26fb1bc6d6b59a8a78ffe82 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Tue, 17 Oct 2023 19:37:28 +0200 Subject: [PATCH 1/2] Lifetime bound check for coroutine --- clang/lib/Sema/SemaInit.cpp | 16 +- .../SemaCXX/coroutine-lifetimebound-args.cpp | 184 ++ 2 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 clang/test/SemaCXX/coroutine-lifetimebound-args.cpp diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index fd95b16b84b6e3a..54e72b220bc47a4 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -7607,11 +7607,23 @@ static void visitLifetimeBoundArguments(IndirectLocalPath , Expr *Call, if (ObjectArg && implicitObjectParamIsLifetimeBound(Callee)) VisitLifetimeBoundArg(Callee, ObjectArg); - + bool checkCoroCall = false; + if (const auto *RD = Callee->getReturnType()->getAsRecordDecl()) { +for (const auto : + RD->getUnderlyingDecl()->specific_attrs()) { + // Only for demonstration: Get feedback and add a clang annotation as an + // extension. + if (attr->getAnnotation() == "coro_type") { + +checkCoroCall = true; +break; + } +} + } for (unsigned I = 0, N = std::min(Callee->getNumParams(), Args.size()); I != N; ++I) { -if (Callee->getParamDecl(I)->hasAttr()) +if (checkCoroCall || Callee->getParamDecl(I)->hasAttr()) VisitLifetimeBoundArg(Callee->getParamDecl(I), Args[I]); } } diff --git a/clang/test/SemaCXX/coroutine-lifetimebound-args.cpp b/clang/test/SemaCXX/coroutine-lifetimebound-args.cpp new file mode 100644 index 000..4cc5730ef896581 --- /dev/null +++ b/clang/test/SemaCXX/coroutine-lifetimebound-args.cpp @@ -0,0 +1,184 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++20 -fsyntax-only -verify -Wall -Wextra -Wno-error=unreachable-code -Wno-unused + +#include "Inputs/std-coroutine.h" + +using std::suspend_always; +using std::suspend_never; + + +#define CORO_TYPE [[clang::annotate("coro_type")]] +#define CORO_UNSAFE [[clang::annotate("coro_unsafe")]] + +template struct CORO_TYPE Gen { + struct promise_type { +Gen get_return_object() { + return {}; +} +suspend_always initial_suspend(); +suspend_always final_suspend() noexcept; +void unhandled_exception(); +void return_value(const T ); + +template +auto await_transform(const Gen &) { + struct awaitable { +bool await_ready() noexcept { return false; } +void await_suspend(std::coroutine_handle<>) noexcept {} +U await_resume() noexcept { return {}; } + }; + return awaitable{}; +} + }; +}; + +template using Co = Gen; + +Gen foo_coro(const int& b); + +Gen plain_return_foo_decl(int b) { + return foo_coro(b); // expected-warning {{address of stack memory associated with parameter}} +} + +Gen foo_coro(const int& b) { + if (b > 0) +co_return 1; + co_return 2; +} + +int getInt() { return 0; } + +Co bar_coro(const int , int c) { + int x = co_await foo_coro(b); + int y = co_await foo_coro(1); + int z = co_await foo_coro(getInt()); + auto unsafe1 = foo_coro(1); // expected-warning {{temporary whose address is used as value of local variable}} + auto unsafe2 = foo_coro(getInt()); // expected-warning {{temporary whose address is used as value of local variable}} + auto safe1 = foo_coro(b); + auto safe2 = foo_coro(c); + co_return co_await foo_coro(co_await foo_coro(1)); +} + +Gen plain_return_co(int b) { + return foo_coro(b); // expected-warning {{address of stack memory associated with parameter}} +} + +Gen safe_forwarding(const int& b) { + return foo_coro(b); +} + +Gen unsafe_wrapper(int b) { + return safe_forwarding(b); // expected-warning {{address of stack memory associated with parameter}} +} + +Co complex_plain_return(int b) { + return b > 0 + ? foo_coro(1) // expected-warning {{returning address of local temporary object}} + : bar_coro(0, 1); // expected-warning {{returning address of local temporary object}} +} + +void lambdas() { + auto unsafe_lambda = [](int b) { +return foo_coro(b); // expected-warning {{address of stack memory associated with parameter}} + }; + auto safe_lambda = [](int b) -> Co { +int x = co_await foo_coro(1); +co_return x + co_await foo_coro(b); + }; +} +// = +// Safe usage when parameters are value +// = +namespace by_value { +Gen value_coro(int b) { co_return co_await foo_coro(b); } + +Gen wrapper1(int b) { return value_coro(b); } +Gen wrapper2(const int& b) { return value_coro(b); } +} + +// = +// std::function like
[clang] [RFC] Perform lifetime bound checks for arguments to coroutine (PR #69360)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/69360 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [RFC] Perform lifetime bound checks for arguments to coroutine (PR #69360)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/69360 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [RFC] Perform lifetime bound checks for arguments to coroutine (PR #69360)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/69360 >From be3f5faa6cd17d76f26fb1bc6d6b59a8a78ffe82 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Tue, 17 Oct 2023 19:37:28 +0200 Subject: [PATCH] Lifetime bound check for coroutine --- clang/lib/Sema/SemaInit.cpp | 16 +- .../SemaCXX/coroutine-lifetimebound-args.cpp | 184 ++ 2 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 clang/test/SemaCXX/coroutine-lifetimebound-args.cpp diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index fd95b16b84b6e3a..54e72b220bc47a4 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -7607,11 +7607,23 @@ static void visitLifetimeBoundArguments(IndirectLocalPath , Expr *Call, if (ObjectArg && implicitObjectParamIsLifetimeBound(Callee)) VisitLifetimeBoundArg(Callee, ObjectArg); - + bool checkCoroCall = false; + if (const auto *RD = Callee->getReturnType()->getAsRecordDecl()) { +for (const auto : + RD->getUnderlyingDecl()->specific_attrs()) { + // Only for demonstration: Get feedback and add a clang annotation as an + // extension. + if (attr->getAnnotation() == "coro_type") { + +checkCoroCall = true; +break; + } +} + } for (unsigned I = 0, N = std::min(Callee->getNumParams(), Args.size()); I != N; ++I) { -if (Callee->getParamDecl(I)->hasAttr()) +if (checkCoroCall || Callee->getParamDecl(I)->hasAttr()) VisitLifetimeBoundArg(Callee->getParamDecl(I), Args[I]); } } diff --git a/clang/test/SemaCXX/coroutine-lifetimebound-args.cpp b/clang/test/SemaCXX/coroutine-lifetimebound-args.cpp new file mode 100644 index 000..4cc5730ef896581 --- /dev/null +++ b/clang/test/SemaCXX/coroutine-lifetimebound-args.cpp @@ -0,0 +1,184 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++20 -fsyntax-only -verify -Wall -Wextra -Wno-error=unreachable-code -Wno-unused + +#include "Inputs/std-coroutine.h" + +using std::suspend_always; +using std::suspend_never; + + +#define CORO_TYPE [[clang::annotate("coro_type")]] +#define CORO_UNSAFE [[clang::annotate("coro_unsafe")]] + +template struct CORO_TYPE Gen { + struct promise_type { +Gen get_return_object() { + return {}; +} +suspend_always initial_suspend(); +suspend_always final_suspend() noexcept; +void unhandled_exception(); +void return_value(const T ); + +template +auto await_transform(const Gen &) { + struct awaitable { +bool await_ready() noexcept { return false; } +void await_suspend(std::coroutine_handle<>) noexcept {} +U await_resume() noexcept { return {}; } + }; + return awaitable{}; +} + }; +}; + +template using Co = Gen; + +Gen foo_coro(const int& b); + +Gen plain_return_foo_decl(int b) { + return foo_coro(b); // expected-warning {{address of stack memory associated with parameter}} +} + +Gen foo_coro(const int& b) { + if (b > 0) +co_return 1; + co_return 2; +} + +int getInt() { return 0; } + +Co bar_coro(const int , int c) { + int x = co_await foo_coro(b); + int y = co_await foo_coro(1); + int z = co_await foo_coro(getInt()); + auto unsafe1 = foo_coro(1); // expected-warning {{temporary whose address is used as value of local variable}} + auto unsafe2 = foo_coro(getInt()); // expected-warning {{temporary whose address is used as value of local variable}} + auto safe1 = foo_coro(b); + auto safe2 = foo_coro(c); + co_return co_await foo_coro(co_await foo_coro(1)); +} + +Gen plain_return_co(int b) { + return foo_coro(b); // expected-warning {{address of stack memory associated with parameter}} +} + +Gen safe_forwarding(const int& b) { + return foo_coro(b); +} + +Gen unsafe_wrapper(int b) { + return safe_forwarding(b); // expected-warning {{address of stack memory associated with parameter}} +} + +Co complex_plain_return(int b) { + return b > 0 + ? foo_coro(1) // expected-warning {{returning address of local temporary object}} + : bar_coro(0, 1); // expected-warning {{returning address of local temporary object}} +} + +void lambdas() { + auto unsafe_lambda = [](int b) { +return foo_coro(b); // expected-warning {{address of stack memory associated with parameter}} + }; + auto safe_lambda = [](int b) -> Co { +int x = co_await foo_coro(1); +co_return x + co_await foo_coro(b); + }; +} +// = +// Safe usage when parameters are value +// = +namespace by_value { +Gen value_coro(int b) { co_return co_await foo_coro(b); } + +Gen wrapper1(int b) { return value_coro(b); } +Gen wrapper2(const int& b) { return value_coro(b); } +} + +// = +// std::function like
[clang] [RFC] Perform lifetime bound checks for arguments to coroutine (PR #69360)
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/69360 >From be3f5faa6cd17d76f26fb1bc6d6b59a8a78ffe82 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Tue, 17 Oct 2023 19:37:28 +0200 Subject: [PATCH] Lifetime bound check for coroutine --- clang/lib/Sema/SemaInit.cpp | 16 +- .../SemaCXX/coroutine-lifetimebound-args.cpp | 184 ++ 2 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 clang/test/SemaCXX/coroutine-lifetimebound-args.cpp diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index fd95b16b84b6e3a..54e72b220bc47a4 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -7607,11 +7607,23 @@ static void visitLifetimeBoundArguments(IndirectLocalPath , Expr *Call, if (ObjectArg && implicitObjectParamIsLifetimeBound(Callee)) VisitLifetimeBoundArg(Callee, ObjectArg); - + bool checkCoroCall = false; + if (const auto *RD = Callee->getReturnType()->getAsRecordDecl()) { +for (const auto : + RD->getUnderlyingDecl()->specific_attrs()) { + // Only for demonstration: Get feedback and add a clang annotation as an + // extension. + if (attr->getAnnotation() == "coro_type") { + +checkCoroCall = true; +break; + } +} + } for (unsigned I = 0, N = std::min(Callee->getNumParams(), Args.size()); I != N; ++I) { -if (Callee->getParamDecl(I)->hasAttr()) +if (checkCoroCall || Callee->getParamDecl(I)->hasAttr()) VisitLifetimeBoundArg(Callee->getParamDecl(I), Args[I]); } } diff --git a/clang/test/SemaCXX/coroutine-lifetimebound-args.cpp b/clang/test/SemaCXX/coroutine-lifetimebound-args.cpp new file mode 100644 index 000..4cc5730ef896581 --- /dev/null +++ b/clang/test/SemaCXX/coroutine-lifetimebound-args.cpp @@ -0,0 +1,184 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++20 -fsyntax-only -verify -Wall -Wextra -Wno-error=unreachable-code -Wno-unused + +#include "Inputs/std-coroutine.h" + +using std::suspend_always; +using std::suspend_never; + + +#define CORO_TYPE [[clang::annotate("coro_type")]] +#define CORO_UNSAFE [[clang::annotate("coro_unsafe")]] + +template struct CORO_TYPE Gen { + struct promise_type { +Gen get_return_object() { + return {}; +} +suspend_always initial_suspend(); +suspend_always final_suspend() noexcept; +void unhandled_exception(); +void return_value(const T ); + +template +auto await_transform(const Gen &) { + struct awaitable { +bool await_ready() noexcept { return false; } +void await_suspend(std::coroutine_handle<>) noexcept {} +U await_resume() noexcept { return {}; } + }; + return awaitable{}; +} + }; +}; + +template using Co = Gen; + +Gen foo_coro(const int& b); + +Gen plain_return_foo_decl(int b) { + return foo_coro(b); // expected-warning {{address of stack memory associated with parameter}} +} + +Gen foo_coro(const int& b) { + if (b > 0) +co_return 1; + co_return 2; +} + +int getInt() { return 0; } + +Co bar_coro(const int , int c) { + int x = co_await foo_coro(b); + int y = co_await foo_coro(1); + int z = co_await foo_coro(getInt()); + auto unsafe1 = foo_coro(1); // expected-warning {{temporary whose address is used as value of local variable}} + auto unsafe2 = foo_coro(getInt()); // expected-warning {{temporary whose address is used as value of local variable}} + auto safe1 = foo_coro(b); + auto safe2 = foo_coro(c); + co_return co_await foo_coro(co_await foo_coro(1)); +} + +Gen plain_return_co(int b) { + return foo_coro(b); // expected-warning {{address of stack memory associated with parameter}} +} + +Gen safe_forwarding(const int& b) { + return foo_coro(b); +} + +Gen unsafe_wrapper(int b) { + return safe_forwarding(b); // expected-warning {{address of stack memory associated with parameter}} +} + +Co complex_plain_return(int b) { + return b > 0 + ? foo_coro(1) // expected-warning {{returning address of local temporary object}} + : bar_coro(0, 1); // expected-warning {{returning address of local temporary object}} +} + +void lambdas() { + auto unsafe_lambda = [](int b) { +return foo_coro(b); // expected-warning {{address of stack memory associated with parameter}} + }; + auto safe_lambda = [](int b) -> Co { +int x = co_await foo_coro(1); +co_return x + co_await foo_coro(b); + }; +} +// = +// Safe usage when parameters are value +// = +namespace by_value { +Gen value_coro(int b) { co_return co_await foo_coro(b); } + +Gen wrapper1(int b) { return value_coro(b); } +Gen wrapper2(const int& b) { return value_coro(b); } +} + +// = +// std::function like
[clang] [RFC] Perform lifetime bound checks for arguments to coroutine (PR #69360)
github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning: You can test this locally with the following command: ``bash git-clang-format --diff 4480e650b3cf7cc63cfd3767cd6b120f8bfad2ac be3f5faa6cd17d76f26fb1bc6d6b59a8a78ffe82 -- clang/test/SemaCXX/coroutine-lifetimebound-args.cpp clang/lib/Sema/SemaInit.cpp `` View the diff from clang-format here. ``diff diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 54e72b220bc4..52e05b62e505 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -7614,7 +7614,7 @@ static void visitLifetimeBoundArguments(IndirectLocalPath , Expr *Call, // Only for demonstration: Get feedback and add a clang annotation as an // extension. if (attr->getAnnotation() == "coro_type") { - + checkCoroCall = true; break; } `` https://github.com/llvm/llvm-project/pull/69360 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [RFC] Perform lifetime bound checks for arguments to coroutine (PR #69360)
https://github.com/usx95 created https://github.com/llvm/llvm-project/pull/69360 None >From be3f5faa6cd17d76f26fb1bc6d6b59a8a78ffe82 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Tue, 17 Oct 2023 19:37:28 +0200 Subject: [PATCH] Lifetime bound check for coroutine --- clang/lib/Sema/SemaInit.cpp | 16 +- .../SemaCXX/coroutine-lifetimebound-args.cpp | 184 ++ 2 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 clang/test/SemaCXX/coroutine-lifetimebound-args.cpp diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index fd95b16b84b6e3a..54e72b220bc47a4 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -7607,11 +7607,23 @@ static void visitLifetimeBoundArguments(IndirectLocalPath , Expr *Call, if (ObjectArg && implicitObjectParamIsLifetimeBound(Callee)) VisitLifetimeBoundArg(Callee, ObjectArg); - + bool checkCoroCall = false; + if (const auto *RD = Callee->getReturnType()->getAsRecordDecl()) { +for (const auto : + RD->getUnderlyingDecl()->specific_attrs()) { + // Only for demonstration: Get feedback and add a clang annotation as an + // extension. + if (attr->getAnnotation() == "coro_type") { + +checkCoroCall = true; +break; + } +} + } for (unsigned I = 0, N = std::min(Callee->getNumParams(), Args.size()); I != N; ++I) { -if (Callee->getParamDecl(I)->hasAttr()) +if (checkCoroCall || Callee->getParamDecl(I)->hasAttr()) VisitLifetimeBoundArg(Callee->getParamDecl(I), Args[I]); } } diff --git a/clang/test/SemaCXX/coroutine-lifetimebound-args.cpp b/clang/test/SemaCXX/coroutine-lifetimebound-args.cpp new file mode 100644 index 000..4cc5730ef896581 --- /dev/null +++ b/clang/test/SemaCXX/coroutine-lifetimebound-args.cpp @@ -0,0 +1,184 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++20 -fsyntax-only -verify -Wall -Wextra -Wno-error=unreachable-code -Wno-unused + +#include "Inputs/std-coroutine.h" + +using std::suspend_always; +using std::suspend_never; + + +#define CORO_TYPE [[clang::annotate("coro_type")]] +#define CORO_UNSAFE [[clang::annotate("coro_unsafe")]] + +template struct CORO_TYPE Gen { + struct promise_type { +Gen get_return_object() { + return {}; +} +suspend_always initial_suspend(); +suspend_always final_suspend() noexcept; +void unhandled_exception(); +void return_value(const T ); + +template +auto await_transform(const Gen &) { + struct awaitable { +bool await_ready() noexcept { return false; } +void await_suspend(std::coroutine_handle<>) noexcept {} +U await_resume() noexcept { return {}; } + }; + return awaitable{}; +} + }; +}; + +template using Co = Gen; + +Gen foo_coro(const int& b); + +Gen plain_return_foo_decl(int b) { + return foo_coro(b); // expected-warning {{address of stack memory associated with parameter}} +} + +Gen foo_coro(const int& b) { + if (b > 0) +co_return 1; + co_return 2; +} + +int getInt() { return 0; } + +Co bar_coro(const int , int c) { + int x = co_await foo_coro(b); + int y = co_await foo_coro(1); + int z = co_await foo_coro(getInt()); + auto unsafe1 = foo_coro(1); // expected-warning {{temporary whose address is used as value of local variable}} + auto unsafe2 = foo_coro(getInt()); // expected-warning {{temporary whose address is used as value of local variable}} + auto safe1 = foo_coro(b); + auto safe2 = foo_coro(c); + co_return co_await foo_coro(co_await foo_coro(1)); +} + +Gen plain_return_co(int b) { + return foo_coro(b); // expected-warning {{address of stack memory associated with parameter}} +} + +Gen safe_forwarding(const int& b) { + return foo_coro(b); +} + +Gen unsafe_wrapper(int b) { + return safe_forwarding(b); // expected-warning {{address of stack memory associated with parameter}} +} + +Co complex_plain_return(int b) { + return b > 0 + ? foo_coro(1) // expected-warning {{returning address of local temporary object}} + : bar_coro(0, 1); // expected-warning {{returning address of local temporary object}} +} + +void lambdas() { + auto unsafe_lambda = [](int b) { +return foo_coro(b); // expected-warning {{address of stack memory associated with parameter}} + }; + auto safe_lambda = [](int b) -> Co { +int x = co_await foo_coro(1); +co_return x + co_await foo_coro(b); + }; +} +// = +// Safe usage when parameters are value +// = +namespace by_value { +Gen value_coro(int b) { co_return co_await foo_coro(b); } + +Gen wrapper1(int b) { return value_coro(b); } +Gen wrapper2(const int& b) { return value_coro(b); } +} + +// = +// std::function