Title
Possibly unintended preconditions for completion functions of std::barrier
Status
ready
Section
[thread.barrier.class]
Submitter
Jiang An

Created on 2023-03-02.00:00:00 last changed 3 days ago

Messages

Date: 2026-09-11.16:39:09

Proposed resolution:

This wording is relative to N5054.

  1. Modify [except.terminate] as indicated:

    -1- Some errors in a program cannot be recovered from, such as when an exception is not handled or a `std::thread` object is destroyed while its thread function is still executing. In such cases, the function `std::terminate` ([exception.terminate]) is invoked.

    [Note 1: These situations are:

    1. (1.1) — […]

    2. (1.2) — […]

    3. (1.3) — […]

    4. (1.4) — […]

    5. (1.5) — […]

    6. (1.6) — […]

    7. (1.7) — […]

    8. (1.8) — […]

    9. (1.9) — […]

    10. (1.10) — […]

    11. (1.11) — […]

    12. (1.12) — […]

    13. (1.13) — […]

    14. (1.14) — when a callback invocation exits via an exception when requesting stop on a `std::stop_source` or a `std::inplace_stop_source` ([stopsource.mem], [stopsource.inplace.mem]), or in the constructor of `std::stop_callback` or `std::inplace_stop_callback` ([stopcallback.cons], [stopcallback.inplace.cons]) when a callback invocation exits via an exception, or

    15. (1.?) — when an invocation of the completion function of a `std::barrier` object ([thread.barrier.class]) exits via an exception, or

    16. (1.15) — when a `run_loop` object is destroyed that is still in the `running` state ([exec.run.loop]), or

    17. (1.16) — […]

    18. (1.17) — […]

    19. (1.18) — […]

    20. (1.19) — […]

    end note ]

  2. Modify [thread.barrier.class] as indicated:

    -3- The phase completion step that is executed at the end of each phase has the following effects:

    1. (3.1) — Invokes the completion function, equivalent to completion(); if that invocation exits via an exception, the function std::terminate is invoked.

    2. (3.2) — Unblocks all threads that are blocked on the phase synchronization point.

    […]

    -5- CompletionFunction shall meet the Cpp17MoveConstructible (Table 32) and Cpp17Destructible (Table 36) requirements. is_nothrow_invocable_v<CompletionFunction&> shall be true. A program that instantiates barrier<CompletionFunction> is ill-formed if is_invocable_v<CompletionFunction&> is false.

Date: 2026-09-15.00:00:00

[ 2026-09-11; LWG telecon. Status changed: New → Ready. ]

Date: 2026-09-15.00:00:00

[ 2026-09-11; Tim provides new wording ]

Needs an update to the gigantic "when do we call `std::terminate`?" note.

Date: 2023-03-15.00:00:00

[ 2023-03-22; Jonathan provides improved wording ]

This wording is relative to N4928.

  1. Modify [thread.barrier.class] as indicated:

    -3- The phase completion step that is executed at the end of each phase has the following effects:

    1. (3.1) — Invokes the completion function, equivalent to completion(); if that invocation exits via an exception, the function std::terminate is invoked.

    2. (3.2) — Unblocks all threads that are blocked on the phase synchronization point.

    […]

    -5- CompletionFunction shall meet the Cpp17MoveConstructible (Table 32) and Cpp17Destructible (Table 36) requirements. is_nothrow_invocable_v<CompletionFunction&> shall be true. A program that instantiates barrier<CompletionFunction> is ill-formed if is_invocable_v<CompletionFunction&> is false.

Date: 2023-03-15.00:00:00

[ 2023-03-22; Reflector poll ]

Set priority to 3 after reflector poll.

This wording is relative to N4928.

[Drafting Note: Two mutually exclusive options are prepared, depicted below by Option A and Option B, respectively.]

Option A: Effectively impose a Mandates: requirement.

  1. Modify [thread.barrier.class] as indicated:

    -5- CompletionFunction shall meet the Cpp17MoveConstructible (Table 32) and Cpp17Destructible (Table 36) requirements. Instantiation of barrier<CompletionFunction> is ill-formed if is_nothrow_invocable_v<CompletionFunction&> is not trueis_nothrow_invocable_v<CompletionFunction&> shall be true.

Option B: Clarify that we impose a no-throw precondition here, whose violation causes UB.

  1. Modify [thread.barrier.class] as indicated:

    -3- The phase completion step that is executed at the end of each phase has the following effects:

    1. (3.1) — Invokes the completion function, equivalent to completion(). If any invocation to the completion function throws an exception, the behavior is undefined.

    2. (3.2) — Unblocks all threads that are blocked on the phase synchronization point.

    […]

    -5- CompletionFunction shall meet the Cpp17MoveConstructible (Table 32) and Cpp17Destructible (Table 36) requirements. is_nothrow_invocable_v<CompletionFunction&> shall be true.

Date: 2023-03-02.00:00:00

[thread.barrier.class]/5 currently says:

[…] is_nothrow_invocable_v<CompletionFunction&> shall be true.

This requirement introduces a kind of undefined behavior and permits implementation divergence. Currently MSVC STL enforces the requirement, while libstdc++ and libc++ don't.

If implementation divergence is not intended, I don't think it makes much sense to introduce UB in this way. I guess we should either strengthen the requirement to require well-formedness affection or relax it.

History
Date User Action Args
2026-09-11 16:39:09adminsetmessages: + msg16606
2026-09-11 16:39:09adminsetstatus: new -> ready
2026-09-11 07:12:52adminsetmessages: + msg16603
2023-03-22 23:00:59adminsetmessages: + msg13487
2023-03-22 22:40:39adminsetmessages: + msg13483
2023-03-04 12:47:21adminsetmessages: + msg13444
2023-03-02 00:00:00admincreate