This patch generalizes the optional rewind_info_t associated with an
exploded_edge (for handling longjmp) into a subclass of a new
exploded_edge::custom_info_t abstract base class, so that other kinds
of custom edges can be supported (e.g. to support signal handlers being
called, or possibly to support C++ exceptions, etc)

gcc/ChangeLog:
        * analyzer/analyzer.h (class rewind_info_t): New forward decl.
        * analyzer/checker-path.cc (rewind_event::rewind_event): Update
        assertion.
        (rewind_to_setjmp_event::prepare_for_emission): Update call to
        get_enode_origin.
        * analyzer/checker-path.h
        (rewind_to_setjmp_event::rewind_to_setjmp_event): Add rewind_info
        param and use it to initializer m_rewind_event.
        (rewind_to_setjmp_event::clone): Update for new field.
        (rewind_to_setjmp_event::m_rewind_info): New field.
        * analyzer/diagnostic-manager.cc
        (diagnostic_manager::add_events_for_eedge): Drop src_stack_depth
        local.  Move injection of rewind_from/to_setjmp_event from here
        to rewind_info_t::add_events_to_path, calling it via a vfunc.
        * analyzer/engine.cc: Include "analyzer/checker-path.h".
        (rewind_info_t::update_model): New vfunc.
        (rewind_info_t::add_events_to_path): New vfunc.
        (exploded_edge::exploded_edge): Generalize final param from
        rewind_info_t * to custom_info_t *.
        (exploded_edge::~exploded_edge): Update for renaming of
        m_rewind_info to m_custom_info.
        (exploded_edge::dump_dot): Likewise, replacing hardcode print
        of "rewind" with a call to the custom_info_t::print vfunc.
        (exploded_graph::add_edge): Update final param from
        rewind_info_t * to exploded_edge::custom_info_t *.
        (exploded_path::feasible_p): When logging a rejection due to the
        region model, dump the model.  Move update due to rewind info
        to rewind_info_t::update_model and call it via a vfunc.
        * analyzer/exploded-graph.h (class exploded_edge::custom_info_t):
        New class.
        (exploded_edge::m_rewind_info): Rename to...
        (exploded_edge::m_custom_info): ...this, converting from a
        rewind_info_t * to a custom_info_t *.
        (class rewind_info_t): Make a subclass of
        exploded_edge::custom_info_t.
        (rewind_info_t::print): New vfunc.
        (rewind_info_t::update_model): New vfunc.
        (rewind_info_t::add_events_to_path): New vfunc.
        (exploded_graph::add_edge): Convert final param from
        rewind_info_t * to exploded_edge::custom_info_t *.
---
 gcc/analyzer/analyzer.h            |   1 +
 gcc/analyzer/checker-path.cc       |   4 +-
 gcc/analyzer/checker-path.h        |  10 ++-
 gcc/analyzer/diagnostic-manager.cc |  19 ++----
 gcc/analyzer/engine.cc             | 104 +++++++++++++++++++++--------
 gcc/analyzer/exploded-graph.h      |  85 +++++++++++++++--------
 6 files changed, 148 insertions(+), 75 deletions(-)

diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h
index 90da44b1a00a..19bc2c6d8252 100644
--- a/gcc/analyzer/analyzer.h
+++ b/gcc/analyzer/analyzer.h
@@ -65,6 +65,7 @@ class analysis_plan;
 class state_purge_map;
 class state_purge_per_ssa_name;
 class state_change;
+class rewind_info_t;
 
 ////////////////////////////////////////////////////////////////////////////
 
