From c945c3045666edfe4ae06d7cb322cba30c322378 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 24 Jun 2020 16:34:04 -0400
Subject: [PATCH 249/315] FIXME: move reachable_region2s to its own .h and .cc
 files

---
 gcc/Makefile.in               |   1 +
 gcc/analyzer/reachable.cc     | 263 ++++++++++++++++++++++++++++++++++
 gcc/analyzer/reachable.h      | 115 +++++++++++++++
 gcc/analyzer/region-model2.cc | 212 +--------------------------
 gcc/analyzer/region-model2.h  |   2 +-
 5 files changed, 381 insertions(+), 212 deletions(-)
 create mode 100644 gcc/analyzer/reachable.cc
 create mode 100644 gcc/analyzer/reachable.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 4c68e3a087d..e731025f0c8 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1233,6 +1233,7 @@ ANALYZER_OBJS = \
 	analyzer/pending-diagnostic.o \
 	analyzer/program-point.o \
 	analyzer/program-state.o \
+	analyzer/reachable.o \
 	analyzer/region-model.o \
 	analyzer/region-model2.o \
 	analyzer/sm.o \
diff --git a/gcc/analyzer/reachable.cc b/gcc/analyzer/reachable.cc
new file mode 100644
index 00000000000..f325b4392b1
--- /dev/null
+++ b/gcc/analyzer/reachable.cc
@@ -0,0 +1,263 @@
+/* Finding reachable regions and values.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@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/>.  */
+
+// TODO: purge this:
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "function.h"
+#include "basic-block.h"
+#include "gimple.h"
+#include "gimple-iterator.h"
+#include "diagnostic-core.h"
+#include "graphviz.h"
+#include "options.h"
+#include "cgraph.h"
+#include "tree-dfa.h"
+#include "stringpool.h"
+#include "convert.h"
+#include "target.h"
+#include "fold-const.h"
+#include "tree-pretty-print.h"
+#include "diagnostic-color.h"
+#include "diagnostic-metadata.h"
+#include "tristate.h"
+#include "bitmap.h"
+#include "selftest.h"
+#include "function.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/analyzer-logging.h"
+#include "ordered-hash-map.h"
+#include "options.h"
+#include "cgraph.h"
+#include "cfg.h"
+#include "digraph.h"
+#include "analyzer/supergraph.h"
+#include "sbitmap.h"
+#include "analyzer/region-model2.h"
+#include "analyzer/constraint-manager2.h"
+#include "diagnostic-event-id.h"
+#include "analyzer/sm.h"
+#include "diagnostic-event-id.h"
+#include "analyzer/sm.h"
+#include "analyzer/pending-diagnostic.h"
+#include "analyzer/reachable.h"
+#include "analyzer/analyzer-selftests.h"
+#include "stor-layout.h"
+#include "value-range.h" // for tree-ssanames.h
+#include "gimple-ssa.h" // for struct gimple_df in FOR_EACH_SSA_NAME
+#include "tree-ssanames.h" // for FOR_EACH_SSA_NAME
+
+#if ENABLE_ANALYZER
+
+namespace ana {
+
+reachable_region2s::reachable_region2s (store2 *store,
+					region_model2_manager *mgr)
+: m_store (store), m_mgr (mgr), m_reachable_regs (), m_mutable_regs ()
+{
+}
+
+/* Callback called for each cluster when initializing this object.  */
+
+void
+reachable_region2s::init_cluster_cb (const region2 *base_reg,
+				     reachable_region2s *this_ptr)
+{
+  this_ptr->init_cluster (base_reg);
+}
+
+/* Called for each cluster when initializing this object.  */
+void
+reachable_region2s::init_cluster (const region2 *base_reg)
+{
+  /* Mark any globals as mutable (and traverse what they point to).  */
+  const region2 *parent = base_reg->get_parent_region ();
+  gcc_assert (parent);
+  if (parent->get_kind () == region2::RK_GLOBALS)
+    add (base_reg, true);
+
+  /* Mark any clusters that already escaped in previous unknown calls
+     as mutable (and traverse what they currently point to).  */
+  if (m_store->escaped_p (base_reg))
+    add (base_reg, true);
+}
+
+  /* Lazily mark the cluster containing REG as being reachable, recursively
+     adding clusters reachable from REG's cluster.  */
+void
+reachable_region2s::add (const region2 *reg, bool is_mutable)
+{
+  gcc_assert (reg);
+
+  const region2 *base_reg = const_cast <region2 *> (reg->get_base_region ());
+  gcc_assert (base_reg);
+
+  /* Bail out if this cluster is already in the sets at the IS_MUTABLE
+     level of mutability.  */
+  if (!is_mutable && m_reachable_regs.contains (base_reg))
+    return;
+  m_reachable_regs.add (base_reg);
+
+  if (is_mutable)
+    {
+      if (m_mutable_regs.contains (base_reg))
+	return;
+      else
+	m_mutable_regs.add (base_reg);
+    }
+
+  /* Add values within the cluster.  If any are pointers, add the pointee.  */
+  if (binding_cluster2 *bind_cluster = m_store->get_cluster (base_reg))
+    bind_cluster->for_each_value (handle_sval_cb, this);
+  else
+    handle_sval (m_mgr->get_or_create_initial_value (base_reg));
+}
+
+void
+reachable_region2s::handle_sval_cb (const svalue2 *sval,
+				    reachable_region2s *this_ptr)
+{
+  this_ptr->handle_sval (sval);
+}
+
+/* Add SVAL.  If it is a pointer, add the pointed-to region.  */
+
+void
+reachable_region2s::handle_sval (const svalue2 *sval)
+{
+  m_reachable_svals.add (sval);
+  if (const region_svalue2 *ptr = sval->dyn_cast_region_svalue2 ())
+    {
+      const region2 *pointee = ptr->get_pointee ();
+      /* Use const-ness of pointer type to affect mutability.  */
+      bool ptr_is_mutable = true;
+      if (ptr->get_type ()
+	  && TREE_CODE (ptr->get_type ()) == POINTER_TYPE
+	  && TYPE_READONLY (TREE_TYPE (ptr->get_type ())))
+	{
+	  ptr_is_mutable = false;
+	  m_mutable_svals.add (sval);
+	}
+      add (pointee, ptr_is_mutable);
+    }
+}
+
+/* Add SVAL.  If it is a pointer, add the pointed-to region.
+   Use PARAM_TYPE for determining mutability.  */
+
+void
+reachable_region2s::handle_parm (const svalue2 *sval, tree param_type)
+{
+  bool is_mutable = true;
+  if (param_type
+      && TREE_CODE (param_type) == POINTER_TYPE
+      &&  TYPE_READONLY (TREE_TYPE (param_type)))
+    is_mutable = false;
+  if (is_mutable)
+    m_mutable_svals.add (sval);
+  else
+    m_reachable_svals.add (sval);
+  if (const region_svalue2 *parm_ptr
+      = sval->dyn_cast_region_svalue2 ())
+    {
+      const region2 *pointee_reg = parm_ptr->get_pointee ();
+      add (pointee_reg, is_mutable);
+    }
+}
+
+/* Update m_store to set the clusters that were found to be mutable
+   to "unknown" values.  */
+
+void
+reachable_region2s::update_bindings (store2_manager *mgr)
+{
+  for (hash_set<const region2 *>::iterator iter = m_mutable_regs.begin ();
+       iter != m_mutable_regs.end (); ++iter)
+    {
+      const region2 *base_reg = *iter;
+      m_store->on_escape_to_unknown_fncall (mgr, base_reg);
+    }
+}
+
+void
+reachable_region2s::dump_to_pp (pretty_printer *pp) const
+{
+  pp_string (pp, "reachable clusters: ");
+  pp_newline (pp);
+  for (hash_set<const region2 *>::iterator iter = m_reachable_regs.begin ();
+       iter != m_reachable_regs.end (); ++iter)
+    {
+      pp_string (pp, "  ");
+      (*iter)->dump_to_pp (pp, true);
+      pp_newline (pp);
+    }
+  pp_string (pp, "mutable clusters: ");
+  pp_newline (pp);
+  for (hash_set<const region2 *>::iterator iter = m_mutable_regs.begin ();
+       iter != m_mutable_regs.end (); ++iter)
+    {
+      pp_string (pp, "  ");
+      (*iter)->dump_to_pp (pp, true);
+      pp_newline (pp);
+    }
+  pp_string (pp, "mutable svals: ");
+  pp_newline (pp);
+  for (hash_set<const svalue2 *>::iterator iter = m_mutable_svals.begin ();
+       iter != m_mutable_svals.end (); ++iter)
+    {
+      pp_string (pp, "  ");
+      (*iter)->dump_to_pp (pp, true);
+      pp_newline (pp);
+    }
+}
+
+DEBUG_FUNCTION void
+reachable_region2s::dump () const
+{
+  pretty_printer pp;
+  pp_format_decoder (&pp) = default_tree_printer;
+  pp_show_color (&pp) = pp_show_color (global_dc->printer);
+  pp.buffer->stream = stderr;
+  dump_to_pp (&pp);
+  pp_flush (&pp);
+}
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Run all of the selftests within this file.  */
+
+void
+analyzer_reachable_cc_tests ()
+{
+  // TODO; not yet called
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
+
+} // namespace ana
+
+#endif /* #if ENABLE_ANALYZER */
diff --git a/gcc/analyzer/reachable.h b/gcc/analyzer/reachable.h
new file mode 100644
index 00000000000..b8d83e82ff4
--- /dev/null
+++ b/gcc/analyzer/reachable.h
@@ -0,0 +1,115 @@
+/* Finding reachable regions and values.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@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/>.  */
+
+#ifndef GCC_ANALYZER_REACHABLE_H
+#define GCC_ANALYZER_REACHABLE_H
+
+namespace ana {
+
+/* Helper class for region_model2::handle_unrecognized_call, for keeping
+   track of all region2s that are reachable, and, of those, which are
+   mutable.
+   FIXME: also for detecting leaks.  */
+
+class reachable_region2s
+{
+public:
+  reachable_region2s (store2 *store, region_model2_manager *mgr);
+
+  /* Callback called for each cluster when initializing this object.  */
+  static void init_cluster_cb (const region2 *base_reg,
+			       reachable_region2s *this_ptr);
+
+  /* Called for each cluster when initializing this object.  */
+  void init_cluster (const region2 *base_reg);
+
+  /* Lazily mark the cluster containing REG as being reachable, recursively
+     adding clusters reachable from REG's cluster.  */
+  void add (const region2 *reg, bool is_mutable);
+
+  static void handle_sval_cb (const svalue2 *sval,
+			      reachable_region2s *this_ptr);
+
+  /* Add SVAL.  If it is a pointer, add the pointed-to region.  */
+  void handle_sval (const svalue2 *sval);
+
+  /* Add SVAL.  If it is a pointer, add the pointed-to region.
+     Use PARAM_TYPE for determining mutability.  */
+  void handle_parm (const svalue2 *sval, tree param_type);
+
+  /* Update m_store to set the clusters that were found to be mutable
+     to "unknown" values.  */
+
+  void update_bindings (store2_manager *mgr);
+
+  /* Iteration over reachable regions.  */
+  hash_set<const region2 *>::iterator begin ()
+  {
+    return m_reachable_regs.begin ();
+  }
+  hash_set<const region2 *>::iterator end ()
+  {
+    return m_reachable_regs.end ();
+  }
+
+  hash_set<const svalue2 *>::iterator begin_reachable_svals ()
+  {
+    return m_reachable_svals.begin ();
+  }
+  hash_set<const svalue2 *>::iterator end_reachable_svals ()
+  {
+    return m_reachable_svals.end ();
+  }
+  hash_set<const svalue2 *>::iterator begin_mutable_svals ()
+  {
+    return m_mutable_svals.begin ();
+  }
+  hash_set<const svalue2 *>::iterator end_mutable_svals ()
+  {
+    return m_mutable_svals.end ();
+  }
+
+  void dump_to_pp (pretty_printer *pp) const;
+
+  DEBUG_FUNCTION void dump () const;
+
+private:
+  store2 *m_store;
+  region_model2_manager *m_mgr;
+
+  // FIXME: actually, the clusters
+  /* The regions already seen.  */
+  hash_set<const region2 *> m_reachable_regs;
+
+  /* The regions that can be changed (accessed via non-const pointers).  */
+  hash_set<const region2 *> m_mutable_regs;
+
+  /* svalues that were passed as const pointers, so e.g. couldn't have
+     been freed (but could have e.g. had "close" called on them if an
+     int file-descriptor).  */
+  hash_set<const svalue2 *> m_reachable_svals;
+  /* svalues that were passed as non-const pointers, so e.g. could have
+     been freed.  */
+  hash_set<const svalue2 *> m_mutable_svals;
+};
+
+} // namespace ana
+
+#endif /* GCC_ANALYZER_REACHABLE_H */
diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc
index 5edf1c1556f..b7043a0514a 100644
--- a/gcc/analyzer/region-model2.cc
+++ b/gcc/analyzer/region-model2.cc
@@ -58,6 +58,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic-event-id.h"
 #include "analyzer/sm.h"
 #include "analyzer/pending-diagnostic.h"
+#include "analyzer/reachable.h"
 #include "analyzer/analyzer-selftests.h"
 #include "stor-layout.h"
 #include "value-range.h" // for tree-ssanames.h
@@ -5135,217 +5136,6 @@ region_model2::impl_call_strlen (const call_details &cd)
   return true;
 }
 
