// 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(); }