From 39b1f0b6688d0358a0749302ce269fde2815ebce Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 30 Apr 2019 14:39:49 -0400
Subject: [PATCH 215/217] FIXME: impl-4: capture origins of states

---
 gcc/analyzer/constraints.cc |   2 +
 gcc/analyzer/impl-4.cc      | 109 +++++++++++++++++++++++++++++---------------
 2 files changed, 75 insertions(+), 36 deletions(-)

diff --git a/gcc/analyzer/constraints.cc b/gcc/analyzer/constraints.cc
index cad4dab..14965b8 100644
--- a/gcc/analyzer/constraints.cc
+++ b/gcc/analyzer/constraints.cc
@@ -46,6 +46,8 @@
 std::string
 path_var::to_str () const
 {
+  if (m_tree == NULL_TREE)
+    return "NULL";
   if (CONSTANT_CLASS_P (m_tree))
     return expr_to_string (m_tree);
   else
diff --git a/gcc/analyzer/impl-4.cc b/gcc/analyzer/impl-4.cc
index 04b5895..0ecb2c0 100644
--- a/gcc/analyzer/impl-4.cc
+++ b/gcc/analyzer/impl-4.cc
@@ -281,12 +281,23 @@ pod_hash_traits<path_var>::is_empty (value_type v)
 
 namespace impl_4 {
 
-/* Map from var to state machine state.  */
+/* Map from var to state machine state, also capturing the origin of
+   each state.  */
 
 class sm_state_map
 {
 public:
-  typedef hash_map <path_var, state_machine::state_t> map_t;
+  struct entry_t
+  {
+    entry_t (state_machine::state_t state,
+	     path_var origin)
+    : m_state (state), m_origin (origin)
+    {}
+
+    state_machine::state_t m_state;
+    path_var m_origin;
+  };
+  typedef hash_map <path_var, entry_t> map_t;
   typedef map_t::iterator iterator_t;
 
   sm_state_map *clone () const;
@@ -296,17 +307,22 @@ public:
   bool is_empty_p () const;
 
   state_machine::state_t get_state (path_var pv) const;
-  void set_state (path_state *ps, path_var pv, state_machine::state_t state);
-  void set_state (const equiv_class &ec, state_machine::state_t state);
-  void impl_set_state (path_var pv, state_machine::state_t state);
+  path_var get_origin (path_var pv) const;
 
-  iterator_t begin () const { return m_var_to_state.begin (); }
-  iterator_t end () const { return m_var_to_state.end (); }
-
-  //private:
-  map_t m_var_to_state;
+  void set_state (path_state *ps, path_var pv, state_machine::state_t state,
+		  path_var origin);
+  void set_state (const equiv_class &ec,
+		  state_machine::state_t state,
+		  path_var origin);
+  void impl_set_state (path_var pv,
+		       state_machine::state_t state,
+		       path_var origin);
 
+  iterator_t begin () const { return m_map.begin (); }
+  iterator_t end () const { return m_map.end (); }
 
+  //private:
+  map_t m_map;
 };
 
 /* FIXME.  */
@@ -1168,15 +1184,17 @@ void
 sm_state_map::print (const state_machine &sm, pretty_printer *pp) const
 {
   pp_string (pp, "{");
-  for (map_t::iterator iter = m_var_to_state.begin ();
-       iter != m_var_to_state.end ();
+  for (map_t::iterator iter = m_map.begin ();
+       iter != m_map.end ();
        ++iter)
     {
-      if (iter != m_var_to_state.begin ())
+      if (iter != m_map.begin ())
 	pp_string (pp, ", ");
-      pp_printf (pp, "%s: %s",
+      entry_t e = (*iter).second;
+      pp_printf (pp, "%s: %s (origin: %s)",
 		 (*iter).first.to_str ().c_str (),
-		 sm.get_state_name ((*iter).second));
+		 sm.get_state_name (e.m_state),
+		 e.m_origin.to_str ().c_str ());
     }
 
   // TODO
@@ -1186,54 +1204,66 @@ sm_state_map::print (const state_machine &sm, pretty_printer *pp) const
 bool
 sm_state_map::is_empty_p () const
 {
-  return m_var_to_state.elements () == 0;
+  return m_map.elements () == 0;
 }
 
 state_machine::state_t
 sm_state_map::get_state (path_var pv) const
 {
-  if (state_machine::state_t *slot
-      = const_cast <map_t &> (m_var_to_state).get (pv))
-    return *slot;
+  if (entry_t *slot
+      = const_cast <map_t &> (m_map).get (pv))
+    return slot->m_state;
   else
     return 0;
 }
 
+path_var
+sm_state_map::get_origin (path_var pv) const
+{
+  entry_t *slot
+    = const_cast <map_t &> (m_map).get (pv);
+  gcc_assert (slot);
+  return slot->m_origin;
+}
+
 /* FIXME.  */
 
 void
 sm_state_map::set_state (path_state *ps,
 			 path_var pv,
-			 state_machine::state_t state)
+			 state_machine::state_t state,
+			 path_var origin)
 {
   equiv_class &ec = ps->get_equiv_class (pv);
-  set_state (ec, state);
+  set_state (ec, state, origin);
 }
 
 /* FIXME.  */
 
 void
-sm_state_map::set_state (const equiv_class &ec, state_machine::state_t state)
+sm_state_map::set_state (const equiv_class &ec, state_machine::state_t state,
+			 path_var origin)
 {
   int i;
   path_var *pv;
   FOR_EACH_VEC_ELT (ec.m_vars, i, pv)
-    impl_set_state (*pv, state);
+    impl_set_state (*pv, state, origin);
 }
 
 /* Set state of PV to STATE, bypassing equivalend classes.  */
 
 void
-sm_state_map::impl_set_state (path_var pv, state_machine::state_t state)
+sm_state_map::impl_set_state (path_var pv, state_machine::state_t state,
+			      path_var origin)
 {
   /* Special-case state 0 as the default value.  */
   if (state == 0)
     {
-      if (m_var_to_state.get (pv))
-	m_var_to_state.remove (pv);
+      if (m_map.get (pv))
+	m_map.remove (pv);
       return;
     }
-  m_var_to_state.put (pv, state);
+  m_map.put (pv, entry_t (state, origin));
 }
 
 ////////////////////////////////////////////////////////////////////////////
@@ -1267,7 +1297,8 @@ public:
     path_var pv (var, 0); // FIXME: stack depth
     state_machine::state_t current = m_old_smap.get_state (pv);
     if (current == from)
-      m_new_smap->set_state (&m_new_state->m_path_state, pv, to);
+      m_new_smap->set_state (&m_new_state->m_path_state, pv, to,
+			     path_var (origin, 0)/* FIXME: stack */);
   }
 
   void warn_for_state (const supernode *node, const gimple *stmt,
@@ -1636,7 +1667,7 @@ exploded_node::on_assignment (const exploded_graph &eg,
       const sm_state_map *src_smap = old_state.m_checker_states[i];
       sm_state_map *dst_smap = new_state->m_checker_states[i];
       state_machine::state_t rhs_state = src_smap->get_state (rhs);
-      dst_smap->set_state (&new_state->m_path_state, lhs, rhs_state);
+      dst_smap->set_state (&new_state->m_path_state, lhs, rhs_state, rhs);
       if (eg.get_logger ())
 	eg.log ("%s: copying state %qs to %s from %s",
 		sm.get_name (),
@@ -2057,7 +2088,7 @@ exploded_graph::emit_diagnostic (const state_machine &sm,
 	       ++iter)
 	    {
 	      path_var pv = (*iter).first;
-	      state_machine::state_t dst_sm_val = (*iter).second;
+	      state_machine::state_t dst_sm_val = (*iter).second.m_state;
 	      state_machine::state_t src_sm_val = src_smap.get_state (pv);
 	      if (dst_sm_val != src_sm_val)
 		emission_path.add_event
@@ -2068,8 +2099,7 @@ exploded_graph::emit_diagnostic (const state_machine &sm,
 					   pv.m_tree,
 					   src_sm_val,
 					   dst_sm_val,
-					   // FIXME:
-					   NULL_TREE)); /*tree origin */
+					   (*iter).second.m_origin.m_tree));
 	    }
 	}
     }
