[libc++] add basic runtime assertions to <latch>
authorEdoardo Sanguineti <edoardo.sanguineti222@gmail.com>
Wed, 5 Jul 2023 21:33:18 +0000 (17:33 -0400)
committerLouis Dionne <ldionne.2@gmail.com>
Wed, 5 Jul 2023 21:34:23 +0000 (17:34 -0400)
Adding assertions will aid users that have bugs in their code to
receive better error messages.

Differential Revision: https://reviews.llvm.org/D154425

libcxx/include/latch
libcxx/test/libcxx/thread/thread.latch/assert.arrive_and_wait.pass.cpp [new file with mode: 0644]
libcxx/test/libcxx/thread/thread.latch/assert.count_down.pass.cpp [new file with mode: 0644]
libcxx/test/libcxx/thread/thread.latch/assert.ctor.pass.cpp [new file with mode: 0644]

index cb33666..4753806 100644 (file)
@@ -75,7 +75,15 @@ public:
     }
 
     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 @@ public:
     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 @@ public:
     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();
     }
diff --git a/libcxx/test/libcxx/thread/thread.latch/assert.arrive_and_wait.pass.cpp b/libcxx/test/libcxx/thread/thread.latch/assert.arrive_and_wait.pass.cpp
new file mode 100644 (file)
index 0000000..d00540c
--- /dev/null
@@ -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
+
+// <latch>
+
+// 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 <latch>
+
+#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;
+}
diff --git a/libcxx/test/libcxx/thread/thread.latch/assert.count_down.pass.cpp b/libcxx/test/libcxx/thread/thread.latch/assert.count_down.pass.cpp
new file mode 100644 (file)
index 0000000..abd1601
--- /dev/null
@@ -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
+
+// <latch>
+
+// 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 <latch>
+
+#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;
+}
diff --git a/libcxx/test/libcxx/thread/thread.latch/assert.ctor.pass.cpp b/libcxx/test/libcxx/thread/thread.latch/assert.ctor.pass.cpp
new file mode 100644 (file)
index 0000000..dbd582f
--- /dev/null
@@ -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
+
+// <latch>
+
+// 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 <latch>
+
+#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;
+}