-/* Helper class for region_model2::handle_unrecognized_call, for keeping
-   track of all region2s that are reachable, and, of those, which are
-   mutable.
-   FIXME: also for detecting leaks.  */
-
-class reachable_region2s
-{
-public:
-  reachable_region2s (store2 *store, region_model2_manager *mgr)
-  : m_store (store), m_mgr (mgr), m_reachable_regs (), m_mutable_regs ()
-  {}
-
-  /* Callback called for each cluster when initializing this object.  */
-  static void init_cluster_cb (const region2 *base_reg,
-			       reachable_region2s *this_ptr)
-  {
-    this_ptr->init_cluster (base_reg);
-  }
-
-  /* Called for each cluster when initializing this object.  */
-  void init_cluster (const region2 *base_reg)
-  {
-    /* Mark any globals as mutable (and traverse what they point to).  */
-    const region2 *parent = base_reg->get_parent_region ();
-    gcc_assert (parent);
-    if (parent->get_kind () == region2::RK_GLOBALS)
-      add (base_reg, true);
-
-    /* Mark any clusters that already escaped in previous unknown calls
-       as mutable (and traverse what they currently point to).  */
-    if (m_store->escaped_p (base_reg))
-      add (base_reg, true);
-  }
-
-  /* Lazily mark the cluster containing REG as being reachable, recursively
-     adding clusters reachable from REG's cluster.  */
-  void add (const region2 *reg, bool is_mutable)
-  {
-    gcc_assert (reg);
-
-    const region2 *base_reg = const_cast <region2 *> (reg->get_base_region ());
-    gcc_assert (base_reg);
-
-    /* Bail out if this cluster is already in the sets at the IS_MUTABLE
-       level of mutability.  */
-    if (!is_mutable && m_reachable_regs.contains (base_reg))
-      return;
-    m_reachable_regs.add (base_reg);
-
-    if (is_mutable)
-      {
-	if (m_mutable_regs.contains (base_reg))
-	  return;
-	else
-	  m_mutable_regs.add (base_reg);
-      }
-
-    /* Add values within the cluster.  If any are pointers, add the pointee.  */
-    if (binding_cluster2 *bind_cluster = m_store->get_cluster (base_reg))
-      bind_cluster->for_each_value (handle_sval_cb, this);
-    else
-      handle_sval (m_mgr->get_or_create_initial_value (base_reg));
-  }
-
-  static void handle_sval_cb (const svalue2 *sval, reachable_region2s *this_ptr)
-  {
-    this_ptr->handle_sval (sval);
-  }
-
-  /* Add SVAL.  If it is a pointer, add the pointed-to region.  */
-  void handle_sval (const svalue2 *sval)
-  {
-    m_reachable_svals.add (sval);
-    if (const region_svalue2 *ptr = sval->dyn_cast_region_svalue2 ())
-      {
-	const region2 *pointee = ptr->get_pointee ();
-	/* Use const-ness of pointer type to affect mutability.  */
-	bool ptr_is_mutable = true;
-	if (ptr->get_type ()
-	    && TREE_CODE (ptr->get_type ()) == POINTER_TYPE
-	    && TYPE_READONLY (TREE_TYPE (ptr->get_type ())))
-	  {
-	    ptr_is_mutable = false;
-	    m_mutable_svals.add (sval);
-	  }
-	add (pointee, ptr_is_mutable);
-      }
-  }
-
-  /* Add SVAL.  If it is a pointer, add the pointed-to region.
-     Use PARAM_TYPE for determining mutability.  */
-  void handle_parm (const svalue2 *sval, tree param_type)
-  {
-    bool is_mutable = true;
-    if (param_type
-	&& TREE_CODE (param_type) == POINTER_TYPE
-	    &&  TYPE_READONLY (TREE_TYPE (param_type)))
-      is_mutable = false;
-    if (is_mutable)
-      m_mutable_svals.add (sval);
-    else
-      m_reachable_svals.add (sval);
-    if (const region_svalue2 *parm_ptr
-	= sval->dyn_cast_region_svalue2 ())
-      {
-	const region2 *pointee_reg = parm_ptr->get_pointee ();
-	add (pointee_reg, is_mutable);
-      }
-  }
-
-  /* Update m_store to set the clusters that were found to be mutable
-     to "unknown" values.  */
-
-  void update_bindings (store2_manager *mgr)
-  {
-    for (hash_set<const region2 *>::iterator iter = m_mutable_regs.begin ();
-	 iter != m_mutable_regs.end (); ++iter)
-      {
-	const region2 *base_reg = *iter;
-	m_store->on_escape_to_unknown_fncall (mgr, base_reg);
-      }
-  }
-
-  /* Iteration over reachable regions.  */
-  hash_set<const region2 *>::iterator begin ()
-  {
-    return m_reachable_regs.begin ();
-  }
-  hash_set<const region2 *>::iterator end ()
-  {
-    return m_reachable_regs.end ();
-  }
-
-  hash_set<const svalue2 *>::iterator begin_reachable_svals ()
-  {
-    return m_reachable_svals.begin ();
-  }
-  hash_set<const svalue2 *>::iterator end_reachable_svals ()
-  {
-    return m_reachable_svals.end ();
-  }
-  hash_set<const svalue2 *>::iterator begin_mutable_svals ()
-  {
-    return m_mutable_svals.begin ();
-  }
-  hash_set<const svalue2 *>::iterator end_mutable_svals ()
-  {
-    return m_mutable_svals.end ();
-  }
-
-  void dump_to_pp (pretty_printer *pp) const
-  {
-    pp_string (pp, "reachable clusters: ");
-    pp_newline (pp);
-    for (hash_set<const region2 *>::iterator iter = m_reachable_regs.begin ();
-	 iter != m_reachable_regs.end (); ++iter)
-      {
-	pp_string (pp, "  ");
-	(*iter)->dump_to_pp (pp, true);
-	pp_newline (pp);
-      }
-    pp_string (pp, "mutable clusters: ");
-    pp_newline (pp);
-    for (hash_set<const region2 *>::iterator iter = m_mutable_regs.begin ();
-	 iter != m_mutable_regs.end (); ++iter)
-      {
-	pp_string (pp, "  ");
-	(*iter)->dump_to_pp (pp, true);
-	pp_newline (pp);
-      }
-    pp_string (pp, "mutable svals: ");
-    pp_newline (pp);
-    for (hash_set<const svalue2 *>::iterator iter = m_mutable_svals.begin ();
-	 iter != m_mutable_svals.end (); ++iter)
-      {
-	pp_string (pp, "  ");
-	(*iter)->dump_to_pp (pp, true);
-	pp_newline (pp);
-      }
-  }
-
-  DEBUG_FUNCTION void dump () const
-  {
-    pretty_printer pp;
-    pp_format_decoder (&pp) = default_tree_printer;
-    pp_show_color (&pp) = pp_show_color (global_dc->printer);
-    pp.buffer->stream = stderr;
-    dump_to_pp (&pp);
-    pp_flush (&pp);
-  }
-
-private:
-  store2 *m_store;
-  region_model2_manager *m_mgr;
-
-  // FIXME: actually, the clusters
-  /* The regions already seen.  */
-  hash_set<const region2 *> m_reachable_regs;
-
-  /* The regions that can be changed (accessed via non-const pointers).  */
-  hash_set<const region2 *> m_mutable_regs;
-
-  /* svalues that were passed as const pointers, so e.g. couldn't have
-     been freed (but could have e.g. had "close" called on them if an
-     int file-descriptor).  */
-  hash_set<const svalue2 *> m_reachable_svals;
-  /* svalues that were passed as non-const pointers, so e.g. could have
-     been freed.  */
-  hash_set<const svalue2 *> m_mutable_svals;
-};
-
 /* Handle a call CALL to a function with unknown behavior.
 
    Traverse the region2s in this model, determining what region2s are
diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h
index 70f98cae282..967b8734d94 100644
--- a/gcc/analyzer/region-model2.h
+++ b/gcc/analyzer/region-model2.h
@@ -2492,7 +2492,7 @@ public:
 		     tree rhs ATTRIBUTE_UNUSED) OVERRIDE
   {
   }
-  void on_unknown_change (const svalue2 *sval, ATTRIBUTE_UNUSED
+  void on_unknown_change (const svalue2 *sval ATTRIBUTE_UNUSED,
 			  bool is_mutable ATTRIBUTE_UNUSED) OVERRIDE
   {
   }
-- 
2.26.2

