https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124651

--- Comment #5 from Heiko Eißfeldt <heiko at hexco dot de> ---
Also I changed function pass_warn_recursion::find_function_exit() as suggested
(i think), but that did not help with the ICE.

Here is my rewrite which searchs until a recursion is found:
```
/* Return true if there is path from BB to M_FUNC exit point along which
   there is no (recursive) call to M_FUNC.  */

bool
pass_warn_recursion::find_function_exit (basic_block bb_start)
{
  // work item list of BB's
  auto_vec<basic_block, 1> bbs;
  bbs.safe_push(bb_start);

  for (const auto &bb : bbs)
    {

      if (!bitmap_set_bit (m_visited, bb->index))
        return false;
      if (bb == EXIT_BLOCK_PTR_FOR_FN (m_func))
        return true;

      /* Iterate over statements in BB, looking for a call to FNDECL.  */
      for (auto si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next_nondebug
(&si))
        {
          gimple *stmt = gsi_stmt (si);
          if (!is_gimple_call (stmt))
            continue;

          if (gimple_call_builtin_p (stmt, BUILT_IN_LONGJMP))
            /* A longjmp breaks infinite recursion.  */
            break;

          if (tree fndecl = gimple_call_fndecl (stmt))
            {
              /* A throw statement breaks infinite recursion.  */
              tree id = DECL_NAME (fndecl);
              const char *name = IDENTIFIER_POINTER (id);
              if (startswith (name, "__cxa_throw"))
                break;
              /* As does a call to POSIX siglongjmp.  */
              if (!strcmp (name, "siglongjmp"))
                break;

              if (m_built_in
                  && gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)
                  && m_built_in == DECL_FUNCTION_CODE (fndecl))
                {
                  const char *cname
                    = IDENTIFIER_POINTER (DECL_NAME (current_function_decl));
                  /* Don't warn about gnu_inline extern inline function
                       like strcpy calling __builtin_strcpy, that is fine,
                       if some call is made (the builtin isn't expanded
inline),
                       a call is made to the external definition.  */
                  if (!(DECL_DECLARED_INLINE_P (current_function_decl)
                      && DECL_EXTERNAL (current_function_decl))
                      || strcmp (name, cname) == 0)
                    {
                      /* The call is being made from the definition of a
built-in
                        (e.g., in a replacement of one) to itself.  */
                      m_calls->safe_push (stmt);
                      return false;
                    }
                }
            }

          if (noreturn_p)
            {
              /* A noreturn call breaks infinite recursion.  */
              int flags = gimple_call_flags (stmt);
              if (flags & ECF_NORETURN)
                break;
            }

          tree callee = gimple_call_fndecl (stmt);
          if (!callee || m_func->decl != callee)
            continue;

          /* Add the recursive call to the vector and return false.  */
          m_calls->safe_push (stmt);
          return false;
        }

        /* If no call to FNDECL has been found search all BB's successors.  */
        /* Add more BB's to check for on demand. */
        edge e;
        edge_iterator ei;

        FOR_EACH_EDGE (e, ei, bb->succs)
          bbs.safe_push (e->dest);
    }

  return true;
}
```


