[PATCH v2 2/4] libstdc++/regex: Convert DFS executor to use iteration [PR86164]

Patrick Palka ppalka@redhat.com
Wed Jan 21 18:03:53 GMT 2026


This replaces the recursion and implicit call stack usage of the DFS
executor with iteration and an explicit heap-based stack.  After this
patch, we no longer stack overflow on the PR86164 testcases since stack
usage is minimal.  Besides reduced stack usage, this should be a
non-functional change.  Readability rather than optimal heap usage is
emphasized.  There's some low-hanging fruit for optimizing heap usage
that I'll submit as follow-up patches.

Since the signature of _Executor was changed by the previous patch via
the __dfs_mode template parameter removal, and _Executor is an internal
type that users can't name, I believe there's no ABI issues or risks of
mixing old/new version member functions?

	PR libstdc++/86164

libstdc++-v3/ChangeLog:

	* include/bits/regex_executor.h (__detail::_ExecutorFrame):
	Declare.
	(__detail::_ExecutorFrameVec): Declare.
	(__detail::_Executor::_ExecutorFrame): Declare.
	(__detail::_Executor::_ExecutorFrameVec): Declare.
	(__detail::_Executor): Add _ExecutorFrameVec& parameter to each
	subroutine of _M_dfs.
	(__detail::_Executor::_M_node): Declare.
	(__detail::_Executor::_M_dfs): Remove __start parameter.
	* include/bits/regex_executor.tcc (__detail::_ExecutorFrameOpcode):
	New.
	(__detail::_ExecutorFrame): New.
	(__detail::_Executor::_M_main_dispatch): Adjust _M_dfs call
	after _StateId parameter removal.
	(__detail::_Executor::_M_rep_once_more): Add _ExecutorFrame&
	parameter.  Replace recursive _M_dfs calls with a _S_opcode_next
	frame push, and any tail work after such calls with an
	appropriate frame push.
	(__detail::_M_handle_repeat): Likewise.
	(__detail::_M_handle_subexpr_begin): Likewise.
	(__detail::_M_handle_subexpr_end): Likewise.
	(__detail::_M_handle_line_begin_assertion): Likewise.
	(__detail::_M_handle_line_end_assertion): Likewise.
	(__detail::_M_handle_word_boundary): Likewise.
	(__detail::_M_handle_subexpr_lookahead): Likewise.
	(__detail::_M_handle_match): Likewise.
	(__detail::_M_handle_backref): Likewise.
	(__detail::_M_handle_accept): Likewise.
	(__detail::_M_handle_alternative): Likewise.
	(__detail::_M_node): Factored out from _M_dfs.
	(__detail::_M_dfs): Remove _StateIdT parameter.  Create an
	_ExecutorFrameVec stack with an initial frame that visits the
	starting node and pass this stack each subroutine.  Pop the
	latest _ExecutorFrame from the stack and handle appropriately
	according to its _ExecutorFrameOpcode.  Loop until the stack
	is empty.
---
 libstdc++-v3/include/bits/regex_executor.h   |  38 ++-
 libstdc++-v3/include/bits/regex_executor.tcc | 281 ++++++++++++++-----
 2 files changed, 230 insertions(+), 89 deletions(-)

