Date: Thu, 30 Jan 2025 16:00:25 -0500
> Unfortunately C++ (language and/or library) cannot detect when a reference (or string_view or function_ref or whatever) refers to a temporary. We can detect value category, but value category is not lifetime. It's legal and not even uncommon for an rvalue reference to refer to a "long-lived-enough" object; and it's extremely common to have a (const) lvalue reference that refers to a short-lived temporary.
https://quuxplusone.github.io/blog/2019/03/11/value-category-is-not-lifetime/
I'm not an expert on the topic of coroutines, but I am wondering if std::coroutine_traits could be specialized for coroutines that returns a std::generator and which has any parameter of a type that is known to potentially refer to a temporary, then that specialization of std::coroutine_traits would have no promise_type member (thereby making the coroutine definition ill-formed). In particular, if the specialization for `std::coroutine_traits<std::generator<R, V, A>, Args...>` has no promise_type in the event that one Arg type in the pack is known to potentially refer or wrap a reference to a materialized temporary object. For instance, the usual 'T&&', 'T const&' and 'std::initializer_list', but possibly also non owning view types that convert from a prvalue.
On January 29, 2025 11:28:42 a.m. EST, Arthur O'Dwyer via Std-Proposals <std-proposals_at_[hidden]> wrote:
>On Wed, Jan 29, 2025 at 10:35 AM Peter Bindels via Std-Proposals <
>std-proposals_at_[hidden]> wrote:
>
>> On Wed, Jan 29, 2025 at 3:55 PM Karl Semich via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>>
>> > I'm trying out c++23 std::generator and noticing that I cannot safely
>> pass arguments to my generators that are temporaries such as
>> std::initializer_list. It seems like this is because promise_type's
>> initial_suspend returns suspend_always, so passed temporaries are out of
>> scope as soon as initial code is executed.
>
>> > Where can I read about this and best practices, or is it a mistake? It
>> looks like a mistake to me.
>
>Thanks, that wrapper solution is just the thing!
>>>
>>> I didn't find a way that move semantics would help with the argument
>>> case; the temporaries still go out of scope before data can be moved in
>>> (unless one uses a wrapper function, a patch, or writes their own
>>> generator).
>>> Given when a wrapper function is not used that the misbehavior is (a)
>>> severe, (b) undocumented, and (c) not reported by compilers and
>>> implementations, my personal opinion is still that this is a bug.
>>>
>>> The standard should clearly state that passing temporaries to a generator
>>> or defining temporary generators is illegal or at least undefined.
>>>
>>
>Unfortunately C++ (language and/or library) cannot detect when a reference
>(or string_view or function_ref or whatever) refers to a temporary. We can
>detect *value** category*, but value category is not lifetime. It's legal
>and not even uncommon for an rvalue reference to refer to a
>"long-lived-enough" object; and it's *extremely* common to have a (const)
>lvalue reference that refers to a short-lived temporary.
>https://quuxplusone.github.io/blog/2019/03/11/value-category-is-not-lifetime/
>
>
>
>> However, if generators executed eagerly, it would prevent a wide class of
>>> these memory corruption errors.
>>>
>>
>
>> This to me reads like a great argumentation to put into a paper, that can
>> be submitted for inclusion into C++26 or 29. If we have a
>> known-bug-inducing current setup, that is not used much, that we can then
>> still fix and have working in C++26/29, it would make sense to write a
>> paper & to see if it can be seen at Austria - or shortly after. Teaching
>> everybody "generator is kinda broken and you need to define this wrapper
>> function" seems counterproductive, when we can propose to change
>> "suspend_always" to "suspend_never" in one location and fix it for
>> everybody.
>>
>
>I agree that at first glance it *seems* like std::generator shouldn't
>suspend_always... but I'm sure there is some concrete reason that P2168
>made it suspend_never. Cc'ed the paper authors in case they want to give an
>authoritative-ish answer, and/or suggest a workaround.
>https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2168r3.pdf
>
>–Arthur
https://quuxplusone.github.io/blog/2019/03/11/value-category-is-not-lifetime/
I'm not an expert on the topic of coroutines, but I am wondering if std::coroutine_traits could be specialized for coroutines that returns a std::generator and which has any parameter of a type that is known to potentially refer to a temporary, then that specialization of std::coroutine_traits would have no promise_type member (thereby making the coroutine definition ill-formed). In particular, if the specialization for `std::coroutine_traits<std::generator<R, V, A>, Args...>` has no promise_type in the event that one Arg type in the pack is known to potentially refer or wrap a reference to a materialized temporary object. For instance, the usual 'T&&', 'T const&' and 'std::initializer_list', but possibly also non owning view types that convert from a prvalue.
On January 29, 2025 11:28:42 a.m. EST, Arthur O'Dwyer via Std-Proposals <std-proposals_at_[hidden]> wrote:
>On Wed, Jan 29, 2025 at 10:35 AM Peter Bindels via Std-Proposals <
>std-proposals_at_[hidden]> wrote:
>
>> On Wed, Jan 29, 2025 at 3:55 PM Karl Semich via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>>
>> > I'm trying out c++23 std::generator and noticing that I cannot safely
>> pass arguments to my generators that are temporaries such as
>> std::initializer_list. It seems like this is because promise_type's
>> initial_suspend returns suspend_always, so passed temporaries are out of
>> scope as soon as initial code is executed.
>
>> > Where can I read about this and best practices, or is it a mistake? It
>> looks like a mistake to me.
>
>Thanks, that wrapper solution is just the thing!
>>>
>>> I didn't find a way that move semantics would help with the argument
>>> case; the temporaries still go out of scope before data can be moved in
>>> (unless one uses a wrapper function, a patch, or writes their own
>>> generator).
>>> Given when a wrapper function is not used that the misbehavior is (a)
>>> severe, (b) undocumented, and (c) not reported by compilers and
>>> implementations, my personal opinion is still that this is a bug.
>>>
>>> The standard should clearly state that passing temporaries to a generator
>>> or defining temporary generators is illegal or at least undefined.
>>>
>>
>Unfortunately C++ (language and/or library) cannot detect when a reference
>(or string_view or function_ref or whatever) refers to a temporary. We can
>detect *value** category*, but value category is not lifetime. It's legal
>and not even uncommon for an rvalue reference to refer to a
>"long-lived-enough" object; and it's *extremely* common to have a (const)
>lvalue reference that refers to a short-lived temporary.
>https://quuxplusone.github.io/blog/2019/03/11/value-category-is-not-lifetime/
>
>
>
>> However, if generators executed eagerly, it would prevent a wide class of
>>> these memory corruption errors.
>>>
>>
>
>> This to me reads like a great argumentation to put into a paper, that can
>> be submitted for inclusion into C++26 or 29. If we have a
>> known-bug-inducing current setup, that is not used much, that we can then
>> still fix and have working in C++26/29, it would make sense to write a
>> paper & to see if it can be seen at Austria - or shortly after. Teaching
>> everybody "generator is kinda broken and you need to define this wrapper
>> function" seems counterproductive, when we can propose to change
>> "suspend_always" to "suspend_never" in one location and fix it for
>> everybody.
>>
>
>I agree that at first glance it *seems* like std::generator shouldn't
>suspend_always... but I'm sure there is some concrete reason that P2168
>made it suspend_never. Cc'ed the paper authors in case they want to give an
>authoritative-ish answer, and/or suggest a workaround.
>https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2168r3.pdf
>
>–Arthur
Received on 2025-01-30 21:00:40