Created on 2025-08-25.00:00:00 last changed 3 weeks ago
There are a number of CPOs defined in [exec] which have behaviour specified in terms of being expression-equivalent to a MANDATE-NOTHROW expression.
The intent of this is that we want to make sure that the call that the CPO dispatches to is marked `noexcept`. However, the way that these CPOs are currently specified in terms of sub-expressions means that we are currently requiring that all of the expressions passed as arguments to the CPO are also `noexcept`. Outside of defining these CPOs as preprocessor macros, this is unimplementable — and also undesirable behaviour. For example, [exec.set.value] defines `set_value(rcvr, vs...)` to be equivalent to MANDATE-NOTHROW(rcvr.set_value(vs...)) for sub-expressions `rcvr` and pack of sub-expressions `vs`. In [exec.general] p5 we define MANDATE-NOTHROW(expr) as expression-equivalent to `expr` but mandate that `noexcept(expr)` is `true`. So in the above definition of `set_value(rcvr, vs...)` we are actually requiring that the expression `noexcept(rcvr.set_value(vs...))` is `true`. This is only true if all of the sub-expressions are `noexcept`, i.e. all of the following expressions are `true`.noexcept(rcvr),
(noexcept(vs) && ...),
the member-function call to `rcvr.set_value(vs...)` including any implicit conversions of arguments.
This means that if, for example, one of the sub-expressions in the pack `vs` was a call to some potentially-throwing function then the overall `set_value` expression would be violating the mandates requirement.
For example:
struct my_receiver
{
void set_value(int x) noexcept;
};
int get_value() noexcept(false);
my_receiver r;
std::execution::set_value(r, get_value()); // fails MANDATE-NOTHROW mandates
Instead, we need to redefine these CPOs as being expression-equivalent to something that does not require that the argument expressions to the CPO themselves are `noexcept` — only what will be in the body of the CPO function.
For example, we could change [exec.set.value] to define `set_value(rcvr, vs...)` as expression-equivalent to:[](auto&& rcvr2, auto&&... vs2) noexcept -> decltype(auto) requires requires { std::forward<decltype(rcvr2)>(rcvr2).set_value(std::forward<decltype(vs2)>(vs2)...); } { return MANDATE-NOTHROW(std::forward<decltype(rcvr2)>(rcvr2).set_value(std::forward<decltype(vs2)>(vs2)...)); }(rcvr, vs...)
The following sections all contain problematic uses of MANDATE-NOTHROW:
[exec.get.allocator]
[exec.get.stop.token]
[exec.get.env]
[exec.get.domain]
[exec.get.scheduler]
[exec.get.delegation.scheduler]
[exec.get.fwd.progress]
[exec.get.compl.sched]
[exec.get.await.adapt]
[exec.set.value]
[exec.set.error]
[exec.set.stopped]
[exec.opstate.start]
History | |||
---|---|---|---|
Date | User | Action | Args |
2025-08-25 00:00:00 | admin | create |