Skip to content

[libc++] Add test coverage for our implementation of LWG4031 #87508

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 9, 2024

Conversation

ldionne
Copy link
Member

@ldionne ldionne commented Apr 3, 2024

This was actually already implemented in the initial version of std::expected, but this patch adds test coverage and makes it more explicit that we intend to make these functions noexcept.

@ldionne ldionne requested a review from a team as a code owner April 3, 2024 15:27
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Apr 3, 2024
@ldionne
Copy link
Member Author

ldionne commented Apr 3, 2024

CC @frederick-vs-ja

@llvmbot
Copy link
Member

llvmbot commented Apr 3, 2024

@llvm/pr-subscribers-libcxx

Author: Louis Dionne (ldionne)

Changes

This was actually already implemented in the initial version of std::expected, but this patch adds test coverage and makes it more explicit that we intend to make these functions noexcept.


Full diff: https://github.com/llvm/llvm-project/pull/87508.diff

5 Files Affected:

  • (modified) libcxx/docs/Status/Cxx2cIssues.csv (+1-1)
  • (modified) libcxx/include/__expected/bad_expected_access.h (+6-6)
  • (renamed) libcxx/test/std/utilities/expected/expected.bad/base.compile.pass.cpp (+5-12)
  • (added) libcxx/test/std/utilities/expected/expected.bad/void-specialization.pass.cpp (+82)
  • (added) libcxx/test/std/utilities/expected/expected.bad/what.pass.cpp (+35)
diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv
index f471c430b19c18..54ea374c5bdd17 100644
--- a/libcxx/docs/Status/Cxx2cIssues.csv
+++ b/libcxx/docs/Status/Cxx2cIssues.csv
@@ -52,7 +52,7 @@
 "`4023 <https://wg21.link/LWG4023>`__","Preconditions of ``std::basic_streambuf::setg/setp``","Tokyo March 2024","","",""
 "`4025 <https://wg21.link/LWG4025>`__","Move assignment operator of ``std::expected<cv void, E>`` should not be conditionally deleted","Tokyo March 2024","","",""
 "`4030 <https://wg21.link/LWG4030>`__","Clarify whether arithmetic expressions in ``[numeric.sat.func]`` are mathematical or C++","Tokyo March 2024","","",""
-"`4031 <https://wg21.link/LWG4031>`__","``bad_expected_access<void>`` member functions should be ``noexcept``","Tokyo March 2024","","",""
+"`4031 <https://wg21.link/LWG4031>`__","``bad_expected_access<void>`` member functions should be ``noexcept``","Tokyo March 2024","|Complete|","16.0",""
 "`4035 <https://wg21.link/LWG4035>`__","``single_view`` should provide ``empty``","Tokyo March 2024","","","|ranges|"
 "`4036 <https://wg21.link/LWG4036>`__","``__alignof_is_defined`` is only implicitly specified in C++ and not yet deprecated","Tokyo March 2024","","",""
 "`4037 <https://wg21.link/LWG4037>`__","Static data members of ``ctype_base`` are not yet required to be usable in constant expressions","Tokyo March 2024","","",""
