On Mon, 9 Feb 2026 at 15:19, Patrick Palka <[email protected]> wrote:
>
> Changes in v2:
> - Rebased
>
> This patch mechanically removes _Executor's __dfs_mode template
> parameter. In passing we can also get rid of the _V2 inline namespace
> because this change is sufficient to make all of _Executor's member
> function signatures different from the previous (GCC <= 15) recursive
> implementation, so that mixing the two implementations won't conflict.
OK
>
> libstdc++-v3/ChangeLog:
>
> * include/bits/regex.h (_Executor): Remove __dfs_mode template
> parameter and _V2 inline namespace.
> * include/bits/regex.tcc (__regex_algo_impl): Adjust after
> __dfs_mode template parameter removal.
> * include/bits/regex_executor.h (_Executor): Remove __dfs_mode
> parameter and _V2 inline namespace.
> * include/bits/regex_executor.tcc (_Executor): Likewise.
> ---
> libstdc++-v3/include/bits/regex.h | 8 +-
> libstdc++-v3/include/bits/regex.tcc | 2 +-
> libstdc++-v3/include/bits/regex_executor.h | 7 +-
> libstdc++-v3/include/bits/regex_executor.tcc | 97 ++++++++------------
> 4 files changed, 44 insertions(+), 70 deletions(-)
>
> diff --git a/libstdc++-v3/include/bits/regex.h
> b/libstdc++-v3/include/bits/regex.h
> index 5bcb9a447ce2..0e815ca086eb 100644
> --- a/libstdc++-v3/include/bits/regex.h
> +++ b/libstdc++-v3/include/bits/regex.h
> @@ -61,10 +61,8 @@ namespace __detail
> _RegexExecutorPolicy __policy,
> bool __match_mode);
>
> -_GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> - template<typename, typename, typename, bool>
> + template<typename, typename, typename>
> class _Executor;
> -_GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
>
> template<typename _Tp>
> struct __is_contiguous_iter : false_type { };
> @@ -842,7 +840,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
> regex_constants::match_flag_type,
> __detail::_RegexExecutorPolicy, bool);
>
> - template<typename, typename, typename, bool>
> + template<typename, typename, typename>
> friend class __detail::_Executor;
>
> flag_type _M_flags;
> @@ -2136,7 +2134,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>
> /// @cond undocumented
>
> - template<typename, typename, typename, bool>
> + template<typename, typename, typename>
> friend class __detail::_Executor;
>
> template<typename _Bp, typename _Ap, typename _Cp, typename _Rp>
> diff --git a/libstdc++-v3/include/bits/regex.tcc
> b/libstdc++-v3/include/bits/regex.tcc
> index d16cfd5baf01..ca500d21c348 100644
> --- a/libstdc++-v3/include/bits/regex.tcc
> +++ b/libstdc++-v3/include/bits/regex.tcc
> @@ -67,7 +67,7 @@ namespace __detail
> && !__re._M_automaton->_M_has_backref))
> __use_dfs = false;
>
> - _Executor<_BiIter, _Alloc, _TraitsT, true>
> + _Executor<_BiIter, _Alloc, _TraitsT>
> __executor(__s, __e, __res, __re, __flags, __use_dfs);
> if (__match_mode)
> __ret = __executor._M_match();
> diff --git a/libstdc++-v3/include/bits/regex_executor.h
> b/libstdc++-v3/include/bits/regex_executor.h
> index 2638df4d5afb..797ad702784b 100644
> --- a/libstdc++-v3/include/bits/regex_executor.h
> +++ b/libstdc++-v3/include/bits/regex_executor.h
> @@ -36,7 +36,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
> namespace __detail
> {
> -_GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> /**
> * @addtogroup regex-detail
> * @{
> @@ -49,10 +48,9 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> * @brief Takes a regex and an input string and does the matching.
> *
> * The %_Executor class has two modes: DFS mode and BFS mode, controlled
> - * by the template parameter %__dfs_mode.
> + * by the function parameter %__search_mode.
> */
> - template<typename _BiIter, typename _Alloc, typename _TraitsT,
> - bool __dfs_mode>
> + template<typename _BiIter, typename _Alloc, typename _TraitsT>
> class _Executor
> {
> enum class _Search_mode : unsigned char { _BFS = 0, _DFS = 1 };
> @@ -287,7 +285,6 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> };
>
> ///@} regex-detail
> -_GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
> } // namespace __detail
> _GLIBCXX_END_NAMESPACE_VERSION
> } // namespace std
> diff --git a/libstdc++-v3/include/bits/regex_executor.tcc
> b/libstdc++-v3/include/bits/regex_executor.tcc
> index 0ae7bdf6839a..4eda6bdf5531 100644
> --- a/libstdc++-v3/include/bits/regex_executor.tcc
> +++ b/libstdc++-v3/include/bits/regex_executor.tcc
> @@ -36,10 +36,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> #pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr
> namespace __detail
> {
> -_GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> - template<typename _BiIter, typename _Alloc, typename _TraitsT,
> - bool __dfs_mode>
> - bool _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
> + template<typename _BiIter, typename _Alloc, typename _TraitsT>
> + bool _Executor<_BiIter, _Alloc, _TraitsT>::
> _M_search()
> {
> if (_M_search_from_first())
> @@ -160,9 +158,8 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> // Time complexity: \Omega(match_length), O(2^(_M_nfa.size()))
> // Space complexity: \theta(match_results.size() + match_length)
> //
> - template<typename _BiIter, typename _Alloc, typename _TraitsT,
> - bool __dfs_mode>
> - bool _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
> + template<typename _BiIter, typename _Alloc, typename _TraitsT>
> + bool _Executor<_BiIter, _Alloc, _TraitsT>::
> _M_main_dfs(_Match_mode __match_mode)
> {
> _M_has_sol = false;
> @@ -194,9 +191,8 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> // O(match_length * _M_nfa.size() * match_results.size())
> // Space complexity: \Omega(_M_nfa.size() + match_results.size())
> // O(_M_nfa.size() * match_results.size())
> - template<typename _BiIter, typename _Alloc, typename _TraitsT,
> - bool __dfs_mode>
> - bool _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
> + template<typename _BiIter, typename _Alloc, typename _TraitsT>
> + bool _Executor<_BiIter, _Alloc, _TraitsT>::
> _M_main_bfs(_Match_mode __match_mode)
> {
> _M_match_queue.emplace_back(_M_start, _M_results);
> @@ -227,9 +223,8 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> }
>
> // Return whether now match the given sub-NFA.
> - template<typename _BiIter, typename _Alloc, typename _TraitsT,
> - bool __dfs_mode>
> - bool _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
> + template<typename _BiIter, typename _Alloc, typename _TraitsT>
> + bool _Executor<_BiIter, _Alloc, _TraitsT>::
> _M_lookahead(_StateIdT __next)
> {
> // Backreferences may refer to captured content.
> @@ -255,9 +250,8 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> // infinite loop by refusing to continue when it's already been
> // visited more than twice. It's `twice` instead of `once` because
> // we need to spare one more time for potential group capture.
> - template<typename _BiIter, typename _Alloc, typename _TraitsT,
> - bool __dfs_mode>
> - void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
> + template<typename _BiIter, typename _Alloc, typename _TraitsT>
> + void _Executor<_BiIter, _Alloc, _TraitsT>::
> _M_rep_once_more(_Match_mode __match_mode, _StateIdT __i)
> {
> const auto& __state = _M_nfa[__i];
> @@ -286,9 +280,8 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> // of this quantifier". Executing _M_next first or _M_alt first don't
> // mean the same thing, and we need to choose the correct order under
> // given greedy mode.
> - template<typename _BiIter, typename _Alloc, typename _TraitsT,
> - bool __dfs_mode>
> - void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
> + template<typename _BiIter, typename _Alloc, typename _TraitsT>
> + void _Executor<_BiIter, _Alloc, _TraitsT>::
> _M_handle_repeat(_Match_mode __match_mode, _StateIdT __i)
> {
> const auto& __state = _M_nfa[__i];
> @@ -329,9 +322,8 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> }
> }
>
> - template<typename _BiIter, typename _Alloc, typename _TraitsT,
> - bool __dfs_mode>
> - void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
> + template<typename _BiIter, typename _Alloc, typename _TraitsT>
> + void _Executor<_BiIter, _Alloc, _TraitsT>::
> _M_handle_subexpr_begin(_Match_mode __match_mode, _StateIdT __i)
> {
> const auto& __state = _M_nfa[__i];
> @@ -343,9 +335,8 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> _M_frames.emplace_back(_S_fopcode_next, __state._M_next);
> }
>
> - template<typename _BiIter, typename _Alloc, typename _TraitsT,
> - bool __dfs_mode>
> - void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
> + template<typename _BiIter, typename _Alloc, typename _TraitsT>
> + void _Executor<_BiIter, _Alloc, _TraitsT>::
> _M_handle_subexpr_end(_Match_mode __match_mode, _StateIdT __i)
> {
> const auto& __state = _M_nfa[__i];
> @@ -360,9 +351,8 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> _M_frames.emplace_back(_S_fopcode_next, __state._M_next);
> }
>
> - template<typename _BiIter, typename _Alloc, typename _TraitsT,
> - bool __dfs_mode>
> - inline void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
> + template<typename _BiIter, typename _Alloc, typename _TraitsT>
> + inline void _Executor<_BiIter, _Alloc, _TraitsT>::
> _M_handle_line_begin_assertion(_Match_mode __match_mode, _StateIdT __i)
> {
> const auto& __state = _M_nfa[__i];
> @@ -370,9 +360,8 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> _M_frames.emplace_back(_S_fopcode_next, __state._M_next);
> }
>
> - template<typename _BiIter, typename _Alloc, typename _TraitsT,
> - bool __dfs_mode>
> - inline void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
> + template<typename _BiIter, typename _Alloc, typename _TraitsT>
> + inline void _Executor<_BiIter, _Alloc, _TraitsT>::
> _M_handle_line_end_assertion(_Match_mode __match_mode, _StateIdT __i)
> {
> const auto& __state = _M_nfa[__i];
> @@ -380,9 +369,8 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> _M_frames.emplace_back(_S_fopcode_next, __state._M_next);
> }
>
> - template<typename _BiIter, typename _Alloc, typename _TraitsT,
> - bool __dfs_mode>
> - inline void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
> + template<typename _BiIter, typename _Alloc, typename _TraitsT>
> + inline void _Executor<_BiIter, _Alloc, _TraitsT>::
> _M_handle_word_boundary(_Match_mode __match_mode, _StateIdT __i)
> {
> const auto& __state = _M_nfa[__i];
> @@ -392,9 +380,8 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>
> // Here __state._M_alt offers a single start node for a sub-NFA.
> // We recursively invoke our algorithm to match the sub-NFA.
> - template<typename _BiIter, typename _Alloc, typename _TraitsT,
> - bool __dfs_mode>
> - void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
> + template<typename _BiIter, typename _Alloc, typename _TraitsT>
> + void _Executor<_BiIter, _Alloc, _TraitsT>::
> _M_handle_subexpr_lookahead(_Match_mode __match_mode, _StateIdT __i)
> {
> const auto& __state = _M_nfa[__i];
> @@ -402,9 +389,8 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> _M_frames.emplace_back(_S_fopcode_next, __state._M_next);
> }
>
> - template<typename _BiIter, typename _Alloc, typename _TraitsT,
> - bool __dfs_mode>
> - void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
> + template<typename _BiIter, typename _Alloc, typename _TraitsT>
> + void _Executor<_BiIter, _Alloc, _TraitsT>::
> _M_handle_match(_Match_mode __match_mode, _StateIdT __i)
> {
> const auto& __state = _M_nfa[__i];
> @@ -475,9 +461,8 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> // then compare it with
> // (_M_current, _M_current + (__submatch.second - __submatch.first)).
> // If matched, keep going; else just return and try another state.
> - template<typename _BiIter, typename _Alloc, typename _TraitsT,
> - bool __dfs_mode>
> - void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
> + template<typename _BiIter, typename _Alloc, typename _TraitsT>
> + void _Executor<_BiIter, _Alloc, _TraitsT>::
> _M_handle_backref(_Match_mode __match_mode, _StateIdT __i)
> {
> __glibcxx_assert(_M_search_mode == _Search_mode::_DFS);
> @@ -501,9 +486,8 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> }
> }
>
> - template<typename _BiIter, typename _Alloc, typename _TraitsT,
> - bool __dfs_mode>
> - void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
> + template<typename _BiIter, typename _Alloc, typename _TraitsT>
> + void _Executor<_BiIter, _Alloc, _TraitsT>::
> _M_handle_accept(_Match_mode __match_mode, _StateIdT)
> {
> if (_M_search_mode == _Search_mode::_DFS)
> @@ -554,9 +538,8 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> }
> }
>
> - template<typename _BiIter, typename _Alloc, typename _TraitsT,
> - bool __dfs_mode>
> - void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
> + template<typename _BiIter, typename _Alloc, typename _TraitsT>
> + void _Executor<_BiIter, _Alloc, _TraitsT>::
> _M_handle_alternative(_Match_mode __match_mode, _StateIdT __i)
> {
> const auto& __state = _M_nfa[__i];
> @@ -578,12 +561,11 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> }
> }
>
> - template<typename _BiIter, typename _Alloc, typename _TraitsT,
> - bool __dfs_mode>
> + template<typename _BiIter, typename _Alloc, typename _TraitsT>
> #ifdef __OPTIMIZE__
> [[__gnu__::__always_inline__]]
> #endif
> - inline void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
> + inline void _Executor<_BiIter, _Alloc, _TraitsT>::
> _M_node(_Match_mode __match_mode, _StateIdT __i)
> {
> if (_M_visited(__i))
> @@ -622,9 +604,8 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> }
> }
>
> - template<typename _BiIter, typename _Alloc, typename _TraitsT,
> - bool __dummy>
> - void _Executor<_BiIter, _Alloc, _TraitsT, __dummy>::
> + template<typename _BiIter, typename _Alloc, typename _TraitsT>
> + void _Executor<_BiIter, _Alloc, _TraitsT>::
> _M_dfs(_Match_mode __match_mode, _StateIdT __start)
> {
> const bool __dfs_mode = (_M_search_mode == _Search_mode::_DFS);
> @@ -692,9 +673,8 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
> }
>
> // Return whether now is at some word boundary.
> - template<typename _BiIter, typename _Alloc, typename _TraitsT,
> - bool __dfs_mode>
> - bool _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>::
> + template<typename _BiIter, typename _Alloc, typename _TraitsT>
> + bool _Executor<_BiIter, _Alloc, _TraitsT>::
> _M_word_boundary() const
> {
> if (_M_current == _M_begin && (_M_flags &
> regex_constants::match_not_bow))
> @@ -715,7 +695,6 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
>
> return __left_is_word != __right_is_word;
> }
> -_GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
> } // namespace __detail
> #pragma GCC diagnostic pop
>
> --
> 2.53.0.40.g3e0db84c88
>