From a6b92e0484d6ba0c71a5689b27b166b2f7a4d715 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 1 Oct 2020 14:44:34 -0400
Subject: [PATCH 28/47] FIXME: undo last two commits and fix callbacks by
 eliminating toplevel_function_p and just adding everything

---
 gcc/analyzer/engine.cc                      | 89 +--------------------
 gcc/analyzer/exploded-graph.h               |  8 --
 gcc/analyzer/region-model-reachability.cc   | 15 +---
 gcc/analyzer/region-model-reachability.h    |  6 +-
 gcc/analyzer/region-model.cc                | 55 +++++++------
 gcc/analyzer/region-model.h                 |  7 +-
 gcc/testsuite/gcc.dg/analyzer/callbacks-2.c |  2 +-
 7 files changed, 37 insertions(+), 145 deletions(-)

diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index 4392d189046..7d8e1517d0f 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -143,12 +143,6 @@ impl_region_model_context::on_unknown_change (const svalue *sval,
     smap->on_unknown_change (sval, is_mutable, m_ext_state);
 }
 
-void
-impl_region_model_context::on_escaped_function (tree fndecl)
-{
-  m_eg->on_escaped_function (fndecl);
-}
-
 /* class setjmp_svalue : public svalue.  */
 
 /* Implementation of svalue::accept vfunc for setjmp_svalue.  */
@@ -1990,15 +1984,6 @@ exploded_graph::~exploded_graph ()
 exploded_node *
 exploded_graph::add_function_entry (function *fun)
 {
-  /* Be idempotent.  */
-  if (m_functions_with_enodes.contains (fun))
-    {
-      logger * const logger = get_logger ();
-       if (logger)
-	logger->log ("entrypoint for %qE already exists", fun->decl);
-      return NULL;
-    }
-
   program_point point = program_point::from_function_entry (m_sg, fun);
   program_state state (m_ext_state);
   state.push_frame (m_ext_state, fun);
@@ -2010,9 +1995,6 @@ exploded_graph::add_function_entry (function *fun)
   /* We should never fail to add such a node.  */
   gcc_assert (enode);
   add_edge (m_origin, enode, NULL);
-
-  m_functions_with_enodes.add (fun);
-
   return enode;
 }
 
@@ -2300,49 +2282,7 @@ exploded_graph::get_per_function_data (function *fun) const
   return NULL;
 }
 
-/* Return true if NODE and FUN should be traversed directly, rather than
-   called via other functions.  */
-
-static bool
-toplevel_function_p (cgraph_node *node, function *fun, logger *logger)
-{
-  /* TODO: better logic here
-     e.g. only if more than one caller, and significantly complicated.
-     Perhaps some whole-callgraph analysis to decide if it's worth summarizing
-     an edge, and if so, we need summaries.  */
-  if (flag_analyzer_call_summaries)
-    {
-      int num_call_sites = 0;
-      for (cgraph_edge *edge = node->callers; edge; edge = edge->next_caller)
-	++num_call_sites;
-
-      /* For now, if there's more than one in-edge, and we want call
-	 summaries, do it at the top level so that there's a chance
-	 we'll have a summary when we need one.  */
-      if (num_call_sites > 1)
-	{
-	  if (logger)
-	    logger->log ("traversing %qE (%i call sites)",
-			 fun->decl, num_call_sites);
-	  return true;
-	}
-    }
-
-  if (!TREE_PUBLIC (fun->decl))
-    {
-      if (logger)
-	logger->log ("not traversing %qE (static)", fun->decl);
-      return false;
-    }
-
-  if (logger)
-    logger->log ("traversing %qE (all checks passed)", fun->decl);
-
-  return true;
-}
-
-/* Add initial nodes to EG, with entrypoints for externally-callable
-   functions.  */
+/* Add initial nodes to EG, with entrypoints for all functions.  */
 
 void
 exploded_graph::build_initial_worklist ()
