blob: b13e8b92329fea5dced185d56fde19ea3d4e2b2c [file] [log] [blame]
// { dg-do run { target c++26 } }
#include <optional>
#include <type_traits>
#include <testsuite_hooks.h>
struct NonTrivial
{
constexpr NonTrivial() {}
constexpr NonTrivial(NonTrivial const&) {};
constexpr ~NonTrivial() {};
};
struct NonMovable
{
constexpr NonMovable() {}
NonMovable(NonMovable&&) = delete;
};
template<typename T>
struct Conv
{
T t;
constexpr operator T() const noexcept
{ return t; }
};
struct Tracker
{
int copy = 0;
int move = 0;
Tracker() = default;
constexpr Tracker(Tracker const& o)
: copy(o.copy+1), move(o.move)
{}
constexpr Tracker(Tracker&& o)
: copy(o.copy), move(o.move+1)
{}
Tracker& operator=(Tracker) = delete;
};
template<typename T>
void
test_trivial()
{
static_assert(std::is_trivially_copyable_v<std::optional<T&>>);
static_assert(std::is_copy_constructible_v<std::optional<T&>>);
static_assert(std::is_move_constructible_v<std::optional<T&>>);
static_assert(std::is_destructible_v<std::optional<T&>>);
}
constexpr void
test_trivial_all()
{
test_trivial<int>();
test_trivial<NonTrivial>();
test_trivial<NonMovable>();
test_trivial<std::optional<int&>>();
}
constexpr void
test_copy()
{
Tracker t;
std::optional<Tracker&> o1(t);
VERIFY( o1.has_value() );
VERIFY( &o1.value() == &t );
VERIFY( t.copy == 0 );
VERIFY( t.move == 0 );
std::optional<Tracker&> o2(o1);
VERIFY( o1.has_value() );
VERIFY( &o1.value() == &t );
VERIFY( o2.has_value() );
VERIFY( &o2.value() == &t );
VERIFY( t.copy == 0 );
VERIFY( t.move == 0 );
std::optional<Tracker&> o3(std::move(o1));
VERIFY( o1.has_value() );
VERIFY( &o1.value() == &t );
VERIFY( o3.has_value() );
VERIFY( &o3.value() == &t );
VERIFY( t.copy == 0 );
VERIFY( t.move == 0 );
std::optional<Tracker&> e;
VERIFY( !e.has_value() );
std::optional<Tracker&> o4(e);
VERIFY( !e.has_value() );
VERIFY( !o4.has_value() );
std::optional<Tracker&> o5(std::move(e));
VERIFY( !e.has_value() );
VERIFY( !o5.has_value() );
}
constexpr void
test_from_value()
{
NonTrivial v;
const NonTrivial& cv = v;
std::optional<NonTrivial&> o1(v);
VERIFY( o1.has_value() );
VERIFY( &o1.value() == &v );
static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
const NonTrivial&> );
static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
NonTrivial> );
static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
const NonTrivial> );
std::optional<NonTrivial&> o2(std::in_place, v);
VERIFY( o2.has_value() );
VERIFY( &o2.value() == &v );
static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
std::in_place_t, const NonTrivial&> );
static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
std::in_place_t, NonTrivial> );
static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
std::in_place_t, const NonTrivial> );
std::optional<const NonTrivial&> co1(v);
VERIFY( co1.has_value() );
VERIFY( &co1.value() == &v );
std::optional<const NonTrivial&> co2(cv);
VERIFY( co2.has_value() );
VERIFY( &co2.value() == &v );
// No binding to rvalue
static_assert( !std::is_constructible_v<std::optional<const NonTrivial&>,
NonTrivial> );
static_assert( !std::is_constructible_v<std::optional<const NonTrivial&>,
const NonTrivial> );
std::optional<const NonTrivial&> co3(std::in_place, v);
VERIFY( co3.has_value() );
VERIFY( &co3.value() == &v );
std::optional<const NonTrivial&> co4(std::in_place, cv);
VERIFY( co4.has_value() );
VERIFY( &co4.value() == &v );
// No binding to rvalue
static_assert( !std::is_constructible_v<std::optional<const NonTrivial&>,
std::in_place_t, NonTrivial> );
static_assert( !std::is_constructible_v<std::optional<const NonTrivial&>,
std::in_place_t, const NonTrivial> );
// Conversion create a pr-value that would bind to temporary
static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
Conv<NonTrivial>&> );
static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
const Conv<NonTrivial>&> );
static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
Conv<NonTrivial>> );
static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
const Conv<NonTrivial>> );
static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
std::in_place_t, Conv<NonTrivial>&> );
static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
std::in_place_t, const Conv<NonTrivial>&> );
static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
std::in_place_t, Conv<NonTrivial>> );
static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
std::in_place_t, const Conv<NonTrivial>> );
Conv<NonTrivial&> rw(v);
const Conv<NonTrivial&> crw(v);
std::optional<NonTrivial&> ro1(rw);
VERIFY( ro1.has_value() );
VERIFY( &ro1.value() == &v );
std::optional<NonTrivial&> ro2(crw);
VERIFY( ro2.has_value() );
VERIFY( &ro2.value() == &v );
std::optional<NonTrivial&> ro3(std::move(rw));
VERIFY( ro3.has_value() );
VERIFY( &ro3.value() == &v );
std::optional<NonTrivial&> ro4(std::move(crw));
VERIFY( ro4.has_value() );
VERIFY( &ro4.value() == &v );
std::optional<NonTrivial&> ro5(std::in_place, rw);
VERIFY( ro5.has_value() );
VERIFY( &ro5.value() == &v );
std::optional<NonTrivial&> ro6(std::in_place, crw);
VERIFY( ro6.has_value() );
VERIFY( &ro6.value() == &v );
std::optional<NonTrivial&> ro7(std::in_place, std::move(rw));
VERIFY( ro7.has_value() );
VERIFY( &ro7.value() == &v );
std::optional<NonTrivial&> ro8(std::in_place, std::move(crw));
VERIFY( ro8.has_value() );
VERIFY( &ro8.value() == &v );
}
constexpr void
test_from_opt_value()
{
std::optional<NonTrivial> v(std::in_place);
const std::optional<NonTrivial>& cv = v;
std::optional<NonTrivial&> o1(v);
VERIFY( o1.has_value() );
VERIFY( &o1.value() == &v.value() );
static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
const std::optional<NonTrivial>&> );
static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
std::optional<NonTrivial>> );
static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
const std::optional<NonTrivial>> );
std::optional<const NonTrivial&> co1(v);
VERIFY( co1.has_value() );
VERIFY( &co1.value() == &v.value() );
std::optional<const NonTrivial&> co2(cv);
VERIFY( co2.has_value() );
VERIFY( &co2.value() == &v.value() );
// No binding to rvalue
static_assert( !std::is_constructible_v<std::optional<const NonTrivial&>,
std::optional<NonTrivial>> );
static_assert( !std::is_constructible_v<std::optional<const NonTrivial&>,
const std::optional<NonTrivial>> );
// Conversion create a pr-value that would bind to temporary
static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
std::optional<Conv<NonTrivial>>&> );
static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
const std::optional<Conv<NonTrivial>>&> );
static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
std::optional<Conv<NonTrivial>>> );
static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
const std::optional<Conv<NonTrivial>>> );
std::optional<Conv<NonTrivial&>> rw(*v);
std::optional<const Conv<NonTrivial&>> crw(*v);
std::optional<NonTrivial&> ro1(rw);
VERIFY( ro1.has_value() );
VERIFY( &ro1.value() == &v.value() );
std::optional<NonTrivial&> ro2(crw);
VERIFY( ro2.has_value() );
VERIFY( &ro2.value() == &v.value() );
std::optional<NonTrivial&> ro3(std::move(rw));
VERIFY( ro3.has_value() );
VERIFY( &ro3.value() == &v.value() );
std::optional<NonTrivial&> ro4(std::move(crw));
VERIFY( ro4.has_value() );
VERIFY( &ro4.value() == &v.value() );
}
constexpr void
test_to_opt_value()
{
Tracker t;
std::optional<Tracker&> r(t);
const std::optional<Tracker&> cr(t);
std::optional<Tracker> o1(r);
VERIFY( o1.has_value() );
VERIFY( o1->copy == 1 );
VERIFY( o1->move == 0 );
std::optional<Tracker> o2(cr);
VERIFY( o2.has_value() );
VERIFY( o2->copy == 1 );
VERIFY( o2->move == 0 );
std::optional<Tracker> o3(std::move(r));
VERIFY( o3.has_value() );
VERIFY( o3->copy == 1 );
VERIFY( o3->move == 0 );
std::optional<Tracker> o4(std::move(cr));
VERIFY( o4.has_value() );
VERIFY( o4->copy == 1 );
VERIFY( o4->move == 0 );
std::optional<Tracker&> er;
const std::optional<Tracker&> cer;
std::optional<Tracker> e1(er);
VERIFY( !e1.has_value() );
std::optional<Tracker> e2(cer);
VERIFY( !e2.has_value() );
std::optional<Tracker> e3(std::move(er));
VERIFY( !e3.has_value() );
std::optional<Tracker> e4(std::move(cer));
VERIFY( !e4.has_value() );
}
constexpr void
test_opt_opt()
{
std::optional<int> s(43);
std::optional<std::optional<int>&> o1(s);
VERIFY( o1.has_value() );
VERIFY( &o1.value() == &s );
std::optional<std::optional<int>&> o2(std::in_place, s);
VERIFY( o2.has_value() );
VERIFY( &o2.value() == &s );
std::optional<std::optional<int>> o3(o1);
VERIFY( o2.has_value() );
VERIFY( o2.value().has_value() );
VERIFY( o2.value() == 43 );
s.reset();
std::optional<std::optional<int>&> o4(s);
VERIFY( o4.has_value() );
VERIFY( &o4.value() == &s );
std::optional<std::optional<int>&> o5(std::in_place, s);
VERIFY( o5.has_value() );
VERIFY( &o5.value() == &s );
std::optional<std::optional<int>> o6(o1);
VERIFY( o6.has_value() );
VERIFY( !o6.value().has_value() );
std::optional<std::optional<int>> s2(std::in_place);
std::optional<std::optional<int>&> oo1(s2);
VERIFY( oo1.has_value() );
VERIFY( &oo1.value() == &s2.value() );
s2.reset();
std::optional<std::optional<int>&> oo2(s2);
VERIFY( !oo2.has_value() );
}
int main()
{
auto test_all = [] {
test_copy();
test_from_value();
test_from_opt_value();
test_to_opt_value();
test_opt_opt();
return true;
};
test_all();
static_assert(test_all());
}