This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of Ready status.

3898. Possibly unintended preconditions for completion functions of std::barrier

Section: 32.9.3.3 [thread.barrier.class] Status: Ready Submitter: Jiang An Opened: 2023-03-02 Last modified: 2026-09-11

Priority: 3

View all issues with Ready status.

Discussion:

32.9.3.3 [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.

[2023-03-22; Reflector poll]

Set priority to 3 after reflector poll.

Previous resolution [SUPERSEDED]

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 32.9.3.3 [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 32.9.3.3 [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.

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

Previous resolution [SUPERSEDED]

This wording is relative to N4928.

  1. Modify 32.9.3.3 [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.

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

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

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

Proposed resolution:

This wording is relative to N5054.

  1. Modify 14.6.2 [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 (17.9.5 [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 (32.3.5.3 [stopsource.mem], 32.3.9.3 [stopsource.inplace.mem]), or in the constructor of std::stop_callback or std::inplace_stop_callback (32.3.6.2 [stopcallback.cons], 32.3.10.2 [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 (32.9.3.3 [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 (33.12.1 [exec.run.loop]), or

    17. (1.16) — […]

    18. (1.17) — […]

    19. (1.18) — […]

    20. (1.19) — […]

    — end note ]

  2. Modify 32.9.3.3 [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.