PR analyzer/114159 reports an ICE inside playback of call summaries
for very low values of --param=analyzer-max-svalue-depth=VAL.

Root cause is that call_summary_edge_info's ctor tries to evaluate
the function ptr of a gimple call stmt and assumes it gets a function *,
but with low values of --param=analyzer-max-svalue-depth=VAL we get
back an UNKNOWN svalue, rather than a pointer to a specific function.

Fix by adding a new call_info ctor that passes a specific
const function & from the call_summary_edge_info, rather than trying
to compute the function.

In doing so, I noticed that the analyzer was using "function *" despite
not modifying functions, and was sloppy about can-be-null versus
must-be-non-null function pointers, so I "constified" the function, and
converted the many places where the function must be non-null to be
"const function &".

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
Successful run of analyzer integration tests on x86_64-pc-linux-gnu.
Pushed to trunk as r14-9245-gc0d8a64e72324d.

gcc/analyzer/ChangeLog:
        PR analyzer/114159
        * analyzer.cc: Include "tree-dfa.h".
        (get_ssa_default_def): New decl.
        * analyzer.h (get_ssa_default_def): New.
        * call-info.cc (call_info::call_info): New ctor taking an explicit
        called_fn.
        * call-info.h (call_info::call_info): Likewise.
        * call-summary.cc (call_summary_replay::call_summary_replay):
        Convert param from function * to const function &.
        * call-summary.h (call_summary_replay::call_summary_replay):
        Likewise.
        * checker-event.h (state_change_event::get_dest_function):
        Constify return value.
        * engine.cc (point_and_state::validate): Update for conversion to
        const function &.
        (exploded_node::on_stmt): Likewise.
        (call_summary_edge_info::call_summary_edge_info): Likewise.
        Pass in called_fn to call_info ctor.
        (exploded_node::replay_call_summaries): Update for conversion to
        const function &.  Convert per_function_data from * to &.
        (exploded_node::replay_call_summary): Update for conversion to
        const function &.
        (exploded_graph::add_function_entry): Likewise.
        (toplevel_function_p): Likewise.
        (add_tainted_args_callback): Likewise.
        (exploded_graph::build_initial_worklist): Likewise.
        (exploded_graph::maybe_create_dynamic_call): Likewise.
        (maybe_update_for_edge): Likewise.
        (exploded_graph::on_escaped_function): Likewise.
        * exploded-graph.h (exploded_node::replay_call_summaries):
        Likewise.
        (exploded_node::replay_call_summary): Likewise.
        (exploded_graph::add_function_entry): Likewise.
        * program-point.cc (function_point::from_function_entry):
        Likewise.
        (program_point::from_function_entry): Likewise.
        * program-point.h (function_point::from_function_entry): Likewise.
        (program_point::from_function_entry): Likewise.
        * program-state.cc (program_state::push_frame): Likewise.
        (program_state::get_current_function): Constify return type.
        * program-state.h (program_state::push_frame): Update for
        conversion to const function &.
        (program_state::get_current_function): Likewise.
        * region-model-manager.cc
        (region_model_manager::get_frame_region): Likewise.
        * region-model-manager.h
        (region_model_manager::get_frame_region): Likewise.
        * region-model.cc (region_model::called_from_main_p): Likewise.
        (region_model::update_for_gcall): Likewise.
        (region_model::push_frame): Likewise.
        (region_model::get_current_function): Constify return type.
        (region_model::pop_frame): Update for conversion to
        const function &.
        (selftest::test_stack_frames): Likewise.
        (selftest::test_get_representative_path_var): Likewise.
        (selftest::test_state_merging): Likewise.
        (selftest::test_alloca): Likewise.
        * region-model.h (region_model::push_frame): Likewise.
        (region_model::get_current_function): Likewise.
        * region.cc (frame_region::dump_to_pp): Likewise.
        (frame_region::get_region_for_local): Likewise.
        * region.h (class frame_region): Likewise.
        * sm-signal.cc (signal_unsafe_call::describe_state_change):
        Likewise.
        (update_model_for_signal_handler): Likewise.
        (signal_delivery_edge_info_t::update_model): Likewise.
        (register_signal_handler::impl_transition): Likewise.
        * state-purge.cc (class gimple_op_visitor): Likewise.
        (state_purge_map::state_purge_map): Likewise.
        (state_purge_map::get_or_create_data_for_decl): Likewise.
        (state_purge_per_ssa_name::state_purge_per_ssa_name): Likewise.
        (state_purge_per_ssa_name::add_to_worklist): Likewise.
        (state_purge_per_ssa_name::process_point): Likewise.
        (state_purge_per_decl::add_to_worklist): Likewise.
        (state_purge_annotator::print_needed): Likewise.
        * state-purge.h
        (state_purge_map::get_or_create_data_for_decl): Likewise.
        (class state_purge_per_tree): Likewise.
        (class state_purge_per_ssa_name): Likewise.
        (class state_purge_per_decl): Likewise.
        * supergraph.cc (supergraph::dump_dot_to_pp): Likewise.
        * supergraph.h
        (supergraph::get_node_for_function_entry): Likewise.
        (supergraph::get_node_for_function_exit): Likewise.

gcc/ChangeLog:
        PR analyzer/114159
        * function.cc (function_name): Make param const.
        * function.h (function_name): Likewise.

gcc/testsuite/ChangeLog:
        PR analyzer/114159
        * c-c++-common/analyzer/call-summaries-pr114159.c: New test.

Signed-off-by: David Malcolm <dmalc...@redhat.com>
---
 gcc/analyzer/analyzer.cc                      |  9 ++
 gcc/analyzer/analyzer.h                       |  3 +
 gcc/analyzer/call-info.cc                     |  8 ++
 gcc/analyzer/call-info.h                      |  1 +
 gcc/analyzer/call-summary.cc                  |  6 +-
 gcc/analyzer/call-summary.h                   |  2 +-
 gcc/analyzer/checker-event.h                  |  2 +-
 gcc/analyzer/engine.cc                        | 83 ++++++++++---------
 gcc/analyzer/exploded-graph.h                 |  8 +-
 gcc/analyzer/program-point.cc                 |  4 +-
 gcc/analyzer/program-point.h                  |  4 +-
 gcc/analyzer/program-state.cc                 |  4 +-
 gcc/analyzer/program-state.h                  |  4 +-
 gcc/analyzer/region-model-manager.cc          |  2 +-
 gcc/analyzer/region-model-manager.h           |  2 +-
 gcc/analyzer/region-model.cc                  | 42 +++++-----
 gcc/analyzer/region-model.h                   |  4 +-
 gcc/analyzer/region.cc                        | 10 +--
 gcc/analyzer/region.h                         | 18 ++--
 gcc/analyzer/sm-signal.cc                     | 13 +--
 gcc/analyzer/state-purge.cc                   | 29 ++++---
 gcc/analyzer/state-purge.h                    | 15 ++--
 gcc/analyzer/supergraph.cc                    |  5 +-
 gcc/analyzer/supergraph.h                     |  8 +-
 gcc/function.cc                               |  2 +-
 gcc/function.h                                |  2 +-
 .../analyzer/call-summaries-pr114159.c        | 20 +++++
 27 files changed, 181 insertions(+), 129 deletions(-)
 create mode 100644 