diff --git a/gcc/analyzer/checker-path.cc b/gcc/analyzer/checker-path.cc
index 0a1840682cd5..d277c2806308 100644
--- a/gcc/analyzer/checker-path.cc
+++ b/gcc/analyzer/checker-path.cc
@@ -705,7 +705,7 @@ rewind_event::rewind_event (const exploded_edge *eedge,
 : checker_event (kind, loc, fndecl, depth),
   m_eedge (eedge)
 {
-  gcc_assert (m_eedge->m_rewind_info);
+  gcc_assert (m_eedge->m_custom_info); // a rewind_info_t
 }
 
 ////////////////////////////////////////////////////////////////////////////
@@ -789,7 +789,7 @@ rewind_to_setjmp_event::prepare_for_emission (checker_path 
*path,
                                              diagnostic_event_id_t emission_id)
 {
   checker_event::prepare_for_emission (path, pd, emission_id);
-  path->get_setjmp_event (get_eedge ()->m_rewind_info->get_enode_origin (),
+  path->get_setjmp_event (m_rewind_info->get_enode_origin (),
                          &m_original_setjmp_event_id);
 }
 
diff --git a/gcc/analyzer/checker-path.h b/gcc/analyzer/checker-path.h
index 916e5a736e3e..ccff8f2ea0bc 100644
--- a/gcc/analyzer/checker-path.h
+++ b/gcc/analyzer/checker-path.h
@@ -428,8 +428,10 @@ class rewind_to_setjmp_event : public rewind_event
 {
 public:
   rewind_to_setjmp_event (const exploded_edge *eedge,
-                         location_t loc, tree fndecl, int depth)
-  : rewind_event (eedge, EK_REWIND_TO_SETJMP, loc, fndecl, depth)
+                         location_t loc, tree fndecl, int depth,
+                         const rewind_info_t *rewind_info)
+  : rewind_event (eedge, EK_REWIND_TO_SETJMP, loc, fndecl, depth),
+    m_rewind_info (rewind_info)
   {
   }
 
@@ -438,7 +440,8 @@ public:
   rewind_to_setjmp_event *clone () const FINAL OVERRIDE
   {
     return new rewind_to_setjmp_event (get_eedge (),
-                                      m_loc, m_fndecl, m_depth);
+                                      m_loc, m_fndecl, m_depth,
+                                      m_rewind_info);
   }
 
   void prepare_for_emission (checker_path *path,
@@ -447,6 +450,7 @@ public:
 
 private:
   diagnostic_event_id_t m_original_setjmp_event_id;
+  const rewind_info_t *m_rewind_info;
 };
 
 /* Concrete subclass of checker_event for use at the end of a path:
diff --git a/gcc/analyzer/diagnostic-manager.cc 
b/gcc/analyzer/diagnostic-manager.cc
index 8cd4507bc6e5..461cc3318b7f 100644
--- a/gcc/analyzer/diagnostic-manager.cc
+++ b/gcc/analyzer/diagnostic-manager.cc
@@ -655,7 +655,6 @@ diagnostic_manager::add_events_for_eedge (const 
exploded_edge &eedge,
 {
   const exploded_node *src_node = eedge.m_src;
   const program_point &src_point = src_node->get_point ();
-  const int src_stack_depth = src_point.get_stack_depth ();
   const exploded_node *dst_node = eedge.m_dest;
   const program_point &dst_point = dst_node->get_point ();
   const int dst_stack_depth = dst_point.get_stack_depth ();
@@ -693,20 +692,10 @@ diagnostic_manager::add_events_for_eedge (const 
exploded_edge &eedge,
   for_each_state_change (src_state, dst_state, ext_state,
                         &visitor);
 
-  /* Add events for rewinding from a longjmp to a setjmp.  */
-  if (eedge.m_rewind_info)
-    {
-      emission_path->add_event
-       (new rewind_from_longjmp_event
-        (&eedge, src_point.get_supernode ()->get_end_location (),
-         src_point.get_fndecl (),
-         src_stack_depth));
-      emission_path->add_event
-       (new rewind_to_setjmp_event
-        (&eedge, eedge.m_rewind_info->get_setjmp_call ()->location,
-         dst_point.get_fndecl (),
-         dst_stack_depth));
-    }
+  /* Allow non-standard edges to add events, e.g. when rewinding from
+     longjmp to a setjmp.  */
+  if (eedge.m_custom_info)
+    eedge.m_custom_info->add_events_to_path (emission_path, eedge);
 
   /* Add events for superedges, function entries, and for statements.  */
   switch (dst_point.get_kind ())
diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index eed2be091c93..d327340c8c28 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -26,6 +26,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gcc-rich-location.h"
 #include "analyzer/exploded-graph.h"
 #include "analyzer/analysis-plan.h"
+#include "analyzer/checker-path.h"
 #include "analyzer/state-purge.h"
 
 /* For an overview, see gcc/doc/analyzer.texi.  */
@@ -1247,6 +1248,66 @@ exploded_node::dump_succs_and_preds (FILE *outf) const
 
 ////////////////////////////////////////////////////////////////////////////
 
+/* class rewind_info_t : public exploded_edge::custom_info_t.  */
+
+/* Implementation of exploded_edge::custom_info_t::update_model vfunc
+   for rewind_info_t.
+
+   Update state for the special-case of a rewind of a longjmp
+   to a setjmp (which doesn't have a superedge, but does affect
+   state).  */
+
+void
+rewind_info_t::update_model (region_model *model,
+                            const exploded_edge &eedge)
+{
+  const exploded_node &src_enode = *eedge.m_src;
+  const program_point &src_point = src_enode.get_point ();
+
+  const gimple *last_stmt
+    = src_point.get_supernode ()->get_last_stmt ();
+  gcc_assert (last_stmt);
+  const gcall *longjmp_call = as_a <const gcall *> (last_stmt);
+
+  const program_point &longjmp_point = eedge.m_src->get_point ();
+  const program_point &setjmp_point = eedge.m_dest->get_point ();
+
+  gcc_assert (longjmp_point.get_stack_depth ()
+             >= setjmp_point.get_stack_depth ());
+
+  model->on_longjmp (longjmp_call,
+                    get_setjmp_call (),
+                    setjmp_point.get_stack_depth (), NULL);
+}
+
+/* Implementation of exploded_edge::custom_info_t::add_events_to_path vfunc
+   for rewind_info_t.  */
+
+void
+rewind_info_t::add_events_to_path (checker_path *emission_path,
+                                  const exploded_edge &eedge)
+{
+  const exploded_node *src_node = eedge.m_src;
+  const program_point &src_point = src_node->get_point ();
+  const int src_stack_depth = src_point.get_stack_depth ();
+  const exploded_node *dst_node = eedge.m_dest;
+  const program_point &dst_point = dst_node->get_point ();
+  const int dst_stack_depth = dst_point.get_stack_depth ();
+
+  emission_path->add_event
+    (new rewind_from_longjmp_event
+     (&eedge, src_point.get_supernode ()->get_end_location (),
+      src_point.get_fndecl (),
+      src_stack_depth));
+  emission_path->add_event
+    (new rewind_to_setjmp_event
+     (&eedge, get_setjmp_call ()->location,
+      dst_point.get_fndecl (),
+      dst_stack_depth, this));
+}
+
+////////////////////////////////////////////////////////////////////////////
+
 /* class exploded_edge : public dedge.  */
 
 /* exploded_edge's ctor.  */
@@ -1254,9 +1315,9 @@ exploded_node::dump_succs_and_preds (FILE *outf) const
 exploded_edge::exploded_edge (exploded_node *src, exploded_node *dest,
                              const superedge *sedge,
                              const state_change &change,
-                             rewind_info_t *rewind_info)
+                             custom_info_t *custom_info)
 : dedge (src, dest), m_sedge (sedge), m_change (change),