@@ -2761,8 +2791,12 @@ test_sm_state_map ()
   tree y = build_decl (UNKNOWN_LOCATION, PARM_DECL,
 		       get_identifier ("y"),
 		       integer_type_node);
+  tree z = build_decl (UNKNOWN_LOCATION, PARM_DECL,
+		       get_identifier ("z"),
+		       integer_type_node);
   path_var x0 (x, 0);
   path_var y0 (y, 0);
+  path_var z0 (z, 0);
 
   /* Test setting states on path_var instances directly.  */
   {
@@ -2770,15 +2804,16 @@ test_sm_state_map ()
     ASSERT_TRUE (map.is_empty_p ());
     ASSERT_EQ (map.get_state (x0), 0);
 
-    map.impl_set_state (x0, 42);
+    map.impl_set_state (x0, 42, z0);
     ASSERT_EQ (map.get_state (x0), 42);
+    ASSERT_EQ (map.get_origin (x0), z0);
     ASSERT_EQ (map.get_state (y0), 0);
     ASSERT_FALSE (map.is_empty_p ());
 
-    map.impl_set_state (y0, 0);
+    map.impl_set_state (y0, 0, z0);
     ASSERT_EQ (map.get_state (y0), 0);
 
-    map.impl_set_state (x0, 0);
+    map.impl_set_state (x0, 0, z0);
     ASSERT_EQ (map.get_state (x0), 0);
     ASSERT_TRUE (map.is_empty_p ());
   }
@@ -2795,9 +2830,11 @@ test_sm_state_map ()
 
     /* Setting x to a state should also update y, as they
        are in the same equivalence class.  */
-    map.set_state (&ps, x0, 5);
+    map.set_state (&ps, x0, 5, z0);
     ASSERT_EQ (map.get_state (x0), 5);
     ASSERT_EQ (map.get_state (y0), 5);
+    ASSERT_EQ (map.get_origin (x0), z0);
+    ASSERT_EQ (map.get_origin (y0), z0);
   }
 }
 
-- 
1.8.5.3