diff --git a/libcxx/include/__expected/bad_expected_access.h b/libcxx/include/__expected/bad_expected_access.h
index 27f01d9350eea6..4341e94be0f2c2 100644
--- a/libcxx/include/__expected/bad_expected_access.h
+++ b/libcxx/include/__expected/bad_expected_access.h
@@ -30,12 +30,12 @@ class bad_expected_access;
 template <>
 class bad_expected_access<void> : public exception {
 protected:
-  _LIBCPP_HIDE_FROM_ABI bad_expected_access() noexcept                             = default;
-  _LIBCPP_HIDE_FROM_ABI bad_expected_access(const bad_expected_access&)            = default;
-  _LIBCPP_HIDE_FROM_ABI bad_expected_access(bad_expected_access&&)                 = default;
-  _LIBCPP_HIDE_FROM_ABI bad_expected_access& operator=(const bad_expected_access&) = default;
-  _LIBCPP_HIDE_FROM_ABI bad_expected_access& operator=(bad_expected_access&&)      = default;
-  _LIBCPP_HIDE_FROM_ABI_VIRTUAL ~bad_expected_access() override                    = default;
+  _LIBCPP_HIDE_FROM_ABI bad_expected_access() noexcept                                      = default;
+  _LIBCPP_HIDE_FROM_ABI bad_expected_access(const bad_expected_access&) noexcept            = default;
+  _LIBCPP_HIDE_FROM_ABI bad_expected_access(bad_expected_access&&) noexcept                 = default;
+  _LIBCPP_HIDE_FROM_ABI bad_expected_access& operator=(const bad_expected_access&) noexcept = default;
+  _LIBCPP_HIDE_FROM_ABI bad_expected_access& operator=(bad_expected_access&&) noexcept      = default;
+  _LIBCPP_HIDE_FROM_ABI_VIRTUAL ~bad_expected_access() override                             = default;
 
 public:
   // The way this has been designed (by using a class template below) means that we'll already
diff --git a/libcxx/test/std/utilities/expected/expected.bad/what.noexcept.compile.pass.cpp b/libcxx/test/std/utilities/expected/expected.bad/base.compile.pass.cpp
similarity index 56%
rename from libcxx/test/std/utilities/expected/expected.bad/what.noexcept.compile.pass.cpp
rename to libcxx/test/std/utilities/expected/expected.bad/base.compile.pass.cpp
index e6d050b2129d62..545215a3b16130 100644
--- a/libcxx/test/std/utilities/expected/expected.bad/what.noexcept.compile.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.bad/base.compile.pass.cpp
@@ -7,19 +7,12 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
 
-// const char* what() const noexcept override;
+// Make sure std::bad_expected_access<E> inherits from std::bad_expected_access<void>.
 
 #include <expected>
-#include <utility>
+#include <type_traits>
 
-template <class T>
-concept WhatNoexcept =
-    requires(const T& t) {
-      { t.what() } noexcept;
-    };
+struct Foo {};
 
-struct foo{};
-
-static_assert(!WhatNoexcept<foo>);
-static_assert(WhatNoexcept<std::bad_expected_access<int>>);
-static_assert(WhatNoexcept<std::bad_expected_access<foo>>);
+static_assert(std::is_base_of_v<std::bad_expected_access<void>, std::bad_expected_access<int>>);
+static_assert(std::is_base_of_v<std::bad_expected_access<void>, std::bad_expected_access<Foo>>);
diff --git a/libcxx/test/std/utilities/expected/expected.bad/void-specialization.pass.cpp b/libcxx/test/std/utilities/expected/expected.bad/void-specialization.pass.cpp
new file mode 100644
index 00000000000000..ce0609acdb5abd
--- /dev/null
+++ b/libcxx/test/std/utilities/expected/expected.bad/void-specialization.pass.cpp
@@ -0,0 +1,82 @@
+//===----------------------------------------------------------------------===//
+// 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, c++20
+
+// template<>
+// class bad_expected_access<void> : public exception {
+// protected:
+//   bad_expected_access() noexcept;
+//   bad_expected_access(const bad_expected_access&) noexcept;
+//   bad_expected_access(bad_expected_access&&) noexcept;
+//   bad_expected_access& operator=(const bad_expected_access&) noexcept;
+//   bad_expected_access& operator=(bad_expected_access&&) noexcept;
+//   ~bad_expected_access();
+//
+// public:
+//   const char* what() const noexcept override;
+// };
+
+#include <expected>
+#include <cassert>
+#include <type_traits>
+#include <utility>
+
+#include "test_macros.h"
+
+struct Inherit : std::bad_expected_access<void> {};
+
+int main(int, char**) {
+  // base class
+  static_assert(std::is_base_of_v<std::exception, std::bad_expected_access<void>>);
+
+  // default constructor
+  {
+    Inherit exc;
+    ASSERT_NOEXCEPT(Inherit());
+  }
+
+  // copy constructor
+  {
+    Inherit exc;
+    Inherit copy(exc);
+    ASSERT_NOEXCEPT(Inherit(exc));
+  }
+
+  // move constructor
+  {
+    Inherit exc;
+    Inherit copy(std::move(exc));
+    ASSERT_NOEXCEPT(Inherit(std::move(exc)));
+  }
+
+  // copy assignment
+  {
+    Inherit exc;
+    Inherit copy;
+    [[maybe_unused]] Inherit& result = (copy = exc);
+    ASSERT_NOEXCEPT(copy = exc);
+  }
+
+  // move assignment
+  {
+    Inherit exc;
+    Inherit copy;
+    [[maybe_unused]] Inherit& result = (copy = std::move(exc));
+    ASSERT_NOEXCEPT(copy = std::move(exc));
+  }
+
+  // what()
+  {
+    Inherit exc;
+    char const* what = exc.what();
+    assert(what != nullptr);
+    ASSERT_NOEXCEPT(exc.what());
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/expected/expected.bad/what.pass.cpp b/libcxx/test/std/utilities/expected/expected.bad/what.pass.cpp
new file mode 100644
index 00000000000000..bc5e356161a740
--- /dev/null
+++ b/libcxx/test/std/utilities/expected/expected.bad/what.pass.cpp
@@ -0,0 +1,35 @@
+//===----------------------------------------------------------------------===//
+// 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, c++20
+
+// const char* what() const noexcept override;
+
+#include <expected>
+#include <cassert>
+#include <utility>
+
+#include "test_macros.h"
+
+struct Foo {};
+
+int main(int, char**) {
+  {
+    std::bad_expected_access<int> const exc(99);
+    char const* what = exc.what();
+    assert(what != nullptr);
+    ASSERT_NOEXCEPT(exc.what());
+  }
+  {
+    std::bad_expected_access<Foo> const exc(Foo{});
+    char const* what = exc.what();
+    assert(what != nullptr);
+    ASSERT_NOEXCEPT(exc.what());
+  }
+
+  return 0;
+}

This was actually already implemented in the initial version of std::expected,
but this patch adds test coverage and makes it more explicit that we intend
to make these functions noexcept.
@ldionne ldionne force-pushed the review/LWG4031-expected branch from c66a826 to 27fec94 Compare April 4, 2024 15:05
@ldionne ldionne merged commit e280407 into llvm:main Apr 9, 2024
53 checks passed
@ldionne ldionne deleted the review/LWG4031-expected branch April 9, 2024 15:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants