diff --git a/doc/leaf.adoc b/doc/leaf.adoc index 55272a3..acb6ccd 100644 --- a/doc/leaf.adoc +++ b/doc/leaf.adoc @@ -2350,7 +2350,7 @@ namespace boost { namespace leaf { #define BOOST_LEAF_ASSIGN(v, r)\ auto && <> = r;\ if( !<> )\ - return <>.error();\ + return std::forward>)>(<>).error();\ v = std::forward>)>(<>).value() #define BOOST_LEAF_AUTO(v, r)\ @@ -2362,7 +2362,7 @@ namespace boost { namespace leaf { ({\ auto && <> = (r);\ if( !<> )\ - return <>.error();\ + return std::forward>)>(<>).error();\ std::move(<>);\ }).value() @@ -5571,7 +5571,7 @@ TIP: The contents of each Reference section are organized alphabetically. #define BOOST_LEAF_ASSIGN(v, r)\ auto && <> = r;\ if( !<> )\ - return <>.error();\ + return std::forward>)>(<>).error();\ v = std::forward>)>(<>).value() ---- @@ -5645,7 +5645,7 @@ NOTE: See also <>. ({\ auto && <> = (r);\ if( !<> )\ - return <>.error();\ + return std::forward>)>(<>).error();\ std::move(<>);\ }).value() @@ -5655,7 +5655,7 @@ NOTE: See also <>. {\ auto && <> = (r);\ if( !<> )\ - return <>.error();\ + return std::forward>)>(<>).error();\ } #endif diff --git a/include/boost/leaf/error.hpp b/include/boost/leaf/error.hpp index 77304bf..cd82c93 100644 --- a/include/boost/leaf/error.hpp +++ b/include/boost/leaf/error.hpp @@ -53,7 +53,7 @@ namespace serialization static_assert(::boost::leaf::is_result_type::type>::value,\ "BOOST_LEAF_ASSIGN/BOOST_LEAF_AUTO requires a result object as the second argument (see is_result_type)");\ if( !BOOST_LEAF_TMP )\ - return BOOST_LEAF_TMP.error();\ + return std::forward(BOOST_LEAF_TMP).error();\ v = std::forward(BOOST_LEAF_TMP).value() #define BOOST_LEAF_AUTO(v, r)\ @@ -67,7 +67,7 @@ namespace serialization static_assert(::boost::leaf::is_result_type::type>::value,\ "BOOST_LEAF_CHECK requires a result object (see is_result_type)");\ if( !BOOST_LEAF_TMP )\ - return BOOST_LEAF_TMP.error();\ + return std::forward(BOOST_LEAF_TMP).error();\ std::move(BOOST_LEAF_TMP);\ }).value() @@ -79,7 +79,7 @@ namespace serialization static_assert(::boost::leaf::is_result_type::type>::value,\ "BOOST_LEAF_CHECK requires a result object (see is_result_type)");\ if( !BOOST_LEAF_TMP )\ - return BOOST_LEAF_TMP.error();\ + return std::forward(BOOST_LEAF_TMP).error();\ } #endif // #else (#if BOOST_LEAF_CFG_GNUC_STMTEXPR) diff --git a/test/BOOST_LEAF_ASSIGN_test.cpp b/test/BOOST_LEAF_ASSIGN_test.cpp index 1b974f4..d6101f9 100644 --- a/test/BOOST_LEAF_ASSIGN_test.cpp +++ b/test/BOOST_LEAF_ASSIGN_test.cpp @@ -9,6 +9,7 @@ # include #endif +#include "_test_res.hpp" #include "lightweight_test.hpp" #ifdef BOOST_LEAF_BOOST_AVAILABLE # include @@ -83,5 +84,19 @@ int main() BOOST_TEST_EQ(r, 0); } +#ifndef BOOST_LEAF_NO_CXX11_REF_QUALIFIERS + { + auto r = []() -> test_res + { + int v = 0; + BOOST_LEAF_ASSIGN(v, ([]() -> test_res { return test_error(42); }())); + return v; + }(); + BOOST_TEST(!r); + BOOST_TEST(r.error().moved); + BOOST_TEST_EQ(r.error().value, 42); + } +#endif + return boost::report_errors(); } diff --git a/test/BOOST_LEAF_AUTO_test.cpp b/test/BOOST_LEAF_AUTO_test.cpp index a56dff6..c309e5b 100644 --- a/test/BOOST_LEAF_AUTO_test.cpp +++ b/test/BOOST_LEAF_AUTO_test.cpp @@ -9,6 +9,7 @@ # include #endif +#include "_test_res.hpp" #include "lightweight_test.hpp" #ifdef BOOST_LEAF_BOOST_AVAILABLE # include @@ -95,5 +96,18 @@ int main() BOOST_TEST_EQ(r, 0); } +#ifndef BOOST_LEAF_NO_CXX11_REF_QUALIFIERS + { + auto r = []() -> test_res + { + BOOST_LEAF_AUTO(v, ([]() -> test_res { return test_error(42); }())); + return v; + }(); + BOOST_TEST(!r); + BOOST_TEST(r.error().moved); + BOOST_TEST_EQ(r.error().value, 42); + } +#endif + return boost::report_errors(); } diff --git a/test/BOOST_LEAF_CHECK_test.cpp b/test/BOOST_LEAF_CHECK_test.cpp index e6c4523..5828988 100644 --- a/test/BOOST_LEAF_CHECK_test.cpp +++ b/test/BOOST_LEAF_CHECK_test.cpp @@ -15,6 +15,7 @@ # define BOOST_WORKAROUND(a,b) 0 #endif +#include "_test_res.hpp" #include "lightweight_test.hpp" namespace leaf = boost::leaf; @@ -63,6 +64,24 @@ leaf::result f3( bool success ) return { }; } +#ifndef BOOST_LEAF_NO_CXX11_REF_QUALIFIERS + +test_res f_te( bool succeed ) +{ + if( succeed ) + return 42; + else + return test_error(42); +} + +test_res g_check_te() +{ + BOOST_LEAF_CHECK(f_te(false)); + return 21; +} + +#endif + int main() { BOOST_TEST_EQ(f2(true).value().x, 42); @@ -70,5 +89,14 @@ int main() BOOST_TEST(f3(true)); BOOST_TEST(!f3(false)); +#ifndef BOOST_LEAF_NO_CXX11_REF_QUALIFIERS + { + auto r = g_check_te(); + BOOST_TEST(!r); + BOOST_TEST(r.error().moved); + BOOST_TEST_EQ(r.error().value, 42); + } +#endif + return boost::report_errors(); } diff --git a/test/_test_res.hpp b/test/_test_res.hpp index 26cb3bc..dbc7fd2 100644 --- a/test/_test_res.hpp +++ b/test/_test_res.hpp @@ -6,6 +6,19 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "_test_ec.hpp" +#include + +struct test_error +{ + int value; + bool moved; + test_error() noexcept: value(0), moved(false) {} + explicit test_error(int v) noexcept: value(v), moved(false) {} + test_error(test_error const & o) noexcept: value(o.value), moved(false) {} + test_error(test_error && o) noexcept: value(o.value), moved(true) {} + test_error & operator=(test_error const &) = default; + test_error & operator=(test_error &&) = default; +}; template class test_res @@ -31,6 +44,12 @@ public: which_(variant::error) { } + test_res( E && error ) noexcept: + value_(), + error_(std::move(error)), + which_(variant::error) + { + } template test_res( Enum e, typename std::enable_if::value, Enum>::type * = nullptr ): value_(), @@ -47,11 +66,24 @@ public: BOOST_LEAF_ASSERT(which_ == variant::value); return value_; } +#ifndef BOOST_LEAF_NO_CXX11_REF_QUALIFIERS + E const & error() const & + { + BOOST_LEAF_ASSERT(which_ == variant::error); + return error_; + } + E && error() && + { + BOOST_LEAF_ASSERT(which_ == variant::error); + return std::move(error_); + } +#else E const & error() const { BOOST_LEAF_ASSERT(which_ == variant::error); return error_; } +#endif }; template @@ -75,6 +107,11 @@ public: which_(variant::error) { } + test_res( E && error ) noexcept: + error_(std::move(error)), + which_(variant::error) + { + } template test_res( Enum e, typename std::enable_if::value, Enum>::type * = nullptr ): error_(make_error_code(e)), @@ -89,11 +126,24 @@ public: { BOOST_LEAF_ASSERT(which_ == variant::value); } +#ifndef BOOST_LEAF_NO_CXX11_REF_QUALIFIERS + E const & error() const & + { + BOOST_LEAF_ASSERT(which_ == variant::error); + return error_; + } + E && error() && + { + BOOST_LEAF_ASSERT(which_ == variant::error); + return std::move(error_); + } +#else E const & error() const { BOOST_LEAF_ASSERT(which_ == variant::error); return error_; } +#endif }; namespace boost { namespace leaf {