diff --git a/libstdc++-v3/include/bits/regex_executor.h b/libstdc++-v3/include/bits/regex_executor.h
index 0c3f7f9050b0..a51018fd0134 100644
--- a/libstdc++-v3/include/bits/regex_executor.h
+++ b/libstdc++-v3/include/bits/regex_executor.h
@@ -41,6 +41,12 @@ namespace __detail
    * @{
    */
 
+  template<typename _BiIter, bool _Trivial = is_trivially_copyable<_BiIter>::value>
+    struct _ExecutorFrame;
+
+  template<typename _BiIter>
+    using _ExecutorFrameVec = _GLIBCXX_STD_C::vector<_ExecutorFrame<_BiIter>>;
+
   /**
    * @brief Takes a regex and an input string and does the matching.
    */
@@ -98,44 +104,50 @@ namespace __detail
       _M_search();
 
     private:
+      using _ExecutorFrame = __detail::_ExecutorFrame<_BiIter>;
+      using _ExecutorFrameVec = __detail::_ExecutorFrameVec<_BiIter>;
+
+      void
+      _M_rep_once_more(_Match_mode, _StateIdT, _ExecutorFrameVec&);
+
       void
-      _M_rep_once_more(_Match_mode __match_mode, _StateIdT);
+      _M_handle_repeat(_Match_mode, _StateIdT, _ExecutorFrameVec&);
 
       void
-      _M_handle_repeat(_Match_mode, _StateIdT);
+      _M_handle_subexpr_begin(_Match_mode, _StateIdT, _ExecutorFrameVec&);
 
       void
-      _M_handle_subexpr_begin(_Match_mode, _StateIdT);
+      _M_handle_subexpr_end(_Match_mode, _StateIdT, _ExecutorFrameVec&);
 
       void
-      _M_handle_subexpr_end(_Match_mode, _StateIdT);
+      _M_handle_line_begin_assertion(_Match_mode, _StateIdT, _ExecutorFrameVec&);
 
       void
-      _M_handle_line_begin_assertion(_Match_mode, _StateIdT);
+      _M_handle_line_end_assertion(_Match_mode, _StateIdT, _ExecutorFrameVec&);
 
       void
-      _M_handle_line_end_assertion(_Match_mode, _StateIdT);
+      _M_handle_word_boundary(_Match_mode, _StateIdT, _ExecutorFrameVec&);
 
       void
-      _M_handle_word_boundary(_Match_mode, _StateIdT);
+      _M_handle_subexpr_lookahead(_Match_mode, _StateIdT, _ExecutorFrameVec&);
 
       void
-      _M_handle_subexpr_lookahead(_Match_mode, _StateIdT);
+      _M_handle_match(_Match_mode, _StateIdT, _ExecutorFrameVec&);
 
       void
-      _M_handle_match(_Match_mode, _StateIdT);
+      _M_handle_backref(_Match_mode, _StateIdT, _ExecutorFrameVec&);
 
       void
-      _M_handle_backref(_Match_mode, _StateIdT);
+      _M_handle_accept(_Match_mode, _StateIdT, _ExecutorFrameVec&);
 
       void
-      _M_handle_accept(_Match_mode, _StateIdT);
+      _M_handle_alternative(_Match_mode, _StateIdT, _ExecutorFrameVec&);
 
       void
-      _M_handle_alternative(_Match_mode, _StateIdT);
+      _M_node(_Match_mode, _StateIdT, _ExecutorFrameVec&);
 
       void
-      _M_dfs(_Match_mode __match_mode, _StateIdT __start);
+      _M_dfs(_Match_mode);
 
       bool
       _M_main(_Match_mode __match_mode)
diff --git a/libstdc++-v3/include/bits/regex_executor.tcc b/libstdc++-v3/include/bits/regex_executor.tcc
index 58d5a2bfec3a..0e78cb2e2c87 100644
--- a/libstdc++-v3/include/bits/regex_executor.tcc
+++ b/libstdc++-v3/include/bits/regex_executor.tcc
@@ -54,15 +54,72 @@ namespace __detail
       return false;
     }
 
-  // The _M_main function operates in different modes, DFS mode or BFS mode,
-  // indicated by template parameter __dfs_mode, and dispatches to one of the
-  // _M_main_dispatch overloads.
-  //
-  // ------------------------------------------------------------
-  //
-  // DFS mode:
-  //
-  // It applies a Depth-First-Search (aka backtracking) on given NFA and input
+  enum _ExecutorFrameOpcode : unsigned char
+  {
+    _S_fopcode_next,
+    _S_fopcode_fallback_next,
+    _S_fopcode_rep_once_more,
+    _S_fopcode_fallback_rep_once_more,
+    _S_fopcode_posix_alternative,
+    _S_fopcode_merge_sol,
+    _S_fopcode_restore_current,
+    _S_fopcode_restore_subexpr_begin,
+    _S_fopcode_restore_subexpr_end,
+    _S_fopcode_restore_rep_count_pos,
+    _S_fopcode_restore_rep_count_val,
+    _S_fopcode_decrement_rep_count,
+  };
+
+  template<typename _BiIter, bool _Trivial /* = is_trivially_copyable<_BiIter>::value */>
+    struct _ExecutorFrame
+    {
+      _ExecutorFrame(_ExecutorFrameOpcode __op, _StateIdT __i)
+      : _M_op(__op), _M_state_id(__i)
+      { }
+
+      _ExecutorFrame(_ExecutorFrameOpcode __op, _StateIdT __i, _BiIter __p)
+      : _M_op(__op), _M_state_id(__i), _M_pos(__p)
+      { }
+
+      _ExecutorFrame(_ExecutorFrameOpcode __op, _StateIdT __i, long __v)
+      : _M_op(__op), _M_state_id(__i), _M_val(__v)
+      { }
+
+      _ExecutorFrameOpcode _M_op;
+      _StateIdT _M_state_id;
+      // _M_pos and _M_val are mutually exclusive, which is more obvious
+      // in the optimized partial specialization below.
+      _BiIter _M_pos = _BiIter();
+      long _M_val = 0;
+    };
+
+  // Space-optimized partial specialization for when the input iterator is
+  // trivially copyable.
+  template<typename _BiIter>
+    struct _ExecutorFrame<_BiIter, true>
+    {
+      _ExecutorFrame(_ExecutorFrameOpcode __op, _StateIdT __i)
+      : _M_op(__op), _M_state_id(__i)
+      { }
+
+      _ExecutorFrame(_ExecutorFrameOpcode __op, _StateIdT __i, _BiIter __p)
+      : _M_op(__op), _M_state_id(__i), _M_pos(__p)
+      { }
+
+      _ExecutorFrame(_ExecutorFrameOpcode __op, _StateIdT __i, long __v)
+      : _M_op(__op), _M_state_id(__i), _M_val(__v)
+      { }
+
+      _ExecutorFrameOpcode _M_op;
+      _StateIdT _M_state_id;
+      union
+      {
+	_BiIter _M_pos;
+	long _M_val;
+      };
+    };
+
+  // Apply a Depth-First-Search (aka backtracking) on given NFA and input
   // string.
   // At the very beginning the executor stands in the start state, then it
   // tries every possible state transition in current state recursively. Some
@@ -84,7 +141,7 @@ namespace __detail
       _M_has_sol = false;
       *_M_states._M_get_sol_pos() = _BiIter();
       _M_cur_results = _M_results;
-      _M_dfs(__match_mode, _M_states._M_start);
+      _M_dfs(__match_mode);
       return _M_has_sol;
     }
 
@@ -117,25 +174,28 @@ namespace __detail
   // we need to spare one more time for potential group capture.
   template<typename _BiIter, typename _Alloc, typename _TraitsT>
     void _Executor<_BiIter, _Alloc, _TraitsT>::
-    _M_rep_once_more(_Match_mode __match_mode, _StateIdT __i)
+    _M_rep_once_more(_Match_mode, _StateIdT __i,
+		     _ExecutorFrameVec& __frames)
     {
       const auto& __state = _M_nfa[__i];
       auto& __rep_count = _M_rep_count[__i];
       if (__rep_count.second == 0 || __rep_count.first != _M_current)
 	{
-	  auto __back = __rep_count;
+	  __frames.emplace_back(_S_fopcode_restore_rep_count_val,
+				__i, __rep_count.second);
+	  __frames.emplace_back(_S_fopcode_restore_rep_count_pos,
+				__i, __rep_count.first);
 	  __rep_count.first = _M_current;
 	  __rep_count.second = 1;
-	  _M_dfs(__match_mode, __state._M_alt);
-	  __rep_count = __back;
+	  __frames.emplace_back(_S_fopcode_next, __state._M_alt);
 	}
       else
 	{
 	  if (__rep_count.second < 2)
 	    {
 	      __rep_count.second++;
-	      _M_dfs(__match_mode, __state._M_alt);
-	      __rep_count.second--;
+	      __frames.emplace_back(_S_fopcode_decrement_rep_count, __i);
+	      __frames.emplace_back(_S_fopcode_next, __state._M_alt);
 	    }
 	}
     }
@@ -146,105 +206,105 @@ namespace __detail
   // given greedy mode.
   template<typename _BiIter, typename _Alloc, typename _TraitsT>
     void _Executor<_BiIter, _Alloc, _TraitsT>::
-    _M_handle_repeat(_Match_mode __match_mode, _StateIdT __i)
+    _M_handle_repeat(_Match_mode, _StateIdT __i,
+		     _ExecutorFrameVec& __frames)
     {
       const auto& __state = _M_nfa[__i];
-
       // Greedy.
       if (!__state._M_neg)
 	{
-	  _M_rep_once_more(__match_mode, __i);
-	  // If we already accepted, we're done.
-	  if (!_M_has_sol)
-	    _M_dfs(__match_mode, __state._M_next);
+	  __frames.emplace_back(_S_fopcode_fallback_next, __state._M_next);
+	  __frames.emplace_back(_S_fopcode_rep_once_more, __i);
 	}
       else // Non-greedy mode
 	{
-	  // vice-versa.
-	  _M_dfs(__match_mode, __state._M_next);
-	  if (!_M_has_sol)
-	    _M_rep_once_more(__match_mode, __i);
+	  __frames.emplace_back(_S_fopcode_fallback_rep_once_more, __i);
+	  __frames.emplace_back(_S_fopcode_next, __state._M_next);
 	}
     }
 
   template<typename _BiIter, typename _Alloc, typename _TraitsT>
     void _Executor<_BiIter, _Alloc, _TraitsT>::
-    _M_handle_subexpr_begin(_Match_mode __match_mode, _StateIdT __i)
+    _M_handle_subexpr_begin(_Match_mode, _StateIdT __i,
+			    _ExecutorFrameVec& __frames)
     {
       const auto& __state = _M_nfa[__i];
-
       auto& __res = _M_cur_results[__state._M_subexpr];
-      auto __back = __res.first;
+      __frames.emplace_back(_S_fopcode_restore_subexpr_begin,
+			    __state._M_subexpr, __res.first);
       __res.first = _M_current;
-      _M_dfs(__match_mode, __state._M_next);
-      __res.first = __back;
+      __frames.emplace_back(_S_fopcode_next, __state._M_next);
     }
 
   template<typename _BiIter, typename _Alloc, typename _TraitsT>
     void _Executor<_BiIter, _Alloc, _TraitsT>::
-    _M_handle_subexpr_end(_Match_mode __match_mode, _StateIdT __i)
+    _M_handle_subexpr_end(_Match_mode, _StateIdT __i,
+			  _ExecutorFrameVec& __frames)
     {
       const auto& __state = _M_nfa[__i];
-
       auto& __res = _M_cur_results[__state._M_subexpr];
-      auto __back = __res;
+      __frames.emplace_back(_S_fopcode_restore_subexpr_end,
+			    __state._M_subexpr, __res.second);
       __res.second = _M_current;
       __res.matched = true;
-      _M_dfs(__match_mode, __state._M_next);
-      __res = __back;
+      __frames.emplace_back(_S_fopcode_next, __state._M_next);
     }
 
   template<typename _BiIter, typename _Alloc, typename _TraitsT>
     inline void _Executor<_BiIter, _Alloc, _TraitsT>::