@@ -2354,8 +2294,6 @@ exploded_graph::build_initial_worklist ()
   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
   {
     function *fun = node->get_fun ();
-    if (!toplevel_function_p (node, fun, logger))
-      continue;
     exploded_node *enode = add_function_entry (fun);
     if (logger)
       {
@@ -4009,31 +3947,6 @@ exploded_graph::get_node_by_index (int idx) const
   return enode;
 }
 
-/* FIXME.  */
-
-void
-exploded_graph::on_escaped_function (tree fndecl)
-{
-  logger * const logger = get_logger ();
-  LOG_FUNC (logger);
-
-  cgraph_node *cgnode = cgraph_node::get (fndecl);
-  if (!cgnode)
-    return;
-
-  function *fun = cgnode->get_fun ();
-
-  exploded_node *enode = add_function_entry (fun);
-  if (logger)
-    {
-      if (enode)
-	logger->log ("created EN %i for %qE entrypoint",
-		     enode->m_index, fun->decl);
-      else
-	logger->log ("did not create enode for %qE entrypoint", fun->decl);
-    }
-}
-
 /* A collection of classes for visualizing the callgraph in .dot form
    (as represented in the supergraph).  */
 
diff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h
index b07752756f8..fadf22cbdd0 100644
--- a/gcc/analyzer/exploded-graph.h
+++ b/gcc/analyzer/exploded-graph.h
@@ -66,8 +66,6 @@ class impl_region_model_context : public region_model_context
   void on_unexpected_tree_code (tree t,
 				const dump_location_t &loc) FINAL OVERRIDE;
 
-  void on_escaped_function (tree fndecl) FINAL OVERRIDE;
-
   exploded_graph *m_eg;
   log_user m_logger;
   const exploded_node *m_enode_for_diag;
@@ -802,8 +800,6 @@ public:
     return m_worklist.get_scc_id (node);
   }
 
-  void on_escaped_function (tree fndecl);
-
 private:
   void print_bar_charts (pretty_printer *pp) const;
 
@@ -850,10 +846,6 @@ private:
   call_string_data_map_t m_per_call_string_data;
 
   auto_vec<int> m_PK_AFTER_SUPERNODE_per_snode;
-
-  /* Functions with a top-level enode, to make add_function_entry
-     be idempotent, for use in handling callbacks.  */
-  hash_set<function *> m_functions_with_enodes;
 };
 
 /* A path within an exploded_graph: a sequence of edges.  */
