Commit 3aa61df5 authored by Hidehiko Abe's avatar Hidehiko Abe Committed by Commit Bot

Mark noexcept for Optional to catch up with C++17 spec.

Although, exceptions are not used in chromium,
some standard libraries depend on noexcept markers.
Because Optional is an alternative of standard library,
it is nice to have such markers.

BUG=784732
TEST=Ran trybot.

Change-Id: I958bc3f18e1d898d65cc106748795c6a27462650
Reviewed-on: https://chromium-review.googlesource.com/857358Reviewed-by: default avatardanakj <danakj@chromium.org>
Commit-Queue: Hidehiko Abe <hidehiko@chromium.org>
Cr-Commit-Position: refs/heads/master@{#539012}
parent b07aa404
...@@ -244,7 +244,9 @@ class OptionalBase { ...@@ -244,7 +244,9 @@ class OptionalBase {
return *this; return *this;
} }
OptionalBase& operator=(OptionalBase&& other) { OptionalBase& operator=(OptionalBase&& other) noexcept(
std::is_nothrow_move_assignable<T>::value&&
std::is_nothrow_move_constructible<T>::value) {
MoveAssign(std::move(other)); MoveAssign(std::move(other));
return *this; return *this;
} }
...@@ -401,6 +403,7 @@ using RemoveCvRefT = std::remove_cv_t<std::remove_reference_t<T>>; ...@@ -401,6 +403,7 @@ using RemoveCvRefT = std::remove_cv_t<std::remove_reference_t<T>>;
// - Constructors do not use 'constexpr' as it is a C++14 extension. // - Constructors do not use 'constexpr' as it is a C++14 extension.
// - 'constexpr' might be missing in some places for reasons specified locally. // - 'constexpr' might be missing in some places for reasons specified locally.
// - No exceptions are thrown, because they are banned from Chromium. // - No exceptions are thrown, because they are banned from Chromium.
// Marked noexcept for only move constructor and move assign operators.
// - All the non-members are in the 'base' namespace instead of 'std'. // - All the non-members are in the 'base' namespace instead of 'std'.
// //
// Note that T cannot have a constructor T(Optional<T>) etc. Optional<T> checks // Note that T cannot have a constructor T(Optional<T>) etc. Optional<T> checks
...@@ -424,7 +427,8 @@ class Optional ...@@ -424,7 +427,8 @@ class Optional
// Defer default/copy/move constructor implementation to OptionalBase. // Defer default/copy/move constructor implementation to OptionalBase.
constexpr Optional() = default; constexpr Optional() = default;
constexpr Optional(const Optional& other) = default; constexpr Optional(const Optional& other) = default;
constexpr Optional(Optional&& other) = default; constexpr Optional(Optional&& other) noexcept(
std::is_nothrow_move_constructible<T>::value) = default;
constexpr Optional(nullopt_t) {} // NOLINT(runtime/explicit) constexpr Optional(nullopt_t) {} // NOLINT(runtime/explicit)
...@@ -511,7 +515,9 @@ class Optional ...@@ -511,7 +515,9 @@ class Optional
// Defer copy-/move- assign operator implementation to OptionalBase. // Defer copy-/move- assign operator implementation to OptionalBase.
Optional& operator=(const Optional& other) = default; Optional& operator=(const Optional& other) = default;
Optional& operator=(Optional&& other) = default; Optional& operator=(Optional&& other) noexcept(
std::is_nothrow_move_assignable<T>::value&&
std::is_nothrow_move_constructible<T>::value) = default;
Optional& operator=(nullopt_t) { Optional& operator=(nullopt_t) {
FreeIfNeeded(); FreeIfNeeded();
...@@ -634,9 +640,7 @@ class Optional ...@@ -634,9 +640,7 @@ class Optional
swap(**this, *other); swap(**this, *other);
} }
void reset() { void reset() { FreeIfNeeded(); }
FreeIfNeeded();
}
template <class... Args> template <class... Args>
T& emplace(Args&&... args) { T& emplace(Args&&... args) {
......
...@@ -2110,4 +2110,41 @@ TEST(OptionalTest, DontCallNewMemberFunction) { ...@@ -2110,4 +2110,41 @@ TEST(OptionalTest, DontCallNewMemberFunction) {
EXPECT_TRUE(a.has_value()); EXPECT_TRUE(a.has_value());
} }
TEST(OptionalTest, Noexcept) {
// non-noexcept move-constructible.
struct Test1 {
Test1(Test1&&) {}
Test1& operator=(Test1&&) = default;
};
// non-noexcept move-assignable.
struct Test2 {
Test2(Test2&&) = default;
Test2& operator=(Test2&&) { return *this; }
};
static_assert(
noexcept(Optional<int>(std::declval<Optional<int>>())),
"move constructor for noexcept move-constructible T must be noexcept");
static_assert(
!noexcept(Optional<Test1>(std::declval<Optional<Test1>>())),
"move constructor for non-noexcept move-constructible T must not be "
"noexcept");
static_assert(
noexcept(Optional<Test2>(std::declval<Optional<Test2>>())),
"move constructor for noexcept move-constructible T must be noexcept");
static_assert(
noexcept(std::declval<Optional<int>>() = std::declval<Optional<int>>()),
"move assign for noexcept move-constructible/move-assignable T "
"must be noexcept");
static_assert(
!noexcept(std::declval<Optional<Test1>>() =
std::declval<Optional<Test1>>()),
"move assign for non-noexcept move-constructible T must not be noexcept");
static_assert(
!noexcept(std::declval<Optional<Test2>>() =
std::declval<Optional<Test2>>()),
"move assign for non-noexcept move-assignable T must not be noexcept");
}
} // namespace base } // namespace base
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment