(root)/
gcc-13.2.0/
libstdc++-v3/
testsuite/
19_diagnostics/
stacktrace/
stacktrace.cc
// { dg-options "-std=gnu++23 -lstdc++_libbacktrace" }
// { dg-do run { target c++23 } }
// { dg-require-effective-target stacktrace }

#include <stacktrace>
#include "testsuite_allocator.h"

static_assert( std::is_nothrow_default_constructible_v<std::stacktrace> );
static_assert( std::is_copy_constructible_v<std::stacktrace> );
static_assert( std::is_nothrow_move_constructible_v<std::stacktrace> );
static_assert( std::is_copy_assignable_v<std::stacktrace> );
static_assert( std::is_nothrow_move_assignable_v<std::stacktrace> );
static_assert( std::is_nothrow_swappable_v<std::stacktrace> );

void
test_cons()
{
  {
    using Stacktrace = std::stacktrace;
    using Alloc = Stacktrace::allocator_type;

    Stacktrace s0;
    VERIFY( s0.empty() );
    VERIFY( s0.size() == 0 );
    VERIFY( s0.begin() == s0.end() );

    Stacktrace s1(Alloc{});
    VERIFY( s1.empty() );
    VERIFY( s1.size() == 0 );
    VERIFY( s1.begin() == s1.end() );

    VERIFY( s0 == s1 );

    Stacktrace s2(s0);
    VERIFY( s2 == s0 );

    const Stacktrace curr = Stacktrace::current();

    Stacktrace s3(curr);
    VERIFY( ! s3.empty() );
    VERIFY( s3.size() != 0 );
    VERIFY( s3.begin() != s3.end() );
    VERIFY( s3 != s0 );

    Stacktrace s4(s3);
    VERIFY( ! s4.empty() );
    VERIFY( s4.size() != 0 );
    VERIFY( s4.begin() != s4.end() );
    VERIFY( s4 == s3 );
    VERIFY( s4 != s0 );

    Stacktrace s5(std::move(s3));
    VERIFY( ! s5.empty() );
    VERIFY( s5.size() != 0 );
    VERIFY( s5.begin() != s5.end() );
    VERIFY( s5 == s4 );
    VERIFY( s5 != s0 );
    VERIFY( s3 == s0 );

    Stacktrace s6(s4, Alloc{});
    VERIFY( s6 == s4 );

    Stacktrace s7(std::move(s6), Alloc{});
    VERIFY( s7 == s4 );
  }

  {
    using Alloc = __gnu_test::uneq_allocator<std::stacktrace_entry>;
    using Stacktrace = std::basic_stacktrace<Alloc>;

    Stacktrace s0;
    VERIFY( s0.empty() );
    VERIFY( s0.size() == 0 );
    VERIFY( s0.begin() == s0.end() );

    Stacktrace s1(Alloc{});
    VERIFY( s1.empty() );
    VERIFY( s1.size() == 0 );
    VERIFY( s1.begin() == s1.end() );

    VERIFY( s0 == s1 );

    Stacktrace s2(s0);
    VERIFY( s2 == s0 );

    const Stacktrace curr = Stacktrace::current();

    Stacktrace s3(curr);
    VERIFY( ! s3.empty() );
    VERIFY( s3.size() != 0 );
    VERIFY( s3.begin() != s3.end() );
    VERIFY( s3 != s0 );

    Stacktrace s4(s3);
    VERIFY( ! s4.empty() );
    VERIFY( s4.size() != 0 );
    VERIFY( s4.begin() != s4.end() );
    VERIFY( s4 == s3 );
    VERIFY( s4 != s0 );

    Stacktrace s5(std::move(s3));
    VERIFY( ! s5.empty() );
    VERIFY( s5.size() != 0 );
    VERIFY( s5.begin() != s5.end() );
    VERIFY( s5 == s4 );
    VERIFY( s5 != s0 );
    VERIFY( s3 == s0 );

    // TODO test allocator-extended copy/move

    // TODO test allocator propagation
  }
}


void
test_assign()
{
  {
    using Stacktrace = std::stacktrace;

    Stacktrace s0;
    s0 = s0;
    VERIFY( s0.empty() );
    s0 = std::move(s0);
    VERIFY( s0.empty() );

    Stacktrace s1 = Stacktrace::current();
    VERIFY( s1 != s0 );
    s0 = s1;
    VERIFY( s0 == s1 );
    VERIFY( s0.at(0).source_line() == (__LINE__ - 4) );

    s1 = Stacktrace::current();
    VERIFY( s1 != s0 );
    Stacktrace s2 = s0;
    Stacktrace s3 = s1;
    s0 = std::move(s1);
    VERIFY( s0 == s3 );
    VERIFY( s1 == s2 ); // ISO C++: valid but unspecified; GCC: swapped.
  }

  {
    using Alloc = __gnu_test::uneq_allocator<std::stacktrace_entry>;
    using Stacktrace = std::basic_stacktrace<Alloc>;

    Stacktrace s0;
    s0 = s0;
    VERIFY( s0.empty() );
    s0 = std::move(s0);
    VERIFY( s0.empty() );

    Stacktrace s1 = Stacktrace::current();
    VERIFY( s1 != s0 );
    s0 = s1;
    VERIFY( s0 == s1 );

    s1 = Stacktrace::current(Alloc(__LINE__));
    VERIFY( s1 != s0 );
    s0 = std::move(s1);
    VERIFY( s0.at(0).source_line() == s0.get_allocator().get_personality() );
    VERIFY( s1.empty() ); // ISO C++: valid but unspecified; GCC: empty.

    Stacktrace s2 = Stacktrace::current(s0.get_allocator());
    Stacktrace s3 = s2;
    s2 = std::move(s0);
    VERIFY( s2.at(0).source_line() == s2.get_allocator().get_personality() );
    VERIFY( s0 == s3 ); // ISO C++: valid but unspecified, GCC: swapped.
  }
}

void
test_swap()
{
  {
    using Stacktrace = std::stacktrace;

    Stacktrace s0;
    Stacktrace s1 = Stacktrace::current();
    swap(s0, s1);
    VERIFY( s1.empty() );
    VERIFY( ! s0.empty() );
  }

  {
    using Alloc = __gnu_test::uneq_allocator<std::stacktrace_entry>;
    using Stacktrace = std::basic_stacktrace<Alloc>;

    Stacktrace s0;
    Stacktrace s1 = Stacktrace::current();
    swap(s0, s1);
    VERIFY( s1.empty() );
    VERIFY( ! s0.empty() );

    // TODO test allocator propagation
  }
}

void
test_pr105031()
{
  // PR libstdc++/105031
  // wrong constexpr if statement in operator=(basic_stacktrace&&)
  using Alloc = __gnu_test::uneq_allocator<std::stacktrace_entry>;
  std::basic_stacktrace<Alloc> s;
  s = auto(s);
}

int main()
{
  test_cons();
  test_assign();
  test_swap();
  test_pr105031();
}