diff --git a/doc/Changelog.md b/doc/Changelog.md index 7d2bf53c6..17d39a901 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -2,7 +2,7 @@ ## 3.2.6 -Released 2022-??-?? +Released 2022-06-29 * Made `unwind()` optional for parse tree nodes. * Fixed `demangle()` for MSVC, again. diff --git a/include/tao/pegtl/internal/unwind_guard.hpp b/include/tao/pegtl/internal/unwind_guard.hpp new file mode 100644 index 000000000..668d8a1b4 --- /dev/null +++ b/include/tao/pegtl/internal/unwind_guard.hpp @@ -0,0 +1,39 @@ +// Copyright (c) 2014-2022 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#ifndef TAO_PEGTL_INTERNAL_UNWIND_GUARD_HPP +#define TAO_PEGTL_INTERNAL_UNWIND_GUARD_HPP + +#include "../config.hpp" + +#include +#include + +namespace TAO_PEGTL_NAMESPACE::internal +{ + template< typename Unwind > + struct unwind_guard + { + explicit unwind_guard( Unwind&& unwind_impl ) + : unwind( std::move( unwind_impl ) ) + {} + + ~unwind_guard() + { + if( unwind ) { + ( *unwind )(); + } + } + + unwind_guard( const unwind_guard& ) = delete; + unwind_guard( unwind_guard&& ) noexcept = delete; + + unwind_guard& operator=( const unwind_guard& ) = delete; + unwind_guard& operator=( unwind_guard&& ) noexcept = delete; + + std::optional< Unwind > unwind; + }; + +} // namespace TAO_PEGTL_NAMESPACE::internal + +#endif diff --git a/include/tao/pegtl/match.hpp b/include/tao/pegtl/match.hpp index b07352d1b..f6904f928 100644 --- a/include/tao/pegtl/match.hpp +++ b/include/tao/pegtl/match.hpp @@ -19,6 +19,7 @@ #include "internal/marker.hpp" #include "internal/missing_apply.hpp" #include "internal/missing_apply0.hpp" +#include "internal/unwind_guard.hpp" #if defined( _MSC_VER ) #pragma warning( push ) @@ -72,13 +73,12 @@ namespace TAO_PEGTL_NAMESPACE { #if defined( __cpp_exceptions ) if constexpr( has_unwind< Control< Rule >, void, const ParseInput&, States... > ) { - try { - return match_no_control< Rule, A, M, Action, Control >( in, st... ); - } - catch( ... ) { + unwind_guard ug( [ & ] { Control< Rule >::unwind( static_cast< const ParseInput& >( in ), st... ); - throw; - } + } ); + const auto result = match_no_control< Rule, A, M, Action, Control >( in, st... ); + ug.unwind.reset(); + return result; } else { return match_no_control< Rule, A, M, Action, Control >( in, st... );