and the diff
```
diff --git a/gcc/gimple-warn-recursion.cc b/gcc/gimple-warn-recursion.cc
index 67ce192142d..e61548f5c56 100644
--- a/gcc/gimple-warn-recursion.cc
+++ b/gcc/gimple-warn-recursion.cc
@@ -82,83 +82,91 @@ pass_warn_recursion::pass_warn_recursion (gcc::context
*ctxt)
    there is no (recursive) call to M_FUNC.  */

 bool
-pass_warn_recursion::find_function_exit (basic_block bb)
+pass_warn_recursion::find_function_exit (basic_block bb_start)
 {
-  if (!bitmap_set_bit (m_visited, bb->index))
-    return false;
+  // work item list of BB's
+  auto_vec<basic_block, 1> bbs;
+  bbs.safe_push(bb_start);

-  if (bb == EXIT_BLOCK_PTR_FOR_FN (m_func))
-    return true;
-
-  /* Iterate over statements in BB, looking for a call to FNDECL.  */
-  for (auto si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next_nondebug (&si))
+  for (const auto &bb : bbs)
     {
-      gimple *stmt = gsi_stmt (si);
-      if (!is_gimple_call (stmt))
-       continue;

-      if (gimple_call_builtin_p (stmt, BUILT_IN_LONGJMP))
-       /* A longjmp breaks infinite recursion.  */
+      if (!bitmap_set_bit (m_visited, bb->index))
+       return false;
+      if (bb == EXIT_BLOCK_PTR_FOR_FN (m_func))
        return true;

-      if (tree fndecl = gimple_call_fndecl (stmt))
+      /* Iterate over statements in BB, looking for a call to FNDECL.  */
+      for (auto si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next_nondebug
(&si))
        {
-         /* A throw statement breaks infinite recursion.  */
-         tree id = DECL_NAME (fndecl);
-         const char *name = IDENTIFIER_POINTER (id);
-         if (startswith (name, "__cxa_throw"))
-           return true;
-         /* As does a call to POSIX siglongjmp.  */
-         if (!strcmp (name, "siglongjmp"))
-           return true;
-
-         if (m_built_in
-             && gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)
-             && m_built_in == DECL_FUNCTION_CODE (fndecl))
+         gimple *stmt = gsi_stmt (si);
+         if (!is_gimple_call (stmt))
+           continue;
+
+         if (gimple_call_builtin_p (stmt, BUILT_IN_LONGJMP))
+           /* A longjmp breaks infinite recursion.  */
+           break;
+
+         if (tree fndecl = gimple_call_fndecl (stmt))
            {
-             const char *cname
-               = IDENTIFIER_POINTER (DECL_NAME (current_function_decl));
-             /* Don't warn about gnu_inline extern inline function
-                like strcpy calling __builtin_strcpy, that is fine,
-                if some call is made (the builtin isn't expanded inline),
-                a call is made to the external definition.  */
-             if (!(DECL_DECLARED_INLINE_P (current_function_decl)
-                   && DECL_EXTERNAL (current_function_decl))
-                 || strcmp (name, cname) == 0)
+             /* A throw statement breaks infinite recursion.  */
+             tree id = DECL_NAME (fndecl);
+             const char *name = IDENTIFIER_POINTER (id);
+             if (startswith (name, "__cxa_throw"))
+               break;
+             /* As does a call to POSIX siglongjmp.  */
+             if (!strcmp (name, "siglongjmp"))
+               break;
+
+             if (m_built_in
+                 && gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)
+                 && m_built_in == DECL_FUNCTION_CODE (fndecl))
                {
-                 /* The call is being made from the definition of a built-in
-                    (e.g., in a replacement of one) to itself.  */
-                 m_calls->safe_push (stmt);
-                 return false;
+                 const char *cname
+                   = IDENTIFIER_POINTER (DECL_NAME (current_function_decl));
+                 /* Don't warn about gnu_inline extern inline function
+                      like strcpy calling __builtin_strcpy, that is fine,
+                      if some call is made (the builtin isn't expanded
inline),
+                      a call is made to the external definition.  */
+                 if (!(DECL_DECLARED_INLINE_P (current_function_decl)
+                     && DECL_EXTERNAL (current_function_decl))
+                     || strcmp (name, cname) == 0)
+                   {
+                     /* The call is being made from the definition of a
built-in
+                       (e.g., in a replacement of one) to itself.  */
+                     m_calls->safe_push (stmt);
+                     return false;
+                   }
                }
            }
-       }

-      if (noreturn_p)
-       {
-         /* A noreturn call breaks infinite recursion.  */
-         int flags = gimple_call_flags (stmt);
-         if (flags & ECF_NORETURN)
-           return true;
+         if (noreturn_p)
+           {
+             /* A noreturn call breaks infinite recursion.  */
+             int flags = gimple_call_flags (stmt);
+             if (flags & ECF_NORETURN)
+               break;
+           }
+
+         tree callee = gimple_call_fndecl (stmt);
+         if (!callee || m_func->decl != callee)
+           continue;
+
+         /* Add the recursive call to the vector and return false.  */
+         m_calls->safe_push (stmt);
+         return false;
        }

-      tree callee = gimple_call_fndecl (stmt);
-      if (!callee || m_func->decl != callee)
-       continue;
+       /* If no call to FNDECL has been found search all BB's successors.  */
+       /* Add more BB's to check for on demand. */
+       edge e;
+       edge_iterator ei;

-      /* Add the recursive call to the vector and return false.  */
-      m_calls->safe_push (stmt);
-      return false;
+       FOR_EACH_EDGE (e, ei, bb->succs)
+         bbs.safe_push (e->dest);
     }

-  /* If no call to FNDECL has been found search all BB's successors.  */
-  edge e;
-  edge_iterator ei;
-  FOR_EACH_EDGE (e, ei, bb->succs)
-    if (find_function_exit (e->dest))
-      return true;
-
-  return false;
+  return true;
 }

```

Reply via email to