Mark not_null constructors as noexcept when underlying type can be moved with no exception (#1135)

This enables possible optimisations for trivial types. This also avoids a bug
in std::variant::emplace from GNU's libstdc++.

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106547
This commit is contained in:
Nicholas Guriev 2023-10-19 01:15:26 +03:00 committed by GitHub
parent 52212c2d76
commit e64c97fc2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 15 additions and 3 deletions

View File

@ -100,19 +100,19 @@ public:
static_assert(details::is_comparable_to_nullptr<T>::value, "T cannot be compared to nullptr."); static_assert(details::is_comparable_to_nullptr<T>::value, "T cannot be compared to nullptr.");
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>> template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
constexpr not_null(U&& u) : ptr_(std::forward<U>(u)) constexpr not_null(U&& u) noexcept(std::is_nothrow_move_constructible<T>::value) : ptr_(std::forward<U>(u))
{ {
Expects(ptr_ != nullptr); Expects(ptr_ != nullptr);
} }
template <typename = std::enable_if_t<!std::is_same<std::nullptr_t, T>::value>> template <typename = std::enable_if_t<!std::is_same<std::nullptr_t, T>::value>>
constexpr not_null(T u) : ptr_(std::move(u)) constexpr not_null(T u) noexcept(std::is_nothrow_move_constructible<T>::value) : ptr_(std::move(u))
{ {
Expects(ptr_ != nullptr); Expects(ptr_ != nullptr);
} }
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>> template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
constexpr not_null(const not_null<U>& other) : not_null(other.get()) constexpr not_null(const not_null<U>& other) noexcept(std::is_nothrow_move_constructible<T>::value) : not_null(other.get())
{} {}
not_null(const not_null& other) = default; not_null(const not_null& other) = default;

View File

@ -24,6 +24,7 @@
#include <sstream> // for operator<<, ostringstream, basic_ostream:... #include <sstream> // for operator<<, ostringstream, basic_ostream:...
#include <string> // for basic_string, operator==, string, operator<< #include <string> // for basic_string, operator==, string, operator<<
#include <typeinfo> // for type_info #include <typeinfo> // for type_info
#include <variant> // for variant, monostate, get
#include "deathTestCommon.h" #include "deathTestCommon.h"
using namespace gsl; using namespace gsl;
@ -514,6 +515,17 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
} }
#endif #endif
} }
TEST(notnull_tests, TestVariantEmplace)
{
int i = 0;
std::variant<std::monostate, not_null<int*>> v;
v.emplace<not_null<int*>>(&i);
EXPECT_FALSE(v.valueless_by_exception());
EXPECT_TRUE(v.index() == 1);
EXPECT_TRUE(std::get<not_null<int*>>(v) == &i);
}
#endif // #if defined(__cplusplus) && (__cplusplus >= 201703L) #endif // #if defined(__cplusplus) && (__cplusplus >= 201703L)
TEST(notnull_tests, TestMakeNotNull) TEST(notnull_tests, TestMakeNotNull)