-  m_rewind_info (rewind_info)
+  m_custom_info (custom_info)
 {
   change.validate (dest->get_state ());
 }
@@ -1265,7 +1326,7 @@ exploded_edge::exploded_edge (exploded_node *src, 
exploded_node *dest,
 
 exploded_edge::~exploded_edge ()
 {
-  delete m_rewind_info;
+  delete m_custom_info;
 }
 
 /* Implementation of dedge::dump_dot vfunc for exploded_edge.
@@ -1300,7 +1361,7 @@ exploded_edge::dump_dot (graphviz_out *gv, const 
dump_args_t &args) const
        style = "\"dotted\"";
        break;
       }
-  if (m_rewind_info)
+  if (m_custom_info)
     {
       color = "red";
       style = "\"dotted\"";
@@ -1316,8 +1377,8 @@ exploded_edge::dump_dot (graphviz_out *gv, const 
dump_args_t &args) const
 
   if (m_sedge)
     m_sedge->dump_label_to_pp (pp, false);
-  else if (m_rewind_info)
-    pp_string (pp, "rewind");
+  else if (m_custom_info)
+    m_custom_info->print (pp);
 
   m_change.dump (pp, args.m_eg.get_ext_state ());
   //pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
@@ -1859,9 +1920,9 @@ exploded_edge *
 exploded_graph::add_edge (exploded_node *src, exploded_node *dest,
                          const superedge *sedge,
                          const state_change &change,
-                         rewind_info_t *rewind_info)
+                         exploded_edge::custom_info_t *custom_info)
 {
-  exploded_edge *e = new exploded_edge (src, dest, sedge, change, rewind_info);
+  exploded_edge *e = new exploded_edge (src, dest, sedge, change, custom_info);
   digraph::add_edge (e);
   return e;
 }
@@ -2569,7 +2630,10 @@ exploded_path::feasible_p (logger *logger) const
          if (!model.maybe_update_for_edge (*sedge, last_stmt, NULL))
            {
              if (logger)
-               logger->log ("rejecting due to region model");
+               {
+                 logger->log ("rejecting due to region model");
+                 model.dump_to_pp (logger->get_printer (), false);
+               }
              return false;
            }
        }
@@ -2589,26 +2653,8 @@ exploded_path::feasible_p (logger *logger) const
              if (logger)
                logger->log ("  pushing frame for %qD", fun->decl);
            }
-         else if (eedge->m_rewind_info)
-           {
-             /* Update state for the special-case of a rewind of a longjmp
-                to a setjmp (which doesn't have a superedge, but does affect
-                state).  */
-             const gimple *last_stmt
-               = src_point.get_supernode ()->get_last_stmt ();
-             gcc_assert (last_stmt);
-             const gcall *longjmp_call = as_a <const gcall *> (last_stmt);
-
-             const program_point &longjmp_point = eedge->m_src->get_point ();
-             const program_point &setjmp_point = eedge->m_dest->get_point ();
-
-             gcc_assert (longjmp_point.get_stack_depth ()
-                         >= setjmp_point.get_stack_depth ());
-
-             model.on_longjmp (longjmp_call,
-                               eedge->m_rewind_info->get_setjmp_call (),
-                               setjmp_point.get_stack_depth (), NULL);
-           }
+         else if (eedge->m_custom_info)
+           eedge->m_custom_info->update_model (&model, *eedge);
        }
 
       /* Handle phi nodes on an edge leaving a PK_BEFORE_SUPERNODE (to
diff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h
index c8e36f25a575..26ae109628f4 100644
--- a/gcc/analyzer/exploded-graph.h
+++ b/gcc/analyzer/exploded-graph.h
@@ -252,16 +252,73 @@ public:
   const int m_index;
 };
 
+/* An edge within the exploded graph.
+   Some exploded_edges have an underlying superedge; others don't.  */
+
+class exploded_edge : public dedge<eg_traits>
+{
+ public:
+  /* Abstract base class for associating custom data with an
+     exploded_edge, for handling non-standard edges such as
+     rewinding from a longjmp, signal handlers, etc.  */
+  class custom_info_t
+  {
+  public:
+    virtual ~custom_info_t () {}
+
+    /* Hook for making .dot label more readable .  */
+    virtual void print (pretty_printer *pp) = 0;
+
+    /* Hook for updating MODEL within exploded_path::feasible_p.  */
+    virtual void update_model (region_model *model,
+                              const exploded_edge &eedge) = 0;
+
+    virtual void add_events_to_path (checker_path *emission_path,
+                                    const exploded_edge &eedge) = 0;
+  };
+
+  exploded_edge (exploded_node *src, exploded_node *dest,
+                const superedge *sedge,
+                const state_change &change,
+                custom_info_t *custom_info);
+  ~exploded_edge ();
+  void dump_dot (graphviz_out *gv, const dump_args_t &args)
+    const FINAL OVERRIDE;
+
+  //private:
+  const superedge *const m_sedge;
+
+  const state_change m_change;
+
+  /* NULL for most edges; will be non-NULL for special cases
+     such as an unwind from a longjmp to a setjmp, or when
+     a signal is delivered to a signal-handler.
+
+     Owned by this class.  */
+  custom_info_t *m_custom_info;
+};
+
 /* Extra data for an exploded_edge that represents a rewind from a
    longjmp to a setjmp.  */
 
