ericniebler / range-v3

Range library for C++14/17/20, basis for C++20's std::ranges
Other
4.06k stars 437 forks source link

view::join: fix noexcept specifier on functions which may throw (#1753) #1754

Closed luciang closed 1 year ago

luciang commented 1 year ago

Fix for #1753

https://github.com/ericniebler/range-v3/commit/d800a032132512a54c291ce55a2a43e0460591c7 changed this clearly noexcept function

        struct pass_thru_inner_
        {
            // Intentionally promote xvalues to lvalues here:
            template<typename Inner>
            static constexpr Inner & update_inner_(Inner && inner) noexcept
            {
                return inner;
            }

to this which may throw if *inner throws:

        struct pass_thru_inner_
        {
            // Intentionally promote xvalues to lvalues here:
            template<typename OuterIt>
            static constexpr auto && update_inner_(OuterIt && it) noexcept
            {
                return *it;
            }

A simple repro like

    void test_issue_xxx()
    {
        bool exceptionCaught = false;
        try
        {
            int rgi[] = {1};
            rgi | ranges::views::transform([&](int) {
                throw std::exception();
                return std::vector<int>{};
            })                          //
                | ranges::views::cache1 //
                | ranges::views::join   //
                | ranges::to<std::vector>();
        }
        catch(const std::exception &)
        {
            exceptionCaught = true;
        }
        check_equal(exceptionCaught, true);
    }
$ make range.v3.view.join && ctest range.v3.view.join --rerun-failed --output-on-failure
1/1 Test #207: range.v3.test.view.join ..........Subprocess aborted***Exception:   0.16 sec
terminate called after throwing an instance of 'std::exception'
  what():  std::exception

0% tests passed, 1 tests failed out of 1

Total Test time (real) =   0.17 sec

The following tests FAILED:
    207 - range.v3.test.view.join (Subprocess aborted)
Errors while running CTest

This throwing_view | ranges::views::cache1 | ranges::views::join pattern used to work fine before the mentioned commit. I couldn't easily find docs about exception-safety guarantees of cache1/join, but the code looks reasonable so I assume it's "valid".

brevzin commented 1 year ago

Thanks for the PR. This was just fixed by #1752.