-    _M_handle_line_begin_assertion(_Match_mode __match_mode, _StateIdT __i)
+    _M_handle_line_begin_assertion(_Match_mode, _StateIdT __i,
+				   _ExecutorFrameVec& __frames)
     {
       const auto& __state = _M_nfa[__i];
       if (_M_at_begin())
-	_M_dfs(__match_mode, __state._M_next);
+	__frames.emplace_back(_S_fopcode_next, __state._M_next);
     }
 
   template<typename _BiIter, typename _Alloc, typename _TraitsT>
     inline void _Executor<_BiIter, _Alloc, _TraitsT>::
-    _M_handle_line_end_assertion(_Match_mode __match_mode, _StateIdT __i)
+    _M_handle_line_end_assertion(_Match_mode, _StateIdT __i,
+				 _ExecutorFrameVec& __frames)
     {
       const auto& __state = _M_nfa[__i];
       if (_M_at_end())
-	_M_dfs(__match_mode, __state._M_next);
+	__frames.emplace_back(_S_fopcode_next, __state._M_next);
     }
 
   template<typename _BiIter, typename _Alloc, typename _TraitsT>
     inline void _Executor<_BiIter, _Alloc, _TraitsT>::
-    _M_handle_word_boundary(_Match_mode __match_mode, _StateIdT __i)
+    _M_handle_word_boundary(_Match_mode, _StateIdT __i,
+			    _ExecutorFrameVec& __frames)
     {
       const auto& __state = _M_nfa[__i];
       if (_M_word_boundary() == !__state._M_neg)
-	_M_dfs(__match_mode, __state._M_next);
+	__frames.emplace_back(_S_fopcode_next, __state._M_next);
     }
 
   // 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>
     void _Executor<_BiIter, _Alloc, _TraitsT>::
-    _M_handle_subexpr_lookahead(_Match_mode __match_mode, _StateIdT __i)
+    _M_handle_subexpr_lookahead(_Match_mode, _StateIdT __i,
+				_ExecutorFrameVec& __frames)
     {
       const auto& __state = _M_nfa[__i];
       if (_M_lookahead(__state._M_alt) == !__state._M_neg)
-	_M_dfs(__match_mode, __state._M_next);
+	__frames.emplace_back(_S_fopcode_next, __state._M_next);
     }
 
   template<typename _BiIter, typename _Alloc, typename _TraitsT>
     void _Executor<_BiIter, _Alloc, _TraitsT>::
-    _M_handle_match(_Match_mode __match_mode, _StateIdT __i)
+    _M_handle_match(_Match_mode, _StateIdT __i,
+		    _ExecutorFrameVec& __frames)
     {
       const auto& __state = _M_nfa[__i];
-
       if (_M_current == _M_end)
 	return;
       if (__state._M_matches(*_M_current))
 	{
+	  __frames.emplace_back(_S_fopcode_restore_current, 0, _M_current);
 	  ++_M_current;
-	  _M_dfs(__match_mode, __state._M_next);
-	  --_M_current;
+	  __frames.emplace_back(_S_fopcode_next, __state._M_next);
 	}
     }
 
@@ -302,7 +362,8 @@ namespace __detail
   // If matched, keep going; else just return and try another state.
   template<typename _BiIter, typename _Alloc, typename _TraitsT>
     void _Executor<_BiIter, _Alloc, _TraitsT>::
-    _M_handle_backref(_Match_mode __match_mode, _StateIdT __i)
+    _M_handle_backref(_Match_mode, _StateIdT __i,
+		      _ExecutorFrameVec& __frames)
     {
       const auto& __state = _M_nfa[__i];
       auto& __submatch = _M_cur_results[__state._M_backref_index];
@@ -320,19 +381,19 @@ namespace __detail
 	{
 	  if (__last != _M_current)
 	    {
-	      auto __backup = _M_current;
+	      __frames.emplace_back(_S_fopcode_restore_current, 0, _M_current);
 	      _M_current = __last;
-	      _M_dfs(__match_mode, __state._M_next);
-	      _M_current = __backup;
+	      __frames.emplace_back(_S_fopcode_next, __state._M_next);
 	    }
 	  else
-	    _M_dfs(__match_mode, __state._M_next);
+	    __frames.emplace_back(_S_fopcode_next, __state._M_next);
 	}
     }
 
   template<typename _BiIter, typename _Alloc, typename _TraitsT>
     void _Executor<_BiIter, _Alloc, _TraitsT>::