diff --git a/gcc/analyzer/region-model-reachability.cc b/gcc/analyzer/region-model-reachability.cc
index 53a87e0dfb2..c1b3b2db630 100644
--- a/gcc/analyzer/region-model-reachability.cc
+++ b/gcc/analyzer/region-model-reachability.cc
@@ -58,9 +58,9 @@ along with GCC; see the file COPYING3.  If not see
 
 namespace ana {
 
-reachable_regions::reachable_regions (region_model *model,
+reachable_regions::reachable_regions (store *store,
 				      region_model_manager *mgr)
-: m_model (model), m_store (model->get_store ()), m_mgr (mgr),
+: m_store (store), m_mgr (mgr),
   m_reachable_base_regs (), m_mutable_base_regs ()
 {
 }
@@ -135,7 +135,7 @@ reachable_regions::add (const region *reg, bool is_mutable)
   if (binding_cluster *bind_cluster = m_store->get_cluster (base_reg))
     bind_cluster->for_each_value (handle_sval_cb, this);
   else
-    handle_sval (m_model->get_store_value (reg));
+    handle_sval (m_mgr->get_or_create_initial_value (base_reg));
 }
 
 void
@@ -208,22 +208,15 @@ reachable_regions::handle_parm (const svalue *sval, tree param_type)
 
 /* Update m_store to mark the clusters that were found to be mutable
    as having escaped.  */
-// TODO
 
 void
-reachable_regions::mark_escaped_clusters (region_model_context *ctxt)
+reachable_regions::mark_escaped_clusters ()
 {
-  gcc_assert (ctxt);
   for (hash_set<const region *>::iterator iter = m_mutable_base_regs.begin ();
        iter != m_mutable_base_regs.end (); ++iter)
     {
       const region *base_reg = *iter;
       m_store->mark_as_escaped (base_reg);
-
-      /* If we have a function that's escaped, potentially add
-	 it to the worklist.  */
-      if (const function_region *fn_reg = base_reg->dyn_cast_function_region ())
-	ctxt->on_escaped_function (fn_reg->get_fndecl ());
     }
 }
 
diff --git a/gcc/analyzer/region-model-reachability.h b/gcc/analyzer/region-model-reachability.h
index 7d551e0a4a2..aba1a58ec7f 100644
--- a/gcc/analyzer/region-model-reachability.h
+++ b/gcc/analyzer/region-model-reachability.h
@@ -35,7 +35,7 @@ namespace ana {
 class reachable_regions
 {
 public:
-  reachable_regions (region_model *model, region_model_manager *mgr);
+  reachable_regions (store *store, region_model_manager *mgr);
 
   /* Callback called for each cluster when initializing this object.  */
   static void init_cluster_cb (const region *base_reg,
@@ -60,8 +60,7 @@ public:
 
   /* Update the store to mark the clusters that were found to be mutable
      as having escaped.  */
-  // TODO
-  void mark_escaped_clusters (region_model_context *ctxt);
+  void mark_escaped_clusters ();
 
   /* Iteration over reachable base regions.  */
   hash_set<const region *>::iterator begin ()
@@ -95,7 +94,6 @@ public:
   DEBUG_FUNCTION void dump () const;
 
 private:
-  region_model *m_model;
   store *m_store;
   region_model_manager *m_mgr;
 
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 258e81b9d65..02cfb6cb8d5 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -836,7 +836,7 @@ region_model::handle_unrecognized_call (const gcall *call,
 {
   tree fndecl = get_fndecl_for_call (call, ctxt);
 
-  reachable_regions reachable_regs (this, m_mgr);
+  reachable_regions reachable_regs (&m_store, m_mgr);
 
   /* Determine the reachable regions and their mutability.  */
   {
@@ -884,7 +884,7 @@ region_model::handle_unrecognized_call (const gcall *call,
     }
 
   /* Mark any clusters that have escaped.  */
-  reachable_regs.mark_escaped_clusters (ctxt);
+  reachable_regs.mark_escaped_clusters ();
 
   /* Update bindings for all clusters that have escaped, whether above,
      or previously.  */
@@ -904,7 +904,7 @@ void
 region_model::get_reachable_svalues (svalue_set *out,
 				     const svalue *extra_sval)
 {
-  reachable_regions reachable_regs (this, m_mgr);
+  reachable_regions reachable_regs (&m_store, m_mgr);
 
   /* Add globals and regions that already escaped in previous
      unknown calls.  */
@@ -1315,6 +1315,28 @@ region_model::called_from_main_p () const
   return id_equal (DECL_NAME (frame0->get_function ()->decl), "main");
 }
 
+/* FIXME.  */
+#if 0
+bool
+region_model::use_initializer_for_global_p (tree decl) const
+{
+  /* Special-case: to avoid having to explicitly update all previously
+     untracked globals when calling an unknown fn, they implicitly have
+     an unknown value if an unknown call has occurred, unless this is
+     static to-this-TU and hasn't escaped.  Globals that have escaped
+     are explicitly tracked, so we shouldn't hit this case for them.  */
+  if (m_store.called_unknown_fn_p () && TREE_PUBLIC (decl))
+    return m_mgr->get_or_create_unknown_svalue (reg->get_type ());
+
+  /* If we are on a path from the entrypoint from "main" and we have a
+     global decl defined in this TU that hasn't been touched yet, then
+     the initial value of REG can be taken from the initialization value
+     of the decl.  */
+  if (called_from_main_p () && !DECL_EXTERNAL (decl))
+
+}
+#endif
+
 /* Subroutine of region_model::get_store_value for when REG is (or is within)
    a global variable that hasn't been touched since the start of this path
    (or was implicitly touched due to a call to an unknown function).  */
@@ -1328,41 +1350,19 @@ region_model::get_initial_value_for_global (const region *reg) const
   gcc_assert (base_reg);
   tree decl = base_reg->get_decl ();
 
-#if 0
-  if (TREE_READONLY (decl))
-    {
-      gcc_unreachable ();
-    }
-#endif
-
-#if 0
-  if (use_initializer_for_global_p (decl))
-    {
-    }
-#endif
-
   /* Special-case: to avoid having to explicitly update all previously
      untracked globals when calling an unknown fn, they implicitly have
      an unknown value if an unknown call has occurred, unless this is
      static to-this-TU and hasn't escaped.  Globals that have escaped
      are explicitly tracked, so we shouldn't hit this case for them.  */
-  if (m_store.called_unknown_fn_p ()
-      && TREE_PUBLIC (decl)
-      && !TREE_READONLY (decl))
+  if (m_store.called_unknown_fn_p () && TREE_PUBLIC (decl))
     return m_mgr->get_or_create_unknown_svalue (reg->get_type ());
 
   /* If we are on a path from the entrypoint from "main" and we have a
      global decl defined in this TU that hasn't been touched yet, then
      the initial value of REG can be taken from the initialization value
      of the decl.  */
-  if ((called_from_main_p () && !DECL_EXTERNAL (decl))
-      || TREE_READONLY (decl))
-#if 0
-    if (const svalue *init_sval = reg->get_svalue_for_any_initializer (m_mgr))
-	return init_sval;
-   // FIXME
-#error
-#else
+  if (called_from_main_p () && !DECL_EXTERNAL (decl))
     {
       /* Get the initializer value for base_reg.  */
       const svalue *base_reg_init
@@ -1387,7 +1387,6 @@ region_model::get_initial_value_for_global (const region *reg) const
 	    }
 	}
     }
-#endif
 
   /* Otherwise, return INIT_VAL(REG).  */
   return m_mgr->get_or_create_initial_value (reg);
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index 8bbec5e76cf..4e8eecbe546 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -1435,6 +1435,8 @@ public:
 
   const complexity &get_complexity () const { return m_complexity; }
 
+  const svalue *get_svalue_for_any_initializer (region_model_manager *mgr) const;
+
  protected:
   region (complexity c, unsigned id, const region *parent, tree type);
 
@@ -2792,9 +2794,6 @@ class region_model_context
      know how to handle the tree code of T at LOC.  */
   virtual void on_unexpected_tree_code (tree t,
 					const dump_location_t &loc) = 0;
-
-  // TODO
-  virtual void on_escaped_function (tree fndecl) = 0;
 };
 
 /* A "do nothing" subclass of region_model_context.  */
@@ -2821,8 +2820,6 @@ public:
   {
   }
   void on_unexpected_tree_code (tree, const dump_location_t &) OVERRIDE {}
-
-  void on_escaped_function (tree) OVERRIDE {}
 };
 
 /* A subclass of region_model_context for determining if operations fail
diff --git a/gcc/testsuite/gcc.dg/analyzer/callbacks-2.c b/gcc/testsuite/gcc.dg/analyzer/callbacks-2.c
index 26844e36189..c5da06c3f46 100644
--- a/gcc/testsuite/gcc.dg/analyzer/callbacks-2.c
+++ b/gcc/testsuite/gcc.dg/analyzer/callbacks-2.c
@@ -6,7 +6,7 @@
 static void callback_1 (void *p)
 {
   free (p);
-  free (p);
+  free (p); /* { dg-warning "double-'free' of 'p'" } */
 }
 
 struct ops {
-- 
2.26.2

