about summary refs log tree commit diff
path: root/third_party/abseil_cpp/absl/types/variant_exception_safety_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/abseil_cpp/absl/types/variant_exception_safety_test.cc')
-rw-r--r--third_party/abseil_cpp/absl/types/variant_exception_safety_test.cc532
1 files changed, 0 insertions, 532 deletions
diff --git a/third_party/abseil_cpp/absl/types/variant_exception_safety_test.cc b/third_party/abseil_cpp/absl/types/variant_exception_safety_test.cc
deleted file mode 100644
index 439c6e1df3..0000000000
--- a/third_party/abseil_cpp/absl/types/variant_exception_safety_test.cc
+++ /dev/null
@@ -1,532 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/types/variant.h"
-
-#include "absl/base/config.h"
-
-// This test is a no-op when absl::variant is an alias for std::variant and when
-// exceptions are not enabled.
-#if !defined(ABSL_USES_STD_VARIANT) && defined(ABSL_HAVE_EXCEPTIONS)
-
-#include <iostream>
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-#include "absl/base/internal/exception_safety_testing.h"
-#include "absl/memory/memory.h"
-
-// See comment in absl/base/config.h
-#if !defined(ABSL_INTERNAL_MSVC_2017_DBG_MODE)
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace {
-
-using ::testing::MakeExceptionSafetyTester;
-using ::testing::strong_guarantee;
-using ::testing::TestNothrowOp;
-using ::testing::TestThrowingCtor;
-
-using Thrower = testing::ThrowingValue<>;
-using CopyNothrow = testing::ThrowingValue<testing::TypeSpec::kNoThrowCopy>;
-using MoveNothrow = testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>;
-using ThrowingAlloc = testing::ThrowingAllocator<Thrower>;
-using ThrowerVec = std::vector<Thrower, ThrowingAlloc>;
-using ThrowingVariant =
-    absl::variant<Thrower, CopyNothrow, MoveNothrow, ThrowerVec>;
-
-struct ConversionException {};
-
-template <class T>
-struct ExceptionOnConversion {
-  operator T() const {  // NOLINT
-    throw ConversionException();
-  }
-};
-
-// Forces a variant into the valueless by exception state.
-void ToValuelessByException(ThrowingVariant& v) {  // NOLINT
-  try {
-    v.emplace<Thrower>();
-    v.emplace<Thrower>(ExceptionOnConversion<Thrower>());
-  } catch (const ConversionException&) {
-    // This space intentionally left blank.
-  }
-}
-
-// Check that variant is still in a usable state after an exception is thrown.
-testing::AssertionResult VariantInvariants(ThrowingVariant* v) {
-  using testing::AssertionFailure;
-  using testing::AssertionSuccess;
-
-  // Try using the active alternative
-  if (absl::holds_alternative<Thrower>(*v)) {
-    auto& t = absl::get<Thrower>(*v);
-    t = Thrower{-100};
-    if (t.Get() != -100) {
-      return AssertionFailure() << "Thrower should be assigned -100";
-    }
-  } else if (absl::holds_alternative<ThrowerVec>(*v)) {
-    auto& tv = absl::get<ThrowerVec>(*v);
-    tv.clear();
-    tv.emplace_back(-100);
-    if (tv.size() != 1 || tv[0].Get() != -100) {
-      return AssertionFailure() << "ThrowerVec should be {Thrower{-100}}";
-    }
-  } else if (absl::holds_alternative<CopyNothrow>(*v)) {
-    auto& t = absl::get<CopyNothrow>(*v);
-    t = CopyNothrow{-100};
-    if (t.Get() != -100) {
-      return AssertionFailure() << "CopyNothrow should be assigned -100";
-    }
-  } else if (absl::holds_alternative<MoveNothrow>(*v)) {
-    auto& t = absl::get<MoveNothrow>(*v);
-    t = MoveNothrow{-100};
-    if (t.Get() != -100) {
-      return AssertionFailure() << "MoveNothrow should be assigned -100";
-    }
-  }
-
-  // Try making variant valueless_by_exception
-  if (!v->valueless_by_exception()) ToValuelessByException(*v);
-  if (!v->valueless_by_exception()) {
-    return AssertionFailure() << "Variant should be valueless_by_exception";
-  }
-  try {
-    auto unused = absl::get<Thrower>(*v);
-    static_cast<void>(unused);
-    return AssertionFailure() << "Variant should not contain Thrower";
-  } catch (const absl::bad_variant_access&) {
-  } catch (...) {
-    return AssertionFailure() << "Unexpected exception throw from absl::get";
-  }
-
-  // Try using the variant
-  v->emplace<Thrower>(100);
-  if (!absl::holds_alternative<Thrower>(*v) ||
-      absl::get<Thrower>(*v) != Thrower(100)) {
-    return AssertionFailure() << "Variant should contain Thrower(100)";
-  }
-  v->emplace<ThrowerVec>({Thrower(100)});
-  if (!absl::holds_alternative<ThrowerVec>(*v) ||
-      absl::get<ThrowerVec>(*v)[0] != Thrower(100)) {
-    return AssertionFailure()
-           << "Variant should contain ThrowerVec{Thrower(100)}";
-  }
-  return AssertionSuccess();
-}
-
-template <typename... Args>
-Thrower ExpectedThrower(Args&&... args) {
-  return Thrower(42, args...);
-}
-
-ThrowerVec ExpectedThrowerVec() { return {Thrower(100), Thrower(200)}; }
-ThrowingVariant ValuelessByException() {
-  ThrowingVariant v;
-  ToValuelessByException(v);
-  return v;
-}
-ThrowingVariant WithThrower() { return Thrower(39); }
-ThrowingVariant WithThrowerVec() {
-  return ThrowerVec{Thrower(1), Thrower(2), Thrower(3)};
-}
-ThrowingVariant WithCopyNoThrow() { return CopyNothrow(39); }
-ThrowingVariant WithMoveNoThrow() { return MoveNothrow(39); }
-
-TEST(VariantExceptionSafetyTest, DefaultConstructor) {
-  TestThrowingCtor<ThrowingVariant>();
-}
-
-TEST(VariantExceptionSafetyTest, CopyConstructor) {
-  {
-    ThrowingVariant v(ExpectedThrower());
-    TestThrowingCtor<ThrowingVariant>(v);
-  }
-  {
-    ThrowingVariant v(ExpectedThrowerVec());
-    TestThrowingCtor<ThrowingVariant>(v);
-  }
-  {
-    ThrowingVariant v(ValuelessByException());
-    TestThrowingCtor<ThrowingVariant>(v);
-  }
-}
-
-TEST(VariantExceptionSafetyTest, MoveConstructor) {
-  {
-    ThrowingVariant v(ExpectedThrower());
-    TestThrowingCtor<ThrowingVariant>(std::move(v));
-  }
-  {
-    ThrowingVariant v(ExpectedThrowerVec());
-    TestThrowingCtor<ThrowingVariant>(std::move(v));
-  }
-  {
-    ThrowingVariant v(ValuelessByException());
-    TestThrowingCtor<ThrowingVariant>(std::move(v));
-  }
-}
-
-TEST(VariantExceptionSafetyTest, ValueConstructor) {
-  TestThrowingCtor<ThrowingVariant>(ExpectedThrower());
-  TestThrowingCtor<ThrowingVariant>(ExpectedThrowerVec());
-}
-
-TEST(VariantExceptionSafetyTest, InPlaceTypeConstructor) {
-  TestThrowingCtor<ThrowingVariant>(absl::in_place_type_t<Thrower>{},
-                                    ExpectedThrower());
-  TestThrowingCtor<ThrowingVariant>(absl::in_place_type_t<ThrowerVec>{},
-                                    ExpectedThrowerVec());
-}
-
-TEST(VariantExceptionSafetyTest, InPlaceIndexConstructor) {
-  TestThrowingCtor<ThrowingVariant>(absl::in_place_index_t<0>{},
-                                    ExpectedThrower());
-  TestThrowingCtor<ThrowingVariant>(absl::in_place_index_t<3>{},
-                                    ExpectedThrowerVec());
-}
-
-TEST(VariantExceptionSafetyTest, CopyAssign) {
-  // variant& operator=(const variant& rhs);
-  // Let j be rhs.index()
-  {
-    // - neither *this nor rhs holds a value
-    const ThrowingVariant rhs = ValuelessByException();
-    ThrowingVariant lhs = ValuelessByException();
-    EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; }));
-  }
-  {
-    // - *this holds a value but rhs does not
-    const ThrowingVariant rhs = ValuelessByException();
-    ThrowingVariant lhs = WithThrower();
-    EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; }));
-  }
-  // - index() == j
-  {
-    const ThrowingVariant rhs(ExpectedThrower());
-    auto tester =
-        MakeExceptionSafetyTester()
-            .WithInitialValue(WithThrower())
-            .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
-    EXPECT_TRUE(tester.WithContracts(VariantInvariants).Test());
-    EXPECT_FALSE(tester.WithContracts(strong_guarantee).Test());
-  }
-  {
-    const ThrowingVariant rhs(ExpectedThrowerVec());
-    auto tester =
-        MakeExceptionSafetyTester()
-            .WithInitialValue(WithThrowerVec())
-            .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
-    EXPECT_TRUE(tester.WithContracts(VariantInvariants).Test());
-    EXPECT_FALSE(tester.WithContracts(strong_guarantee).Test());
-  }
-  // libstdc++ std::variant has bugs on copy assignment regarding exception
-  // safety.
-#if !(defined(ABSL_USES_STD_VARIANT) && defined(__GLIBCXX__))
-  // index() != j
-  // if is_nothrow_copy_constructible_v<Tj> or
-  // !is_nothrow_move_constructible<Tj> is true, equivalent to
-  // emplace<j>(get<j>(rhs))
-  {
-    // is_nothrow_copy_constructible_v<Tj> == true
-    // should not throw because emplace() invokes Tj's copy ctor
-    // which should not throw.
-    const ThrowingVariant rhs(CopyNothrow{});
-    ThrowingVariant lhs = WithThrower();
-    EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; }));
-  }
-  {
-    // is_nothrow_copy_constructible<Tj> == false &&
-    // is_nothrow_move_constructible<Tj> == false
-    // should provide basic guarantee because emplace() invokes Tj's copy ctor
-    // which may throw.
-    const ThrowingVariant rhs(ExpectedThrower());
-    auto tester =
-        MakeExceptionSafetyTester()
-            .WithInitialValue(WithCopyNoThrow())
-            .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
-    EXPECT_TRUE(tester
-                    .WithContracts(VariantInvariants,
-                                   [](ThrowingVariant* lhs) {
-                                     return lhs->valueless_by_exception();
-                                   })
-                    .Test());
-    EXPECT_FALSE(tester.WithContracts(strong_guarantee).Test());
-  }
-#endif  // !(defined(ABSL_USES_STD_VARIANT) && defined(__GLIBCXX__))
-  {
-    // is_nothrow_copy_constructible_v<Tj> == false &&
-    // is_nothrow_move_constructible_v<Tj> == true
-    // should provide strong guarantee because it is equivalent to
-    // operator=(variant(rhs)) which creates a temporary then invoke the move
-    // ctor which shouldn't throw.
-    const ThrowingVariant rhs(MoveNothrow{});
-    EXPECT_TRUE(MakeExceptionSafetyTester()
-                    .WithInitialValue(WithThrower())
-                    .WithContracts(VariantInvariants, strong_guarantee)
-                    .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
-  }
-}
-
-TEST(VariantExceptionSafetyTest, MoveAssign) {
-  // variant& operator=(variant&& rhs);
-  // Let j be rhs.index()
-  {
-    // - neither *this nor rhs holds a value
-    ThrowingVariant rhs = ValuelessByException();
-    ThrowingVariant lhs = ValuelessByException();
-    EXPECT_TRUE(TestNothrowOp([&]() { lhs = std::move(rhs); }));
-  }
-  {
-    // - *this holds a value but rhs does not
-    ThrowingVariant rhs = ValuelessByException();
-    ThrowingVariant lhs = WithThrower();
-    EXPECT_TRUE(TestNothrowOp([&]() { lhs = std::move(rhs); }));
-  }
-  {
-    // - index() == j
-    // assign get<j>(std::move(rhs)) to the value contained in *this.
-    // If an exception is thrown during call to Tj's move assignment, the state
-    // of the contained value is as defined by the exception safety guarantee of
-    // Tj's move assignment; index() will be j.
-    ThrowingVariant rhs(ExpectedThrower());
-    size_t j = rhs.index();
-    // Since Thrower's move assignment has basic guarantee, so should variant's.
-    auto tester = MakeExceptionSafetyTester()
-                      .WithInitialValue(WithThrower())
-                      .WithOperation([&](ThrowingVariant* lhs) {
-                        auto copy = rhs;
-                        *lhs = std::move(copy);
-                      });
-    EXPECT_TRUE(tester
-                    .WithContracts(
-                        VariantInvariants,
-                        [&](ThrowingVariant* lhs) { return lhs->index() == j; })
-                    .Test());
-    EXPECT_FALSE(tester.WithContracts(strong_guarantee).Test());
-  }
-  {
-    // libstdc++ introduced a regression between 2018-09-25 and 2019-01-06.
-    // The fix is targeted for gcc-9.
-    // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87431#c7
-    // https://gcc.gnu.org/viewcvs/gcc?view=revision&revision=267614
-#if !(defined(ABSL_USES_STD_VARIANT) && \
-      defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE == 8)
-    // - otherwise (index() != j), equivalent to
-    // emplace<j>(get<j>(std::move(rhs)))
-    // - If an exception is thrown during the call to Tj's move construction
-    // (with j being rhs.index()), the variant will hold no value.
-    ThrowingVariant rhs(CopyNothrow{});
-    EXPECT_TRUE(MakeExceptionSafetyTester()
-                    .WithInitialValue(WithThrower())
-                    .WithContracts(VariantInvariants,
-                                   [](ThrowingVariant* lhs) {
-                                     return lhs->valueless_by_exception();
-                                   })
-                    .Test([&](ThrowingVariant* lhs) {
-                      auto copy = rhs;
-                      *lhs = std::move(copy);
-                    }));
-#endif  // !(defined(ABSL_USES_STD_VARIANT) &&
-        //   defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE == 8)
-  }
-}
-
-TEST(VariantExceptionSafetyTest, ValueAssign) {
-  // template<class T> variant& operator=(T&& t);
-  // Let Tj be the type that is selected by overload resolution to be assigned.
-  {
-    // If *this holds a Tj, assigns std::forward<T>(t) to the value contained in
-    // *this. If  an exception is thrown during the assignment of
-    // std::forward<T>(t) to the value contained in *this, the state of the
-    // contained value and t are as defined by the exception safety guarantee of
-    // the assignment expression; valueless_by_exception() will be false.
-    // Since Thrower's copy/move assignment has basic guarantee, so should
-    // variant's.
-    Thrower rhs = ExpectedThrower();
-    // copy assign
-    auto copy_tester =
-        MakeExceptionSafetyTester()
-            .WithInitialValue(WithThrower())
-            .WithOperation([rhs](ThrowingVariant* lhs) { *lhs = rhs; });
-    EXPECT_TRUE(copy_tester
-                    .WithContracts(VariantInvariants,
-                                   [](ThrowingVariant* lhs) {
-                                     return !lhs->valueless_by_exception();
-                                   })
-                    .Test());
-    EXPECT_FALSE(copy_tester.WithContracts(strong_guarantee).Test());
-    // move assign
-    auto move_tester = MakeExceptionSafetyTester()
-                           .WithInitialValue(WithThrower())
-                           .WithOperation([&](ThrowingVariant* lhs) {
-                             auto copy = rhs;
-                             *lhs = std::move(copy);
-                           });
-    EXPECT_TRUE(move_tester
-                    .WithContracts(VariantInvariants,
-                                   [](ThrowingVariant* lhs) {
-                                     return !lhs->valueless_by_exception();
-                                   })
-                    .Test());
-
-    EXPECT_FALSE(move_tester.WithContracts(strong_guarantee).Test());
-  }
-  // Otherwise (*this holds something else), if is_nothrow_constructible_v<Tj,
-  // T> || !is_nothrow_move_constructible_v<Tj> is true, equivalent to
-  // emplace<j>(std::forward<T>(t)).
-  // We simplify the test by letting T = `const Tj&`  or `Tj&&`, so we can reuse
-  // the CopyNothrow and MoveNothrow types.
-
-  // if is_nothrow_constructible_v<Tj, T>
-  // (i.e. is_nothrow_copy/move_constructible_v<Tj>) is true, emplace() just
-  // invokes the copy/move constructor and it should not throw.
-  {
-    const CopyNothrow rhs;
-    ThrowingVariant lhs = WithThrower();
-    EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; }));
-  }
-  {
-    MoveNothrow rhs;
-    ThrowingVariant lhs = WithThrower();
-    EXPECT_TRUE(TestNothrowOp([&]() { lhs = std::move(rhs); }));
-  }
-  // if is_nothrow_constructible_v<Tj, T> == false &&
-  // is_nothrow_move_constructible<Tj> == false
-  // emplace() invokes the copy/move constructor which may throw so it should
-  // provide basic guarantee and variant object might not hold a value.
-  {
-    Thrower rhs = ExpectedThrower();
-    // copy
-    auto copy_tester =
-        MakeExceptionSafetyTester()
-            .WithInitialValue(WithCopyNoThrow())
-            .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
-    EXPECT_TRUE(copy_tester
-                    .WithContracts(VariantInvariants,
-                                   [](ThrowingVariant* lhs) {
-                                     return lhs->valueless_by_exception();
-                                   })
-                    .Test());
-    EXPECT_FALSE(copy_tester.WithContracts(strong_guarantee).Test());
-    // move
-    auto move_tester = MakeExceptionSafetyTester()
-                           .WithInitialValue(WithCopyNoThrow())
-                           .WithOperation([](ThrowingVariant* lhs) {
-                             *lhs = ExpectedThrower(testing::nothrow_ctor);
-                           });
-    EXPECT_TRUE(move_tester
-                    .WithContracts(VariantInvariants,
-                                   [](ThrowingVariant* lhs) {
-                                     return lhs->valueless_by_exception();
-                                   })
-                    .Test());
-    EXPECT_FALSE(move_tester.WithContracts(strong_guarantee).Test());
-  }
-  // Otherwise (if is_nothrow_constructible_v<Tj, T> == false &&
-  // is_nothrow_move_constructible<Tj> == true),
-  // equivalent to operator=(variant(std::forward<T>(t)))
-  // This should have strong guarantee because it creates a temporary variant
-  // and operator=(variant&&) invokes Tj's move ctor which doesn't throw.
-  // libstdc++ std::variant has bugs on conversion assignment regarding
-  // exception safety.
-#if !(defined(ABSL_USES_STD_VARIANT) && defined(__GLIBCXX__))
-  {
-    MoveNothrow rhs;
-    EXPECT_TRUE(MakeExceptionSafetyTester()
-                    .WithInitialValue(WithThrower())
-                    .WithContracts(VariantInvariants, strong_guarantee)
-                    .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
-  }
-#endif  // !(defined(ABSL_USES_STD_VARIANT) && defined(__GLIBCXX__))
-}
-
-TEST(VariantExceptionSafetyTest, Emplace) {
-  // If an exception during the initialization of the contained value, the
-  // variant might not hold a value. The standard requires emplace() to provide
-  // only basic guarantee.
-  {
-    Thrower args = ExpectedThrower();
-    auto tester = MakeExceptionSafetyTester()
-                      .WithInitialValue(WithThrower())
-                      .WithOperation([&args](ThrowingVariant* v) {
-                        v->emplace<Thrower>(args);
-                      });
-    EXPECT_TRUE(tester
-                    .WithContracts(VariantInvariants,
-                                   [](ThrowingVariant* v) {
-                                     return v->valueless_by_exception();
-                                   })
-                    .Test());
-    EXPECT_FALSE(tester.WithContracts(strong_guarantee).Test());
-  }
-}
-
-TEST(VariantExceptionSafetyTest, Swap) {
-  // if both are valueless_by_exception(), no effect
-  {
-    ThrowingVariant rhs = ValuelessByException();
-    ThrowingVariant lhs = ValuelessByException();
-    EXPECT_TRUE(TestNothrowOp([&]() { lhs.swap(rhs); }));
-  }
-  // if index() == rhs.index(), calls swap(get<i>(*this), get<i>(rhs))
-  // where i is index().
-  {
-    ThrowingVariant rhs = ExpectedThrower();
-    EXPECT_TRUE(MakeExceptionSafetyTester()
-                    .WithInitialValue(WithThrower())
-                    .WithContracts(VariantInvariants)
-                    .Test([&](ThrowingVariant* lhs) {
-                      auto copy = rhs;
-                      lhs->swap(copy);
-                    }));
-  }
-  // Otherwise, exchanges the value of rhs and *this. The exception safety
-  // involves variant in moved-from state which is not specified in the
-  // standard, and since swap is 3-step it's impossible for it to provide a
-  // overall strong guarantee. So, we are only checking basic guarantee here.
-  {
-    ThrowingVariant rhs = ExpectedThrower();
-    EXPECT_TRUE(MakeExceptionSafetyTester()
-                    .WithInitialValue(WithCopyNoThrow())
-                    .WithContracts(VariantInvariants)
-                    .Test([&](ThrowingVariant* lhs) {
-                      auto copy = rhs;
-                      lhs->swap(copy);
-                    }));
-  }
-  {
-    ThrowingVariant rhs = ExpectedThrower();
-    EXPECT_TRUE(MakeExceptionSafetyTester()
-                    .WithInitialValue(WithCopyNoThrow())
-                    .WithContracts(VariantInvariants)
-                    .Test([&](ThrowingVariant* lhs) {
-                      auto copy = rhs;
-                      copy.swap(*lhs);
-                    }));
-  }
-}
-
-}  // namespace
-ABSL_NAMESPACE_END
-}  // namespace absl
-
-#endif  // !defined(ABSL_INTERNAL_MSVC_2017_DBG_MODE)
-
-#endif  // #if !defined(ABSL_USES_STD_VARIANT) && defined(ABSL_HAVE_EXCEPTIONS)