-    _M_handle_accept(_Match_mode __match_mode, _StateIdT)
+    _M_handle_accept(_Match_mode __match_mode, _StateIdT,
+		     _ExecutorFrameVec&)
     {
       __glibcxx_assert(!_M_has_sol);
       if (__match_mode == _Match_mode::_Exact)
@@ -370,63 +431,131 @@ namespace __detail
 
   template<typename _BiIter, typename _Alloc, typename _TraitsT>
     void _Executor<_BiIter, _Alloc, _TraitsT>::
-    _M_handle_alternative(_Match_mode __match_mode, _StateIdT __i)
+    _M_handle_alternative(_Match_mode, _StateIdT __i,
+			  _ExecutorFrameVec& __frames)
     {
       const auto& __state = _M_nfa[__i];
-
       if (_M_nfa._M_flags & regex_constants::ECMAScript)
 	{
-	  _M_dfs(__match_mode, __state._M_alt);
 	  // Pick lhs if it matches. Only try rhs if it doesn't.
-	  if (!_M_has_sol)
-	    _M_dfs(__match_mode, __state._M_next);
+	  __frames.emplace_back(_S_fopcode_fallback_next, __state._M_next);
+	  __frames.emplace_back(_S_fopcode_next, __state._M_alt);
 	}
       else
 	{
 	  // Try both and compare the result.
 	  // See "case _S_opcode_accept:" handling above.
-	  _M_dfs(__match_mode, __state._M_alt);
-	  auto __has_sol = _M_has_sol;
-	  _M_has_sol = false;
-	  _M_dfs(__match_mode, __state._M_next);
-	  _M_has_sol |= __has_sol;
+	  __frames.emplace_back(_S_fopcode_posix_alternative, __state._M_next);
+	  __frames.emplace_back(_S_fopcode_next, __state._M_alt);
 	}
     }
 
   template<typename _BiIter, typename _Alloc, typename _TraitsT>
     void _Executor<_BiIter, _Alloc, _TraitsT>::
-    _M_dfs(_Match_mode __match_mode, _StateIdT __i)
+    _M_node(_Match_mode __match_mode, _StateIdT __i,
+	    _ExecutorFrameVec& __frames)
     {
       switch (_M_nfa[__i]._M_opcode())
 	{
 	case _S_opcode_repeat:
-	  _M_handle_repeat(__match_mode, __i); break;
+	  _M_handle_repeat(__match_mode, __i, __frames); break;
 	case _S_opcode_subexpr_begin:
-	  _M_handle_subexpr_begin(__match_mode, __i); break;
+	  _M_handle_subexpr_begin(__match_mode, __i, __frames); break;
 	case _S_opcode_subexpr_end:
-	  _M_handle_subexpr_end(__match_mode, __i); break;
+	  _M_handle_subexpr_end(__match_mode, __i, __frames); break;
 	case _S_opcode_line_begin_assertion:
-	  _M_handle_line_begin_assertion(__match_mode, __i); break;
+	  _M_handle_line_begin_assertion(__match_mode, __i, __frames); break;
 	case _S_opcode_line_end_assertion:
-	  _M_handle_line_end_assertion(__match_mode, __i); break;
+	  _M_handle_line_end_assertion(__match_mode, __i, __frames); break;
 	case _S_opcode_word_boundary:
-	  _M_handle_word_boundary(__match_mode, __i); break;
+	  _M_handle_word_boundary(__match_mode, __i, __frames); break;
 	case _S_opcode_subexpr_lookahead:
-	  _M_handle_subexpr_lookahead(__match_mode, __i); break;
+	  _M_handle_subexpr_lookahead(__match_mode, __i, __frames); break;
 	case _S_opcode_match:
-	  _M_handle_match(__match_mode, __i); break;
+	  _M_handle_match(__match_mode, __i, __frames); break;
 	case _S_opcode_backref:
-	  _M_handle_backref(__match_mode, __i);
+	  _M_handle_backref(__match_mode, __i, __frames);
 	  break;
 	case _S_opcode_accept:
-	  _M_handle_accept(__match_mode, __i); break;
+	  _M_handle_accept(__match_mode, __i, __frames); break;
 	case _S_opcode_alternative:
-	  _M_handle_alternative(__match_mode, __i); break;
+	  _M_handle_alternative(__match_mode, __i, __frames); break;
 	default:
 	  __glibcxx_assert(false);
 	}
     }
 
+  template<typename _BiIter, typename _Alloc, typename _TraitsT>
+    void _Executor<_BiIter, _Alloc, _TraitsT>::
+    _M_dfs(_Match_mode __match_mode)
+    {
+      _ExecutorFrameVec __frames;
+      __frames.emplace_back(_S_fopcode_next, _M_states._M_start);
+
+      while (!__frames.empty())
+	{
+	  _ExecutorFrame __frame = std::move(__frames.back());
+	  __frames.pop_back();
+
+	  switch (__frame._M_op)
+	    {
+	    case _S_fopcode_next:
+	      _M_node(__match_mode, __frame._M_state_id, __frames);
+	      break;
+
+	    case _S_fopcode_fallback_next:
+	      if (!_M_has_sol)
+		__frames.emplace_back(_S_fopcode_next, __frame._M_state_id);
+	      break;
+
+	    case _S_fopcode_fallback_rep_once_more:
+	      if (!_M_has_sol)
+		__frames.emplace_back(_S_fopcode_rep_once_more,
+				      __frame._M_state_id);
+	      break;
+
+	    case _S_fopcode_rep_once_more:
+	      _M_rep_once_more(__match_mode, __frame._M_state_id, __frames);
+	      break;
+
+	    case _S_fopcode_posix_alternative:
+	      __frames.emplace_back(_S_fopcode_merge_sol, 0, _M_has_sol);
+	      __frames.emplace_back(_S_fopcode_next, __frame._M_state_id);
+	      _M_has_sol = false;
+	      break;
+
+	    case _S_fopcode_merge_sol:
+	      _M_has_sol |= __frame._M_val;
+	      break;
+
+	    case _S_fopcode_restore_current:
+	      _M_current = __frame._M_pos;
+	      break;
+
+	    case _S_fopcode_restore_subexpr_begin:
+	      _M_cur_results[__frame._M_state_id].first = __frame._M_pos;
+	      break;
+
+	    case _S_fopcode_restore_subexpr_end:
+	      _M_cur_results[__frame._M_state_id].second = __frame._M_pos;
+	      _M_cur_results[__frame._M_state_id].matched = true;
+	      break;
+
+	    case _S_fopcode_restore_rep_count_pos:
+	      _M_rep_count[__frame._M_state_id].first = __frame._M_pos;
+	      break;
+
+	    case _S_fopcode_restore_rep_count_val:
+	      _M_rep_count[__frame._M_state_id].second = __frame._M_val;
+	      break;
+
+	    case _S_fopcode_decrement_rep_count:
+	      _M_rep_count[__frame._M_state_id].second--;
+	      break;
+	    }
+	}
+    }
+
   // Return whether now is at some word boundary.
   template<typename _BiIter, typename _Alloc, typename _TraitsT>
     bool _Executor<_BiIter, _Alloc, _TraitsT>::
-- 
2.53.0.rc0.25.gb5c409c40f



More information about the Libstdc++ mailing list