// Copyright (C) 2019 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
// .
// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
#include
#include
#include
#include
#include
#include
#include
#include
void
test01()
{
#if _GLIBCXX_USE_CXX11_ABI
std::variant> 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 l) : i(2) { if (l.size() > 2) throw 3; }
int i;
};
static_assert( std::is_trivially_copyable_v );
std::variant v(111);
VERIFY( v.index() == 1 );
try
{
v.emplace(3);
VERIFY( false );
}
catch(int)
{
VERIFY( !v.valueless_by_exception() );
VERIFY( v.index() == 1 );
VERIFY( std::get(v) == 111 );
}
v.emplace(1);
VERIFY( v.index() == 2 );
VERIFY( std::get(v).i == 1 );
try
{
v.emplace(3);
VERIFY( false );
}
catch(int)
{
VERIFY( !v.valueless_by_exception() );
VERIFY( v.index() == 2 );
VERIFY( std::get(v).i == 1 );
}
try
{
v.emplace({1, 2, 3});
VERIFY( false );
}
catch(int)
{
VERIFY( !v.valueless_by_exception() );
VERIFY( v.index() == 2 );
VERIFY( std::get(v).i == 1 );
}
}
template
bool bad_emplace(V& v)
{
struct X {
operator T() const { throw 1; }
};
const auto index = v.index();
try
{
if (std::is_same_v)
{
// Need to test std::any differently, because emplace(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(t);
}
else
v.template emplace(X{});
}
catch (int)
{
return v.index() == index;
}
return false;
}
void
test03()
{
struct TriviallyCopyable { int i = 0; };
std::variant,
std::string, std::vector, std::function, std::any,
std::shared_ptr, std::weak_ptr, std::unique_ptr> v(1);
VERIFY( v.index() == 1 );
VERIFY( bad_emplace(v) );
VERIFY( bad_emplace(v) );
VERIFY( bad_emplace>(v) );
VERIFY( bad_emplace(v) );
VERIFY( bad_emplace>(v) );
VERIFY( bad_emplace>(v) );
VERIFY( bad_emplace(v) );
VERIFY( bad_emplace>(v) );
VERIFY( bad_emplace>(v) );
VERIFY( bad_emplace>(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 v1(std::in_place_type), v2(2);
try
{
v2 = v1; // uses variant::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::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();
}