Index: libcxx/include/latch =================================================================== --- libcxx/include/latch +++ libcxx/include/latch @@ -75,7 +75,15 @@ } 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, + "latch::latch(ptrdiff_t): latch cannot be " + "initialized with a negative value"); + _LIBCPP_ASSERT_UNCATEGORIZED(__expected <= max(), + "latch::latch(ptrdiff_t): latch cannot be " + "initialized with a value greater than max()"); + } _LIBCPP_HIDE_FROM_ABI ~latch() = default; latch(const latch&) = delete; @@ -84,8 +92,13 @@ 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"); auto const __old = __a_.fetch_sub(__update, memory_order_release); - if(__old == __update) + _LIBCPP_ASSERT_UNCATEGORIZED( + __update <= __old, "latch::count_down called with a value greater " + "than the internal counter"); + if (__old == __update) __a_.notify_all(); } inline _LIBCPP_INLINE_VISIBILITY @@ -103,6 +116,10 @@ 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"); + // other preconditions on __update are checked in count_down() + 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,37 @@ +//===----------------------------------------------------------------------===// +// +// 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: no-threads +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// class latch; + +// void arrive_and_wait(ptrdiff_t __update = 1); + +// Make sure that calling arrive_and_wait with a negative value 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"); + } + + 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,45 @@ +//===----------------------------------------------------------------------===// +// +// 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: no-threads +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// class latch; + +// void count_down(ptrdiff_t __update = 1); + +// Make sure that calling count_down 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 a value greater " + "than the internal counter"); + } + + return 0; +} Index: libcxx/test/libcxx/thread/thread.latch/assert.ctor.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/libcxx/thread/thread.latch/assert.ctor.pass.cpp @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// 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: no-threads +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// class latch; + +// constexpr explicit latch(ptrdiff_t __expected); + +// Make sure that calling latch with a negative value 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 **) { + { + TEST_LIBCPP_ASSERT_FAILURE([]{ std::latch l(-1); }(), + "latch::latch(ptrdiff_t): latch cannot be " + "initialized with a negative value"); + } + + // We can't check the precondition for max() because there's no value + // that would violate the precondition (in our implementation) + + return 0; +}