gcc/testsuite/c-c++-common/analyzer/call-summaries-pr114159.c

diff --git a/gcc/analyzer/analyzer.cc b/gcc/analyzer/analyzer.cc
index 389496cd57ab..7f5d3d56d338 100644
--- a/gcc/analyzer/analyzer.cc
+++ b/gcc/analyzer/analyzer.cc
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "analyzer/analyzer.h"
 #include "tree-pretty-print.h"
 #include "diagnostic-event-id.h"
+#include "tree-dfa.h"
 
 #if ENABLE_ANALYZER
 
@@ -275,6 +276,14 @@ byte_offset_to_json (const byte_offset_t &offset)
   return new json::string (pp_formatted_text (&pp));
 }
 
+/* Workaround for lack of const-correctness of ssa_default_def.  */
+
+tree
+get_ssa_default_def (const function &fun, tree var)
+{
+  return ssa_default_def (const_cast <function *> (&fun), var);
+}
+
 } // namespace ana
 
 /* Helper function for checkers.  Is the CALL to the given function name,
diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h
index 20a8e3f9a1d0..1d792ed23ec7 100644
--- a/gcc/analyzer/analyzer.h
+++ b/gcc/analyzer/analyzer.h
@@ -433,6 +433,9 @@ compare_constants (tree lhs_const, enum tree_code op, tree 
rhs_const);
 extern tree
 get_string_cst_size (const_tree string_cst);
 
+extern tree
+get_ssa_default_def (const function &fun, tree var);
+
 } // namespace ana
 
 extern bool is_special_named_call_p (const gcall *call, const char *funcname,
diff --git a/gcc/analyzer/call-info.cc b/gcc/analyzer/call-info.cc
index 7ec82124d523..4c965b2136c0 100644
--- a/gcc/analyzer/call-info.cc
+++ b/gcc/analyzer/call-info.cc
@@ -143,6 +143,14 @@ call_info::call_info (const call_details &cd)
   gcc_assert (m_fndecl);
 }
 
+call_info::call_info (const call_details &cd,
+                     const function &called_fn)
+: m_call_stmt (cd.get_call_stmt ()),
+  m_fndecl (called_fn.decl)
+{
+  gcc_assert (m_fndecl);
+}
+
 /* class succeed_or_fail_call_info : public call_info.  */
 
 label_text
diff --git a/gcc/analyzer/call-info.h b/gcc/analyzer/call-info.h
index 9815b4141c34..17d5fdfec735 100644
--- a/gcc/analyzer/call-info.h
+++ b/gcc/analyzer/call-info.h
@@ -44,6 +44,7 @@ public:
 
 protected:
   call_info (const call_details &cd);
+  call_info (const call_details &cd, const function &called_fn);
 
 private:
   const gcall *m_call_stmt;
diff --git a/gcc/analyzer/call-summary.cc b/gcc/analyzer/call-summary.cc
index ecb6fb13c9ec..8b8567a15280 100644
--- a/gcc/analyzer/call-summary.cc
+++ b/gcc/analyzer/call-summary.cc
@@ -167,7 +167,7 @@ call_summary::dump (const extrinsic_state &ext_state, bool 
simple) const
    arguments at the caller. */
 
 call_summary_replay::call_summary_replay (const call_details &cd,
-                                         function *called_fn,
+                                         const function &called_fn,
                                          call_summary *summary,
                                          const extrinsic_state &ext_state)
 : m_cd (cd),
