From 30cfe9fce19934752e93de55f27b1eb4f4835bda Mon Sep 17 00:00:00 2001 From: Emil Dotchevski Date: Sun, 29 Dec 2019 18:13:10 -0800 Subject: [PATCH] Context activation/deactivation/propagation refactored. --- .travis.yml | 106 ++++- .vscode/tasks.json | 27 ++ doc/leaf.adoc | 145 +++--- examples/asio_beast_leaf_rpc.cpp | 4 +- include/boost/leaf/all.hpp | 534 ++++++++++++---------- include/boost/leaf/capture.hpp | 10 +- include/boost/leaf/config.hpp | 4 +- include/boost/leaf/context.hpp | 100 ++-- include/boost/leaf/detail/handle.hpp | 102 ++--- include/boost/leaf/error.hpp | 128 +++--- include/boost/leaf/exception.hpp | 4 +- include/boost/leaf/handle_error.hpp | 46 +- include/boost/leaf/handle_exception.hpp | 134 ++++-- include/boost/leaf/preload.hpp | 6 +- meson.build | 6 +- test/Jamfile.v2 | 3 + test/capture_exception_state_test.cpp | 10 +- test/context_activator_test.cpp | 8 +- test/ctx_handle_all_test.cpp | 51 +++ test/ctx_handle_exception_test.cpp | 143 ++++++ test/ctx_handle_some_test.cpp | 49 ++ test/ctx_remote_handle_all_test.cpp | 2 +- test/ctx_remote_handle_exception_test.cpp | 2 +- test/ctx_remote_handle_some_test.cpp | 2 +- test/handle_basic_test.cpp | 35 ++ test/result_state_test.cpp | 16 +- 26 files changed, 1104 insertions(+), 573 deletions(-) create mode 100644 test/ctx_handle_all_test.cpp create mode 100644 test/ctx_handle_exception_test.cpp create mode 100644 test/ctx_handle_some_test.cpp diff --git a/.travis.yml b/.travis.yml index b954d81..059ae4f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ +# Copyright 2016-2018 Peter Dimov # Copyright 2018-2019 Emil Dotchevski -# Copyright 2016 Peter Dimov # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) @@ -52,7 +52,7 @@ matrix: include: - - os: linux + - os: linux env: DOC=1 script: - |- @@ -137,6 +137,10 @@ matrix: compiler: clang++ env: TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1z + - os: osx + compiler: clang++ + env: UBSAN=1 TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1z UBSAN_OPTIONS=print_stacktrace=1 + - os: linux compiler: g++-4.9 env: TOOLSET=gcc COMPILER=g++-4.9 CXXSTD=11 @@ -169,7 +173,7 @@ matrix: - os: linux compiler: g++-7 - env: TOOLSET=gcc COMPILER=g++-7 CXXSTD=11,14,1z + env: TOOLSET=gcc COMPILER=g++-7 CXXSTD=11,14,17 addons: apt: packages: @@ -187,6 +191,26 @@ matrix: sources: - ubuntu-toolchain-r-test + - os: linux + compiler: g++-9 + env: TOOLSET=gcc COMPILER=g++-9 CXXSTD=11,14,17,2a + addons: + apt: + packages: + - g++-9 + sources: + - ubuntu-toolchain-r-test + + - os: linux + compiler: g++-9 + env: UBSAN=1 TOOLSET=gcc COMPILER=g++-9 CXXSTD=11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1 LINKFLAGS=-fuse-ld=gold + addons: + apt: + packages: + - g++-9 + sources: + - ubuntu-toolchain-r-test + - os: linux compiler: /usr/bin/clang++ env: TOOLSET=clang COMPILER=/usr/bin/clang++ CXXSTD=11 @@ -203,6 +227,10 @@ matrix: packages: - clang-3.4 + - os: linux + compiler: clang++ + env: TOOLSET=clang COMPILER=clang++ CXXSTD=11 + - os: linux compiler: clang++-3.5 env: TOOLSET=clang COMPILER=clang++-3.5 CXXSTD=11,14,1z @@ -213,7 +241,6 @@ matrix: - libstdc++-4.9-dev sources: - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.5 - os: linux compiler: clang++-3.6 @@ -222,9 +249,9 @@ matrix: apt: packages: - clang-3.6 + - libstdc++-4.9-dev sources: - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.6 - os: linux compiler: clang++-3.7 @@ -247,7 +274,6 @@ matrix: - libstdc++-4.9-dev sources: - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.8 - os: linux compiler: clang++-3.9 @@ -259,7 +285,6 @@ matrix: - libstdc++-4.9-dev sources: - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.9 - os: linux compiler: clang++-4.0 @@ -294,6 +319,52 @@ matrix: - ubuntu-toolchain-r-test - llvm-toolchain-trusty-6.0 + - os: linux + compiler: clang++-7 + env: TOOLSET=clang COMPILER=clang++-7 CXXSTD=11,14,17,2a + addons: + apt: + packages: + - clang-7 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-7 + + - os: linux + compiler: clang++-8 + env: TOOLSET=clang COMPILER=clang++-8 CXXSTD=11,14,17,2a + addons: + apt: + packages: + - clang-8 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-8 + + - os: linux + dist: xenial + compiler: clang++-9 + env: TOOLSET=clang COMPILER=clang++-9 CXXSTD=11,14,17,2a + addons: + apt: + packages: + - clang-9 + sources: + - ubuntu-toolchain-r-test + - sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main' + key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' + + - os: linux + compiler: clang++-8 + env: UBSAN=1 TOOLSET=clang COMPILER=clang++-8 CXXSTD=11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1 + addons: + apt: + packages: + - clang-8 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-8 + install: - gem install asciidoctor - gem install coderay @@ -316,23 +387,10 @@ install: script: - |- echo "using $TOOLSET : : $COMPILER ;" > ~/user-config.jam - - ../../b2 test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug - - ../../b2 test toolset=$TOOLSET cxxstd=$CXXSTD variant=release - - ../../b2 test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug-diagnostics0 - - ../../b2 test toolset=$TOOLSET cxxstd=$CXXSTD variant=release-diagnostics0 - - ../../b2 exception-handling=off rtti=off test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug - - ../../b2 exception-handling=off rtti=off test toolset=$TOOLSET cxxstd=$CXXSTD variant=release - - ../../b2 exception-handling=off rtti=off test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug-diagnostics0 - - ../../b2 exception-handling=off rtti=off test toolset=$TOOLSET cxxstd=$CXXSTD variant=release-diagnostics0 - - ../../b2 threading=single test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug - - ../../b2 threading=single test toolset=$TOOLSET cxxstd=$CXXSTD variant=release - - ../../b2 threading=single test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug-diagnostics0 - - ../../b2 threading=single test toolset=$TOOLSET cxxstd=$CXXSTD variant=release-diagnostics0 - - ../../b2 threading=single exception-handling=off rtti=off test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug - - ../../b2 threading=single exception-handling=off rtti=off test toolset=$TOOLSET cxxstd=$CXXSTD variant=release - - ../../b2 threading=single exception-handling=off rtti=off test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug-diagnostics0 - - ../../b2 threading=single exception-handling=off rtti=off test toolset=$TOOLSET cxxstd=$CXXSTD variant=release-diagnostics0 -# - cd bld/debug && meson test + - ../../b2 test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release,debug-diagnostics0,release-diagnostics0 ${UBSAN:+cxxflags=-fsanitize=undefined cxxflags=-fno-sanitize-recover=undefined linkflags=-fsanitize=undefined debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS} + - ../../b2 exception-handling=off rtti=off test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release,debug-diagnostics0,release-diagnostics0 ${UBSAN:+cxxflags=-fsanitize=undefined cxxflags=-fno-sanitize-recover=undefined linkflags=-fsanitize=undefined debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS} + - ../../b2 threading=single test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release,debug-diagnostics0,release-diagnostics0 ${UBSAN:+cxxflags=-fsanitize=undefined cxxflags=-fno-sanitize-recover=undefined linkflags=-fsanitize=undefined debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS} + - ../../b2 threading=single exception-handling=off rtti=off test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release,debug-diagnostics0,release-diagnostics0 ${UBSAN:+cxxflags=-fsanitize=undefined cxxflags=-fno-sanitize-recover=undefined linkflags=-fsanitize=undefined debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS} notifications: email: diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 945d70d..00f62e7 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -167,6 +167,33 @@ "command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test context_deduction_test" } }, + { + "label": "ctx_handle_all_test", + "type": "shell", + "command": "cd ${workspaceRoot}/bld/debug && meson test ctx_handle_all_test", + "problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] }, + "windows": { + "command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test ctx_handle_all_test" + } + }, + { + "label": "ctx_handle_exception_test", + "type": "shell", + "command": "cd ${workspaceRoot}/bld/debug && meson test ctx_handle_exception_test", + "problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] }, + "windows": { + "command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test ctx_handle_exception_test" + } + }, + { + "label": "ctx_handle_some_test", + "type": "shell", + "command": "cd ${workspaceRoot}/bld/debug && meson test ctx_handle_some_test", + "problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] }, + "windows": { + "command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test ctx_handle_some_test" + } + }, { "label": "ctx_remote_handle_all_test", "type": "shell", diff --git a/doc/leaf.adoc b/doc/leaf.adoc index 3916363..be6745e 100644 --- a/doc/leaf.adoc +++ b/doc/leaf.adoc @@ -1634,21 +1634,16 @@ namespace boost { namespace leaf { public: virtual void activate() noexcept = 0; - virtual void deactivate( bool propagate_errors ) noexcept = 0; + virtual void deactivate() noexcept = 0; virtual bool is_active() const noexcept = 0; + virtual void propagate() noexcept = 0; + virtual void print( std::ostream & ) const = 0; }; ////////////////////////////////////////// - enum class on_deactivation - { - propagate, - propagate_if_uncaught_exception, - capture_do_not_propagate - }; - template class context_activator { @@ -1657,17 +1652,15 @@ namespace boost { namespace leaf { public: - context_activator( Ctx & ctx, on_deactivation on_deactivate ) noexcept; + explicit context_activator( Ctx & ctx ) noexcept; context_activator( context_activator && ) noexcept; ~context_activator() noexcept; - - void set_on_deactivate( on_deactivation on_deactivate ) noexcept; }; } } template -context_activator activate_context( Ctx & ctx, on_deactivation on_deactivate ) noexcept; +context_activator activate_context( Ctx & ctx ) noexcept; #define LEAF_NEW_ERROR(...) .... #define LEAF_AUTO(v,r) .... @@ -1936,9 +1929,11 @@ namespace boost { namespace leaf { ~context() noexcept; void activate() noexcept; - void deactivate( bool propagate_errors ) noexcept; + void deactivate() noexcept; bool is_active() const noexcept; + void propagate () noexcept; + void print( std::ostream & os ) const; // Note: leaves the rest of the member functions undefined. @@ -1949,29 +1944,29 @@ namespace boost { namespace leaf { template typename std::decay().value())>::type - handle_all( R &, H && ... ) const; + handle_all( R &, H && ... ); template typename std::decay().value())>::type - remote_handle_all( R &, RemoteH && ) const; + remote_handle_all( R &, RemoteH && ); template - R handle_some( R &&, H && ... ) const; + R handle_some( R &&, H && ... ); template - R remote_handle_some( R &&, RemoteH && ) const; + R remote_handle_some( R &&, RemoteH && ); template - R handle_current_exception( H && ... ) const; + R handle_current_exception( H && ... ); template - R remote_handle_current_exception( RemoteH && ) const; + R remote_handle_current_exception( RemoteH && ); template - R handle_exception( std::exception_ptr const &, H && ... ) const; + R handle_exception( std::exception_ptr const &, H && ... ); template - R remote_handle_exception( std::exception_ptr const &, RemoteH && ) const; + R remote_handle_exception( std::exception_ptr const &, RemoteH && ); }; @@ -2216,9 +2211,9 @@ TIP: See also <> from the Tutorial. namespace boost { namespace leaf { template - context_activator activate_context( Ctx & ctx, on_deactivation on_deactivate ) noexcept + context_activator activate_context( Ctx & ctx ) noexcept { - return context_activator(ctx, on_deactivate); + return context_activator(ctx); } } } @@ -3043,39 +3038,41 @@ namespace boost { namespace leaf { context() noexcept; context( context && x ) noexcept; - ~context() noexcept final override; + ~context() noexcept; - void activate() noexcept final override; - void deactivate( bool propagate_errors ) noexcept final override; - virtual bool is_active() const noexcept = 0; + void activate() noexcept; + void deactivate() noexcept; + bool is_active() const noexcept = 0; - void print( std::ostream & os ) const final override; + void propagate() noexcept = 0; + + void print( std::ostream & os ) const; template typename std::decay().value())>::type - handle_all( R &, H && ... ) const; + handle_all( R &, H && ... ); template typename std::decay().value())>::type - remote_handle_all( R &, RemoteH && ) const; + remote_handle_all( R &, RemoteH && ); template - R handle_some( R &&, H && ... ) const; + R handle_some( R &&, H && ... ); template - R remote_handle_some( R &&, RemoteH && ) const; + R remote_handle_some( R &&, RemoteH && ); template - R handle_current_exception( H && ... ) const; + R handle_current_exception( H && ... ); template - R remote_handle_current_exception( RemoteH && ) const; + R remote_handle_current_exception( RemoteH && ); template - R handle_exception( std::exception_ptr const &, H && ... ) const; + R handle_exception( std::exception_ptr const &, H && ... ); template - R remote_handle_exception( std::exception_ptr const &, RemoteH && ) const; + R remote_handle_exception( std::exception_ptr const &, RemoteH && ); }; template @@ -3096,7 +3093,7 @@ To be able to load up error objects in a `context` object, it must be activated. To handle an error, call one of the error handling member functions, which match E-objects currently stored in `*this` to the user-supplied handler functions. See <> for a description of the handler matching procedure (this works regardless of whether or not the `context` is currently `active`). -When a `context` is deactivated, it detaches from the calling thread, restoring the thread-local pointers to their pre-`activate` values. Typically, at this point the stored E-objects, if any, are either moved to corresponding storage in other `context` objects active in the calling thread (if available) -- or discarded, depending on the `propagate_errors` argument passed to <>. +When a `context` is deactivated, it detaches from the calling thread, restoring the thread-local pointers to their pre-`activate` values. Typically, at this point the stored E-objects, if any, are either discarded (by default) or moved to corresponding storage in other `context` objects active in the calling thread (if available), by calling <>. TIP: `context` objects can be moved, as long as they aren't active. Moving an active `context` results in undefined behavior. @@ -3162,7 +3159,7 @@ When an E-object is <>, it is moved in the last activat namespace boost { namespace leaf { template - void context::deactivate( bool propagate_errors ) noexcept final override; + void context::deactivate() noexcept; } } ---- @@ -3177,11 +3174,6 @@ Ensures: :: * `!<>()`. When a context is deactivated, the thread-local pointers that currently point to each individual E-object storage in it are restored to their original value prior to calling <>. -What happens to the E-objects currently stored in `*this` depends on `propagate_errors`: - -* If `propagate_errors` is `false`, any stored E-objects are discarded. -* If `propagate_errors` is `true`, each stored E-object is moved to the storage pointed by the restored corresponding thread-local pointer. If that pointer is `0`, the stored E-object is discarded. - ''' [[context::is_active]] @@ -3202,6 +3194,29 @@ Returns: :: `true` if the `*this` is active in any thread, `false` otherwise. ''' +[[context::propagate]] +==== `propagate` + +.#include +[source,c++] +---- +namespace boost { namespace leaf { + + template + void context::propagate() noexcept; + +} } +---- + +Preconditions: :: +`<>()` or `*this` must be the last deactivated `context` object in the calling thread. That is, it is valid to call `propagate` while `is_active()` is true, or immediately after calling `<>()`. + +Effects: :: + +Each stored E-object is moved to the storage (within other active `context` objects) pointed by the corresponding thread-local pointer, set when a `context` is activated -- or discarded, if the corresponding thread-local pointer is null. + +''' + [[context::handle_all]] ==== `handle_all` @@ -3213,7 +3228,7 @@ namespace boost { namespace leaf { template template typename std::decay().value())>::type - context::handle_all( R && r, H && ... h ) const; + context::handle_all( R && r, H && ... h ); } } ---- @@ -3251,7 +3266,7 @@ namespace boost { namespace leaf { template template - R context::handle_current_exception( H && ... h ) const; + R context::handle_current_exception( H && ... h ); } } ---- @@ -3287,7 +3302,7 @@ namespace boost { namespace leaf { template template - R context::handle_exception( std::exception_ptr const & ep, H && ... h ) const + R context::handle_exception( std::exception_ptr const & ep, H && ... h ) { try { @@ -3317,7 +3332,7 @@ namespace boost { namespace leaf { template template - R context::handle_some( R && r, H && ... h ) const; + R context::handle_some( R && r, H && ... h ); } } ---- @@ -3613,7 +3628,7 @@ else namespace boost { namespace leaf { template - void context::print( std::ostream & os ) const final override; + void context::print( std::ostream & os ) const; } } ---- @@ -3633,7 +3648,7 @@ namespace boost { namespace leaf { template template typename std::decay().value())>::type - context::remote_handle_all( R & r, RemoteH && h ) const; + context::remote_handle_all( R & r, RemoteH && h ); } } ---- @@ -3699,7 +3714,7 @@ namespace boost { namespace leaf { template template - R context::remote_handle_current_exception( RemoteH && h ) const; + R context::remote_handle_current_exception( RemoteH && h ); } } ---- @@ -3760,7 +3775,7 @@ namespace boost { namespace leaf { template template - R context::remote_handle_exception( std::exception_ptr const & ep, RemoteH && h ) const; + R context::remote_handle_exception( std::exception_ptr const & ep, RemoteH && h ); } } ---- @@ -3794,7 +3809,7 @@ namespace boost { namespace leaf { template template - R context::remote_handle_some( R && r, RemoteH && h ) const; + R context::remote_handle_some( R && r, RemoteH && h ); } } ---- @@ -3857,13 +3872,6 @@ TIP: Because LEAF does not invoke the user-defined `handle_error` function direc ---- namespace boost { namespace leaf { - enum class on_deactivation - { - propagate, - propagate_if_uncaught_exception, - capture_do_not_propagate - }; - template class context_activator { @@ -3872,11 +3880,9 @@ namespace boost { namespace leaf { public: - context_activator( Ctx & ctx, on_deactivation on_deactivate ) noexcept; + explicit context_activator( Ctx & ctx ) noexcept; context_activator( context_activator && ) noexcept; ~context_activator() noexcept; - - void set_on_deactivate( on_deactivation on_deactivate ) noexcept; }; } } @@ -3884,11 +3890,12 @@ namespace boost { namespace leaf { `context_activator` is a simple class that activates and deactivates a <> using RAII: -* The constructor stores a reference to `ctx` and calls <>. -* The destructor behavior depends on the `on_deactivation` state: -** `on_deactivation::propagate` instructs `~context_activator` to call <> with `true`; -** `on_deactivation::propagate_if_uncaught_exception` instructs `~context_activator` to call `deactivate` with the value returned from `std::uncaught_exception()`; -** `on_deactivation::capture_do_not_propagate` instructs `~context_activator` to call `deactivate` with `false`. +If `<>`() is `true` at the time the `context_activator` is initialized, the constructor and the destructor have no effects. Otherwise: + +* The constructor stores a reference to `ctx` and calls `<>`(). +* The destructor: +** If `ctx.is_active()` is false, has no effects (that is, it is valid to call <> manually, before the `context_activator` object expires); +** Otherwise, calls `<>`() and, if there are new uncaught exceptions since the constructor was called, the destructor calls `<>`(). For automatic deduction of `Ctx`, use <>. @@ -4412,9 +4419,11 @@ namespace boost { namespace leaf { public: virtual void activate() noexcept = 0; - virtual void deactivate( bool propagate_errors ) noexcept = 0; + virtual void deactivate() noexcept = 0; virtual bool is_active() const noexcept = 0; + virtual void propagate() noexcept = 0; + virtual void print( std::ostream & ) const = 0; }; diff --git a/examples/asio_beast_leaf_rpc.cpp b/examples/asio_beast_leaf_rpc.cpp index 39921c3..06decdc 100644 --- a/examples/asio_beast_leaf_rpc.cpp +++ b/examples/asio_beast_leaf_rpc.cpp @@ -124,7 +124,7 @@ auto async_demo_rpc(AsyncStream &stream, ErrorContext &error_context, Completion void operator()(error_code ec, std::size_t /*bytes_transferred*/ = 0) { leaf::result result_continue_execution; { - auto active_context = activate_context(m_error_context, leaf::on_deactivation::do_not_propagate); + auto active_context = activate_context(m_error_context); auto load = leaf::preload(e_last_operation{m_data.response ? "async_demo_rpc::continuation-write" : "async_demo_rpc::continuation-read"}); if (ec == http::error::end_of_stream) { @@ -539,7 +539,7 @@ int main(int argc, char **argv) { async_demo_rpc(socket, error_context, [&](leaf::result result) { // Note: In case we wanted to add some additional information to the error associated with the result // we would need to activate the error-context - auto active_context = activate_context(error_context, leaf::on_deactivation::do_not_propagate); + auto active_context = activate_context(error_context); if (result) { std::cout << "Server: Client work completed successfully" << std::endl; rv = 0; diff --git a/include/boost/leaf/all.hpp b/include/boost/leaf/all.hpp index 128fb50..4e10aa7 100644 --- a/include/boost/leaf/all.hpp +++ b/include/boost/leaf/all.hpp @@ -119,10 +119,10 @@ #if __cplusplus > 201402L # define LEAF_CONSTEXPR constexpr -# define LEAF_UNCAUGHT_EXCEPTIONS std::uncaught_exceptions +# define LEAF_STD_UNCAUGHT_EXCEPTIONS 1 #else # define LEAF_CONSTEXPR -# define LEAF_UNCAUGHT_EXCEPTIONS std::uncaught_exception +# define LEAF_STD_UNCAUGHT_EXCEPTIONS 0 #endif #endif @@ -1129,20 +1129,22 @@ namespace boost { namespace leaf { assert(x.top_==0); } - ~slot() noexcept - { - assert(top_==0); - } - LEAF_CONSTEXPR void activate() noexcept { - assert(top_==0); + assert(top_==0 || *top_!=this); top_ = &tl_slot_ptr(); prev_ = *top_; *top_ = this; } - LEAF_CONSTEXPR void deactivate( bool propagate_errors ) noexcept; + + LEAF_CONSTEXPR void deactivate() noexcept + { + assert(top_!=0 && *top_==this); + *top_ = prev_; + } + + LEAF_CONSTEXPR void propagate() noexcept; using impl::put; using impl::has_value; @@ -1182,28 +1184,25 @@ namespace boost { namespace leaf { #endif template - LEAF_CONSTEXPR inline void slot::deactivate( bool propagate_errors ) noexcept + LEAF_CONSTEXPR inline void slot::propagate() noexcept { - assert(top_!=0); - if( propagate_errors ) - if( prev_ ) - { - impl & this_ = *this; - impl & that_ = *prev_; - that_ = std::move(this_); - } + assert(top_!=0 && (*top_==prev_ || *top_==this)); + if( prev_ ) + { + impl & this_ = *this; + impl & that_ = *prev_; + that_ = std::move(this_); + } #if LEAF_DIAGNOSTICS - else - { - int c = tl_unexpected_enabled_counter(); - assert(c>=0); - if( c ) - if( int err_id = impl::key() ) - load_unexpected(err_id, std::move(*this).value(err_id)); - } + else + { + int c = tl_unexpected_enabled_counter(); + assert(c>=0); + if( c ) + if( int err_id = impl::key() ) + load_unexpected(err_id, std::move(*this).value(err_id)); + } #endif - *top_ = prev_; - top_ = 0; } template @@ -1494,7 +1493,8 @@ namespace boost { namespace leaf { public: virtual error_id propagate_captured_errors() noexcept = 0; virtual void activate() noexcept = 0; - virtual void deactivate( bool propagate_errors ) noexcept = 0; + virtual void deactivate() noexcept = 0; + virtual void propagate() noexcept = 0; virtual bool is_active() const noexcept = 0; virtual void print( std::ostream & ) const = 0; error_id captured_id_; @@ -1504,77 +1504,61 @@ namespace boost { namespace leaf { //////////////////////////////////////////// - enum class on_deactivation - { - propagate, - do_not_propagate, - propagate_if_uncaught_exception - }; - template class context_activator { context_activator( context_activator const & ) = delete; context_activator & operator=( context_activator const & ) = delete; +#if !defined(LEAF_NO_EXCEPTIONS) && LEAF_STD_UNCAUGHT_EXCEPTIONS + int const uncaught_exceptions_; +#endif Ctx * ctx_; - bool const ctx_was_active_; - on_deactivation on_deactivate_; public: - LEAF_CONSTEXPR LEAF_ALWAYS_INLINE context_activator(Ctx & ctx, on_deactivation on_deactivate) noexcept: - ctx_(&ctx), - ctx_was_active_(ctx.is_active()), - on_deactivate_(on_deactivate) + explicit LEAF_CONSTEXPR LEAF_ALWAYS_INLINE context_activator(Ctx & ctx) noexcept: +#if !defined(LEAF_NO_EXCEPTIONS) && LEAF_STD_UNCAUGHT_EXCEPTIONS + uncaught_exceptions_(std::uncaught_exceptions()), +#endif + ctx_(ctx.is_active() ? 0 : &ctx) { - if( !ctx_was_active_ ) - ctx.activate(); + if( ctx_ ) + ctx_->activate(); } LEAF_CONSTEXPR LEAF_ALWAYS_INLINE context_activator( context_activator && x ) noexcept: - ctx_(x.ctx_), - ctx_was_active_(x.ctx_was_active_), - on_deactivate_(x.on_deactivate_) +#if !defined(LEAF_NO_EXCEPTIONS) && LEAF_STD_UNCAUGHT_EXCEPTIONS + uncaught_exceptions_(x.uncaught_exceptions_), +#endif + ctx_(x.ctx_) { x.ctx_ = 0; } LEAF_ALWAYS_INLINE ~context_activator() noexcept { - if( ctx_ ) - { - assert( - on_deactivate_ == on_deactivation::propagate || - on_deactivate_ == on_deactivation::do_not_propagate || - on_deactivate_ == on_deactivation::propagate_if_uncaught_exception); - if( !ctx_was_active_ ) - if( on_deactivate_ == on_deactivation::propagate_if_uncaught_exception ) - { -#ifdef LEAF_NO_EXCEPTIONS - ctx_->deactivate(false); -#else - bool has_exception = LEAF_UNCAUGHT_EXCEPTIONS(); - ctx_->deactivate(has_exception); - if( !has_exception ) - (void) leaf_detail::new_id(); + if( !ctx_ ) + return; + if( ctx_->is_active() ) + ctx_->deactivate(); +#ifndef LEAF_NO_EXCEPTIONS +# if LEAF_STD_UNCAUGHT_EXCEPTIONS + if( std::uncaught_exceptions() > uncaught_exceptions_ ) +# else + if( std::uncaught_exception() ) +# endif + ctx_->propagate(); + else + (void) leaf_detail::new_id(); #endif - } - else - ctx_->deactivate(on_deactivate_ == on_deactivation::propagate); - } - } - - LEAF_CONSTEXPR LEAF_ALWAYS_INLINE void set_on_deactivate( on_deactivation on_deactivate ) noexcept - { - on_deactivate_ = on_deactivate; } }; template - LEAF_CONSTEXPR LEAF_ALWAYS_INLINE context_activator activate_context( Ctx & ctx, on_deactivation on_deactivate ) noexcept + LEAF_CONSTEXPR LEAF_ALWAYS_INLINE context_activator activate_context(Ctx & ctx) noexcept { - return context_activator(ctx, on_deactivate); + return context_activator(ctx); } //////////////////////////////////////////// @@ -1660,7 +1644,7 @@ namespace boost { namespace leaf { { public: - virtual error_id get_error_id() const = 0; + virtual error_id get_error_id() const noexcept = 0; protected: @@ -1674,7 +1658,7 @@ namespace boost { namespace leaf { public exception_base, public error_id { - error_id get_error_id() const final override + error_id get_error_id() const noexcept final override { return *this; } @@ -1754,7 +1738,11 @@ namespace boost { namespace leaf { else { #ifndef LEAF_NO_EXCEPTIONS - if( LEAF_UNCAUGHT_EXCEPTIONS() ) +# if LEAF_STD_UNCAUGHT_EXCEPTIONS + if( std::uncaught_exceptions() ) +# else + if( std::uncaught_exception() ) +# endif return leaf_detail::new_id(); #endif return 0; @@ -2068,7 +2056,7 @@ namespace boost { namespace leaf { [[noreturn]] void unload_and_rethrow_original_exception() const { assert(ctx_->captured_id_); - auto active_context = activate_context(*ctx_, on_deactivation::propagate); + auto active_context = activate_context(*ctx_); id_factory<>::current_id = ctx_->captured_id_.value(); std::rethrow_exception(ex_); } @@ -2082,7 +2070,7 @@ namespace boost { namespace leaf { template inline decltype(std::declval()(std::forward(std::declval())...)) capture_impl(is_result_tag, context_ptr && ctx, F && f, A... a) { - auto active_context = activate_context(*ctx, on_deactivation::do_not_propagate); + auto active_context = activate_context(*ctx); augment_id aug; try { @@ -2107,7 +2095,7 @@ namespace boost { namespace leaf { template inline decltype(std::declval()(std::forward(std::declval())...)) capture_impl(is_result_tag, context_ptr && ctx, F && f, A... a) { - auto active_context = activate_context(*ctx, on_deactivation::do_not_propagate); + auto active_context = activate_context(*ctx); augment_id aug; try { @@ -2172,14 +2160,14 @@ namespace boost { namespace leaf { template inline decltype(std::declval()(std::forward(std::declval())...)) capture_impl(is_result_tag, context_ptr && ctx, F && f, A... a) noexcept { - auto active_context = activate_context(*ctx, on_deactivation::do_not_propagate); + auto active_context = activate_context(*ctx); return std::forward(f)(std::forward(a)...); } template inline decltype(std::declval()(std::forward(std::declval())...)) capture_impl(is_result_tag, context_ptr && ctx, F && f, A... a) noexcept { - auto active_context = activate_context(*ctx, on_deactivation::do_not_propagate); + auto active_context = activate_context(*ctx); if( auto r = std::forward(f)(std::forward(a)...) ) return r; else @@ -2398,18 +2386,25 @@ namespace boost { namespace leaf { std::get(tup).activate(); } - LEAF_CONSTEXPR static void deactivate( Tuple & tup, bool propagate_errors ) noexcept + LEAF_CONSTEXPR static void deactivate( Tuple & tup ) noexcept { - std::get(tup).deactivate(propagate_errors); - tuple_for_each::deactivate(tup, propagate_errors); + std::get(tup).deactivate(); + tuple_for_each::deactivate(tup); } - LEAF_CONSTEXPR static void propagate( Tuple & tup, int err_id ) noexcept + LEAF_CONSTEXPR static void propagate( Tuple & tup ) noexcept + { + auto & sl = std::get(tup); + sl.propagate(); + tuple_for_each::propagate(tup); + } + + LEAF_CONSTEXPR static void propagate_captured( Tuple & tup, int err_id ) noexcept { auto & sl = std::get(tup); if( sl.has_value(err_id) ) leaf_detail::load_slot(err_id, std::move(sl).value(err_id)); - tuple_for_each::propagate(tup, err_id); + tuple_for_each::propagate_captured(tup, err_id); } static void print( std::ostream & os, void const * tup, int key_to_print ) @@ -2424,8 +2419,9 @@ namespace boost { namespace leaf { struct tuple_for_each<0, Tuple> { LEAF_CONSTEXPR static void activate( Tuple & ) noexcept { } - LEAF_CONSTEXPR static void deactivate( Tuple &, bool ) noexcept { } - LEAF_CONSTEXPR static void propagate( Tuple & tup, int ) noexcept { } + LEAF_CONSTEXPR static void deactivate( Tuple & ) noexcept { } + LEAF_CONSTEXPR static void propagate( Tuple & tup ) noexcept { } + LEAF_CONSTEXPR static void propagate_captured( Tuple & tup, int ) noexcept { } static void print( std::ostream &, void const *, int ) { } }; } @@ -2606,7 +2602,7 @@ namespace boost { namespace leaf { is_active_ = true; } - LEAF_CONSTEXPR void deactivate( bool propagate_errors ) noexcept + LEAF_CONSTEXPR void deactivate() noexcept { using namespace leaf_detail; assert(is_active()); @@ -2619,7 +2615,12 @@ namespace boost { namespace leaf { if( unexpected_requested::value ) --tl_unexpected_enabled_counter(); #endif - tuple_for_each::value,Tup>::deactivate(tup_, propagate_errors); + tuple_for_each::value,Tup>::deactivate(tup_); + } + + LEAF_CONSTEXPR void propagate() noexcept + { + tuple_for_each::value,Tup>::propagate(tup_); } LEAF_CONSTEXPR bool is_active() const noexcept @@ -2632,57 +2633,69 @@ namespace boost { namespace leaf { leaf_detail::tuple_for_each::value,Tup>::print(os, &tup_, 0); } + template + LEAF_CONSTEXPR typename std::decay().value())>::type handle_all_( R &, H && ... ); + + template + LEAF_CONSTEXPR typename std::decay().value())>::type remote_handle_all_( R &, RemoteH && ); + + template + LEAF_CONSTEXPR R handle_some_( R &&, H && ... ); + + template + LEAF_CONSTEXPR R remote_handle_some_( R &&, RemoteH && ); + + template + decltype(std::declval()()) try_catch_( TryBlock &&, H && ... ); + + template + decltype(std::declval()()) remote_try_catch_( TryBlock &&, RemoteH && ); + + template + LEAF_CONSTEXPR R handle_current_exception_( H && ... ); + + template + LEAF_CONSTEXPR R remote_handle_current_exception_( RemoteH && ); + + template + LEAF_CONSTEXPR R handle_exception_( std::exception_ptr const &, H && ... ); + + template + LEAF_CONSTEXPR R remote_handle_exception_( std::exception_ptr const &, RemoteH && ); + protected: LEAF_CONSTEXPR error_id propagate_captured_errors( error_id err_id ) noexcept { - tuple_for_each::value,Tup>::propagate(tup_, err_id.value()); + tuple_for_each::value,Tup>::propagate_captured(tup_, err_id.value()); return err_id; } - template - LEAF_CONSTEXPR typename std::decay()().value())>::type try_handle_all_( TryBlock &&, H && ... ) const; - - template - LEAF_CONSTEXPR typename std::decay()().value())>::type remote_try_handle_all_( TryBlock &&, RemoteH && ) const; - - template - LEAF_CONSTEXPR typename std::decay()())>::type try_handle_some_( context_activator &, TryBlock &&, H && ... ) const; - - template - LEAF_CONSTEXPR typename std::decay()())>::type remote_try_handle_some_( context_activator &, TryBlock &&, RemoteH && ) const; - public: template - LEAF_CONSTEXPR typename std::decay().value())>::type handle_all( R &, H && ... ) const; + LEAF_CONSTEXPR typename std::decay().value())>::type handle_all( R &, H && ... ); template - LEAF_CONSTEXPR typename std::decay().value())>::type remote_handle_all( R &, RemoteH && ) const; + LEAF_CONSTEXPR typename std::decay().value())>::type remote_handle_all( R &, RemoteH && ); template - LEAF_CONSTEXPR R handle_some( R &&, H && ... ) const; + LEAF_CONSTEXPR R handle_some( R &&, H && ... ); template - LEAF_CONSTEXPR R remote_handle_some( R &&, RemoteH && ) const; - - template - decltype(std::declval()()) try_catch_( TryBlock &&, H && ... ) const; - - template - decltype(std::declval()()) remote_try_catch_( TryBlock &&, RemoteH && ) const; + LEAF_CONSTEXPR R remote_handle_some( R &&, RemoteH && ); template - LEAF_CONSTEXPR R handle_current_exception( H && ... ) const; + LEAF_CONSTEXPR R handle_current_exception( H && ... ); template - LEAF_CONSTEXPR R remote_handle_current_exception( RemoteH && ) const; + LEAF_CONSTEXPR R remote_handle_current_exception( RemoteH && ); template - LEAF_CONSTEXPR R handle_exception( std::exception_ptr const &, H && ... ) const; + LEAF_CONSTEXPR R handle_exception( std::exception_ptr const &, H && ... ); template - LEAF_CONSTEXPR R remote_handle_exception( std::exception_ptr const &, RemoteH && ) const; + LEAF_CONSTEXPR R remote_handle_exception( std::exception_ptr const &, RemoteH && ); }; template @@ -2813,7 +2826,8 @@ namespace boost { namespace leaf { { error_id propagate_captured_errors() noexcept final override { return Ctx::propagate_captured_errors(captured_id_); } void activate() noexcept final override { Ctx::activate(); } - void deactivate( bool propagate_errors ) noexcept final override { Ctx::deactivate(propagate_errors); } + void deactivate() noexcept final override { Ctx::deactivate(); } + void propagate() noexcept final override { Ctx::propagate(); } bool is_active() const noexcept final override { return Ctx::is_active(); } void print( std::ostream & os ) const final override { return Ctx::print(os); } }; @@ -3574,102 +3588,80 @@ namespace boost { namespace leaf { { template template - LEAF_CONSTEXPR inline typename std::decay().value())>::type context_base::handle_all( R & r, H && ... h ) const + LEAF_CONSTEXPR inline typename std::decay().value())>::type context_base::handle_all_( R & r, H && ... h ) { - using namespace leaf_detail; using Ret = typename std::decay().value())>::type; static_assert(is_result_type::value, "The R type used with a handle_all function must be registered with leaf::is_result_type"); - return handle_error_(tup(), error_info(r.error()), std::forward(h)...); + assert(is_active()); + error_info const ei(r.error()); + deactivate(); + return handle_error_(tup(), ei, std::forward(h)...); } template template - LEAF_CONSTEXPR inline typename std::decay().value())>::type context_base::remote_handle_all( R & r, RemoteH && h ) const + LEAF_CONSTEXPR inline typename std::decay().value())>::type context_base::remote_handle_all_( R & r, RemoteH && h ) { static_assert(is_result_type::value, "The R type used with a handle_all function must be registered with leaf::is_result_type"); - return std::forward(h)(error_info(r.error(), this)).get(); + assert(is_active()); + error_info const ei(r.error(), this); + deactivate(); + return std::forward(h)(ei).get(); } template template - LEAF_CONSTEXPR inline R context_base::handle_some( R && r, H && ... h ) const + LEAF_CONSTEXPR inline R context_base::handle_some_( R && r, H && ... h ) { - using namespace leaf_detail; static_assert(is_result_type::value, "The R type used with a handle_some function must be registered with leaf::is_result_type"); - return handle_error_(tup(), error_info(r.error()), std::forward(h)..., + assert(is_active()); + error_info const ei(r.error()); + deactivate(); + return handle_error_(tup(), ei, std::forward(h)..., [&r]()->R { return std::move(r); }); } template template - LEAF_CONSTEXPR inline R context_base::remote_handle_some( R && r, RemoteH && h ) const + LEAF_CONSTEXPR inline R context_base::remote_handle_some_( R && r, RemoteH && h ) { static_assert(is_result_type::value, "The R type used with a handle_some function must be registered with leaf::is_result_type"); - return std::forward(h)(error_info(r.error(), this)).get(); - } - - //////////////////////////////////////////// - - template - template - LEAF_CONSTEXPR inline typename std::decay()().value())>::type context_base::try_handle_all_( TryBlock && try_block, H && ... h ) const - { - using namespace leaf_detail; - static_assert(is_result_type()())>::value, "The return type of the try_block passed to a try_handle_all function must be registered with leaf::is_result_type"); - assert(this->is_active()); - if( auto r = std::forward(try_block)() ) - return r.value(); - else - return handle_all(r, std::forward(h)...); + assert(is_active()); + error_info const ei(r.error(), this); + deactivate(); + return std::forward(h)(ei).get(); } template - template - LEAF_CONSTEXPR inline typename std::decay()().value())>::type context_base::remote_try_handle_all_( TryBlock && try_block, RemoteH && h ) const + template + LEAF_CONSTEXPR inline typename std::decay().value())>::type context_base::handle_all( R & r, H && ... h ) { - using namespace leaf_detail; - static_assert(is_result_type()())>::value, "The return type of the try_block passed to a remote_try_handle_all function must be registered with leaf::is_result_type"); - assert(this->is_active()); - if( auto r = std::forward(try_block)() ) - return r.value(); - else - return remote_handle_all(r, std::forward(h)); + auto active_context = activate_context(*this); + return handle_all_(r, std::forward(h)...); } template - template - LEAF_CONSTEXPR inline typename std::decay()())>::type context_base::try_handle_some_( context_activator & active_context, TryBlock && try_block, H && ... h ) const + template + LEAF_CONSTEXPR inline typename std::decay().value())>::type context_base::remote_handle_all( R & r, RemoteH && h ) { - using namespace leaf_detail; - static_assert(is_result_type()())>::value, "The return type of the try_block passed to a try_handle_some function must be registered with leaf::is_result_type"); - assert(this->is_active()); - if( auto r = std::forward(try_block)() ) - return r; - else - { - auto rr = handle_some(std::move(r), std::forward(h)...); - if( !rr ) - active_context.set_on_deactivate(on_deactivation::propagate); - return rr; - } + auto active_context = activate_context(*this); + return remote_handle_all_(r, std::forward(h)); } template - template - LEAF_CONSTEXPR inline typename std::decay()())>::type context_base::remote_try_handle_some_( context_activator & active_context, TryBlock && try_block, RemoteH && h ) const + template + LEAF_CONSTEXPR inline R context_base::handle_some( R && r, H && ... h ) { - using namespace leaf_detail; - static_assert(is_result_type()())>::value, "The return type of the try_block passed to a remote_try_handle_some function must be registered with leaf::is_result_type"); - assert(this->is_active()); - if( auto r = std::forward(try_block)() ) - return r; - else - { - auto rr = remote_handle_some(std::move(r), std::forward(h)); - if( !rr ) - active_context.set_on_deactivate(on_deactivation::propagate); - return rr; - } + auto active_context = activate_context(*this); + return handle_some_(std::forward(r), std::forward(h)...); + } + + template + template + LEAF_CONSTEXPR inline R context_base::remote_handle_some( R && r, RemoteH && h ) + { + auto active_context = activate_context(*this); + return remote_handle_some_(std::forward(r), std::forward(h)); } } @@ -3780,32 +3772,62 @@ namespace boost { namespace leaf { template LEAF_CONSTEXPR LEAF_ALWAYS_INLINE typename std::decay()().value())>::type nocatch_context::try_handle_all( TryBlock && try_block, H && ... h ) { - auto active_context = activate_context(*this, on_deactivation::do_not_propagate); - return this->try_handle_all_( std::forward(try_block), std::forward(h)... ); + using namespace leaf_detail; + static_assert(is_result_type()())>::value, "The return type of the try_block passed to a try_handle_all function must be registered with leaf::is_result_type"); + auto active_context = activate_context(*this); + if( auto r = std::forward(try_block)() ) + return r.value(); + else + return this->handle_all_(r, std::forward(h)...); } template template LEAF_CONSTEXPR LEAF_ALWAYS_INLINE typename std::decay()().value())>::type nocatch_context::remote_try_handle_all( TryBlock && try_block, RemoteH && h ) { - auto active_context = activate_context(*this, on_deactivation::do_not_propagate); - return this->remote_try_handle_all_( std::forward(try_block), std::forward(h) ); + using namespace leaf_detail; + static_assert(is_result_type()())>::value, "The return type of the try_block passed to a remote_try_handle_all function must be registered with leaf::is_result_type"); + auto active_context = activate_context(*this); + if( auto r = std::forward(try_block)() ) + return r.value(); + else + return this->remote_handle_all_(r, std::forward(h)); } template template LEAF_CONSTEXPR LEAF_ALWAYS_INLINE typename std::decay()())>::type nocatch_context::try_handle_some( TryBlock && try_block, H && ... h ) { - auto active_context = activate_context(*this, on_deactivation::propagate_if_uncaught_exception); - return this->try_handle_some_( active_context, std::forward(try_block), std::forward(h)... ); + using namespace leaf_detail; + static_assert(is_result_type()())>::value, "The return type of the try_block passed to a try_handle_some function must be registered with leaf::is_result_type"); + auto active_context = activate_context(*this); + if( auto r = std::forward(try_block)() ) + return r; + else + { + auto rr = this->handle_some_(std::move(r), std::forward(h)...); + if( !rr ) + this->propagate(); + return rr; + } } template template LEAF_CONSTEXPR LEAF_ALWAYS_INLINE typename std::decay()())>::type nocatch_context::remote_try_handle_some( TryBlock && try_block, RemoteH && h ) { - auto active_context = activate_context(*this, on_deactivation::propagate_if_uncaught_exception); - return this->remote_try_handle_some_( active_context, std::forward(try_block), std::forward(h) ); + using namespace leaf_detail; + static_assert(is_result_type()())>::value, "The return type of the try_block passed to a remote_try_handle_some function must be registered with leaf::is_result_type"); + auto active_context = activate_context(*this); + if( auto r = std::forward(try_block)() ) + return r; + else + { + auto rr = remote_handle_some_(std::move(r), std::forward(h)); + if( !rr ) + this->propagate(); + return rr; + } } } @@ -4059,49 +4081,23 @@ namespace boost { namespace leaf { //////////////////////////////////////// - template - LEAF_CONSTEXPR inline decltype(std::declval()()) try_catch( TryBlock && try_block, H && ... h ) - { - using namespace leaf_detail; - context_type_from_handlers ctx; - auto active_context = activate_context(ctx, on_deactivation::propagate_if_uncaught_exception); - return ctx.try_catch_( - [&] - { - return std::forward(try_block)(); - }, - std::forward(h)...); - } - - template - LEAF_CONSTEXPR inline decltype(std::declval()()) remote_try_catch( TryBlock && try_block, RemoteH && h ) - { - using namespace leaf_detail; - context_type_from_remote_handler ctx; - auto active_context = activate_context(ctx, on_deactivation::propagate_if_uncaught_exception); - return ctx.remote_try_catch_( - [&] - { - return std::forward(try_block)(); - }, - std::forward(h)); - } - namespace leaf_detail { template template - LEAF_CONSTEXPR inline R context_base::handle_current_exception( H && ... h ) const + LEAF_CONSTEXPR inline R context_base::handle_current_exception_( H && ... h ) { + assert(is_active()); return this->try_catch_( - []{ throw; }, + []() -> R { throw; }, std::forward(h)...); } template template - LEAF_CONSTEXPR inline R context_base::remote_handle_current_exception( RemoteH && h ) const + LEAF_CONSTEXPR inline R context_base::remote_handle_current_exception_( RemoteH && h ) { + assert(is_active()); return this->remote_try_catch_( []() -> R { throw; }, std::forward(h)); @@ -4109,22 +4105,56 @@ namespace boost { namespace leaf { template template - LEAF_CONSTEXPR inline R context_base::handle_exception( std::exception_ptr const & ep, H && ... h ) const + LEAF_CONSTEXPR inline R context_base::handle_exception_( std::exception_ptr const & ep, H && ... h ) { + assert(is_active()); return this->try_catch_( - [&]{ std::rethrow_exception(ep); }, + [&]() -> R { std::rethrow_exception(ep); }, std::forward(h)...); } template template - LEAF_CONSTEXPR inline R context_base::remote_handle_exception( std::exception_ptr const & ep, RemoteH && h ) const + LEAF_CONSTEXPR inline R context_base::remote_handle_exception_( std::exception_ptr const & ep, RemoteH && h ) { + assert(is_active()); return this->remote_try_catch_( [&]() -> R { std::rethrow_exception(ep); }, std::forward(h)); } + template + template + LEAF_CONSTEXPR inline R context_base::handle_current_exception( H && ... h ) + { + auto active_context = activate_context(*this); + return handle_current_exception_(std::forward(h)...); + } + + template + template + LEAF_CONSTEXPR inline R context_base::remote_handle_current_exception( RemoteH && h ) + { + auto active_context = activate_context(*this); + return remote_handle_current_exception_(std::forward(h)); + } + + template + template + LEAF_CONSTEXPR inline R context_base::handle_exception( std::exception_ptr const & ep, H && ... h ) + { + auto active_context = activate_context(*this); + return handle_exception_(ep, std::forward(h)...); + } + + template + template + LEAF_CONSTEXPR inline R context_base::remote_handle_exception( std::exception_ptr const & ep, RemoteH && h ) + { + auto active_context = activate_context(*this); + return remote_handle_exception_(ep, std::forward(h)); + } + //////////////////////////////////////// template @@ -4133,7 +4163,7 @@ namespace boost { namespace leaf { { using namespace leaf_detail; static_assert(is_result_type()())>::value, "The return type of the try_block passed to a try_handle_all function must be registered with leaf::is_result_type"); - auto active_context = activate_context(*this, on_deactivation::propagate_if_uncaught_exception); + auto active_context = activate_context(*this); if( auto r = this->try_catch_( [&] { @@ -4151,7 +4181,7 @@ namespace boost { namespace leaf { { using namespace leaf_detail; static_assert(is_result_type()())>::value, "The return type of the try_block passed to a try_handle_all function must be registered with leaf::is_result_type"); - auto active_context = activate_context(*this, on_deactivation::propagate_if_uncaught_exception); + auto active_context = activate_context(*this); if( auto r = this->remote_try_catch_( [&] { @@ -4169,7 +4199,7 @@ namespace boost { namespace leaf { { using namespace leaf_detail; static_assert(is_result_type()())>::value, "The return type of the try_block passed to a try_handle_some function must be registered with leaf::is_result_type"); - auto active_context = activate_context(*this, on_deactivation::propagate_if_uncaught_exception); + auto active_context = activate_context(*this); if( auto r = this->try_catch_( [&] { @@ -4181,7 +4211,7 @@ namespace boost { namespace leaf { { auto rr = this->handle_some(std::move(r), std::forward(h)...); if( !rr ) - active_context.set_on_deactivate(on_deactivation::propagate); + this->propagate(); return rr; } } @@ -4190,7 +4220,9 @@ namespace boost { namespace leaf { template LEAF_CONSTEXPR inline typename std::decay()())>::type catch_context::remote_try_handle_some( TryBlock && try_block, RemoteH && h ) { - auto active_context = activate_context(*this, on_deactivation::propagate_if_uncaught_exception); + using namespace leaf_detail; + static_assert(is_result_type()())>::value, "The return type of the try_block passed to a remote_try_handle_some function must be registered with leaf::is_result_type"); + auto active_context = activate_context(*this); if( auto r = this->remote_try_catch_( [&] { @@ -4202,7 +4234,7 @@ namespace boost { namespace leaf { { auto rr = this->remote_handle_some(std::move(r), std::forward(h)); if( !rr ) - active_context.set_on_deactivate(on_deactivation::propagate); + this->propagate(); return rr; } } @@ -4228,9 +4260,10 @@ namespace boost { namespace leaf { template template - inline decltype(std::declval()()) context_base::try_catch_( TryBlock && try_block, H && ... h ) const + inline decltype(std::declval()()) context_base::try_catch_( TryBlock && try_block, H && ... h ) { using namespace leaf_detail; + assert(is_active()); using R = decltype(std::declval()()); try { @@ -4244,22 +4277,26 @@ namespace boost { namespace leaf { } catch( std::exception const & ex ) { + deactivate(); return leaf_detail::handle_error_(this->tup(), error_info(exception_info_(&ex)), std::forward(h)..., []() -> R { throw; } ); } catch(...) { + deactivate(); return leaf_detail::handle_error_(this->tup(), error_info(exception_info_(0)), std::forward(h)..., []() -> R { throw; } ); } } catch( std::exception const & ex ) { + deactivate(); return leaf_detail::handle_error_(this->tup(), error_info(exception_info_(&ex)), std::forward(h)..., []() -> R { throw; } ); } catch(...) { + deactivate(); return leaf_detail::handle_error_(this->tup(), error_info(exception_info_(0)), std::forward(h)..., []() -> R { throw; } ); } @@ -4267,9 +4304,10 @@ namespace boost { namespace leaf { template template - inline decltype(std::declval()()) context_base::remote_try_catch_( TryBlock && try_block, RemoteH && h ) const + inline decltype(std::declval()()) context_base::remote_try_catch_( TryBlock && try_block, RemoteH && h ) { using namespace leaf_detail; + assert(is_active()); try { return std::forward(try_block)(); @@ -4282,19 +4320,23 @@ namespace boost { namespace leaf { } catch( std::exception const & ex ) { + deactivate(); return std::forward(h)(error_info(exception_info_(&ex), this)).get(); } catch(...) { + deactivate(); return std::forward(h)(error_info(exception_info_(0), this)).get(); } } catch( std::exception const & ex ) { + deactivate(); return std::forward(h)(error_info(exception_info_(&ex), this)).get(); } catch(...) { + deactivate(); return std::forward(h)(error_info(exception_info_(0), this)).get(); } } @@ -4376,6 +4418,36 @@ namespace boost { namespace leaf { { } + //////////////////////////////////////// + + template + LEAF_CONSTEXPR inline decltype(std::declval()()) try_catch( TryBlock && try_block, H && ... h ) + { + using namespace leaf_detail; + context_type_from_handlers ctx; + auto active_context = activate_context(ctx); + return ctx.try_catch_( + [&] + { + return std::forward(try_block)(); + }, + std::forward(h)...); + } + + template + LEAF_CONSTEXPR inline decltype(std::declval()()) remote_try_catch( TryBlock && try_block, RemoteH && h ) + { + using namespace leaf_detail; + context_type_from_remote_handler ctx; + auto active_context = activate_context(ctx); + return ctx.remote_try_catch_( + [&] + { + return std::forward(try_block)(); + }, + std::forward(h)); + } + } } #endif diff --git a/include/boost/leaf/capture.hpp b/include/boost/leaf/capture.hpp index e8a58b4..63050a7 100644 --- a/include/boost/leaf/capture.hpp +++ b/include/boost/leaf/capture.hpp @@ -36,7 +36,7 @@ namespace boost { namespace leaf { [[noreturn]] void unload_and_rethrow_original_exception() const { assert(ctx_->captured_id_); - auto active_context = activate_context(*ctx_, on_deactivation::propagate); + auto active_context = activate_context(*ctx_); id_factory<>::current_id = ctx_->captured_id_.value(); std::rethrow_exception(ex_); } @@ -50,7 +50,7 @@ namespace boost { namespace leaf { template inline decltype(std::declval()(std::forward(std::declval())...)) capture_impl(is_result_tag, context_ptr && ctx, F && f, A... a) { - auto active_context = activate_context(*ctx, on_deactivation::do_not_propagate); + auto active_context = activate_context(*ctx); augment_id aug; try { @@ -75,7 +75,7 @@ namespace boost { namespace leaf { template inline decltype(std::declval()(std::forward(std::declval())...)) capture_impl(is_result_tag, context_ptr && ctx, F && f, A... a) { - auto active_context = activate_context(*ctx, on_deactivation::do_not_propagate); + auto active_context = activate_context(*ctx); augment_id aug; try { @@ -140,14 +140,14 @@ namespace boost { namespace leaf { template inline decltype(std::declval()(std::forward(std::declval())...)) capture_impl(is_result_tag, context_ptr && ctx, F && f, A... a) noexcept { - auto active_context = activate_context(*ctx, on_deactivation::do_not_propagate); + auto active_context = activate_context(*ctx); return std::forward(f)(std::forward(a)...); } template inline decltype(std::declval()(std::forward(std::declval())...)) capture_impl(is_result_tag, context_ptr && ctx, F && f, A... a) noexcept { - auto active_context = activate_context(*ctx, on_deactivation::do_not_propagate); + auto active_context = activate_context(*ctx); if( auto r = std::forward(f)(std::forward(a)...) ) return r; else diff --git a/include/boost/leaf/config.hpp b/include/boost/leaf/config.hpp index 8b4ae80..f6eae5e 100644 --- a/include/boost/leaf/config.hpp +++ b/include/boost/leaf/config.hpp @@ -109,10 +109,10 @@ #if __cplusplus > 201402L # define LEAF_CONSTEXPR constexpr -# define LEAF_UNCAUGHT_EXCEPTIONS std::uncaught_exceptions +# define LEAF_STD_UNCAUGHT_EXCEPTIONS 1 #else # define LEAF_CONSTEXPR -# define LEAF_UNCAUGHT_EXCEPTIONS std::uncaught_exception +# define LEAF_STD_UNCAUGHT_EXCEPTIONS 0 #endif #endif diff --git a/include/boost/leaf/context.hpp b/include/boost/leaf/context.hpp index f573ef7..f845475 100644 --- a/include/boost/leaf/context.hpp +++ b/include/boost/leaf/context.hpp @@ -21,18 +21,25 @@ namespace boost { namespace leaf { std::get(tup).activate(); } - LEAF_CONSTEXPR static void deactivate( Tuple & tup, bool propagate_errors ) noexcept + LEAF_CONSTEXPR static void deactivate( Tuple & tup ) noexcept { - std::get(tup).deactivate(propagate_errors); - tuple_for_each::deactivate(tup, propagate_errors); + std::get(tup).deactivate(); + tuple_for_each::deactivate(tup); } - LEAF_CONSTEXPR static void propagate( Tuple & tup, int err_id ) noexcept + LEAF_CONSTEXPR static void propagate( Tuple & tup ) noexcept + { + auto & sl = std::get(tup); + sl.propagate(); + tuple_for_each::propagate(tup); + } + + LEAF_CONSTEXPR static void propagate_captured( Tuple & tup, int err_id ) noexcept { auto & sl = std::get(tup); if( sl.has_value(err_id) ) leaf_detail::load_slot(err_id, std::move(sl).value(err_id)); - tuple_for_each::propagate(tup, err_id); + tuple_for_each::propagate_captured(tup, err_id); } static void print( std::ostream & os, void const * tup, int key_to_print ) @@ -47,8 +54,9 @@ namespace boost { namespace leaf { struct tuple_for_each<0, Tuple> { LEAF_CONSTEXPR static void activate( Tuple & ) noexcept { } - LEAF_CONSTEXPR static void deactivate( Tuple &, bool ) noexcept { } - LEAF_CONSTEXPR static void propagate( Tuple & tup, int ) noexcept { } + LEAF_CONSTEXPR static void deactivate( Tuple & ) noexcept { } + LEAF_CONSTEXPR static void propagate( Tuple & tup ) noexcept { } + LEAF_CONSTEXPR static void propagate_captured( Tuple & tup, int ) noexcept { } static void print( std::ostream &, void const *, int ) { } }; } @@ -229,7 +237,7 @@ namespace boost { namespace leaf { is_active_ = true; } - LEAF_CONSTEXPR void deactivate( bool propagate_errors ) noexcept + LEAF_CONSTEXPR void deactivate() noexcept { using namespace leaf_detail; assert(is_active()); @@ -242,7 +250,12 @@ namespace boost { namespace leaf { if( unexpected_requested::value ) --tl_unexpected_enabled_counter(); #endif - tuple_for_each::value,Tup>::deactivate(tup_, propagate_errors); + tuple_for_each::value,Tup>::deactivate(tup_); + } + + LEAF_CONSTEXPR void propagate() noexcept + { + tuple_for_each::value,Tup>::propagate(tup_); } LEAF_CONSTEXPR bool is_active() const noexcept @@ -255,57 +268,69 @@ namespace boost { namespace leaf { leaf_detail::tuple_for_each::value,Tup>::print(os, &tup_, 0); } + template + LEAF_CONSTEXPR typename std::decay().value())>::type handle_all_( R &, H && ... ); + + template + LEAF_CONSTEXPR typename std::decay().value())>::type remote_handle_all_( R &, RemoteH && ); + + template + LEAF_CONSTEXPR R handle_some_( R &&, H && ... ); + + template + LEAF_CONSTEXPR R remote_handle_some_( R &&, RemoteH && ); + + template + decltype(std::declval()()) try_catch_( TryBlock &&, H && ... ); + + template + decltype(std::declval()()) remote_try_catch_( TryBlock &&, RemoteH && ); + + template + LEAF_CONSTEXPR R handle_current_exception_( H && ... ); + + template + LEAF_CONSTEXPR R remote_handle_current_exception_( RemoteH && ); + + template + LEAF_CONSTEXPR R handle_exception_( std::exception_ptr const &, H && ... ); + + template + LEAF_CONSTEXPR R remote_handle_exception_( std::exception_ptr const &, RemoteH && ); + protected: LEAF_CONSTEXPR error_id propagate_captured_errors( error_id err_id ) noexcept { - tuple_for_each::value,Tup>::propagate(tup_, err_id.value()); + tuple_for_each::value,Tup>::propagate_captured(tup_, err_id.value()); return err_id; } - template - LEAF_CONSTEXPR typename std::decay()().value())>::type try_handle_all_( TryBlock &&, H && ... ) const; - - template - LEAF_CONSTEXPR typename std::decay()().value())>::type remote_try_handle_all_( TryBlock &&, RemoteH && ) const; - - template - LEAF_CONSTEXPR typename std::decay()())>::type try_handle_some_( context_activator &, TryBlock &&, H && ... ) const; - - template - LEAF_CONSTEXPR typename std::decay()())>::type remote_try_handle_some_( context_activator &, TryBlock &&, RemoteH && ) const; - public: template - LEAF_CONSTEXPR typename std::decay().value())>::type handle_all( R &, H && ... ) const; + LEAF_CONSTEXPR typename std::decay().value())>::type handle_all( R &, H && ... ); template - LEAF_CONSTEXPR typename std::decay().value())>::type remote_handle_all( R &, RemoteH && ) const; + LEAF_CONSTEXPR typename std::decay().value())>::type remote_handle_all( R &, RemoteH && ); template - LEAF_CONSTEXPR R handle_some( R &&, H && ... ) const; + LEAF_CONSTEXPR R handle_some( R &&, H && ... ); template - LEAF_CONSTEXPR R remote_handle_some( R &&, RemoteH && ) const; - - template - decltype(std::declval()()) try_catch_( TryBlock &&, H && ... ) const; - - template - decltype(std::declval()()) remote_try_catch_( TryBlock &&, RemoteH && ) const; + LEAF_CONSTEXPR R remote_handle_some( R &&, RemoteH && ); template - LEAF_CONSTEXPR R handle_current_exception( H && ... ) const; + LEAF_CONSTEXPR R handle_current_exception( H && ... ); template - LEAF_CONSTEXPR R remote_handle_current_exception( RemoteH && ) const; + LEAF_CONSTEXPR R remote_handle_current_exception( RemoteH && ); template - LEAF_CONSTEXPR R handle_exception( std::exception_ptr const &, H && ... ) const; + LEAF_CONSTEXPR R handle_exception( std::exception_ptr const &, H && ... ); template - LEAF_CONSTEXPR R remote_handle_exception( std::exception_ptr const &, RemoteH && ) const; + LEAF_CONSTEXPR R remote_handle_exception( std::exception_ptr const &, RemoteH && ); }; template @@ -436,7 +461,8 @@ namespace boost { namespace leaf { { error_id propagate_captured_errors() noexcept final override { return Ctx::propagate_captured_errors(captured_id_); } void activate() noexcept final override { Ctx::activate(); } - void deactivate( bool propagate_errors ) noexcept final override { Ctx::deactivate(propagate_errors); } + void deactivate() noexcept final override { Ctx::deactivate(); } + void propagate() noexcept final override { Ctx::propagate(); } bool is_active() const noexcept final override { return Ctx::is_active(); } void print( std::ostream & os ) const final override { return Ctx::print(os); } }; diff --git a/include/boost/leaf/detail/handle.hpp b/include/boost/leaf/detail/handle.hpp index 532b898..57a6f38 100644 --- a/include/boost/leaf/detail/handle.hpp +++ b/include/boost/leaf/detail/handle.hpp @@ -708,102 +708,80 @@ namespace boost { namespace leaf { { template template - LEAF_CONSTEXPR inline typename std::decay().value())>::type context_base::handle_all( R & r, H && ... h ) const + LEAF_CONSTEXPR inline typename std::decay().value())>::type context_base::handle_all_( R & r, H && ... h ) { - using namespace leaf_detail; using Ret = typename std::decay().value())>::type; static_assert(is_result_type::value, "The R type used with a handle_all function must be registered with leaf::is_result_type"); - return handle_error_(tup(), error_info(r.error()), std::forward(h)...); + assert(is_active()); + error_info const ei(r.error()); + deactivate(); + return handle_error_(tup(), ei, std::forward(h)...); } template template - LEAF_CONSTEXPR inline typename std::decay().value())>::type context_base::remote_handle_all( R & r, RemoteH && h ) const + LEAF_CONSTEXPR inline typename std::decay().value())>::type context_base::remote_handle_all_( R & r, RemoteH && h ) { static_assert(is_result_type::value, "The R type used with a handle_all function must be registered with leaf::is_result_type"); - return std::forward(h)(error_info(r.error(), this)).get(); + assert(is_active()); + error_info const ei(r.error(), this); + deactivate(); + return std::forward(h)(ei).get(); } template template - LEAF_CONSTEXPR inline R context_base::handle_some( R && r, H && ... h ) const + LEAF_CONSTEXPR inline R context_base::handle_some_( R && r, H && ... h ) { - using namespace leaf_detail; static_assert(is_result_type::value, "The R type used with a handle_some function must be registered with leaf::is_result_type"); - return handle_error_(tup(), error_info(r.error()), std::forward(h)..., + assert(is_active()); + error_info const ei(r.error()); + deactivate(); + return handle_error_(tup(), ei, std::forward(h)..., [&r]()->R { return std::move(r); }); } template template - LEAF_CONSTEXPR inline R context_base::remote_handle_some( R && r, RemoteH && h ) const + LEAF_CONSTEXPR inline R context_base::remote_handle_some_( R && r, RemoteH && h ) { static_assert(is_result_type::value, "The R type used with a handle_some function must be registered with leaf::is_result_type"); - return std::forward(h)(error_info(r.error(), this)).get(); - } - - //////////////////////////////////////////// - - template - template - LEAF_CONSTEXPR inline typename std::decay()().value())>::type context_base::try_handle_all_( TryBlock && try_block, H && ... h ) const - { - using namespace leaf_detail; - static_assert(is_result_type()())>::value, "The return type of the try_block passed to a try_handle_all function must be registered with leaf::is_result_type"); - assert(this->is_active()); - if( auto r = std::forward(try_block)() ) - return r.value(); - else - return handle_all(r, std::forward(h)...); + assert(is_active()); + error_info const ei(r.error(), this); + deactivate(); + return std::forward(h)(ei).get(); } template - template - LEAF_CONSTEXPR inline typename std::decay()().value())>::type context_base::remote_try_handle_all_( TryBlock && try_block, RemoteH && h ) const + template + LEAF_CONSTEXPR inline typename std::decay().value())>::type context_base::handle_all( R & r, H && ... h ) { - using namespace leaf_detail; - static_assert(is_result_type()())>::value, "The return type of the try_block passed to a remote_try_handle_all function must be registered with leaf::is_result_type"); - assert(this->is_active()); - if( auto r = std::forward(try_block)() ) - return r.value(); - else - return remote_handle_all(r, std::forward(h)); + auto active_context = activate_context(*this); + return handle_all_(r, std::forward(h)...); } template - template - LEAF_CONSTEXPR inline typename std::decay()())>::type context_base::try_handle_some_( context_activator & active_context, TryBlock && try_block, H && ... h ) const + template + LEAF_CONSTEXPR inline typename std::decay().value())>::type context_base::remote_handle_all( R & r, RemoteH && h ) { - using namespace leaf_detail; - static_assert(is_result_type()())>::value, "The return type of the try_block passed to a try_handle_some function must be registered with leaf::is_result_type"); - assert(this->is_active()); - if( auto r = std::forward(try_block)() ) - return r; - else - { - auto rr = handle_some(std::move(r), std::forward(h)...); - if( !rr ) - active_context.set_on_deactivate(on_deactivation::propagate); - return rr; - } + auto active_context = activate_context(*this); + return remote_handle_all_(r, std::forward(h)); } template - template - LEAF_CONSTEXPR inline typename std::decay()())>::type context_base::remote_try_handle_some_( context_activator & active_context, TryBlock && try_block, RemoteH && h ) const + template + LEAF_CONSTEXPR inline R context_base::handle_some( R && r, H && ... h ) { - using namespace leaf_detail; - static_assert(is_result_type()())>::value, "The return type of the try_block passed to a remote_try_handle_some function must be registered with leaf::is_result_type"); - assert(this->is_active()); - if( auto r = std::forward(try_block)() ) - return r; - else - { - auto rr = remote_handle_some(std::move(r), std::forward(h)); - if( !rr ) - active_context.set_on_deactivate(on_deactivation::propagate); - return rr; - } + auto active_context = activate_context(*this); + return handle_some_(std::forward(r), std::forward(h)...); + } + + template + template + LEAF_CONSTEXPR inline R context_base::remote_handle_some( R && r, RemoteH && h ) + { + auto active_context = activate_context(*this); + return remote_handle_some_(std::forward(r), std::forward(h)); } } diff --git a/include/boost/leaf/error.hpp b/include/boost/leaf/error.hpp index f1e8d1d..3afcc36 100644 --- a/include/boost/leaf/error.hpp +++ b/include/boost/leaf/error.hpp @@ -243,20 +243,22 @@ namespace boost { namespace leaf { assert(x.top_==0); } - ~slot() noexcept - { - assert(top_==0); - } - LEAF_CONSTEXPR void activate() noexcept { - assert(top_==0); + assert(top_==0 || *top_!=this); top_ = &tl_slot_ptr(); prev_ = *top_; *top_ = this; } - LEAF_CONSTEXPR void deactivate( bool propagate_errors ) noexcept; + + LEAF_CONSTEXPR void deactivate() noexcept + { + assert(top_!=0 && *top_==this); + *top_ = prev_; + } + + LEAF_CONSTEXPR void propagate() noexcept; using impl::put; using impl::has_value; @@ -296,28 +298,25 @@ namespace boost { namespace leaf { #endif template - LEAF_CONSTEXPR inline void slot::deactivate( bool propagate_errors ) noexcept + LEAF_CONSTEXPR inline void slot::propagate() noexcept { - assert(top_!=0); - if( propagate_errors ) - if( prev_ ) - { - impl & this_ = *this; - impl & that_ = *prev_; - that_ = std::move(this_); - } + assert(top_!=0 && (*top_==prev_ || *top_==this)); + if( prev_ ) + { + impl & this_ = *this; + impl & that_ = *prev_; + that_ = std::move(this_); + } #if LEAF_DIAGNOSTICS - else - { - int c = tl_unexpected_enabled_counter(); - assert(c>=0); - if( c ) - if( int err_id = impl::key() ) - load_unexpected(err_id, std::move(*this).value(err_id)); - } + else + { + int c = tl_unexpected_enabled_counter(); + assert(c>=0); + if( c ) + if( int err_id = impl::key() ) + load_unexpected(err_id, std::move(*this).value(err_id)); + } #endif - *top_ = prev_; - top_ = 0; } template @@ -608,7 +607,8 @@ namespace boost { namespace leaf { public: virtual error_id propagate_captured_errors() noexcept = 0; virtual void activate() noexcept = 0; - virtual void deactivate( bool propagate_errors ) noexcept = 0; + virtual void deactivate() noexcept = 0; + virtual void propagate() noexcept = 0; virtual bool is_active() const noexcept = 0; virtual void print( std::ostream & ) const = 0; error_id captured_id_; @@ -618,77 +618,61 @@ namespace boost { namespace leaf { //////////////////////////////////////////// - enum class on_deactivation - { - propagate, - do_not_propagate, - propagate_if_uncaught_exception - }; - template class context_activator { context_activator( context_activator const & ) = delete; context_activator & operator=( context_activator const & ) = delete; +#if !defined(LEAF_NO_EXCEPTIONS) && LEAF_STD_UNCAUGHT_EXCEPTIONS + int const uncaught_exceptions_; +#endif Ctx * ctx_; - bool const ctx_was_active_; - on_deactivation on_deactivate_; public: - LEAF_CONSTEXPR LEAF_ALWAYS_INLINE context_activator(Ctx & ctx, on_deactivation on_deactivate) noexcept: - ctx_(&ctx), - ctx_was_active_(ctx.is_active()), - on_deactivate_(on_deactivate) + explicit LEAF_CONSTEXPR LEAF_ALWAYS_INLINE context_activator(Ctx & ctx) noexcept: +#if !defined(LEAF_NO_EXCEPTIONS) && LEAF_STD_UNCAUGHT_EXCEPTIONS + uncaught_exceptions_(std::uncaught_exceptions()), +#endif + ctx_(ctx.is_active() ? 0 : &ctx) { - if( !ctx_was_active_ ) - ctx.activate(); + if( ctx_ ) + ctx_->activate(); } LEAF_CONSTEXPR LEAF_ALWAYS_INLINE context_activator( context_activator && x ) noexcept: - ctx_(x.ctx_), - ctx_was_active_(x.ctx_was_active_), - on_deactivate_(x.on_deactivate_) +#if !defined(LEAF_NO_EXCEPTIONS) && LEAF_STD_UNCAUGHT_EXCEPTIONS + uncaught_exceptions_(x.uncaught_exceptions_), +#endif + ctx_(x.ctx_) { x.ctx_ = 0; } LEAF_ALWAYS_INLINE ~context_activator() noexcept { - if( ctx_ ) - { - assert( - on_deactivate_ == on_deactivation::propagate || - on_deactivate_ == on_deactivation::do_not_propagate || - on_deactivate_ == on_deactivation::propagate_if_uncaught_exception); - if( !ctx_was_active_ ) - if( on_deactivate_ == on_deactivation::propagate_if_uncaught_exception ) - { -#ifdef LEAF_NO_EXCEPTIONS - ctx_->deactivate(false); -#else - bool has_exception = LEAF_UNCAUGHT_EXCEPTIONS(); - ctx_->deactivate(has_exception); - if( !has_exception ) - (void) leaf_detail::new_id(); + if( !ctx_ ) + return; + if( ctx_->is_active() ) + ctx_->deactivate(); +#ifndef LEAF_NO_EXCEPTIONS +# if LEAF_STD_UNCAUGHT_EXCEPTIONS + if( std::uncaught_exceptions() > uncaught_exceptions_ ) +# else + if( std::uncaught_exception() ) +# endif + ctx_->propagate(); + else + (void) leaf_detail::new_id(); #endif - } - else - ctx_->deactivate(on_deactivate_ == on_deactivation::propagate); - } - } - - LEAF_CONSTEXPR LEAF_ALWAYS_INLINE void set_on_deactivate( on_deactivation on_deactivate ) noexcept - { - on_deactivate_ = on_deactivate; } }; template - LEAF_CONSTEXPR LEAF_ALWAYS_INLINE context_activator activate_context( Ctx & ctx, on_deactivation on_deactivate ) noexcept + LEAF_CONSTEXPR LEAF_ALWAYS_INLINE context_activator activate_context(Ctx & ctx) noexcept { - return context_activator(ctx, on_deactivate); + return context_activator(ctx); } //////////////////////////////////////////// diff --git a/include/boost/leaf/exception.hpp b/include/boost/leaf/exception.hpp index afe1aef..d3b5179 100644 --- a/include/boost/leaf/exception.hpp +++ b/include/boost/leaf/exception.hpp @@ -55,7 +55,7 @@ namespace boost { namespace leaf { { public: - virtual error_id get_error_id() const = 0; + virtual error_id get_error_id() const noexcept = 0; protected: @@ -69,7 +69,7 @@ namespace boost { namespace leaf { public exception_base, public error_id { - error_id get_error_id() const final override + error_id get_error_id() const noexcept final override { return *this; } diff --git a/include/boost/leaf/handle_error.hpp b/include/boost/leaf/handle_error.hpp index f79c1ae..9f88722 100644 --- a/include/boost/leaf/handle_error.hpp +++ b/include/boost/leaf/handle_error.hpp @@ -16,32 +16,62 @@ namespace boost { namespace leaf { template LEAF_CONSTEXPR LEAF_ALWAYS_INLINE typename std::decay()().value())>::type nocatch_context::try_handle_all( TryBlock && try_block, H && ... h ) { - auto active_context = activate_context(*this, on_deactivation::do_not_propagate); - return this->try_handle_all_( std::forward(try_block), std::forward(h)... ); + using namespace leaf_detail; + static_assert(is_result_type()())>::value, "The return type of the try_block passed to a try_handle_all function must be registered with leaf::is_result_type"); + auto active_context = activate_context(*this); + if( auto r = std::forward(try_block)() ) + return r.value(); + else + return this->handle_all_(r, std::forward(h)...); } template template LEAF_CONSTEXPR LEAF_ALWAYS_INLINE typename std::decay()().value())>::type nocatch_context::remote_try_handle_all( TryBlock && try_block, RemoteH && h ) { - auto active_context = activate_context(*this, on_deactivation::do_not_propagate); - return this->remote_try_handle_all_( std::forward(try_block), std::forward(h) ); + using namespace leaf_detail; + static_assert(is_result_type()())>::value, "The return type of the try_block passed to a remote_try_handle_all function must be registered with leaf::is_result_type"); + auto active_context = activate_context(*this); + if( auto r = std::forward(try_block)() ) + return r.value(); + else + return this->remote_handle_all_(r, std::forward(h)); } template template LEAF_CONSTEXPR LEAF_ALWAYS_INLINE typename std::decay()())>::type nocatch_context::try_handle_some( TryBlock && try_block, H && ... h ) { - auto active_context = activate_context(*this, on_deactivation::propagate_if_uncaught_exception); - return this->try_handle_some_( active_context, std::forward(try_block), std::forward(h)... ); + using namespace leaf_detail; + static_assert(is_result_type()())>::value, "The return type of the try_block passed to a try_handle_some function must be registered with leaf::is_result_type"); + auto active_context = activate_context(*this); + if( auto r = std::forward(try_block)() ) + return r; + else + { + auto rr = this->handle_some_(std::move(r), std::forward(h)...); + if( !rr ) + this->propagate(); + return rr; + } } template template LEAF_CONSTEXPR LEAF_ALWAYS_INLINE typename std::decay()())>::type nocatch_context::remote_try_handle_some( TryBlock && try_block, RemoteH && h ) { - auto active_context = activate_context(*this, on_deactivation::propagate_if_uncaught_exception); - return this->remote_try_handle_some_( active_context, std::forward(try_block), std::forward(h) ); + using namespace leaf_detail; + static_assert(is_result_type()())>::value, "The return type of the try_block passed to a remote_try_handle_some function must be registered with leaf::is_result_type"); + auto active_context = activate_context(*this); + if( auto r = std::forward(try_block)() ) + return r; + else + { + auto rr = remote_handle_some_(std::move(r), std::forward(h)); + if( !rr ) + this->propagate(); + return rr; + } } } diff --git a/include/boost/leaf/handle_exception.hpp b/include/boost/leaf/handle_exception.hpp index b289045..e23ddec 100644 --- a/include/boost/leaf/handle_exception.hpp +++ b/include/boost/leaf/handle_exception.hpp @@ -119,49 +119,23 @@ namespace boost { namespace leaf { //////////////////////////////////////// - template - LEAF_CONSTEXPR inline decltype(std::declval()()) try_catch( TryBlock && try_block, H && ... h ) - { - using namespace leaf_detail; - context_type_from_handlers ctx; - auto active_context = activate_context(ctx, on_deactivation::propagate_if_uncaught_exception); - return ctx.try_catch_( - [&] - { - return std::forward(try_block)(); - }, - std::forward(h)...); - } - - template - LEAF_CONSTEXPR inline decltype(std::declval()()) remote_try_catch( TryBlock && try_block, RemoteH && h ) - { - using namespace leaf_detail; - context_type_from_remote_handler ctx; - auto active_context = activate_context(ctx, on_deactivation::propagate_if_uncaught_exception); - return ctx.remote_try_catch_( - [&] - { - return std::forward(try_block)(); - }, - std::forward(h)); - } - namespace leaf_detail { template template - LEAF_CONSTEXPR inline R context_base::handle_current_exception( H && ... h ) const + LEAF_CONSTEXPR inline R context_base::handle_current_exception_( H && ... h ) { + assert(is_active()); return this->try_catch_( - []{ throw; }, + []() -> R { throw; }, std::forward(h)...); } template template - LEAF_CONSTEXPR inline R context_base::remote_handle_current_exception( RemoteH && h ) const + LEAF_CONSTEXPR inline R context_base::remote_handle_current_exception_( RemoteH && h ) { + assert(is_active()); return this->remote_try_catch_( []() -> R { throw; }, std::forward(h)); @@ -169,22 +143,56 @@ namespace boost { namespace leaf { template template - LEAF_CONSTEXPR inline R context_base::handle_exception( std::exception_ptr const & ep, H && ... h ) const + LEAF_CONSTEXPR inline R context_base::handle_exception_( std::exception_ptr const & ep, H && ... h ) { + assert(is_active()); return this->try_catch_( - [&]{ std::rethrow_exception(ep); }, + [&]() -> R { std::rethrow_exception(ep); }, std::forward(h)...); } template template - LEAF_CONSTEXPR inline R context_base::remote_handle_exception( std::exception_ptr const & ep, RemoteH && h ) const + LEAF_CONSTEXPR inline R context_base::remote_handle_exception_( std::exception_ptr const & ep, RemoteH && h ) { + assert(is_active()); return this->remote_try_catch_( [&]() -> R { std::rethrow_exception(ep); }, std::forward(h)); } + template + template + LEAF_CONSTEXPR inline R context_base::handle_current_exception( H && ... h ) + { + auto active_context = activate_context(*this); + return handle_current_exception_(std::forward(h)...); + } + + template + template + LEAF_CONSTEXPR inline R context_base::remote_handle_current_exception( RemoteH && h ) + { + auto active_context = activate_context(*this); + return remote_handle_current_exception_(std::forward(h)); + } + + template + template + LEAF_CONSTEXPR inline R context_base::handle_exception( std::exception_ptr const & ep, H && ... h ) + { + auto active_context = activate_context(*this); + return handle_exception_(ep, std::forward(h)...); + } + + template + template + LEAF_CONSTEXPR inline R context_base::remote_handle_exception( std::exception_ptr const & ep, RemoteH && h ) + { + auto active_context = activate_context(*this); + return remote_handle_exception_(ep, std::forward(h)); + } + //////////////////////////////////////// template @@ -193,7 +201,7 @@ namespace boost { namespace leaf { { using namespace leaf_detail; static_assert(is_result_type()())>::value, "The return type of the try_block passed to a try_handle_all function must be registered with leaf::is_result_type"); - auto active_context = activate_context(*this, on_deactivation::propagate_if_uncaught_exception); + auto active_context = activate_context(*this); if( auto r = this->try_catch_( [&] { @@ -211,7 +219,7 @@ namespace boost { namespace leaf { { using namespace leaf_detail; static_assert(is_result_type()())>::value, "The return type of the try_block passed to a try_handle_all function must be registered with leaf::is_result_type"); - auto active_context = activate_context(*this, on_deactivation::propagate_if_uncaught_exception); + auto active_context = activate_context(*this); if( auto r = this->remote_try_catch_( [&] { @@ -229,7 +237,7 @@ namespace boost { namespace leaf { { using namespace leaf_detail; static_assert(is_result_type()())>::value, "The return type of the try_block passed to a try_handle_some function must be registered with leaf::is_result_type"); - auto active_context = activate_context(*this, on_deactivation::propagate_if_uncaught_exception); + auto active_context = activate_context(*this); if( auto r = this->try_catch_( [&] { @@ -241,7 +249,7 @@ namespace boost { namespace leaf { { auto rr = this->handle_some(std::move(r), std::forward(h)...); if( !rr ) - active_context.set_on_deactivate(on_deactivation::propagate); + this->propagate(); return rr; } } @@ -250,7 +258,9 @@ namespace boost { namespace leaf { template LEAF_CONSTEXPR inline typename std::decay()())>::type catch_context::remote_try_handle_some( TryBlock && try_block, RemoteH && h ) { - auto active_context = activate_context(*this, on_deactivation::propagate_if_uncaught_exception); + using namespace leaf_detail; + static_assert(is_result_type()())>::value, "The return type of the try_block passed to a remote_try_handle_some function must be registered with leaf::is_result_type"); + auto active_context = activate_context(*this); if( auto r = this->remote_try_catch_( [&] { @@ -262,7 +272,7 @@ namespace boost { namespace leaf { { auto rr = this->remote_handle_some(std::move(r), std::forward(h)); if( !rr ) - active_context.set_on_deactivate(on_deactivation::propagate); + this->propagate(); return rr; } } @@ -288,9 +298,10 @@ namespace boost { namespace leaf { template template - inline decltype(std::declval()()) context_base::try_catch_( TryBlock && try_block, H && ... h ) const + inline decltype(std::declval()()) context_base::try_catch_( TryBlock && try_block, H && ... h ) { using namespace leaf_detail; + assert(is_active()); using R = decltype(std::declval()()); try { @@ -304,22 +315,26 @@ namespace boost { namespace leaf { } catch( std::exception const & ex ) { + deactivate(); return leaf_detail::handle_error_(this->tup(), error_info(exception_info_(&ex)), std::forward(h)..., []() -> R { throw; } ); } catch(...) { + deactivate(); return leaf_detail::handle_error_(this->tup(), error_info(exception_info_(0)), std::forward(h)..., []() -> R { throw; } ); } } catch( std::exception const & ex ) { + deactivate(); return leaf_detail::handle_error_(this->tup(), error_info(exception_info_(&ex)), std::forward(h)..., []() -> R { throw; } ); } catch(...) { + deactivate(); return leaf_detail::handle_error_(this->tup(), error_info(exception_info_(0)), std::forward(h)..., []() -> R { throw; } ); } @@ -327,9 +342,10 @@ namespace boost { namespace leaf { template template - inline decltype(std::declval()()) context_base::remote_try_catch_( TryBlock && try_block, RemoteH && h ) const + inline decltype(std::declval()()) context_base::remote_try_catch_( TryBlock && try_block, RemoteH && h ) { using namespace leaf_detail; + assert(is_active()); try { return std::forward(try_block)(); @@ -342,19 +358,23 @@ namespace boost { namespace leaf { } catch( std::exception const & ex ) { + deactivate(); return std::forward(h)(error_info(exception_info_(&ex), this)).get(); } catch(...) { + deactivate(); return std::forward(h)(error_info(exception_info_(0), this)).get(); } } catch( std::exception const & ex ) { + deactivate(); return std::forward(h)(error_info(exception_info_(&ex), this)).get(); } catch(...) { + deactivate(); return std::forward(h)(error_info(exception_info_(0), this)).get(); } } @@ -436,6 +456,36 @@ namespace boost { namespace leaf { { } + //////////////////////////////////////// + + template + LEAF_CONSTEXPR inline decltype(std::declval()()) try_catch( TryBlock && try_block, H && ... h ) + { + using namespace leaf_detail; + context_type_from_handlers ctx; + auto active_context = activate_context(ctx); + return ctx.try_catch_( + [&] + { + return std::forward(try_block)(); + }, + std::forward(h)...); + } + + template + LEAF_CONSTEXPR inline decltype(std::declval()()) remote_try_catch( TryBlock && try_block, RemoteH && h ) + { + using namespace leaf_detail; + context_type_from_remote_handler ctx; + auto active_context = activate_context(ctx); + return ctx.remote_try_catch_( + [&] + { + return std::forward(try_block)(); + }, + std::forward(h)); + } + } } #endif diff --git a/include/boost/leaf/preload.hpp b/include/boost/leaf/preload.hpp index 6d683ce..2189576 100644 --- a/include/boost/leaf/preload.hpp +++ b/include/boost/leaf/preload.hpp @@ -29,7 +29,11 @@ namespace boost { namespace leaf { else { #ifndef LEAF_NO_EXCEPTIONS - if( LEAF_UNCAUGHT_EXCEPTIONS() ) +# if LEAF_STD_UNCAUGHT_EXCEPTIONS + if( std::uncaught_exceptions() ) +# else + if( std::uncaught_exception() ) +# endif return leaf_detail::new_id(); #endif return 0; diff --git a/meson.build b/meson.build index ba5b61d..a5563b9 100644 --- a/meson.build +++ b/meson.build @@ -78,6 +78,9 @@ tests = [ 'context_activator_test', 'context_deduction_test', 'capture_result_unload_test', + 'ctx_handle_all_test', + 'ctx_handle_exception_test', + 'ctx_handle_some_test', 'ctx_remote_handle_all_test', 'ctx_remote_handle_exception_test', 'ctx_remote_handle_some_test', @@ -127,8 +130,9 @@ tests = [ '_hpp_result_test', '_hpp_all_test', ] +ubsan_args = [ '-fsanitize=undefined', '-fno-sanitize-recover=undefined' ] foreach t : tests - test(t, executable(t, 'test/'+t+'.cpp', dependencies: [leaf,thread_dep]+mp11 ) ) + test(t, executable(t, 'test/'+t+'.cpp', dependencies: [leaf,thread_dep]+mp11, cpp_args: ubsan_args, link_args: ubsan_args) ) endforeach if exceptions diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index bd88925..f9209cc 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -45,6 +45,9 @@ run capture_exception_unload_test.cpp ; run capture_result_async_test.cpp ; run capture_result_state_test.cpp ; run capture_result_unload_test.cpp ; +run ctx_handle_all_test.cpp ; +run ctx_handle_exception_test.cpp ; +run ctx_handle_some_test.cpp ; run ctx_remote_handle_all_test.cpp ; run ctx_remote_handle_exception_test.cpp ; run ctx_remote_handle_some_test.cpp ; diff --git a/test/capture_exception_state_test.cpp b/test/capture_exception_state_test.cpp index 7ff25ab..6748cff 100644 --- a/test/capture_exception_state_test.cpp +++ b/test/capture_exception_state_test.cpp @@ -55,6 +55,11 @@ int main() return leaf::remote_handle_exception( err, []( info<1>, info<3> ) { + return 1; + }, + [] + { + return 2; } ); }; BOOST_TEST_EQ(count, 0); @@ -74,8 +79,8 @@ int main() ep = std::current_exception(); } BOOST_TEST_EQ(count, 2); - leaf::remote_try_catch( - [&] + int r = leaf::remote_try_catch( + [&]() -> int { std::rethrow_exception(ep); }, @@ -83,6 +88,7 @@ int main() { return error_handler(err); } ); + BOOST_TEST_EQ(r, 1); ep = std::exception_ptr(); BOOST_TEST_EQ(count, 0); return boost::report_errors(); diff --git a/test/context_activator_test.cpp b/test/context_activator_test.cpp index 111a660..054c3cf 100644 --- a/test/context_activator_test.cpp +++ b/test/context_activator_test.cpp @@ -19,7 +19,7 @@ struct info template leaf::result f( Ctx & ctx ) { - auto active_context = activate_context(ctx, leaf::on_deactivation::do_not_propagate); + auto active_context = activate_context(ctx); return leaf::new_error( info<1>{1} ); } @@ -43,8 +43,10 @@ int main() [&] { auto ctx = leaf::make_context(&handle_error); - auto active_context = activate_context(ctx, leaf::on_deactivation::propagate); - return f(ctx); + auto active_context = activate_context(ctx); + auto r = f(ctx); + ctx.propagate(); + return r; }, [&]( leaf::error_info const & error ) { diff --git a/test/ctx_handle_all_test.cpp b/test/ctx_handle_all_test.cpp new file mode 100644 index 0000000..a19883b --- /dev/null +++ b/test/ctx_handle_all_test.cpp @@ -0,0 +1,51 @@ +// Copyright (c) 2018-2019 Emil Dotchevski and Reverge Studios, Inc. + +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include "lightweight_test.hpp" +#include + +namespace leaf = boost::leaf; + +template +struct info +{ + int value; +}; + +template +leaf::result f( Ctx & ctx ) +{ + auto active_context = activate_context(ctx); + return leaf::new_error( info<1>{1} ); +} + +int main() +{ + leaf::context, leaf::verbose_diagnostic_info const &> ctx; + + { + leaf::result r1 = f(ctx); + BOOST_TEST(!r1); + + int r2 = ctx.handle_all( + r1, + []( info<1> x ) + { + BOOST_TEST(x.value==1); + return 1; + }, + []( leaf::verbose_diagnostic_info const & info ) + { + std::cout << info; + return 2; + } ); + BOOST_TEST_EQ(r2, 1); + } + + return boost::report_errors(); +} diff --git a/test/ctx_handle_exception_test.cpp b/test/ctx_handle_exception_test.cpp new file mode 100644 index 0000000..3ea4384 --- /dev/null +++ b/test/ctx_handle_exception_test.cpp @@ -0,0 +1,143 @@ +// Copyright (c) 2018-2019 Emil Dotchevski and Reverge Studios, Inc. + +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#ifdef LEAF_NO_EXCEPTIONS + +#include + +int main() +{ + std::cout << "Unit test not applicable." << std::endl; + return 0; +} + +#else + +#include +#include +#include "lightweight_test.hpp" + +namespace leaf = boost::leaf; + +template +struct info +{ + int value; +}; + +template +void f( Ctx & ctx ) +{ + auto active_context = activate_context(ctx); + throw leaf::exception(std::exception(), info<1>{1}); +} + +int main() +{ + { + using Ctx = leaf::context, info<1>>; + + { + Ctx ctx; + try + { + f(ctx); + } + catch(...) + { + int r = ctx.handle_current_exception( + []( leaf::catch_, info<1> x ) + { + BOOST_TEST(x.value==1); + return 1; + }, + [] + { + return 2; + } ); + BOOST_TEST_EQ(r, 1); + } + } + + { + Ctx ctx; + try + { + f(ctx); + } + catch(...) + { + int r = ctx.handle_exception( + std::current_exception(), + []( leaf::catch_, info<1> x ) + { + BOOST_TEST(x.value==1); + return 1; + }, + [] + { + return 2; + } ); + BOOST_TEST_EQ(r, 1); + } + } + } + + { + using Ctx = leaf::context, info<1>>; + + { + Ctx ctx; + try + { + f(ctx); + } + catch(...) + { + int r = 0; + ctx.handle_current_exception( + [&]( leaf::catch_, info<1> x ) + { + BOOST_TEST(x.value==1); + r = 1; + }, + [&] + { + r = 2; + } ); + BOOST_TEST_EQ(r, 1); + } + } + + { + Ctx ctx; + try + { + f(ctx); + } + catch(...) + { + int r = 0; + ctx.handle_exception( + std::current_exception(), + [&]( leaf::catch_, info<1> x ) + { + BOOST_TEST(x.value==1); + r = 1; + }, + [&] + { + r = 2; + } ); + BOOST_TEST_EQ(r, 1); + } + } + } + + return boost::report_errors(); +} + +#endif diff --git a/test/ctx_handle_some_test.cpp b/test/ctx_handle_some_test.cpp new file mode 100644 index 0000000..2ebcce9 --- /dev/null +++ b/test/ctx_handle_some_test.cpp @@ -0,0 +1,49 @@ +// Copyright (c) 2018-2019 Emil Dotchevski and Reverge Studios, Inc. + +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include "lightweight_test.hpp" + +namespace leaf = boost::leaf; + +template +struct info +{ + int value; +}; + +template +leaf::result f( Ctx & ctx ) +{ + auto active_context = activate_context(ctx); + return leaf::new_error( info<1>{1} ); +} + +int main() +{ + leaf::context> ctx; + + { + leaf::result r1 = f(ctx); + BOOST_TEST(!r1); + + leaf::result r2 = ctx.handle_some( + std::move(r1), + []( info<1> x ) -> leaf::result + { + BOOST_TEST(x.value==1); + return 1; + }, + [] + { + return 2; + } ); + BOOST_TEST_EQ(r2.value(), 1); + } + + return boost::report_errors(); +} diff --git a/test/ctx_remote_handle_all_test.cpp b/test/ctx_remote_handle_all_test.cpp index e253f28..148e10e 100644 --- a/test/ctx_remote_handle_all_test.cpp +++ b/test/ctx_remote_handle_all_test.cpp @@ -20,7 +20,7 @@ struct info template leaf::result f( Ctx & ctx ) { - auto active_context = activate_context(ctx, leaf::on_deactivation::do_not_propagate); + auto active_context = activate_context(ctx); return leaf::new_error( info<1>{1} ); } diff --git a/test/ctx_remote_handle_exception_test.cpp b/test/ctx_remote_handle_exception_test.cpp index c1ff02c..8f6dbbb 100644 --- a/test/ctx_remote_handle_exception_test.cpp +++ b/test/ctx_remote_handle_exception_test.cpp @@ -31,7 +31,7 @@ struct info template void f( Ctx & ctx ) { - auto active_context = activate_context(ctx, leaf::on_deactivation::do_not_propagate); + auto active_context = activate_context(ctx); throw leaf::exception(std::exception(), info<1>{1}); } diff --git a/test/ctx_remote_handle_some_test.cpp b/test/ctx_remote_handle_some_test.cpp index 99a5feb..ffe3a3d 100644 --- a/test/ctx_remote_handle_some_test.cpp +++ b/test/ctx_remote_handle_some_test.cpp @@ -19,7 +19,7 @@ struct info template leaf::result f( Ctx & ctx ) { - auto active_context = activate_context(ctx, leaf::on_deactivation::do_not_propagate); + auto active_context = activate_context(ctx); return leaf::new_error( info<1>{1} ); } diff --git a/test/handle_basic_test.cpp b/test/handle_basic_test.cpp index 46c7a66..8ffc0dc 100644 --- a/test/handle_basic_test.cpp +++ b/test/handle_basic_test.cpp @@ -13,6 +13,8 @@ namespace leaf = boost::leaf; +struct test_info { int value;}; + enum class error_code { error1=1, @@ -170,5 +172,38 @@ int main() } #endif + /////////////////////////// + + { + int r = leaf::try_handle_all( + []() -> leaf::result + { + return leaf::new_error( test_info{42} ); + }, + []( test_info const & x ) + { + BOOST_TEST_EQ(x.value, 42); + int r = leaf::try_handle_all( + []() -> leaf::result + { + return leaf::new_error( test_info{43} ); + }, + []() + { + return -1; + } ); + BOOST_TEST_EQ(r, -1); + BOOST_TEST_EQ(x.value, 42); + return 0; + }, + []() + { + return -1; + } ); + BOOST_TEST_EQ(r, 0); + } + + /////////////////////////// + return boost::report_errors(); } diff --git a/test/result_state_test.cpp b/test/result_state_test.cpp index 26d6a4c..4237911 100644 --- a/test/result_state_test.cpp +++ b/test/result_state_test.cpp @@ -246,7 +246,7 @@ int main() { // error move -> move context_type ctx; - auto active_context = activate_context(ctx, leaf::on_deactivation::do_not_propagate); + auto active_context = activate_context(ctx); leaf::result r1 = leaf::new_error( e_err { } ); BOOST_TEST(!r1); BOOST_TEST_EQ(err::count, 1); @@ -261,7 +261,7 @@ int main() BOOST_TEST_EQ(val::count, 0); { // error copy -> move context_type ctx; - auto active_context = activate_context(ctx, leaf::on_deactivation::propagate); + auto active_context = activate_context(ctx); leaf::error_id err = leaf::new_error( e_err{ } ); leaf::result r1 = err; BOOST_TEST(!r1); @@ -278,7 +278,7 @@ int main() { // error move -> assign move context_type ctx; - auto active_context = activate_context(ctx, leaf::on_deactivation::propagate); + auto active_context = activate_context(ctx); leaf::result r1 = leaf::new_error( e_err { } ); BOOST_TEST(!r1); BOOST_TEST_EQ(err::count, 1); @@ -299,7 +299,7 @@ int main() BOOST_TEST_EQ(val::count, 0); { // error copy -> assign move context_type ctx; - auto active_context = activate_context(ctx, leaf::on_deactivation::propagate); + auto active_context = activate_context(ctx); leaf::error_id err = leaf::new_error( e_err{ } ); leaf::result r1 = err; BOOST_TEST(!r1); @@ -411,7 +411,7 @@ int main() { // void error move -> move context_type ctx; - auto active_context = activate_context(ctx, leaf::on_deactivation::do_not_propagate); + auto active_context = activate_context(ctx); leaf::result r1 = leaf::new_error( e_err { } ); BOOST_TEST(!r1); BOOST_TEST_EQ(err::count, 1); @@ -424,7 +424,7 @@ int main() BOOST_TEST_EQ(err::count, 0); { // void error copy -> move context_type ctx; - auto active_context = activate_context(ctx, leaf::on_deactivation::propagate); + auto active_context = activate_context(ctx); leaf::error_id err = leaf::new_error( e_err{ } ); leaf::result r1 = err; BOOST_TEST(!r1); @@ -439,7 +439,7 @@ int main() { // void error move -> assign move context_type ctx; - auto active_context = activate_context(ctx, leaf::on_deactivation::propagate); + auto active_context = activate_context(ctx); leaf::result r1 = leaf::new_error( e_err { } ); BOOST_TEST(!r1); BOOST_TEST_EQ(err::count, 1); @@ -454,7 +454,7 @@ int main() BOOST_TEST_EQ(err::count, 0); { // void error copy -> assign move context_type ctx; - auto active_context = activate_context(ctx, leaf::on_deactivation::propagate); + auto active_context = activate_context(ctx); leaf::error_id err = leaf::new_error( e_err{ } ); leaf::result r1 = err; BOOST_TEST(!r1);