// { dg-options "-std=gnu++23" }
// { dg-do run { target c++23 } }
#include <expected>
#include <testsuite_hooks.h>
constexpr bool
test_default()
{
  std::expected<int, int> e;
  VERIFY( e.has_value() );
  VERIFY( *e == 0 );
  std::expected<void, int> ev;
  VERIFY( ev.has_value() );
  VERIFY( (ev.value(), true) );
  return true;
}
constexpr bool
test_val()
{
  std::expected<int, int> e1(1);
  VERIFY( e1.has_value() );
  VERIFY( *e1 == 1 );
  std::expected<int, int> e2(std::in_place, 2);
  VERIFY( e2.has_value() );
  VERIFY( *e2 == 2 );
  struct X
  {
    constexpr X(std::initializer_list<int> l, void*) : n(l.size()) { }
    int n;
  };
  std::expected<X, int> e3(X{{1, 2, 3}, nullptr});
  VERIFY( e3.has_value() );
  VERIFY( e3->n == 3 );
  std::expected<X, int> e4(std::in_place, {1, 2, 3, 4}, nullptr);
  VERIFY( e4.has_value() );
  VERIFY( e4->n == 4 );
  std::expected<void, int> ev(std::in_place);
  VERIFY( ev.has_value() );
  VERIFY( (ev.value(), true) );
  return true;
}
constexpr bool
test_err()
{
  std::expected<int, int> e1(std::unexpected<int>(1));
  VERIFY( ! e1.has_value() );
  VERIFY( e1.error() == 1 );
  const std::unexpected<int> u2(2);
  std::expected<int, int> e2(u2);
  VERIFY( ! e2.has_value() );
  VERIFY( e2.error() == 2 );
  std::expected<int, int> e3(std::unexpect, 3);
  VERIFY( ! e3.has_value() );
  VERIFY( e3.error() == 3 );
  struct X
  {
    constexpr X(int i, int j) : n(i+j) { }
    constexpr X(std::initializer_list<int> l, void*) : n(l.size()) { }
    int n;
  };
  std::expected<int, X> e4(std::unexpect, 1, 3);
  VERIFY( ! e4.has_value() );
  VERIFY( e4.error().n == 4 );
  std::expected<int, X> e5(std::unexpect, {1, 2, 3, 4, 5}, nullptr);
  VERIFY( ! e5.has_value() );
  VERIFY( e5.error().n == 5 );
  std::expected<const void, int> ev1(std::unexpected<int>(1));
  VERIFY( ! ev1.has_value() );
  VERIFY( ev1.error() == 1 );
  std::expected<volatile void, int> ev2(u2);
  VERIFY( ! ev2.has_value() );
  VERIFY( ev2.error() == 2 );
  std::expected<const volatile void, int> ev3(std::unexpect, 3);
  VERIFY( ! ev3.has_value() );
  VERIFY( ev3.error() == 3 );
  std::expected<void, X> ev4(std::unexpect, 1, 3);
  VERIFY( ! ev4.has_value() );
  VERIFY( ev4.error().n == 4 );
  std::expected<void, X> ev5(std::unexpect, {1, 2, 3, 4, 5}, nullptr);
  VERIFY( ! ev5.has_value() );
  VERIFY( ev5.error().n == 5 );
  return true;
}
constexpr bool
test_copy()
{
  std::expected<int, int> e1(1);
  std::expected<int, int> e2(e1);
  VERIFY( e2.value() == 1 );
  std::expected<int, int> e3(std::move(e2));
  VERIFY( e2.value() == 1 );
  VERIFY( e3.value() == 1 );
  std::expected<short, short> e4(e1);
  VERIFY( e4.value() == 1 );
  std::expected<short, short> e5(std::move(e4));
  VERIFY( e4.value() == 1 );
  VERIFY( e5.value() == 1 );
  std::expected<int, int> u1(std::unexpect, 2);
  std::expected<int, int> u2(u1);
  VERIFY( ! u2.has_value() );
  VERIFY( u2.error() == 2 );
  std::expected<int, int> u3(std::move(u2));
  VERIFY( ! u3.has_value() );
  VERIFY( u3.error() == 2 );
  std::expected<short, short> u4(u1);
  VERIFY( ! u4.has_value() );
  VERIFY( u4.error() == 2 );
  std::expected<short, short> u5(std::move(u4));
  VERIFY( ! u5.has_value() );
  VERIFY( u5.error() == 2 );
  std::expected<void, int> ev1;
  std::expected<void, int> ev2(ev1);
  VERIFY( ev2.has_value() );
  std::expected<void, int> ev3(std::move(ev2));
  VERIFY( ev2.has_value() );
  VERIFY( ev3.has_value() );
  std::expected<volatile void, short> ev4(ev1);
  VERIFY( ev4.has_value() );
  std::expected<const void, short> ev5(std::move(ev4));
  VERIFY( ev4.has_value() );
  VERIFY( ev5.has_value() );
  std::expected<void, int> uv1(std::unexpect, 2);
  std::expected<void, int> uv2(uv1);
  VERIFY( ! uv2.has_value() );
  VERIFY( uv2.error() == 2 );
  std::expected<void, int> uv3(std::move(uv2));
  VERIFY( ! uv3.has_value() );
  VERIFY( uv3.error() == 2 );
  std::expected<const void, short> uv4(uv1);
  VERIFY( ! uv4.has_value() );
  VERIFY( uv4.error() == 2 );
  std::expected<volatile void, short> uv5(std::move(uv4));
  VERIFY( ! uv5.has_value() );
  VERIFY( uv5.error() == 2 );
  return true;
}
constexpr bool
test_pr105153()
{
  struct E {
    E(int&&) = delete;
    E(const int&);
  };
  std::expected<void, E> e(std::expected<void, int>{});
  static_assert( ! std::is_constructible_v<std::expected<void, int>,
					   std::expected<int, int>> );
  return true;
}
int main()
{
  test_default();
  static_assert( test_default() );
  test_val();
  static_assert( test_val() );
  test_err();
  static_assert( test_err() );
  test_copy();
  static_assert( test_copy() );
  test_pr105153();
  static_assert( test_pr105153() );
}