// { dg-do run { target c++20 } } #include #include int da_funk = 0; void funk() { ++da_funk; } struct ThrowingCopy { ThrowingCopy() = default; ThrowingCopy(ThrowingCopy&&) noexcept(false) { VERIFY(false); } ThrowingCopy(const ThrowingCopy&) { if (nocopy) throw 1; } void operator()() const noexcept { ++counter; } static ThrowingCopy create() noexcept { nocopy = false; return {}; } static bool nocopy; static int counter; }; bool ThrowingCopy::nocopy = false; int ThrowingCopy::counter = 0; void test_exit() { using std::experimental::scope_exit; int counter = 0; auto d = [&counter] () { ++counter; }; { scope_exit e(d); } VERIFY( counter == 1 ); try { scope_exit e(d); throw 1; } catch (int) { } VERIFY( counter == 2 ); { scope_exit e(d); scope_exit e2(std::move(e)); } VERIFY( counter == 3 ); { scope_exit e(d); e.release(); } VERIFY( counter == 3 ); try { scope_exit e(d); e.release(); throw 1; } catch (int) { } VERIFY( counter == 3 ); { da_funk = 0; scope_exit e(funk); } VERIFY( da_funk == 1 ); static_assert(!std::is_move_assignable_v>); static_assert(!std::is_move_assignable_v>); static_assert(!std::is_move_assignable_v>); static_assert(!std::is_move_assignable_v>); { ThrowingCopy::counter = 0; try { scope_exit e(ThrowingCopy::create()); ThrowingCopy::nocopy = true; scope_exit e2(std::move(e)); VERIFY(false); } catch (int) { } VERIFY( ThrowingCopy::counter == 1 ); scope_exit e(ThrowingCopy::create()); try { ThrowingCopy::nocopy = true; scope_exit e2(std::move(e)); VERIFY(false); } catch (int) { } VERIFY( ThrowingCopy::counter == 1 ); } VERIFY( ThrowingCopy::counter == 2 ); } void test_fail() { using std::experimental::scope_fail; int counter = 0; auto d = [&counter] () { ++counter; }; { scope_fail f(d); } VERIFY( counter == 0 ); try { scope_fail f(d); throw 1; } catch (int) { } VERIFY( counter == 1 ); { scope_fail f(d); f.release(); } VERIFY( counter == 1 ); try { scope_fail f(d); scope_fail f2(std::move(f)); throw 1; } catch(int) { } VERIFY( counter == 2 ); try { scope_fail f(d); f.release(); throw 1; } catch (int) { } VERIFY( counter == 2 ); try { da_funk = 0; scope_fail e(funk); throw 1; } catch (int) { } VERIFY( da_funk == 1 ); static_assert(!std::is_move_assignable_v>); static_assert(!std::is_move_assignable_v>); static_assert(!std::is_move_assignable_v>); static_assert(!std::is_move_assignable_v>); { ThrowingCopy::counter = 0; try { scope_fail f(ThrowingCopy::create()); ThrowingCopy::nocopy = true; scope_fail f2(std::move(f)); VERIFY(false); } catch (int) { } VERIFY( ThrowingCopy::counter == 1 ); scope_fail f(ThrowingCopy::create()); try { ThrowingCopy::nocopy = true; scope_fail f2(std::move(f)); VERIFY(false); } catch (int) { } VERIFY( ThrowingCopy::counter == 1 ); } VERIFY( ThrowingCopy::counter == 1 ); } void test_success() { using std::experimental::scope_success; int counter = 0; auto d = [&counter] () { ++counter; }; { scope_success s(d); } VERIFY( counter == 1 ); try { scope_success s(d); throw 1; } catch (int) { } VERIFY( counter == 1 ); { scope_success s(d); scope_success s2(std::move(s)); } VERIFY( counter == 2 ); { scope_success s(d); s.release(); } VERIFY( counter == 2 ); try { scope_success s(d); s.release(); throw 1; } catch (int) { } VERIFY( counter == 2 ); { da_funk = 0; scope_success e(funk); } VERIFY( da_funk == 1 ); static_assert(!std::is_move_assignable_v>); static_assert(!std::is_move_assignable_v>); static_assert(!std::is_move_assignable_v>); static_assert(!std::is_move_assignable_v>); { ThrowingCopy::counter = 0; try { scope_success s(ThrowingCopy::create()); ThrowingCopy::nocopy = true; scope_success s2(std::move(s)); VERIFY(false); } catch (int) { } VERIFY( ThrowingCopy::counter == 0 ); scope_success s(ThrowingCopy::create()); try { ThrowingCopy::nocopy = true; scope_success s2(std::move(s)); VERIFY(false); } catch (int) { } VERIFY( ThrowingCopy::counter == 0 ); } VERIFY( ThrowingCopy::counter == 1 ); } int main() { test_exit(); test_fail(); test_success(); }