-class rewind_info_t
+class rewind_info_t : public exploded_edge::custom_info_t
 {
 public:
   rewind_info_t (const exploded_node *enode_origin)
   : m_enode_origin (enode_origin)
   {}
 
+  void print (pretty_printer *pp) FINAL OVERRIDE
+  {
+    pp_string (pp, "rewind");
+  }
+
+  void update_model (region_model *model,
+                    const exploded_edge &eedge) FINAL OVERRIDE;
+
+  void add_events_to_path (checker_path *emission_path,
+                          const exploded_edge &eedge) FINAL OVERRIDE;
+
   const program_point &get_setjmp_point () const
   {
     const program_point &origin_point = m_enode_origin->get_point ();
@@ -285,30 +342,6 @@ private:
   const exploded_node *m_enode_origin;
 };
 
-/* An edge within the exploded graph.
-   Some exploded_edges have an underlying superedge; others don't.  */
-
-class exploded_edge : public dedge<eg_traits>
-{
- public:
-  exploded_edge (exploded_node *src, exploded_node *dest,
-                const superedge *sedge,
-                const state_change &change,
-                rewind_info_t *rewind_info);
-  ~exploded_edge ();
-  void dump_dot (graphviz_out *gv, const dump_args_t &args)
-    const FINAL OVERRIDE;
-
-  //private:
-  const superedge *const m_sedge;
-
-  const state_change m_change;
-
-  /* NULL for most edges; will be non-NULL for an unwind from a longjmp
-     to a setjmp (owned by this class).  */
-  rewind_info_t *m_rewind_info;
-};
-
 /* Statistics about aspects of an exploded_graph.  */
 
 struct stats
@@ -665,7 +698,7 @@ public:
   exploded_edge *add_edge (exploded_node *src, exploded_node *dest,
                           const superedge *sedge,
                           const state_change &change,
-                          rewind_info_t *rewind_info = NULL);
+                          exploded_edge::custom_info_t *custom = NULL);
 
   per_program_point_data *
   get_or_create_per_program_point_data (const program_point &);
-- 
2.21.0

Reply via email to