aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimple-warn-recursion.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/gimple-warn-recursion.c')
-rw-r--r--gcc/gimple-warn-recursion.c202
1 files changed, 0 insertions, 202 deletions
diff --git a/gcc/gimple-warn-recursion.c b/gcc/gimple-warn-recursion.c
deleted file mode 100644
index 3a50d5e..0000000
--- a/gcc/gimple-warn-recursion.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/* -Winfinite-recursion support.
- Copyright (C) 2021-2022 Free Software Foundation, Inc.
- Contributed by Martin Sebor <msebor@redhat.com>
-
- This file is part of GCC.
-
- GCC is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your option)
- any later version.
-
- GCC is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GCC; see the file COPYING3. If not see
- <http://www.gnu.org/licenses/>. */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "backend.h"
-#include "tree.h"
-#include "gimple.h"
-#include "tree-pass.h"
-#include "ssa.h"
-#include "diagnostic-core.h"
-// #include "tree-dfa.h"
-#include "attribs.h"
-#include "gimple-iterator.h"
-
-namespace {
-
-const pass_data warn_recursion_data =
-{
- GIMPLE_PASS, /* type */
- "*infinite-recursion", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- TV_NONE, /* tv_id */
- PROP_ssa, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0, /* todo_flags_finish */
-};
-
-class pass_warn_recursion : public gimple_opt_pass
-{
-public:
- pass_warn_recursion (gcc::context *);
-
-private:
- virtual bool gate (function *) { return warn_infinite_recursion; }
-
- virtual unsigned int execute (function *);
-
- bool find_function_exit (basic_block);
-
- /* Recursive calls found in M_FUNC. */
- vec<gimple *> *m_calls;
- /* Basic blocks already visited in the current function. */
- bitmap m_visited;
- /* The current function. */
- function *m_func;
- /* The current function code if it's (also) a built-in. */
- built_in_function m_built_in;
- /* True if M_FUNC is a noreturn function. */
- bool noreturn_p;
-};
-
-/* Initialize the pass and its members. */
-
-pass_warn_recursion::pass_warn_recursion (gcc::context *ctxt)
- : gimple_opt_pass (warn_recursion_data, ctxt),
- m_calls (), m_visited (), m_func (), m_built_in (), noreturn_p ()
-{
-}
-
-/* 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)
-{
- 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. */
- return true;
-
- 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"))
- 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))
- {
- /* 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;
- }
-
- 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. */
- edge e;
- edge_iterator ei;
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (find_function_exit (e->dest))
- return true;
-
- return false;
-}
-
-
-/* Search FUNC for unconditionally infinitely recursive calls to self
- and issue a warning if it is such a function. */
-
-unsigned int
-pass_warn_recursion::execute (function *func)
-{
- auto_bitmap visited;
- auto_vec<gimple *> calls;
-
- m_visited = visited;
- m_calls = &calls;
- m_func = func;
-
- /* Avoid diagnosing an apparently infinitely recursive function that
- doesn't return where the infinite recursion might be avoided by
- a call to another noreturn function. */
- noreturn_p = lookup_attribute ("noreturn", DECL_ATTRIBUTES (m_func->decl));
-
- if (fndecl_built_in_p (m_func->decl, BUILT_IN_NORMAL))
- m_built_in = DECL_FUNCTION_CODE (m_func->decl);
- else
- m_built_in = BUILT_IN_NONE;
-
- basic_block entry_bb = ENTRY_BLOCK_PTR_FOR_FN (func);
-
- if (find_function_exit (entry_bb) || m_calls->length () == 0)
- return 0;
-
- if (warning_at (DECL_SOURCE_LOCATION (func->decl),
- OPT_Winfinite_recursion,
- "infinite recursion detected"))
- for (auto stmt: *m_calls)
- {
- location_t loc = gimple_location (stmt);
- if (loc == UNKNOWN_LOCATION)
- continue;
-
- inform (loc, "recursive call");
- }
-
- return 0;
-}
-
-} // namespace
-
-gimple_opt_pass *
-make_pass_warn_recursion (gcc::context *ctxt)
-{
- return new pass_warn_recursion (ctxt);
-}