Index: libcxx/include/latch =================================================================== --- libcxx/include/latch +++ libcxx/include/latch @@ -75,7 +75,11 @@ } inline _LIBCPP_INLINE_VISIBILITY - constexpr explicit latch(ptrdiff_t __expected) : __a_(__expected) { } + constexpr explicit latch(ptrdiff_t __expected) : __a_(__expected) + { + _LIBCPP_ASSERT_UNCATEGORIZED(__expected >= 0, + "__expected cannot be negative"); + } _LIBCPP_HIDE_FROM_ABI ~latch() = default; latch(const latch&) = delete; @@ -84,6 +88,12 @@ inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY void count_down(ptrdiff_t __update = 1) { + _LIBCPP_ASSERT_UNCATEGORIZED( + __update >= 0, "latch::count_down called with a negative value"); + _LIBCPP_ASSERT_UNCATEGORIZED( + __update > __a_.load(memory_order_relaxed), + "__update is greater than the value of the internal counter"); + auto const __old = __a_.fetch_sub(__update, memory_order_release); if(__old == __update) __a_.notify_all(); @@ -103,6 +113,12 @@ inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY void arrive_and_wait(ptrdiff_t __update = 1) { + _LIBCPP_ASSERT_UNCATEGORIZED( + __update >= 0, "latch::arrive_and_wait called with a negative value"); + _LIBCPP_ASSERT_UNCATEGORIZED( + __update > __a_.load(memory_order_relaxed), + "__update is greater than the value of the internal counter"); + count_down(__update); wait(); } Index: libcxx/test/libcxx/thread/thread.latch/assert.arrive_and_wait.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/libcxx/thread/thread.latch/assert.arrive_and_wait.pass.cpp @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// +// +// void arrive_and_wait(ptrdiff_t __update = 1); + +// Make sure that calling arrive_and_wait with a negative value or a value +// higher than the internal counter triggers an assertion. + +// REQUIRES: has-unix-headers +// XFAIL: availability-verbose_abort-missing +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +#include + +#include "check_assertion.h" + +int main(int, char **) { + { + std::latch l(5); + + TEST_LIBCPP_ASSERT_FAILURE( + l.arrive_and_wait(-10), + "latch::arrive_and_wait() called with a negative value"); + } + + { + std::latch l(5); + + TEST_LIBCPP_ASSERT_FAILURE( + l.arrive_and_wait(10), + "latch::arrive_and_wait() called with value greater " + "than the internal counter"); + } + + return 0; +} Index: libcxx/test/libcxx/thread/thread.latch/assert.count_down.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/libcxx/thread/thread.latch/assert.count_down.pass.cpp @@ -0,0 +1,42 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// +// +// void count_down(ptrdiff_t __update = 1); + +// Make sure that calling arrive_and_wait with a negative value or a value +// higher than the internal counter triggers an assertion. + +// REQUIRES: has-unix-headers +// XFAIL: availability-verbose_abort-missing +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +#include + +#include "check_assertion.h" + +int main(int, char **) { + { + std::latch l(5); + + TEST_LIBCPP_ASSERT_FAILURE( + l.count_down(-10), "latch::count_down() called with a negative value"); + } + + { + std::latch l(5); + + TEST_LIBCPP_ASSERT_FAILURE(l.count_down(10), + "latch::count_down() called with value greater " + "than the internal counter"); + } + + return 0; +}