Move the exception_ptr used for propagating exceptions into the promise rather
than holding it in the awaitable and passing a pointer to this to the
nested promise.
The problem with the old approach was that the __yield_sequence_awaiter struct
contained both the exception_ptr and the generator that was being yielded.
Taking the address of the exception_ptr member caused the compiler to treat
the whole struct as aliased and so it was unable to deduce that the generator
destructor called by the awaiter destructor held the same coroutine that it did
before the coroutine suspended and this was inhibiting the compiler's ability
to elide the allocation.
This change comes at a slight increase in the promise_type size - an extra pointer
on most platforms. But the __yield_sequence_awaiter has reduced in size which
offsets this cost a little, at least for nested generator usage.
Also added some more tests of nested generator behaviour.
…on elision optimisations.
Move the exception_ptr used for propagating exceptions into the promise rather than holding it in the awaitable and passing a pointer to this to the nested promise.
The problem with the old approach was that the __yield_sequence_awaiter struct contained both the exception_ptr and the generator that was being yielded. Taking the address of the exception_ptr member caused the compiler to treat the whole struct as aliased and so it was unable to deduce that the generator destructor called by the awaiter destructor held the same coroutine that it did before the coroutine suspended and this was inhibiting the compiler's ability to elide the allocation.
This change comes at a slight increase in the promise_type size - an extra pointer on most platforms. But the __yield_sequence_awaiter has reduced in size which offsets this cost a little, at least for nested generator usage.
Also added some more tests of nested generator behaviour.