jbaldwin / libcoro

C++20 coroutine library
Apache License 2.0
599 stars 62 forks source link

MSVC compiler warning #191

Closed bjones1 closed 7 months ago

bjones1 commented 1 year ago

From the MSVC compiler:

D:\a\libcoro\libcoro\include\coro/when_all.hpp(447): warning C4033: 'coro::detail::make_when_all_task' must return a value 
[D:\a\libcoro\libcoro\build-release-cl\examples\coro_thread_pool.vcxproj]
D:\a\libcoro\libcoro\include\coro/when_all.hpp(447): message : Flowing off the end of a coroutine results in undefined behavior when
promise type 'coro::detail::when_all_task_promise<return_type>' does not declare 'return_void' [D:\a\libcoro\libcoro\build-release-cl\examples\coro_thread_pool.vcxproj]
          with
          [
              return_type=unsigned __int64 &&
          ]
D:\a\libcoro\libcoro\include\coro/when_all.hpp(475): message : see reference to function template instantiation
 'coro::detail::when_all_task<unsigned __int64 &&> coro::detail::make_when_all_task<coro::task<uint64_t>,unsigned __int64&&>
(awaitable)' being compiled [D:\a\libcoro\libcoro\build-release-cl\examples\coro_thread_pool.vcxproj]
          with
          [
              awaitable=coro::task<uint64_t>
          ]
D:\a\libcoro\libcoro\examples\coro_thread_pool.cpp(74): message : see reference to function template instantiation 
'coro::detail::when_all_ready_awaitable<std::vector<coro::detail::when_all_task<unsigned __int64 
&&>,std::allocator<coro::detail::when_all_task<unsigned __int64 &&>>>> 
coro::when_all<std::vector<coro::task<uint64_t>,std::allocator<coro::task<uint64_t>>>,coro::task<uint64_t>,unsigned __int64&&>
(range_type)' being compiled [D:\a\libcoro\libcoro\build-release-cl\examples\coro_thread_pool.vcxproj]
          with
          [
              range_type=std::vector<coro::task<uint64_t>,std::allocator<coro::task<uint64_t>>>
          ]

Unfortunately, I lack the C++ knowledge to fix this myself.

bjones1 commented 1 year ago

@a858438680. do you know how to fix this?

a858438680 commented 1 year ago

@a858438680. do you know how to fix this?

Yes, I know. Just don't use co_yield and change it to co_return and change some of the member functions in the promise type.

I tried to change this locally. But I can't tell why the author designed it this way. So I didn't create a pull request. You can ask him and if he thinks I'm right, I will create a PR.

bjones1 commented 1 year ago

@jbaldwin, are you open to a PR from @a858438680 which would fix this? Did you have any specific design goals in mind, or is s/he free to innovate?

jbaldwin commented 1 year ago

Honestly I don't remember why I did it this way a few years ago, looking at the code using co yield shouldn't be necessary. I'm definitely open to a PR to clean this up.

a858438680 commented 1 year ago

Honestly I don't remember why I did it this way a few years ago, looking at the code using co yield shouldn't be necessary. I'm definitely open to a PR to clean this up.

Here is the thing, I'm also glad to create a PR but I also thinks that the api of when_all is not proper, co_await a when_all_task should return the value of all tasks rather than get a container of some handles.

But if you think that it is ok now and does not want a broken change, I will create a PR which just cleans the warning. Otherwise, if you think that adding a new api or changing the behavior of co_await when_all is acceptable, please tell me you your opinion.

jbaldwin commented 1 year ago

The original intent behind the coro::when_all api is so that you can compose it with coro::sync_wait as well as co_await it within a coroutine. I realize now typing this out there is no test for coro::when_all within the test_when_all.cpp file so I'm going to add one. https://github.com/jbaldwin/libcoro/pull/197

Can you propose an API that would return the values directly that would work in both situations? Or would it require two implementations, one coro::when_all to work outside a coroutine context and another to work inside coroutine contexts? The former would mean all instances of coro::sync_wait(coro::when_all(...awaitables...)) would become coro::when_all(...awaitables...). If you have a way to make it work both ways without duplicating it I'd love to see that.

How would you handle multiple exceptions being thrown? Right now you get each one upon calling each output task's return_value() and can handle them individually, I think you'd need a std::variant<return_type, std::exception> type result to capture each one appropriately for the user.

jbaldwin commented 11 months ago

I'm kind of thinking something new coro::when_all_values(awaitable...) -> coro::generator<result<T, E>>, perhaps two APIs isn't the worst.

mscppppppppp commented 7 months ago

I've implemented a temporary solution to address the build warning and have also raised a pull request for it. @jbaldwin , when you have a moment, could you please take a look and provide your feedback?

jbaldwin commented 7 months ago

Thanks for taking the time to write this up to fix the warning.

jbaldwin commented 7 months ago

260