@@ -177,7 +177,7 @@ call_summary_replay::call_summary_replay (const 
call_details &cd,
   region_model_manager *mgr = cd.get_manager ();
 
   // populate params based on args
-  tree fndecl = called_fn->decl;
+  tree fndecl = called_fn.decl;
 
   /* Get a frame_region for use with respect to the summary.
      This will be a top-level frame, since that's what's in
@@ -196,7 +196,7 @@ call_summary_replay::call_summary_replay (const 
call_details &cd,
        break;
       const svalue *caller_arg_sval = cd.get_arg_svalue (idx);
       tree parm_lval = iter_parm;
-      if (tree parm_default_ssa = ssa_default_def (called_fn, iter_parm))
+      if (tree parm_default_ssa = get_ssa_default_def (called_fn, iter_parm))
        parm_lval = parm_default_ssa;
       const region *summary_parm_reg
        = summary_frame->get_region_for_local (mgr, parm_lval, cd.get_ctxt ());
diff --git a/gcc/analyzer/call-summary.h b/gcc/analyzer/call-summary.h
index 73f21ac72826..220dd0831846 100644
--- a/gcc/analyzer/call-summary.h
+++ b/gcc/analyzer/call-summary.h
@@ -68,7 +68,7 @@ class call_summary_replay
 {
 public:
   call_summary_replay (const call_details &cd,
-                      function *called_fn,
+                      const function &called_fn,
                       call_summary *m_summary,
                       const extrinsic_state &ext_state);
 
diff --git a/gcc/analyzer/checker-event.h b/gcc/analyzer/checker-event.h
index 7d8915c8e530..d2fb87fb523f 100644
--- a/gcc/analyzer/checker-event.h
+++ b/gcc/analyzer/checker-event.h
@@ -370,7 +370,7 @@ public:
   label_text get_desc (bool can_colorize) const final override;
   meaning get_meaning () const override;
 
-  function *get_dest_function () const
+  const function *get_dest_function () const
   {
     return m_dst_state.get_current_function ();
   }
diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index 44ff20cf9af7..ad310b4d8731 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -1072,7 +1072,7 @@ point_and_state::validate (const extrinsic_state 
&ext_state) const
     {
       int index = iter_frame->get_index ();
       gcc_assert (m_point.get_function_at_depth (index)
-                 == iter_frame->get_function ());
+                 == &iter_frame->get_function ());
     }
 }
 
@@ -1496,14 +1496,17 @@ exploded_node::on_stmt (exploded_graph &eg,
        per_function_data *called_fn_data
          = eg.get_per_function_data (called_fn);
        if (called_fn_data)
-         return replay_call_summaries (eg,
-                                       snode,
-                                       as_a <const gcall *> (stmt),
-                                       state,
-                                       path_ctxt,
-                                       called_fn,
-                                       called_fn_data,
-                                       &ctxt);
+         {
+           gcc_assert (called_fn);
+           return replay_call_summaries (eg,
+                                         snode,
+                                         as_a <const gcall *> (stmt),
+                                         state,
+                                         path_ctxt,
+                                         *called_fn,
+                                         *called_fn_data,
+                                         &ctxt);
+         }
       }
 
   bool unknown_side_effects = false;
@@ -1610,10 +1613,10 @@ class call_summary_edge_info : public call_info
 {
 public:
   call_summary_edge_info (const call_details &cd,
-                         function *called_fn,
+                         const function &called_fn,
                          call_summary *summary,
                          const extrinsic_state &ext_state)
-  : call_info (cd),
+  : call_info (cd, called_fn),
     m_called_fn (called_fn),
     m_summary (summary),
     m_ext_state (ext_state)
@@ -1648,7 +1651,7 @@ public:
   }
 
 private:
-  function *m_called_fn;
+  const function &m_called_fn;
   call_summary *m_summary;
   const extrinsic_state &m_ext_state;
 };
@@ -1662,18 +1665,15 @@ exploded_node::replay_call_summaries (exploded_graph 
&eg,
                                      const gcall *call_stmt,
                                      program_state *state,
                                      path_context *path_ctxt,
-                                     function *called_fn,
-                                     per_function_data *called_fn_data,
+                                     const function &called_fn,
+                                     per_function_data &called_fn_data,
                                      region_model_context *ctxt)
 {
   logger *logger = eg.get_logger ();
   LOG_SCOPE (logger);
 
-  gcc_assert (called_fn);
-  gcc_assert (called_fn_data);
-
   /* Each summary will call bifurcate on the PATH_CTXT.  */
-  for (auto summary : called_fn_data->m_summaries)
+  for (auto summary : called_fn_data.m_summaries)
     replay_call_summary (eg, snode, call_stmt, state,
                         path_ctxt, called_fn, summary, ctxt);
   path_ctxt->terminate_path ();
@@ -1691,7 +1691,7 @@ exploded_node::replay_call_summary (exploded_graph &eg,
                                    const gcall *call_stmt,
                                    program_state *old_state,
                                    path_context *path_ctxt,
-                                   function *called_fn,
+                                   const function &called_fn,
                                    call_summary *summary,
                                    region_model_context *ctxt)
 {
@@ -1700,13 +1700,12 @@ exploded_node::replay_call_summary (exploded_graph &eg,
   gcc_assert (snode);
   gcc_assert (call_stmt);
   gcc_assert (old_state);
-  gcc_assert (called_fn);
   gcc_assert (summary);
 
   if (logger)
     logger->log ("using %s as summary for call to %qE from %qE",
                 summary->get_desc ().get (),
-                called_fn->decl,
+                called_fn.decl,
                 snode->get_function ()->decl);
   const extrinsic_state &ext_state = eg.get_ext_state ();
   const program_state &summary_end_state = summary->get_state ();
@@ -2784,16 +2783,17 @@ private:
    Return the exploded_node for the entrypoint to the function.  */
 
 exploded_node *
-exploded_graph::add_function_entry (function *fun)
+exploded_graph::add_function_entry (const function &fun)
 {
-  gcc_assert (gimple_has_body_p (fun->decl));
+  gcc_assert (gimple_has_body_p (fun.decl));
 
   /* Be idempotent.  */
-  if (m_functions_with_enodes.contains (fun))
+  function *key = const_cast<function *> (&fun);
+  if (m_functions_with_enodes.contains (key))
     {
       logger * const logger = get_logger ();
        if (logger)
-       logger->log ("entrypoint for %qE already exists", fun->decl);
+       logger->log ("entrypoint for %qE already exists", fun.decl);
       return NULL;
     }
 
@@ -2805,10 +2805,10 @@ exploded_graph::add_function_entry (function *fun)
 
   std::unique_ptr<custom_edge_info> edge_info = NULL;
 
-  if (lookup_attribute ("tainted_args", DECL_ATTRIBUTES (fun->decl)))
+  if (lookup_attribute ("tainted_args", DECL_ATTRIBUTES (fun.decl)))
     {
-      if (mark_params_as_tainted (&state, fun->decl, m_ext_state))
-       edge_info = make_unique<tainted_args_function_info> (fun->decl);
+      if (mark_params_as_tainted (&state, fun.decl, m_ext_state))
+       edge_info = make_unique<tainted_args_function_info> (fun.decl);
     }
 
   if (!state.m_valid)
@@ -2820,7 +2820,7 @@ exploded_graph::add_function_entry (function *fun)
 
   add_edge (m_origin, enode, NULL, false, std::move (edge_info));
 
-  m_functions_with_enodes.add (fun);
+  m_functions_with_enodes.add (key);
 
   return enode;
 }
@@ -3108,7 +3108,7 @@ exploded_graph::get_per_function_data (function *fun) 
const
    called via other functions.  */
 
 static bool
-toplevel_function_p (function *fun, logger *logger)
+toplevel_function_p (const function &fun, logger *logger)
 {
   /* Don't directly traverse into functions that have an "__analyzer_"
      prefix.  Doing so is useful for the analyzer test suite, allowing
@@ -3119,17 +3119,17 @@ toplevel_function_p (function *fun, logger *logger)
      excess messages from the case of the first function being traversed
      directly.  */
 #define ANALYZER_PREFIX "__analyzer_"
-  if (!strncmp (IDENTIFIER_POINTER (DECL_NAME (fun->decl)), ANALYZER_PREFIX,
+  if (!strncmp (IDENTIFIER_POINTER (DECL_NAME (fun.decl)), ANALYZER_PREFIX,
                strlen (ANALYZER_PREFIX)))
     {
       if (logger)
        logger->log ("not traversing %qE (starts with %qs)",
-                    fun->decl, ANALYZER_PREFIX);
+                    fun.decl, ANALYZER_PREFIX);
       return false;
     }
 
   if (logger)
-    logger->log ("traversing %qE (all checks passed)", fun->decl);
+    logger->log ("traversing %qE (all checks passed)", fun.decl);
 
   return true;
 }
@@ -3254,9 +3254,9 @@ add_tainted_args_callback (exploded_graph *eg, tree 
field, tree fndecl,
 
   program_point point
     = program_point::from_function_entry (*ext_state.get_model_manager (),
-                                         eg->get_supergraph (), fun);
+                                         eg->get_supergraph (), *fun);
   program_state state (ext_state);
-  state.push_frame (ext_state, fun);
+  state.push_frame (ext_state, *fun);
 
   if (!mark_params_as_tainted (&state, fndecl, ext_state))
     return;
@@ -3330,9 +3330,10 @@ exploded_graph::build_initial_worklist ()
   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
   {
     function *fun = node->get_fun ();
-    if (!toplevel_function_p (fun, logger))
+    gcc_assert (fun);
+    if (!toplevel_function_p (*fun, logger))
       continue;
-    exploded_node *enode = add_function_entry (fun);
+    exploded_node *enode = add_function_entry (*fun);
     if (logger)
       {
        if (enode)
@@ -3838,8 +3839,8 @@ exploded_graph::maybe_create_dynamic_call (const gcall 
*call,
   if (fun)
     {
       const supergraph &sg = this->get_supergraph ();
-      supernode *sn_entry = sg.get_node_for_function_entry (fun);
-      supernode *sn_exit = sg.get_node_for_function_exit (fun);
+      supernode *sn_entry = sg.get_node_for_function_entry (*fun);
+      supernode *sn_exit = sg.get_node_for_function_exit (*fun);
 
       program_point new_point
        = program_point::before_supernode (sn_entry,
@@ -4962,7 +4963,7 @@ maybe_update_for_edge (logger *logger,
                      == PK_BEFORE_SUPERNODE);
          function *fun = eedge->m_dest->get_function ();
          gcc_assert (fun);
-         m_model.push_frame (fun, NULL, ctxt);
+         m_model.push_frame (*fun, NULL, ctxt);
          if (logger)
            logger->log ("  pushing frame for %qD", fun->decl);
        }
@@ -5582,7 +5583,7 @@ exploded_graph::on_escaped_function (tree fndecl)
   if (!gimple_has_body_p (fndecl))
     return;
 
-  exploded_node *enode = add_function_entry (fun);
+  exploded_node *enode = add_function_entry (*fun);
   if (logger)
     {
       if (enode)
diff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h
index 387ae3a3aea0..642d69bbcc0a 100644
--- a/gcc/analyzer/exploded-graph.h
+++ b/gcc/analyzer/exploded-graph.h
@@ -285,15 +285,15 @@ class exploded_node : public dnode<eg_traits>
                                       const gcall *call_stmt,
                                       program_state *state,
                                       path_context *path_ctxt,
-                                      function *called_fn,
-                                      per_function_data *called_fn_data,
+                                      const function &called_fn,
+                                      per_function_data &called_fn_data,
                                       region_model_context *ctxt);
   void replay_call_summary (exploded_graph &eg,
                            const supernode *snode,
                            const gcall *call_stmt,
                            program_state *state,
                            path_context *path_ctxt,
-                           function *called_fn,
+                           const function &called_fn,
                            call_summary *summary,
                            region_model_context *ctxt);
 
@@ -810,7 +810,7 @@ public:
 
   exploded_node *get_origin () const { return m_origin; }
 
-  exploded_node *add_function_entry (function *fun);
+  exploded_node *add_function_entry (const function &fun);
 
   void build_initial_worklist ();
   void process_worklist ();
diff --git a/gcc/analyzer/program-point.cc b/gcc/analyzer/program-point.cc
index 5e98b5234dcc..6e225cfe7254 100644
--- a/gcc/analyzer/program-point.cc
+++ b/gcc/analyzer/program-point.cc
@@ -230,7 +230,7 @@ function_point::final_stmt_p () const
 /* Create a function_point representing the entrypoint of function FUN.  */
 
 function_point
-function_point::from_function_entry (const supergraph &sg, function *fun)
+function_point::from_function_entry (const supergraph &sg, const function &fun)
 {
   return before_supernode (sg.get_node_for_function_entry (fun), NULL);
 }
@@ -698,7 +698,7 @@ program_point::origin (const region_model_manager &mgr)
 program_point
 program_point::from_function_entry (const region_model_manager &mgr,
                                    const supergraph &sg,
-                                   function *fun)
+                                   const function &fun)
 {
   return program_point (function_point::from_function_entry (sg, fun),
                        mgr.get_empty_call_string ());
diff --git a/gcc/analyzer/program-point.h b/gcc/analyzer/program-point.h
index 62c2c946412d..61b895f4499b 100644
--- a/gcc/analyzer/program-point.h
+++ b/gcc/analyzer/program-point.h
@@ -112,7 +112,7 @@ public:
   /* Factory functions for making various kinds of program_point.  */
 
   static function_point from_function_entry (const supergraph &sg,
-                                            function *fun);
+                                            const function &fun);
 
   static function_point before_supernode (const supernode *supernode,
                                          const superedge *from_edge);
@@ -252,7 +252,7 @@ public:
   static program_point origin (const region_model_manager &mgr);
   static program_point from_function_entry (const region_model_manager &mgr,
                                            const supergraph &sg,
-                                           function *fun);
+                                           const function &fun);
 
   static program_point before_supernode (const supernode *supernode,
                                         const superedge *from_edge,
diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc
index 55dd6ca71667..c88652baf5ca 100644
--- a/gcc/analyzer/program-state.cc
+++ b/gcc/analyzer/program-state.cc
@@ -1143,14 +1143,14 @@ program_state::to_json (const extrinsic_state 
&ext_state) const
 
 void
 program_state::push_frame (const extrinsic_state &ext_state ATTRIBUTE_UNUSED,
-                          function *fun)
+                          const function &fun)
 {
   m_region_model->push_frame (fun, NULL, NULL);
 }
 
 /* Get the current function of this state.  */
 
-function *
+const function *
 program_state::get_current_function () const
 {
   return m_region_model->get_current_function ();
diff --git a/gcc/analyzer/program-state.h b/gcc/analyzer/program-state.h
index 69bf931f070c..3ba6a931cd6f 100644
--- a/gcc/analyzer/program-state.h
+++ b/gcc/analyzer/program-state.h
@@ -226,8 +226,8 @@ public:
 
   json::object *to_json (const extrinsic_state &ext_state) const;
 
-  void push_frame (const extrinsic_state &ext_state, function *fun);
-  function * get_current_function () const;
+  void push_frame (const extrinsic_state &ext_state, const function &fun);
+  const function * get_current_function () const;
 
   void push_call (exploded_graph &eg,
                  exploded_node *enode,
diff --git a/gcc/analyzer/region-model-manager.cc 
b/gcc/analyzer/region-model-manager.cc
index 93e72ec45a85..8530f49e74ab 100644
--- a/gcc/analyzer/region-model-manager.cc
+++ b/gcc/analyzer/region-model-manager.cc
@@ -1676,7 +1676,7 @@ region_model_manager::get_cast_region (const region 
*original_region,
 
 const frame_region *
 region_model_manager::get_frame_region (const frame_region *calling_frame,
-                                       function *fun)
+                                       const function &fun)
 {
   int index = calling_frame ? calling_frame->get_index () + 1 : 0;
 
diff --git a/gcc/analyzer/region-model-manager.h 
b/gcc/analyzer/region-model-manager.h
index 5c89de1f7c13..7d1208c70a70 100644
--- a/gcc/analyzer/region-model-manager.h
+++ b/gcc/analyzer/region-model-manager.h
@@ -131,7 +131,7 @@ public:
   const region *get_cast_region (const region *original_region,
                                 tree type);
   const frame_region *get_frame_region (const frame_region *calling_frame,
-                                       function *fun);
+                                       const function &fun);
   const region *get_symbolic_region (const svalue *sval);
   const string_region *get_region_for_string (tree string_cst);
   const region *get_bit_range (const region *parent, tree type,
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 6ab917465d6f..33a4584841e4 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -2619,7 +2619,7 @@ region_model::called_from_main_p () const
   /* Determine if the oldest stack frame in this model is for "main".  */
   const frame_region *frame0 = get_frame_at_index (0);
   gcc_assert (frame0);
-  return id_equal (DECL_NAME (frame0->get_function ()->decl), "main");
+  return id_equal (DECL_NAME (frame0->get_function ().decl), "main");
 }
 
 /* Subroutine of region_model::get_store_value for when REG is (or is within)
@@ -5552,7 +5552,8 @@ region_model::update_for_gcall (const gcall *call_stmt,
     callee = DECL_STRUCT_FUNCTION (fn_decl);
   }
 
-  push_frame (callee, &arg_svals, ctxt);
+  gcc_assert (callee);
+  push_frame (*callee, &arg_svals, ctxt);
 }
 
 /* Pop the top-most frame_region from the stack, and copy the return
@@ -5896,14 +5897,15 @@ region_model::on_top_level_param (tree param,
    Return the frame_region for the new frame.  */
 
 const region *
-region_model::push_frame (function *fun, const vec<const svalue *> *arg_svals,
+region_model::push_frame (const function &fun,
+                         const vec<const svalue *> *arg_svals,
                          region_model_context *ctxt)
 {
   m_current_frame = m_mgr->get_frame_region (m_current_frame, fun);
   if (arg_svals)
     {
       /* Arguments supplied from a caller frame.  */
-      tree fndecl = fun->decl;
+      tree fndecl = fun.decl;
       unsigned idx = 0;
       for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm;
           iter_parm = DECL_CHAIN (iter_parm), ++idx)
@@ -5914,7 +5916,7 @@ region_model::push_frame (function *fun, const vec<const 
svalue *> *arg_svals,
          if (idx >= arg_svals->length ())
            break;
          tree parm_lval = iter_parm;
-         if (tree parm_default_ssa = ssa_default_def (fun, iter_parm))
+         if (tree parm_default_ssa = get_ssa_default_def (fun, iter_parm))
            parm_lval = parm_default_ssa;
          const region *parm_reg = get_lvalue (parm_lval, ctxt);
          const svalue *arg_sval = (*arg_svals)[idx];
@@ -5937,7 +5939,7 @@ region_model::push_frame (function *fun, const vec<const 
svalue *> *arg_svals,
       /* Otherwise we have a top-level call within the analysis.  The params
         have defined but unknown initial values.
         Anything they point to has escaped.  */
-      tree fndecl = fun->decl;
+      tree fndecl = fun.decl;
 
       /* Handle "__attribute__((nonnull))".   */
       tree fntype = TREE_TYPE (fndecl);
@@ -5951,7 +5953,7 @@ region_model::push_frame (function *fun, const vec<const 
svalue *> *arg_svals,
                           ? (bitmap_empty_p (nonnull_args)
                              || bitmap_bit_p (nonnull_args, parm_idx))
                           : false);
-         if (tree parm_default_ssa = ssa_default_def (fun, iter_parm))
+         if (tree parm_default_ssa = get_ssa_default_def (fun, iter_parm))
            on_top_level_param (parm_default_ssa, non_null, ctxt);
          else
            on_top_level_param (iter_parm, non_null, ctxt);
@@ -5967,12 +5969,12 @@ region_model::push_frame (function *fun, const 
vec<const svalue *> *arg_svals,
 /* Get the function of the top-most frame in this region_model's stack.
    There must be such a frame.  */
 
-function *
+const function *
 region_model::get_current_function () const
 {
   const frame_region *frame = get_current_frame ();
   gcc_assert (frame);
-  return frame->get_function ();
+  return &frame->get_function ();
 }
 
 /* Pop the topmost frame_region from this region_model's stack;
@@ -6007,7 +6009,7 @@ region_model::pop_frame (tree result_lvalue,
     ctxt->on_pop_frame (frame_reg);
 
   /* Evaluate the result, within the callee frame.  */
-  tree fndecl = m_current_frame->get_function ()->decl;
+  tree fndecl = m_current_frame->get_function ().decl;
   tree result = DECL_RESULT (fndecl);
   const svalue *retval = NULL;
   if (result
@@ -7966,7 +7968,7 @@ test_stack_frames ()
 
   /* Push stack frame for "parent_fn".  */
   const region *parent_frame_reg
-    = model.push_frame (DECL_STRUCT_FUNCTION (parent_fndecl),
+    = model.push_frame (*DECL_STRUCT_FUNCTION (parent_fndecl),
                        NULL, &ctxt);
   ASSERT_EQ (model.get_current_frame (), parent_frame_reg);
   ASSERT_TRUE (model.region_exists_p (parent_frame_reg));
@@ -7982,7 +7984,7 @@ test_stack_frames ()
 
   /* Push stack frame for "child_fn".  */
   const region *child_frame_reg
-    = model.push_frame (DECL_STRUCT_FUNCTION (child_fndecl), NULL, &ctxt);
+    = model.push_frame (*DECL_STRUCT_FUNCTION (child_fndecl), NULL, &ctxt);
   ASSERT_EQ (model.get_current_frame (), child_frame_reg);
   ASSERT_TRUE (model.region_exists_p (child_frame_reg));
   const region *x_in_child_reg = model.get_lvalue (x, &ctxt);
@@ -8075,7 +8077,7 @@ test_get_representative_path_var ()
   for (int depth = 0; depth < 5; depth++)
     {
       const region *frame_n_reg
-       = model.push_frame (DECL_STRUCT_FUNCTION (fndecl), NULL, &ctxt);
+       = model.push_frame (*DECL_STRUCT_FUNCTION (fndecl), NULL, &ctxt);
       const region *parm_n_reg = model.get_lvalue (path_var (n, depth), &ctxt);
       parm_regs.safe_push (parm_n_reg);
 
@@ -8319,9 +8321,9 @@ test_state_merging ()
     region_model model0 (&mgr);
     region_model model1 (&mgr);
     ASSERT_EQ (model0.get_stack_depth (), 0);
-    model0.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, &ctxt);
+    model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, &ctxt);
     ASSERT_EQ (model0.get_stack_depth (), 1);
-    model1.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, &ctxt);
+    model1.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, &ctxt);
 
     placeholder_svalue test_sval (mgr.alloc_symbol_id (),
                                  integer_type_node, "test sval");
@@ -8413,7 +8415,7 @@ test_state_merging ()
   /* Pointers: non-NULL and non-NULL: ptr to a local.  */
   {
     region_model model0 (&mgr);
-    model0.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
+    model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
     model0.set_value (model0.get_lvalue (p, NULL),
                      model0.get_rvalue (addr_of_a, NULL), NULL);
 
@@ -8552,12 +8554,12 @@ test_state_merging ()
      frame points to a local in a more recent stack frame.  */
   {
     region_model model0 (&mgr);
-    model0.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
+    model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
     const region *q_in_first_frame = model0.get_lvalue (q, NULL);
 
     /* Push a second frame.  */
     const region *reg_2nd_frame
-      = model0.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
+      = model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
 
     /* Have a pointer in the older frame point to a local in the
        more recent frame.  */
@@ -8584,7 +8586,7 @@ test_state_merging ()
   /* Verify that we can merge a model in which a local points to a global.  */
   {
     region_model model0 (&mgr);
-    model0.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
+    model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
     model0.set_value (model0.get_lvalue (q, NULL),
                      model0.get_rvalue (addr_of_y, NULL), NULL);
 
@@ -9110,7 +9112,7 @@ test_alloca ()
 
   /* Push stack frame.  */
   const region *frame_reg
-    = model.push_frame (DECL_STRUCT_FUNCTION (fndecl),
+    = model.push_frame (*DECL_STRUCT_FUNCTION (fndecl),
                        NULL, &ctxt);
   /* "p = alloca (n * 4);".  */
   const svalue *size_sval = model.get_rvalue (n_times_4, &ctxt);
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index d4ef10120dd5..118e0f254273 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -347,10 +347,10 @@ class region_model
   void update_for_return_gcall (const gcall *call_stmt,
                                 region_model_context *ctxt);
 
-  const region *push_frame (function *fun, const vec<const svalue *> *arg_sids,
+  const region *push_frame (const function &fun, const vec<const svalue *> 
*arg_sids,
                            region_model_context *ctxt);
   const frame_region *get_current_frame () const { return m_current_frame; }
-  function * get_current_function () const;
+  const function *get_current_function () const;
   void pop_frame (tree result_lvalue,
                  const svalue **out_result,
                  region_model_context *ctxt,
diff --git a/gcc/analyzer/region.cc b/gcc/analyzer/region.cc
index 50821a592302..d45706141fb0 100644
--- a/gcc/analyzer/region.cc
+++ b/gcc/analyzer/region.cc
@@ -1306,10 +1306,10 @@ void
 frame_region::dump_to_pp (pretty_printer *pp, bool simple) const
 {
   if (simple)
-    pp_printf (pp, "frame: %qs@%i", function_name (m_fun), get_stack_depth ());
+    pp_printf (pp, "frame: %qs@%i", function_name (&m_fun), get_stack_depth 
());
   else
     pp_printf (pp, "frame_region(%qs, index: %i, depth: %i)",
-              function_name (m_fun), m_index, get_stack_depth ());
+              function_name (&m_fun), m_index, get_stack_depth ());
 }
 
 const decl_region *
@@ -1334,14 +1334,14 @@ frame_region::get_region_for_local 
(region_model_manager *mgr,
          /* Fall through.  */
        case PARM_DECL:
        case RESULT_DECL:
-         gcc_assert (DECL_CONTEXT (expr) == m_fun->decl);
+         gcc_assert (DECL_CONTEXT (expr) == m_fun.decl);
          break;
        case SSA_NAME:
          {
            if (tree var = SSA_NAME_VAR (expr))
              {
                if (DECL_P (var))
-                 gcc_assert (DECL_CONTEXT (var) == m_fun->decl);
+                 gcc_assert (DECL_CONTEXT (var) == m_fun.decl);
              }
            else if (ctxt)
              if (const extrinsic_state *ext_state = ctxt->get_ext_state ())
@@ -1351,7 +1351,7 @@ frame_region::get_region_for_local (region_model_manager 
*mgr,
                    const gimple *def_stmt = SSA_NAME_DEF_STMT (expr);
                    const supernode *snode
                      = sg->get_supernode_for_stmt (def_stmt);
-                   gcc_assert (snode->get_function () == m_fun);
+                   gcc_assert (snode->get_function () == &m_fun);
                  }
          }
          break;
diff --git a/gcc/analyzer/region.h b/gcc/analyzer/region.h
index 70557babbc04..73f35f55ba71 100644
--- a/gcc/analyzer/region.h
+++ b/gcc/analyzer/region.h
@@ -305,11 +305,10 @@ public:
   /* A support class for uniquifying instances of frame_region.  */
   struct key_t
   {
-    key_t (const frame_region *calling_frame, function *fun)
-    : m_calling_frame (calling_frame), m_fun (fun)
+    key_t (const frame_region *calling_frame, const function &fun)
+    : m_calling_frame (calling_frame), m_fun (&fun)
     {
       /* calling_frame can be NULL.  */
-      gcc_assert (fun);
     }
 
     hashval_t hash () const
@@ -322,7 +321,8 @@ public:
 
     bool operator== (const key_t &other) const
     {
-      return (m_calling_frame == other.m_calling_frame && m_fun == 
other.m_fun);
+      return (m_calling_frame == other.m_calling_frame
+             && m_fun == other.m_fun);
     }
 
     void mark_deleted () { m_fun = reinterpret_cast<function *> (1); }
@@ -334,12 +334,12 @@ public:
     bool is_empty () const { return m_fun == NULL; }
 
     const frame_region *m_calling_frame;
-    function *m_fun;
+    const function *m_fun;
   };
 
   frame_region (symbol::id_t id, const region *parent,
                const frame_region *calling_frame,
-               function *fun, int index)
+               const function &fun, int index)
   : space_region (id, parent), m_calling_frame (calling_frame),
     m_fun (fun), m_index (index)
   {}
@@ -356,8 +356,8 @@ public:
 
   /* Accessors.  */
   const frame_region *get_calling_frame () const { return m_calling_frame; }
-  function *get_function () const { return m_fun; }
-  tree get_fndecl () const { return get_function ()->decl; }
+  const function &get_function () const { return m_fun; }
+  tree get_fndecl () const { return get_function ().decl; }
   int get_index () const { return m_index; }
   int get_stack_depth () const { return m_index + 1; }
 
@@ -373,7 +373,7 @@ public:
 
  private:
   const frame_region *m_calling_frame;
-  function *m_fun;
+  const function &m_fun;
   int m_index;
 
   /* The regions for the decls within this frame are managed by this
diff --git a/gcc/analyzer/sm-signal.cc b/gcc/analyzer/sm-signal.cc
index 5be857a99ff8..93269caa0dc5 100644
--- a/gcc/analyzer/sm-signal.cc
+++ b/gcc/analyzer/sm-signal.cc
@@ -146,7 +146,8 @@ public:
     if (change.is_global_p ()
        && change.m_new_state == m_sm.m_in_signal_handler)
       {
-       function *handler = change.m_event.get_dest_function ();
+       const function *handler = change.m_event.get_dest_function ();
+       gcc_assert (handler);
        return change.formatted_print ("registering %qD as signal handler",
                                       handler->decl);
       }
@@ -193,7 +194,7 @@ signal_state_machine::signal_state_machine (logger *logger)
 
 static void
 update_model_for_signal_handler (region_model *model,
-                                function *handler_fun)
+                                const function &handler_fun)
 {
   gcc_assert (model);
   /* Purge all state within MODEL.  */
@@ -222,7 +223,9 @@ public:
                     region_model_context *) const final override
   {
     gcc_assert (eedge);
-    update_model_for_signal_handler (model, eedge->m_dest->get_function ());
+    gcc_assert (eedge->m_dest->get_function ());
+    update_model_for_signal_handler (model,
+                                    *eedge->m_dest->get_function ());
     return true;
   }
 
@@ -263,11 +266,11 @@ public:
     program_point entering_handler
       = program_point::from_function_entry (*ext_state.get_model_manager (),
                                            eg->get_supergraph (),
-                                           handler_fun);
+                                           *handler_fun);
 
     program_state state_entering_handler (ext_state);
     update_model_for_signal_handler (state_entering_handler.m_region_model,
-                                    handler_fun);
+                                    *handler_fun);
     state_entering_handler.m_checker_states[sm_idx]->set_global_state
       (m_sm.m_in_signal_handler);
 
diff --git a/gcc/analyzer/state-purge.cc b/gcc/analyzer/state-purge.cc
index 93959fb08ea3..324b548f75b1 100644
--- a/gcc/analyzer/state-purge.cc
+++ b/gcc/analyzer/state-purge.cc
@@ -89,7 +89,7 @@ class gimple_op_visitor : public log_user
 public:
   gimple_op_visitor (state_purge_map *map,
                     const function_point &point,
-                    function *fun)
+                    const function &fun)
   : log_user (map->get_logger ()),
     m_map (map),
     m_point (point),
@@ -172,7 +172,7 @@ private:
 
   state_purge_map *m_map;
   const function_point &m_point;
-  function *m_fun;
+  const function &m_fun;
 };
 
 static bool
@@ -214,6 +214,7 @@ state_purge_map::state_purge_map (const supergraph &sg,
   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
   {
     function *fun = node->get_fun ();
+    gcc_assert (fun);
     if (logger)
       log ("function: %s", function_name (fun));
     tree name;
@@ -225,7 +226,7 @@ state_purge_map::state_purge_map (const supergraph &sg,
          if (TREE_CODE (var) == VAR_DECL)
            if (VAR_DECL_IS_VIRTUAL_OPERAND (var))
              continue;
-       m_ssa_map.put (name, new state_purge_per_ssa_name (*this, name, fun));
+       m_ssa_map.put (name, new state_purge_per_ssa_name (*this, name, *fun));
       }
   }
 
@@ -241,8 +242,10 @@ state_purge_map::state_purge_map (const supergraph &sg,
       unsigned i;
       FOR_EACH_VEC_ELT (snode->m_stmts, i, stmt)
        {
+         function *fun = snode->get_function ();
+         gcc_assert (fun);
          function_point point (function_point::before_stmt (snode, i));
-         gimple_op_visitor v (this, point, snode->get_function ());
+         gimple_op_visitor v (this, point, *fun);
          walk_stmt_load_store_addr_ops (stmt, &v,
                                         my_load_cb, my_store_cb, my_addr_cb);
        }
@@ -272,7 +275,7 @@ state_purge_map::~state_purge_map ()
    if necessary.  */
 
 state_purge_per_decl &
-state_purge_map::get_or_create_data_for_decl (function *fun, tree decl)
+state_purge_map::get_or_create_data_for_decl (const function &fun, tree decl)
 {
   if (state_purge_per_decl **slot
       = const_cast <decl_map_t&> (m_decl_map).get (decl))
@@ -295,14 +298,14 @@ state_purge_map::get_or_create_data_for_decl (function 
*fun, tree decl)
 
 state_purge_per_ssa_name::state_purge_per_ssa_name (const state_purge_map &map,
                                                    tree name,
-                                                   function *fun)
+                                                   const function &fun)
 : state_purge_per_tree (fun), m_points_needing_name (), m_name (name)
 {
   LOG_FUNC (map.get_logger ());
 
   if (map.get_logger ())
     {
-      map.log ("SSA name: %qE within %qD", name, fun->decl);
+      map.log ("SSA name: %qE within %qD", name, fun.decl);
 
       /* Show def stmt.  */
       const gimple *def_stmt = SSA_NAME_DEF_STMT (name);
@@ -410,7 +413,7 @@ state_purge_per_ssa_name::state_purge_per_ssa_name (const 
state_purge_map &map,
 
   if (map.get_logger ())
     {
-      map.log ("%qE in %qD is needed to process:", name, fun->decl);
+      map.log ("%qE in %qD is needed to process:", name, fun.decl);
       /* Log m_points_needing_name, sorting it to avoid churn when comparing
         dumps.  */
       auto_vec<function_point> points;
@@ -472,7 +475,7 @@ state_purge_per_ssa_name::add_to_worklist (const 
function_point &point,
       logger->end_log_line ();
     }
 
-  gcc_assert (point.get_function () == get_function ());
+  gcc_assert (point.get_function () == &get_function ());
   if (point.get_from_edge ())
     gcc_assert (point.get_from_edge ()->get_kind () == SUPEREDGE_CFG_EDGE);
 
@@ -678,7 +681,7 @@ state_purge_per_ssa_name::process_point (const 
function_point &point,
 
 state_purge_per_decl::state_purge_per_decl (const state_purge_map &map,
                                            tree decl,
-                                           function *fun)
+                                           const function &fun)
 : state_purge_per_tree (fun),
   m_decl (decl)
 {
@@ -794,7 +797,7 @@ state_purge_per_decl::add_to_worklist (const function_point 
&point,
       logger->end_log_line ();
     }
 
-  gcc_assert (point.get_function () == get_function ());
+  gcc_assert (point.get_function () == &get_function ());
   if (point.get_from_edge ())
     gcc_assert (point.get_from_edge ()->get_kind () == SUPEREDGE_CFG_EDGE);
 
@@ -1192,7 +1195,7 @@ state_purge_annotator::print_needed (graphviz_out *gv,
     {
       tree name = (*iter).first;
       state_purge_per_ssa_name *per_name_data = (*iter).second;
-      if (per_name_data->get_function () == point.get_function ())
+      if (&per_name_data->get_function () == point.get_function ())
        {
          if (per_name_data->needed_at_point_p (point))
            needed.safe_push (name);
@@ -1206,7 +1209,7 @@ state_purge_annotator::print_needed (graphviz_out *gv,
     {
       tree decl = (*iter).first;
       state_purge_per_decl *per_decl_data = (*iter).second;
-      if (per_decl_data->get_function () == point.get_function ())
+      if (&per_decl_data->get_function () == point.get_function ())
        {
          if (per_decl_data->needed_at_point_p (point))
            needed.safe_push (decl);
diff --git a/gcc/analyzer/state-purge.h b/gcc/analyzer/state-purge.h
index c6d64b41fd46..4eb2ba0a908a 100644
--- a/gcc/analyzer/state-purge.h
+++ b/gcc/analyzer/state-purge.h
@@ -112,7 +112,8 @@ public:
       return NULL;
   }
 
-  state_purge_per_decl &get_or_create_data_for_decl (function *fun, tree decl);
+  state_purge_per_decl &
+  get_or_create_data_for_decl (const function &fun, tree decl);
 
   const supergraph &get_sg () const { return m_sg; }
 
@@ -135,19 +136,19 @@ private:
 class state_purge_per_tree
 {
 public:
-  function *get_function () const { return m_fun; }
-  tree get_fndecl () const { return m_fun->decl; }
+  const function &get_function () const { return m_fun; }
+  tree get_fndecl () const { return m_fun.decl; }
 
 protected:
   typedef hash_set<function_point> point_set_t;
 
-  state_purge_per_tree (function *fun)
+  state_purge_per_tree (const function &fun)
   : m_fun (fun)
   {
   }
 
 private:
-  function *m_fun;
+  const function &m_fun;
 };
 
 /* The part of a state_purge_map relating to a specific SSA name.
@@ -162,7 +163,7 @@ class state_purge_per_ssa_name : public state_purge_per_tree
 public:
   state_purge_per_ssa_name (const state_purge_map &map,
                            tree name,
-                           function *fun);
+                           const function &fun);
 
   bool needed_at_point_p (const function_point &point) const;
 
@@ -194,7 +195,7 @@ class state_purge_per_decl : public state_purge_per_tree
 public:
   state_purge_per_decl (const state_purge_map &map,
                        tree decl,
-                       function *fun);
+                       const function &fun);
 
   bool needed_at_point_p (const function_point &point) const;
 
diff --git a/gcc/analyzer/supergraph.cc b/gcc/analyzer/supergraph.cc
index b82275256b72..adbf90f17ede 100644
--- a/gcc/analyzer/supergraph.cc
+++ b/gcc/analyzer/supergraph.cc
@@ -364,6 +364,7 @@ supergraph::dump_dot_to_pp (pretty_printer *pp,
     FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
     {
       function *fun = node->get_fun ();
+      gcc_assert (fun);
       const char *funcname = function_name (fun);
       gv.println ("subgraph \"cluster_%s\" {",
                  funcname);
@@ -409,9 +410,9 @@ supergraph::dump_dot_to_pp (pretty_printer *pp,
 
       /* Add an invisible edge from ENTRY to EXIT, to improve the graph 
layout.  */
       pp_string (pp, "\t");
-      get_node_for_function_entry (fun)->dump_dot_id (pp);
+      get_node_for_function_entry (*fun)->dump_dot_id (pp);
       pp_string (pp, ":s -> ");
-      get_node_for_function_exit (fun)->dump_dot_id (pp);
+      get_node_for_function_exit (*fun)->dump_dot_id (pp);
       pp_string (pp, ":n [style=\"invis\",constraint=true];\n");
 
       /* Terminate per-function "subgraph" */
diff --git a/gcc/analyzer/supergraph.h b/gcc/analyzer/supergraph.h
index 2677acad8d6a..86f918bc8b5d 100644
--- a/gcc/analyzer/supergraph.h
+++ b/gcc/analyzer/supergraph.h
@@ -111,14 +111,14 @@ public:
   supergraph (logger *logger);
   ~supergraph ();
 
-  supernode *get_node_for_function_entry (function *fun) const
+  supernode *get_node_for_function_entry (const function &fun) const
   {
-    return get_node_for_block (ENTRY_BLOCK_PTR_FOR_FN (fun));
+    return get_node_for_block (ENTRY_BLOCK_PTR_FOR_FN (&fun));
   }
 
-  supernode *get_node_for_function_exit (function *fun) const
+  supernode *get_node_for_function_exit (const function &fun) const
   {
-    return get_node_for_block (EXIT_BLOCK_PTR_FOR_FN (fun));
+    return get_node_for_block (EXIT_BLOCK_PTR_FOR_FN (&fun));
   }
 
   supernode *get_node_for_block (basic_block bb) const
diff --git a/gcc/function.cc b/gcc/function.cc
index 5ffd438475e9..9488181cbd95 100644
--- a/gcc/function.cc
+++ b/gcc/function.cc
@@ -6391,7 +6391,7 @@ fndecl_name (tree fndecl)
 
 /* Returns the name of function FN.  */
 const char *
-function_name (struct function *fn)
+function_name (const function *fn)
 {
   tree fndecl = (fn == NULL) ? NULL : fn->decl;
   return fndecl_name (fndecl);
diff --git a/gcc/function.h b/gcc/function.h
index 2d775b877fc2..19e15bd63b0a 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -730,7 +730,7 @@ extern poly_int64 get_stack_dynamic_offset ();
 
 /* Returns the name of the current function.  */
 extern const char *fndecl_name (tree);
-extern const char *function_name (struct function *);
+extern const char *function_name (const function *);
 extern const char *current_function_name (void);
 
 extern void used_types_insert (tree);
diff --git a/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr114159.c 
b/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr114159.c
new file mode 100644
index 000000000000..19b545a1154d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr114159.c
@@ -0,0 +1,20 @@
+/* Verify we don't ICE on this case with these options.  */
+
+/* { dg-additional-options "-fanalyzer-call-summaries 
--param=analyzer-max-svalue-depth=0 -Wno-analyzer-symbol-too-complex" } */
+
+int foo_i;
+void bar() {}
+void foo() {
+  if (foo_i)
+    bar();
+  else
+    goto f1;
+  bar();
+f1:
+  bar();
+}
+int main() {
+  foo();
+  foo();
+  return 0;
+}
-- 
2.26.3

Reply via email to