[libc++] Strengthen optional value constructor noexcept (#202765)
The standard does not require `optional<T>(U&&)` to be potentially throwing; it simply does not specify noexcept for the primary `optional<T>` converting constructor. Standard library implementations are permitted [[res.on.exception.handling]/5](https://eel.is/c++draft/res.on.exception.handling#5) to strengthen exception specifications for non-virtual library functions, as long as the strengthened specification is correct. GNU libstdc++ already does this: https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/optional#L911-L913 https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/optional#L962-L974 The existing libc++ code only added noexcept for the C++26 `optional<T&>` case, guarded by `is_lvalue_reference_v<_Tp>`. It is safe to remove that gate and use the general condition instead: ``` noexcept(is_nothrow_constructible_v<_Tp, _Up>) ``` For `optional<T&>`, this still becomes the intended reference-construction check. For ordinary `optional<T>`, it correctly reflects whether constructing `T` from `U` can throw. The constructor only forwards into the contained object construction and updates optional bookkeeping, so if `T` is nothrow-constructible from `U`, the optional construction is also nothrow.
This commit is contained in:
1 parent
ffb3458175
commit
9a851497a4
2 files changed
+25
-2
No files matched your search
@@ -970,11 +970,14 @@ public:
|
||||
: __base(in_place, __il, std::forward<_Args>(__args)...) {}
|
||||
|
||||
template <class _Up = _Tp, enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_implicit<_Up>(), int> = 0>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr optional(_Up&& __v) : __base(in_place, std::forward<_Up>(__v)) {}
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr optional(_Up&& __v) noexcept(is_nothrow_constructible_v<_Tp, _Up>) // strengthened
|
||||
: __base(in_place, std::forward<_Up>(__v)) {}
|
||||
|
||||
template <class _Up = remove_cv_t<_Tp>,
|
||||
enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_explicit<_Up>(), int> = 0>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit optional(_Up&& __v) : __base(in_place, std::forward<_Up>(__v)) {}
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit optional(_Up&& __v) noexcept(
|
||||
is_nothrow_constructible_v<_Tp, _Up>) // strengthened
|
||||
: __base(in_place, std::forward<_Up>(__v)) {}
|
||||
|
||||
// LWG2756: conditionally explicit conversion from const optional<_Up>&
|
||||
template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::template __enable_implicit<_Up>(), int> = 0>
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <cassert>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "archetypes.h"
|
||||
@@ -44,6 +45,14 @@ struct ImplicitAny {
|
||||
constexpr ImplicitAny(U&&) {}
|
||||
};
|
||||
|
||||
struct ImplicitNoThrow {
|
||||
constexpr ImplicitNoThrow(int) noexcept {}
|
||||
};
|
||||
|
||||
struct ExplicitNoThrow {
|
||||
constexpr explicit ExplicitNoThrow(int) noexcept {}
|
||||
};
|
||||
|
||||
template <class To, class From>
|
||||
constexpr bool implicit_conversion(optional<To>&& opt, const From& v) {
|
||||
using O = optional<To>;
|
||||
@@ -98,6 +107,10 @@ void test_implicit() {
|
||||
static_assert(!test_convertible<O, std::in_place_t&&>(), "");
|
||||
static_assert(!test_convertible<O, const std::in_place_t&&>(), "");
|
||||
}
|
||||
{
|
||||
LIBCPP_ASSERT_NOEXCEPT(optional<ImplicitNoThrow>(42));
|
||||
LIBCPP_ASSERT_NOT_NOEXCEPT(optional<ImplicitThrow>(42));
|
||||
}
|
||||
#ifndef TEST_HAS_NO_EXCEPTIONS
|
||||
{
|
||||
try {
|
||||
@@ -139,6 +152,13 @@ void test_explicit() {
|
||||
}
|
||||
assert(T::alive == 0);
|
||||
}
|
||||
{
|
||||
LIBCPP_ASSERT_NOEXCEPT(optional<ExplicitNoThrow>(42));
|
||||
LIBCPP_ASSERT_NOT_NOEXCEPT(optional<ExplicitThrow>(42));
|
||||
}
|
||||
{
|
||||
LIBCPP_STATIC_ASSERT(std::is_nothrow_constructible<optional<std::vector<int>>, std::vector<int>&&>::value, "");
|
||||
}
|
||||
#ifndef TEST_HAS_NO_EXCEPTIONS
|
||||
{
|
||||
try {
|
||||
|
||||
Reference in new issue
Block a user