From 524cab295980087241134f5d8142252a975f90a6 Mon Sep 17 00:00:00 2001 From: Omar <42871183+OmarSaber98@users.noreply.github.com> Date: Thu, 9 Dec 2021 05:44:47 +0200 Subject: [PATCH] LWG-2762 `unique_ptr` `operator*()` should be `noexcept` (#2376) Co-authored-by: Stephan T. Lavavej --- stl/inc/memory | 2 +- stl/inc/optional | 12 ++--- tests/std/tests/P0220R1_optional/test.cpp | 54 +++-------------------- 3 files changed, 13 insertions(+), 55 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 8de1c1561..00e5fa3f9 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -3242,7 +3242,7 @@ public: return _Mypair._Get_first(); } - _NODISCARD add_lvalue_reference_t<_Ty> operator*() const noexcept /* strengthened */ { + _NODISCARD add_lvalue_reference_t<_Ty> operator*() const noexcept(noexcept(*_STD declval())) { return *_Mypair._Myval2; } diff --git a/stl/inc/optional b/stl/inc/optional index f0fd6f996..b1f2dac53 100644 --- a/stl/inc/optional +++ b/stl/inc/optional @@ -342,38 +342,38 @@ public: } } - _NODISCARD constexpr const _Ty* operator->() const { + _NODISCARD constexpr const _Ty* operator->() const noexcept { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(this->_Has_value, "Cannot access value of empty optional"); #endif // _CONTAINER_DEBUG_LEVEL > 0 return _STD addressof(this->_Value); } - _NODISCARD constexpr _Ty* operator->() { + _NODISCARD constexpr _Ty* operator->() noexcept { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(this->_Has_value, "Cannot access value of empty optional"); #endif // _CONTAINER_DEBUG_LEVEL > 0 return _STD addressof(this->_Value); } - _NODISCARD constexpr const _Ty& operator*() const& { + _NODISCARD constexpr const _Ty& operator*() const& noexcept { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(this->_Has_value, "Cannot access value of empty optional"); #endif // _CONTAINER_DEBUG_LEVEL > 0 return this->_Value; } - _NODISCARD constexpr _Ty& operator*() & { + _NODISCARD constexpr _Ty& operator*() & noexcept { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(this->_Has_value, "Cannot access value of empty optional"); #endif // _CONTAINER_DEBUG_LEVEL > 0 return this->_Value; } - _NODISCARD constexpr _Ty&& operator*() && { + _NODISCARD constexpr _Ty&& operator*() && noexcept { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(this->_Has_value, "Cannot access value of empty optional"); #endif // _CONTAINER_DEBUG_LEVEL > 0 return _STD move(this->_Value); } - _NODISCARD constexpr const _Ty&& operator*() const&& { + _NODISCARD constexpr const _Ty&& operator*() const&& noexcept { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(this->_Has_value, "Cannot access value of empty optional"); #endif // _CONTAINER_DEBUG_LEVEL > 0 diff --git a/tests/std/tests/P0220R1_optional/test.cpp b/tests/std/tests/P0220R1_optional/test.cpp index 72f092800..ad7ea5f3f 100644 --- a/tests/std/tests/P0220R1_optional/test.cpp +++ b/tests/std/tests/P0220R1_optional/test.cpp @@ -4776,14 +4776,7 @@ int run_test() { optional opt; ((void)opt); ASSERT_SAME_TYPE(decltype(*opt), X&); - // ASSERT_NOT_NOEXCEPT(*opt); - // TODO: This assertion fails with GCC because it can see that - // (A) operator*() is constexpr, and - // (B) there is no path through the function that throws. - // It's arguable if this is the correct behavior for the noexcept - // operator. - // Regardless this function should still be noexcept(false) because - // it has a narrow contract. + STATIC_ASSERT(noexcept(*opt)); } { optional opt(X{}); @@ -4847,14 +4840,7 @@ int run_test() { const optional opt; ((void)opt); ASSERT_SAME_TYPE(decltype(*opt), X const&); - // ASSERT_NOT_NOEXCEPT(*opt); - // TODO: This assertion fails with GCC because it can see that - // (A) operator*() is constexpr, and - // (B) there is no path through the function that throws. - // It's arguable if this is the correct behavior for the noexcept - // operator. - // Regardless this function should still be noexcept(false) because - // it has a narrow contract. + STATIC_ASSERT(noexcept(*opt)); } { constexpr optional opt(X{}); @@ -4921,14 +4907,7 @@ int run_test() { const optional opt; ((void)opt); ASSERT_SAME_TYPE(decltype(*std::move(opt)), X const &&); - // ASSERT_NOT_NOEXCEPT(*std::move(opt)); - // TODO: This assertion fails with GCC because it can see that - // (A) operator*() is constexpr, and - // (B) there is no path through the function that throws. - // It's arguable if this is the correct behavior for the noexcept - // operator. - // Regardless this function should still be noexcept(false) because - // it has a narrow contract. + STATIC_ASSERT(noexcept(*std::move(opt))); } { constexpr optional opt(X{}); @@ -5002,14 +4981,7 @@ int run_test() { optional opt; ((void)opt); ASSERT_SAME_TYPE(decltype(*std::move(opt)), X&&); - // ASSERT_NOT_NOEXCEPT(*std::move(opt)); - // TODO: This assertion fails with GCC because it can see that - // (A) operator*() is constexpr, and - // (B) there is no path through the function that throws. - // It's arguable if this is the correct behavior for the noexcept - // operator. - // Regardless this function should still be noexcept(false) because - // it has a narrow contract. + STATIC_ASSERT(noexcept(*std::move(opt))); } { optional opt(X{}); @@ -5119,14 +5091,7 @@ int run_test() { std::optional opt; ((void)opt); ASSERT_SAME_TYPE(decltype(opt.operator->()), X*); - // ASSERT_NOT_NOEXCEPT(opt.operator->()); - // TODO: This assertion fails with GCC because it can see that - // (A) operator->() is constexpr, and - // (B) there is no path through the function that throws. - // It's arguable if this is the correct behavior for the noexcept - // operator. - // Regardless this function should still be noexcept(false) because - // it has a narrow contract. + STATIC_ASSERT(noexcept(opt.operator->())); } { optional opt(X{}); @@ -5195,14 +5160,7 @@ int run_test() { const std::optional opt; ((void)opt); ASSERT_SAME_TYPE(decltype(opt.operator->()), X const*); - // ASSERT_NOT_NOEXCEPT(opt.operator->()); - // TODO: This assertion fails with GCC because it can see that - // (A) operator->() is constexpr, and - // (B) there is no path through the function that throws. - // It's arguable if this is the correct behavior for the noexcept - // operator. - // Regardless this function should still be noexcept(false) because - // it has a narrow contract. + STATIC_ASSERT(noexcept(opt.operator->())); } { constexpr optional opt(X{});