Skip to content

Commit e280407

Browse files
authored
[libc++] Add test coverage for our implementation of LWG4031 (llvm#87508)
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.
1 parent 568ec13 commit e280407

File tree

5 files changed

+130
-19
lines changed

5 files changed

+130
-19
lines changed

libcxx/docs/Status/Cxx2cIssues.csv

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
"`4023 <https://wg21.link/LWG4023>`__","Preconditions of ``std::basic_streambuf::setg/setp``","Tokyo March 2024","","",""
5353
"`4025 <https://wg21.link/LWG4025>`__","Move assignment operator of ``std::expected<cv void, E>`` should not be conditionally deleted","Tokyo March 2024","","",""
5454
"`4030 <https://wg21.link/LWG4030>`__","Clarify whether arithmetic expressions in ``[numeric.sat.func]`` are mathematical or C++","Tokyo March 2024","|Nothing To Do|","",""
55-
"`4031 <https://wg21.link/LWG4031>`__","``bad_expected_access<void>`` member functions should be ``noexcept``","Tokyo March 2024","","",""
55+
"`4031 <https://wg21.link/LWG4031>`__","``bad_expected_access<void>`` member functions should be ``noexcept``","Tokyo March 2024","|Complete|","16.0",""
5656
"`4035 <https://wg21.link/LWG4035>`__","``single_view`` should provide ``empty``","Tokyo March 2024","","","|ranges|"
5757
"`4036 <https://wg21.link/LWG4036>`__","``__alignof_is_defined`` is only implicitly specified in C++ and not yet deprecated","Tokyo March 2024","","",""
5858
"`4037 <https://wg21.link/LWG4037>`__","Static data members of ``ctype_base`` are not yet required to be usable in constant expressions","Tokyo March 2024","","",""

libcxx/include/__expected/bad_expected_access.h

+6-6
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wweak-vtables")
3232
template <>
3333
class bad_expected_access<void> : public exception {
3434
protected:
35-
_LIBCPP_HIDE_FROM_ABI bad_expected_access() noexcept = default;
36-
_LIBCPP_HIDE_FROM_ABI bad_expected_access(const bad_expected_access&) = default;
37-
_LIBCPP_HIDE_FROM_ABI bad_expected_access(bad_expected_access&&) = default;
38-
_LIBCPP_HIDE_FROM_ABI bad_expected_access& operator=(const bad_expected_access&) = default;
39-
_LIBCPP_HIDE_FROM_ABI bad_expected_access& operator=(bad_expected_access&&) = default;
40-
_LIBCPP_HIDE_FROM_ABI_VIRTUAL ~bad_expected_access() override = default;
35+
_LIBCPP_HIDE_FROM_ABI bad_expected_access() noexcept = default;
36+
_LIBCPP_HIDE_FROM_ABI bad_expected_access(const bad_expected_access&) noexcept = default;
37+
_LIBCPP_HIDE_FROM_ABI bad_expected_access(bad_expected_access&&) noexcept = default;
38+
_LIBCPP_HIDE_FROM_ABI bad_expected_access& operator=(const bad_expected_access&) noexcept = default;
39+
_LIBCPP_HIDE_FROM_ABI bad_expected_access& operator=(bad_expected_access&&) noexcept = default;
40+
_LIBCPP_HIDE_FROM_ABI_VIRTUAL ~bad_expected_access() override = default;
4141

4242
public:
4343
// The way this has been designed (by using a class template below) means that we'll already

libcxx/test/std/utilities/expected/expected.bad/what.noexcept.compile.pass.cpp renamed to libcxx/test/std/utilities/expected/expected.bad/base.compile.pass.cpp

+5-12
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,12 @@
77

88
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
99

10-
// const char* what() const noexcept override;
10+
// Make sure std::bad_expected_access<E> inherits from std::bad_expected_access<void>.
1111

1212
#include <expected>
13-
#include <utility>
13+
#include <type_traits>
1414

15-
template <class T>
16-
concept WhatNoexcept =
17-
requires(const T& t) {
18-
{ t.what() } noexcept;
19-
};
15+
struct Foo {};
2016

21-
struct foo{};
22-
23-
static_assert(!WhatNoexcept<foo>);
24-
static_assert(WhatNoexcept<std::bad_expected_access<int>>);
25-
static_assert(WhatNoexcept<std::bad_expected_access<foo>>);
17+
static_assert(std::is_base_of_v<std::bad_expected_access<void>, std::bad_expected_access<int>>);
18+
static_assert(std::is_base_of_v<std::bad_expected_access<void>, std::bad_expected_access<Foo>>);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
//===----------------------------------------------------------------------===//
2+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3+
// See https://llvm.org/LICENSE.txt for license information.
4+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5+
//
6+
//===----------------------------------------------------------------------===//
7+
8+
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
9+
10+
// template<>
11+
// class bad_expected_access<void> : public exception {
12+
// protected:
13+
// bad_expected_access() noexcept;
14+
// bad_expected_access(const bad_expected_access&) noexcept;
15+
// bad_expected_access(bad_expected_access&&) noexcept;
16+
// bad_expected_access& operator=(const bad_expected_access&) noexcept;
17+
// bad_expected_access& operator=(bad_expected_access&&) noexcept;
18+
// ~bad_expected_access();
19+
//
20+
// public:
21+
// const char* what() const noexcept override;
22+
// };
23+
24+
#include <cassert>
25+
#include <exception>
26+
#include <expected>
27+
#include <type_traits>
28+
#include <utility>
29+
30+
#include "test_macros.h"
31+
32+
struct Inherit : std::bad_expected_access<void> {};
33+
34+
int main(int, char**) {
35+
// base class
36+
static_assert(std::is_base_of_v<std::exception, std::bad_expected_access<void>>);
37+
38+
// default constructor
39+
{
40+
Inherit exc;
41+
ASSERT_NOEXCEPT(Inherit());
42+
}
43+
44+
// copy constructor
45+
{
46+
Inherit exc;
47+
Inherit copy(exc);
48+
ASSERT_NOEXCEPT(Inherit(exc));
49+
}
50+
51+
// move constructor
52+
{
53+
Inherit exc;
54+
Inherit copy(std::move(exc));
55+
ASSERT_NOEXCEPT(Inherit(std::move(exc)));
56+
}
57+
58+
// copy assignment
59+
{
60+
Inherit exc;
61+
Inherit copy;
62+
[[maybe_unused]] Inherit& result = (copy = exc);
63+
ASSERT_NOEXCEPT(copy = exc);
64+
}
65+
66+
// move assignment
67+
{
68+
Inherit exc;
69+
Inherit copy;
70+
[[maybe_unused]] Inherit& result = (copy = std::move(exc));
71+
ASSERT_NOEXCEPT(copy = std::move(exc));
72+
}
73+
74+
// what()
75+
{
76+
Inherit exc;
77+
char const* what = exc.what();
78+
assert(what != nullptr);
79+
ASSERT_NOEXCEPT(exc.what());
80+
}
81+
82+
return 0;
83+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//===----------------------------------------------------------------------===//
2+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3+
// See https://llvm.org/LICENSE.txt for license information.
4+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5+
//
6+
//===----------------------------------------------------------------------===//
7+
8+
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
9+
10+
// const char* what() const noexcept override;
11+
12+
#include <expected>
13+
#include <cassert>
14+
#include <utility>
15+
16+
#include "test_macros.h"
17+
18+
struct Foo {};
19+
20+
int main(int, char**) {
21+
{
22+
std::bad_expected_access<int> const exc(99);
23+
char const* what = exc.what();
24+
assert(what != nullptr);
25+
ASSERT_NOEXCEPT(exc.what());
26+
}
27+
{
28+
std::bad_expected_access<Foo> const exc(Foo{});
29+
char const* what = exc.what();
30+
assert(what != nullptr);
31+
ASSERT_NOEXCEPT(exc.what());
32+
}
33+
34+
return 0;
35+
}

0 commit comments

Comments
 (0)