gcc/libstdc++-v3/testsuite/20_util/variant/exception_safety.cc
2021-01-04 10:26:59 +01:00

221 lines
4.8 KiB
C++

// Copyright (C) 2019-2021 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
#include <variant>
#include <vector>
#include <string>
#include <memory_resource>
#include <memory>
#include <functional>
#include <any>
#include <optional>
#include <testsuite_hooks.h>
void
test01()
{
#if _GLIBCXX_USE_CXX11_ABI
std::variant<int, std::pmr::string, std::pmr::vector<int>> v(1);
VERIFY( v.index() == 0 );
try
{
std::pmr::string s = "how long is a piece of SSO string?";
v.emplace<1>(s, std::pmr::null_memory_resource());
VERIFY( false );
}
catch(const std::bad_alloc&)
{
VERIFY( v.valueless_by_exception() );
}
v.emplace<0>(2);
VERIFY( v.index() == 0 );
try
{
v.emplace<2>({1, 2, 3}, std::pmr::null_memory_resource());
VERIFY( false );
}
catch(const std::bad_alloc&)
{
VERIFY( v.valueless_by_exception() );
}
#endif
}
void
test02()
{
struct X
{
X(int i) : i(1) { if (i > 2) throw 3; }
X(std::initializer_list<int> l) : i(2) { if (l.size() > 2) throw 3; }
int i;
};
static_assert( std::is_trivially_copyable_v<X> );
std::variant<std::monostate, int, X> v(111);
VERIFY( v.index() == 1 );
try
{
v.emplace<X>(3);
VERIFY( false );
}
catch(int)
{
VERIFY( !v.valueless_by_exception() );
VERIFY( v.index() == 1 );
VERIFY( std::get<int>(v) == 111 );
}
v.emplace<X>(1);
VERIFY( v.index() == 2 );
VERIFY( std::get<X>(v).i == 1 );
try
{
v.emplace<X>(3);
VERIFY( false );
}
catch(int)
{
VERIFY( !v.valueless_by_exception() );
VERIFY( v.index() == 2 );
VERIFY( std::get<X>(v).i == 1 );
}
try
{
v.emplace<X>({1, 2, 3});
VERIFY( false );
}
catch(int)
{
VERIFY( !v.valueless_by_exception() );
VERIFY( v.index() == 2 );
VERIFY( std::get<X>(v).i == 1 );
}
}
template<typename T, typename V>
bool bad_emplace(V& v)
{
struct X {
operator T() const { throw 1; }
};
const auto index = v.index();
try
{
if (std::is_same_v<T, std::any>)
{
// Need to test std::any differently, because emplace<std::any>(X{})
// would create a std::any with a contained X, instead of using
// X::operator any() to convert to std::any.
struct ThrowOnCopy {
ThrowOnCopy() { }
ThrowOnCopy(const ThrowOnCopy&) { throw 1; }
} t;
v.template emplace<std::any>(t);
}
else
v.template emplace<T>(X{});
}
catch (int)
{
return v.index() == index;
}
return false;
}
void
test03()
{
struct TriviallyCopyable { int i = 0; };
std::variant<std::monostate, int, TriviallyCopyable, std::optional<int>,
std::string, std::vector<int>, std::function<void()>, std::any,
std::shared_ptr<int>, std::weak_ptr<int>, std::unique_ptr<int>> v(1);
VERIFY( v.index() == 1 );
VERIFY( bad_emplace<int>(v) );
VERIFY( bad_emplace<TriviallyCopyable>(v) );
VERIFY( bad_emplace<std::optional<int>>(v) );
VERIFY( bad_emplace<std::string>(v) );
VERIFY( bad_emplace<std::vector<int>>(v) );
VERIFY( bad_emplace<std::function<void()>>(v) );
VERIFY( bad_emplace<std::any>(v) );
VERIFY( bad_emplace<std::shared_ptr<int>>(v) );
VERIFY( bad_emplace<std::weak_ptr<int>>(v) );
VERIFY( bad_emplace<std::unique_ptr<int>>(v) );
}
void
test04()
{
// LWG 2904. Make variant move-assignment more exception safe
struct ThrowOnCopy
{
ThrowOnCopy() { }
ThrowOnCopy(const ThrowOnCopy&) { throw 1; }
ThrowOnCopy& operator=(const ThrowOnCopy&) { throw "shouldn't happen"; }
ThrowOnCopy(ThrowOnCopy&&) noexcept { }
};
std::variant<int, ThrowOnCopy> v1(std::in_place_type<ThrowOnCopy>), v2(2);
try
{
v2 = v1; // uses variant<Types...>::operator=(const variant&)
VERIFY( false );
}
catch (int)
{
VERIFY( !v2.valueless_by_exception() );
VERIFY( v2.index() == 0 );
VERIFY( std::get<0>(v2) == 2 );
}
try
{
ThrowOnCopy toc;
v2 = toc; // uses variant<Types...>::operator=(T&&)
VERIFY( false );
}
catch (int)
{
VERIFY( !v2.valueless_by_exception() );
VERIFY( v2.index() == 0 );
VERIFY( std::get<0>(v2) == 2 );
}
}
int
main()
{
test01();
test02();
test03();
test04();
}