Skip to content

Don't drop a throwing transformation from transform_sender's noexcept - #2377

Open
ispeters wants to merge 1 commit into
NVIDIA:mainfrom
ispeters:fix-transform-sender-noexcept
Open

ispeters wants to merge 1 commit into
NVIDIA:mainfrom
ispeters:fix-transform-sender-noexcept

Conversation

@ispeters

Copy link
Copy Markdown
Contributor

transform_sender transforms a sender repeatedly, until a domain's transformation returns a sender of the same type, and its noexcept is meant to be the conjunction of the steps'. The step that ends the recursion reports only its own noexcept, though, dropping the earlier steps'. So when a potentially-throwing transformation returns a sender that's then transformed again, for example by default_domain's identity transformation, transform_sender, and with it connect, claim not to throw, and an exception thrown by the transformation calls std::terminate.

This diff makes the last step report the conjunction too.

That exposes a missing noexcept on sequence's lowering, whose transform_sender had no exception specification, so connecting a sequence, or a repeat_n, which connects one, became potentially-throwing. It's now noexcept exactly when moving or copying the children into the lowered sender is.

The new tests check that a potentially-throwing transformation whose result is transformed again makes transform_sender and connect potentially-throwing, that its exception propagates out of connect, and when lowering a sequence is noexcept.

@copy-pr-bot

copy-pr-bot Bot commented Oct 28, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

`transform_sender` transforms a sender repeatedly, until a domain's
transformation returns a sender of the same type, and its `noexcept` is
meant to be the conjunction of the steps'. The step that ends the
recursion reports only its own `noexcept`, though, dropping the earlier
steps'. So when a potentially-throwing transformation returns a
sender that's then transformed again, for example by `default_domain`'s
identity transformation, `transform_sender`, and with it `connect`,
claim not to throw, and an exception thrown by the transformation calls
`std::terminate`.

This diff makes the last step report the conjunction too.

That exposes a missing `noexcept` on `sequence`'s lowering, whose
`transform_sender` had no exception specification, so connecting a
`sequence`, or a `repeat_n`, which connects one, became
potentially-throwing. It's now `noexcept` exactly when moving or copying
the children into the lowered sender is.

The new tests check that a potentially-throwing transformation whose
result is transformed again makes `transform_sender` and `connect`
potentially-throwing, that its exception propagates out of `connect`,
and when lowering a `sequence` is `noexcept`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant