From 6d9dfa005de631fe569eceb9478c2bae316e2926 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 4 Aug 2020 14:01:13 -0400
Subject: [PATCH 10/18] FIXME: delete old impl

---
 gcc/analyzer/analyzer.h            |   18 -
 gcc/analyzer/checker-path.cc       |  104 -
 gcc/analyzer/checker-path.h        |   43 -
 gcc/analyzer/constraint-manager.cc | 2198 -------
 gcc/analyzer/constraint-manager.h  |  222 -
 gcc/analyzer/diagnostic-manager.cc |  477 +-
 gcc/analyzer/engine.cc             | 1200 +---
 gcc/analyzer/exploded-graph.h      |  108 +-
 gcc/analyzer/program-state.cc      | 1179 +---
 gcc/analyzer/program-state.h       |  217 +-
 gcc/analyzer/region-model.cc       | 8675 +---------------------------
 gcc/analyzer/region-model.h        | 1866 ------
 gcc/analyzer/sm-signal.cc          |   34 +-
 13 files changed, 176 insertions(+), 16165 deletions(-)

diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h
index 6d92ce39617..4a1bbf066b7 100644
--- a/gcc/analyzer/analyzer.h
+++ b/gcc/analyzer/analyzer.h
@@ -39,24 +39,6 @@ class superedge;
   class callgraph_superedge;
     class call_superedge;
     class return_superedge;
-class svalue;
-  class region_svalue;
-  class constant_svalue;
-  class poisoned_svalue;
-  class unknown_svalue;
-  class setjmp_svalue;
-class region;
-  class map_region;
-  class array_region;
-  class symbolic_region;
-class region_model;
-class region_model_context;
-  class impl_region_model_context;
-class constraint_manager;
-class equiv_class;
-struct model_merger;
-struct svalue_id_merger_mapping;
-struct canonicalization;
 
 class svalue2;
   class region_svalue2;
diff --git a/gcc/analyzer/checker-path.cc b/gcc/analyzer/checker-path.cc
index bcdf4d9b4ed..da01d39cd0a 100644
--- a/gcc/analyzer/checker-path.cc
+++ b/gcc/analyzer/checker-path.cc
@@ -208,110 +208,6 @@ function_entry_event::get_desc (bool can_colorize) const
   return make_label_text (can_colorize, "entry to %qE", m_fndecl);
 }
 
-/* class state_change_event : public checker_event.  */
-
-/* state_change_event's ctor.  */
-
-state_change_event::state_change_event (const supernode *node,
-					const gimple *stmt,
-					int stack_depth,
-					const state_machine &sm,
-					tree var,
-					state_machine::state_t from,
-					state_machine::state_t to,
-					tree origin,
-					const program_state &dst_state)
-: base_state_change_event (EK_STATE_CHANGE,
-			   stmt->location, node->m_fun->decl,
-			   stack_depth),
-  m_node (node), m_stmt (stmt), m_sm (sm),
-  m_var (var), m_from (from), m_to (to),
-  m_origin (origin),
-  m_dst_state (dst_state)
-{
-}
-
-/* Implementation of diagnostic_event::get_desc vfunc for
-   state_change_event.
-
-   Attempt to generate a nicer human-readable description.
-   For greatest precision-of-wording, give the pending diagnostic
-   a chance to describe this state change (in terms of the
-   diagnostic).
-   Note that we only have a pending_diagnostic set on the event once
-   the diagnostic is about to being emitted, so the description for
-   an event can change.  */
-
-label_text
-state_change_event::get_desc (bool can_colorize) const
-{
-  if (m_pending_diagnostic)
-    {
-      label_text custom_desc
-	= m_pending_diagnostic->describe_state_change
-	    (evdesc::state_change (can_colorize, m_var, m_origin,
-				   m_from, m_to, m_emission_id, *this));
-      if (custom_desc.m_buffer)
-	{
-	  if (flag_analyzer_verbose_state_changes)
-	    {
-	      /* Append debug version.  */
-	      label_text result;
-	      if (m_origin)
-		result = make_label_text
-		  (can_colorize,
-		   "%s (state of %qE: %qs -> %qs, origin: %qE)",
-		   custom_desc.m_buffer,
-		   m_var,
-		   m_sm.get_state_name (m_from),
-		   m_sm.get_state_name (m_to),
-		   m_origin);
-	      else
-		result = make_label_text
-		  (can_colorize,
-		   "%s (state of %qE: %qs -> %qs, origin: NULL)",
-		   custom_desc.m_buffer,
-		   m_var,
-		   m_sm.get_state_name (m_from),
-		   m_sm.get_state_name (m_to));
-	      custom_desc.maybe_free ();
-	      return result;
-	    }
-	  else
-	    return custom_desc;
-	}
-    }
-
-  /* Fallback description.  */
-  if (m_var)
-    {
-      if (m_origin)
-	return make_label_text
-	  (can_colorize,
-	   "state of %qE: %qs -> %qs (origin: %qE)",
-	   m_var,
-	   m_sm.get_state_name (m_from),
-	   m_sm.get_state_name (m_to),
-	   m_origin);
-      else
-	return make_label_text
-	  (can_colorize,
-	   "state of %qE: %qs -> %qs (origin: NULL)",
-	   m_var,
-	   m_sm.get_state_name (m_from),
-	   m_sm.get_state_name (m_to));
-    }
-  else
-    {
-      gcc_assert (m_origin == NULL_TREE);
-      return make_label_text
-	(can_colorize,
-	 "global state: %qs -> %qs",
-	 m_sm.get_state_name (m_from),
-	 m_sm.get_state_name (m_to));
-    }
-}
-
 /* class state_change2_event : public checker_event.  */
 
 /* state_change2_event's ctor.  */
diff --git a/gcc/analyzer/checker-path.h b/gcc/analyzer/checker-path.h
index 46b398729f7..a8fa5147109 100644
--- a/gcc/analyzer/checker-path.h
+++ b/gcc/analyzer/checker-path.h
@@ -206,49 +206,6 @@ protected:
 
 /* Subclass of checker_event describing a state change.  */
 
-class state_change_event : public base_state_change_event
-{
-public:
-  state_change_event (const supernode *node, const gimple *stmt,
-		      int stack_depth,
-		      const state_machine &sm,
-		      tree var,
-		      state_machine::state_t from,
-		      state_machine::state_t to,
-		      tree origin,
-		      const program_state &dst_state);
-
-  label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
-
-  region_id get_lvalue (tree expr, region_model_context *ctxt) const
-  {
-    gcc_assert (m_dst_state.m_region_model);
-    return m_dst_state.m_region_model->get_lvalue (expr, ctxt);
-  }
-
-  const region2* get_lvalue2 (tree expr, region_model2_context *ctxt) const
-  {
-    gcc_assert (m_dst_state.m_region_model2);
-    return m_dst_state.m_region_model2->get_lvalue (expr, ctxt);
-  }
-
-  function *get_dest_function () const
-  {
-    return m_dst_state.get_current_function ();
-  }
-
-  const supernode *m_node;
-  const gimple *m_stmt;
-  const state_machine &m_sm;
-  tree m_var;
-  state_machine::state_t m_from;
-  state_machine::state_t m_to;
-  tree m_origin;
-  program_state m_dst_state;
-};
-
-/* Subclass of checker_event describing a state change.  */
-
 class state_change2_event : public base_state_change_event
 {
 public:
diff --git a/gcc/analyzer/constraint-manager.cc b/gcc/analyzer/constraint-manager.cc
index 786bd6ccf85..723a0c161b0 100644
--- a/gcc/analyzer/constraint-manager.cc
+++ b/gcc/analyzer/constraint-manager.cc
@@ -49,2213 +49,15 @@ along with GCC; see the file COPYING3.  If not see
 
 namespace ana {
 
-/* One of the end-points of a range.  */
-
-struct bound
-{
-  bound () : m_constant (NULL_TREE), m_closed (false) {}
-  bound (tree constant, bool closed)
-  : m_constant (constant), m_closed (closed) {}
-
-  void ensure_closed (bool is_upper);
-
-  const char * get_relation_as_str () const;
-
-  tree m_constant;
-  bool m_closed;
-};
-
-/* A range of values, used for determining if a value has been
-   constrained to just one possible constant value.  */
-
-struct range
-{
-  range () : m_lower_bound (), m_upper_bound () {}
-  range (const bound &lower, const bound &upper)
-  : m_lower_bound (lower), m_upper_bound (upper) {}
-
-  void dump (pretty_printer *pp) const;
-
-  bool constrained_to_single_element (tree *out);
-
-  bound m_lower_bound;
-  bound m_upper_bound;
-};
-
-/* struct bound.  */
-
-/* Ensure that this bound is closed by converting an open bound to a
-   closed one.  */
-
-void
-bound::ensure_closed (bool is_upper)
-{
-  if (!m_closed)
-    {
-      /* Offset by 1 in the appropriate direction.
-	 For example, convert 3 < x into 4 <= x,
-	 and convert x < 5 into x <= 4.  */
-      gcc_assert (CONSTANT_CLASS_P (m_constant));
-      m_constant = fold_build2 (is_upper ? MINUS_EXPR : PLUS_EXPR,
-				TREE_TYPE (m_constant),
-				m_constant, integer_one_node);
-      gcc_assert (CONSTANT_CLASS_P (m_constant));
-      m_closed = true;
-    }
-}
-
-/* Get "<=" vs "<" for this bound.  */
-
-const char *
-bound::get_relation_as_str () const
-{
-  if (m_closed)
-    return "<=";
-  else
-    return "<";
-}
-
-/* struct range.  */
-
-/* Dump this range to PP, which must support %E for tree.  */
-
-void
-range::dump (pretty_printer *pp) const
-{
-  pp_printf (pp, "%qE %s x %s %qE",
-	     m_lower_bound.m_constant,
-	     m_lower_bound.get_relation_as_str (),
-	     m_upper_bound.get_relation_as_str (),
-	     m_upper_bound.m_constant);
-}
-
-/* Determine if there is only one possible value for this range.
-   If so, return true and write the constant to *OUT.
-   Otherwise, return false.  */
-
-bool
-range::constrained_to_single_element (tree *out)
-{
-  if (!INTEGRAL_TYPE_P (TREE_TYPE (m_lower_bound.m_constant)))
-    return false;
-  if (!INTEGRAL_TYPE_P (TREE_TYPE (m_upper_bound.m_constant)))
-    return false;
-
-  /* Convert any open bounds to closed bounds.  */
-  m_lower_bound.ensure_closed (false);
-  m_upper_bound.ensure_closed (true);
-
-  // Are they equal?
-  tree comparison = fold_binary (EQ_EXPR, boolean_type_node,
-				 m_lower_bound.m_constant,
-				 m_upper_bound.m_constant);
-  if (comparison == boolean_true_node)
-    {
-      *out = m_lower_bound.m_constant;
-      return true;
-    }
-  else
-    return false;
-}
-
-/* class equiv_class.  */
-
-/* equiv_class's default ctor.  */
-
-equiv_class::equiv_class ()
-: m_constant (NULL_TREE), m_cst_sid (svalue_id::null ()),
-  m_vars ()
-{
-}
-
-/* equiv_class's copy ctor.  */
-
-equiv_class::equiv_class (const equiv_class &other)
-: m_constant (other.m_constant), m_cst_sid (other.m_cst_sid),
-  m_vars (other.m_vars.length ())
-{
-  int i;
-  svalue_id *sid;
-  FOR_EACH_VEC_ELT (other.m_vars, i, sid)
-    m_vars.quick_push (*sid);
-}
-
-/* Print an all-on-one-line representation of this equiv_class to PP,
-   which must support %E for trees.  */
-
-void
-equiv_class::print (pretty_printer *pp) const
-{
-  pp_character (pp, '{');
-  int i;
-  svalue_id *sid;
-  FOR_EACH_VEC_ELT (m_vars, i, sid)
-    {
-      if (i > 0)
-	pp_string (pp, " == ");
-      sid->print (pp);
-    }
-  if (m_constant)
-    {
-      if (i > 0)
-	pp_string (pp, " == ");
-      pp_printf (pp, "%qE", m_constant);
-    }
-  pp_character (pp, '}');
-}
-
-/* Generate a hash value for this equiv_class.  */
-
-hashval_t
-equiv_class::hash () const
-{
-  inchash::hash hstate;
-  int i;
-  svalue_id *sid;
-
-  inchash::add_expr (m_constant, hstate);
-  FOR_EACH_VEC_ELT (m_vars, i, sid)
-    inchash::add (*sid, hstate);
-  return hstate.end ();
-}
-
-/* Equality operator for equiv_class.  */
-
-bool
-equiv_class::operator== (const equiv_class &other)
-{
-  if (m_constant != other.m_constant)
-    return false; // TODO: use tree equality here?
-
-  /* FIXME: should we compare m_cst_sid?  */
-
-  if (m_vars.length () != other.m_vars.length ())
-    return false;
-
-  int i;
-  svalue_id *sid;
-  FOR_EACH_VEC_ELT (m_vars, i, sid)
-    if (! (*sid == other.m_vars[i]))
-      return false;
-
-  return true;
-}
-
-/* Add SID to this equiv_class, using CM to check if it's a constant.  */
-
-void
-equiv_class::add (svalue_id sid, const constraint_manager &cm)
-{
-  gcc_assert (!sid.null_p ());
-  if (tree cst = cm.maybe_get_constant (sid))
-    {
-      gcc_assert (CONSTANT_CLASS_P (cst));
-      /* FIXME: should we canonicalize which svalue is the constant
-	 when there are multiple equal constants?  */
-      m_constant = cst;
-      m_cst_sid = sid;
-    }
-  m_vars.safe_push (sid);
-}
-
-/* Remove SID from this equivalence class.
-   Return true if SID was the last var in the equivalence class (suggesting
-   a possible leak).  */
-
-bool
-equiv_class::del (svalue_id sid)
-{
-  gcc_assert (!sid.null_p ());
-  gcc_assert (sid != m_cst_sid);
-
-  int i;
-  svalue_id *iv;
-  FOR_EACH_VEC_ELT (m_vars, i, iv)
-    {
-      if (*iv == sid)
-	{
-	  m_vars[i] = m_vars[m_vars.length () - 1];
-	  m_vars.pop ();
-	  return m_vars.length () == 0;
-	}
-    }
-
-  /* SID must be in the class.  */
-  gcc_unreachable ();
-  return false;
-}
-
-/* Get a representative member of this class, for handling cases
-   where the IDs can change mid-traversal.  */
-
-svalue_id
-equiv_class::get_representative () const
-{
-  if (!m_cst_sid.null_p ())
-    return m_cst_sid;
-  else
-    {
-      gcc_assert (m_vars.length () > 0);
-      return m_vars[0];
-    }
-}
-
-/* Remap all svalue_ids within this equiv_class using MAP.  */
-
-void
-equiv_class::remap_svalue_ids (const svalue_id_map &map)
-{
-  int i;
-  svalue_id *iv;
-  FOR_EACH_VEC_ELT (m_vars, i, iv)
-    map.update (iv);
-  map.update (&m_cst_sid);
-}
-
-/* Comparator for use by equiv_class::canonicalize.  */
-
-static int
-svalue_id_cmp_by_id (const void *p1, const void *p2)
-{
-  const svalue_id *sid1 = (const svalue_id *)p1;
-  const svalue_id *sid2 = (const svalue_id *)p2;
-  return sid1->as_int () - sid2->as_int ();
-}
-
-/* Sort the svalues_ids within this equiv_class.  */
-
-void
-equiv_class::canonicalize ()
-{
-  m_vars.qsort (svalue_id_cmp_by_id);
-}
-
-/* Get a debug string for C_OP.  */
-
-const char *
-constraint_op_code (enum constraint_op c_op)
-{
-  switch (c_op)
-    {
-    default:
-      gcc_unreachable ();
-    case CONSTRAINT_NE: return "!=";
-    case CONSTRAINT_LT: return "<";
-    case CONSTRAINT_LE: return "<=";
-    }
-}
-
-/* Convert C_OP to an enum tree_code.  */
-
-enum tree_code
-constraint_tree_code (enum constraint_op c_op)
-{
-  switch (c_op)
-    {
-    default:
-      gcc_unreachable ();
-    case CONSTRAINT_NE: return NE_EXPR;
-    case CONSTRAINT_LT: return LT_EXPR;
-    case CONSTRAINT_LE: return LE_EXPR;
-    }
-}
-
-/* Given "lhs C_OP rhs", determine "lhs T_OP rhs".
-
-   For example, given "x < y", then "x > y" is false.  */
-
-static tristate
-eval_constraint_op_for_op (enum constraint_op c_op, enum tree_code t_op)
-{
-  switch (c_op)
-    {
-    default:
-      gcc_unreachable ();
-    case CONSTRAINT_NE:
-      if (t_op == EQ_EXPR)
-	return tristate (tristate::TS_FALSE);
-      if (t_op == NE_EXPR)
-	return tristate (tristate::TS_TRUE);
-      break;
-    case CONSTRAINT_LT:
-      if (t_op == LT_EXPR || t_op == LE_EXPR || t_op == NE_EXPR)
-	return tristate (tristate::TS_TRUE);
-      if (t_op == EQ_EXPR || t_op == GT_EXPR || t_op == GE_EXPR)
-	return tristate (tristate::TS_FALSE);
-      break;
-    case CONSTRAINT_LE:
-      if (t_op == LE_EXPR)
-	return tristate (tristate::TS_TRUE);
-      if (t_op == GT_EXPR)
-	return tristate (tristate::TS_FALSE);
-      break;
-    }
-  return tristate (tristate::TS_UNKNOWN);
-}
-
-/* class constraint.  */
-
-/* Print this constraint to PP (which must support %E for trees),
-   using CM to look up equiv_class instances from ids.  */
-
-void
-constraint::print (pretty_printer *pp, const constraint_manager &cm) const
-{
-  m_lhs.print (pp);
-  pp_string (pp, ": ");
-  m_lhs.get_obj (cm).print (pp);
-  pp_string (pp, " ");
-  pp_string (pp, constraint_op_code (m_op));
-  pp_string (pp, " ");
-  m_rhs.print (pp);
-  pp_string (pp, ": ");
-  m_rhs.get_obj (cm).print (pp);
-}
-
-/* Generate a hash value for this constraint.  */
-
-hashval_t
-constraint::hash () const
-{
-  inchash::hash hstate;
-  hstate.add_int (m_lhs.m_idx);
-  hstate.add_int (m_op);
-  hstate.add_int (m_rhs.m_idx);
-  return hstate.end ();
-}
-
-/* Equality operator for constraints.  */
-
-bool
-constraint::operator== (const constraint &other) const
-{
-  if (m_lhs != other.m_lhs)
-    return false;
-  if (m_op != other.m_op)
-    return false;
-  if (m_rhs != other.m_rhs)
-    return false;
-  return true;
-}
-
-/* class equiv_class_id.  */
-
-/* Get the underlying equiv_class for this ID from CM.  */
-
-const equiv_class &
-equiv_class_id::get_obj (const constraint_manager &cm) const
-{
-  return cm.get_equiv_class_by_index (m_idx);
-}
-
-/* Access the underlying equiv_class for this ID from CM.  */
-
-equiv_class &
-equiv_class_id::get_obj (constraint_manager &cm) const
-{
-  return cm.get_equiv_class_by_index (m_idx);
-}
-
-/* Print this equiv_class_id to PP.  */
-
-void
-equiv_class_id::print (pretty_printer *pp) const
-{
-  if (null_p ())
-    pp_printf (pp, "null");
-  else
-    pp_printf (pp, "ec%i", m_idx);
-}
-
-/* class constraint_manager.  */
-
-/* constraint_manager's copy ctor.  */
-
-constraint_manager::constraint_manager (const constraint_manager &other)
-: m_equiv_classes (other.m_equiv_classes.length ()),
-  m_constraints (other.m_constraints.length ())
-{
-  int i;
-  equiv_class *ec;
-  FOR_EACH_VEC_ELT (other.m_equiv_classes, i, ec)
-    m_equiv_classes.quick_push (new equiv_class (*ec));
-  constraint *c;
-  FOR_EACH_VEC_ELT (other.m_constraints, i, c)
-    m_constraints.quick_push (*c);
-}
-
-/* constraint_manager's assignment operator.  */
-
-constraint_manager&
-constraint_manager::operator= (const constraint_manager &other)
-{
-  gcc_assert (m_equiv_classes.length () == 0);
-  gcc_assert (m_constraints.length () == 0);
-
-  int i;
-  equiv_class *ec;
-  m_equiv_classes.reserve (other.m_equiv_classes.length ());
-  FOR_EACH_VEC_ELT (other.m_equiv_classes, i, ec)
-    m_equiv_classes.quick_push (new equiv_class (*ec));
-  constraint *c;
-  m_constraints.reserve (other.m_constraints.length ());
-  FOR_EACH_VEC_ELT (other.m_constraints, i, c)
-    m_constraints.quick_push (*c);
-
-  return *this;
-}
-
-/* Generate a hash value for this constraint_manager.  */
-
-hashval_t
-constraint_manager::hash () const
-{
-  inchash::hash hstate;
-  int i;
-  equiv_class *ec;
-  constraint *c;
-
-  FOR_EACH_VEC_ELT (m_equiv_classes, i, ec)
-    hstate.merge_hash (ec->hash ());
-  FOR_EACH_VEC_ELT (m_constraints, i, c)
-    hstate.merge_hash (c->hash ());
-  return hstate.end ();
-}
-
-/* Equality operator for constraint_manager.  */
-
-bool
-constraint_manager::operator== (const constraint_manager &other) const
-{
-  if (m_equiv_classes.length () != other.m_equiv_classes.length ())
-    return false;
-  if (m_constraints.length () != other.m_constraints.length ())
-    return false;
-
-  int i;
-  equiv_class *ec;
-
-  FOR_EACH_VEC_ELT (m_equiv_classes, i, ec)
-    if (!(*ec == *other.m_equiv_classes[i]))
-      return false;
-
-  constraint *c;
-
-  FOR_EACH_VEC_ELT (m_constraints, i, c)
-    if (!(*c == other.m_constraints[i]))
-      return false;
-
-  return true;
-}
-
-/* Print this constraint_manager to PP (which must support %E for trees).  */
-
-void
-constraint_manager::print (pretty_printer *pp) const
-{
-  pp_string (pp, "{");
-  int i;
-  equiv_class *ec;
-  FOR_EACH_VEC_ELT (m_equiv_classes, i, ec)
-    {
-      if (i > 0)
-	pp_string (pp, ", ");
-      equiv_class_id (i).print (pp);
-      pp_string (pp, ": ");
-      ec->print (pp);
-    }
-  pp_string (pp, "  |  ");
-  constraint *c;
-  FOR_EACH_VEC_ELT (m_constraints, i, c)
-    {
-      if (i > 0)
-	pp_string (pp, " && ");
-      c->print (pp, *this);
-    }
-  pp_printf (pp, "}");
-}
-
-/* Dump a multiline representation of this constraint_manager to PP
-   (which must support %E for trees).  */
-
-void
-constraint_manager::dump_to_pp (pretty_printer *pp) const
-{
-  // TODO
-  pp_string (pp, "  equiv classes:");
-  pp_newline (pp);
-  int i;
-  equiv_class *ec;
-  FOR_EACH_VEC_ELT (m_equiv_classes, i, ec)
-    {
-      pp_string (pp, "    ");
-      equiv_class_id (i).print (pp);
-      pp_string (pp, ": ");
-      ec->print (pp);
-      pp_newline (pp);
-    }
-  pp_string (pp, "  constraints:");
-  pp_newline (pp);
-  constraint *c;
-  FOR_EACH_VEC_ELT (m_constraints, i, c)
-    {
-      pp_printf (pp, "    %i: ", i);
-      c->print (pp, *this);
-      pp_newline (pp);
-    }
-}
-
-/* Dump a multiline representation of this constraint_manager to FP.  */
-
-void
-constraint_manager::dump (FILE *fp) const
-{
-  pretty_printer pp;
-  pp_format_decoder (&pp) = default_tree_printer;
-  pp_show_color (&pp) = pp_show_color (global_dc->printer);
-  pp.buffer->stream = fp;
-  dump_to_pp (&pp);
-  pp_flush (&pp);
-}
-
-/* Dump a multiline representation of this constraint_manager to stderr.  */
-
-DEBUG_FUNCTION void
-constraint_manager::dump () const
-{
-  dump (stderr);
-}
-
-/* Dump a multiline representation of CM to stderr.  */
-
-DEBUG_FUNCTION void
-debug (const constraint_manager &cm)
-{
-  cm.dump ();
-}
-
-/* Attempt to add the constraint LHS OP RHS to this constraint_manager.
-   Return true if the constraint could be added (or is already true).
-   Return false if the constraint contradicts existing knowledge.  */
-
-bool
-constraint_manager::add_constraint (svalue_id lhs,
-				    enum tree_code op,
-				    svalue_id rhs)
-{
-  equiv_class_id lhs_ec_id = get_or_add_equiv_class (lhs);
-  equiv_class_id rhs_ec_id = get_or_add_equiv_class (rhs);
-  return add_constraint (lhs_ec_id, op,rhs_ec_id);
-}
-
-/* Attempt to add the constraint LHS_EC_ID OP RHS_EC_ID to this
-   constraint_manager.
-   Return true if the constraint could be added (or is already true).
-   Return false if the constraint contradicts existing knowledge.  */
-
-bool
-constraint_manager::add_constraint (equiv_class_id lhs_ec_id,
-				    enum tree_code op,
-				    equiv_class_id rhs_ec_id)
-{
-  tristate t = eval_condition (lhs_ec_id, op, rhs_ec_id);
-
-  /* Discard constraints that are already known.  */
-  if (t.is_true ())
-    return true;
-
-  /* Reject unsatisfiable constraints.  */
-  if (t.is_false ())
-    return false;
-
-  gcc_assert (lhs_ec_id != rhs_ec_id);
-
-  /* For now, simply accumulate constraints, without attempting any further
-     optimization.  */
-  switch (op)
-    {
-    case EQ_EXPR:
-      {
-	/* Merge rhs_ec into lhs_ec.  */
-	equiv_class &lhs_ec_obj = lhs_ec_id.get_obj (*this);
-	const equiv_class &rhs_ec_obj = rhs_ec_id.get_obj (*this);
-
-	int i;
-	svalue_id *sid;
-	FOR_EACH_VEC_ELT (rhs_ec_obj.m_vars, i, sid)
-	  lhs_ec_obj.add (*sid, *this);
-
-	if (rhs_ec_obj.m_constant)
-	  {
-	    lhs_ec_obj.m_constant = rhs_ec_obj.m_constant;
-	    lhs_ec_obj.m_cst_sid = rhs_ec_obj.m_cst_sid;
-	  }
-
-	/* Drop rhs equivalence class, overwriting it with the
-	   final ec (which might be the same one).  */
-	equiv_class_id final_ec_id = m_equiv_classes.length () - 1;
-	equiv_class *old_ec = m_equiv_classes[rhs_ec_id.m_idx];
-	equiv_class *final_ec = m_equiv_classes.pop ();
-	if (final_ec != old_ec)
-	  m_equiv_classes[rhs_ec_id.m_idx] = final_ec;
-	delete old_ec;
-
-	/* Update the constraints.  */
-	constraint *c;
-	FOR_EACH_VEC_ELT (m_constraints, i, c)
-	  {
-	    /* Update references to the rhs_ec so that
-	       they refer to the lhs_ec.  */
-	    if (c->m_lhs == rhs_ec_id)
-	      c->m_lhs = lhs_ec_id;
-	    if (c->m_rhs == rhs_ec_id)
-	      c->m_rhs = lhs_ec_id;
-
-	    /* Renumber all constraints that refer to the final rhs_ec
-	       to the old rhs_ec, where the old final_ec now lives.  */
-	    if (c->m_lhs == final_ec_id)
-	      c->m_lhs = rhs_ec_id;
-	    if (c->m_rhs == final_ec_id)
-	      c->m_rhs = rhs_ec_id;
-	  }
-      }
-      break;
-    case GE_EXPR:
-      add_constraint_internal (rhs_ec_id, CONSTRAINT_LE, lhs_ec_id);
-      break;
-    case LE_EXPR:
-      add_constraint_internal (lhs_ec_id, CONSTRAINT_LE, rhs_ec_id);
-      break;
-    case NE_EXPR:
-      add_constraint_internal (lhs_ec_id, CONSTRAINT_NE, rhs_ec_id);
-      break;
-    case GT_EXPR:
-      add_constraint_internal (rhs_ec_id, CONSTRAINT_LT, lhs_ec_id);
-      break;
-    case LT_EXPR:
-      add_constraint_internal (lhs_ec_id, CONSTRAINT_LT, rhs_ec_id);
-      break;
-    default:
-      /* do nothing.  */
-      break;
-    }
-  validate ();
-  return true;
-}
-
-/* Subroutine of constraint_manager::add_constraint, for handling all
-   operations other than equality (for which equiv classes are merged).  */
-
-void
-constraint_manager::add_constraint_internal (equiv_class_id lhs_id,
-					     enum constraint_op c_op,
-					     equiv_class_id rhs_id)
-{
-  /* Add the constraint.  */
-  m_constraints.safe_push (constraint (lhs_id, c_op, rhs_id));
-
-  if (!flag_analyzer_transitivity)
-    return;
-
-  if (c_op != CONSTRAINT_NE)
-    {
-      /* The following can potentially add EQ_EXPR facts, which could lead
-	 to ECs being merged, which would change the meaning of the EC IDs.
-	 Hence we need to do this via representatives.  */
-      svalue_id lhs = lhs_id.get_obj (*this).get_representative ();
-      svalue_id rhs = rhs_id.get_obj (*this).get_representative ();
-
-      /* We have LHS </<= RHS */
-
-      /* Handle transitivity of ordering by adding additional constraints
-	 based on what we already knew.
-
-	 So if we have already have:
-	   (a < b)
-	   (c < d)
-	 Then adding:
-	   (b < c)
-	 will also add:
-	   (a < c)
-	   (b < d)
-	 We need to recurse to ensure we also add:
-	   (a < d).
-	 We call the checked add_constraint to avoid adding constraints
-	 that are already present.  Doing so also ensures termination
-	 in the case of cycles.
-
-	 We also check for single-element ranges, adding EQ_EXPR facts
-	 where we discover them.  For example 3 < x < 5 implies
-	 that x == 4 (if x is an integer).  */
-      for (unsigned i = 0; i < m_constraints.length (); i++)
-	{
-	  const constraint *other = &m_constraints[i];
-	  if (other->is_ordering_p ())
-	    {
-	      /* Refresh the EC IDs, in case any mergers have happened.  */
-	      lhs_id = get_or_add_equiv_class (lhs);
-	      rhs_id = get_or_add_equiv_class (rhs);
-
-	      tree lhs_const = lhs_id.get_obj (*this).m_constant;
-	      tree rhs_const = rhs_id.get_obj (*this).m_constant;
-	      tree other_lhs_const
-		= other->m_lhs.get_obj (*this).m_constant;
-	      tree other_rhs_const
-		= other->m_rhs.get_obj (*this).m_constant;
-
-	      /* We have "LHS </<= RHS" and "other.lhs </<= other.rhs".  */
-
-	      /* If we have LHS </<= RHS and RHS </<= LHS, then we have a
-		 cycle.  */
-	      if (rhs_id == other->m_lhs
-		  && other->m_rhs == lhs_id)
-		{
-		  /* We must have equality for this to be possible.  */
-		  gcc_assert (c_op == CONSTRAINT_LE
-			      && other->m_op == CONSTRAINT_LE);
-		  add_constraint (lhs_id, EQ_EXPR, rhs_id);
-		  /* Adding an equality will merge the two ECs and potentially
-		     reorganize the constraints.  Stop iterating.  */
-		  return;
-		}
-	      /* Otherwise, check for transitivity.  */
-	      if (rhs_id == other->m_lhs)
-		{
-		  /* With RHS == other.lhs, we have:
-		     "LHS </<= (RHS, other.lhs) </<= other.rhs"
-		     and thus this implies "LHS </<= other.rhs".  */
-
-		  /* Do we have a tightly-constrained range?  */
-		  if (lhs_const
-		      && !rhs_const
-		      && other_rhs_const)
-		    {
-		      range r (bound (lhs_const, c_op == CONSTRAINT_LE),
-			       bound (other_rhs_const,
-				      other->m_op == CONSTRAINT_LE));
-		      tree constant;
-		      if (r.constrained_to_single_element (&constant))
-			{
-			  svalue_id cst_sid = get_sid_for_constant (constant);
-			  add_constraint
-			    (rhs_id, EQ_EXPR,
-			     get_or_add_equiv_class (cst_sid));
-			  return;
-			}
-		    }
-
-		  /* Otherwise, add the constraint implied by transitivity.  */
-		  enum tree_code new_op
-		    = ((c_op == CONSTRAINT_LE && other->m_op == CONSTRAINT_LE)
-		       ? LE_EXPR : LT_EXPR);
-		  add_constraint (lhs_id, new_op, other->m_rhs);
-		}
-	      else if (other->m_rhs == lhs_id)
-		{
-		  /* With other.rhs == LHS, we have:
-		     "other.lhs </<= (other.rhs, LHS) </<= RHS"
-		     and thus this implies "other.lhs </<= RHS".  */
-
-		  /* Do we have a tightly-constrained range?  */
-		  if (other_lhs_const
-		      && !lhs_const
-		      && rhs_const)
-		    {
-		      range r (bound (other_lhs_const,
-				      other->m_op == CONSTRAINT_LE),
-			       bound (rhs_const,
-				      c_op == CONSTRAINT_LE));
-		      tree constant;
-		      if (r.constrained_to_single_element (&constant))
-			{
-			  svalue_id cst_sid = get_sid_for_constant (constant);
-			  add_constraint
-			    (lhs_id, EQ_EXPR,
-			     get_or_add_equiv_class (cst_sid));
-			  return;
-			}
-		    }
-
-		  /* Otherwise, add the constraint implied by transitivity.  */
-		  enum tree_code new_op
-		    = ((c_op == CONSTRAINT_LE && other->m_op == CONSTRAINT_LE)
-		       ? LE_EXPR : LT_EXPR);
-		  add_constraint (other->m_lhs, new_op, rhs_id);
-		}
-	    }
-	}
-    }
-}
-
-/* Look for SID within the equivalence classes of this constraint_manager;
-   if found, write the id to *OUT and return true, otherwise return false.  */
-
-bool
-constraint_manager::get_equiv_class_by_sid (svalue_id sid, equiv_class_id *out) const
-{
-  /* TODO: should we have a map, rather than these searches?  */
-  int i;
-  equiv_class *ec;
-  FOR_EACH_VEC_ELT (m_equiv_classes, i, ec)
-    {
-      int j;
-      svalue_id *iv;
-      FOR_EACH_VEC_ELT (ec->m_vars, j, iv)
-	if (*iv == sid)
-	  {
-	    *out = equiv_class_id (i);
-	    return true;
-	  }
-    }
-  return false;
-}
-
-/* Ensure that SID has an equivalence class within this constraint_manager;
-   return the ID of the class.  */
-
-equiv_class_id
-constraint_manager::get_or_add_equiv_class (svalue_id sid)
-{
-  equiv_class_id result (-1);
-
-  /* Try svalue_id match.  */
-  if (get_equiv_class_by_sid (sid, &result))
-    return result;
-
-  /* Try equality of constants.  */
-  if (tree cst = maybe_get_constant (sid))
-    {
-      int i;
-      equiv_class *ec;
-      FOR_EACH_VEC_ELT (m_equiv_classes, i, ec)
-	if (ec->m_constant
-	    && types_compatible_p (TREE_TYPE (cst),
-				   TREE_TYPE (ec->m_constant)))
-	  {
-	    tree eq = fold_binary (EQ_EXPR, boolean_type_node,
-				   cst, ec->m_constant);
-	    if (eq == boolean_true_node)
-	      {
-		ec->add (sid, *this);
-		return equiv_class_id (i);
-	      }
-	  }
-    }
-
-
-  /* Not found.  */
-  equiv_class *new_ec = new equiv_class ();
-  new_ec->add (sid, *this);
-  m_equiv_classes.safe_push (new_ec);
-
-  equiv_class_id new_id (m_equiv_classes.length () - 1);
-
-  if (maybe_get_constant (sid))
-    {
-      /* If we have a new EC for a constant, add constraints comparing this
-	 to other constants we may have (so that we accumulate the transitive
-	 closure of all constraints on constants as the constants are
-	 added).  */
-      for (equiv_class_id other_id (0); other_id.m_idx < new_id.m_idx;
-	   other_id.m_idx++)
-	{
-	  const equiv_class &other_ec = other_id.get_obj (*this);
-	  if (other_ec.m_constant
-	      && types_compatible_p (TREE_TYPE (new_ec->m_constant),
-				     TREE_TYPE (other_ec.m_constant)))
-	    {
-	      /* If we have two ECs, both with constants, the constants must be
-		 non-equal (or they would be in the same EC).
-		 Determine the direction of the inequality, and record that
-		 fact.  */
-	      tree lt
-		= fold_binary (LT_EXPR, boolean_type_node,
-			       new_ec->m_constant, other_ec.m_constant);
-	      if (lt == boolean_true_node)
-		add_constraint_internal (new_id, CONSTRAINT_LT, other_id);
-	      else if (lt == boolean_false_node)
-		add_constraint_internal (other_id, CONSTRAINT_LT, new_id);
-	      /* Refresh new_id, in case ECs were merged.  SID should always
-		 be present by now, so this should never lead to a
-		 recursion.  */
-	      new_id = get_or_add_equiv_class (sid);
-	    }
-	}
-    }
-
-  return new_id;
-}
-
-/* Evaluate the condition LHS_EC OP RHS_EC.  */
-
-tristate
-constraint_manager::eval_condition (equiv_class_id lhs_ec,
-				    enum tree_code op,
-				    equiv_class_id rhs_ec)
-{
-  if (lhs_ec == rhs_ec)
-    {
-      switch (op)
-	{
-	case EQ_EXPR:
-	case GE_EXPR:
-	case LE_EXPR:
-	  return tristate (tristate::TS_TRUE);
-
-	case NE_EXPR:
-	case GT_EXPR:
-	case LT_EXPR:
-	  return tristate (tristate::TS_FALSE);
-	default:
-	  break;
-	}
-    }
-
-  tree lhs_const = lhs_ec.get_obj (*this).get_any_constant ();
-  tree rhs_const = rhs_ec.get_obj (*this).get_any_constant ();
-  if (lhs_const && rhs_const)
-    {
-      tree comparison
-	= fold_binary (op, boolean_type_node, lhs_const, rhs_const);
-      if (comparison == boolean_true_node)
-	return tristate (tristate::TS_TRUE);
-      if (comparison == boolean_false_node)
-	return tristate (tristate::TS_FALSE);
-    }
-
-  enum tree_code swapped_op = swap_tree_comparison (op);
-
-  int i;
-  constraint *c;
-  FOR_EACH_VEC_ELT (m_constraints, i, c)
-    {
-      if (c->m_lhs == lhs_ec
-	  && c->m_rhs == rhs_ec)
-	{
-	  tristate result_for_constraint
-	    = eval_constraint_op_for_op (c->m_op, op);
-	  if (result_for_constraint.is_known ())
-	    return result_for_constraint;
-	}
-      /* Swapped operands.  */
-      if (c->m_lhs == rhs_ec
-	  && c->m_rhs == lhs_ec)
-	{
-	  tristate result_for_constraint
-	    = eval_constraint_op_for_op (c->m_op, swapped_op);
-	  if (result_for_constraint.is_known ())
-	    return result_for_constraint;
-	}
-    }
-
-  return tristate (tristate::TS_UNKNOWN);
-}
-
-/* Evaluate the condition LHS OP RHS, creating equiv_class instances for
-   LHS and RHS if they aren't already in equiv_classes.  */
-
-tristate
-constraint_manager::eval_condition (svalue_id lhs,
-				    enum tree_code op,
-				    svalue_id rhs)
-{
-  return eval_condition (get_or_add_equiv_class (lhs),
-			 op,
-			 get_or_add_equiv_class (rhs));
-}
-
-/* Delete any information about svalue_id instances identified by P.
-   Such instances are removed from equivalence classes, and any
-   redundant ECs and constraints are also removed.
-   Accumulate stats into STATS.  */
-
-void
-constraint_manager::purge (const purge_criteria &p, purge_stats *stats)
-{
-  /* Delete any svalue_ids identified by P within the various equivalence
-     classes.  */
-  for (unsigned ec_idx = 0; ec_idx < m_equiv_classes.length (); )
-    {
-      equiv_class *ec = m_equiv_classes[ec_idx];
-
-      int i;
-      svalue_id *pv;
-      bool delete_ec = false;
-      FOR_EACH_VEC_ELT (ec->m_vars, i, pv)
-	{
-	  if (*pv == ec->m_cst_sid)
-	    continue;
-	  if (p.should_purge_p (*pv))
-	    {
-	      if (ec->del (*pv))
-		if (!ec->m_constant)
-		  delete_ec = true;
-	    }
-	}
-
-      if (delete_ec)
-	{
-	  delete ec;
-	  m_equiv_classes.ordered_remove (ec_idx);
-	  if (stats)
-	    stats->m_num_equiv_classes++;
-
-	  /* Update the constraints, potentially removing some.  */
-	  for (unsigned con_idx = 0; con_idx < m_constraints.length (); )
-	    {
-	      constraint *c = &m_constraints[con_idx];
-
-	      /* Remove constraints that refer to the deleted EC.  */
-	      if (c->m_lhs == ec_idx
-		  || c->m_rhs == ec_idx)
-		{
-		  m_constraints.ordered_remove (con_idx);
-		  if (stats)
-		    stats->m_num_constraints++;
-		}
-	      else
-		{
-		  /* Renumber constraints that refer to ECs that have
-		     had their idx changed.  */
-		  c->m_lhs.update_for_removal (ec_idx);
-		  c->m_rhs.update_for_removal (ec_idx);
-
-		  con_idx++;
-		}
-	    }
-	}
-      else
-	ec_idx++;
-    }
-
-  /* Now delete any constraints that are purely between constants.  */
-  for (unsigned con_idx = 0; con_idx < m_constraints.length (); )
-    {
-      constraint *c = &m_constraints[con_idx];
-      if (m_equiv_classes[c->m_lhs.m_idx]->m_vars.length () == 0
-	  && m_equiv_classes[c->m_rhs.m_idx]->m_vars.length () == 0)
-	{
-	  m_constraints.ordered_remove (con_idx);
-	  if (stats)
-	    stats->m_num_constraints++;
-	}
-      else
-	{
-	  con_idx++;
-	}
-    }
-
-  /* Finally, delete any ECs that purely contain constants and aren't
-     referenced by any constraints.  */
-  for (unsigned ec_idx = 0; ec_idx < m_equiv_classes.length (); )
-    {
-      equiv_class *ec = m_equiv_classes[ec_idx];
-      if (ec->m_vars.length () == 0)
-	{
-	  equiv_class_id ec_id (ec_idx);
-	  bool has_constraint = false;
-	  for (unsigned con_idx = 0; con_idx < m_constraints.length ();
-	       con_idx++)
-	    {
-	      constraint *c = &m_constraints[con_idx];
-	      if (c->m_lhs == ec_id
-		  || c->m_rhs == ec_id)
-		{
-		  has_constraint = true;
-		  break;
-		}
-	    }
-	  if (!has_constraint)
-	    {
-	      delete ec;
-	      m_equiv_classes.ordered_remove (ec_idx);
-	      if (stats)
-		stats->m_num_equiv_classes++;
-
-	      /* Renumber constraints that refer to ECs that have
-		 had their idx changed.  */
-	      for (unsigned con_idx = 0; con_idx < m_constraints.length ();
-		   con_idx++)
-		{
-		  constraint *c = &m_constraints[con_idx];
-		  c->m_lhs.update_for_removal (ec_idx);
-		  c->m_rhs.update_for_removal (ec_idx);
-		}
-	      continue;
-	    }
-	}
-      ec_idx++;
-    }
-
-  validate ();
-}
-
-/* Remap all svalue_ids within this constraint_manager using MAP.  */
-
-void
-constraint_manager::remap_svalue_ids (const svalue_id_map &map)
-{
-  int i;
-  equiv_class *ec;
-  FOR_EACH_VEC_ELT (m_equiv_classes, i, ec)
-    ec->remap_svalue_ids (map);
-}
-
-/* Comparator for use by constraint_manager::canonicalize.
-   Sort a pair of equiv_class instances, using the representative
-   svalue_id as a sort key.  */
-
-static int
-equiv_class_cmp (const void *p1, const void *p2)
-{
-  const equiv_class *ec1 = *(const equiv_class * const *)p1;
-  const equiv_class *ec2 = *(const equiv_class * const *)p2;
-
-  svalue_id rep1 = ec1->get_representative ();
-  svalue_id rep2 = ec2->get_representative ();
-
-  return rep1.as_int () - rep2.as_int ();
-}
-
-/* Comparator for use by constraint_manager::canonicalize.
-   Sort a pair of constraint instances.  */
-
-static int
-constraint_cmp (const void *p1, const void *p2)
-{
-  const constraint *c1 = (const constraint *)p1;
-  const constraint *c2 = (const constraint *)p2;
-  int lhs_cmp = c1->m_lhs.as_int () - c2->m_lhs.as_int ();
-  if (lhs_cmp)
-    return lhs_cmp;
-  int rhs_cmp = c1->m_rhs.as_int () - c2->m_rhs.as_int ();
-  if (rhs_cmp)
-    return rhs_cmp;
-  return c1->m_op - c2->m_op;
-}
-
-/* Reorder the equivalence classes and constraints within this
-   constraint_manager into a canonical order, to increase the
-   chances of finding equality with another instance.  */
-
-void
-constraint_manager::canonicalize (unsigned num_svalue_ids)
-{
-  /* First, sort svalue_ids within the ECs.  */
-  unsigned i;
-  equiv_class *ec;
-  FOR_EACH_VEC_ELT (m_equiv_classes, i, ec)
-    ec->canonicalize ();
-
-  /* Next, sort the ECs into a canonical order.  */
-
-  /* We will need to remap the equiv_class_ids in the constraints,
-     so we need to store the original index of each EC.
-     Build a lookup table, mapping from representative svalue_id
-     to the original equiv_class_id of that svalue_id.  */
-  auto_vec<equiv_class_id> original_ec_id (num_svalue_ids);
-  for (i = 0; i < num_svalue_ids; i++)
-    original_ec_id.quick_push (equiv_class_id::null ());
-  FOR_EACH_VEC_ELT (m_equiv_classes, i, ec)
-    {
-      svalue_id rep = ec->get_representative ();
-      gcc_assert (!rep.null_p ());
-      original_ec_id[rep.as_int ()] = i;
-    }
-
-  /* Sort the equivalence classes.  */
-  m_equiv_classes.qsort (equiv_class_cmp);
-
-  /* Populate ec_id_map based on the old vs new EC ids.  */
-  one_way_id_map<equiv_class_id> ec_id_map (m_equiv_classes.length ());
-  FOR_EACH_VEC_ELT (m_equiv_classes, i, ec)
-    {
-      svalue_id rep = ec->get_representative ();
-      ec_id_map.put (original_ec_id[rep.as_int ()], i);
-    }
-
-  /* Update the EC ids within the constraints.  */
-  constraint *c;
-  FOR_EACH_VEC_ELT (m_constraints, i, c)
-    {
-      ec_id_map.update (&c->m_lhs);
-      ec_id_map.update (&c->m_rhs);
-    }
-
-  /* Finally, sort the constraints. */
-  m_constraints.qsort (constraint_cmp);
-}
-
-/* A concrete subclass of constraint_manager for use when
-   merging two constraint_manager into a third constraint_manager,
-   each of which has its own region_model.
-   Calls are delegated to the constraint_manager for the merged model,
-   and thus affect its region_model.  */
-
-class cleaned_constraint_manager : public constraint_manager
-{
-public:
-  cleaned_constraint_manager (constraint_manager *merged) : m_merged (merged) {}
-
-  constraint_manager *clone (region_model *) const FINAL OVERRIDE
-  {
-    gcc_unreachable ();
-  }
-  tree maybe_get_constant (svalue_id sid) const FINAL OVERRIDE
-  {
-    return m_merged->maybe_get_constant (sid);
-  }
-  svalue_id get_sid_for_constant (tree cst) const FINAL OVERRIDE
-  {
-    return m_merged->get_sid_for_constant (cst);
-  }
-  virtual int get_num_svalues () const FINAL OVERRIDE
-  {
-    return m_merged->get_num_svalues ();
-  }
-private:
-  constraint_manager *m_merged;
-};
-
-/* Concrete subclass of fact_visitor for use by constraint_manager::merge.
-   For every fact in CM_A, see if it is also true in *CM_B.  Add such
-   facts to *OUT.  */
-
-class merger_fact_visitor : public fact_visitor
-{
-public:
-  merger_fact_visitor (constraint_manager *cm_b,
-		       constraint_manager *out)
-  : m_cm_b (cm_b), m_out (out)
-  {}
-
-  void on_fact (svalue_id lhs, enum tree_code code, svalue_id rhs)
-    FINAL OVERRIDE
-  {
-    if (m_cm_b->eval_condition (lhs, code, rhs).is_true ())
-      {
-	bool sat = m_out->add_constraint (lhs, code, rhs);
-	gcc_assert (sat);
-      }
-  }
-
-private:
-  constraint_manager *m_cm_b;
-  constraint_manager *m_out;
-};
-
-/* Use MERGER to merge CM_A and CM_B into *OUT.
-   If one thinks of a constraint_manager as a subset of N-dimensional
-   space, this takes the union of the points of CM_A and CM_B, and
-   expresses that into *OUT.  Alternatively, it can be thought of
-   as the intersection of the constraints.  */
-
-void
-constraint_manager::merge (const constraint_manager &cm_a,
-			   const constraint_manager &cm_b,
-			   constraint_manager *out,
-			   const model_merger &merger)
-{
-  gcc_assert (merger.m_sid_mapping);
-
-  /* Map svalue_ids in each equiv class from both sources
-     to the merged region_model, dropping ids that don't survive merger,
-     and potentially creating svalues in *OUT for constants.  */
-  cleaned_constraint_manager cleaned_cm_a (out);
-  const one_way_svalue_id_map &map_a_to_m
-    = merger.m_sid_mapping->m_map_from_a_to_m;
-  clean_merger_input (cm_a, map_a_to_m, &cleaned_cm_a);
-
-  cleaned_constraint_manager cleaned_cm_b (out);
-  const one_way_svalue_id_map &map_b_to_m
-    = merger.m_sid_mapping->m_map_from_b_to_m;
-  clean_merger_input (cm_b, map_b_to_m, &cleaned_cm_b);
-
-  /* At this point, the two cleaned CMs have ECs and constraints referring
-     to svalues in the merged region model, but both of them have separate
-     ECs.  */
-
-  /* Merge the equivalence classes and constraints.
-     The easiest way to do this seems to be to enumerate all of the facts
-     in cleaned_cm_a, see which are also true in cleaned_cm_b,
-     and add those to *OUT.  */
-  merger_fact_visitor v (&cleaned_cm_b, out);
-  cleaned_cm_a.for_each_fact (&v);
-}
-
-/* A subroutine of constraint_manager::merge.
-   Use MAP_SID_TO_M to map equivalence classes and constraints from
-   SM_IN to *OUT.  Purge any non-constant svalue_id that don't appear
-   in the result of MAP_SID_TO_M, purging any ECs and their constraints
-   that become empty as a result.  Potentially create svalues in
-   the merged region_model for constants that weren't already in use there.  */
-
-void
-constraint_manager::
-clean_merger_input (const constraint_manager &cm_in,
-		    const one_way_svalue_id_map &map_sid_to_m,
-		    constraint_manager *out)
-{
-  one_way_id_map<equiv_class_id> map_ec_to_m
-    (cm_in.m_equiv_classes.length ());
-  unsigned ec_idx;
-  equiv_class *ec;
-  FOR_EACH_VEC_ELT (cm_in.m_equiv_classes, ec_idx, ec)
-    {
-      equiv_class cleaned_ec;
-      if (tree cst = ec->get_any_constant ())
-	{
-	  cleaned_ec.m_constant = cst;
-	  /* Lazily create the constant in the out region_model.  */
-	  cleaned_ec.m_cst_sid = out->get_sid_for_constant (cst);
-	}
-      unsigned var_idx;
-      svalue_id *var_in_sid;
-      FOR_EACH_VEC_ELT (ec->m_vars, var_idx, var_in_sid)
-	{
-	  svalue_id var_m_sid = map_sid_to_m.get_dst_for_src (*var_in_sid);
-	  if (!var_m_sid.null_p ())
-	    cleaned_ec.m_vars.safe_push (var_m_sid);
-	}
-      if (cleaned_ec.get_any_constant () || !cleaned_ec.m_vars.is_empty ())
-	{
-	  map_ec_to_m.put (ec_idx, out->m_equiv_classes.length ());
-	  out->m_equiv_classes.safe_push (new equiv_class (cleaned_ec));
-	}
-    }
-
-  /* Write out to *OUT any constraints for which both sides survived
-     cleaning, using the new EC IDs.  */
-  unsigned con_idx;
-  constraint *c;
-  FOR_EACH_VEC_ELT (cm_in.m_constraints, con_idx, c)
-    {
-      equiv_class_id new_lhs = map_ec_to_m.get_dst_for_src (c->m_lhs);
-      if (new_lhs.null_p ())
-	continue;
-      equiv_class_id new_rhs = map_ec_to_m.get_dst_for_src (c->m_rhs);
-      if (new_rhs.null_p ())
-	continue;
-      out->m_constraints.safe_push (constraint (new_lhs,
-						c->m_op,
-						new_rhs));
-    }
-}
-
-/* Call VISITOR's on_fact vfunc repeatedly to express the various
-   equivalence classes and constraints.
-   This is used by constraint_manager::merge to find the common
-   facts between two input constraint_managers.  */
-
-void
-constraint_manager::for_each_fact (fact_visitor *visitor) const
-{
-  /* First, call EQ_EXPR within the various equivalence classes.  */
-  unsigned ec_idx;
-  equiv_class *ec;
-  FOR_EACH_VEC_ELT (m_equiv_classes, ec_idx, ec)
-    {
-      if (!ec->m_cst_sid.null_p ())
-	{
-	  unsigned i;
-	  svalue_id *sid;
-	  FOR_EACH_VEC_ELT (ec->m_vars, i, sid)
-	    visitor->on_fact (ec->m_cst_sid, EQ_EXPR, *sid);
-	}
-      for (unsigned i = 0; i < ec->m_vars.length (); i++)
-	for (unsigned j = i + 1; j < ec->m_vars.length (); j++)
-	  visitor->on_fact (ec->m_vars[i], EQ_EXPR, ec->m_vars[j]);
-    }
-
-  /* Now, express the various constraints.  */
-  unsigned con_idx;
-  constraint *c;
-  FOR_EACH_VEC_ELT (m_constraints, con_idx, c)
-    {
-      const equiv_class &ec_lhs = c->m_lhs.get_obj (*this);
-      const equiv_class &ec_rhs = c->m_rhs.get_obj (*this);
-      enum tree_code code = constraint_tree_code (c->m_op);
-
-      if (!ec_lhs.m_cst_sid.null_p ())
-	{
-	  for (unsigned j = 0; j < ec_rhs.m_vars.length (); j++)
-	    {
-	      visitor->on_fact (ec_lhs.m_cst_sid, code, ec_rhs.m_vars[j]);
-	    }
-	}
-      for (unsigned i = 0; i < ec_lhs.m_vars.length (); i++)
-	{
-	  if (!ec_rhs.m_cst_sid.null_p ())
-	    visitor->on_fact (ec_lhs.m_vars[i], code, ec_rhs.m_cst_sid);
-	  for (unsigned j = 0; j < ec_rhs.m_vars.length (); j++)
-	    visitor->on_fact (ec_lhs.m_vars[i], code, ec_rhs.m_vars[j]);
-	}
-    }
-}
-
-/* Assert that this object is valid.  */
-
-void
-constraint_manager::validate () const
-{
-  /* Skip this in a release build.  */
-#if !CHECKING_P
-  return;
-#endif
-
-  int i;
-  equiv_class *ec;
-  FOR_EACH_VEC_ELT (m_equiv_classes, i, ec)
-    {
-      gcc_assert (ec);
-
-      int j;
-      svalue_id *sid;
-      FOR_EACH_VEC_ELT (ec->m_vars, j, sid)
-	{
-	  gcc_assert (!sid->null_p ());
-	  gcc_assert (sid->as_int () < get_num_svalues ());
-	}
-      if (ec->m_constant)
-	{
-	  gcc_assert (CONSTANT_CLASS_P (ec->m_constant));
-	  gcc_assert (!ec->m_cst_sid.null_p ());
-	  gcc_assert (ec->m_cst_sid.as_int () < get_num_svalues ());
-	}
-#if 0
-      else
-	gcc_assert (ec->m_vars.length () > 0);
-#endif
-    }
-
-  constraint *c;
-  FOR_EACH_VEC_ELT (m_constraints, i, c)
-    {
-      gcc_assert (!c->m_lhs.null_p ());
-      gcc_assert (c->m_lhs.as_int () <= (int)m_equiv_classes.length ());
-      gcc_assert (!c->m_rhs.null_p ());
-      gcc_assert (c->m_rhs.as_int () <= (int)m_equiv_classes.length ());
-    }
-}
-
 #if CHECKING_P
 
 namespace selftest {
 
-/* Various constraint_manager selftests.
-   These have to be written in terms of a region_model, since
-   the latter is responsible for managing svalue and svalue_id
-   instances.  */
-
-/* Verify that setting and getting simple conditions within a region_model
-   work (thus exercising the underlying constraint_manager).  */
-
-static void
-test_constraint_conditions ()
-{
-  tree int_42 = build_int_cst (integer_type_node, 42);
-  tree int_0 = build_int_cst (integer_type_node, 0);
-
-  tree x = build_global_decl ("x", integer_type_node);
-  tree y = build_global_decl ("y", integer_type_node);
-  tree z = build_global_decl ("z", integer_type_node);
-
-  /* Self-comparisons.  */
-  {
-    region_model model;
-    ASSERT_CONDITION_TRUE (model, x, EQ_EXPR, x);
-    ASSERT_CONDITION_TRUE (model, x, LE_EXPR, x);
-    ASSERT_CONDITION_TRUE (model, x, GE_EXPR, x);
-    ASSERT_CONDITION_FALSE (model, x, NE_EXPR, x);
-    ASSERT_CONDITION_FALSE (model, x, LT_EXPR, x);
-    ASSERT_CONDITION_FALSE (model, x, GT_EXPR, x);
-  }
-
-  /* x == y.  */
-  {
-    region_model model;
-    ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, y);
-
-    ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, y);
-
-    ASSERT_CONDITION_TRUE (model, x, EQ_EXPR, y);
-    ASSERT_CONDITION_TRUE (model, x, LE_EXPR, y);
-    ASSERT_CONDITION_TRUE (model, x, GE_EXPR, y);
-    ASSERT_CONDITION_FALSE (model, x, NE_EXPR, y);
-    ASSERT_CONDITION_FALSE (model, x, LT_EXPR, y);
-    ASSERT_CONDITION_FALSE (model, x, GT_EXPR, y);
-
-    /* Swapped operands.  */
-    ASSERT_CONDITION_TRUE (model, y, EQ_EXPR, x);
-    ASSERT_CONDITION_TRUE (model, y, LE_EXPR, x);
-    ASSERT_CONDITION_TRUE (model, y, GE_EXPR, x);
-    ASSERT_CONDITION_FALSE (model, y, NE_EXPR, x);
-    ASSERT_CONDITION_FALSE (model, y, LT_EXPR, x);
-    ASSERT_CONDITION_FALSE (model, y, GT_EXPR, x);
-
-    /* Comparison with other var.  */
-    ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, z);
-    ASSERT_CONDITION_UNKNOWN (model, x, LE_EXPR, z);
-    ASSERT_CONDITION_UNKNOWN (model, x, GE_EXPR, z);
-    ASSERT_CONDITION_UNKNOWN (model, x, NE_EXPR, z);
-    ASSERT_CONDITION_UNKNOWN (model, x, LT_EXPR, z);
-    ASSERT_CONDITION_UNKNOWN (model, x, GT_EXPR, z);
-  }
-
-  /* x == y, then y == z  */
-  {
-    region_model model;
-    ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, y);
-
-    ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, y);
-    ADD_SAT_CONSTRAINT (model, y, EQ_EXPR, z);
-
-    ASSERT_CONDITION_TRUE (model, x, EQ_EXPR, z);
-    ASSERT_CONDITION_TRUE (model, x, LE_EXPR, z);
-    ASSERT_CONDITION_TRUE (model, x, GE_EXPR, z);
-    ASSERT_CONDITION_FALSE (model, x, NE_EXPR, z);
-    ASSERT_CONDITION_FALSE (model, x, LT_EXPR, z);
-    ASSERT_CONDITION_FALSE (model, x, GT_EXPR, z);
-  }
-
-  /* x != y.  */
-  {
-    region_model model;
-
-    ADD_SAT_CONSTRAINT (model, x, NE_EXPR, y);
-
-    ASSERT_CONDITION_TRUE (model, x, NE_EXPR, y);
-    ASSERT_CONDITION_FALSE (model, x, EQ_EXPR, y);
-    ASSERT_CONDITION_UNKNOWN (model, x, LE_EXPR, y);
-    ASSERT_CONDITION_UNKNOWN (model, x, GE_EXPR, y);
-    ASSERT_CONDITION_UNKNOWN (model, x, LT_EXPR, y);
-    ASSERT_CONDITION_UNKNOWN (model, x, GT_EXPR, y);
-
-    /* Swapped operands.  */
-    ASSERT_CONDITION_TRUE (model, y, NE_EXPR, x);
-    ASSERT_CONDITION_FALSE (model, y, EQ_EXPR, x);
-    ASSERT_CONDITION_UNKNOWN (model, y, LE_EXPR, x);
-    ASSERT_CONDITION_UNKNOWN (model, y, GE_EXPR, x);
-    ASSERT_CONDITION_UNKNOWN (model, y, LT_EXPR, x);
-    ASSERT_CONDITION_UNKNOWN (model, y, GT_EXPR, x);
-
-    /* Comparison with other var.  */
-    ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, z);
-    ASSERT_CONDITION_UNKNOWN (model, x, LE_EXPR, z);
-    ASSERT_CONDITION_UNKNOWN (model, x, GE_EXPR, z);
-    ASSERT_CONDITION_UNKNOWN (model, x, NE_EXPR, z);
-    ASSERT_CONDITION_UNKNOWN (model, x, LT_EXPR, z);
-    ASSERT_CONDITION_UNKNOWN (model, x, GT_EXPR, z);
-  }
-
-  /* x < y.  */
-  {
-    region_model model;
-
-    ADD_SAT_CONSTRAINT (model, x, LT_EXPR, y);
-
-    ASSERT_CONDITION_TRUE (model, x, LT_EXPR, y);
-    ASSERT_CONDITION_TRUE (model, x, LE_EXPR, y);
-    ASSERT_CONDITION_TRUE (model, x, NE_EXPR, y);
-    ASSERT_CONDITION_FALSE (model, x, EQ_EXPR, y);
-    ASSERT_CONDITION_FALSE (model, x, GT_EXPR, y);
-    ASSERT_CONDITION_FALSE (model, x, GE_EXPR, y);
-
-    /* Swapped operands.  */
-    ASSERT_CONDITION_FALSE (model, y, LT_EXPR, x);
-    ASSERT_CONDITION_FALSE (model, y, LE_EXPR, x);
-    ASSERT_CONDITION_TRUE (model, y, NE_EXPR, x);
-    ASSERT_CONDITION_FALSE (model, y, EQ_EXPR, x);
-    ASSERT_CONDITION_TRUE (model, y, GT_EXPR, x);
-    ASSERT_CONDITION_TRUE (model, y, GE_EXPR, x);
-  }
-
-  /* x <= y.  */
-  {
-    region_model model;
-
-    ADD_SAT_CONSTRAINT (model, x, LE_EXPR, y);
-
-    ASSERT_CONDITION_UNKNOWN (model, x, LT_EXPR, y);
-    ASSERT_CONDITION_TRUE (model, x, LE_EXPR, y);
-    ASSERT_CONDITION_UNKNOWN (model, x, NE_EXPR, y);
-    ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, y);
-    ASSERT_CONDITION_FALSE (model, x, GT_EXPR, y);
-    ASSERT_CONDITION_UNKNOWN (model, x, GE_EXPR, y);
-
-    /* Swapped operands.  */
-    ASSERT_CONDITION_FALSE (model, y, LT_EXPR, x);
-    ASSERT_CONDITION_UNKNOWN (model, y, LE_EXPR, x);
-    ASSERT_CONDITION_UNKNOWN (model, y, NE_EXPR, x);
-    ASSERT_CONDITION_UNKNOWN (model, y, EQ_EXPR, x);
-    ASSERT_CONDITION_UNKNOWN (model, y, GT_EXPR, x);
-    ASSERT_CONDITION_TRUE (model, y, GE_EXPR, x);
-  }
-
-  /* x > y.  */
-  {
-    region_model model;
-
-    ADD_SAT_CONSTRAINT (model, x, GT_EXPR, y);
-
-    ASSERT_CONDITION_TRUE (model, x, GT_EXPR, y);
-    ASSERT_CONDITION_TRUE (model, x, GE_EXPR, y);
-    ASSERT_CONDITION_TRUE (model, x, NE_EXPR, y);
-    ASSERT_CONDITION_FALSE (model, x, EQ_EXPR, y);
-    ASSERT_CONDITION_FALSE (model, x, LT_EXPR, y);
-    ASSERT_CONDITION_FALSE (model, x, LE_EXPR, y);
-
-    /* Swapped operands.  */
-    ASSERT_CONDITION_FALSE (model, y, GT_EXPR, x);
-    ASSERT_CONDITION_FALSE (model, y, GE_EXPR, x);
-    ASSERT_CONDITION_TRUE (model, y, NE_EXPR, x);
-    ASSERT_CONDITION_FALSE (model, y, EQ_EXPR, x);
-    ASSERT_CONDITION_TRUE (model, y, LT_EXPR, x);
-    ASSERT_CONDITION_TRUE (model, y, LE_EXPR, x);
-  }
-
-  /* x >= y.  */
-  {
-    region_model model;
-
-    ADD_SAT_CONSTRAINT (model, x, GE_EXPR, y);
-
-    ASSERT_CONDITION_UNKNOWN (model, x, GT_EXPR, y);
-    ASSERT_CONDITION_TRUE (model, x, GE_EXPR, y);
-    ASSERT_CONDITION_UNKNOWN (model, x, NE_EXPR, y);
-    ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, y);
-    ASSERT_CONDITION_FALSE (model, x, LT_EXPR, y);
-    ASSERT_CONDITION_UNKNOWN (model, x, LE_EXPR, y);
-
-    /* Swapped operands.  */
-    ASSERT_CONDITION_FALSE (model, y, GT_EXPR, x);
-    ASSERT_CONDITION_UNKNOWN (model, y, GE_EXPR, x);
-    ASSERT_CONDITION_UNKNOWN (model, y, NE_EXPR, x);
-    ASSERT_CONDITION_UNKNOWN (model, y, EQ_EXPR, x);
-    ASSERT_CONDITION_UNKNOWN (model, y, LT_EXPR, x);
-    ASSERT_CONDITION_TRUE (model, y, LE_EXPR, x);
-  }
-
-  // TODO: implied orderings
-
-  /* Constants.  */
-  {
-    region_model model;
-    ASSERT_CONDITION_FALSE (model, int_0, EQ_EXPR, int_42);
-    ASSERT_CONDITION_TRUE (model, int_0, NE_EXPR, int_42);
-    ASSERT_CONDITION_TRUE (model, int_0, LT_EXPR, int_42);
-    ASSERT_CONDITION_TRUE (model, int_0, LE_EXPR, int_42);
-    ASSERT_CONDITION_FALSE (model, int_0, GT_EXPR, int_42);
-    ASSERT_CONDITION_FALSE (model, int_0, GE_EXPR, int_42);
-  }
-
-  /* x == 0, y == 42.  */
-  {
-    region_model model;
-    ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, int_0);
-    ADD_SAT_CONSTRAINT (model, y, EQ_EXPR, int_42);
-
-    ASSERT_CONDITION_TRUE (model, x, NE_EXPR, y);
-    ASSERT_CONDITION_FALSE (model, x, EQ_EXPR, y);
-    ASSERT_CONDITION_TRUE (model, x, LE_EXPR, y);
-    ASSERT_CONDITION_FALSE (model, x, GE_EXPR, y);
-    ASSERT_CONDITION_TRUE (model, x, LT_EXPR, y);
-    ASSERT_CONDITION_FALSE (model, x, GT_EXPR, y);
-  }
-
-  /* Unsatisfiable combinations.  */
-
-  /* x == y && x != y.  */
-  {
-    region_model model;
-    ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, y);
-    ADD_UNSAT_CONSTRAINT (model, x, NE_EXPR, y);
-  }
-
-  /* x == 0 then x == 42.  */
-  {
-    region_model model;
-    ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, int_0);
-    ADD_UNSAT_CONSTRAINT (model, x, EQ_EXPR, int_42);
-  }
-
-  /* x == 0 then x != 0.  */
-  {
-    region_model model;
-    ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, int_0);
-    ADD_UNSAT_CONSTRAINT (model, x, NE_EXPR, int_0);
-  }
-
-  /* x == 0 then x > 0.  */
-  {
-    region_model model;
-    ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, int_0);
-    ADD_UNSAT_CONSTRAINT (model, x, GT_EXPR, int_0);
-  }
-
-  /* x != y && x == y.  */
-  {
-    region_model model;
-    ADD_SAT_CONSTRAINT (model, x, NE_EXPR, y);
-    ADD_UNSAT_CONSTRAINT (model, x, EQ_EXPR, y);
-  }
-
-  /* x <= y && x > y.  */
-  {
-    region_model model;
-    ADD_SAT_CONSTRAINT (model, x, LE_EXPR, y);
-    ADD_UNSAT_CONSTRAINT (model, x, GT_EXPR, y);
-  }
-
-  // etc
-}
-
-/* Test transitivity of conditions.  */
-
-static void
-test_transitivity ()
-{
-  tree a = build_global_decl ("a", integer_type_node);
-  tree b = build_global_decl ("b", integer_type_node);
-  tree c = build_global_decl ("c", integer_type_node);
-  tree d = build_global_decl ("d", integer_type_node);
-
-  /* a == b, then c == d, then c == b.  */
-  {
-    region_model model;
-    ASSERT_CONDITION_UNKNOWN (model, a, EQ_EXPR, b);
-    ASSERT_CONDITION_UNKNOWN (model, b, EQ_EXPR, c);
-    ASSERT_CONDITION_UNKNOWN (model, c, EQ_EXPR, d);
-    ASSERT_CONDITION_UNKNOWN (model, a, EQ_EXPR, d);
-
-    ADD_SAT_CONSTRAINT (model, a, EQ_EXPR, b);
-    ASSERT_CONDITION_TRUE (model, a, EQ_EXPR, b);
-
-    ADD_SAT_CONSTRAINT (model, c, EQ_EXPR, d);
-    ASSERT_CONDITION_TRUE (model, c, EQ_EXPR, d);
-    ASSERT_CONDITION_UNKNOWN (model, a, EQ_EXPR, d);
-
-    ADD_SAT_CONSTRAINT (model, c, EQ_EXPR, b);
-    ASSERT_CONDITION_TRUE (model, c, EQ_EXPR, b);
-    ASSERT_CONDITION_TRUE (model, a, EQ_EXPR, d);
-  }
-
-  /* Transitivity: "a < b", "b < c" should imply "a < c".  */
-  {
-    region_model model;
-    ADD_SAT_CONSTRAINT (model, a, LT_EXPR, b);
-    ADD_SAT_CONSTRAINT (model, b, LT_EXPR, c);
-
-    ASSERT_CONDITION_TRUE (model, a, LT_EXPR, c);
-    ASSERT_CONDITION_FALSE (model, a, EQ_EXPR, c);
-  }
-
-  /* Transitivity: "a <= b", "b < c" should imply "a < c".  */
-  {
-    region_model model;
-    ADD_SAT_CONSTRAINT (model, a, LE_EXPR, b);
-    ADD_SAT_CONSTRAINT (model, b, LT_EXPR, c);
-
-    ASSERT_CONDITION_TRUE (model, a, LT_EXPR, c);
-    ASSERT_CONDITION_FALSE (model, a, EQ_EXPR, c);
-  }
-
-  /* Transitivity: "a <= b", "b <= c" should imply "a <= c".  */
-  {
-    region_model model;
-    ADD_SAT_CONSTRAINT (model, a, LE_EXPR, b);
-    ADD_SAT_CONSTRAINT (model, b, LE_EXPR, c);
-
-    ASSERT_CONDITION_TRUE (model, a, LE_EXPR, c);
-    ASSERT_CONDITION_UNKNOWN (model, a, EQ_EXPR, c);
-  }
-
-  /* Transitivity: "a > b", "b > c" should imply "a > c".  */
-  {
-    region_model model;
-    ADD_SAT_CONSTRAINT (model, a, GT_EXPR, b);
-    ADD_SAT_CONSTRAINT (model, b, GT_EXPR, c);
-
-    ASSERT_CONDITION_TRUE (model, a, GT_EXPR, c);
-    ASSERT_CONDITION_FALSE (model, a, EQ_EXPR, c);
-  }
-
-  /* Transitivity: "a >= b", "b > c" should imply " a > c".  */
-  {
-    region_model model;
-    ADD_SAT_CONSTRAINT (model, a, GE_EXPR, b);
-    ADD_SAT_CONSTRAINT (model, b, GT_EXPR, c);
-
-    ASSERT_CONDITION_TRUE (model, a, GT_EXPR, c);
-    ASSERT_CONDITION_FALSE (model, a, EQ_EXPR, c);
-  }
-
-  /* Transitivity: "a >= b", "b >= c" should imply "a >= c".  */
-  {
-    region_model model;
-    ADD_SAT_CONSTRAINT (model, a, GE_EXPR, b);
-    ADD_SAT_CONSTRAINT (model, b, GE_EXPR, c);
-
-    ASSERT_CONDITION_TRUE (model, a, GE_EXPR, c);
-    ASSERT_CONDITION_UNKNOWN (model, a, EQ_EXPR, c);
-  }
-
-  /* Transitivity: "(a < b)", "(c < d)", "(b < c)" should
-     imply the easy cases:
-       (a < c)
-       (b < d)
-     but also that:
-       (a < d).  */
-  {
-    region_model model;
-    ADD_SAT_CONSTRAINT (model, a, LT_EXPR, b);
-    ADD_SAT_CONSTRAINT (model, c, LT_EXPR, d);
-    ADD_SAT_CONSTRAINT (model, b, LT_EXPR, c);
-
-    ASSERT_CONDITION_TRUE (model, a, LT_EXPR, c);
-    ASSERT_CONDITION_TRUE (model, b, LT_EXPR, d);
-    ASSERT_CONDITION_TRUE (model, a, LT_EXPR, d);
-  }
-
-  /* Transitivity: "a >= b", "b >= a" should imply that a == b.  */
-  {
-    region_model model;
-    ADD_SAT_CONSTRAINT (model, a, GE_EXPR, b);
-    ADD_SAT_CONSTRAINT (model, b, GE_EXPR, a);
-
-    // TODO:
-    ASSERT_CONDITION_TRUE (model, a, EQ_EXPR, b);
-  }
-
-  /* Transitivity: "a >= b", "b > a" should be impossible.  */
-  {
-    region_model model;
-    ADD_SAT_CONSTRAINT (model, a, GE_EXPR, b);
-    ADD_UNSAT_CONSTRAINT (model, b, GT_EXPR, a);
-  }
-
-  /* Transitivity: "a >= b", "b >= c", "c >= a" should imply
-     that a == b == c.  */
-  {
-    region_model model;
-    ADD_SAT_CONSTRAINT (model, a, GE_EXPR, b);
-    ADD_SAT_CONSTRAINT (model, b, GE_EXPR, c);
-    ADD_SAT_CONSTRAINT (model, c, GE_EXPR, a);
-
-    ASSERT_CONDITION_TRUE (model, a, EQ_EXPR, c);
-  }
-
-  /* Transitivity: "a > b", "b > c", "c > a"
-     should be impossible.  */
-  {
-    region_model model;
-    ADD_SAT_CONSTRAINT (model, a, GT_EXPR, b);
-    ADD_SAT_CONSTRAINT (model, b, GT_EXPR, c);
-    ADD_UNSAT_CONSTRAINT (model, c, GT_EXPR, a);
-  }
-
-}
-
-/* Test various conditionals involving constants where the results
-   ought to be implied based on the values of the constants.  */
-
-static void
-test_constant_comparisons ()
-{
-  tree int_3 = build_int_cst (integer_type_node, 3);
-  tree int_4 = build_int_cst (integer_type_node, 4);
-  tree int_5 = build_int_cst (integer_type_node, 5);
-
-  tree int_1023 = build_int_cst (integer_type_node, 1023);
-  tree int_1024 = build_int_cst (integer_type_node, 1024);
-
-  tree a = build_global_decl ("a", integer_type_node);
-  tree b = build_global_decl ("b", integer_type_node);
-
-  /* Given a >= 1024, then a <= 1023 should be impossible.  */
-  {
-    region_model model;
-    ADD_SAT_CONSTRAINT (model, a, GE_EXPR, int_1024);
-    ADD_UNSAT_CONSTRAINT (model, a, LE_EXPR, int_1023);
-  }
-
-  /* a > 4.  */
-  {
-    region_model model;
-    ADD_SAT_CONSTRAINT (model, a, GT_EXPR, int_4);
-    ASSERT_CONDITION_TRUE (model, a, GT_EXPR, int_4);
-    ASSERT_CONDITION_TRUE (model, a, NE_EXPR, int_3);
-    ASSERT_CONDITION_UNKNOWN (model, a, NE_EXPR, int_5);
-  }
-
-  /* a <= 4.  */
-  {
-    region_model model;
-    ADD_SAT_CONSTRAINT (model, a, LE_EXPR, int_4);
-    ASSERT_CONDITION_FALSE (model, a, GT_EXPR, int_4);
-    ASSERT_CONDITION_FALSE (model, a, GT_EXPR, int_5);
-    ASSERT_CONDITION_UNKNOWN (model, a, NE_EXPR, int_3);
-  }
-
-  /* If "a > b" and "a == 3", then "b == 4" ought to be unsatisfiable.  */
-  {
-    region_model model;
-    ADD_SAT_CONSTRAINT (model, a, GT_EXPR, b);
-    ADD_SAT_CONSTRAINT (model, a, EQ_EXPR, int_3);
-    ADD_UNSAT_CONSTRAINT (model, b, EQ_EXPR, int_4);
-  }
-
-  /* Various tests of int ranges where there is only one possible candidate.  */
-  {
-    /* If "a <= 4" && "a > 3", then "a == 4",
-       assuming a is of integral type.  */
-    {
-      region_model model;
-      ADD_SAT_CONSTRAINT (model, a, LE_EXPR, int_4);
-      ADD_SAT_CONSTRAINT (model, a, GT_EXPR, int_3);
-      ASSERT_CONDITION_TRUE (model, a, EQ_EXPR, int_4);
-    }
-
-    /* If "a > 3" && "a <= 4", then "a == 4",
-       assuming a is of integral type.  */
-    {
-      region_model model;
-      ADD_SAT_CONSTRAINT (model, a, GT_EXPR, int_3);
-      ADD_SAT_CONSTRAINT (model, a, LE_EXPR, int_4);
-      ASSERT_CONDITION_TRUE (model, a, EQ_EXPR, int_4);
-    }
-    /* If "a > 3" && "a < 5", then "a == 4",
-       assuming a is of integral type.  */
-    {
-      region_model model;
-      ADD_SAT_CONSTRAINT (model, a, GT_EXPR, int_3);
-      ADD_SAT_CONSTRAINT (model, a, LT_EXPR, int_5);
-      ASSERT_CONDITION_TRUE (model, a, EQ_EXPR, int_4);
-    }
-    /* If "a >= 4" && "a < 5", then "a == 4",
-       assuming a is of integral type.  */
-    {
-      region_model model;
-      ADD_SAT_CONSTRAINT (model, a, GE_EXPR, int_4);
-      ADD_SAT_CONSTRAINT (model, a, LT_EXPR, int_5);
-      ASSERT_CONDITION_TRUE (model, a, EQ_EXPR, int_4);
-    }
-    /* If "a >= 4" && "a <= 4", then "a == 4".  */
-    {
-      region_model model;
-      ADD_SAT_CONSTRAINT (model, a, GE_EXPR, int_4);
-      ADD_SAT_CONSTRAINT (model, a, LE_EXPR, int_4);
-      ASSERT_CONDITION_TRUE (model, a, EQ_EXPR, int_4);
-    }
-  }
-
-  /* As above, but for floating-point:
-     if "f > 3" && "f <= 4" we don't know that f == 4.  */
-  {
-    tree f = build_global_decl ("f", double_type_node);
-    tree float_3 = build_real_from_int_cst (double_type_node, int_3);
-    tree float_4 = build_real_from_int_cst (double_type_node, int_4);
-
-    region_model model;
-    ADD_SAT_CONSTRAINT (model, f, GT_EXPR, float_3);
-    ADD_SAT_CONSTRAINT (model, f, LE_EXPR, float_4);
-    ASSERT_CONDITION_UNKNOWN (model, f, EQ_EXPR, float_4);
-    ASSERT_CONDITION_UNKNOWN (model, f, EQ_EXPR, int_4);
-  }
-}
-
-/* Verify various lower-level implementation details about
-   constraint_manager.  */
-
-static void
-test_constraint_impl ()
-{
-  tree int_42 = build_int_cst (integer_type_node, 42);
-  tree int_0 = build_int_cst (integer_type_node, 0);
-
-  tree x = build_global_decl ("x", integer_type_node);
-  tree y = build_global_decl ("y", integer_type_node);
-  tree z = build_global_decl ("z", integer_type_node);
-
-  /* x == y.  */
-  {
-    region_model model;
-
-    ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, y);
-
-    /* Assert various things about the insides of model.  */
-    constraint_manager *cm = model.get_constraints ();
-    ASSERT_EQ (cm->m_constraints.length (), 0);
-    ASSERT_EQ (cm->m_equiv_classes.length (), 1);
-  }
-
-  /* y <= z; x == y.  */
-  {
-    region_model model;
-    ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, y);
-    ASSERT_CONDITION_UNKNOWN (model, x, GE_EXPR, z);
-
-    ADD_SAT_CONSTRAINT (model, y, GE_EXPR, z);
-    ASSERT_CONDITION_TRUE (model, y, GE_EXPR, z);
-    ASSERT_CONDITION_UNKNOWN (model, x, GE_EXPR, z);
-
-    ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, y);
-
-    /* Assert various things about the insides of model.  */
-    constraint_manager *cm = model.get_constraints ();
-    ASSERT_EQ (cm->m_constraints.length (), 1);
-    ASSERT_EQ (cm->m_equiv_classes.length (), 2);
-
-    /* Ensure that we merged the constraints.  */
-    ASSERT_CONDITION_TRUE (model, x, GE_EXPR, z);
-  }
-
-  /* y <= z; y == x.  */
-  {
-    region_model model;
-    ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, y);
-    ASSERT_CONDITION_UNKNOWN (model, x, GE_EXPR, z);
-
-    ADD_SAT_CONSTRAINT (model, y, GE_EXPR, z);
-    ASSERT_CONDITION_TRUE (model, y, GE_EXPR, z);
-    ASSERT_CONDITION_UNKNOWN (model, x, GE_EXPR, z);
-
-    ADD_SAT_CONSTRAINT (model, y, EQ_EXPR, x);
-
-    /* Assert various things about the insides of model.  */
-    constraint_manager *cm = model.get_constraints ();
-    ASSERT_EQ (cm->m_constraints.length (), 1);
-    ASSERT_EQ (cm->m_equiv_classes.length (), 2);
-
-    /* Ensure that we merged the constraints.  */
-    ASSERT_CONDITION_TRUE (model, x, GE_EXPR, z);
-  }
-
-  /* x == 0, then x != 42.  */
-  {
-    region_model model;
-
-    ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, int_0);
-    ADD_SAT_CONSTRAINT (model, x, NE_EXPR, int_42);
-
-    /* Assert various things about the insides of model.  */
-    constraint_manager *cm = model.get_constraints ();
-    ASSERT_EQ (cm->m_constraints.length (), 1);
-    ASSERT_EQ (cm->m_equiv_classes.length (), 2);
-    ASSERT_EQ (cm->m_constraints[0].m_lhs,
-	       cm->get_or_add_equiv_class (model.get_rvalue (int_0, NULL)));
-    ASSERT_EQ (cm->m_constraints[0].m_rhs,
-	       cm->get_or_add_equiv_class (model.get_rvalue (int_42, NULL)));
-    ASSERT_EQ (cm->m_constraints[0].m_op, CONSTRAINT_LT);
-  }
-
-  // TODO: selftest for merging ecs "in the middle"
-  // where a non-final one gets overwritten
-
-  // TODO: selftest where there are pre-existing constraints
-}
-
-/* Check that operator== and hashing works as expected for the
-   various types.  */
-
-static void
-test_equality ()
-{
-  tree x = build_global_decl ("x", integer_type_node);
-  tree y = build_global_decl ("y", integer_type_node);
-
-  {
-    region_model model0;
-    region_model model1;
-
-    constraint_manager *cm0 = model0.get_constraints ();
-    constraint_manager *cm1 = model1.get_constraints ();
-
-    ASSERT_EQ (cm0->hash (), cm1->hash ());
-    ASSERT_EQ (*cm0, *cm1);
-
-    ASSERT_EQ (model0.hash (), model1.hash ());
-    ASSERT_EQ (model0, model1);
-
-    ADD_SAT_CONSTRAINT (model1, x, EQ_EXPR, y);
-    ASSERT_NE (cm0->hash (), cm1->hash ());
-    ASSERT_NE (*cm0, *cm1);
-
-    ASSERT_NE (model0.hash (), model1.hash ());
-    ASSERT_NE (model0, model1);
-
-    region_model model2;
-    constraint_manager *cm2 = model2.get_constraints ();
-    /* Make the same change to cm2.  */
-    ADD_SAT_CONSTRAINT (model2, x, EQ_EXPR, y);
-    ASSERT_EQ (cm1->hash (), cm2->hash ());
-    ASSERT_EQ (*cm1, *cm2);
-
-    ASSERT_EQ (model1.hash (), model2.hash ());
-    ASSERT_EQ (model1, model2);
-  }
-}
-
-/* Verify tracking inequality of a variable against many constants.  */
-
-static void
-test_many_constants ()
-{
-  tree a = build_global_decl ("a", integer_type_node);
-
-  region_model model;
-  auto_vec<tree> constants;
-  for (int i = 0; i < 20; i++)
-    {
-      tree constant = build_int_cst (integer_type_node, i);
-      constants.safe_push (constant);
-      ADD_SAT_CONSTRAINT (model, a, NE_EXPR, constant);
-
-      /* Merge, and check the result.  */
-      region_model other (model);
-
-      region_model merged;
-      ASSERT_TRUE (model.can_merge_with_p (other, &merged));
-      model.canonicalize (NULL);
-      merged.canonicalize (NULL);
-      ASSERT_EQ (model, merged);
-
-      for (int j = 0; j <= i; j++)
-	ASSERT_CONDITION_TRUE (model, a, NE_EXPR, constants[j]);
-    }
-}
-
-/* Run the selftests in this file, temporarily overriding
-   flag_analyzer_transitivity with TRANSITIVITY.  */
-
-static void
-run_constraint_manager_tests (bool transitivity)
-{
-  int saved_flag_analyzer_transitivity = flag_analyzer_transitivity;
-  flag_analyzer_transitivity = transitivity;
-
-  test_constraint_conditions ();
-  if (flag_analyzer_transitivity)
-    {
-      /* These selftests assume transitivity.  */
-      test_transitivity ();
-      test_constant_comparisons ();
-    }
-  test_constraint_impl ();
-  test_equality ();
-  test_many_constants ();
-
-  flag_analyzer_transitivity = saved_flag_analyzer_transitivity;
-}
-
 /* Run all of the selftests within this file.  */
 
 void
 analyzer_constraint_manager_cc_tests ()
 {
-  /* Run the tests twice: with and without transitivity.  */
-  run_constraint_manager_tests (true);
-  run_constraint_manager_tests (false);
 }
 
 } // namespace selftest
diff --git a/gcc/analyzer/constraint-manager.h b/gcc/analyzer/constraint-manager.h
index 0f4506cc40d..e65ad827ce2 100644
--- a/gcc/analyzer/constraint-manager.h
+++ b/gcc/analyzer/constraint-manager.h
@@ -23,228 +23,6 @@ along with GCC; see the file COPYING3.  If not see
 
 namespace ana {
 
-class constraint_manager;
-
-/* Abstract base class for specifying how state should be purged.  */
-
-class purge_criteria
-{
-public:
-  virtual ~purge_criteria () {}
-  virtual bool should_purge_p (svalue_id sid) const = 0;
-};
-
-/* An equivalence class within a constraint manager: a set of
-   svalue_ids that are known to all be equal to each other,
-   together with an optional tree constant that they are equal to.  */
-
-class equiv_class
-{
-public:
-  equiv_class ();
-  equiv_class (const equiv_class &other);
-
-  hashval_t hash () const;
-  bool operator== (const equiv_class &other);
-
-  void add (svalue_id sid, const constraint_manager &cm);
-  bool del (svalue_id sid);
-
-  tree get_any_constant () const { return m_constant; }
-
-  svalue_id get_representative () const;
-
-  void remap_svalue_ids (const svalue_id_map &map);
-
-  void canonicalize ();
-
-  void print (pretty_printer *pp) const;
-
-  /* An equivalence class can contain multiple constants (e.g. multiple
-     different zeroes, for different types); these are just for the last
-     constant added.  */
-  tree m_constant;
-  svalue_id m_cst_sid;
-
-  // TODO: should this be a set rather than a vec?
-  auto_vec<svalue_id> m_vars;
-};
-
-/* The various kinds of constraint.  */
-
-enum constraint_op
-{
-  CONSTRAINT_NE,
-  CONSTRAINT_LT,
-  CONSTRAINT_LE
-};
-
-const char *constraint_op_code (enum constraint_op c_op);
-
-/* An ID for an equiv_class within a constraint_manager.  Internally, this
-   is an index into a vector of equiv_class * within the constraint_manager.  */
-
-class equiv_class_id
-{
-public:
-  static equiv_class_id null () { return equiv_class_id (-1); }
-
-  equiv_class_id (unsigned idx) : m_idx (idx) {}
-  const equiv_class &get_obj (const constraint_manager &cm) const;
-  equiv_class &get_obj (constraint_manager &cm) const;
-
-  bool operator== (const equiv_class_id &other) const
-  {
-    return m_idx == other.m_idx;
-  }
-  bool operator!= (const equiv_class_id &other) const
-  {
-    return m_idx != other.m_idx;
-  }
-
-  bool null_p () const { return m_idx == -1; }
-
-  static equiv_class_id from_int (int idx) { return equiv_class_id (idx); }
-  int as_int () const { return m_idx; }
-
-  void print (pretty_printer *pp) const;
-
-  void update_for_removal (equiv_class_id other)
-  {
-    if (m_idx > other.m_idx)
-      m_idx--;
-  }
-
-  int m_idx;
-};
-
-/* A relationship between two equivalence classes in a constraint_manager.  */
-
-class constraint
-{
- public:
-  constraint (equiv_class_id lhs, enum constraint_op c_op, equiv_class_id rhs)
-  : m_lhs (lhs), m_op (c_op), m_rhs (rhs)
-  {
-    gcc_assert (!lhs.null_p ());
-    gcc_assert (!rhs.null_p ());
-  }
-
-  void print (pretty_printer *pp, const constraint_manager &cm) const;
-
-  hashval_t hash () const;
-  bool operator== (const constraint &other) const;
-
-  /* Is this an ordering, rather than a "!=".  */
-  bool is_ordering_p () const
-  {
-    return m_op != CONSTRAINT_NE;
-  }
-
-  equiv_class_id m_lhs;
-  enum constraint_op m_op;
-  equiv_class_id m_rhs;
-};
-
-/* An abstract base class for use with constraint_manager::for_each_fact.  */
-
-class fact_visitor
-{
- public:
-  virtual ~fact_visitor () {}
-  virtual void on_fact (svalue_id lhs, enum tree_code, svalue_id rhs) = 0;
-};
-
-/* A collection of equivalence classes and constraints on them.
-
-   Given N svalues, this can be thought of as representing a subset of
-   N-dimensional space.  When we call add_constraint,
-   we are effectively taking an intersection with that constraint.  */
-
-class constraint_manager
-{
-public:
-  constraint_manager () {}
-  constraint_manager (const constraint_manager &other);
-  virtual ~constraint_manager () {}
-
-  virtual constraint_manager *clone (region_model *) const = 0;
-  virtual tree maybe_get_constant (svalue_id sid) const = 0;
-  virtual svalue_id get_sid_for_constant (tree cst) const = 0;
-  virtual int get_num_svalues () const = 0;
-
-  constraint_manager& operator= (const constraint_manager &other);
-
-  hashval_t hash () const;
-  bool operator== (const constraint_manager &other) const;
-  bool operator!= (const constraint_manager &other) const
-  {
-    return !(*this == other);
-  }
-
-  void print (pretty_printer *pp) const;
-  void dump_to_pp (pretty_printer *pp) const;
-  void dump (FILE *fp) const;
-  void dump () const;
-
-  const equiv_class &get_equiv_class_by_index (unsigned idx) const
-  {
-    return *m_equiv_classes[idx];
-  }
-  equiv_class &get_equiv_class_by_index (unsigned idx)
-  {
-    return *m_equiv_classes[idx];
-  }
-
-  equiv_class &get_equiv_class (svalue_id sid)
-  {
-    equiv_class_id ec_id = get_or_add_equiv_class (sid);
-    return ec_id.get_obj (*this);
-  }
-
-  bool add_constraint (svalue_id lhs, enum tree_code op, svalue_id rhs);
-
-  bool add_constraint (equiv_class_id lhs_ec_id,
-		       enum tree_code op,
-		       equiv_class_id rhs_ec_id);
-
-  bool get_equiv_class_by_sid (svalue_id sid, equiv_class_id *out) const;
-  equiv_class_id get_or_add_equiv_class (svalue_id sid);
-  tristate eval_condition (equiv_class_id lhs,
-			   enum tree_code op,
-			   equiv_class_id rhs);
-  tristate eval_condition (svalue_id lhs,
-			   enum tree_code op,
-			   svalue_id rhs);
-
-  void purge (const purge_criteria &p, purge_stats *stats);
-
-  void remap_svalue_ids (const svalue_id_map &map);
-
-  void canonicalize (unsigned num_svalue_ids);
-
-  static void merge (const constraint_manager &cm_a,
-		     const constraint_manager &cm_b,
-		     constraint_manager *out,
-		     const model_merger &merger);
-
-  void for_each_fact (fact_visitor *) const;
-
-  void validate () const;
-
-  auto_delete_vec<equiv_class> m_equiv_classes;
-  auto_vec<constraint> m_constraints;
-
- private:
-  static void clean_merger_input (const constraint_manager &cm_in,
-				  const one_way_svalue_id_map &map_sid_to_m,
-				  constraint_manager *out);
-
-  void add_constraint_internal (equiv_class_id lhs_id,
-				enum constraint_op c_op,
-				equiv_class_id rhs_id);
-};
-
 } // namespace ana
 
 #endif /* GCC_ANALYZER_CONSTRAINT_MANAGER_H */
diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc
index f7c63080caf..a0e1ddb45b1 100644
--- a/gcc/analyzer/diagnostic-manager.cc
+++ b/gcc/analyzer/diagnostic-manager.cc
@@ -379,10 +379,7 @@ public:
 
     feasibility_problem *p = NULL;
     bool feasible;
-    if (m_engine2)
-      feasible = dc->get_path ().feasible2_p (logger, &p, m_engine2, eg);
-    else
-      feasible = dc->get_path ().feasible_p (logger, &p);
+    feasible = dc->get_path ().feasible2_p (logger, &p, m_engine2, eg);
     if (!feasible)
       {
 	if (logger)
@@ -609,12 +606,15 @@ get_any_origin (const gimple *stmt,
 
   gcc_assert (dst_rep);
 
+#if 0
   // TODO:
   if (dst_state.m_region_model == NULL)
     return NULL;
+#endif
 
   if (const gassign *assign = dyn_cast <const gassign *> (stmt))
     {
+#if 0
       tree lhs = gimple_assign_lhs (assign);
       /* Use region IDs to compare lhs with DST_REP, bulletproofing against
 	 cases where they can't have lvalues by using
@@ -637,6 +637,7 @@ get_any_origin (const gimple *stmt,
 	      return rhs1;
 	    }
 	}
+#endif
     }
   return NULL_TREE;
 }
@@ -667,178 +668,6 @@ diagnostic_manager::build_emission_path (const path_builder &pb,
     }
 }
 
-/* Subclass of state_change_visitor that creates state_change_event
-   instances.  */
-
-class state_change_event_creator : public state_change_visitor
-{
-public:
-  state_change_event_creator (const exploded_edge &eedge,
-			      checker_path *emission_path)
-    : m_eedge (eedge),
-      m_emission_path (emission_path)
-  {}
-
-  bool on_global_state_change (const state_machine &sm,
-			       state_machine::state_t src_sm_val,
-			       state_machine::state_t dst_sm_val)
-    FINAL OVERRIDE
-  {
-    const exploded_node *src_node = m_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 = m_eedge.m_dest;
-    const gimple *stmt = src_point.get_stmt ();
-    const supernode *supernode = src_point.get_supernode ();
-    const program_state &dst_state = dst_node->get_state ();
-
-    int stack_depth = src_stack_depth;
-
-    m_emission_path->add_event (new state_change_event (supernode,
-							stmt,
-							stack_depth,
-							sm,
-							NULL_TREE,
-							src_sm_val,
-							dst_sm_val,
-							NULL_TREE,
-							dst_state));
-    return false;
-  }
-
-  bool on_state_change (const state_machine &sm,
-			state_machine::state_t src_sm_val,
-			state_machine::state_t dst_sm_val,
-			tree dst_rep,
-			svalue_id dst_origin_sid) FINAL OVERRIDE
-  {
-    const exploded_node *src_node = m_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 = m_eedge.m_dest;
-    const gimple *stmt = src_point.get_stmt ();
-    const supernode *supernode = src_point.get_supernode ();
-    const program_state &dst_state = dst_node->get_state ();
-
-    int stack_depth = src_stack_depth;
-
-    if (m_eedge.m_sedge
-	&& m_eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE)
-      {
-	supernode = src_point.get_supernode ();
-	stmt = supernode->get_last_stmt ();
-	stack_depth = src_stack_depth;
-      }
-
-    /* Bulletproofing for state changes at calls/returns;
-       TODO: is there a better way? */
-    if (!stmt)
-      return false;
-
-    tree origin_rep
-      = dst_state.get_representative_tree (dst_origin_sid);
-
-    if (origin_rep == NULL_TREE)
-      origin_rep = get_any_origin (stmt, dst_rep, dst_state);
-    m_emission_path->add_event (new state_change_event (supernode,
-							stmt,
-							stack_depth,
-							sm,
-							dst_rep,
-							src_sm_val,
-							dst_sm_val,
-							origin_rep,
-							dst_state));
-    return false;
-  }
-
-  const exploded_edge &m_eedge;
-  checker_path *m_emission_path;
-};
-
-/* Compare SRC_STATE and DST_STATE (which use EXT_STATE), and call
-   VISITOR's on_state_change for every sm-state change that occurs
-   to a tree, and on_global_state_change for every global state change
-   that occurs.
-
-   This determines the state changes that ought to be reported to
-   the user: a combination of the effects of changes to sm_state_map
-   (which maps svalues to sm-states), and of region_model changes
-   (which map trees to svalues).
-
-   Bail out early and return true if any call to on_global_state_change
-   or on_state_change returns true, otherwise return false.
-
-   This is split out to make it easier to experiment with changes to
-   exploded_node granularity (so that we can observe what state changes
-   lead to state_change_events being emitted).  */
-
-bool
-for_each_state_change (const program_state &src_state,
-		       const program_state &dst_state,
-		       const extrinsic_state &ext_state,
-		       state_change_visitor *visitor)
-{
-  gcc_assert (src_state.m_checker_states.length ()
-	      == ext_state.get_num_checkers ());
-  gcc_assert (dst_state.m_checker_states.length ()
-	      == ext_state.get_num_checkers ());
-  for (unsigned i = 0; i < ext_state.get_num_checkers (); i++)
-    {
-      const state_machine &sm = ext_state.get_sm (i);
-      const sm_state_map &src_smap = *src_state.m_checker_states[i];
-      const sm_state_map &dst_smap = *dst_state.m_checker_states[i];
-
-      /* Add events for any global state changes.  */
-      if (src_smap.get_global_state () != dst_smap.get_global_state ())
-	if (visitor->on_global_state_change (sm,
-					     src_smap.get_global_state (),
-					     dst_smap.get_global_state ()))
-	  return true;
-
-      /* Add events for per-svalue state changes.  */
-      for (sm_state_map::iterator_t iter = dst_smap.begin ();
-	   iter != dst_smap.end ();
-	   ++iter)
-	{
-	  /* Ideally we'd directly compare the SM state between src state
-	     and dst state, but there's no guarantee that the IDs can
-	     be meaningfully compared.  */
-	  svalue_id dst_sid = (*iter).first;
-	  state_machine::state_t dst_sm_val = (*iter).second.m_state;
-
-	  auto_vec<path_var> dst_pvs;
-	  dst_state.m_region_model->get_path_vars_for_svalue (dst_sid,
-							      &dst_pvs);
-
-	  unsigned j;
-	  path_var *dst_pv;
-	  FOR_EACH_VEC_ELT (dst_pvs, j, dst_pv)
-	    {
-	      tree dst_rep = dst_pv->m_tree;
-	      gcc_assert (dst_rep);
-	      if (dst_pv->m_stack_depth
-		  >= src_state.m_region_model->get_stack_depth ())
-		continue;
-	      tentative_region_model_context ctxt;
-	      svalue_id src_sid
-		= src_state.m_region_model->get_rvalue (*dst_pv, &ctxt);
-	      if (src_sid.null_p () || ctxt.had_errors_p ())
-		continue;
-	      state_machine::state_t src_sm_val = src_smap.get_state (src_sid);
-	      if (dst_sm_val != src_sm_val)
-		{
-		  svalue_id dst_origin_sid = (*iter).second.m_origin;
-		  if (visitor->on_state_change (sm, src_sm_val, dst_sm_val,
-						dst_rep, dst_origin_sid))
-		    return true;
-		}
-	    }
-	}
-    }
-  return false;
-}
-
 /* Subclass of state_change_visitor that creates state_change_event
    instances.  */
 
@@ -1165,18 +994,9 @@ diagnostic_manager::add_events_for_eedge (const path_builder &pb,
       | ~~~~~~~~~~~~~^~~~~
       |              |
       |              (3) ...to here        (end_cfg_edge_event).  */
-  if (src_state.m_region_model)
-    {
-      state_change_event_creator visitor (eedge, emission_path);
-      for_each_state_change (src_state, dst_state, pb.get_ext_state (),
-			     &visitor);
-    }
-  if (src_state.m_region_model2)
-    {
-      state_change_event_creator2 visitor2 (eedge, emission_path);
-      for_each_state_change2 (src_state, dst_state, pb.get_ext_state (),
-			      &visitor2);
-    }
+  state_change_event_creator2 visitor2 (eedge, emission_path);
+  for_each_state_change2 (src_state, dst_state, pb.get_ext_state (),
+			  &visitor2);
 
   /* Allow non-standard edges to add events, e.g. when rewinding from
      longjmp to a setjmp.  */
@@ -1439,10 +1259,7 @@ diagnostic_manager::prune_path (checker_path *path,
 {
   LOG_FUNC (get_logger ());
   path->maybe_log (get_logger (), "path");
-  if (get_engine2 ())
-    prune_for_sm_diagnostic2 (path, sm, sval, state);
-  else
-    prune_for_sm_diagnostic (path, sm, var, state);
+  prune_for_sm_diagnostic2 (path, sm, sval, state);
   prune_interproc_events (path);
   finish_pruning (path);
   path->maybe_log (get_logger (), "pruned");
@@ -1467,282 +1284,6 @@ can_be_expr_of_interest_p (tree expr)
   return true;
 }
 
-// FIXME: old implementation:
-/* First pass of diagnostic_manager::prune_path: apply verbosity level,
-   pruning unrelated state change events.
-
-   Iterate backwards through PATH, skipping state change events that aren't
-   VAR but update the pertinent VAR when state-copying occurs.
-
-   As well as deleting events, call record_critical_state on events in
-   which state critical to the pending_diagnostic is being handled, so
-   that the event's get_desc vfunc can potentially supply a more precise
-   description of the event to the user.
-   e.g. improving
-     "calling 'foo' from 'bar'"
-   to
-     "passing possibly-NULL pointer 'ptr' to 'foo' from 'bar' as param 1"
-   when the diagnostic relates to later dereferencing 'ptr'.  */
-
-void
-diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
-					     const state_machine *sm,
-					     tree var,
-					     state_machine::state_t state) const
-{
-  update_for_unsuitable_sm_exprs (&var);
-
-  int idx = path->num_events () - 1;
-  while (idx >= 0 && idx < (signed)path->num_events ())
-    {
-      checker_event *base_event = path->get_checker_event (idx);
-      if (get_logger ())
-	{
-	  if (sm)
-	    {
-	      if (var)
-		log ("considering event %i, with var: %qE, state: %qs",
-		     idx, var, sm->get_state_name (state));
-	      else
-		log ("considering event %i, with global state: %qs",
-		     idx, sm->get_state_name (state));
-	    }
-	  else
-	    log ("considering event %i", idx);
-	}
-      gcc_assert (var == NULL || can_be_expr_of_interest_p (var));
-      switch (base_event->m_kind)
-	{
-	default:
-	  gcc_unreachable ();
-
-	case EK_DEBUG:
-	  if (m_verbosity < 4)
-	    {
-	      log ("filtering event %i: debug event", idx);
-	      path->delete_event (idx);
-	    }
-	  break;
-
-	case EK_CUSTOM:
-	  /* Don't filter custom events.  */
-	  break;
-
-	case EK_STMT:
-	  {
-	    /* If this stmt is the origin of "var", update var.  */
-	    if (var)
-	      {
-		statement_event *stmt_event = (statement_event *)base_event;
-		tree new_var = get_any_origin (stmt_event->m_stmt, var,
-					       stmt_event->m_dst_state);
-		if (new_var)
-		  {
-		    log ("event %i: switching var of interest from %qE to %qE",
-			 idx, var, new_var);
-		    var = new_var;
-		  }
-	      }
-	    if (m_verbosity < 4)
-	      {
-		log ("filtering event %i: statement event", idx);
-		path->delete_event (idx);
-	      }
-	  }
-	  break;
-
-	case EK_FUNCTION_ENTRY:
-	  if (m_verbosity < 1)
-	    {
-	      log ("filtering event %i: function entry", idx);
-	      path->delete_event (idx);
-	    }
-	  break;
-
-	case EK_STATE_CHANGE:
-	  {
-	    state_change_event *state_change = (state_change_event *)base_event;
-	    bool same_region = false;
-	    bool ctxt_had_errors = false;
-	    if (state_change->m_dst_state.m_region_model2)
-	      {
-		/* Use regions to compare var with the state_change's m_var,
-		   bulletproofing against cases where they can't have lvalues by
-		   using tentative_region_model_context.  */
-		tentative_region_model2_context ctxt;
-		const region2 *state_var_reg
-		  = state_change->get_lvalue2 (state_change->m_var, &ctxt);
-		const region2 *var_reg = state_change->get_lvalue2 (var, &ctxt);
-		ctxt_had_errors = ctxt.had_errors_p ();
-		same_region = (state_var_reg == var_reg && !ctxt.had_errors_p ());
-	      }
-	    else
-	      {
-		/* Use region IDs to compare var with the state_change's m_var,
-		   bulletproofing against cases where they can't have lvalues by
-		   using tentative_region_model_context.  */
-		tentative_region_model_context ctxt;
-		region_id state_var_rid
-		  = state_change->get_lvalue (state_change->m_var, &ctxt);
-		region_id var_rid = state_change->get_lvalue (var, &ctxt);
-		ctxt_had_errors = ctxt.had_errors_p ();
-		same_region = (state_var_rid == var_rid && !ctxt.had_errors_p ());
-	      }
-	    if (same_region)
-	      {
-		if (state_change->m_origin)
-		  {
-		    log ("event %i: switching var of interest from %qE to %qE",
-			 idx, var, state_change->m_origin);
-		    var = state_change->m_origin;
-		    update_for_unsuitable_sm_exprs (&var);
-		  }
-		log ("event %i: switching state of interest from %qs to %qs",
-		     idx, sm->get_state_name (state_change->m_to),
-		     sm->get_state_name (state_change->m_from));
-		state = state_change->m_from;
-	      }
-	    else if (m_verbosity < 4)
-	      {
-		if (var && state_change->m_var)
-		  log ("filtering event %i:"
-		       " state change to %qE unrelated to %qE",
-		       idx, state_change->m_var, var);
-		else if (state_change->m_var)
-		  log ("filtering event %i: state change to %qE",
-		       idx, state_change->m_var);
-		else
-		  log ("filtering event %i: global state change", idx);
-		if (ctxt_had_errors)
-		  log ("context had errors");
-		path->delete_event (idx);
-	      }
-	  }
-	  break;
-
-	case EK_STATE_CHANGE2:
-	  /* Old implementation should create EK_STATE_CHANGE instead.  */
-	  gcc_unreachable ();
-
-	case EK_START_CFG_EDGE:
-	  {
-	    cfg_edge_event *event = (cfg_edge_event *)base_event;
-	    const cfg_superedge& cfg_superedge
-	      = event->get_cfg_superedge ();
-	    const supernode *dest = event->m_sedge->m_dest;
-	    /* Do we have an SSA_NAME defined via a phi node in
-	       the dest CFG node?  */
-	    if (var && TREE_CODE (var) == SSA_NAME)
-	      if (SSA_NAME_DEF_STMT (var)->bb == dest->m_bb)
-		{
-		  if (gphi *phi
-		      = dyn_cast <gphi *> (SSA_NAME_DEF_STMT (var)))
-		    {
-		      /* Update var based on its phi node.  */
-		      tree old_var = var;
-		      var = cfg_superedge.get_phi_arg (phi);
-		      log ("updating from %qE to %qE based on phi node",
-			   old_var, var);
-		      if (get_logger ())
-			{
-			  pretty_printer pp;
-			  pp_gimple_stmt_1 (&pp, phi, 0, (dump_flags_t)0);
-			  log ("  phi: %s", pp_formatted_text (&pp));
-			}
-		      /* If we've chosen a bad exploded_path, then the
-			 phi arg might be a constant.  Fail gracefully for
-			 this case.  */
-		      update_for_unsuitable_sm_exprs (&var);
-		    }
-		}
-
-	    /* TODO: is this edge significant to var?
-	       See if var can be in other states in the dest, but not
-	       in other states in the src?
-	       Must have multiple sibling edges.  */
-
-	    if (event->should_filter_p (m_verbosity))
-	      {
-		log ("filtering events %i and %i: CFG edge", idx, idx + 1);
-		path->delete_event (idx);
-		/* Also delete the corresponding EK_END_CFG_EDGE.  */
-		gcc_assert (path->get_checker_event (idx)->m_kind
-			    == EK_END_CFG_EDGE);
-		path->delete_event (idx);
-	      }
-	  }
-	  break;
-
-	case EK_END_CFG_EDGE:
-	  /* These come in pairs with EK_START_CFG_EDGE events and are
-	     filtered when their start event is filtered.  */
-	  break;
-
-	case EK_CALL_EDGE:
-	  {
-	    call_event *event = (call_event *)base_event;
-	    const callgraph_superedge& cg_superedge
-	      = event->get_callgraph_superedge ();
-	    callsite_expr expr;
-	    tree caller_var
-	      = cg_superedge.map_expr_from_callee_to_caller (var, &expr);
-	    if (caller_var)
-	      {
-		log ("event %i:"
-		     " switching var of interest"
-		     " from %qE in callee to %qE in caller",
-		     idx, var, caller_var);
-		var = caller_var;
-		if (expr.param_p ())
-		  event->record_critical_state (var, state);
-		update_for_unsuitable_sm_exprs (&var);
-	      }
-	  }
-	  break;
-
-	case EK_RETURN_EDGE:
-	  // TODO: potentially update var/state based on return value,
-	  // args etc
-	  {
-	    if (var)
-	      {
-		return_event *event = (return_event *)base_event;
-		const callgraph_superedge& cg_superedge
-		  = event->get_callgraph_superedge ();
-		callsite_expr expr;
-		tree callee_var
-		  = cg_superedge.map_expr_from_caller_to_callee (var, &expr);
-		if (callee_var)
-		  {
-		    log ("event %i:"
-			 " switching var of interest"
-			 " from %qE in caller to %qE in callee",
-			 idx, var, callee_var);
-		    var = callee_var;
-		    if (expr.return_value_p ())
-		      event->record_critical_state (var, state);
-		    update_for_unsuitable_sm_exprs (&var);
-		  }
-	      }
-	  }
-	  break;
-
-	case EK_SETJMP:
-	  /* TODO: only show setjmp_events that matter i.e. those for which
-	     there is a later rewind event using them.  */
-	case EK_REWIND_FROM_LONGJMP:
-	case EK_REWIND_TO_SETJMP:
-	  break;
-
-	case EK_WARNING:
-	  /* Always show the final "warning" event in the path.  */
-	  break;
-	}
-      idx--;
-    }
-}
-
-// FIXME: new implementation:
 /* First pass of diagnostic_manager::prune_path: apply verbosity level,
    pruning unrelated state change events.
 
diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index 1e2ae2b5655..0808cadeeef 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -68,87 +68,6 @@ along with GCC; see the file COPYING3.  If not see
 
 namespace ana {
 
-/* class impl_region_model_context : public region_model_context.  */
-
-impl_region_model_context::
-impl_region_model_context (exploded_graph &eg,
-			   const exploded_node *enode_for_diag,
-			   const program_state *old_state,
-			   program_state *new_state,
-			   state_change *change,
-			   const gimple *stmt,
-			   stmt_finder *stmt_finder)
-: m_eg (&eg), m_logger (eg.get_logger ()),
-  m_enode_for_diag (enode_for_diag),
-  m_old_state (old_state),
-  m_new_state (new_state),
-  m_change (change),
-  m_stmt (stmt),
-  m_stmt_finder (stmt_finder),
-  m_ext_state (eg.get_ext_state ())
-{
-}
-
-impl_region_model_context::
-impl_region_model_context (program_state *state,
-			   state_change *change,
-			   const extrinsic_state &ext_state,
-			   logger *logger)
-: m_eg (NULL), m_logger (logger), m_enode_for_diag (NULL),
-  m_old_state (NULL),
-  m_new_state (state),
-  m_change (change),
-  m_stmt (NULL),
-  m_stmt_finder (NULL),
-  m_ext_state (ext_state)
-{
-}
-
-void
-impl_region_model_context::warn (pending_diagnostic *d)
-{
-  LOG_FUNC (get_logger ());
-  if (m_eg)
-    m_eg->get_diagnostic_manager ().add_diagnostic
-      (m_enode_for_diag, m_enode_for_diag->get_supernode (),
-       m_stmt, m_stmt_finder, d);
-}
-
-void
-impl_region_model_context::remap_svalue_ids (const svalue_id_map &map)
-{
-  m_new_state->remap_svalue_ids (map);
-  if (m_change)
-    m_change->remap_svalue_ids (map);
-}
-
-int
-impl_region_model_context::on_svalue_purge (svalue_id first_unused_sid,
-					    const svalue_id_map &map)
-{
-  int total = 0;
-  int sm_idx;
-  sm_state_map *smap;
-  FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap)
-    {
-      const state_machine &sm = m_ext_state.get_sm (sm_idx);
-      total += smap->on_svalue_purge (sm, sm_idx, first_unused_sid,
-				      map, this);
-    }
-  if (m_change)
-    total += m_change->on_svalue_purge (first_unused_sid);
-  return total;
-}
-
-void
-impl_region_model_context::on_unknown_change (svalue_id sid)
-{
-  int sm_idx;
-  sm_state_map *smap;
-  FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap)
-    smap->on_unknown_change (sid);
-}
-
 /* class impl_region_model2_context : public region_model_context.  */
 
 impl_region_model2_context::
@@ -156,14 +75,12 @@ impl_region_model2_context (exploded_graph &eg,
 			   const exploded_node *enode_for_diag,
 			   const program_state *old_state,
 			   program_state *new_state,
-			   state_change *change,
 			   const gimple *stmt,
 			   stmt_finder *stmt_finder)
 : m_eg (&eg), m_logger (eg.get_logger ()),
   m_enode_for_diag (enode_for_diag),
   m_old_state (old_state),
   m_new_state (new_state),
-  m_change (change),
   m_stmt (stmt),
   m_stmt_finder (stmt_finder),
   m_ext_state (eg.get_ext_state ())
@@ -172,13 +89,11 @@ impl_region_model2_context (exploded_graph &eg,
 
 impl_region_model2_context::
 impl_region_model2_context (program_state *state,
-			   state_change *change,
-			   const extrinsic_state &ext_state,
-			   logger *logger)
+			    const extrinsic_state &ext_state,
+			    logger *logger)
 : m_eg (NULL), m_logger (logger), m_enode_for_diag (NULL),
   m_old_state (NULL),
   m_new_state (state),
-  m_change (change),
   m_stmt (NULL),
   m_stmt_finder (NULL),
   m_ext_state (ext_state)
@@ -235,44 +150,6 @@ impl_region_model2_context::on_unknown_change (const svalue2 *sval,
     }
 }
 
-/* class setjmp_svalue : public svalue.  */
-
-/* Compare the fields of this setjmp_svalue with OTHER, returning true
-   if they are equal.
-   For use by svalue::operator==.  */
-
-bool
-setjmp_svalue::compare_fields (const setjmp_svalue &other) const
-{
-  return m_setjmp_record == other.m_setjmp_record;
-}
-
-/* Implementation of svalue::add_to_hash vfunc for setjmp_svalue.  */
-
-void
-setjmp_svalue::add_to_hash (inchash::hash &hstate) const
-{
-  hstate.add_int (m_setjmp_record.m_enode->m_index);
-}
-
-/* Get the index of the stored exploded_node.  */
-
-int
-setjmp_svalue::get_enode_index () const
-{
-  return m_setjmp_record.m_enode->m_index;
-}
-
-/* Implementation of svalue::print_details vfunc for setjmp_svalue.  */
-
-void
-setjmp_svalue::print_details (const region_model &model ATTRIBUTE_UNUSED,
-			      svalue_id this_sid ATTRIBUTE_UNUSED,
-			      pretty_printer *pp) const
-{
-  pp_printf (pp, "setjmp: EN: %i", get_enode_index ());
-}
-
 /* class setjmp_svalue2 : public svalue2.  */
 
 /* FIXME.  */
@@ -323,183 +200,6 @@ setjmp_svalue2::get_enode_index () const
   return m_setjmp_record.m_enode->m_index;
 }
 
-/* Concrete implementation of sm_context, wiring it up to the rest of this
-   file.  */
-
-class impl_sm_context : public sm_context
-{
-public:
-  impl_sm_context (exploded_graph &eg,
-		   int sm_idx,
-		   const state_machine &sm,
-		   const exploded_node *enode_for_diag,
-		   const program_state *old_state,
-		   program_state *new_state,
-		   state_change *change,
-		   const sm_state_map *old_smap,
-		   sm_state_map *new_smap,
-		   stmt_finder *stmt_finder = NULL)
-  : sm_context (sm_idx, sm),
-    m_logger (eg.get_logger ()),
-    m_eg (eg), m_enode_for_diag (enode_for_diag),
-    m_old_state (old_state), m_new_state (new_state),
-    m_change (change),
-    m_old_smap (old_smap), m_new_smap (new_smap),
-    m_stmt_finder (stmt_finder)
-  {
-  }
-
-  logger *get_logger () const { return m_logger.get_logger (); }
-
-  tree get_fndecl_for_call (const gcall *call) FINAL OVERRIDE
-  {
-    impl_region_model_context old_ctxt
-      (m_eg, m_enode_for_diag, NULL, NULL/*m_enode->get_state ()*/,
-       m_change, call);
-    region_model *model = m_new_state->m_region_model;
-    return model->get_fndecl_for_call (call, &old_ctxt);
-  }
-
-  void on_transition (const supernode *node  ATTRIBUTE_UNUSED,
-		      const gimple *stmt  ATTRIBUTE_UNUSED,
-		      tree var,
-		      state_machine::state_t from,
-		      state_machine::state_t to,
-		      tree origin) FINAL OVERRIDE
-  {
-    logger * const logger = get_logger ();
-    LOG_FUNC (logger);
-    impl_region_model_context old_ctxt
-      (m_eg, m_enode_for_diag, NULL, NULL/*m_enode->get_state ()*/,
-       m_change, stmt);
-    svalue_id var_old_sid
-      = m_old_state->m_region_model->get_rvalue (var, &old_ctxt);
-
-    impl_region_model_context new_ctxt (m_eg, m_enode_for_diag,
-					m_old_state, m_new_state,
-					m_change, NULL);
-    svalue_id var_new_sid
-      = m_new_state->m_region_model->get_rvalue (var, &new_ctxt);
-    svalue_id origin_new_sid
-      = m_new_state->m_region_model->get_rvalue (origin, &new_ctxt);
-
-    state_machine::state_t current = m_old_smap->get_state (var_old_sid);
-    if (current == from)
-      {
-	if (logger)
-	  logger->log ("%s: state transition of %qE: %s -> %s",
-		       m_sm.get_name (),
-		       var,
-		       m_sm.get_state_name (from),
-		       m_sm.get_state_name (to));
-	m_new_smap->set_state (m_new_state->m_region_model, var_new_sid,
-			       to, origin_new_sid);
-	if (m_change)
-	  m_change->add_sm_change (m_sm_idx, var_new_sid, from, to);
-      }
-  }
-
-  void warn_for_state (const supernode *snode, const gimple *stmt,
-		       tree var, state_machine::state_t state,
-		       pending_diagnostic *d) FINAL OVERRIDE
-  {
-    LOG_FUNC (get_logger ());
-    gcc_assert (d); // take ownership
-
-    impl_region_model_context old_ctxt
-      (m_eg, m_enode_for_diag, m_old_state, m_new_state, m_change, NULL);
-    state_machine::state_t current;
-    if (var)
-      {
-	svalue_id var_old_sid
-	  = m_old_state->m_region_model->get_rvalue (var, &old_ctxt);
-	current = m_old_smap->get_state (var_old_sid);
-      }
-    else
-      current = m_old_smap->get_global_state ();
-
-    if (state == current)
-      {
-	m_eg.get_diagnostic_manager ().add_diagnostic
-	  (&m_sm, m_enode_for_diag, snode, stmt, m_stmt_finder,
-	   var, NULL, state, d);
-      }
-    else
-      delete d;
-  }
-
-  /* Hook for picking more readable trees for SSA names of temporaries,
-     so that rather than e.g.
-       "double-free of '<unknown>'"
-     we can print:
-       "double-free of 'inbuf.data'".  */
-
-  tree get_diagnostic_tree (tree expr) FINAL OVERRIDE
-  {
-    /* Only for SSA_NAMEs of temporaries; otherwise, return EXPR, as it's
-       likely to be the least surprising tree to report.  */
-    if (TREE_CODE (expr) != SSA_NAME)
-      return expr;
-    if (SSA_NAME_VAR (expr) != NULL)
-      return expr;
-
-    gcc_assert (m_new_state);
-    svalue_id sid = m_new_state->m_region_model->get_rvalue (expr, NULL);
-    /* Find trees for all regions storing the value.  */
-    auto_vec<path_var> pvs;
-    m_new_state->m_region_model->get_path_vars_for_svalue (sid, &pvs);
-    if (pvs.length () < 1)
-      return expr;
-    /* Pick the "best" such tree.  */
-    // TODO: should we also consider (and consolidate) equiv classes?
-    pvs.qsort (readability_comparator);
-    return pvs[0].m_tree;
-  }
-
-  state_machine::state_t get_global_state () const FINAL OVERRIDE
-  {
-    return m_old_state->m_checker_states[m_sm_idx]->get_global_state ();
-  }
-
-  void set_global_state (state_machine::state_t state) FINAL OVERRIDE
-  {
-    m_new_state->m_checker_states[m_sm_idx]->set_global_state (state);
-  }
-
-  void on_custom_transition (custom_transition *transition) FINAL OVERRIDE
-  {
-    transition->impl_transition (&m_eg,
-				 const_cast<exploded_node *> (m_enode_for_diag),
-				 m_sm_idx);
-  }
-
-  tree is_zero_assignment (const gimple *stmt) FINAL OVERRIDE
-  {
-    const gassign *assign_stmt = dyn_cast <const gassign *> (stmt);
-    if (!assign_stmt)
-     return NULL_TREE;
-
-    enum tree_code op = gimple_assign_rhs_code (assign_stmt);
-    if (TREE_CODE_CLASS (op) != tcc_constant)
-      return NULL_TREE;
-
-    if (!zerop (gimple_assign_rhs1 (assign_stmt)))
-      return NULL_TREE;
-
-    return gimple_assign_lhs (assign_stmt);
-  }
-
-  log_user m_logger;
-  exploded_graph &m_eg;
-  const exploded_node *m_enode_for_diag;
-  const program_state *m_old_state;
-  program_state *m_new_state;
-  state_change *m_change;
-  const sm_state_map *m_old_smap;
-  sm_state_map *m_new_smap;
-  stmt_finder *m_stmt_finder;
-};
-
 // FIXME: revamped version:
 /* Concrete implementation of sm_context, wiring it up to the rest of this
    file.  */
@@ -513,7 +213,6 @@ public:
 		    const exploded_node *enode_for_diag,
 		    const program_state *old_state,
 		    program_state *new_state,
-		    state_change *change,
 		    const sm_state_map2 *old_smap,
 		    sm_state_map2 *new_smap,
 		    stmt_finder *stmt_finder = NULL)
@@ -521,7 +220,6 @@ public:
     m_logger (eg.get_logger ()),
     m_eg (eg), m_enode_for_diag (enode_for_diag),
     m_old_state (old_state), m_new_state (new_state),
-    m_change (change),
     m_old_smap (old_smap), m_new_smap (new_smap),
     m_stmt_finder (stmt_finder)
   {
@@ -533,7 +231,7 @@ public:
   {
     impl_region_model2_context old_ctxt
       (m_eg, m_enode_for_diag, NULL, NULL/*m_enode->get_state ()*/,
-       m_change, call);
+       call);
     region_model2 *model = m_new_state->m_region_model2;
     return model->get_fndecl_for_call (call, &old_ctxt);
   }
@@ -549,13 +247,13 @@ public:
     LOG_FUNC (logger);
     impl_region_model2_context old_ctxt
       (m_eg, m_enode_for_diag, NULL, NULL/*m_enode->get_state ()*/,
-       m_change, stmt);
+       stmt);
     const svalue2 *var_old_sval
       = m_old_state->m_region_model2->get_rvalue (var, &old_ctxt);
 
     impl_region_model2_context new_ctxt (m_eg, m_enode_for_diag,
 					 m_old_state, m_new_state,
-					 m_change, stmt);
+					 stmt);
     const svalue2 *var_new_sval
       = m_new_state->m_region_model2->get_rvalue (var, &new_ctxt);
     const svalue2 *origin_new_sval
@@ -588,7 +286,7 @@ public:
     gcc_assert (d); // take ownership
 
     impl_region_model2_context old_ctxt
-      (m_eg, m_enode_for_diag, m_old_state, m_new_state, m_change, NULL);
+      (m_eg, m_enode_for_diag, m_old_state, m_new_state, NULL);
     state_machine::state_t current;
     if (var)
       {
@@ -637,12 +335,12 @@ public:
 
   state_machine::state_t get_global_state () const FINAL OVERRIDE
   {
-    return m_old_state->m_checker_states[m_sm_idx]->get_global_state ();
+    return m_old_state->m_checker_states2[m_sm_idx]->get_global_state ();
   }
 
   void set_global_state (state_machine::state_t state) FINAL OVERRIDE
   {
-    m_new_state->m_checker_states[m_sm_idx]->set_global_state (state);
+    m_new_state->m_checker_states2[m_sm_idx]->set_global_state (state);
   }
 
   void on_custom_transition (custom_transition *transition) FINAL OVERRIDE
@@ -658,7 +356,7 @@ public:
     if (!assign_stmt)
      return NULL_TREE;
     impl_region_model2_context old_ctxt
-      (m_eg, m_enode_for_diag, m_old_state, m_new_state, m_change, stmt);
+      (m_eg, m_enode_for_diag, m_old_state, m_new_state, stmt);
     if (const svalue2 *sval
 	= m_new_state->m_region_model2->get_gassign_result (assign_stmt,
 							    &old_ctxt))
@@ -673,7 +371,6 @@ public:
   const exploded_node *m_enode_for_diag;
   const program_state *m_old_state;
   program_state *m_new_state;
-  state_change *m_change;
   const sm_state_map2 *m_old_smap;
   sm_state_map2 *m_new_smap;
   stmt_finder *m_stmt_finder;
@@ -841,223 +538,6 @@ readability_comparator (const void *p1, const void *p2)
   return 0;
 }
 
-/* Create an sm_context and use it to call SM's on_leak vfunc, so that
-   it can potentially complain about a leak of DST_SID (in a new region_model)
-   in the given STATE, where MAP can be used to map SID back to an "old"
-   region_model.  */
-
-void
-impl_region_model_context::on_state_leak (const state_machine &sm,
-					  int sm_idx,
-					  svalue_id dst_sid,
-					  svalue_id first_unused_sid,
-					  const svalue_id_map &map,
-					  state_machine::state_t state)
-{
-  logger * const logger = get_logger ();
-  LOG_SCOPE (logger);
-  if (logger)
-    logger->log ("considering leak of sv%i", dst_sid.as_int ());
-
-  if (!m_eg)
-    return;
-
-  /* m_old_state also needs to be non-NULL so that the sm_ctxt can look
-     up the old state of the sid.  */
-  gcc_assert (m_old_state);
-
-  /* Don't report on sid leaking if it's equal to one of the used sids.
-     For example, given:
-       some_non_trivial_expression = malloc (sizeof (struct foo));
-     we have:
-       _1 = malloc;                         (void *)
-       some_non_trivial_expression = _1;    (struct foo *)
-     and at leak-detection time we may have:
-       sv5: {type: 'struct foo *', &r3}  (used)
-       sv6: {type: 'void *', &r3}         (unused)
-     where both point to the same region.  We don't want to report a
-     leak of sv6, so we reject the report due to its equality with sv5.  */
-  gcc_assert (m_new_state);
-  gcc_assert (!first_unused_sid.null_p ());
-  for (int i = 0; i < first_unused_sid.as_int (); i++)
-    {
-      svalue_id used_sid = svalue_id::from_int (i);
-
-      /* Use the "_without_cm" form of eval_condition, since
-	 we're half-way through purging - we don't want to introduce new
-	 equivalence classes into the constraint_manager for "sid" and
-	 for each of the used_sids.  */
-      const region_model &rm = *m_new_state->m_region_model;
-      tristate eq = rm.eval_condition_without_cm (dst_sid, EQ_EXPR, used_sid);
-      if (eq.is_true ())
-	{
-	  if (logger)
-	    logger->log ("rejecting leak of sv%i due to equality with sv%i",
-			 dst_sid.as_int (), used_sid.as_int ());
-	  return;
-	}
-    }
-
-  /* SID has leaked within the new state: no regions use it.
-     We need to convert it back to a tree, but since no regions use it, we
-     have to use MAP to convert it back to an svalue_id within the old state.
-     We can then look that svalue_id up to locate regions and thus tree(s)
-     that use it.  */
-
-  svalue_id old_sid = map.get_src_for_dst (dst_sid);
-
-  auto_vec<path_var> leaked_pvs;
-  m_old_state->m_region_model->get_path_vars_for_svalue (old_sid, &leaked_pvs);
-
-  if (leaked_pvs.length () < 1)
-    return;
-
-  /* Find "best" leaked tree.
-     Sort the leaks into most human-readable first, through
-     to least user-readable.  Given that we only emit one
-     leak per EC, this ought to ensure that we pick the most
-     user-readable description of each leaking EC.
-     This assumes that all vars in the EC have the same state.  */
-  leaked_pvs.qsort (readability_comparator);
-
-  tree leaked_tree = leaked_pvs[0].m_tree;
-  if (logger)
-    logger->log ("best leaked_tree: %qE", leaked_tree);
-
-  leak_stmt_finder stmt_finder (*m_eg, leaked_tree);
-  impl_sm_context sm_ctxt (*m_eg, sm_idx, sm, m_enode_for_diag,
-			   m_old_state, m_new_state,
-			   m_change,
-			   m_old_state->m_checker_states[sm_idx],
-			   m_new_state->m_checker_states[sm_idx],
-			   &stmt_finder);
-  gcc_assert (m_enode_for_diag);
-
-  /* Don't complain about leaks when returning from "main".  */
-  if (m_enode_for_diag->get_supernode ()
-      && m_enode_for_diag->get_supernode ()->return_p ())
-    {
-      tree fndecl = m_enode_for_diag->get_function ()->decl;
-      if (0 == strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "main"))
-	{
-	  if (logger)
-	    logger->log ("not reporting leak from main");
-	  return;
-	}
-    }
-
-  pending_diagnostic *pd = sm.on_leak (leaked_tree);
-  if (pd)
-    m_eg->get_diagnostic_manager ().add_diagnostic
-      (&sm, m_enode_for_diag, m_enode_for_diag->get_supernode (),
-       m_stmt, &stmt_finder,
-       leaked_tree, NULL, state, pd);
-}
-
-/* Implementation of region_model_context::on_inherited_svalue vfunc
-   for impl_region_model_context.
-   Notify all checkers that CHILD_SID has been created from PARENT_SID,
-   so that those state machines that inherit state can propagate the state
-   from parent to child.  */
-
-void
-impl_region_model_context::on_inherited_svalue (svalue_id parent_sid,
-						svalue_id child_sid)
-{
-  if (!m_new_state)
-    return;
-
-  int sm_idx;
-  sm_state_map *smap;
-  FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap)
-    {
-      const state_machine &sm = m_ext_state.get_sm (sm_idx);
-      if (sm.inherited_state_p ())
-	smap->on_inherited_svalue (parent_sid, child_sid);
-    }
-}
-
-/* Implementation of region_model_context::on_cast vfunc
-   for impl_region_model_context.
-   Notify all checkers that DST_SID is a cast of SRC_SID, so that sm-state
-   can be propagated from src to dst.  */
-
-void
-impl_region_model_context::on_cast (svalue_id src_sid,
-				    svalue_id dst_sid)
-{
-  if (!m_new_state)
-    return;
-
-  int sm_idx;
-  sm_state_map *smap;
-  FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap)
-    smap->on_cast (src_sid, dst_sid);
-}
-
-/* Implementation of region_model_context::on_condition vfunc.
-   Notify all state machines about the condition, which could lead to
-   state transitions.  */
-
-void
-impl_region_model_context::on_condition (tree lhs, enum tree_code op, tree rhs)
-{
-  int sm_idx;
-  sm_state_map *smap;
-  FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap)
-    {
-      const state_machine &sm = m_ext_state.get_sm (sm_idx);
-      impl_sm_context sm_ctxt (*m_eg, sm_idx, sm, m_enode_for_diag,
-			       m_old_state, m_new_state,
-			       m_change,
-			       m_old_state->m_checker_states[sm_idx],
-			       m_new_state->m_checker_states[sm_idx]);
-      sm.on_condition (&sm_ctxt,
-		       m_enode_for_diag->get_supernode (), m_stmt,
-		       lhs, op, rhs);
-    }
-}
-
-/* Implementation of region_model_context::on_phi vfunc.
-   Notify all state machines about the phi, which could lead to
-   state transitions.  */
-
-void
-impl_region_model_context::on_phi (const gphi *phi, tree rhs)
-{
-  int sm_idx;
-  sm_state_map *smap;
-  FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap)
-    {
-      const state_machine &sm = m_ext_state.get_sm (sm_idx);
-      impl_sm_context sm_ctxt (*m_eg, sm_idx, sm, m_enode_for_diag,
-			       m_old_state, m_new_state,
-			       m_change,
-			       m_old_state->m_checker_states[sm_idx],
-			       m_new_state->m_checker_states[sm_idx]);
-      sm.on_phi (&sm_ctxt, m_enode_for_diag->get_supernode (), phi, rhs);
-    }
-}
-
-/* Implementation of region_model_context::on_unexpected_tree_code vfunc.
-   Mark the new state as being invalid for further exploration.
-   TODO(stage1): introduce a warning for when this occurs.  */
-
-void
-impl_region_model_context::on_unexpected_tree_code (tree t,
-						    const dump_location_t &loc)
-{
-  logger * const logger = get_logger ();
-  if (logger)
-    logger->log ("unhandled tree code: %qs in %qs at %s:%i",
-		 t ? get_tree_code_name (TREE_CODE (t)) : "(null)",
-		 loc.get_impl_location ().m_function,
-		 loc.get_impl_location ().m_file,
-		 loc.get_impl_location ().m_line);
-  if (m_new_state)
-    m_new_state->m_valid = false;
-}
-
 // FIXME:
 /* Create an sm_context and use it to call SM's on_leak vfunc, so that
    it can potentially complain about a leak of SVAL in the given STATE.  */
@@ -1085,40 +565,6 @@ impl_region_model2_context::on_state_leak (const state_machine &sm,
      up the old state of SVAL.  */
   gcc_assert (m_old_state);
 
-#if 0
-  /* Don't report on sid leaking if it's equal to one of the used sids.
-     For example, given:
-       some_non_trivial_expression = malloc (sizeof (struct foo));
-     we have:
-       _1 = malloc;                         (void *)
-       some_non_trivial_expression = _1;    (struct foo *)
-     and at leak-detection time we may have:
-       sv5: {type: 'struct foo *', &r3}  (used)
-       sv6: {type: 'void *', &r3}         (unused)
-     where both point to the same region.  We don't want to report a
-     leak of sv6, so we reject the report due to its equality with sv5.  */
-  gcc_assert (m_new_state);
-  gcc_assert (!first_unused_sid.null_p ());
-  for (int i = 0; i < first_unused_sid.as_int (); i++)
-    {
-      svalue_id used_sid = svalue_id::from_int (i);
-
-      /* Use the "_without_cm" form of eval_condition, since
-	 we're half-way through purging - we don't want to introduce new
-	 equivalence classes into the constraint_manager for "sid" and
-	 for each of the used_sids.  */
-      const region_model &rm = *m_new_state->m_region_model;
-      tristate eq = rm.eval_condition_without_cm (dst_sid, EQ_EXPR, used_sid);
-      if (eq.is_true ())
-	{
-	  if (logger)
-	    logger->log ("rejecting leak of sv%i due to equality with sv%i",
-			 dst_sid.as_int (), used_sid.as_int ());
-	  return;
-	}
-    }
-#endif
-
   /* SVAL has leaked within the new state: it is not used by any reachable
      regions.
      We need to convert it back to a tree, but since it's likely no regions
@@ -1151,12 +597,6 @@ impl_region_model2_context::on_state_leak (const state_machine &sm,
     }
 
   leak_stmt_finder stmt_finder (*m_eg, leaked_tree);
-  impl_sm_context sm_ctxt (*m_eg, sm_idx, sm, m_enode_for_diag,
-			   m_old_state, m_new_state,
-			   m_change,
-			   m_old_state->m_checker_states[sm_idx],
-			   m_new_state->m_checker_states[sm_idx],
-			   &stmt_finder);
   gcc_assert (m_enode_for_diag);
 
   // FIXME:
@@ -1189,13 +629,12 @@ void
 impl_region_model2_context::on_condition (tree lhs, enum tree_code op, tree rhs)
 {
   int sm_idx;
-  sm_state_map *smap;
-  FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap)
+  sm_state_map2 *smap;
+  FOR_EACH_VEC_ELT (m_new_state->m_checker_states2, sm_idx, smap)
     {
       const state_machine &sm = m_ext_state.get_sm (sm_idx);
       impl_sm_context2 sm_ctxt (*m_eg, sm_idx, sm, m_enode_for_diag,
 				m_old_state, m_new_state,
-				m_change,
 				m_old_state->m_checker_states2[sm_idx],
 				m_new_state->m_checker_states2[sm_idx]);
       sm.on_condition (&sm_ctxt,
@@ -1212,13 +651,12 @@ void
 impl_region_model2_context::on_phi (const gphi *phi, tree rhs)
 {
   int sm_idx;
-  sm_state_map *smap;
-  FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap)
+  sm_state_map2 *smap;
+  FOR_EACH_VEC_ELT (m_new_state->m_checker_states2, sm_idx, smap)
     {
       const state_machine &sm = m_ext_state.get_sm (sm_idx);
       impl_sm_context2 sm_ctxt (*m_eg, sm_idx, sm, m_enode_for_diag,
 				m_old_state, m_new_state,
-				m_change,
 				m_old_state->m_checker_states2[sm_idx],
 				m_new_state->m_checker_states2[sm_idx]);
       sm.on_phi (&sm_ctxt, m_enode_for_diag->get_supernode (), phi, rhs);
@@ -1260,20 +698,19 @@ point_and_state::validate (const extrinsic_state &ext_state) const
 
   m_state.validate (ext_state);
 
-  if (!m_state.m_region_model)
-    return;
-
   /* Verify that the callstring's model of the stack corresponds to that
      of the region_model.  */
   /* They should have the same depth.  */
   gcc_assert (m_point.get_stack_depth ()
-	      == m_state.m_region_model->get_stack_depth ());
+	      == m_state.m_region_model2->get_stack_depth ());
   /* Check the functions in the callstring vs those in the frames
      at each depth.  */
   for (int depth = 0; depth < m_point.get_stack_depth (); ++depth)
     {
+#if 0
       gcc_assert (m_point.get_function_at_depth (depth)
-		  == m_state.m_region_model->get_function_at_depth (depth));
+		  == m_state.m_region_model2->get_function_at_depth (depth));
+#endif
     }
 }
 
@@ -1368,8 +805,6 @@ exploded_node::exploded_node (const point_and_state &ps,
 : m_ps (ps), m_status (STATUS_WORKLIST), m_index (index),
   m_num_processed_stmts (0)
 {
-  if (ps.get_state ().m_region_model)
-    gcc_checking_assert (ps.get_state ().m_region_model->canonicalized_p ());
   if (ps.get_state ().m_region_model2)
     gcc_checking_assert (ps.get_state ().m_region_model2->canonicalized_p ());
 }
@@ -1405,18 +840,6 @@ exploded_node::get_dot_fillcolor () const
      Sum the sm_states, and use the result to choose from a table,
      modulo table-size, special-casing the "no sm-state" case.   */
   int total_sm_state = 0;
-  {
-    int i;
-    sm_state_map *smap;
-    FOR_EACH_VEC_ELT (state.m_checker_states, i, smap)
-      {
-	for (sm_state_map::iterator_t iter = smap->begin ();
-	     iter != smap->end ();
-	     ++iter)
-	  total_sm_state += (*iter).second.m_state;
-	total_sm_state += smap->get_global_state ();
-      }
-  }
   {
     int i;
     sm_state_map2 *smap;
@@ -1493,20 +916,6 @@ exploded_node::dump_dot (graphviz_out *gv, const dump_args_t &args) const
       const program_state &state = m_ps.get_state ();
       state.dump_to_pp (ext_state, false, true, pp);
       pp_newline (pp);
-
-      {
-	int i;
-	sm_state_map *smap;
-	FOR_EACH_VEC_ELT (state.m_checker_states, i, smap)
-	  {
-	    if (!smap->is_empty_p ())
-	      {
-		pp_printf (pp, "%s: ", ext_state.get_name (i));
-		smap->print (ext_state.get_sm (i), state.m_region_model, pp);
-		pp_newline (pp);
-	      }
-	  }
-      }
     }
 
   /* Dump any saved_diagnostics at this enode.  */
@@ -1632,156 +1041,24 @@ public:
    point.  */
 
 exploded_node::on_stmt_flags
-exploded_node::on_stmt (exploded_graph &eg,
-			const supernode *snode,
-			const gimple *stmt,
-			program_state *state,
-			state_change *change) const
-{
-  logger *logger = eg.get_logger ();
-  LOG_SCOPE (logger);
-  if (logger)
-    {
-      logger->start_log_line ();
-      pp_gimple_stmt_1 (logger->get_printer (), stmt, 0, (dump_flags_t)0);
-      logger->end_log_line ();
-    }
-
-  /* Update input_location in case of ICE: make it easier to track down which
-     source construct we're failing to handle.  */
-  input_location = stmt->location;
-
-  if (state->m_region_model2)
-    return on_stmt2 (eg, snode, stmt, state, change);
-
-  /* Preserve the old state.  It is used here for looking
-     up old checker states, for determining state transitions, and
-     also within impl_region_model_context and impl_sm_context for
-     going from tree to svalue_id.  */
-  const program_state old_state (*state);
-
-  impl_region_model_context ctxt (eg, this,
-				  &old_state, state, change,
-				  stmt);
-
-  if (const gassign *assign = dyn_cast <const gassign *> (stmt))
-    state->m_region_model->on_assignment (assign, &ctxt);
-
-  if (const greturn *return_ = dyn_cast <const greturn *> (stmt))
-    state->m_region_model->on_return (return_, &ctxt);
-
-  /* Track whether we have a gcall to a function that's not recognized by
-     anything, for which we don't have a function body, or for which we
-     don't know the fndecl.  */
-  bool unknown_side_effects = false;
-  if (const gcall *call = dyn_cast <const gcall *> (stmt))
-    {
-      /* Debugging/test support.  */
-      if (is_special_named_call_p (call, "__analyzer_dump", 0))
-	{
-	  /* Handle the builtin "__analyzer_dump" by dumping state
-	     to stderr.  */
-	  dump (eg.get_ext_state ());
-	}
-      else if (is_special_named_call_p (call, "__analyzer_dump_path", 0))
-	{
-	  /* Handle the builtin "__analyzer_dump_path" by queuing a
-	     diagnostic at this exploded_node.  */
-	  ctxt.warn (new dump_path_diagnostic ());
-	}
-      else if (is_special_named_call_p (call, "__analyzer_dump_region_model", 0))
-	{
-	  /* Handle the builtin "__analyzer_dump_region_model" by dumping
-	     the region model's state to stderr.  */
-	  state->m_region_model->dump (false);
-	}
-      else if (is_special_named_call_p (call, "__analyzer_eval", 1))
-	{
-	  /* Handle the builtin "__analyzer_eval" by evaluating the input
-	     and dumping as a dummy warning, so that test cases can use
-	     dg-warning to validate the result (and so unexpected warnings will
-	     lead to DejaGnu failures).  */
-	  tree t_arg = gimple_call_arg (call, 0);
-	  tristate t
-	    = state->m_region_model->eval_condition (t_arg,
-						     NE_EXPR,
-						     integer_zero_node,
-						     &ctxt);
-	  warning_at (call->location, 0, "%s", t.as_string ());
-	}
-      else if (is_special_named_call_p (call, "__analyzer_break", 0))
-	{
-	  /* Handle the builtin "__analyzer_break" by triggering a
-	     breakpoint.  */
-	  /* TODO: is there a good cross-platform way to do this?  */
-	  raise (SIGINT);
-	}
-      else if (is_special_named_call_p (call, "__analyzer_dump_exploded_nodes",
-					1))
-	{
-	  /* This is handled elsewhere.  */
-	}
-      else if (is_setjmp_call_p (call))
-	state->m_region_model->on_setjmp (call, this, &ctxt);
-      else if (is_longjmp_call_p (call))
-	{
-	  on_longjmp (eg, call, state, &ctxt);
-	  return on_stmt_flags::terminate_path ();
-	}
-      else
-	unknown_side_effects = state->m_region_model->on_call_pre (call, &ctxt);
-    }
-
-  bool any_sm_changes = false;
-  int sm_idx;
-  sm_state_map *smap;
-  FOR_EACH_VEC_ELT (old_state.m_checker_states, sm_idx, smap)
-    {
-      const state_machine &sm = eg.get_ext_state ().get_sm (sm_idx);
-      const sm_state_map *old_smap
-	= old_state.m_checker_states[sm_idx];
-      sm_state_map *new_smap = state->m_checker_states[sm_idx];
-      impl_sm_context sm_ctxt (eg, sm_idx, sm, this, &old_state, state,
-			       change,
-			       old_smap, new_smap);
-      /* Allow the state_machine to handle the stmt.  */
-      if (sm.on_stmt (&sm_ctxt, snode, stmt))
-	unknown_side_effects = false;
-      else
-	{
-	  /* For those stmts that were not handled by the state machine.  */
-	  if (const gcall *call = dyn_cast <const gcall *> (stmt))
-	    {
-	      tree callee_fndecl
-		= state->m_region_model->get_fndecl_for_call (call, &ctxt);
-
-	      if (!fndecl_has_gimple_body_p (callee_fndecl))
-		new_smap->purge_for_unknown_fncall (eg, sm, call, callee_fndecl,
-						    state->m_region_model,
-						    &ctxt);
-	    }
-	}
-      if (*old_smap != *new_smap)
-	any_sm_changes = true;
-    }
-
-  if (const gcall *call = dyn_cast <const gcall *> (stmt))
-    state->m_region_model->on_call_post (call, unknown_side_effects, &ctxt);
-
-  return on_stmt_flags (any_sm_changes);
-}
-
-/* Modify STATE in place, applying the effects of the stmt at this node's
-   point.  */
-
-exploded_node::on_stmt_flags
-exploded_node::on_stmt2 (exploded_graph &eg,
+exploded_node::on_stmt (exploded_graph &eg,
 			const supernode *snode,
 			const gimple *stmt,
-			program_state *state,
-			state_change *change) const
+			program_state *state) const
 {
-  // FIXME: this is for revamped states
+  logger *logger = eg.get_logger ();
+  LOG_SCOPE (logger);
+  if (logger)
+    {
+      logger->start_log_line ();
+      pp_gimple_stmt_1 (logger->get_printer (), stmt, 0, (dump_flags_t)0);
+      logger->end_log_line ();
+    }
+
+  /* Update input_location in case of ICE: make it easier to track down which
+     source construct we're failing to handle.  */
+  input_location = stmt->location;
+
   gcc_assert (state->m_region_model2);
 #if 0
     {
@@ -1799,7 +1076,7 @@ exploded_node::on_stmt2 (exploded_graph &eg,
   const program_state old_state (*state);
 
   impl_region_model2_context ctxt (eg, this,
-				   &old_state, state, change,
+				   &old_state, state,
 				   stmt);
 
   if (const gassign *assign = dyn_cast <const gassign *> (stmt))
@@ -1833,7 +1110,7 @@ exploded_node::on_stmt2 (exploded_graph &eg,
 	{
 	  /* Handle the builtin "__analyzer_dump_region_model" by dumping
 	     the region model's state to stderr.  */
-	  state->m_region_model->dump (false);
+	  state->m_region_model2->dump (false);
 	}
       else if (is_special_named_call_p (call, "__analyzer_eval", 1))
 	state->m_region_model2->impl_call_analyzer_eval (call, &ctxt);
@@ -1870,7 +1147,6 @@ exploded_node::on_stmt2 (exploded_graph &eg,
 	= old_state.m_checker_states2[sm_idx];
       sm_state_map2 *new_smap = state->m_checker_states2[sm_idx];
       impl_sm_context2 sm_ctxt (eg, sm_idx, sm, this, &old_state, state,
-				change,
 				old_smap, new_smap);
       /* Allow the state_machine to handle the stmt.  */
       if (sm.on_stmt (&sm_ctxt, snode, stmt))
@@ -1919,15 +1195,14 @@ bool
 exploded_node::on_edge (exploded_graph &eg,
 			const superedge *succ,
 			program_point *next_point,
-			program_state *next_state,
-			state_change *change) const
+			program_state *next_state) const
 {
   LOG_FUNC (eg.get_logger ());
 
   if (!next_point->on_edge (eg, succ))
     return false;
 
-  if (!next_state->on_edge (eg, *this, succ, change))
+  if (!next_state->on_edge (eg, *this, succ))
     return false;
 
   return true;
@@ -1993,119 +1268,6 @@ private:
   const gcall *m_longjmp_call;
 };
 
-/* Handle LONGJMP_CALL, a call to longjmp or siglongjmp.
-
-   Attempt to locate where setjmp/sigsetjmp was called on the jmp_buf and build
-   an exploded_node and exploded_edge to it representing a rewind to that frame,
-   handling the various kinds of failure that can occur.  */
-
-void
-exploded_node::on_longjmp (exploded_graph &eg,
-			   const gcall *longjmp_call,
-			   program_state *new_state,
-			   region_model_context *ctxt) const
-{
-  tree buf_ptr = gimple_call_arg (longjmp_call, 0);
-
-  region_model *new_region_model = new_state->m_region_model;
-  region_id buf_rid = new_region_model->deref_rvalue (buf_ptr, ctxt);
-  region *buf = new_region_model->get_region (buf_rid);
-  if (!buf)
-    return;
-
-  svalue_id buf_content_sid
-    = buf->get_value (*new_region_model, false, ctxt);
-  svalue *buf_content_sval = new_region_model->get_svalue (buf_content_sid);
-  if (!buf_content_sval)
-    return;
-  setjmp_svalue *setjmp_sval = buf_content_sval->dyn_cast_setjmp_svalue ();
-  if (!setjmp_sval)
-    return;
-
-  const setjmp_record tmp_setjmp_record = setjmp_sval->get_setjmp_record ();
-
-  /* Build a custom enode and eedge for rewinding from the longjmp/siglongjmp
-     call back to the setjmp/sigsetjmp.  */
-  rewind_info_t rewind_info (tmp_setjmp_record, longjmp_call);
-
-  const gcall *setjmp_call = rewind_info.get_setjmp_call ();
-  const program_point &setjmp_point = rewind_info.get_setjmp_point ();
-
-  const program_point &longjmp_point = get_point ();
-
-  /* Verify that the setjmp's call_stack hasn't been popped.  */
-  if (!valid_longjmp_stack_p (longjmp_point, setjmp_point))
-    {
-      ctxt->warn (new stale_jmp_buf (setjmp_call, longjmp_call));
-      return;
-    }
-
-  gcc_assert (longjmp_point.get_stack_depth ()
-	      >= setjmp_point.get_stack_depth ());
-
-  /* Update the state for use by the destination node.  */
-
-  /* Stash the current number of diagnostics so that we can update
-     any that this adds to show where the longjmp is rewinding to.  */
-
-  diagnostic_manager *dm = &eg.get_diagnostic_manager ();
-  unsigned prev_num_diagnostics = dm->get_num_diagnostics ();
-
-  new_region_model->on_longjmp (longjmp_call, setjmp_call,
-				setjmp_point.get_stack_depth (), ctxt);
-
-  program_point next_point
-    = program_point::after_supernode (setjmp_point.get_supernode (),
-				      setjmp_point.get_call_string ());
-
-  state_change change;
-  exploded_node *next
-    = eg.get_or_create_node (next_point, *new_state, this, &change);
-
-  /* Create custom exploded_edge for a longjmp.  */
-  if (next)
-    {
-      exploded_edge *eedge
-	= eg.add_edge (const_cast<exploded_node *> (this), next, NULL,
-		       change,
-		       new rewind_info_t (tmp_setjmp_record, longjmp_call));
-
-      /* For any diagnostics that were queued here (such as leaks) we want
-	 the checker_path to show the rewinding events after the "final event"
-	 so that the user sees where the longjmp is rewinding to (otherwise the
-	 path is meaningless).
-
-	 For example, we want to emit something like:
-                        |   NN | {
-                        |   NN |   longjmp (env, 1);
-                        |      |   ~~~~~~~~~~~~~~~~
-                        |      |   |
-                        |      |   (10) 'ptr' leaks here; was allocated at (7)
-                        |      |   (11) rewinding from 'longjmp' in 'inner'...
-                        |
-          <-------------+
-          |
-        'outer': event 12
-          |
-          |   NN |   i = setjmp(env);
-          |      |       ^~~~~~
-          |      |       |
-          |      |       (12) ...to 'setjmp' in 'outer' (saved at (2))
-
-	 where the "final" event above is event (10), but we want to append
-	 events (11) and (12) afterwards.
-
-	 Do this by setting m_trailing_eedge on any diagnostics that were
-	 just saved.  */
-      unsigned num_diagnostics = dm->get_num_diagnostics ();
-      for (unsigned i = prev_num_diagnostics; i < num_diagnostics; i++)
-	{
-	  saved_diagnostic *sd = dm->get_saved_diagnostic (i);
-	  sd->m_trailing_eedge = eedge;
-	}
-    }
-}
-
 /* Handle LONGJMP_CALL, a call to longjmp or siglongjmp.
 
    Attempt to locate where setjmp/sigsetjmp was called on the jmp_buf and build
@@ -2175,16 +1337,16 @@ exploded_node::on_longjmp2 (exploded_graph &eg,
     = program_point::after_supernode (setjmp_point.get_supernode (),
 				      setjmp_point.get_call_string ());
 
-  state_change change;
+  /*state_change change;*/
   exploded_node *next
-    = eg.get_or_create_node (next_point, *new_state, this, &change);
+    = eg.get_or_create_node (next_point, *new_state, this/*, &change*/);
 
   /* Create custom exploded_edge for a longjmp.  */
   if (next)
     {
       exploded_edge *eedge
 	= eg.add_edge (const_cast<exploded_node *> (this), next, NULL,
-		       change,
+		       //change,
 		       new rewind_info_t (tmp_setjmp_record, longjmp_call));
 
       /* For any diagnostics that were queued here (such as leaks) we want
@@ -2250,35 +1412,17 @@ exploded_node::detect_leaks (exploded_graph &eg) const
      what leaks (via purge_unused_svalues).  */
   program_state new_state (old_state);
 
-  if (!old_state.m_region_model)
-    {
-      gcc_assert (new_state.m_region_model2);
-
-#if 1
-      purge_stats2 stats;
-      impl_region_model2_context ctxt (eg, this,
-				       &old_state, &new_state,
-				       NULL,
-				       get_stmt ());
-      const svalue2 *result = NULL;
-      new_state.m_region_model2->pop_frame (NULL, true, &stats, &result,
-					    &ctxt);
-      program_state::detect_leaks2 (old_state, new_state, result,
-				    eg.get_ext_state (), &ctxt);
-#endif
-    }
-  else
-    {
-      gcc_assert (new_state.m_region_model);
-
-      purge_stats stats;
-      impl_region_model_context ctxt (eg, this,
-				      &old_state, &new_state,
-				      NULL,
-				      get_stmt ());
-      new_state.m_region_model->pop_frame (region_id::null (),
-					   true, &stats, &ctxt);
-    }
+  gcc_assert (new_state.m_region_model2);
+
+  purge_stats2 stats;
+  impl_region_model2_context ctxt (eg, this,
+				   &old_state, &new_state,
+				   get_stmt ());
+  const svalue2 *result = NULL;
+  new_state.m_region_model2->pop_frame (NULL, true, &stats, &result,
+					&ctxt);
+  program_state::detect_leaks2 (old_state, new_state, result,
+				eg.get_ext_state (), &ctxt);
 }
 
 /* Dump the successors and predecessors of this enode to OUTF.  */
@@ -2317,21 +1461,6 @@ exploded_node::dump_succs_and_preds (FILE *outf) const
    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 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 (get_longjmp_call (),
-		     get_setjmp_call (),
-		     setjmp_point.get_stack_depth (), NULL);
-}
-
 void
 rewind_info_t::update_model2 (region_model2 *model,
 			      const exploded_edge &eedge)
@@ -2380,12 +1509,12 @@ rewind_info_t::add_events_to_path (checker_path *emission_path,
 exploded_edge::exploded_edge (exploded_node *src, exploded_node *dest,
 			      const extrinsic_state &ext_state,
 			      const superedge *sedge,
-			      const state_change &change,
+			      //const state_change &change,
 			      custom_info_t *custom_info)
-: dedge<eg_traits> (src, dest), m_sedge (sedge), m_change (change),
+: dedge<eg_traits> (src, dest), m_sedge (sedge), /*m_change (change),*/
   m_custom_info (custom_info)
 {
-  change.validate (dest->get_state (), ext_state);
+  //change.validate (dest->get_state (), ext_state);
 }
 
 /* exploded_edge's dtor.  */
@@ -2446,7 +1575,7 @@ exploded_edge::dump_dot (graphviz_out *gv, const dump_args_t &args) const
   else if (m_custom_info)
     m_custom_info->print (pp);
 
-  m_change.dump (pp, args.m_eg.get_ext_state ());
+  //m_change.dump (pp, args.m_eg.get_ext_state ());
   //pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
 
   pp_printf (pp, "\"];\n");
@@ -2710,14 +1839,15 @@ worklist::key_t::cmp (const worklist::key_t &ka, const worklist::key_t &kb)
   const program_state &state_a = ka.m_enode->get_state ();
   const program_state &state_b = kb.m_enode->get_state ();
 
+#if 0
   /* Sort by sm-state, so that identical sm-states are grouped
      together in the worklist.
      For now, sort by the hash value (might not be deterministic).  */
-  for (unsigned sm_idx = 0; sm_idx < state_a.m_checker_states.length ();
+  for (unsigned sm_idx = 0; sm_idx < state_a.m_checker_states2.length ();
        ++sm_idx)
     {
-      sm_state_map *smap_a = state_a.m_checker_states[sm_idx];
-      sm_state_map *smap_b = state_b.m_checker_states[sm_idx];
+      sm_state_map2 *smap_a = state_a.m_checker_states2[sm_idx];
+      sm_state_map2 *smap_b = state_b.m_checker_states2[sm_idx];
 
       hashval_t hash_a = smap_a->hash ();
       hashval_t hash_b = smap_b->hash ();
@@ -2726,6 +1856,7 @@ worklist::key_t::cmp (const worklist::key_t &ka, const worklist::key_t &kb)
       else if (hash_a > hash_b)
 	return 1;
     }
+#endif
 
   /* Otherwise, we have two enodes at the same program point but with
      different states.  We don't have a good total ordering on states,
@@ -2752,7 +1883,7 @@ exploded_graph::exploded_graph (const supergraph &sg, logger *logger,
   m_PK_AFTER_SUPERNODE_per_snode (m_sg.num_nodes ())
 {
   m_origin = get_or_create_node (program_point::origin (),
-				 program_state (ext_state), NULL, NULL);
+				 program_state (ext_state), NULL);
   for (int i = 0; i < m_sg.num_nodes (); i++)
     m_PK_AFTER_SUPERNODE_per_snode.quick_push (i);
 }
@@ -2790,18 +1921,16 @@ exploded_graph::add_function_entry (function *fun)
   if (!state.m_valid)
     return NULL;
 
-  exploded_node *enode = get_or_create_node (point, state, NULL, NULL);
+  exploded_node *enode = get_or_create_node (point, state, NULL);
   /* We should never fail to add such a node.  */
   gcc_assert (enode);
-  state_change change;
-  add_edge (m_origin, enode, NULL, change);
+  //state_change change;
+  add_edge (m_origin, enode, NULL/*, change*/);
   return enode;
 }
 
 /* Get or create an exploded_node for (POINT, STATE).
    If a new node is created, it is added to the worklist.
-   If CHANGE is non-NULL, use it to suppress some purging of state,
-   to make generation of state_change_event instances easier.
 
    FIXME: ENODE_FOR_DIAG: we pass this in so that we can emit
    diagnostics when purging state *before* we have a new enode;
@@ -2816,7 +1945,6 @@ exploded_node *
 exploded_graph::get_or_create_node (const program_point &point,
 				    const program_state &state,
 				    const exploded_node *enode_for_diag,
-				    state_change *change,
 				    bool is_split)
 {
   logger * const logger = get_logger ();
@@ -2853,7 +1981,7 @@ exploded_graph::get_or_create_node (const program_point &point,
   /* Prune state to try to improve the chances of a cache hit,
      avoiding generating redundant nodes.  */
   program_state pruned_state
-    = state.prune_for_point (*this, point, enode_for_diag, change);
+    = state.prune_for_point (*this, point, enode_for_diag);
 
   pruned_state.validate (get_ext_state ());
 
@@ -2866,8 +1994,8 @@ exploded_graph::get_or_create_node (const program_point &point,
       pp_string (pp, "pruned_state: ");
       pruned_state.dump_to_pp (m_ext_state, true, false, pp);
       logger->end_log_line ();
-      if (pruned_state.m_region_model)
-	pruned_state.m_region_model->dump_to_pp (logger->get_printer (), true);
+      pruned_state.m_region_model2->dump_to_pp (logger->get_printer (), true,
+						false);
     }
 
   stats *per_fn_stats = get_or_create_function_stats (point.get_function ());
@@ -2920,8 +2048,6 @@ exploded_graph::get_or_create_node (const program_point &point,
 		 relationship to those of the input state, and thus to those
 		 of CHANGE, so we must purge any svalue_ids from *CHANGE.  */
 	      ps.set_state (merged_state);
-	      if (change)
-		change->on_svalue_purge (svalue_id::from_int (0));
 
 	      if (exploded_node **slot = m_point_and_state_to_node.get (&ps))
 		{
@@ -3024,11 +2150,11 @@ exploded_graph::get_or_create_node (const program_point &point,
 exploded_edge *
 exploded_graph::add_edge (exploded_node *src, exploded_node *dest,
 			  const superedge *sedge,
-			  const state_change &change,
+			  //const state_change &change,
 			  exploded_edge::custom_info_t *custom_info)
 {
   exploded_edge *e = new exploded_edge (src, dest, m_ext_state,
-					sedge, change, custom_info);
+					sedge, /*change, */custom_info);
   digraph<eg_traits>::add_edge (e);
 
 #if 0
@@ -3244,7 +2370,6 @@ exploded_graph::process_worklist ()
 		gcc_assert (state != state_2);
 
 		program_state merged_state (m_ext_state);
-		state_change change;
 		if (state.can_merge_with_p (state_2, m_ext_state,
 					    point, &merged_state))
 		  {
@@ -3255,7 +2380,7 @@ exploded_graph::process_worklist ()
 		    if (merged_state == state)
 		      {
 			/* Then merge node_2 into node by adding an edge.  */
-			add_edge (node_2, node, NULL, change);
+			add_edge (node_2, node, NULL);
 
 			/* Remove node_2 from the worklist.  */
 			m_worklist.take_next ();
@@ -3268,7 +2393,7 @@ exploded_graph::process_worklist ()
 			/* Then merge node into node_2, and leave node_2
 			   in the worklist, to be processed on the next
 			   iteration.  */
-			add_edge (node, node_2, NULL, change);
+			add_edge (node, node_2, NULL);
 			node->set_status (exploded_node::STATUS_MERGER);
 			continue;
 		      }
@@ -3284,7 +2409,7 @@ exploded_graph::process_worklist ()
 			   states, adding to the worklist.  */
 			exploded_node *merged_enode
 			  = get_or_create_node (node->get_point (),
-						merged_state, node, &change);
+						merged_state, node);
 			if (merged_enode == NULL)
 			  continue;
 
@@ -3313,7 +2438,7 @@ exploded_graph::process_worklist ()
 			  m_worklist.add_node (merged_enode);
 			else
 			  {
-			    add_edge (node, merged_enode, NULL, change);
+			    add_edge (node, merged_enode, NULL);
 			    node->set_status (exploded_node::STATUS_MERGER);
 			  }
 
@@ -3321,7 +2446,7 @@ exploded_graph::process_worklist ()
 			  m_worklist.add_node (merged_enode);
 			else
 			  {
-			    add_edge (node_2, merged_enode, NULL, change);
+			    add_edge (node_2, merged_enode, NULL);
 			    node_2->set_status (exploded_node::STATUS_MERGER);
 			  }
 
@@ -3441,24 +2566,15 @@ exploded_graph::process_node (exploded_node *node)
     case PK_BEFORE_SUPERNODE:
       {
 	program_state next_state (state);
-	state_change change;
+	//state_change change;
 
 	if (point.get_from_edge ())
 	  {
-	    impl_region_model_context ctxt (*this, node,
-					    &state, &next_state, &change,
-					    NULL);
 	    impl_region_model2_context ctxt2 (*this, node,
-					      &state, &next_state, &change,
-					      NULL);
+					      &state, &next_state, NULL);
 	    const cfg_superedge *last_cfg_superedge
 	      = point.get_from_edge ()->dyn_cast_cfg_superedge ();
-	    if (last_cfg_superedge && next_state.m_region_model)
-	      next_state.m_region_model->update_for_phis
-		(node->get_supernode (),
-		 last_cfg_superedge,
-		 &ctxt);
-	    if (last_cfg_superedge && next_state.m_region_model2)
+	    if (last_cfg_superedge)
 	      next_state.m_region_model2->update_for_phis
 		(node->get_supernode (),
 		 last_cfg_superedge,
@@ -3471,9 +2587,9 @@ exploded_graph::process_node (exploded_node *node)
 	      = program_point::before_stmt (point.get_supernode (), 0,
 					    point.get_call_string ());
 	    exploded_node *next
-	      = get_or_create_node (next_point, next_state, node, &change);
+	      = get_or_create_node (next_point, next_state, node);
 	    if (next)
-	      add_edge (node, next, NULL, change);
+	      add_edge (node, next, NULL);
 	  }
 	else
 	  {
@@ -3481,9 +2597,9 @@ exploded_graph::process_node (exploded_node *node)
 	      = program_point::after_supernode (point.get_supernode (),
 						point.get_call_string ());
 	    exploded_node *next = get_or_create_node (next_point, next_state,
-						      node, &change);
+						      node);
 	    if (next)
-	      add_edge (node, next, NULL, change);
+	      add_edge (node, next, NULL);
 	  }
       }
       break;
@@ -3509,7 +2625,6 @@ exploded_graph::process_node (exploded_node *node)
 	   the sm-state-change occurs on an edge where the src enode has
 	   exactly one stmt, the one that caused the change. */
 	program_state next_state (state);
-	state_change change;
 	const supernode *snode = point.get_supernode ();
 	unsigned stmt_idx;
 	const gimple *prev_stmt = NULL;
@@ -3531,7 +2646,7 @@ exploded_graph::process_node (exploded_node *node)
 
 	    /* Process the stmt.  */
 	    exploded_node::on_stmt_flags flags
-	      = node->on_stmt (*this, snode, stmt, &next_state, &change);
+	      = node->on_stmt (*this, snode, stmt, &next_state);
 	    node->m_num_processed_stmts++;
 
 	    /* If flags.m_terminate_path, stop analyzing; any nodes/edges
@@ -3542,8 +2657,7 @@ exploded_graph::process_node (exploded_node *node)
 	    if (next_state.m_region_model2)
 	      {
 		impl_region_model2_context ctxt (*this, node,
-						 &old_state, &next_state, &change,
-						 stmt);
+						 &old_state, &next_state, stmt);
 		program_state::detect_leaks2 (old_state, next_state, NULL,
 					      get_ext_state (), &ctxt);
 	      }
@@ -3555,8 +2669,7 @@ exploded_graph::process_node (exploded_node *node)
 					       point.get_call_string ())
 		 : program_point::after_supernode (point.get_supernode (),
 						   point.get_call_string ()));
-	    next_state
-	      = next_state.prune_for_point (*this, next_point, node, &change);
+	    next_state = next_state.prune_for_point (*this, next_point, node);
 
 	    if (flags.m_sm_changes || flag_analyzer_fine_grained)
 	      {
@@ -3574,11 +2687,10 @@ exploded_graph::process_node (exploded_node *node)
 		       and any state change will effectively occur on that
 		       latter edge, and split_enode will contain just stmt.  */
 		    exploded_node *split_enode
-		      = get_or_create_node (split_point, old_state, node, NULL,
-					    true);
+		      = get_or_create_node (split_point, old_state, node, true);
 		    if (!split_enode)
 		      return;
-		    add_edge (node, split_enode, NULL, change);
+		    add_edge (node, split_enode, NULL);
 		    node = split_enode;
 		    break;
 		  }
@@ -3594,10 +2706,9 @@ exploded_graph::process_node (exploded_node *node)
 					   point.get_call_string ())
 	     : program_point::after_supernode (point.get_supernode (),
 					       point.get_call_string ()));
-	exploded_node *next = get_or_create_node (next_point, next_state,
-						  node, &change);
+	exploded_node *next = get_or_create_node (next_point, next_state, node);
 	if (next)
-	  add_edge (node, next, NULL, change);
+	  add_edge (node, next, NULL);
       }
       break;
     case PK_AFTER_SUPERNODE:
@@ -3637,14 +2748,12 @@ exploded_graph::process_node (exploded_node *node)
 	      logger->log ("considering SN: %i -> SN: %i",
 			   succ->m_src->m_index, succ->m_dest->m_index);
 
-	    state_change change;
-
 	    program_point next_point
 	      = program_point::before_supernode (succ->m_dest, succ,
 						 point.get_call_string ());
 	    program_state next_state (state);
 
-	    if (!node->on_edge (*this, succ, &next_point, &next_state, &change))
+	    if (!node->on_edge (*this, succ, &next_point, &next_state))
 	      {
 		if (logger)
 		  logger->log ("skipping impossible edge to SN: %i",
@@ -3653,9 +2762,9 @@ exploded_graph::process_node (exploded_node *node)
 	      }
 
 	    exploded_node *next = get_or_create_node (next_point, next_state,
-						      node, &change);
+						      node);
 	    if (next)
-	      add_edge (node, next, succ, change);
+	      add_edge (node, next, succ);
 	  }
       }
       break;
@@ -3897,126 +3006,6 @@ exploded_path::get_final_enode () const
   return m_edges[m_edges.length () - 1]->m_dest;
 }
 
-/* Check state along this path, returning true if it is feasible.
-   If OUT is non-NULL, and the path is infeasible, write a new
-   feasibility_problem to *OUT.  */
-
-bool
-exploded_path::feasible_p (logger *logger, feasibility_problem **out) const
-{
-  LOG_SCOPE (logger);
-
-  /* Traverse the path, updating this model.  */
-  region_model model;
-  for (unsigned edge_idx = 0; edge_idx < m_edges.length (); edge_idx++)
-    {
-      const exploded_edge *eedge = m_edges[edge_idx];
-      if (logger)
-	logger->log ("considering edge %i: EN:%i -> EN:%i",
-		     edge_idx,
-		     eedge->m_src->m_index,
-		     eedge->m_dest->m_index);
-      const exploded_node &src_enode = *eedge->m_src;
-      const program_point &src_point = src_enode.get_point ();
-      if (logger)
-	{
-	  logger->start_log_line ();
-	  src_point.print (logger->get_printer (), format (false));
-	  logger->end_log_line ();
-	}
-
-      /* Update state for the stmts that were processed in each enode.  */
-      for (unsigned stmt_idx = 0; stmt_idx < src_enode.m_num_processed_stmts;
-	   stmt_idx++)
-	{
-	  const gimple *stmt = src_enode.get_processed_stmt (stmt_idx);
-
-	  /* Update cfun and input_location in case of ICE: make it easier to
-	     track down which source construct we're failing to handle.  */
-	  auto_cfun sentinel (src_point.get_function ());
-	  input_location = stmt->location;
-
-	  if (const gassign *assign = dyn_cast <const gassign *> (stmt))
-	    model.on_assignment (assign, NULL);
-	  else if (const greturn *return_ = dyn_cast <const greturn *> (stmt))
-	    model.on_return (return_, NULL);
-	}
-
-      const superedge *sedge = eedge->m_sedge;
-      if (sedge)
-	{
-	  if (logger)
-	    logger->log ("  sedge: SN:%i -> SN:%i %s",
-			 sedge->m_src->m_index,
-			 sedge->m_dest->m_index,
-			 sedge->get_description (false));
-
-	  const gimple *last_stmt = src_point.get_supernode ()->get_last_stmt ();
-	  if (!model.maybe_update_for_edge (*sedge, last_stmt, NULL))
-	    {
-	      if (logger)
-		{
-		  logger->log ("rejecting due to region model");
-		  model.dump_to_pp (logger->get_printer (), false);
-		}
-	      if (out)
-		*out = new feasibility_problem (edge_idx, model, *eedge,
-						last_stmt);
-	      return false;
-	    }
-	}
-      else
-	{
-	  /* Special-case the initial eedge from the origin node to the
-	     initial function by pushing a frame for it.  */
-	  if (edge_idx == 0)
-	    {
-	      gcc_assert (eedge->m_src->m_index == 0);
-	      gcc_assert (src_point.get_kind () == PK_ORIGIN);
-	      gcc_assert (eedge->m_dest->get_point ().get_kind ()
-			  == PK_BEFORE_SUPERNODE);
-	      function *fun = eedge->m_dest->get_function ();
-	      gcc_assert (fun);
-	      model.push_frame (fun, NULL, NULL);
-	      if (logger)
-		logger->log ("  pushing frame for %qD", fun->decl);
-	    }
-	  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
-	 a PK_BEFORE_STMT, or a PK_AFTER_SUPERNODE if no stmts).
-	 This will typically not be associated with a superedge.  */
-      if (src_point.get_from_edge ())
-	{
-	  const cfg_superedge *last_cfg_superedge
-	    = src_point.get_from_edge ()->dyn_cast_cfg_superedge ();
-	  if (last_cfg_superedge)
-	    {
-	      if (logger)
-		logger->log ("  update for phis");
-	      model.update_for_phis (src_enode.get_supernode (),
-				     last_cfg_superedge,
-				     NULL);
-	    }
-	}
-
-      if (logger)
-	{
-	  logger->log ("state after edge %i: EN:%i -> EN:%i",
-		       edge_idx,
-		       eedge->m_src->m_index,
-		       eedge->m_dest->m_index);
-	  logger->start_log_line ();
-	  model.dump_to_pp (logger->get_printer (), true);
-	  logger->end_log_line ();
-	}
-    }
-
-  return true;
-}
-
 /* Check state along this path, returning true if it is feasible.
    If OUT is non-NULL, and the path is infeasible, write a new
    feasibility_problem to *OUT.  */
@@ -4083,13 +3072,8 @@ exploded_path::feasible2_p (logger *logger, feasibility_problem **out,
 		  model.dump_to_pp (logger->get_printer (), true, false);
 		}
 	      if (out)
-		{
-		  /* FIXME: ideally feasibility_problem should use a
-		     region_model2.  However, I don't think the model
-		     is used; it's for debugging.  */
-		  *out = new feasibility_problem (edge_idx, /*model, */ *eedge,
-						  last_stmt);
-		}
+		*out = new feasibility_problem (edge_idx, model, *eedge,
+						last_stmt);
 	      return false;
 	    }
 	}
diff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h
index bfdcee3af87..003bded829d 100644
--- a/gcc/analyzer/exploded-graph.h
+++ b/gcc/analyzer/exploded-graph.h
@@ -25,74 +25,6 @@ along with GCC; see the file COPYING3.  If not see
 
 namespace ana {
 
-/* Concrete implementation of region_model_context, wiring it up to the
-   rest of the analysis engine.  */
-
-class impl_region_model_context : public region_model_context
-{
- public:
-  impl_region_model_context (exploded_graph &eg,
-			     const exploded_node *enode_for_diag,
-
-			     /* TODO: should we be getting the ECs from the
-				old state, rather than the new?  */
-			     const program_state *old_state,
-			     program_state *new_state,
-			     state_change *change,
-
-			     const gimple *stmt,
-			     stmt_finder *stmt_finder = NULL);
-
-  impl_region_model_context (program_state *state,
-			     state_change *change,
-			     const extrinsic_state &ext_state,
-			     logger *logger = NULL);
-
-  void warn (pending_diagnostic *d) FINAL OVERRIDE;
-
-  void remap_svalue_ids (const svalue_id_map &map) FINAL OVERRIDE;
-
-  int on_svalue_purge (svalue_id first_unused_sid,
-		       const svalue_id_map &map) FINAL OVERRIDE;
-
-  logger *get_logger () FINAL OVERRIDE
-  {
-    return m_logger.get_logger ();
-  }
-
-  void on_state_leak (const state_machine &sm,
-		      int sm_idx,
-		      svalue_id sid,
-		      svalue_id first_unused_sid,
-		      const svalue_id_map &map,
-		      state_machine::state_t state);
-
-  void on_inherited_svalue (svalue_id parent_sid,
-			    svalue_id child_sid) FINAL OVERRIDE;
-
-  void on_cast (svalue_id src_sid,
-		svalue_id dst_sid) FINAL OVERRIDE;
-
-  void on_condition (tree lhs, enum tree_code op, tree rhs) FINAL OVERRIDE;
-
-  void on_unknown_change (svalue_id sid ATTRIBUTE_UNUSED) FINAL OVERRIDE;
-
-  void on_phi (const gphi *phi, tree rhs) FINAL OVERRIDE;
-
-  void on_unexpected_tree_code (tree t,
-				const dump_location_t &loc) FINAL OVERRIDE;
-
-  exploded_graph *m_eg;
-  log_user m_logger;
-  const exploded_node *m_enode_for_diag;
-  const program_state *m_old_state;
-  program_state *m_new_state;
-  state_change *m_change;
-  const gimple *m_stmt;
-  stmt_finder *m_stmt_finder;
-  const extrinsic_state &m_ext_state;
-};
-
 /* Concrete implementation of region_model_context, wiring it up to the
    rest of the analysis engine.  */
 
@@ -106,15 +38,13 @@ class impl_region_model2_context : public region_model2_context
 				old state, rather than the new?  */
 			     const program_state *old_state,
 			     program_state *new_state,
-			     state_change *change,
 
 			     const gimple *stmt,
 			     stmt_finder *stmt_finder = NULL);
 
   impl_region_model2_context (program_state *state,
-			     state_change *change,
-			     const extrinsic_state &ext_state,
-			     logger *logger = NULL);
+			      const extrinsic_state &ext_state,
+			      logger *logger = NULL);
 
   void warn (pending_diagnostic *d) FINAL OVERRIDE;
   void on_svalue2_leak (const svalue2 *) OVERRIDE;
@@ -146,7 +76,6 @@ class impl_region_model2_context : public region_model2_context
   const exploded_node *m_enode_for_diag;
   const program_state *m_old_state;
   program_state *m_new_state;
-  state_change *m_change;
   const gimple *m_stmt;
   stmt_finder *m_stmt_finder;
   const extrinsic_state &m_ext_state;
@@ -299,22 +228,11 @@ class exploded_node : public dnode<eg_traits>
   on_stmt_flags on_stmt (exploded_graph &eg,
 			 const supernode *snode,
 			 const gimple *stmt,
-			 program_state *state,
-			 state_change *change) const;
-  on_stmt_flags on_stmt2 (exploded_graph &eg,
-			  const supernode *snode,
-			  const gimple *stmt,
-			  program_state *state,
-			  state_change *change) const;
+			 program_state *state) const;
   bool on_edge (exploded_graph &eg,
 		const superedge *succ,
 		program_point *next_point,
-		program_state *next_state,
-		state_change *change) const;
-  void on_longjmp (exploded_graph &eg,
-		   const gcall *call,
-		   program_state *new_state,
-		   region_model_context *ctxt) const;
+		program_state *next_state) const;
   void on_longjmp2 (exploded_graph &eg,
 		    const gcall *call,
 		    program_state *new_state,
@@ -389,8 +307,6 @@ class exploded_edge : public dedge<eg_traits>
     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 update_model2 (region_model2 *model,
 				const exploded_edge &eedge) = 0;
 
@@ -401,7 +317,7 @@ class exploded_edge : public dedge<eg_traits>
   exploded_edge (exploded_node *src, exploded_node *dest,
 		 const extrinsic_state &ext_state,
 		 const superedge *sedge,
-		 const state_change &change,
+		 /*const state_change &change, */
 		 custom_info_t *custom_info);
   ~exploded_edge ();
   void dump_dot (graphviz_out *gv, const dump_args_t &args)
@@ -410,7 +326,7 @@ class exploded_edge : public dedge<eg_traits>
   //private:
   const superedge *const m_sedge;
 
-  const state_change m_change;
+  //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
@@ -440,8 +356,6 @@ public:
     pp_string (pp, "rewind");
   }
 
-  void update_model (region_model *model,
-		     const exploded_edge &eedge) FINAL OVERRIDE;
   void update_model2 (region_model2 *model,
 		      const exploded_edge &eedge) FINAL OVERRIDE;
 
@@ -842,11 +756,11 @@ public:
   exploded_node *get_or_create_node (const program_point &point,
 				     const program_state &state,
 				     const exploded_node *enode_for_diag,
-				     state_change *change,
+				     /*state_change *change, */
 				     bool is_split = false);
   exploded_edge *add_edge (exploded_node *src, exploded_node *dest,
 			   const superedge *sedge,
-			   const state_change &change,
+			   /*const state_change &change,*/
 			   exploded_edge::custom_info_t *custom = NULL);
 
   per_program_point_data *
@@ -970,12 +884,13 @@ class feasibility_problem
 {
 public:
   feasibility_problem (unsigned eedge_idx,
-		       const region_model &model,
+		       const region_model2 &model,
 		       const exploded_edge &eedge,
 		       const gimple *last_stmt)
   : m_eedge_idx (eedge_idx), m_model (model), m_eedge (eedge),
     m_last_stmt (last_stmt)
   {}
+#if 0
   feasibility_problem (unsigned eedge_idx,
 		       const exploded_edge &eedge,
 		       const gimple *last_stmt)
@@ -985,9 +900,10 @@ public:
     /* FIXME: eventually remove this in favor of porting fully to
        region_model2.  */
   }
+#endif
 
   unsigned m_eedge_idx;
-  region_model m_model;
+  region_model2 m_model;
   const exploded_edge &m_eedge;
   const gimple *m_last_stmt;
 };
diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc
index 6ad7dea7cc7..ae444ada7f3 100644
--- a/gcc/analyzer/program-state.cc
+++ b/gcc/analyzer/program-state.cc
@@ -116,493 +116,64 @@ extrinsic_state::get_model_manager () const
 
 /* sm_state_map's ctor.  */
 
-sm_state_map::sm_state_map ()
-: m_map (), m_global_state (0)
-{
-}
-
 /* Clone the sm_state_map.  */
 
-sm_state_map *
-sm_state_map::clone () const
-{
-  return new sm_state_map (*this);
-}
-
 /* Clone this sm_state_map, remapping all svalue_ids within it with ID_MAP.
 
    Return NULL if there are any svalue_ids that have sm-state for which
    ID_MAP maps them to svalue_id::null (and thus the clone would have lost
    the sm-state information). */
 
-sm_state_map *
-sm_state_map::clone_with_remapping (const one_way_svalue_id_map &id_map) const
-{
-  sm_state_map *result = new sm_state_map ();
-  result->m_global_state = m_global_state;
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      svalue_id sid = (*iter).first;
-      gcc_assert (!sid.null_p ());
-      entry_t e = (*iter).second;
-      /* TODO: what should we do if the origin maps from non-null to null?
-	 Is that loss of information acceptable?  */
-      id_map.update (&e.m_origin);
-
-      svalue_id new_sid = id_map.get_dst_for_src (sid);
-      if (new_sid.null_p ())
-	{
-	  delete result;
-	  return NULL;
-	}
-      result->m_map.put (new_sid, e);
-    }
-  return result;
-}
-
 /* Print this sm_state_map (for SM) to PP.
    If MODEL is non-NULL, print representative tree values where
    available.  */
 
-void
-sm_state_map::print (const state_machine &sm, const region_model *model,
-		     pretty_printer *pp) const
-{
-  bool first = true;
-  pp_string (pp, "{");
-  if (m_global_state != 0)
-    {
-      pp_printf (pp, "global: %s", sm.get_state_name (m_global_state));
-      first = false;
-    }
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      if (!first)
-	pp_string (pp, ", ");
-      first = false;
-      svalue_id sid = (*iter).first;
-      sid.print (pp);
-
-      entry_t e = (*iter).second;
-      pp_printf (pp, ": %s", sm.get_state_name (e.m_state));
-      if (model)
-	if (tree rep = model->get_representative_tree (sid))
-	  {
-	    pp_string (pp, " (");
-	    dump_quoted_tree (pp, rep);
-	    pp_character (pp, ')');
-	  }
-      if (!e.m_origin.null_p ())
-	{
-	  pp_string (pp, " (origin: ");
-	  e.m_origin.print (pp);
-	  if (model)
-	    if (tree rep = model->get_representative_tree (e.m_origin))
-	      {
-		pp_string (pp, " (");
-		dump_quoted_tree (pp, rep);
-		pp_character (pp, ')');
-	      }
-	  pp_string (pp, ")");
-	}
-    }
-  pp_string (pp, "}");
-}
-
 /* Dump this object (for SM) to stderr.  */
 
-DEBUG_FUNCTION void
-sm_state_map::dump (const state_machine &sm) const
-{
-  pretty_printer pp;
-  pp_show_color (&pp) = pp_show_color (global_dc->printer);
-  pp.buffer->stream = stderr;
-  print (sm, NULL, &pp);
-  pp_newline (&pp);
-  pp_flush (&pp);
-}
-
 /* Return true if no states have been set within this map
    (all expressions are for the start state).  */
 
-bool
-sm_state_map::is_empty_p () const
-{
-  return m_map.elements () == 0 && m_global_state == 0;
-}
-
 /* Generate a hash value for this sm_state_map.  */
 
-hashval_t
-sm_state_map::hash () const
-{
-  hashval_t result = 0;
-
-  /* Accumulate the result by xoring a hash for each slot, so that the
-     result doesn't depend on the ordering of the slots in the map.  */
-
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      inchash::hash hstate;
-      inchash::add ((*iter).first, hstate);
-      entry_t e = (*iter).second;
-      hstate.add_int (e.m_state);
-      inchash::add (e.m_origin, hstate);
-      result ^= hstate.end ();
-    }
-  result ^= m_global_state;
-
-  return result;
-}
-
 /* Equality operator for sm_state_map.  */
 
-bool
-sm_state_map::operator== (const sm_state_map &other) const
-{
-  if (m_global_state != other.m_global_state)
-    return false;
-
-  if (m_map.elements () != other.m_map.elements ())
-    return false;
-
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      svalue_id sid = (*iter).first;
-      entry_t e = (*iter).second;
-      entry_t *other_slot = const_cast <map_t &> (other.m_map).get (sid);
-      if (other_slot == NULL)
-	return false;
-      if (e != *other_slot)
-	return false;
-    }
-
-  gcc_checking_assert (hash () == other.hash ());
-
-  return true;
-}
-
 /* Get the state of SID within this object.
    States default to the start state.  */
 
-state_machine::state_t
-sm_state_map::get_state (svalue_id sid) const
-{
-  gcc_assert (!sid.null_p ());
-
-  if (entry_t *slot
-      = const_cast <map_t &> (m_map).get (sid))
-    return slot->m_state;
-  else
-    return 0;
-}
-
 /* Get the "origin" svalue_id for any state of SID.  */
 
-svalue_id
-sm_state_map::get_origin (svalue_id sid) const
-{
-  gcc_assert (!sid.null_p ());
-
-  entry_t *slot
-    = const_cast <map_t &> (m_map).get (sid);
-  if (slot)
-    return slot->m_origin;
-  else
-    return svalue_id::null ();
-}
-
 /* Set the state of SID within MODEL to STATE, recording that
    the state came from ORIGIN.  */
 
-void
-sm_state_map::set_state (region_model *model,
-			 svalue_id sid,
-			 state_machine::state_t state,
-			 svalue_id origin)
-{
-  if (model == NULL)
-    return;
-  equiv_class &ec = model->get_constraints ()->get_equiv_class (sid);
-  if (!set_state (ec, state, origin))
-    return;
-
-  /* Also do it for all svalues that are equal via non-cm, so that
-     e.g. (void *)&r and (foo *)&r transition together.  */
-  for (unsigned i = 0; i < model->get_num_svalues (); i++)
-    {
-      svalue_id other_sid = svalue_id::from_int (i);
-      if (other_sid == sid)
-	continue;
-
-      tristate eq = model->eval_condition_without_cm (sid, EQ_EXPR, other_sid);
-      if (eq.is_true ())
-	impl_set_state (other_sid, state, origin);
-    }
-}
-
 /* Set the state of EC to STATE, recording that the state came from
    ORIGIN.
    Return true if any states of svalue_ids within EC changed.  */
 
-bool
-sm_state_map::set_state (const equiv_class &ec,
-			 state_machine::state_t state,
-			 svalue_id origin)
-{
-  int i;
-  svalue_id *sid;
-  bool any_changed = false;
-  FOR_EACH_VEC_ELT (ec.m_vars, i, sid)
-    any_changed |= impl_set_state (*sid, state, origin);
-  return any_changed;
-}
-
-/* Set state of SID to STATE, bypassing equivalence classes.
-   Return true if the state changed.  */
-
-bool
-sm_state_map::impl_set_state (svalue_id sid, state_machine::state_t state,
-			      svalue_id origin)
-{
-  if (get_state (sid) == state)
-    return false;
-
-  /* Special-case state 0 as the default value.  */
-  if (state == 0)
-    {
-      if (m_map.get (sid))
-	m_map.remove (sid);
-      return true;
-    }
-  gcc_assert (!sid.null_p ());
-  m_map.put (sid, entry_t (state, origin));
-  return true;
-}
-
 /* Set the "global" state within this state map to STATE.  */
 
-void
-sm_state_map::set_global_state (state_machine::state_t state)
-{
-  m_global_state = state;
-}
-
 /* Get the "global" state within this state map.  */
 
-state_machine::state_t
-sm_state_map::get_global_state () const
-{
-  return m_global_state;
-}
-
 /* Handle CALL to unknown FNDECL with an unknown function body, which
    could do anything to the states passed to it.
    Clear any state for SM for the params and any LHS.
    Note that the function might be known to other state machines, but
    not to this one.  */
 
-void
-sm_state_map::purge_for_unknown_fncall (const exploded_graph &eg,
-					const state_machine &sm,
-					const gcall *call,
-					tree fndecl,
-					region_model *new_model,
-					region_model_context *ctxt)
-{
-  logger * const logger = eg.get_logger ();
-  if (logger)
-    {
-      if (fndecl)
-	logger->log ("function %qE is unknown to checker %qs",
-		     fndecl, sm.get_name ());
-      else
-	logger->log ("unknown function pointer for checker %qs",
-		     sm.get_name ());
-    }
-
-  /* Purge any state for parms.  */
-  tree iter_param_types = NULL_TREE;
-  if (fndecl)
-    iter_param_types = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
-  for (unsigned arg_idx = 0; arg_idx < gimple_call_num_args (call); arg_idx++)
-    {
-      /* Track expected param type, where available.  */
-      if (iter_param_types)
-	{
-	  tree param_type = TREE_VALUE (iter_param_types);
-	  gcc_assert (param_type);
-	  iter_param_types = TREE_CHAIN (iter_param_types);
-
-	  /* Don't purge state if it was passed as a const pointer
-	     e.g. for things like strlen (PTR).  */
-	  if (TREE_CODE (param_type) == POINTER_TYPE)
-	    if (TYPE_READONLY (TREE_TYPE (param_type)))
-	      continue;
-	}
-      tree parm = gimple_call_arg (call, arg_idx);
-      svalue_id parm_sid = new_model->get_rvalue (parm, ctxt);
-      set_state (new_model, parm_sid, 0, svalue_id::null ());
-
-      /* Also clear sm-state from svalue_ids that are passed via a
-	 pointer.  */
-      if (TREE_CODE (parm) == ADDR_EXPR)
-	{
-	  tree pointee = TREE_OPERAND (parm, 0);
-	  svalue_id parm_sid = new_model->get_rvalue (pointee, ctxt);
-	  set_state (new_model, parm_sid, 0, svalue_id::null ());
-	}
-    }
-
-  /* Purge any state for any LHS.  */
-  if (tree lhs = gimple_call_lhs (call))
-    {
-      svalue_id lhs_sid = new_model->get_rvalue (lhs, ctxt);
-      set_state (new_model, lhs_sid, 0, svalue_id::null ());
-    }
-}
-
 /* Update this map based on MAP.  */
 
-void
-sm_state_map::remap_svalue_ids (const svalue_id_map &map)
-{
-  map_t tmp_map;
-
-  /* Build an intermediate map, using the new sids.  */
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      svalue_id sid = (*iter).first;
-      entry_t e = (*iter).second;
-
-      map.update (&sid);
-      map.update (&e.m_origin);
-      tmp_map.put (sid, e);
-    }
-
-  /* Clear the existing values.  */
-  m_map.empty ();
-
-  /* Copy over from intermediate map.  */
-  for (map_t::iterator iter = tmp_map.begin ();
-       iter != tmp_map.end ();
-       ++iter)
-    {
-      svalue_id sid = (*iter).first;
-      entry_t e = (*iter).second;
-
-      impl_set_state (sid, e.m_state, e.m_origin);
-    }
-}
-
 /* Purge any state for svalue_ids >= FIRST_UNUSED_SID.
    If !SM::can_purge_p, then report the state as leaking,
    using SM_IDX, CTXT, and MAP.
    Return the number of states that were purged.  */
 
-int
-sm_state_map::on_svalue_purge (const state_machine &sm,
-			       int sm_idx,
-			       svalue_id first_unused_sid,
-			       const svalue_id_map &map,
-			       impl_region_model_context *ctxt)
-{
-  /* TODO: ideally remove the slot directly; for now
-     do it in two stages.  */
-  auto_vec<svalue_id> to_remove;
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      svalue_id dst_sid ((*iter).first);
-      if (dst_sid.as_int () >= first_unused_sid.as_int ())
-	{
-	  /* Complain about leaks here.  */
-	  entry_t e = (*iter).second;
-
-	  if (!sm.can_purge_p (e.m_state))
-	    ctxt->on_state_leak (sm, sm_idx, dst_sid, first_unused_sid,
-				 map, e.m_state);
-
-	  to_remove.safe_push (dst_sid);
-	}
-      else if ((*iter).second.m_origin.as_int () >= first_unused_sid.as_int ())
-	{
-	  /* If the origin svalue is being purged, then reset it to null.  */
-	  (*iter).second.m_origin = svalue_id::null ();
-	}
-    }
-
-  int i;
-  svalue_id *dst_sid;
-  FOR_EACH_VEC_ELT (to_remove, i, dst_sid)
-    m_map.remove (*dst_sid);
-
-  return to_remove.length ();
-}
-
 /* Set the state of CHILD_SID to that of PARENT_SID.  */
 
-void
-sm_state_map::on_inherited_svalue (svalue_id parent_sid,
-				   svalue_id child_sid)
-{
-  state_machine::state_t state = get_state (parent_sid);
-  impl_set_state (child_sid, state, parent_sid);
-}
-
 /* Set the state of DST_SID to that of SRC_SID.  */
 
-void
-sm_state_map::on_cast (svalue_id src_sid,
-		       svalue_id dst_sid)
-{
-  state_machine::state_t state = get_state (src_sid);
-  impl_set_state (dst_sid, state, get_origin (src_sid));
-}
-
 /* Purge state from SID (in response to a call to an unknown function).  */
 
-void
-sm_state_map::on_unknown_change (svalue_id sid)
-{
-  impl_set_state (sid, (state_machine::state_t)0, svalue_id::null ());
-}
-
 /* Assert that this object is sane.  */
 
-void
-sm_state_map::validate (const state_machine &sm,
-			int num_svalues) const
-{
-  /* Skip this in a release build.  */
-#if !CHECKING_P
-  return;
-#endif
-
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      svalue_id sid = (*iter).first;
-      entry_t e = (*iter).second;
-
-      gcc_assert (sid.as_int () < num_svalues);
-      sm.validate (e.m_state);
-      gcc_assert (e.m_origin.as_int () < num_svalues);
-    }
-}
-
 /* class sm_state_map2.  */
 
 /* sm_state_map2's ctor.  */
@@ -1165,47 +736,29 @@ sm_state_map2::canonicalize_svalue2 (const svalue2 *sval,
 
 program_state::program_state (const extrinsic_state &ext_state)
 : m_region_model2 (NULL),
-  m_region_model (NULL),
-  m_checker_states (ext_state.get_num_checkers ()),
-  m_checker_states2 (),
+  m_checker_states2 (ext_state.get_num_checkers ()),
   m_valid (true)
 {
-  if (ext_state.get_engine2 ())
-    {
-      engine2 *eng2 = ext_state.get_engine2 ();
-      region_model2_manager *mgr = eng2->get_model_manager ();
-      m_region_model2 = new region_model2 (mgr);
-    }
-  else
-    m_region_model = new region_model ();
+  engine2 *eng2 = ext_state.get_engine2 ();
+  region_model2_manager *mgr = eng2->get_model_manager ();
+  m_region_model2 = new region_model2 (mgr);
   const int num_states = ext_state.get_num_checkers ();
   for (int i = 0; i < num_states; i++)
-    m_checker_states.quick_push (new sm_state_map ());
-  if (ext_state.get_engine2 ())
-    for (int i = 0; i < num_states; i++)
-      {
-	sm_state_map2 *sm = new sm_state_map2 (ext_state.get_sm (i), i);
-	m_checker_states2.safe_push (sm);
-      }
+    {
+      sm_state_map2 *sm = new sm_state_map2 (ext_state.get_sm (i), i);
+      m_checker_states2.quick_push (sm);
+    }
 }
 
 /* program_state's copy ctor.  */
 
 program_state::program_state (const program_state &other)
 : m_region_model2 (NULL),
-  m_region_model (NULL),
-  m_checker_states (other.m_checker_states.length ()),
   m_checker_states2 (other.m_checker_states2.length ()),
   m_valid (true)
 {
-  if (other.m_region_model2)
-    m_region_model2 = new region_model2 (*other.m_region_model2);
-  if (other.m_region_model)
-    m_region_model = new region_model (*other.m_region_model);
+  m_region_model2 = new region_model2 (*other.m_region_model2);
   int i;
-  sm_state_map *smap;
-  FOR_EACH_VEC_ELT (other.m_checker_states, i, smap)
-    m_checker_states.quick_push (smap->clone ());
   sm_state_map2 *smap2;
   FOR_EACH_VEC_ELT (other.m_checker_states2, i, smap2)
     m_checker_states2.quick_push (smap2->clone ());
@@ -1217,22 +770,9 @@ program_state&
 program_state::operator= (const program_state &other)
 {
   delete m_region_model2;
-  if (other.m_region_model2)
-    m_region_model2 = new region_model2 (*other.m_region_model2);
-  delete m_region_model;
-  if (other.m_region_model)
-    m_region_model = new region_model (*other.m_region_model);
+  m_region_model2 = new region_model2 (*other.m_region_model2);
 
   int i;
-  sm_state_map *smap;
-  FOR_EACH_VEC_ELT (m_checker_states, i, smap)
-    delete smap;
-  m_checker_states.truncate (0);
-  gcc_assert (m_checker_states.space (other.m_checker_states.length ()));
-
-  FOR_EACH_VEC_ELT (other.m_checker_states, i, smap)
-    m_checker_states.quick_push (smap->clone ());
-
   sm_state_map2 *smap2;
   FOR_EACH_VEC_ELT (m_checker_states2, i, smap2)
     delete smap2;
@@ -1251,19 +791,11 @@ program_state::operator= (const program_state &other)
 /* Move constructor for program_state (when building with C++11).  */
 program_state::program_state (program_state &&other)
 : m_region_model2 (other.m_region_model2),
-  m_region_model (other.m_region_model),
-  m_checker_states (other.m_checker_states.length ()),
   m_checker_states2 (other.m_checker_states2.length ())
 {
   other.m_region_model2 = NULL;
-  other.m_region_model = NULL;
 
   int i;
-  sm_state_map *smap;
-  FOR_EACH_VEC_ELT (other.m_checker_states, i, smap)
-    m_checker_states.quick_push (smap);
-  other.m_checker_states.truncate (0);
-
   sm_state_map2 *smap2;
   FOR_EACH_VEC_ELT (other.m_checker_states2, i, smap2)
     m_checker_states2.quick_push (smap2);
@@ -1278,7 +810,6 @@ program_state::program_state (program_state &&other)
 program_state::~program_state ()
 {
   delete m_region_model2;
-  delete m_region_model;
 }
 
 /* Generate a hash value for this program_state.  */
@@ -1289,18 +820,9 @@ program_state::hash () const
   hashval_t result = 0;
 
   // TODO:
-#if 0
-  if (m_region_model2)
-    result ^= m_region_model2->hash ();
-#endif
-
-  if (m_region_model)
-    result ^= m_region_model->hash ();
+  //result ^= m_region_model2->hash ();
 
   int i;
-  sm_state_map *smap;
-  FOR_EACH_VEC_ELT (m_checker_states, i, smap)
-    result ^= smap->hash ();
   sm_state_map2 *smap2;
   FOR_EACH_VEC_ELT (m_checker_states2, i, smap2)
     result ^= smap2->hash ();
@@ -1316,20 +838,10 @@ program_state::hash () const
 bool
 program_state::operator== (const program_state &other) const
 {
-  if (m_region_model)
-    if (!(*m_region_model == *other.m_region_model))
-      return false;
-
-  if (m_region_model2)
-    if (!(*m_region_model2 == *other.m_region_model2))
-      return false;
+  if (!(*m_region_model2 == *other.m_region_model2))
+    return false;
 
   int i;
-  sm_state_map *smap;
-  FOR_EACH_VEC_ELT (m_checker_states, i, smap)
-    if (!(*smap == *other.m_checker_states[i]))
-      return false;
-
   sm_state_map2 *smap2;
   FOR_EACH_VEC_ELT (m_checker_states2, i, smap2)
     if (!(*smap2 == *other.m_checker_states2[i]))
@@ -1347,20 +859,10 @@ program_state::print (const extrinsic_state &ext_state,
 		      pretty_printer *pp) const
 {
   pp_printf (pp, "rmodel: ");
-  m_region_model->print (pp);
+  m_region_model2->dump_to_pp (pp, true, false);
   pp_newline (pp);
 
   int i;
-  sm_state_map *smap;
-  FOR_EACH_VEC_ELT (m_checker_states, i, smap)
-    {
-      if (!smap->is_empty_p ())
-	{
-	  pp_printf (pp, "%s: ", ext_state.get_name (i));
-	  smap->print (ext_state.get_sm (i), m_region_model, pp);
-	  pp_newline (pp);
-	}
-    }
   sm_state_map2 *smap2;
   FOR_EACH_VEC_ELT (m_checker_states2, i, smap2)
     {
@@ -1388,46 +890,21 @@ program_state::dump_to_pp (const extrinsic_state &ext_state,
 			   bool summarize, bool multiline,
 			   pretty_printer *pp) const
 {
-  if (!multiline)
-    pp_string (pp, "{");
-  if (m_region_model)
-    {
-      pp_printf (pp, "rmodel:");
-      if (multiline)
-	pp_newline (pp);
-      else
-	pp_string (pp, " {");
-      m_region_model->dump_to_pp (pp, summarize);
-      if (!multiline)
-	pp_string (pp, "}");
-    }
-  if (m_region_model2)
-    {
-      pp_printf (pp, "rmodel2:");
-      if (multiline)
-	pp_newline (pp);
-      else
-	pp_string (pp, " {");
-      m_region_model2->dump_to_pp (pp, true, multiline);
-      //m_region_model2->summarize_to_pp (pp, true);
-      if (!multiline)
-	pp_string (pp, "}");
-    }
+  if (!multiline)
+    pp_string (pp, "{");
+  {
+    pp_printf (pp, "rmodel2:");
+    if (multiline)
+      pp_newline (pp);
+    else
+      pp_string (pp, " {");
+    m_region_model2->dump_to_pp (pp, true, multiline);
+    //m_region_model2->summarize_to_pp (pp, true);
+    if (!multiline)
+      pp_string (pp, "}");
+  }
 
   int i;
-  sm_state_map *smap;
-  FOR_EACH_VEC_ELT (m_checker_states, i, smap)
-    {
-      if (!smap->is_empty_p ())
-	{
-	  if (!multiline)
-	    pp_space (pp);
-	  pp_printf (pp, "%s: ", ext_state.get_name (i));
-	  smap->print (ext_state.get_sm (i), m_region_model, pp);
-	  if (multiline)
-	    pp_newline (pp);
-	}
-    }
   sm_state_map2 *smap2;
   FOR_EACH_VEC_ELT (m_checker_states2, i, smap2)
     {
@@ -1498,16 +975,8 @@ void
 program_state::push_frame (const extrinsic_state &ext_state,
 			   function *fun)
 {
-  if (m_region_model2)
-    {
-      region_model2_context *ctxt = NULL; // FIXME
-      m_region_model2->push_frame (fun, NULL, ctxt);
-    }
-  else if (m_region_model)
-    {
-      impl_region_model_context ctxt (this, NULL, ext_state, ext_state.get_logger ());
-      m_region_model->push_frame (fun, NULL, &ctxt);
-    }
+  region_model2_context *ctxt = NULL; // FIXME
+  m_region_model2->push_frame (fun, NULL, ctxt);
 }
 
 /* FIXME.  */
@@ -1515,10 +984,7 @@ program_state::push_frame (const extrinsic_state &ext_state,
 function *
 program_state::get_current_function () const
 {
-  if (m_region_model2)
-    return m_region_model2->get_current_function ();
-  else
-    return m_region_model->get_current_function ();
+  return m_region_model2->get_current_function ();
 }
 
 /* Determine if following edge SUCC from ENODE is valid within the graph EG
@@ -1536,8 +1002,7 @@ program_state::get_current_function () const
 bool
 program_state::on_edge (exploded_graph &eg,
 			const exploded_node &enode,
-			const superedge *succ,
-			state_change *change)
+			const superedge *succ)
 {
   /* Update state.  */
   const program_point &point = enode.get_point ();
@@ -1551,47 +1016,26 @@ program_state::on_edge (exploded_graph &eg,
      Adding the relevant conditions for the edge could also trigger
      sm-state transitions (e.g. transitions due to ptrs becoming known
      to be NULL or non-NULL) */
-  if (m_region_model2)
-    {
-      impl_region_model2_context ctxt (eg, &enode,
-				      &enode.get_state (),
-				      this, change,
-				      last_stmt);
-      if (!m_region_model2->maybe_update_for_edge (*succ,
-						   last_stmt,
-						   &ctxt))
-	{
-	  logger * const logger = eg.get_logger ();
-	  if (logger)
-	    logger->log ("edge to SN: %i is impossible"
-			 " due to region_model2 constraints",
-			 succ->m_dest->m_index);
-	  return false;
-	}
-
-      program_state::detect_leaks2 (enode.get_state (), *this,
-				    NULL, eg.get_ext_state (),
-				    &ctxt);
-
-      return true;
-    }
-
-  impl_region_model_context ctxt (eg, &enode,
-				  &enode.get_state (),
-				  this, change,
-				  last_stmt);
-  if (!m_region_model->maybe_update_for_edge (*succ,
-					      last_stmt,
-					      &ctxt))
+  impl_region_model2_context ctxt (eg, &enode,
+				   &enode.get_state (),
+				   this,
+				   last_stmt);
+  if (!m_region_model2->maybe_update_for_edge (*succ,
+					       last_stmt,
+					       &ctxt))
     {
       logger * const logger = eg.get_logger ();
       if (logger)
 	logger->log ("edge to SN: %i is impossible"
-		     " due to region_model constraints",
+		     " due to region_model2 constraints",
 		     succ->m_dest->m_index);
       return false;
     }
 
+  program_state::detect_leaks2 (enode.get_state (), *this,
+				NULL, eg.get_ext_state (),
+				&ctxt);
+
   return true;
 }
 
@@ -1599,140 +1043,12 @@ program_state::on_edge (exploded_graph &eg,
    relevant at POINT.
    The idea is that we're more likely to be able to consolidate
    multiple (point, state) into single exploded_nodes if we discard
-   irrelevant state (e.g. at the end of functions).
-
-   Retain state affected by CHANGE, to make it easier to generate
-   state_change_events.  */
+   irrelevant state (e.g. at the end of functions).  */
 
 program_state
 program_state::prune_for_point (exploded_graph &eg,
 				const program_point &point,
-				const exploded_node *enode_for_diag,
-				state_change *change) const
-{
-  logger * const logger = eg.get_logger ();
-  LOG_SCOPE (logger);
-
-  function *fun = point.get_function ();
-  if (!fun)
-    return *this;
-
-  if (m_region_model2)
-    return prune_for_point2 (eg, point, enode_for_diag, change);
-
-  if (!m_region_model)
-    return *this;
-
-  program_state new_state (*this);
-
-  purge_stats stats;
-
-  const state_purge_map *pm = eg.get_purge_map ();
-  if (pm)
-    {
-      region_id_set purgeable_ssa_regions (new_state.m_region_model);
-      region_id frame_rid
-	= new_state.m_region_model->get_current_frame_id ();
-      frame_region *frame
-	= new_state.m_region_model->get_region <frame_region>(frame_rid);
-
-      /* TODO: maybe move to a member of region_model?  */
-
-      auto_vec<tree> ssa_names_to_purge;
-      for (frame_region::map_t::iterator iter = frame->begin ();
-	   iter != frame->end ();
-	   ++iter)
-	{
-	  tree var = (*iter).first;
-	  region_id rid = (*iter).second;
-	  if (TREE_CODE (var) == SSA_NAME)
-	    {
-	      const state_purge_per_ssa_name &per_ssa
-		= pm->get_data_for_ssa_name (var);
-	      if (!per_ssa.needed_at_point_p (point.get_function_point ()))
-		{
-		  region *region
-		    = new_state.m_region_model->get_region (rid);
-		  svalue_id sid = region->get_value_direct ();
-		  if (!sid.null_p ())
-		    {
-		      if (!new_state.can_purge_p (eg.get_ext_state (), sid))
-			{
-			  /* (currently only state maps can keep things
-			     alive).  */
-			  if (logger)
-			    logger->log ("not purging RID: %i for %qE"
-					 " (used by state map)",
-					 rid.as_int (), var);
-			  continue;
-			}
-
-		      /* Don't purge regions containing svalues that
-			 have a change of sm-state, to make it easier to
-			 generate state_change_event messages.  */
-		      if (change)
-			if (change->affects_p (sid))
-			  {
-			    if (logger)
-			      logger->log ("not purging RID: %i for %qE"
-					   " (affected by change)",
-					   rid.as_int (), var);
-			    continue;
-			  }
-		    }
-		  purgeable_ssa_regions.add_region (rid);
-		  ssa_names_to_purge.safe_push (var);
-		  if (logger)
-		    logger->log ("purging RID: %i for %qE", rid.as_int (), var);
-		  /* We also need to remove the region from the map.
-		     We're in mid-traversal, so the removal is done in
-		     unbind below.  */
-		}
-	    }
-	}
-
-      /* Unbind the regions from the frame's map of vars-to-regions.  */
-      unsigned i;
-      tree var;
-      FOR_EACH_VEC_ELT (ssa_names_to_purge, i, var)
-	frame->unbind (var);
-
-      /* Purge the regions.  Nothing should point to them, and they
-	 should have no children, as they are for SSA names.  */
-      new_state.m_region_model->purge_regions (purgeable_ssa_regions,
-					       &stats,
-					       eg.get_logger ());
-    }
-
-  /* Purge unused svalues.  */
-  // TODO: which enode to use, if any?
-  impl_region_model_context ctxt (eg, NULL,
-				  this,
-				  &new_state,
-				  change,
-				  NULL);
-  new_state.m_region_model->purge_unused_svalues (&stats, &ctxt);
-  if (logger)
-    {
-      logger->log ("num svalues purged: %i", stats.m_num_svalues);
-      logger->log ("num regions purged: %i", stats.m_num_regions);
-      logger->log ("num equiv_classes purged: %i", stats.m_num_equiv_classes);
-      logger->log ("num constraints purged: %i", stats.m_num_constraints);
-      logger->log ("num sm map items purged: %i", stats.m_num_client_items);
-    }
-
-  new_state.m_region_model->canonicalize (&ctxt);
-
-  return new_state;
-}
-
-/* FIXME.  */
-
-program_state
-program_state::prune_for_point2 (exploded_graph &eg,
-				 const program_point &point,
-				 const exploded_node *enode_for_diag,
-				 state_change *change) const
+				const exploded_node *enode_for_diag) const
 {
   logger * const logger = eg.get_logger ();
   LOG_SCOPE (logger);
@@ -1794,80 +1110,7 @@ program_state::prune_for_point2 (exploded_graph &eg,
 		logger->log ("purging region: TODO");
 	    }
 	}
-#if 0
-      region_id_set purgeable_ssa_regions (new_state.m_region_model);
-      region_id frame_rid
-	= new_state.m_region_model->get_current_frame_id ();
-      frame_region *frame
-	= new_state.m_region_model->get_region <frame_region>(frame_rid);
-
-      /* TODO: maybe move to a member of region_model?  */
-
-      auto_vec<tree> ssa_names_to_purge;
-      for (frame_region::map_t::iterator iter = frame->begin ();
-	   iter != frame->end ();
-	   ++iter)
-	{
-	  tree var = (*iter).first;
-	  region_id rid = (*iter).second;
-	  if (TREE_CODE (var) == SSA_NAME)
-	    {
-	      const state_purge_per_ssa_name &per_ssa
-		= pm->get_data_for_ssa_name (var);
-	      if (!per_ssa.needed_at_point_p (point.get_function_point ()))
-		{
-		  region *region
-		    = new_state.m_region_model->get_region (rid);
-		  svalue_id sid = region->get_value_direct ();
-		  if (!sid.null_p ())
-		    {
-		      if (!new_state.can_purge_p (eg.get_ext_state (), sid))
-			{
-			  /* (currently only state maps can keep things
-			     alive).  */
-			  if (logger)
-			    logger->log ("not purging RID: %i for %qE"
-					 " (used by state map)",
-					 rid.as_int (), var);
-			  continue;
-			}
-
-		      /* Don't purge regions containing svalues that
-			 have a change of sm-state, to make it easier to
-			 generate state_change_event messages.  */
-		      if (change)
-			if (change->affects_p (sid))
-			  {
-			    if (logger)
-			      logger->log ("not purging RID: %i for %qE"
-					   " (affected by change)",
-					   rid.as_int (), var);
-			    continue;
-			  }
-		    }
-		  purgeable_ssa_regions.add_region (rid);
-		  ssa_names_to_purge.safe_push (var);
-		  if (logger)
-		    logger->log ("purging RID: %i for %qE", rid.as_int (), var);
-		  /* We also need to remove the region from the map.
-		     We're in mid-traversal, so the removal is done in
-		     unbind below.  */
-		}
-	    }
-	}
 
-      /* Unbind the regions from the frame's map of vars-to-regions.  */
-      unsigned i;
-      tree var;
-      FOR_EACH_VEC_ELT (ssa_names_to_purge, i, var)
-	frame->unbind (var);
-
-      /* Purge the regions.  Nothing should point to them, and they
-	 should have no children, as they are for SSA names.  */
-      new_state.m_region_model->purge_regions (purgeable_ssa_regions,
-					       &stats,
-					       eg.get_logger ());
-#endif
       /* FIXME.  Do this here rather than at add_edge, to cover the
 	 fine-grained cases.  */
       if (num_ssas_purged > 0)
@@ -1876,7 +1119,6 @@ program_state::prune_for_point2 (exploded_graph &eg,
 	  impl_region_model2_context ctxt (eg, enode_for_diag,
 					   this,
 					   &new_state,
-					   change,
 					   point.get_stmt ());
 	  detect_leaks2 (*this, new_state, NULL, eg.get_ext_state (), &ctxt);
 	}
@@ -1910,29 +1152,6 @@ program_state::prune_for_point2 (exploded_graph &eg,
   return new_state;
 }
 
-/* Remap all svalue_ids in this state's m_checker_states according to MAP.
-   The svalues_ids in the region_model are assumed to already have been
-   remapped.  */
-
-void
-program_state::remap_svalue_ids (const svalue_id_map &map)
-{
-  int i;
-  sm_state_map *smap;
-  FOR_EACH_VEC_ELT (m_checker_states, i, smap)
-    smap->remap_svalue_ids (map);
-}
-
-/* Attempt to return a tree that represents SID, or return NULL_TREE.
-   Find the first region that stores the value (e.g. a local) and
-   generate a representative tree for it.  */
-
-tree
-program_state::get_representative_tree (svalue_id sid) const
-{
-  return m_region_model->get_representative_tree (sid);
-}
-
 /* FIXME.  */
 
 tree
@@ -1954,92 +1173,6 @@ program_state::can_merge_with_p (const program_state &other,
 				 program_state *out) const
 {
   gcc_assert (out);
-
-  if (m_region_model2)
-    return can_merge_with2_p (other, ext_state, point, out);
-
-  /* TODO:  initially I had an early reject here if there
-     are sm-differences between the states.  However, this was
-     falsely rejecting merger opportunities for states where the
-     only difference was in svalue_id ordering.  */
-
-  /* Attempt to merge the region_models.  */
-
-  svalue_id_merger_mapping sid_mapping (*m_region_model,
-					*other.m_region_model);
-  if (!m_region_model->can_merge_with_p (*other.m_region_model,
-					 out->m_region_model,
-					 &sid_mapping))
-    return false;
-
-  /* Copy m_checker_states to result, remapping svalue_ids using
-     sid_mapping.  */
-  int i;
-  sm_state_map *smap;
-  FOR_EACH_VEC_ELT (out->m_checker_states, i, smap)
-    delete smap;
-  out->m_checker_states.truncate (0);
-
-  /* Remap this and other's m_checker_states using sid_mapping.
-     Only merge states that have equality between the two end-results:
-     sm-state differences are likely to be interesting to end-users, and
-     hence are worth exploring as separate paths in the exploded graph.  */
-  FOR_EACH_VEC_ELT (m_checker_states, i, smap)
-    {
-      sm_state_map *other_smap = other.m_checker_states[i];
-
-      /* If clone_with_remapping returns NULL for one of the input smaps,
-	 then it has sm-state for an svalue_id where the svalue_id is
-	 being mapped to svalue_id::null in its sid_mapping, meaning that
-	 the svalue is to be dropped during the merger.  We don't want
-	 to lose sm-state during a state merger, so return false for these
-	 cases.  */
-      sm_state_map *remapped_a_smap
-	= smap->clone_with_remapping (sid_mapping.m_map_from_a_to_m);
-      if (!remapped_a_smap)
-	return false;
-      sm_state_map *remapped_b_smap
-	= other_smap->clone_with_remapping (sid_mapping.m_map_from_b_to_m);
-      if (!remapped_b_smap)
-	{
-	  delete remapped_a_smap;
-	  return false;
-	}
-
-      /* Both states have sm-state for the same values; now ensure that the
-	 states are equal.  */
-      if (*remapped_a_smap == *remapped_b_smap)
-	{
-	  out->m_checker_states.safe_push (remapped_a_smap);
-	  delete remapped_b_smap;
-	}
-      else
-	{
-	  /* Don't merge if there are sm-state differences.  */
-	  delete remapped_a_smap;
-	  delete remapped_b_smap;
-	  return false;
-	}
-    }
-
-  impl_region_model_context ctxt (out, NULL, ext_state);
-  out->m_region_model->canonicalize (&ctxt);
-
-  return true;
-}
-
-/* Attempt to merge this state with OTHER, both using EXT_STATE.
-   Write the result to *OUT, canonicalizing it.
-   If the states were merged successfully, return true.  */
-// FIXME: POINT
-
-bool
-program_state::can_merge_with2_p (const program_state &other,
-				  const extrinsic_state &ext_state,
-				  const program_point &point,
-				  program_state *out) const
-{
-  gcc_assert (out);
   gcc_assert (m_region_model2);
 
   /* Early reject if there are sm-differences between the states.  */
@@ -2077,17 +1210,7 @@ program_state::validate (const extrinsic_state &ext_state) const
   return;
 #endif
 
-  if (!m_region_model)
-    return;
-  m_region_model->validate ();
-  gcc_assert (m_checker_states.length () == ext_state.get_num_checkers ());
-  int sm_idx;
-  sm_state_map *smap;
-  FOR_EACH_VEC_ELT (m_checker_states, sm_idx, smap)
-    {
-      const state_machine &sm = ext_state.get_sm (sm_idx);
-      smap->validate (sm, m_region_model->get_num_svalues ());
-    }
+  gcc_assert (m_checker_states2.length () == ext_state.get_num_checkers ());
 }
 
 static void
@@ -2187,6 +1310,7 @@ program_state::detect_leaks2 (const program_state &src_state,
     (dest_svalues, dest_state.m_region_model2);
 }
 
+#if 0
 /* Dump this sm_change to PP.  */
 
 void
@@ -2353,6 +1477,7 @@ state_change::validate (const program_state &new_state,
   FOR_EACH_VEC_ELT (m_sm_changes, i, change)
     change->validate (new_state, ext_state);
 }
+#endif
 
 #if CHECKING_P
 
@@ -2391,127 +1516,6 @@ test_sm_state_map ()
   tree y = build_global_decl ("y", integer_type_node);
   tree z = build_global_decl ("z", integer_type_node);
 
-  /* Test setting states on svalue_id instances directly.  */
-  {
-    region_model model;
-    svalue_id sid_x = model.get_rvalue (x, NULL);
-    svalue_id sid_y = model.get_rvalue (y, NULL);
-    svalue_id sid_z = model.get_rvalue (z, NULL);
-
-    sm_state_map map;
-    ASSERT_TRUE (map.is_empty_p ());
-    ASSERT_EQ (map.get_state (sid_x), 0);
-
-    map.impl_set_state (sid_x, 42, sid_z);
-    ASSERT_EQ (map.get_state (sid_x), 42);
-    ASSERT_EQ (map.get_origin (sid_x), sid_z);
-    ASSERT_EQ (map.get_state (sid_y), 0);
-    ASSERT_FALSE (map.is_empty_p ());
-
-    map.impl_set_state (sid_y, 0, sid_z);
-    ASSERT_EQ (map.get_state (sid_y), 0);
-
-    map.impl_set_state (sid_x, 0, sid_z);
-    ASSERT_EQ (map.get_state (sid_x), 0);
-    ASSERT_TRUE (map.is_empty_p ());
-  }
-
-  /* Test setting states via equivalence classes.  */
-  {
-    region_model model;
-    svalue_id sid_x = model.get_rvalue (x, NULL);
-    svalue_id sid_y = model.get_rvalue (y, NULL);
-    svalue_id sid_z = model.get_rvalue (z, NULL);
-
-    sm_state_map map;
-    ASSERT_TRUE (map.is_empty_p ());
-    ASSERT_EQ (map.get_state (sid_x), 0);
-    ASSERT_EQ (map.get_state (sid_y), 0);
-
-    model.add_constraint (x, EQ_EXPR, y, NULL);
-
-    /* Setting x to a state should also update y, as they
-       are in the same equivalence class.  */
-    map.set_state (&model, sid_x, 5, sid_z);
-    ASSERT_EQ (map.get_state (sid_x), 5);
-    ASSERT_EQ (map.get_state (sid_y), 5);
-    ASSERT_EQ (map.get_origin (sid_x), sid_z);
-    ASSERT_EQ (map.get_origin (sid_y), sid_z);
-  }
-
-  /* Test equality and hashing.  */
-  {
-    region_model model;
-    svalue_id sid_y = model.get_rvalue (y, NULL);
-    svalue_id sid_z = model.get_rvalue (z, NULL);
-
-    sm_state_map map0;
-    sm_state_map map1;
-    sm_state_map map2;
-
-    ASSERT_EQ (map0.hash (), map1.hash ());
-    ASSERT_EQ (map0, map1);
-
-    map1.impl_set_state (sid_y, 5, sid_z);
-    ASSERT_NE (map0.hash (), map1.hash ());
-    ASSERT_NE (map0, map1);
-
-    /* Make the same change to map2.  */
-    map2.impl_set_state (sid_y, 5, sid_z);
-    ASSERT_EQ (map1.hash (), map2.hash ());
-    ASSERT_EQ (map1, map2);
-  }
-
-  /* Equality and hashing shouldn't depend on ordering.  */
-  {
-    sm_state_map map0;
-    sm_state_map map1;
-    sm_state_map map2;
-
-    ASSERT_EQ (map0.hash (), map1.hash ());
-    ASSERT_EQ (map0, map1);
-
-    map1.impl_set_state (svalue_id::from_int (14), 2, svalue_id::null ());
-    map1.impl_set_state (svalue_id::from_int (16), 3, svalue_id::null ());
-    map1.impl_set_state (svalue_id::from_int (1), 2, svalue_id::null ());
-    map1.impl_set_state (svalue_id::from_int (9), 2, svalue_id::null ());
-
-    map2.impl_set_state (svalue_id::from_int (1), 2, svalue_id::null ());
-    map2.impl_set_state (svalue_id::from_int (16), 3, svalue_id::null ());
-    map2.impl_set_state (svalue_id::from_int (14), 2, svalue_id::null ());
-    map2.impl_set_state (svalue_id::from_int (9), 2, svalue_id::null ());
-
-    ASSERT_EQ (map1.hash (), map2.hash ());
-    ASSERT_EQ (map1, map2);
-  }
-
-  /* Test sm_state_map::remap_svalue_ids.  */
-  {
-    sm_state_map map;
-    svalue_id sid_0 = svalue_id::from_int (0);
-    svalue_id sid_1 = svalue_id::from_int (1);
-    svalue_id sid_2 = svalue_id::from_int (2);
-
-    map.impl_set_state (sid_0, 42, sid_2);
-    ASSERT_EQ (map.get_state (sid_0), 42);
-    ASSERT_EQ (map.get_origin (sid_0), sid_2);
-    ASSERT_EQ (map.get_state (sid_1), 0);
-    ASSERT_EQ (map.get_state (sid_2), 0);
-
-    /* Apply a remapping to the IDs.  */
-    svalue_id_map remapping (3);
-    remapping.put (sid_0, sid_1);
-    remapping.put (sid_1, sid_2);
-    remapping.put (sid_2, sid_0);
-    map.remap_svalue_ids (remapping);
-
-    /* Verify that the IDs have been remapped.  */
-    ASSERT_EQ (map.get_state (sid_1), 42);
-    ASSERT_EQ (map.get_origin (sid_1), sid_0);
-    ASSERT_EQ (map.get_state (sid_2), 0);
-    ASSERT_EQ (map.get_state (sid_0), 0);
-  }
-
   // TODO: coverage for purging
 }
 
@@ -2520,48 +1524,6 @@ test_sm_state_map ()
 static void
 test_program_state_dumping ()
 {
-  /* Create a program_state for a global ptr "p" that has
-     malloc sm-state, pointing to a region on the heap.  */
-  tree p = build_global_decl ("p", ptr_type_node);
-
-  state_machine *sm = make_malloc_state_machine (NULL);
-  const state_machine::state_t UNCHECKED_STATE
-    = sm->get_state_by_name ("unchecked");
-  auto_delete_vec <state_machine> checkers;
-  checkers.safe_push (sm);
-  extrinsic_state ext_state (checkers);
-
-  program_state s (ext_state);
-  region_model *model = s.m_region_model;
-  region_id new_rid = model->add_new_malloc_region ();
-  svalue_id ptr_sid
-      = model->get_or_create_ptr_svalue (ptr_type_node, new_rid);
-  model->set_value (model->get_lvalue (p, NULL),
-		    ptr_sid, NULL);
-  sm_state_map *smap = s.m_checker_states[0];
-
-  smap->impl_set_state (ptr_sid, UNCHECKED_STATE, svalue_id::null ());
-  ASSERT_EQ (smap->get_state (ptr_sid), UNCHECKED_STATE);
-
-#if 0
-  ASSERT_DUMP_EQ
-    (s, ext_state, false,
-     "rmodel: r0: {kind: `root', parent: null, sval: null}\n"
-     "|-heap: r1: {kind: `heap', parent: r0, sval: null}\n"
-     "|  `-r2: {kind: `symbolic', parent: r1, sval: null, possibly_null: true}\n"
-     "`-globals: r3: {kind: `globals', parent: r0, sval: null, map: {`p': r4}}\n"
-     "  `-`p': r4: {kind: `primitive', parent: r3, sval: sv0, type: `void *'}\n"
-     "    |: sval: sv0: {type: `void *', &r2}\n"
-     "    |: type: `void *'\n"
-     "svalues:\n"
-     "  sv0: {type: `void *', &r2}\n"
-     "constraint manager:\n"
-     "  equiv classes:\n"
-     "  constraints:\n"
-     "malloc: {sv0: unchecked (`p')}\n");
-  ASSERT_DUMP_EQ (s, ext_state, true,
-		  "rmodel: p: &r2 malloc: {sv0: unchecked (`p')}");
-#endif
 }
 
 /* Verify that program_state::dump_to_pp works for string literals.  */
@@ -2569,45 +1531,6 @@ test_program_state_dumping ()
 static void
 test_program_state_dumping_2 ()
 {
-    /* Create a program_state for a global ptr "p" that points to
-       a string constant.  */
-  tree p = build_global_decl ("p", ptr_type_node);
-
-  tree string_cst_ptr = build_string_literal (4, "foo");
-
-  auto_delete_vec <state_machine> checkers;
-  extrinsic_state ext_state (checkers);
-
-  program_state s (ext_state);
-  region_model *model = s.m_region_model;
-  region_id p_rid = model->get_lvalue (p, NULL);
-  svalue_id str_sid = model->get_rvalue (string_cst_ptr, NULL);
-  model->set_value (p_rid, str_sid, NULL);
-
-  ASSERT_DUMP_EQ
-    (s, ext_state, false,
-     "rmodel:\n"
-     "r0: {kind: `root', parent: null, sval: null}\n"
-     "|-globals: r1: {kind: `globals', parent: r0, sval: null, map: {`p': r2}}\n"
-     "|  `-`p': r2: {kind: `primitive', parent: r1, sval: sv3, type: `void *'}\n"
-     "|    |: sval: sv3: {type: `void *', &r4}\n"
-     "|    |: type: `void *'\n"
-     "`-r3: {kind: `array', parent: r0, sval: sv0, type: `const char[4]', array: {[0]: r4}}\n"
-     "  |: sval: sv0: {type: `const char[4]', `\"foo\"'}\n"
-     "  |: type: `const char[4]'\n"
-     "  `-[0]: r4: {kind: `primitive', parent: r3, sval: null, type: `const char'}\n"
-     "    |: type: `const char'\n"
-     "svalues:\n"
-     "  sv0: {type: `const char[4]', `\"foo\"'}\n"
-     "  sv1: {type: `int', `0'}\n"
-     "  sv2: {type: `const char *', &r4}\n"
-     "  sv3: {type: `void *', &r4}\n"
-     "constraint manager:\n"
-     "  equiv classes:\n"
-     "  constraints:\n");
-
-  ASSERT_DUMP_EQ (s, ext_state, true,
-		  "{rmodel: {p: &\"foo\"[0]}}");
 }
 
 /* Verify that program_states with identical sm-state can be merged,
@@ -2627,6 +1550,7 @@ test_program_state_merging ()
   extrinsic_state ext_state (checkers);
 
   program_state s0 (ext_state);
+#if 0
   impl_region_model_context ctxt (&s0, NULL, ext_state);
 
   region_model *model0 = s0.m_region_model;
@@ -2673,6 +1597,7 @@ test_program_state_merging ()
 
   /* After canonicalization, we ought to have equality with the inputs.  */
   ASSERT_EQ (s0, merged);
+#endif
 }
 
 /* Verify that program_states with different global-state in an sm-state
@@ -2688,7 +1613,7 @@ test_program_state_merging_2 ()
 
   program_state s0 (ext_state);
   {
-    sm_state_map *smap0 = s0.m_checker_states[0];
+    sm_state_map2 *smap0 = s0.m_checker_states2[0];
     const state_machine::state_t TEST_STATE_0 = 0;
     smap0->set_global_state (TEST_STATE_0);
     ASSERT_EQ (smap0->get_global_state (), TEST_STATE_0);
@@ -2696,7 +1621,7 @@ test_program_state_merging_2 ()
 
   program_state s1 (ext_state);
   {
-    sm_state_map *smap1 = s1.m_checker_states[0];
+    sm_state_map2 *smap1 = s1.m_checker_states2[0];
     const state_machine::state_t TEST_STATE_1 = 1;
     smap1->set_global_state (TEST_STATE_1);
     ASSERT_EQ (smap1->get_global_state (), TEST_STATE_1);
diff --git a/gcc/analyzer/program-state.h b/gcc/analyzer/program-state.h
index f6edf8de65b..22b7a6bf297 100644
--- a/gcc/analyzer/program-state.h
+++ b/gcc/analyzer/program-state.h
@@ -64,161 +64,6 @@ private:
   engine2 *m_engine2;
 };
 
-} // namespace ana
-
-template <> struct default_hash_traits<svalue_id>
-: public pod_hash_traits<svalue_id>
-{
-  static const bool empty_zero_p = false;
-};
-
-template <>
-inline hashval_t
-pod_hash_traits<svalue_id>::hash (value_type v)
-{
-  return v.as_int ();
-}
-
-template <>
-inline bool
-pod_hash_traits<svalue_id>::equal (const value_type &existing,
-				   const value_type &candidate)
-{
-  return existing == candidate;
-}
-template <>
-inline void
-pod_hash_traits<svalue_id>::mark_deleted (value_type &v)
-{
-  v = svalue_id::from_int (-2);
-}
-template <>
-inline void
-pod_hash_traits<svalue_id>::mark_empty (value_type &v)
-{
-  v = svalue_id::null ();
-}
-template <>
-inline bool
-pod_hash_traits<svalue_id>::is_deleted (value_type v)
-{
-  return v.as_int () == -2;
-}
-template <>
-inline bool
-pod_hash_traits<svalue_id>::is_empty (value_type v)
-{
-  return v.null_p ();
-}
-
-namespace ana {
-
-/* Map from svalue_id to state machine state, also capturing the origin of
-   each state.  */
-
-class sm_state_map
-{
-public:
-  /* An entry in the hash_map.  */
-  struct entry_t
-  {
-    /* Default ctor needed by hash_map::empty.  */
-    entry_t ()
-    : m_state (0), m_origin (svalue_id::null ())
-    {
-    }
-
-    entry_t (state_machine::state_t state,
-	     svalue_id origin)
-    : m_state (state), m_origin (origin)
-    {}
-
-    bool operator== (const entry_t &other) const
-    {
-      return (m_state == other.m_state
-	      && m_origin == other.m_origin);
-    }
-    bool operator!= (const entry_t &other) const
-    {
-      return !(*this == other);
-    }
-
-    state_machine::state_t m_state;
-    svalue_id m_origin;
-  };
-  typedef hash_map <svalue_id, entry_t> map_t;
-  typedef map_t::iterator iterator_t;
-
-  sm_state_map ();
-
-  sm_state_map *clone () const;
-
-  sm_state_map *
-  clone_with_remapping (const one_way_svalue_id_map &id_map) const;
-
-  void print (const state_machine &sm, const region_model *model,
-	      pretty_printer *pp) const;
-  void dump (const state_machine &sm) const;
-
-  bool is_empty_p () const;
-
-  hashval_t hash () const;
-
-  bool operator== (const sm_state_map &other) const;
-  bool operator!= (const sm_state_map &other) const
-  {
-    return !(*this == other);
-  }
-
-  state_machine::state_t get_state (svalue_id sid) const;
-  svalue_id get_origin (svalue_id sid) const;
-
-  void set_state (region_model *model,
-		  svalue_id sid,
-		  state_machine::state_t state,
-		  svalue_id origin);
-  bool set_state (const equiv_class &ec,
-		  state_machine::state_t state,
-		  svalue_id origin);
-  bool impl_set_state (svalue_id sid,
-		       state_machine::state_t state,
-		       svalue_id origin);
-
-  void set_global_state (state_machine::state_t state);
-  state_machine::state_t get_global_state () const;
-
-  void purge_for_unknown_fncall (const exploded_graph &eg,
-				 const state_machine &sm,
-				 const gcall *call, tree fndecl,
-				 region_model *new_model,
-				 region_model_context *ctxt);
-
-  void remap_svalue_ids (const svalue_id_map &map);
-
-  int on_svalue_purge (const state_machine &sm,
-		       int sm_idx,
-		       svalue_id first_unused_sid,
-		       const svalue_id_map &map,
-		       impl_region_model_context *ctxt);
-
-  void on_inherited_svalue (svalue_id parent_sid,
-			    svalue_id child_sid);
-
-  void on_cast (svalue_id src_sid,
-		svalue_id dst_sid);
-
-  void on_unknown_change (svalue_id sid);
-
-  void validate (const state_machine &sm, int num_svalues) const;
-
-  iterator_t begin () const { return m_map.begin (); }
-  iterator_t end () const { return m_map.end (); }
-
-private:
-  map_t m_map;
-  state_machine::state_t m_global_state;
-};
-
 /* Map from svalue2 * to state machine state, also capturing the origin of
    each state.  */
 
@@ -385,38 +230,14 @@ public:
 
   bool on_edge (exploded_graph &eg,
 		const exploded_node &enode,
-		const superedge *succ,
-		state_change *change);
+		const superedge *succ);
 
   program_state prune_for_point (exploded_graph &eg,
 				 const program_point &point,
-				 const exploded_node *enode_for_diag,
-				 state_change *change) const;
-  program_state prune_for_point2 (exploded_graph &eg,
-				  const program_point &point,
-				  const exploded_node *enode_for_diag,
-				  state_change *change) const;
-
-  void remap_svalue_ids (const svalue_id_map &map);
+				 const exploded_node *enode_for_diag) const;
 
-  tree get_representative_tree (svalue_id sid) const;
   tree get_representative_tree2 (const svalue2 *sval) const;
 
-  bool can_purge_p (const extrinsic_state &ext_state,
-		    svalue_id sid)
-  {
-    /* Don't purge vars that have non-purgeable sm state, to avoid
-       generating false "leak" complaints.  */
-    int i;
-    sm_state_map *smap;
-    FOR_EACH_VEC_ELT (m_checker_states, i, smap)
-      {
-	const state_machine &sm = ext_state.get_sm (i);
-	if (!sm.can_purge_p (smap->get_state (sid)))
-	  return false;
-      }
-    return true;
-  }
   bool can_purge_p2 (const extrinsic_state &ext_state,
 		     const svalue2 *sval)
   {
@@ -450,12 +271,8 @@ public:
 			     const extrinsic_state &ext_state,
 			     region_model2_context *ctxt);
 
-  /* TODO: eventually eliminate the two models in favor of the new one.  */
-  region_model2 *m_region_model2;
   /* TODO: lose the pointer here (const-correctness issues?).  */
-  region_model *m_region_model;
-  /* TODO: eventually eliminate the two sm_state_maps in favor of the new one.  */
-  auto_delete_vec<sm_state_map> m_checker_states;
+  region_model2 *m_region_model2;
   auto_delete_vec<sm_state_map2> m_checker_states2;
 
   /* If false, then don't attempt to explore further states along this path.
@@ -464,31 +281,6 @@ public:
   bool m_valid;
 };
 
-/* An abstract base class for use with for_each_state_change.  */
-
-class state_change_visitor
-{
-public:
-  virtual ~state_change_visitor () {}
-
-  /* Return true for early exit, false to keep iterating.  */
-  virtual bool on_global_state_change (const state_machine &sm,
-				       state_machine::state_t src_sm_val,
-				       state_machine::state_t dst_sm_val) = 0;
-
-  /* Return true for early exit, false to keep iterating.  */
-  virtual bool on_state_change (const state_machine &sm,
-				state_machine::state_t src_sm_val,
-				state_machine::state_t dst_sm_val,
-				tree dst_rep,
-				svalue_id dst_origin_sid) = 0;
-};
-
-extern bool for_each_state_change (const program_state &src_state,
-				   const program_state &dst_state,
-				   const extrinsic_state &ext_state,
-				   state_change_visitor *visitor);
-
 /* An abstract base class for use with for_each_state_change2.  */
 
 class state_change_visitor2
@@ -519,7 +311,7 @@ extern bool for_each_state_change2 (const program_state &src_state,
    exploded_graph, and for recording sm-state-changes, so that
    values that change aren't purged (to make it easier to generate
    state_change_event instances in the diagnostic_path).  */
-
+#if  0
 class state_change
 {
  public:
@@ -575,6 +367,7 @@ class state_change
  private:
   auto_vec<sm_change> m_sm_changes;
 };
+#endif
 
 } // namespace ana
 
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 0794be9a583..48eb491b6d6 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -137,648 +137,6 @@ dump_separator (pretty_printer *pp, bool *is_first)
   *is_first = false;
 }
 
-/* Concrete subclass of constraint_manager that wires it up to a region_model
-   (whilst allowing the constraint_manager and region_model to be somewhat
-   at arms length).
-   TODO: revisit this; maybe put the region_model * into the constraint_manager
-   base class.  */
-
-class impl_constraint_manager : public constraint_manager
-{
- public:
-  impl_constraint_manager (region_model *model)
-  : constraint_manager (),
-    m_model (model)
-  {}
-
-  impl_constraint_manager (const impl_constraint_manager &other,
-			   region_model *model)
-  : constraint_manager (other),
-    m_model (model)
-  {}
-
-  constraint_manager *clone (region_model *model) const
-  {
-    return new impl_constraint_manager (*this, model);
-  }
-
-  tree maybe_get_constant (svalue_id sid) const FINAL OVERRIDE
-  {
-    svalue *svalue = m_model->get_svalue (sid);
-    return svalue->maybe_get_constant ();
-  }
-
-  svalue_id get_sid_for_constant (tree cst) const FINAL OVERRIDE
-  {
-    gcc_assert (CONSTANT_CLASS_P (cst));
-    return m_model->get_rvalue (cst, NULL);
-  }
-
-  int get_num_svalues () const FINAL OVERRIDE
-  {
-    return m_model->get_num_svalues ();
-  }
-
- private:
-  region_model *m_model;
-};
-
-/* class svalue_id.  */
-
-/* Print this svalue_id to PP.  */
-
-void
-svalue_id::print (pretty_printer *pp) const
-{
-  if (null_p ())
-    pp_printf (pp, "null");
-  else
-    pp_printf (pp, "sv%i", m_idx);
-}
-
-/* Print this svalue_id in .dot format to PP.  */
-
-void
-svalue_id::dump_node_name_to_pp (pretty_printer *pp) const
-{
-  gcc_assert (!null_p ());
-  pp_printf (pp, "svalue_%i", m_idx);
-}
-
-/* Assert that this object is valid (w.r.t. MODEL).  */
-
-void
-svalue_id::validate (const region_model &model) const
-{
-  gcc_assert (null_p () || m_idx < (int)model.get_num_svalues ());
-}
-
-/* class region_id.  */
-
-/* Print this region_id to PP.  */
-
-void
-region_id::print (pretty_printer *pp) const
-{
-  if (null_p ())
-    pp_printf (pp, "null");
-  else
-    pp_printf (pp, "r%i", m_idx);
-}
-
-/* Print this region_id in .dot format to PP.  */
-
-void
-region_id::dump_node_name_to_pp (pretty_printer *pp) const
-{
-  gcc_assert (!null_p ());
-  pp_printf (pp, "region_%i", m_idx);
-}
-
-/* Assert that this object is valid (w.r.t. MODEL).  */
-
-void
-region_id::validate (const region_model &model) const
-{
-  gcc_assert (null_p () || m_idx < (int)model.get_num_regions ());
-}
-
-/* class region_id_set.  */
-
-region_id_set::region_id_set (const region_model *model)
-: m_bitmap (model->get_num_regions ())
-{
-  bitmap_clear (m_bitmap);
-}
-
-/* class svalue_id_set.  */
-
-svalue_id_set::svalue_id_set ()
-: m_bitmap (NULL)
-{
-  bitmap_clear (m_bitmap);
-}
-
-/* class svalue and its various subclasses.  */
-
-/* class svalue.  */
-
-/* svalue's equality operator.  Most of the work is done by the
-   a "compare_fields" implementation on each subclass.  */
-
-bool
-svalue::operator== (const svalue &other) const
-{
-  enum svalue_kind this_kind = get_kind ();
-  enum svalue_kind other_kind = other.get_kind ();
-  if (this_kind != other_kind)
-    return false;
-
-  if (m_type != other.m_type)
-    return false;
-
-  switch (this_kind)
-    {
-    default:
-      gcc_unreachable ();
-    case SK_REGION:
-      {
-	const region_svalue &this_sub
-	  = (const region_svalue &)*this;
-	const region_svalue &other_sub
-	  = (const region_svalue &)other;
-	return this_sub.compare_fields (other_sub);
-      }
-      break;
-    case SK_CONSTANT:
-      {
-	const constant_svalue &this_sub
-	  = (const constant_svalue &)*this;
-	const constant_svalue &other_sub
-	  = (const constant_svalue &)other;
-	return this_sub.compare_fields (other_sub);
-      }
-      break;
-    case SK_UNKNOWN:
-      {
-	const unknown_svalue &this_sub
-	  = (const unknown_svalue &)*this;
-	const unknown_svalue &other_sub
-	  = (const unknown_svalue &)other;
-	return this_sub.compare_fields (other_sub);
-      }
-      break;
-    case SK_POISONED:
-      {
-	const poisoned_svalue &this_sub
-	  = (const poisoned_svalue &)*this;
-	const poisoned_svalue &other_sub
-	  = (const poisoned_svalue &)other;
-	return this_sub.compare_fields (other_sub);
-      }
-      break;
-    case SK_SETJMP:
-      {
-	const setjmp_svalue &this_sub
-	  = (const setjmp_svalue &)*this;
-	const setjmp_svalue &other_sub
-	  = (const setjmp_svalue &)other;
-	return this_sub.compare_fields (other_sub);
-      }
-      break;
-    }
-}
-
-/* Generate a hash value for this svalue.  Most of the work is done by the
-   add_to_hash vfunc.  */
-
-hashval_t
-svalue::hash () const
-{
-  inchash::hash hstate;
-  if (m_type)
-    hstate.add_int (TYPE_UID (m_type));
-  add_to_hash (hstate);
-  return hstate.end ();
-}
-
-/* Print this svalue and its ID to PP.  */
-
-void
-svalue::print (const region_model &model,
-	       svalue_id this_sid,
-	       pretty_printer *pp) const
-{
-  this_sid.print (pp);
-  pp_string (pp, ": {");
-
-  if (m_type)
-    {
-      gcc_assert (TYPE_P (m_type));
-      pp_string (pp, "type: ");
-      print_quoted_type (pp, m_type);
-      pp_string (pp, ", ");
-    }
-
-  /* vfunc.  */
-  print_details (model, this_sid, pp);
-
-  pp_string (pp, "}");
-}
-
-/* Dump this svalue in the form of a .dot record to PP.  */
-
-void
-svalue::dump_dot_to_pp (const region_model &model,
-			svalue_id this_sid,
-			pretty_printer *pp) const
-{
-  this_sid.dump_node_name_to_pp (pp);
-  pp_printf (pp, " [label=\"");
-  pp_write_text_to_stream (pp);
-  this_sid.print (pp);
-  pp_string (pp, ": {");
-  print (model, this_sid, pp);
-  pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
-  pp_string (pp, "}\"];");
-  pp_newline (pp);
-}
-
-/* Base implementation of svalue::remap_region_ids vfunc.  */
-
-void
-svalue::remap_region_ids (const region_id_map &)
-{
-  /* Empty.  */
-}
-
-/* Base implementation of svalue::walk_for_canonicalization vfunc.  */
-
-void
-svalue::walk_for_canonicalization (canonicalization *) const
-{
-  /* Empty.  */
-}
-
-/* Base implementation of svalue::get_child_sid vfunc.  */
-
-svalue_id
-svalue::get_child_sid (region *parent ATTRIBUTE_UNUSED,
-		       region *child,
-		       region_model &model,
-		       region_model_context *ctxt ATTRIBUTE_UNUSED)
-{
-  svalue *new_child_value = clone ();
-  if (child->get_type ())
-    new_child_value->m_type = child->get_type ();
-  svalue_id new_child_sid = model.add_svalue (new_child_value);
-  return new_child_sid;
-}
-
-/* If this svalue is a constant_svalue, return the underlying tree constant.
-   Otherwise return NULL_TREE.  */
-
-tree
-svalue::maybe_get_constant () const
-{
-  if (const constant_svalue *cst_sval = dyn_cast_constant_svalue ())
-    return cst_sval->get_constant ();
-  else
-    return NULL_TREE;
-}
-
-/* class region_svalue : public svalue.  */
-
-/* Compare the fields of this region_svalue with OTHER, returning true
-   if they are equal.
-   For use by svalue::operator==.  */
-
-bool
-region_svalue::compare_fields (const region_svalue &other) const
-{
-  return m_rid == other.m_rid;
-}
-
-/* Implementation of svalue::add_to_hash vfunc for region_svalue.  */
-
-void
-region_svalue::add_to_hash (inchash::hash &hstate) const
-{
-  inchash::add (m_rid, hstate);
-}
-
-/* Implementation of svalue::print_details vfunc for region_svalue.  */
-
-void
-region_svalue::print_details (const region_model &model ATTRIBUTE_UNUSED,
-			      svalue_id this_sid ATTRIBUTE_UNUSED,
-			      pretty_printer *pp) const
-{
-  if (m_rid.null_p ())
-    pp_string (pp, "NULL");
-  else
-    {
-      pp_string (pp, "&");
-      m_rid.print (pp);
-    }
-}
-
-/* Implementation of svalue::dump_dot_to_pp for region_svalue.  */
-
-void
-region_svalue::dump_dot_to_pp (const region_model &model,
-			       svalue_id this_sid,
-			       pretty_printer *pp) const
-{
-  svalue::dump_dot_to_pp (model, this_sid, pp);
-
-  /* If non-NULL, add an edge to the pointed-to region.  */
-  if (!m_rid.null_p ())
-    {
-      this_sid.dump_node_name_to_pp (pp);
-      pp_string (pp, " -> ");
-      m_rid.dump_node_name_to_pp (pp);
-      pp_string (pp, ";");
-      pp_newline (pp);
-  }
-}
-
-/* Implementation of svalue::remap_region_ids vfunc for region_svalue.  */
-
-void
-region_svalue::remap_region_ids (const region_id_map &map)
-{
-  map.update (&m_rid);
-}
-
-/* Merge REGION_SVAL_A and REGION_SVAL_B using MERGER, writing the result
-   into *MERGED_SID.  */
-
-void
-region_svalue::merge_values (const region_svalue &region_sval_a,
-			     const region_svalue &region_sval_b,
-			     svalue_id *merged_sid,
-			     tree type,
-			     model_merger *merger)
-{
-  region_id a_rid = region_sval_a.get_pointee ();
-  region_id b_rid = region_sval_b.get_pointee ();
-
-  /* Both are non-NULL. */
-  gcc_assert (!a_rid.null_p () && !b_rid.null_p ());
-
-  /* Have these ptr-values already been merged?  */
-
-  region_id a_rid_in_m
-    = merger->m_map_regions_from_a_to_m.get_dst_for_src (a_rid);
-  region_id b_rid_in_m
-    = merger->m_map_regions_from_b_to_m.get_dst_for_src (b_rid);
-
-  /* "null_p" here means "we haven't seen this ptr-value before".
-     If we've seen one but not the other, or we have different
-     regions, then the merged ptr has to be "unknown".  */
-  if (a_rid_in_m != b_rid_in_m)
-    {
-      svalue *merged_sval = new unknown_svalue (type);
-      *merged_sid = merger->m_merged_model->add_svalue (merged_sval);
-      return;
-    }
-
-  /* Have we seen this yet?  If so, reuse the value.  */
-  if (!a_rid_in_m.null_p ())
-    {
-      *merged_sid
-	= merger->m_merged_model->get_or_create_ptr_svalue (type, a_rid_in_m);
-      return;
-    }
-
-  /* Otherwise we have A/B regions that haven't been referenced yet.  */
-
-  /* Are the regions the "same", when seen from the tree point-of-view.
-     If so, create a merged pointer to it.  */
-  path_var pv_a = merger->m_model_a->get_representative_path_var (a_rid);
-  path_var pv_b = merger->m_model_b->get_representative_path_var (b_rid);
-  if (pv_a.m_tree
-      && pv_a == pv_b)
-    {
-      region_id merged_pointee_rid
-	= merger->m_merged_model->get_lvalue (pv_a, NULL);
-      *merged_sid
-	= merger->m_merged_model->get_or_create_ptr_svalue (type,
-							    merged_pointee_rid);
-      merger->record_regions (a_rid, b_rid, merged_pointee_rid);
-      return;
-    }
-
-  /* Handle an A/B pair of ptrs that both point at heap regions.
-     If they both have a heap region in the merger model, merge them.  */
-  region *region_a = merger->m_model_a->get_region (a_rid);
-  region *region_b = merger->m_model_b->get_region (b_rid);
-  region_id a_parent_rid = region_a->get_parent ();
-  region_id b_parent_rid = region_b->get_parent ();
-  region *parent_region_a = merger->m_model_a->get_region (a_parent_rid);
-  region *parent_region_b = merger->m_model_b->get_region (b_parent_rid);
-  if (parent_region_a
-      && parent_region_b
-      && parent_region_a->get_kind () == RK_HEAP
-      && parent_region_b->get_kind () == RK_HEAP)
-    {
-	/* We have an A/B pair of ptrs that both point at heap regions.  */
-	/* presumably we want to see if each A/B heap region already
-	   has a merged region, and, if so, is it the same one.  */
-	// This check is above
-
-	region_id merged_pointee_rid
-	  = merger->m_merged_model->add_new_malloc_region ();
-	*merged_sid
-	  = merger->m_merged_model->get_or_create_ptr_svalue
-	     (type, merged_pointee_rid);
-	merger->record_regions (a_rid, b_rid, merged_pointee_rid);
-	return;
-    }
-
-  /* Two different non-NULL pointers?  Merge to unknown.  */
-  svalue *merged_sval = new unknown_svalue (type);
-  *merged_sid = merger->m_merged_model->add_svalue (merged_sval);
-  return;
-}
-
-/* Implementation of svalue::walk_for_canonicalization vfunc for
-   region_svalue.  */
-
-void
-region_svalue::walk_for_canonicalization (canonicalization *c) const
-{
-  c->walk_rid (m_rid);
-}
-
-/* Evaluate the condition LHS OP RHS.
-   Subroutine of region_model::eval_condition for when we have a pair of
-   pointers.  */
-
-tristate
-region_svalue::eval_condition (region_svalue *lhs,
-			       enum tree_code op,
-			       region_svalue *rhs)
-{
-  /* See if they point to the same region.  */
-  /* TODO: what about child regions where the child is the first child
-     (or descendent)?  */
-  region_id lhs_rid = lhs->get_pointee ();
-  region_id rhs_rid = rhs->get_pointee ();
-  switch (op)
-    {
-    default:
-      gcc_unreachable ();
-
-    case EQ_EXPR:
-      if (lhs_rid == rhs_rid)
-	return tristate::TS_TRUE;
-      else
-	return tristate::TS_FALSE;
-      break;
-
-    case NE_EXPR:
-      if (lhs_rid != rhs_rid)
-	return tristate::TS_TRUE;
-      else
-	return tristate::TS_FALSE;
-      break;
-
-    case GE_EXPR:
-    case LE_EXPR:
-      if (lhs_rid == rhs_rid)
-	return tristate::TS_TRUE;
-      break;
-
-    case GT_EXPR:
-    case LT_EXPR:
-      if (lhs_rid == rhs_rid)
-	return tristate::TS_FALSE;
-      break;
-    }
-
-  return tristate::TS_UNKNOWN;
-}
-
-/* class constant_svalue : public svalue.  */
-
-/* Compare the fields of this constant_svalue with OTHER, returning true
-   if they are equal.
-   For use by svalue::operator==.  */
-
-bool
-constant_svalue::compare_fields (const constant_svalue &other) const
-{
-  return m_cst_expr == other.m_cst_expr;
-}
-
-/* Implementation of svalue::add_to_hash vfunc for constant_svalue.  */
-
-void
-constant_svalue::add_to_hash (inchash::hash &hstate) const
-{
-  inchash::add_expr (m_cst_expr, hstate);
-}
-
-/* Merge the CST_SVAL_A and CST_SVAL_B using MERGER, writing the id of
-   the resulting svalue into *MERGED_SID.  */
-
-void
-constant_svalue::merge_values (const constant_svalue &cst_sval_a,
-			       const constant_svalue &cst_sval_b,
-			       svalue_id *merged_sid,
-			       model_merger *merger)
-{
-  tree cst_a = cst_sval_a.get_constant ();
-  tree cst_b = cst_sval_b.get_constant ();
-  svalue *merged_sval;
-  if (cst_a == cst_b)
-    {
-      /* If they are the same constant, merge as that constant value.  */
-      merged_sval = new constant_svalue (cst_a);
-    }
-  else
-    {
-      /* Otherwise, we have two different constant values.
-	 Merge as an unknown value.
-	 TODO: impose constraints on the value?
-	 (maybe just based on A, to avoid infinite chains)  */
-      merged_sval = new unknown_svalue (TREE_TYPE (cst_a));
-    }
-  *merged_sid = merger->m_merged_model->add_svalue (merged_sval);
-}
-
-/* Evaluate the condition LHS OP RHS.
-   Subroutine of region_model::eval_condition for when we have a pair of
-   constants.  */
-
-tristate
-constant_svalue::eval_condition (constant_svalue *lhs,
-				 enum tree_code op,
-				 constant_svalue *rhs)
-{
-  tree lhs_const = lhs->get_constant ();
-  tree rhs_const = rhs->get_constant ();
-
-  gcc_assert (CONSTANT_CLASS_P (lhs_const));
-  gcc_assert (CONSTANT_CLASS_P (rhs_const));
-
-  /* Check for comparable types.  */
-  if (types_compatible_p (TREE_TYPE (lhs_const), TREE_TYPE (rhs_const)))
-    {
-      tree comparison
-	= fold_binary (op, boolean_type_node, lhs_const, rhs_const);
-      if (comparison == boolean_true_node)
-	return tristate (tristate::TS_TRUE);
-      if (comparison == boolean_false_node)
-	return tristate (tristate::TS_FALSE);
-    }
-  return tristate::TS_UNKNOWN;
-}
-
-/* Implementation of svalue::print_details vfunc for constant_svalue.  */
-
-void
-constant_svalue::print_details (const region_model &model ATTRIBUTE_UNUSED,
-				svalue_id this_sid ATTRIBUTE_UNUSED,
-				pretty_printer *pp) const
-{
-  pp_printf (pp, "%qE", m_cst_expr);
-}
-
-/* Implementation of svalue::get_child_sid vfunc for constant_svalue.  */
-
-svalue_id
-constant_svalue::get_child_sid (region *parent ATTRIBUTE_UNUSED,
-				region *child,
-				region_model &model,
-				region_model_context *ctxt ATTRIBUTE_UNUSED)
-{
-  /* TODO: handle the all-zeroes case by returning an all-zeroes of the
-     child type.  */
-
-  /* Otherwise, we don't have a good way to get a child value out of a
-     constant.
-
-     Handle this case by using an unknown value.  */
-  svalue *unknown_sval = new unknown_svalue (child->get_type ());
-  return model.add_svalue (unknown_sval);
-}
-
-/* class unknown_svalue : public svalue.  */
-
-/* Compare the fields of this unknown_svalue with OTHER, returning true
-   if they are equal.
-   For use by svalue::operator==.  */
-
-bool
-unknown_svalue::compare_fields (const unknown_svalue &) const
-{
-  /* I *think* we want to return true here, in that when comparing
-     two region models, we want two peer unknown_svalue instances
-     to be the "same".  */
-  return true;
-}
-
-/* Implementation of svalue::add_to_hash vfunc for unknown_svalue.  */
-
-void
-unknown_svalue::add_to_hash (inchash::hash &) const
-{
-  /* Empty.  */
-}
-
-/* Implementation of svalue::print_details vfunc for unknown_svalue.  */
-
-void
-unknown_svalue::print_details (const region_model &model ATTRIBUTE_UNUSED,
-			       svalue_id this_sid ATTRIBUTE_UNUSED,
-			       pretty_printer *pp) const
-{
-  pp_string (pp, "unknown");
-}
-
 /* Get a string for KIND for use in debug dumps.  */
 
 const char *
@@ -795,8045 +153,16 @@ poison_kind_to_str (enum poison_kind kind)
     }
 }
 
-/* class poisoned_svalue : public svalue.  */
-
-/* Compare the fields of this poisoned_svalue with OTHER, returning true
-   if they are equal.
-   For use by svalue::operator==.  */
-
-bool
-poisoned_svalue::compare_fields (const poisoned_svalue &other) const
-{
-  return m_kind == other.m_kind;
-}
-
-/* Implementation of svalue::add_to_hash vfunc for poisoned_svalue.  */
-
-void
-poisoned_svalue::add_to_hash (inchash::hash &hstate) const
-{
-  hstate.add_int (m_kind);
-}
-
-/* Implementation of svalue::print_details vfunc for poisoned_svalue.  */
-
-void
-poisoned_svalue::print_details (const region_model &model ATTRIBUTE_UNUSED,
-				svalue_id this_sid ATTRIBUTE_UNUSED,
-				pretty_printer *pp) const
-{
-  pp_printf (pp, "poisoned: %s", poison_kind_to_str (m_kind));
-}
-
-/* class setjmp_svalue's implementation is in engine.cc, so that it can use
-   the declaration of exploded_node.  */
-
-/* class region and its various subclasses.  */
-
-/* Get a string for KIND for use in debug dumps.  */
-
-const char *
-region_kind_to_str (enum region_kind kind)
-{
-  switch (kind)
-    {
-    default:
-      gcc_unreachable ();
-    case RK_PRIMITIVE:
-      return "primitive";
-    case RK_STRUCT:
-      return "struct";
-    case RK_UNION:
-      return "union";
-    case RK_ARRAY:
-      return "array";
-    case RK_FRAME:
-      return "frame";
-    case RK_GLOBALS:
-      return "globals";
-    case RK_CODE:
-      return "code";
-    case RK_FUNCTION:
-      return "function";
-    case RK_STACK:
-      return "stack";
-    case RK_HEAP:
-      return "heap";
-    case RK_ROOT:
-      return "root";
-    case RK_SYMBOLIC:
-      return "symbolic";
-    }
-}
+#if CHECKING_P
 
-/* class region.  */
+namespace selftest {
 
-/* Equality operator for region.
-   After comparing base class fields and kind, the rest of the
-   comparison is handled off to a "compare_fields" member function
-   specific to the appropriate subclass.  */
-
-bool
-region::operator== (const region &other) const
-{
-  if (m_parent_rid != other.m_parent_rid)
-    return false;
-  if (m_sval_id != other.m_sval_id)
-    return false;
-  if (m_type != other.m_type)
-    return false;
-
-  enum region_kind this_kind = get_kind ();
-  enum region_kind other_kind = other.get_kind ();
-  if (this_kind != other_kind)
-    return false;
-
-  /* Compare views.  */
-  if (m_view_rids.length () != other.m_view_rids.length ())
-    return false;
-  int i;
-  region_id *rid;
-  FOR_EACH_VEC_ELT (m_view_rids, i, rid)
-    if (! (*rid == other.m_view_rids[i]))
-      return false;
-
-  switch (this_kind)
-    {
-    default:
-      gcc_unreachable ();
-    case RK_PRIMITIVE:
-      {
-#if 1
-	return true;
-#else
-	const primitive_region &this_sub
-	  = (const primitive_region &)*this;
-	const primitive_region &other_sub
-	  = (const primitive_region &)other;
-	return this_sub.compare_fields (other_sub);
-#endif
-      }
-    case RK_STRUCT:
-      {
-	const struct_region &this_sub
-	  = (const struct_region &)*this;
-	const struct_region &other_sub
-	  = (const struct_region &)other;
-	return this_sub.compare_fields (other_sub);
-      }
-    case RK_UNION:
-      {
-	const union_region &this_sub
-	  = (const union_region &)*this;
-	const union_region &other_sub
-	  = (const union_region &)other;
-	return this_sub.compare_fields (other_sub);
-      }
-    case RK_ARRAY:
-      {
-	const array_region &this_sub
-	  = (const array_region &)*this;
-	const array_region &other_sub
-	  = (const array_region &)other;
-	return this_sub.compare_fields (other_sub);
-      }
-    case RK_FRAME:
-      {
-	const frame_region &this_sub
-	  = (const frame_region &)*this;
-	const frame_region &other_sub
-	  = (const frame_region &)other;
-	return this_sub.compare_fields (other_sub);
-      }
-    case RK_GLOBALS:
-      {
-	const globals_region &this_sub
-	  = (const globals_region &)*this;
-	const globals_region &other_sub
-	  = (const globals_region &)other;
-	return this_sub.compare_fields (other_sub);
-      }
-    case RK_CODE:
-      {
-	const code_region &this_sub
-	  = (const code_region &)*this;
-	const code_region &other_sub
-	  = (const code_region &)other;
-	return this_sub.compare_fields (other_sub);
-      }
-    case RK_FUNCTION:
-      {
-	const function_region &this_sub
-	  = (const function_region &)*this;
-	const function_region &other_sub
-	  = (const function_region &)other;
-	return this_sub.compare_fields (other_sub);
-      }
-    case RK_STACK:
-      {
-	const stack_region &this_sub
-	  = (const stack_region &)*this;
-	const stack_region &other_sub
-	  = (const stack_region &)other;
-	return this_sub.compare_fields (other_sub);
-      }
-    case RK_ROOT:
-      {
-	const root_region &this_sub
-	  = (const root_region &)*this;
-	const root_region &other_sub
-	  = (const root_region &)other;
-	return this_sub.compare_fields (other_sub);
-      }
-    case RK_SYMBOLIC:
-      {
-	const symbolic_region &this_sub
-	  = (const symbolic_region &)*this;
-	const symbolic_region &other_sub
-	  = (const symbolic_region &)other;
-	return this_sub.compare_fields (other_sub);
-      }
-    case RK_HEAP:
-      {
-	const heap_region &this_sub
-	  = (const heap_region &)*this;
-	const heap_region &other_sub
-	  = (const heap_region &)other;
-	return this_sub.compare_fields (other_sub);
-      }
-    }
-}
-
-/* Get the parent region of this region.  */
-
-region *
-region::get_parent_region (const region_model &model) const
-{
-  return model.get_region (m_parent_rid);
-}
-
-/* Set this region's value to RHS_SID (or potentially a variant of it,
-   for some kinds of casts).  */
-
-void
-region::set_value (region_model &model, region_id this_rid, svalue_id rhs_sid,
-		   region_model_context *ctxt)
-{
-  /* Handle some kinds of casting.  */
-  if (m_type)
-    {
-      svalue *sval = model.get_svalue (rhs_sid);
-      if (sval->get_type ())
-	rhs_sid = model.maybe_cast (m_type, rhs_sid, ctxt);
-
-      sval = model.get_svalue (rhs_sid);
-      if (sval->get_type ())
-	gcc_assert (m_type == sval->get_type ());
-    }
-
-  m_sval_id = rhs_sid;
-
-  /* Update views.
-     If this is a view, it becomes its parent's active view.
-     If there was already an active views, invalidate its value; otherwise
-     if the parent itself had a value, invalidate it.
-     If it's not a view, then deactivate any view that is active on this
-     region.  */
-  {
-    if (m_is_view)
-      become_active_view (model, this_rid);
-    else
-      {
-	deactivate_any_active_view (model);
-	gcc_assert (m_active_view_rid.null_p ());
-      }
-  }
-}
-
-/* Make this region (with id THIS_RID) the "active" view of its parent.
-   Any other active view has its value set to "unknown" and descendent values
-   cleared.
-   If there wasn't an active view, then set the parent's value to unknown, and
-   clear its descendent values (apart from this view).  */
-
-void
-region::become_active_view (region_model &model, region_id this_rid)
-{
-  gcc_assert (m_is_view);
-
-  region *parent_reg = model.get_region (m_parent_rid);
-  gcc_assert (parent_reg);
-
-  region_id old_active_view_rid = parent_reg->m_active_view_rid;
-
-  if (old_active_view_rid == this_rid)
-    {
-      /* Already the active view: do nothing.  */
-      return;
-    }
-
-  /* We have a change of active view.  */
-  parent_reg->m_active_view_rid = this_rid;
-
-  if (old_active_view_rid.null_p ())
-    {
-      /* No previous active view, but the parent and its other children
-	 might have values.
-	 If so, invalidate those values - but not that of the new view.  */
-      region_id_set below_region (&model);
-      model.get_descendents (m_parent_rid, &below_region, this_rid);
-      for (unsigned i = 0; i < model.get_num_regions (); i++)
-	{
-	  region_id rid (region_id::from_int (i));
-	  if (below_region.region_p (rid))
-	    {
-	      region *other_reg = model.get_region (rid);
-	      other_reg->m_sval_id = svalue_id::null ();
-	    }
-	}
-      region *parent = model.get_region (m_parent_rid);
-      parent->m_sval_id
-	= model.add_svalue (new unknown_svalue (parent->get_type ()));
-    }
-  else
-    {
-      /* If there was an active view, invalidate it.  */
-      region *old_active_view = model.get_region (old_active_view_rid);
-      old_active_view->deactivate_view (model, old_active_view_rid);
-    }
-}
-
-/* If this region (with id THIS_RID) has an active view, deactivate it,
-   clearing m_active_view_rid.  */
-
-void
-region::deactivate_any_active_view (region_model &model)
-{
-  if (m_active_view_rid.null_p ())
-    return;
-  region *view = model.get_region (m_active_view_rid);
-  view->deactivate_view (model, m_active_view_rid);
-  m_active_view_rid = region_id::null ();
-}
-
-/* Clear any values for regions below THIS_RID.
-   Set the view's value to unknown.  */
-
-void
-region::deactivate_view (region_model &model, region_id this_view_rid)
-{
-  gcc_assert (is_view_p ());
-
-  /* Purge values from old_active_this_view_rid and all its
-     descendents.  Potentially we could use a poison value
-     for this, but let's use unknown for now.  */
-  region_id_set below_view (&model);
-  model.get_descendents (this_view_rid, &below_view, region_id::null ());
-
-  for (unsigned i = 0; i < model.get_num_regions (); i++)
-    {
-      region_id rid (region_id::from_int (i));
-      if (below_view.region_p (rid))
-	{
-	  region *other_reg = model.get_region (rid);
-	  other_reg->m_sval_id = svalue_id::null ();
-	}
-    }
-
-  m_sval_id = model.add_svalue (new unknown_svalue (get_type ()));
-}
-
-/* Get a value for this region, either its value if it has one,
-   or, failing that, "inherit" a value from first ancestor with a
-   non-null value.
-
-   For example, when getting the value for a local variable within
-   a stack frame that doesn't have one, the frame doesn't have a value
-   either, but the stack as a whole will have an "uninitialized" poison
-   value, so inherit that.  */
-
-svalue_id
-region::get_value (region_model &model, bool non_null,
-		   region_model_context *ctxt)
-{
-  /* If this region has a value, use it. */
-  if (!m_sval_id.null_p ())
-    return m_sval_id;
-
-  /* Otherwise, "inherit" value from first ancestor with a
-     non-null value. */
-
-  region *parent = model.get_region (m_parent_rid);
-  if (parent)
-    {
-      svalue_id inherited_sid
-	= parent->get_inherited_child_sid (this, model, ctxt);
-      if (!inherited_sid.null_p ())
-	return inherited_sid;
-    }
-
-  /* If a non-null value has been requested, then generate
-     a new unknown value.  Store it, so that repeated reads from this
-     region will yield the same unknown value.  */
-  if (non_null)
-    {
-      svalue_id unknown_sid = model.add_svalue (new unknown_svalue (m_type));
-      m_sval_id = unknown_sid;
-      return unknown_sid;
-    }
-
-  return svalue_id::null ();
-}
-
-/* Get a value for CHILD, inheriting from this region.
-
-   Recurse, so this region will inherit a value if it doesn't already
-   have one.  */
-
-svalue_id
-region::get_inherited_child_sid (region *child,
-				 region_model &model,
-				 region_model_context *ctxt)
-{
-  if (m_sval_id.null_p ())
-    {
-      /* Recurse.  */
-      if (!m_parent_rid.null_p ())
-	{
-	  region *parent = model.get_region (m_parent_rid);
-	  m_sval_id = parent->get_inherited_child_sid (this, model, ctxt);
-	}
-    }
-
-  if (!m_sval_id.null_p ())
-    {
-      /* Clone the parent's value, so that attempts to update it
-	 (e.g giving a specific value to an inherited "uninitialized"
-	 value) touch the child, and not the parent.  */
-      svalue *this_value = model.get_svalue (m_sval_id);
-      svalue_id new_child_sid
-	= this_value->get_child_sid (this, child, model, ctxt);
-      if (ctxt)
-	ctxt->on_inherited_svalue (m_sval_id, new_child_sid);
-      child->m_sval_id = new_child_sid;
-      return new_child_sid;
-    }
-
-  return svalue_id::null ();
-}
-
-/* Copy from SRC_RID to DST_RID, using CTXT for any issues that occur.
-   Copy across any value for the region, and handle structs, unions
-   and arrays recursively.  */
-
-void
-region_model::copy_region (region_id dst_rid, region_id src_rid,
-			   region_model_context *ctxt)
-{
-  gcc_assert (!dst_rid.null_p ());
-  gcc_assert (!src_rid.null_p ());
-  if (dst_rid == src_rid)
-    return;
-  region *dst_reg = get_region (dst_rid);
-  region *src_reg = get_region (src_rid);
-
-  /* Copy across any value for the src region itself.  */
-  svalue_id sid = src_reg->get_value (*this, true, ctxt);
-  set_value (dst_rid, sid, ctxt);
-
-  if (dst_reg->get_kind () != src_reg->get_kind ())
-    return;
-
-  /* Copy across child regions for structs, unions, and arrays.  */
-  switch (dst_reg->get_kind ())
-    {
-    case RK_PRIMITIVE:
-      return;
-    case RK_STRUCT:
-      {
-	struct_region *dst_sub = as_a <struct_region *> (dst_reg);
-	struct_region *src_sub = as_a <struct_region *> (src_reg);
-	copy_struct_region (dst_rid, dst_sub, src_sub, ctxt);
-      }
-      return;
-    case RK_UNION:
-      {
-	union_region *src_sub = as_a <union_region *> (src_reg);
-	copy_union_region (dst_rid, src_sub, ctxt);
-      }
-      return;
-    case RK_FRAME:
-    case RK_GLOBALS:
-    case RK_CODE:
-    case RK_FUNCTION:
-      return;
-    case RK_ARRAY:
-      {
-	array_region *dst_sub = as_a <array_region *> (dst_reg);
-	array_region *src_sub = as_a <array_region *> (src_reg);
-	copy_array_region (dst_rid, dst_sub, src_sub, ctxt);
-      }
-      return;
-    case RK_STACK:
-    case RK_HEAP:
-    case RK_ROOT:
-    case RK_SYMBOLIC:
-      return;
-    }
-}
-
-/* Subroutine of region_model::copy_region for copying the child
-   regions for a struct.  */
-
-void
-region_model::copy_struct_region (region_id dst_rid,
-				  struct_region *dst_reg,
-				  struct_region *src_reg,
-				  region_model_context *ctxt)
-{
-  for (map_region::iterator_t iter = src_reg->begin ();
-       iter != src_reg->end (); ++iter)
-    {
-      tree src_key = (*iter).first;
-      region_id src_field_rid = (*iter).second;
-      region *src_field_reg = get_region (src_field_rid);
-      region_id dst_field_rid
-	= dst_reg->get_or_create (this, dst_rid, src_key,
-				  src_field_reg->get_type (), ctxt);
-      copy_region (dst_field_rid, src_field_rid, ctxt);
-    }
-}
-
-/* Subroutine of region_model::copy_region for copying the active
-   child region for a union.  */
-
-void
-region_model::copy_union_region (region_id dst_rid,
-				 union_region *src_reg,
-				 region_model_context *ctxt)
-{
-  region_id src_active_view_rid = src_reg->get_active_view ();
-  if (src_active_view_rid.null_p ())
-    return;
-  region *src_active_view = get_region (src_active_view_rid);
-  tree type = src_active_view->get_type ();
-  region_id dst_active_view_rid = get_or_create_view (dst_rid, type, ctxt);
-  copy_region (dst_active_view_rid, src_active_view_rid, ctxt);
-}
-
-/* Subroutine of region_model::copy_region for copying the child
-   regions for an array.  */
-
-void
-region_model::copy_array_region (region_id dst_rid,
-				 array_region *dst_reg,
-				 array_region *src_reg,
-				 region_model_context *ctxt)
-{
-  for (array_region::iterator_t iter = src_reg->begin ();
-       iter != src_reg->end (); ++iter)
-    {
-      array_region::key_t src_key = (*iter).first;
-      region_id src_field_rid = (*iter).second;
-      region *src_field_reg = get_region (src_field_rid);
-      region_id dst_field_rid
-	= dst_reg->get_or_create (this, dst_rid, src_key,
-				  src_field_reg->get_type (), ctxt);
-      copy_region (dst_field_rid, src_field_rid, ctxt);
-    }
-}
-
-/* Generate a hash value for this region.  The work is done by the
-   add_to_hash vfunc.  */
-
-hashval_t
-region::hash () const
-{
-  inchash::hash hstate;
-  add_to_hash (hstate);
-  return hstate.end ();
-}
-
-/* Print a one-liner representation of this region to PP, assuming
-   that this region is within MODEL and its id is THIS_RID.  */
-
-void
-region::print (const region_model &model,
-	       region_id this_rid,
-	       pretty_printer *pp) const
-{
-  this_rid.print (pp);
-  pp_string (pp, ": {");
-
-  /* vfunc.  */
-  print_fields (model, this_rid, pp);
-
-  pp_string (pp, "}");
-}
-
-/* Base class implementation of region::dump_dot_to_pp vfunc.  */
-
-void
-region::dump_dot_to_pp (const region_model &model,
-			region_id this_rid,
-			pretty_printer *pp) const
-{
-  this_rid.dump_node_name_to_pp (pp);
-  pp_printf (pp, " [shape=none,margin=0,style=filled,fillcolor=%s,label=\"",
-	     "lightgrey");
-  pp_write_text_to_stream (pp);
-  print (model, this_rid, pp);
-  pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
-  pp_string (pp, "\"];");
-  pp_newline (pp);
-
-  /* Add edge to svalue.  */
-  if (!m_sval_id.null_p ())
-    {
-      this_rid.dump_node_name_to_pp (pp);
-      pp_string (pp, " -> ");
-      m_sval_id.dump_node_name_to_pp (pp);
-      pp_string (pp, ";");
-      pp_newline (pp);
-    }
-
-  /* Add edge to parent.  */
-  if (!m_parent_rid.null_p ())
-    {
-      this_rid.dump_node_name_to_pp (pp);
-      pp_string (pp, " -> ");
-      m_parent_rid.dump_node_name_to_pp (pp);
-      pp_string (pp, ";");
-      pp_newline (pp);
-    }
-}
-
-/* Dump a tree-like ASCII-art representation of this region to PP.  */
-
-void
-region::dump_to_pp (const region_model &model,
-		    region_id this_rid,
-		    pretty_printer *pp,
-		    const char *prefix,
-		    bool is_last_child) const
-{
-  print (model, this_rid, pp);
-  pp_newline (pp);
-
-  const char *new_prefix;
-  if (!m_parent_rid.null_p ())
-    new_prefix = ACONCAT ((prefix, is_last_child ? "  " : "|  ", NULL));
-  else
-    new_prefix = prefix;
-
-  const char *begin_color = colorize_start (pp_show_color (pp), "note");
-  const char *end_color = colorize_stop (pp_show_color (pp));
-  char *field_prefix
-    = ACONCAT ((begin_color, new_prefix, "|:", end_color, NULL));
-
-  if (!m_sval_id.null_p ())
-    {
-      pp_printf (pp, "%s sval: ", field_prefix);
-      model.get_svalue (m_sval_id)->print (model, m_sval_id, pp);
-      pp_newline (pp);
-    }
-  if (m_type)
-    {
-      pp_printf (pp, "%s type: ", field_prefix);
-      print_quoted_type (pp, m_type);
-      pp_newline (pp);
-    }
-
-  /* Find the children.  */
-
-  auto_vec<region_id> child_rids;
-  unsigned i;
-  for (unsigned i = 0; i < model.get_num_regions (); ++i)
-    {
-      region_id rid = region_id::from_int (i);
-      region *child = model.get_region (rid);
-      if (child->m_parent_rid == this_rid)
-	child_rids.safe_push (rid);
-    }
-
-  /* Print the children, using dump_child_label to label them.  */
-
-  region_id *child_rid;
-  FOR_EACH_VEC_ELT (child_rids, i, child_rid)
-    {
-      is_last_child = (i == child_rids.length () - 1);
-      if (!this_rid.null_p ())
-	{
-	  const char *tail = is_last_child ? "`-" : "|-";
-	  pp_printf (pp, "%r%s%s%R", "note", new_prefix, tail);
-	}
-      dump_child_label (model, this_rid, *child_rid, pp);
-      model.get_region (*child_rid)->dump_to_pp (model, *child_rid, pp,
-						 new_prefix,
-						 is_last_child);
-    }
-}
-
-/* Base implementation of region::dump_child_label vfunc.  */
-
-void
-region::dump_child_label (const region_model &model,
-			  region_id this_rid ATTRIBUTE_UNUSED,
-			  region_id child_rid,
-			  pretty_printer *pp) const
-{
-  region *child = model.get_region (child_rid);
-  if (child->m_is_view)
-    {
-      gcc_assert (TYPE_P (child->get_type ()));
-      if (m_active_view_rid == child_rid)
-	pp_string (pp, "active ");
-      else
-	pp_string (pp, "inactive ");
-      pp_string (pp, "view as ");
-      print_quoted_type (pp, child->get_type ());
-      pp_string (pp, ": ");
-    }
-}
-
-/* Base implementation of region::validate vfunc.
-   Assert that the fields of "region" are valid; subclasses should
-   chain up their implementation to this one.  */
-
-void
-region::validate (const region_model &model) const
-{
-  m_parent_rid.validate (model);
-  m_sval_id.validate (model);
-  unsigned i;
-  region_id *view_rid;
-  FOR_EACH_VEC_ELT (m_view_rids, i, view_rid)
-    {
-      gcc_assert (!view_rid->null_p ());
-      view_rid->validate (model);
-    }
-  m_active_view_rid.validate (model);
-}
-
-/* Apply MAP to svalue_ids to this region.  This updates the value
-   for the region (if any).  */
-
-void
-region::remap_svalue_ids (const svalue_id_map &map)
-{
-  map.update (&m_sval_id);
-}
-
-/* Base implementation of region::remap_region_ids vfunc; subclasses should
-   chain up to this, updating any region_id data.  */
-
-void
-region::remap_region_ids (const region_id_map &map)
-{
-  map.update (&m_parent_rid);
-  unsigned i;
-  region_id *view_rid;
-  FOR_EACH_VEC_ELT (m_view_rids, i, view_rid)
-    map.update (view_rid);
-  map.update (&m_active_view_rid);
-}
-
-/* Add a new region with id VIEW_RID as a view of this region.  */
-
-void
-region::add_view (region_id view_rid, region_model *model)
-{
-  gcc_assert (!view_rid.null_p ());
-  region *new_view = model->get_region (view_rid);
-  new_view->m_is_view = true;
-  gcc_assert (!new_view->m_parent_rid.null_p ());
-  gcc_assert (new_view->m_sval_id.null_p ());
-
-  //gcc_assert (new_view->get_type () != NULL_TREE);
-  // TODO: this can sometimes be NULL, when viewing through a (void *)
-
-  // TODO: the type ought to not be present yet
-
-  m_view_rids.safe_push (view_rid);
-}
-
-/* Look for a view of type TYPE of this region, returning its id if found,
-   or null otherwise.  */
-
-region_id
-region::get_view (tree type, region_model *model) const
-{
-  unsigned i;
-  region_id *view_rid;
-  FOR_EACH_VEC_ELT (m_view_rids, i, view_rid)
-    {
-      region *view = model->get_region (*view_rid);
-      gcc_assert (view->m_is_view);
-      if (view->get_type () == type)
-	return *view_rid;
-    }
-  return region_id::null ();
-}
-
-/* region's ctor.  */
-
-region::region (region_id parent_rid, svalue_id sval_id, tree type)
-: m_parent_rid (parent_rid), m_sval_id (sval_id), m_type (type),
-  m_view_rids (), m_is_view (false), m_active_view_rid (region_id::null ())
-{
-  gcc_assert (type == NULL_TREE || TYPE_P (type));
-}
-
-/* region's copy ctor.  */
-
-region::region (const region &other)
-: m_parent_rid (other.m_parent_rid), m_sval_id (other.m_sval_id),
-  m_type (other.m_type), m_view_rids (other.m_view_rids.length ()),
-  m_is_view (other.m_is_view), m_active_view_rid (other.m_active_view_rid)
-{
-  int i;
-  region_id *rid;
-  FOR_EACH_VEC_ELT (other.m_view_rids, i, rid)
-    m_view_rids.quick_push (*rid);
-}
-
-/* Base implementation of region::add_to_hash vfunc; subclasses should
-   chain up to this.  */
-
-void
-region::add_to_hash (inchash::hash &hstate) const
-{
-  inchash::add (m_parent_rid, hstate);
-  inchash::add (m_sval_id, hstate);
-  hstate.add_ptr (m_type);
-  // TODO: views
-}
-
-/* Base implementation of region::print_fields vfunc.  */
-
-void
-region::print_fields (const region_model &model ATTRIBUTE_UNUSED,
-		      region_id this_rid ATTRIBUTE_UNUSED,
-		      pretty_printer *pp) const
-{
-  pp_printf (pp, "kind: %qs", region_kind_to_str (get_kind ()));
-
-  pp_string (pp, ", parent: ");
-  m_parent_rid.print (pp);
-
-  pp_printf (pp, ", sval: ");
-  m_sval_id.print (pp);
-
-  if (m_type)
-    {
-      pp_printf (pp, ", type: ");
-      print_quoted_type (pp, m_type);
-    }
-}
-
-/* Determine if a pointer to this region must be non-NULL.
-
-   Generally, pointers to regions must be non-NULL, but pointers
-   to symbolic_regions might, in fact, be NULL.
-
-   This allows us to simulate functions like malloc and calloc with:
-   - only one "outcome" from each statement,
-   - the idea that the pointer is on the heap if non-NULL
-   - the possibility that the pointer could be NULL
-   - the idea that successive values returned from malloc are non-equal
-   - to be able to zero-fill for calloc.  */
-
-bool
-region::non_null_p (const region_model &model) const
-{
-  /* Look through views to get at the underlying region.  */
-  if (is_view_p ())
-    return model.get_region (m_parent_rid)->non_null_p (model);
-
-  /* Are we within a symbolic_region?  If so, it could be NULL.  */
-  if (const symbolic_region *sym_reg = dyn_cast_symbolic_region ())
-    {
-      if (sym_reg->m_possibly_null)
-	return false;
-    }
-
-  return true;
-}
-
-/* class primitive_region : public region.  */
-
-/* Implementation of region::clone vfunc for primitive_region.  */
-
-region *
-primitive_region::clone () const
-{
-  return new primitive_region (*this);
-}
-
-/* Implementation of region::walk_for_canonicalization vfunc for
-   primitive_region.  */
-
-void
-primitive_region::walk_for_canonicalization (canonicalization *) const
-{
-  /* Empty.  */
-}
-
-/* class map_region : public region.  */
-
-/* map_region's copy ctor.  */
-
-map_region::map_region (const map_region &other)
-: region (other),
-  m_map (other.m_map)
-{
-}
-
-/* Compare the fields of this map_region with OTHER, returning true
-   if they are equal.
-   For use by region::operator==.  */
-
-bool
-map_region::compare_fields (const map_region &other) const
-{
-  if (m_map.elements () != other.m_map.elements ())
-    return false;
-
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      tree key = (*iter).first;
-      region_id e = (*iter).second;
-      region_id *other_slot = const_cast <map_t &> (other.m_map).get (key);
-      if (other_slot == NULL)
-	return false;
-      if (e != *other_slot)
-	return false;
-    }
-  return true;
-}
-
-/* Implementation of region::print_fields vfunc for map_region.  */
-
-void
-map_region::print_fields (const region_model &model,
-			  region_id this_rid,
-			  pretty_printer *pp) const
-{
-  region::print_fields (model, this_rid, pp);
-  pp_string (pp, ", map: {");
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      if (iter != m_map.begin ())
-	pp_string (pp, ", ");
-      tree expr = (*iter).first;
-      region_id child_rid = (*iter).second;
-      dump_quoted_tree (pp, expr);
-      pp_string (pp, ": ");
-      child_rid.print (pp);
-    }
-  pp_string (pp, "}");
-}
-
-/* Implementation of region::validate vfunc for map_region.  */
-
-void
-map_region::validate (const region_model &model) const
-{
-  region::validate (model);
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      region_id child_rid = (*iter).second;
-      child_rid.validate (model);
-    }
-}
-
-/* Implementation of region::dump_dot_to_pp vfunc for map_region.  */
-
-void
-map_region::dump_dot_to_pp (const region_model &model,
-			    region_id this_rid,
-			    pretty_printer *pp) const
-{
-  region::dump_dot_to_pp (model, this_rid, pp);
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      // TODO: add nodes/edges to label things
-
-      tree expr = (*iter).first;
-      region_id child_rid = (*iter).second;
-
-      pp_printf (pp, "rid_label_%i [label=\"", child_rid.as_int ());
-      pp_write_text_to_stream (pp);
-      pp_printf (pp, "%qE", expr);
-      pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
-      pp_string (pp, "\"];");
-      pp_newline (pp);
-
-      pp_printf (pp, "rid_label_%i", child_rid.as_int ());
-      pp_string (pp, " -> ");
-      child_rid.dump_node_name_to_pp (pp);
-      pp_string (pp, ";");
-      pp_newline (pp);
-    }
-}
-
-/* Implementation of region::dump_child_label vfunc for map_region.  */
-
-void
-map_region::dump_child_label (const region_model &model,
-			      region_id this_rid,
-			      region_id child_rid,
-			      pretty_printer *pp) const
-{
-  region::dump_child_label (model, this_rid, child_rid, pp);
-
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      if (child_rid == (*iter).second)
-	{
-	  tree key = (*iter).first;
-	  dump_quoted_tree (pp, key);
-	  pp_string (pp, ": ");
-	}
-    }
-}
-
-/* Look for a child region for KEY within this map_region.
-   If it doesn't already exist, create a child map_region, using TYPE for
-   its type.
-   Return the region_id of the child (whether pre-existing, or
-   newly-created).
-   Notify CTXT if we don't know how to handle TYPE.  */
-
-region_id
-map_region::get_or_create (region_model *model,
-			   region_id this_rid,
-			   tree key,
-			   tree type,
-			   region_model_context *ctxt)
-{
-  gcc_assert (key);
-  gcc_assert (valid_key_p (key));
-  region_id *slot = m_map.get (key);
-  if (slot)
-    return *slot;
-  region_id child_rid = model->add_region_for_type (this_rid, type, ctxt);
-  m_map.put (key, child_rid);
-  return child_rid;
-}
-
-/* Get the region_id for the child region for KEY within this
-   MAP_REGION, or NULL if there is no such child region.  */
-
-region_id *
-map_region::get (tree key)
-{
-  gcc_assert (key);
-  gcc_assert (valid_key_p (key));
-  region_id *slot = m_map.get (key);
-  return slot;
-}
-
-/* Implementation of region::add_to_hash vfunc for map_region.  */
-
-void
-map_region::add_to_hash (inchash::hash &hstate) const
-{
-  region::add_to_hash (hstate);
-  // TODO
-}
-
-/* Implementation of region::remap_region_ids vfunc for map_region.  */
-
-void
-map_region::remap_region_ids (const region_id_map &map)
-{
-  region::remap_region_ids (map);
-
-  /* Remap the region ids within the map entries.  */
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end (); ++iter)
-    map.update (&(*iter).second);
-}
-
-/* Remove the binding of KEY to its child region (but not the
-   child region itself).
-   For use when purging unneeded SSA names.  */
-
-void
-map_region::unbind (tree key)
-{
-  gcc_assert (key);
-  gcc_assert (valid_key_p (key));
-  m_map.remove (key);
-}
-
-/* Look for a child region with id CHILD_RID within this map_region.
-   If one is found, return its tree key, otherwise return NULL_TREE.  */
-
-tree
-map_region::get_tree_for_child_region (region_id child_rid) const
-{
-  // TODO: do we want to store an inverse map?
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      tree key = (*iter).first;
-      region_id r = (*iter).second;
-      if (r == child_rid)
-	return key;
-    }
-
-  return NULL_TREE;
-}
-
-/* Look for a child region CHILD within this map_region.
-   If one is found, return its tree key, otherwise return NULL_TREE.  */
-
-tree
-map_region::get_tree_for_child_region (region *child,
-				       const region_model &model) const
-{
-  // TODO: do we want to store an inverse map?
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      tree key = (*iter).first;
-      region_id r = (*iter).second;
-      if (model.get_region (r) == child)
-	return key;
-    }
-
-  return NULL_TREE;
-}
-
-/* Comparator for trees to impose a deterministic ordering on
-   T1 and T2.  */
-
-static int
-tree_cmp (const_tree t1, const_tree t2)
-{
-  gcc_assert (t1);
-  gcc_assert (t2);
-
-  /* Test tree codes first.  */
-  if (TREE_CODE (t1) != TREE_CODE (t2))
-    return TREE_CODE (t1) - TREE_CODE (t2);
-
-  /* From this point on, we know T1 and T2 have the same tree code.  */
-
-  if (DECL_P (t1))
-    {
-      if (DECL_NAME (t1) && DECL_NAME (t2))
-	return strcmp (IDENTIFIER_POINTER (DECL_NAME (t1)),
-		       IDENTIFIER_POINTER (DECL_NAME (t2)));
-      else
-	{
-	  if (DECL_NAME (t1))
-	    return -1;
-	  else if (DECL_NAME (t2))
-	    return 1;
-	  else
-	    return DECL_UID (t1) - DECL_UID (t2);
-	}
-    }
-
-  switch (TREE_CODE (t1))
-    {
-    case SSA_NAME:
-      {
-	if (SSA_NAME_VAR (t1) && SSA_NAME_VAR (t2))
-	  {
-	    int var_cmp = tree_cmp (SSA_NAME_VAR (t1), SSA_NAME_VAR (t2));
-	    if (var_cmp)
-	      return var_cmp;
-	    return SSA_NAME_VERSION (t1) - SSA_NAME_VERSION (t2);
-	  }
-	else
-	  {
-	    if (SSA_NAME_VAR (t1))
-	      return -1;
-	    else if (SSA_NAME_VAR (t2))
-	      return 1;
-	    else
-	      return SSA_NAME_VERSION (t1) - SSA_NAME_VERSION (t2);
-	  }
-      }
-      break;
-
-    case INTEGER_CST:
-      return tree_int_cst_compare (t1, t2);
-
-    case REAL_CST:
-      {
-	const real_value *rv1 = TREE_REAL_CST_PTR (t1);
-	const real_value *rv2 = TREE_REAL_CST_PTR (t2);
-	if (real_compare (UNORDERED_EXPR, rv1, rv2))
-	  {
-	    /* Impose an arbitrary order on NaNs relative to other NaNs
-	       and to non-NaNs.  */
-	    if (int cmp_isnan = real_isnan (rv1) - real_isnan (rv2))
-	      return cmp_isnan;
-	    if (int cmp_issignaling_nan
-		  = real_issignaling_nan (rv1) - real_issignaling_nan (rv2))
-	      return cmp_issignaling_nan;
-	    return real_isneg (rv1) - real_isneg (rv2);
-	  }
-	if (real_compare (LT_EXPR, rv1, rv2))
-	  return -1;
-	if (real_compare (GT_EXPR, rv1, rv2))
-	  return 1;
-	return 0;
-      }
-
-    case STRING_CST:
-      return strcmp (TREE_STRING_POINTER (t1),
-		     TREE_STRING_POINTER (t2));
-
-    default:
-      gcc_unreachable ();
-      break;
-    }
-
-  gcc_unreachable ();
-
-  return 0;
-}
-
-/* qsort comparator for trees to impose a deterministic ordering on
-   P1 and P2.  */
-
-static int
-tree_cmp (const void *p1, const void *p2)
-{
-  const_tree t1 = *(const_tree const *)p1;
-  const_tree t2 = *(const_tree const *)p2;
-
-  return tree_cmp (t1, t2);
-}
-
-/* Attempt to merge MAP_REGION_A and MAP_REGION_B into MERGED_MAP_REGION,
-   which has region_id MERGED_RID, using MERGER.
-   Return true if the merger is possible, false otherwise.  */
-
-bool
-map_region::can_merge_p (const map_region *map_region_a,
-			 const map_region *map_region_b,
-			 map_region *merged_map_region,
-			 region_id merged_rid,
-			 model_merger *merger)
-{
-  for (map_t::iterator iter = map_region_a->m_map.begin ();
-       iter != map_region_a->m_map.end ();
-       ++iter)
-    {
-      tree key_a = (*iter).first;
-      region_id rid_a = (*iter).second;
-
-      if (const region_id *slot_b
-	  = const_cast<map_region *>(map_region_b)->m_map.get (key_a))
-	{
-	  region_id rid_b = *slot_b;
-
-	  region *child_region_a = merger->get_region_a <region> (rid_a);
-	  region *child_region_b = merger->get_region_b <region> (rid_b);
-
-	  gcc_assert (child_region_a->get_type ()
-		      == child_region_b->get_type ());
-
-	  gcc_assert (child_region_a->get_kind ()
-		      == child_region_b->get_kind ());
-
-	  region_id child_merged_rid
-	    = merged_map_region->get_or_create (merger->m_merged_model,
-						merged_rid,
-						key_a,
-						child_region_a->get_type (),
-						NULL);
-
-	  region *child_merged_region
-	    = merger->m_merged_model->get_region (child_merged_rid);
-
-	  /* Consider values.  */
-	  svalue_id child_a_sid = child_region_a->get_value_direct ();
-	  svalue_id child_b_sid = child_region_b->get_value_direct ();
-	  svalue_id child_merged_sid;
-	  if (!merger->can_merge_values_p (child_a_sid, child_b_sid,
-					   &child_merged_sid))
-	    return false;
-	  if (!child_merged_sid.null_p ())
-	    child_merged_region->set_value (*merger->m_merged_model,
-					    child_merged_rid,
-					    child_merged_sid,
-					    NULL);
-
-	  if (map_region *map_region_a = child_region_a->dyn_cast_map_region ())
-	    {
-	      /* Recurse.  */
-	      if (!can_merge_p (map_region_a,
-				as_a <map_region *> (child_region_b),
-				as_a <map_region *> (child_merged_region),
-				child_merged_rid,
-				merger))
-		return false;
-	    }
-
-	}
-      else
-	{
-	  /* TODO: region is present in A, but absent in B.  */
-	}
-    }
-
-  /* TODO: check for keys in B that aren't in A.  */
-
-  return true;
-}
-
-
-/* Implementation of region::walk_for_canonicalization vfunc for
-   map_region.  */
-
-void
-map_region::walk_for_canonicalization (canonicalization *c) const
-{
-  auto_vec<tree> keys (m_map.elements ());
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      tree key_a = (*iter).first;
-      keys.quick_push (key_a);
-    }
-  keys.qsort (tree_cmp);
-
-  unsigned i;
-  tree key;
-  FOR_EACH_VEC_ELT (keys, i, key)
-    {
-      region_id rid = *const_cast<map_region *>(this)->m_map.get (key);
-      c->walk_rid (rid);
-    }
-}
-
-/* For debugging purposes: look for a child region for a decl named
-   IDENTIFIER (or an SSA_NAME for such a decl), returning its value,
-   or svalue_id::null if none are found.  */
-
-svalue_id
-map_region::get_value_by_name (tree identifier,
-			       const region_model &model) const
-{
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      tree key = (*iter).first;
-      if (TREE_CODE (key) == SSA_NAME)
-	if (SSA_NAME_VAR (key))
-	  key = SSA_NAME_VAR (key);
-      if (DECL_P (key))
-	if (DECL_NAME (key) == identifier)
-	  {
-	    region_id rid = (*iter).second;
-	    region *region = model.get_region (rid);
-	    return region->get_value (const_cast<region_model &>(model),
-				      false, NULL);
-	  }
-    }
-  return svalue_id::null ();
-}
-
-/* class struct_or_union_region : public map_region.  */
-
-/* Implementation of map_region::valid_key_p vfunc for
-   struct_or_union_region.  */
-
-bool
-struct_or_union_region::valid_key_p (tree key) const
-{
-  return TREE_CODE (key) == FIELD_DECL;
-}
-
-/* Compare the fields of this struct_or_union_region with OTHER, returning
-   true if they are equal.
-   For use by region::operator==.  */
-
-bool
-struct_or_union_region::compare_fields (const struct_or_union_region &other)
-  const
-{
-  return map_region::compare_fields (other);
-}
-
-/* class struct_region : public struct_or_union_region.  */
-
-/* Implementation of region::clone vfunc for struct_region.  */
-
-region *
-struct_region::clone () const
-{
-  return new struct_region (*this);
-}
-
-/* Compare the fields of this struct_region with OTHER, returning true
-   if they are equal.
-   For use by region::operator==.  */
-
-bool
-struct_region::compare_fields (const struct_region &other) const
-{
-  return struct_or_union_region::compare_fields (other);
-}
-
-/* class union_region : public struct_or_union_region.  */
-
-/* Implementation of region::clone vfunc for union_region.  */
-
-region *
-union_region::clone () const
-{
-  return new union_region (*this);
-}
-
-/* Compare the fields of this union_region with OTHER, returning true
-   if they are equal.
-   For use by region::operator==.  */
-
-bool
-union_region::compare_fields (const union_region &other) const
-{
-  return struct_or_union_region::compare_fields (other);
-}
-
-/* class frame_region : public map_region.  */
-
-/* Compare the fields of this frame_region with OTHER, returning true
-   if they are equal.
-   For use by region::operator==.  */
-
-bool
-frame_region::compare_fields (const frame_region &other) const
-{
-  if (!map_region::compare_fields (other))
-    return false;
-  if (m_fun != other.m_fun)
-    return false;
-  if (m_depth != other.m_depth)
-    return false;
-  return true;
-}
-
-/* Implementation of region::clone vfunc for frame_region.  */
-
-region *
-frame_region::clone () const
-{
-  return new frame_region (*this);
-}
-
-/* Implementation of map_region::valid_key_p vfunc for frame_region.  */
-
-bool
-frame_region::valid_key_p (tree key) const
-{
-  // TODO: could also check that VAR_DECLs are locals
-  return (TREE_CODE (key) == PARM_DECL
-	  || TREE_CODE (key) == VAR_DECL
-	  || TREE_CODE (key) == SSA_NAME
-	  || TREE_CODE (key) == RESULT_DECL);
-}
-
-/* Implementation of region::print_fields vfunc for frame_region.  */
-
-void
-frame_region::print_fields (const region_model &model,
-			    region_id this_rid,
-			    pretty_printer *pp) const
-{
-  map_region::print_fields (model, this_rid, pp);
-  pp_printf (pp, ", function: %qs, depth: %i", function_name (m_fun), m_depth);
-}
-
-/* Implementation of region::add_to_hash vfunc for frame_region.  */
-
-void
-frame_region::add_to_hash (inchash::hash &hstate) const
-{
-  map_region::add_to_hash (hstate);
-  hstate.add_ptr (m_fun);
-  hstate.add_int (m_depth);
-}
-
-/* class globals_region : public scope_region.  */
-
-/* Compare the fields of this globals_region with OTHER, returning true
-   if they are equal.
-   For use by region::operator==.  */
-
-bool
-globals_region::compare_fields (const globals_region &other) const
-{
-  return map_region::compare_fields (other);
-}
-
-/* Implementation of region::clone vfunc for globals_region.  */
-
-region *
-globals_region::clone () const
-{
-  return new globals_region (*this);
-}
-
-/* Implementation of map_region::valid_key_p vfunc for globals_region.  */
-
-bool
-globals_region::valid_key_p (tree key) const
-{
-  return TREE_CODE (key) == VAR_DECL;
-}
-
-/* class code_region : public map_region.  */
-
-/* Compare the fields of this code_region with OTHER, returning true
-   if they are equal.
-   For use by region::operator==.  */
-
-bool
-code_region::compare_fields (const code_region &other) const
-{
-  return map_region::compare_fields (other);
-}
-
-/* Implementation of region::clone vfunc for code_region.  */
-
-region *
-code_region::clone () const
-{
-  return new code_region (*this);
-}
-
-/* Implementation of map_region::valid_key_p vfunc for code_region.  */
-
-bool
-code_region::valid_key_p (tree key) const
-{
-  return TREE_CODE (key) == FUNCTION_DECL;
-}
-
-/* class array_region : public region.  */
-
-/* array_region's copy ctor.  */
-
-array_region::array_region (const array_region &other)
-: region (other),
-  m_map (other.m_map)
-{
-}
-
-/* Get a child region for the element with index INDEX_SID.  */
-
-region_id
-array_region::get_element (region_model *model,
-			   region_id this_rid,
-			   svalue_id index_sid,
-			   region_model_context *ctxt)
-{
-  tree element_type = TREE_TYPE (get_type ());
-  svalue *index_sval = model->get_svalue (index_sid);
-  if (tree cst_index = index_sval->maybe_get_constant ())
-    {
-      key_t key = key_from_constant (cst_index);
-      region_id element_rid
-	= get_or_create (model, this_rid, key, element_type, ctxt);
-      return element_rid;
-   }
-
-  return model->get_or_create_view (this_rid, element_type, ctxt);
-}
-
-/* Implementation of region::clone vfunc for array_region.  */
-
-region *
-array_region::clone () const
-{
-  return new array_region (*this);
-}
-
-/* Compare the fields of this array_region with OTHER, returning true
-   if they are equal.
-   For use by region::operator==.  */
-
-bool
-array_region::compare_fields (const array_region &other) const
-{
-  if (m_map.elements () != other.m_map.elements ())
-    return false;
-
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      int key = (*iter).first;
-      region_id e = (*iter).second;
-      region_id *other_slot = const_cast <map_t &> (other.m_map).get (key);
-      if (other_slot == NULL)
-	return false;
-      if (e != *other_slot)
-	return false;
-    }
-  return true;
-}
-
-/* Implementation of region::print_fields vfunc for array_region.  */
-
-void
-array_region::print_fields (const region_model &model,
-			    region_id this_rid,
-			    pretty_printer *pp) const
-{
-  region::print_fields (model, this_rid, pp);
-  pp_string (pp, ", array: {");
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      if (iter != m_map.begin ())
-	pp_string (pp, ", ");
-      int key = (*iter).first;
-      region_id child_rid = (*iter).second;
-      pp_printf (pp, "[%i]: ", key);
-      child_rid.print (pp);
-    }
-  pp_string (pp, "}");
-}
-
-/* Implementation of region::validate vfunc for array_region.  */
-
-void
-array_region::validate (const region_model &model) const
-{
-  region::validate (model);
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      region_id child_rid = (*iter).second;
-      child_rid.validate (model);
-    }
-}
-
-/* Implementation of region::dump_dot_to_pp vfunc for array_region.  */
-
-void
-array_region::dump_dot_to_pp (const region_model &model,
-			      region_id this_rid,
-			      pretty_printer *pp) const
-{
-  region::dump_dot_to_pp (model, this_rid, pp);
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      // TODO: add nodes/edges to label things
-
-      int key = (*iter).first;
-      region_id child_rid = (*iter).second;
-
-      pp_printf (pp, "rid_label_%i [label=\"", child_rid.as_int ());
-      pp_write_text_to_stream (pp);
-      pp_printf (pp, "%qi", key);
-      pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
-      pp_string (pp, "\"];");
-      pp_newline (pp);
-
-      pp_printf (pp, "rid_label_%i", child_rid.as_int ());
-      pp_string (pp, " -> ");
-      child_rid.dump_node_name_to_pp (pp);
-      pp_string (pp, ";");
-      pp_newline (pp);
-    }
-}
-
-/* Implementation of region::dump_child_label vfunc for array_region.  */
-
-void
-array_region::dump_child_label (const region_model &model,
-			      region_id this_rid,
-			      region_id child_rid,
-			      pretty_printer *pp) const
-{
-  region::dump_child_label (model, this_rid, child_rid, pp);
-
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      if (child_rid == (*iter).second)
-	{
-	  int key = (*iter).first;
-	  pp_printf (pp, "[%i]: ", key);
-	}
-    }
-}
-
-/* Look for a child region for KEY within this array_region.
-   If it doesn't already exist, create a child array_region, using TYPE for
-   its type.
-   Return the region_id of the child (whether pre-existing, or
-   newly-created).
-   Notify CTXT if we don't know how to handle TYPE.  */
-
-region_id
-array_region::get_or_create (region_model *model,
-			     region_id this_rid,
-			     key_t key,
-			     tree type,
-			     region_model_context *ctxt)
-{
-  region_id *slot = m_map.get (key);
-  if (slot)
-    return *slot;
-  region_id child_rid = model->add_region_for_type (this_rid, type, ctxt);
-  m_map.put (key, child_rid);
-  return child_rid;
-}
-
-/* Get the region_id for the child region for KEY within this
-   ARRAY_REGION, or NULL if there is no such child region.  */
-
-region_id *
-array_region::get (key_t key)
-{
-  region_id *slot = m_map.get (key);
-  return slot;
-}
-
-/* Implementation of region::add_to_hash vfunc for array_region.  */
-
-void
-array_region::add_to_hash (inchash::hash &hstate) const
-{
-  region::add_to_hash (hstate);
-  // TODO
-}
-
-/* Implementation of region::remap_region_ids vfunc for array_region.  */
-
-void
-array_region::remap_region_ids (const region_id_map &map)
-{
-  region::remap_region_ids (map);
-
-  /* Remap the region ids within the map entries.  */
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end (); ++iter)
-    map.update (&(*iter).second);
-}
-
-/* Look for a child region with id CHILD_RID within this array_region.
-   If one is found, write its key to *OUT and return true,
-   otherwise return false.  */
-
-bool
-array_region::get_key_for_child_region (region_id child_rid, key_t *out) const
-{
-  // TODO: do we want to store an inverse map?
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      key_t key = (*iter).first;
-      region_id r = (*iter).second;
-      if (r == child_rid)
-	{
-	  *out = key;
-	  return true;
-	}
-    }
-
-  return false;
-}
-
-/* qsort comparator for array_region's keys.  */
-
-int
-array_region::key_cmp (const void *p1, const void *p2)
-{
-  key_t i1 = *(const key_t *)p1;
-  key_t i2 = *(const key_t *)p2;
-
-  if (i1 > i2)
-    return 1;
-  else if (i1 < i2)
-    return -1;
-  else
-    return 0;
-}
-
-/* Implementation of region::walk_for_canonicalization vfunc for
-   array_region.  */
-
-void
-array_region::walk_for_canonicalization (canonicalization *c) const
-{
-  auto_vec<int> keys (m_map.elements ());
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      int key_a = (*iter).first;
-      keys.quick_push (key_a);
-    }
-  keys.qsort (key_cmp);
-
-  unsigned i;
-  int key;
-  FOR_EACH_VEC_ELT (keys, i, key)
-    {
-      region_id rid = *const_cast<array_region *>(this)->m_map.get (key);
-      c->walk_rid (rid);
-    }
-}
-
-/* Convert constant CST into an array_region::key_t.  */
-
-array_region::key_t
-array_region::key_from_constant (tree cst)
-{
-  gcc_assert (CONSTANT_CLASS_P (cst));
-  wide_int w = wi::to_wide (cst);
-  key_t result = w.to_shwi ();
-  return result;
-}
-
-/* Convert array_region::key_t KEY into a tree constant.  */
-
-tree
-array_region::constant_from_key (key_t key)
-{
-  tree array_type = get_type ();
-  tree index_type = TYPE_DOMAIN (array_type);
-  return build_int_cst (index_type, key);
-}
-
-/* class function_region : public map_region.  */
-
-/* Compare the fields of this function_region with OTHER, returning true
-   if they are equal.
-   For use by region::operator==.  */
-
-bool
-function_region::compare_fields (const function_region &other) const
-{
-  return map_region::compare_fields (other);
-}
-
-/* Implementation of region::clone vfunc for function_region.  */
-
-region *
-function_region::clone () const
-{
-  return new function_region (*this);
-}
-
-/* Implementation of map_region::valid_key_p vfunc for function_region.  */
-
-bool
-function_region::valid_key_p (tree key) const
-{
-  return TREE_CODE (key) == LABEL_DECL;
-}
-
-/* class stack_region : public region.  */
-
-/* stack_region's copy ctor.  */
-
-stack_region::stack_region (const stack_region &other)
-: region (other),
-  m_frame_rids (other.m_frame_rids.length ())
-{
-  int i;
-  region_id *frame_rid;
-  FOR_EACH_VEC_ELT (other.m_frame_rids, i, frame_rid)
-    m_frame_rids.quick_push (*frame_rid);
-}
-
-/* Compare the fields of this stack_region with OTHER, returning true
-   if they are equal.
-   For use by region::operator==.  */
-
-bool
-stack_region::compare_fields (const stack_region &other) const
-{
-  if (m_frame_rids.length () != other.m_frame_rids.length ())
-    return false;
-
-  int i;
-  region_id *frame_rid;
-  FOR_EACH_VEC_ELT (m_frame_rids, i, frame_rid)
-    if (m_frame_rids[i] != other.m_frame_rids[i])
-      return false;
-
-  return true;
-}
-
-/* Implementation of region::clone vfunc for stack_region.  */
-
-region *
-stack_region::clone () const
-{
-  return new stack_region (*this);
-}
-
-/* Implementation of region::print_fields vfunc for stack_region.  */
-
-void
-stack_region::print_fields (const region_model &model,
-			    region_id this_rid,
-			    pretty_printer *pp) const
-{
-  region::print_fields (model, this_rid, pp);
-  // TODO
-}
-
-/* Implementation of region::dump_child_label vfunc for stack_region.  */
-
-void
-stack_region::dump_child_label (const region_model &model,
-				region_id this_rid ATTRIBUTE_UNUSED,
-				region_id child_rid,
-				pretty_printer *pp) const
-{
-  function *fun = model.get_region<frame_region> (child_rid)->get_function ();
-  pp_printf (pp, "frame for %qs: ", function_name (fun));
-}
-
-/* Implementation of region::validate vfunc for stack_region.  */
-
-void
-stack_region::validate (const region_model &model) const
-{
-  region::validate (model);
-  int i;
-  region_id *frame_rid;
-  FOR_EACH_VEC_ELT (m_frame_rids, i, frame_rid)
-    m_frame_rids[i].validate (model);
-}
-
-/* Push FRAME_RID (for a frame_region) onto this stack.  */
-
-void
-stack_region::push_frame (region_id frame_rid)
-{
-  m_frame_rids.safe_push (frame_rid);
-}
-
-/* Get the region_id of the top-most frame in this stack, if any.  */
-
-region_id
-stack_region::get_current_frame_id () const
-{
-  if (m_frame_rids.length () > 0)
-    return m_frame_rids[m_frame_rids.length () - 1];
-  else
-    return region_id::null ();
-}
-
-/* Pop the topmost frame_region from this stack.
-
-   If RESULT_DST_RID is non-null, copy any return value from the frame
-   into RESULT_DST_RID's region.
-
-   Purge the frame region and all its descendent regions.
-   Convert any pointers that point into such regions into
-   POISON_KIND_POPPED_STACK svalues.
-
-   If PURGE, then purge all unused svalues, with the exception of any
-   returned values.
-
-   Accumulate stats on purged entities into STATS.  */
-
-void
-stack_region::pop_frame (region_model *model, region_id result_dst_rid,
-			 bool purge, purge_stats *stats,
-			 region_model_context *ctxt)
-{
-  gcc_assert (m_frame_rids.length () > 0);
-
-  region_id frame_rid = get_current_frame_id ();
-  frame_region *frame = model->get_region<frame_region> (frame_rid);
-
-  /* Evaluate the result, within the callee frame.  */
-  svalue_id_set returned_sids;
-  tree fndecl = frame->get_function ()->decl;
-  tree result = DECL_RESULT (fndecl);
-  if (result && TREE_TYPE (result) != void_type_node)
-    {
-      if (!result_dst_rid.null_p ())
-	{
-	  /* Copy the result to RESULT_DST_RID.  */
-	  model->copy_region (result_dst_rid, model->get_lvalue (result, ctxt),
-			      ctxt);
-	}
-      if (purge)
-	{
-	  /* Populate returned_sids, to avoid purging them.  */
-	  region_id return_rid = model->get_lvalue (result, NULL);
-	  region_id_set returned_rids (model);
-	  model->get_descendents (return_rid, &returned_rids,
-				  region_id::null ());
-	  for (unsigned i = 0; i < model->get_num_regions (); i++)
-	    {
-	      region_id rid = region_id::from_int (i);
-	      if (returned_rids.region_p (rid))
-		{
-		  svalue_id sid = model->get_region (rid)->get_value_direct ();
-		  returned_sids.add_svalue (sid);
-		}
-	    }
-	}
-    }
-
-  /* Pop the frame RID.  */
-  m_frame_rids.pop ();
-
-  model->delete_region_and_descendents (frame_rid,
-					POISON_KIND_POPPED_STACK,
-					stats,
-					ctxt ? ctxt->get_logger () : NULL);
-
-  /* Delete unused svalues, but don't delete the return value(s).  */
-  if (purge)
-    model->purge_unused_svalues (stats, ctxt, &returned_sids);
-
-  model->validate ();
-}
-
-/* Implementation of region::add_to_hash vfunc for stack_region.  */
-
-void
-stack_region::add_to_hash (inchash::hash &hstate) const
-{
-  region::add_to_hash (hstate);
-
-  int i;
-  region_id *frame_rid;
-  FOR_EACH_VEC_ELT (m_frame_rids, i, frame_rid)
-    inchash::add (*frame_rid, hstate);
-}
-
-/* Implementation of region::remap_region_ids vfunc for stack_region.  */
-
-void
-stack_region::remap_region_ids (const region_id_map &map)
-{
-  region::remap_region_ids (map);
-  int i;
-  region_id *frame_rid;
-  FOR_EACH_VEC_ELT (m_frame_rids, i, frame_rid)
-    map.update (&m_frame_rids[i]);
-}
-
-/* Attempt to merge STACK_REGION_A and STACK_REGION_B using MERGER.
-   Return true if the merger is possible, false otherwise.  */
-
-bool
-stack_region::can_merge_p (const stack_region *stack_region_a,
-			   const stack_region *stack_region_b,
-			   model_merger *merger)
-{
-  if (stack_region_a->get_num_frames ()
-      != stack_region_b->get_num_frames ())
-    return false;
-
-  region_model *merged_model = merger->m_merged_model;
-
-  region_id rid_merged_stack
-    = merged_model->get_root_region ()->ensure_stack_region (merged_model);
-
-  stack_region *merged_stack
-    = merged_model->get_region <stack_region> (rid_merged_stack);
-
-  /* First, create all frames in the merged model, without populating them.
-     The merging code assumes that all frames in the merged model already exist,
-     so we have to do this first to handle the case in which a local in an
-     older frame points at a local in a more recent frame.  */
-    for (unsigned i = 0; i < stack_region_a->get_num_frames (); i++)
-      {
-	region_id rid_a = stack_region_a->get_frame_rid (i);
-	frame_region *frame_a = merger->get_region_a <frame_region> (rid_a);
-
-	region_id rid_b = stack_region_b->get_frame_rid (i);
-	frame_region *frame_b = merger->get_region_b <frame_region> (rid_b);
-
-	if (frame_a->get_function () != frame_b->get_function ())
-	  return false;
-
-	frame_region *merged_frame = new frame_region (rid_merged_stack,
-						       frame_a->get_function (),
-						       frame_a->get_depth ());
-	region_id rid_merged_frame = merged_model->add_region (merged_frame);
-	merged_stack->push_frame (rid_merged_frame);
-      }
-
-    /* Now populate the frames we created.  */
-    for (unsigned i = 0; i < stack_region_a->get_num_frames (); i++)
-      {
-	region_id rid_a = stack_region_a->get_frame_rid (i);
-	frame_region *frame_a = merger->get_region_a <frame_region> (rid_a);
-
-	region_id rid_b = stack_region_b->get_frame_rid (i);
-	frame_region *frame_b = merger->get_region_b <frame_region> (rid_b);
-
-	region_id rid_merged_frame = merged_stack->get_frame_rid (i);
-	frame_region *merged_frame
-	  = merged_model->get_region <frame_region> (rid_merged_frame);
-	if (!map_region::can_merge_p (frame_a, frame_b,
-				      merged_frame, rid_merged_frame,
-				      merger))
-	  return false;
-      }
-
-  return true;
-}
-
-/* Implementation of region::walk_for_canonicalization vfunc for
-   stack_region.  */
-
-void
-stack_region::walk_for_canonicalization (canonicalization *c) const
-{
-  int i;
-  region_id *frame_rid;
-  FOR_EACH_VEC_ELT (m_frame_rids, i, frame_rid)
-    c->walk_rid (*frame_rid);
-}
-
-/* For debugging purposes: look for a grandchild region within one of
-   the child frame regions, where the grandchild is for a decl named
-   IDENTIFIER (or an SSA_NAME for such a decl):
-
-     stack_region
-     `-frame_region
-       `-region for decl named IDENTIFIER
-
-   returning its value, or svalue_id::null if none are found.  */
-
-svalue_id
-stack_region::get_value_by_name (tree identifier,
-				 const region_model &model) const
-{
-  int i;
-  region_id *frame_rid;
-  FOR_EACH_VEC_ELT (m_frame_rids, i, frame_rid)
-    {
-      frame_region *frame = model.get_region<frame_region> (*frame_rid);
-      svalue_id sid = frame->get_value_by_name (identifier, model);
-      if (!sid.null_p ())
-	return sid;
-    }
-
-  return svalue_id::null ();
-}
-
-/* class heap_region : public region.  */
-
-/* heap_region's copy ctor.  */
-
-heap_region::heap_region (const heap_region &other)
-: region (other)
-{
-}
-
-/* Compare the fields of this heap_region with OTHER, returning true
-   if they are equal.
-   For use by region::operator==.  */
-
-bool
-heap_region::compare_fields (const heap_region &) const
-{
-  /* Empty.  */
-  return true;
-}
-
-/* Implementation of region::clone vfunc for heap_region.  */
-
-region *
-heap_region::clone () const
-{
-  return new heap_region (*this);
-}
-
-/* Implementation of region::walk_for_canonicalization vfunc for
-   heap_region.  */
-
-void
-heap_region::walk_for_canonicalization (canonicalization *) const
-{
-  /* Empty.  */
-}
-
-/* class root_region : public region.  */
-
-/* root_region's default ctor.  */
-
-root_region::root_region ()
-: region (region_id::null (),
-	  svalue_id::null (),
-	  NULL_TREE)
-{
-}
-
-/* root_region's copy ctor.  */
-
-root_region::root_region (const root_region &other)
-: region (other),
-  m_stack_rid (other.m_stack_rid),
-  m_globals_rid (other.m_globals_rid),
-  m_code_rid (other.m_code_rid),
-  m_heap_rid (other.m_heap_rid)
-{
-}
-
-/* Compare the fields of this root_region with OTHER, returning true
-   if they are equal.
-   For use by region::operator==.  */
-
-bool
-root_region::compare_fields (const root_region &other) const
-{
-  if (m_stack_rid != other.m_stack_rid)
-    return false;
-  if (m_globals_rid != other.m_globals_rid)
-    return false;
-  if (m_code_rid != other.m_code_rid)
-    return false;
-  if (m_heap_rid != other.m_heap_rid)
-    return false;
-  return true;
-}
-
-/* Implementation of region::clone vfunc for root_region.  */
-
-region *
-root_region::clone () const
-{
-  return new root_region (*this);
-}
-
-/* Implementation of region::print_fields vfunc for root_region.  */
-
-void
-root_region::print_fields (const region_model &model,
-			   region_id this_rid,
-			   pretty_printer *pp) const
-{
-  region::print_fields (model, this_rid, pp);
-  // TODO
-}
-
-/* Implementation of region::validate vfunc for root_region.  */
-
-void
-root_region::validate (const region_model &model) const
-{
-  region::validate (model);
-  m_stack_rid.validate (model);
-  m_globals_rid.validate (model);
-  m_code_rid.validate (model);
-  m_heap_rid.validate (model);
-}
-
-/* Implementation of region::dump_child_label vfunc for root_region.  */
-
-void
-root_region::dump_child_label (const region_model &model ATTRIBUTE_UNUSED,
-			       region_id this_rid ATTRIBUTE_UNUSED,
-			       region_id child_rid,
-			       pretty_printer *pp) const
-{
-  if (child_rid == m_stack_rid)
-    pp_printf (pp, "stack: ");
-  else if (child_rid == m_globals_rid)
-    pp_printf (pp, "globals: ");
-  else if (child_rid == m_code_rid)
-    pp_printf (pp, "code: ");
-  else if (child_rid == m_heap_rid)
-    pp_printf (pp, "heap: ");
-}
-
-/* Create a new frame_region for a call to FUN and push it onto
-   the stack.
-
-   If ARG_SIDS is non-NULL, use it to populate the parameters
-   in the new frame.
-   Otherwise, populate them with unknown values.
-
-   Return the region_id of the new frame.  */
-
-region_id
-root_region::push_frame (region_model *model, function *fun,
-			 vec<svalue_id> *arg_sids,
-			 region_model_context *ctxt)
-{
-  gcc_assert (fun);
-  /* arg_sids can be NULL.  */
-
-  ensure_stack_region (model);
-  stack_region *stack = model->get_region <stack_region> (m_stack_rid);
-
-  frame_region *region = new frame_region (m_stack_rid, fun,
-					   stack->get_num_frames ());
-  region_id frame_rid = model->add_region (region);
-
-  // TODO: unify these cases by building a vec of unknown?
-
-  if (arg_sids)
-    {
-      /* Arguments supplied from a caller frame.  */
-
-      tree fndecl = fun->decl;
-      unsigned idx = 0;
-      for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm;
-	   iter_parm = DECL_CHAIN (iter_parm), ++idx)
-	{
-	  /* If there's a mismatching declaration, the call stmt might
-	     not have enough args.  Handle this case by leaving the
-	     rest of the params as uninitialized.  */
-	  if (idx >= arg_sids->length ())
-	    break;
-	  svalue_id arg_sid = (*arg_sids)[idx];
-	  region_id parm_rid
-	    = region->get_or_create (model, frame_rid, iter_parm,
-				     TREE_TYPE (iter_parm), ctxt);
-	  model->set_value (parm_rid, arg_sid, ctxt);
-
-	  /* Also do it for default SSA name (sharing the same unknown
-	     value).  */
-	  tree parm_default_ssa = ssa_default_def (fun, iter_parm);
-	  if (parm_default_ssa)
-	    {
-	      region_id defssa_rid
-		= region->get_or_create (model, frame_rid, parm_default_ssa,
-					 TREE_TYPE (iter_parm), ctxt);
-	      model->set_value (defssa_rid, arg_sid, ctxt);
-	    }
-	}
-    }
-  else
-    {
-      /* No known arguments (a top-level call within the analysis).  */
-
-      /* Params have a defined, unknown value; they should not inherit
-	 from the poisoned uninit value.  */
-      tree fndecl = fun->decl;
-      for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm;
-	   iter_parm = DECL_CHAIN (iter_parm))
-	{
-	  region_id parm_rid
-	    = region->get_or_create (model, frame_rid, iter_parm,
-				     TREE_TYPE (iter_parm), ctxt);
-	  svalue_id parm_sid
-	    = model->set_to_new_unknown_value (parm_rid, TREE_TYPE (iter_parm),
-					       ctxt);
-
-	  /* Also do it for default SSA name (sharing the same unknown
-	     value).  */
-	  tree parm_default_ssa = ssa_default_def (fun, iter_parm);
-	  if (parm_default_ssa)
-	    {
-	      region_id defssa_rid
-		= region->get_or_create (model, frame_rid, parm_default_ssa,
-					 TREE_TYPE (iter_parm), ctxt);
-	      model->get_region (defssa_rid)->set_value (*model, defssa_rid,
-							 parm_sid, ctxt);
-	    }
-	}
-    }
-
-  stack->push_frame (frame_rid);
-
-  return frame_rid;
-}
-
-/* Get the region_id of the top-most frame in this root_region's stack,
-   if any.  */
-
-region_id
-root_region::get_current_frame_id (const region_model &model) const
-{
-  stack_region *stack = model.get_region <stack_region> (m_stack_rid);
-  if (stack)
-    return stack->get_current_frame_id ();
-  else
-    return region_id::null ();
-}
-
-/* Pop the topmost frame_region from this root_region's stack;
-   see the comment for stack_region::pop_frame.  */
-
-void
-root_region::pop_frame (region_model *model, region_id result_dst_rid,
-			bool purge, purge_stats *out,
-			region_model_context *ctxt)
-{
-  stack_region *stack = model->get_region <stack_region> (m_stack_rid);
-  stack->pop_frame (model, result_dst_rid, purge, out, ctxt);
-}
-
-/* Return the region_id of the stack region, creating it if doesn't
-   already exist.  */
-
-region_id
-root_region::ensure_stack_region (region_model *model)
-{
-  if (m_stack_rid.null_p ())
-    {
-      m_stack_rid
-	= model->add_region (new stack_region (model->get_root_rid (),
-					       svalue_id::null ()));
-    }
-  return m_stack_rid;
-}
-
-/* Return the stack region (which could be NULL).  */
-
-stack_region *
-root_region::get_stack_region (const region_model *model) const
-{
-  return model->get_region <stack_region> (m_stack_rid);
-}
-
-/* Return the region_id of the globals region, creating it if doesn't
-   already exist.  */
-
-region_id
-root_region::ensure_globals_region (region_model *model)
-{
-  if (m_globals_rid.null_p ())
-    m_globals_rid
-      = model->add_region (new globals_region (model->get_root_rid ()));
-  return m_globals_rid;
-}
-
-/* Return the code region (which could be NULL).  */
-
-code_region *
-root_region::get_code_region (const region_model *model) const
-{
-  return model->get_region <code_region> (m_code_rid);
-}
-
-/* Return the region_id of the code region, creating it if doesn't
-   already exist.  */
-
-region_id
-root_region::ensure_code_region (region_model *model)
-{
-  if (m_code_rid.null_p ())
-    m_code_rid
-      = model->add_region (new code_region (model->get_root_rid ()));
-  return m_code_rid;
-}
-
-/* Return the globals region (which could be NULL).  */
-
-globals_region *
-root_region::get_globals_region (const region_model *model) const
-{
-  return model->get_region <globals_region> (m_globals_rid);
-}
-
-/* Return the region_id of the heap region, creating it if doesn't
-   already exist.  */
-
-region_id
-root_region::ensure_heap_region (region_model *model)
-{
-  if (m_heap_rid.null_p ())
-    {
-      m_heap_rid
-	= model->add_region (new heap_region (model->get_root_rid (),
-					      svalue_id::null ()));
-    }
-  return m_heap_rid;
-}
-
-/* Return the heap region (which could be NULL).  */
-
-heap_region *
-root_region::get_heap_region (const region_model *model) const
-{
-  return model->get_region <heap_region> (m_heap_rid);
-}
-
-/* Implementation of region::remap_region_ids vfunc for root_region.  */
-
-void
-root_region::remap_region_ids (const region_id_map &map)
-{
-  map.update (&m_stack_rid);
-  map.update (&m_globals_rid);
-  map.update (&m_code_rid);
-  map.update (&m_heap_rid);
-}
-
-/* Attempt to merge ROOT_REGION_A and ROOT_REGION_B into
-   MERGED_ROOT_REGION using MERGER.
-   Return true if the merger is possible, false otherwise.  */
-
-bool
-root_region::can_merge_p (const root_region *root_region_a,
-			  const root_region *root_region_b,
-			  root_region *merged_root_region,
-			  model_merger *merger)
-{
-  /* We can only merge if the stacks are sufficiently similar.  */
-  stack_region *stack_a = root_region_a->get_stack_region (merger->m_model_a);
-  stack_region *stack_b = root_region_b->get_stack_region (merger->m_model_b);
-  if (stack_a && stack_b)
-    {
-      /* If the two models both have a stack, attempt to merge them.  */
-      merged_root_region->ensure_stack_region (merger->m_merged_model);
-      if (!stack_region::can_merge_p (stack_a, stack_b, merger))
-	return false;
-    }
-  else if (stack_a || stack_b)
-    /* Don't attempt to merge if one model has a stack and the other
-       doesn't.  */
-    return false;
-
-  map_region *globals_a = root_region_a->get_globals_region (merger->m_model_a);
-  map_region *globals_b = root_region_b->get_globals_region (merger->m_model_b);
-  if (globals_a && globals_b)
-    {
-      /* If both models have globals regions, attempt to merge them.  */
-      region_id merged_globals_rid
-	= merged_root_region->ensure_globals_region (merger->m_merged_model);
-      map_region *merged_globals
-	= merged_root_region->get_globals_region (merger->m_merged_model);
-      if (!map_region::can_merge_p (globals_a, globals_b,
-				    merged_globals, merged_globals_rid,
-				    merger))
-	return false;
-    }
-  /* otherwise, merge as "no globals".  */
-
-  map_region *code_a = root_region_a->get_code_region (merger->m_model_a);
-  map_region *code_b = root_region_b->get_code_region (merger->m_model_b);
-  if (code_a && code_b)
-    {
-      /* If both models have code regions, attempt to merge them.  */
-      region_id merged_code_rid
-	= merged_root_region->ensure_code_region (merger->m_merged_model);
-      map_region *merged_code
-	= merged_root_region->get_code_region (merger->m_merged_model);
-      if (!map_region::can_merge_p (code_a, code_b,
-				    merged_code, merged_code_rid,
-				    merger))
-	return false;
-    }
-  /* otherwise, merge as "no code".  */
-
-  heap_region *heap_a = root_region_a->get_heap_region (merger->m_model_a);
-  heap_region *heap_b = root_region_b->get_heap_region (merger->m_model_b);
-  if (heap_a && heap_b)
-    {
-      /* If both have a heap, create a "merged" heap.
-	 Actually merging the heap contents happens via the region_svalue
-	 instances, as needed, when seeing pairs of region_svalue instances.  */
-      merged_root_region->ensure_heap_region (merger->m_merged_model);
-    }
-  /* otherwise, merge as "no heap".  */
-
-  return true;
-}
-
-/* Implementation of region::add_to_hash vfunc for root_region.  */
-
-void
-root_region::add_to_hash (inchash::hash &hstate) const
-{
-  region::add_to_hash (hstate);
-  inchash::add (m_stack_rid, hstate);
-  inchash::add (m_globals_rid, hstate);
-  inchash::add (m_code_rid, hstate);
-  inchash::add (m_heap_rid, hstate);
-}
-
-/* Implementation of region::walk_for_canonicalization vfunc for
-   root_region.  */
-
-void
-root_region::walk_for_canonicalization (canonicalization *c) const
-{
-  c->walk_rid (m_stack_rid);
-  c->walk_rid (m_globals_rid);
-  c->walk_rid (m_code_rid);
-  c->walk_rid (m_heap_rid);
-}
-
-/* For debugging purposes: look for a descendant region for a local
-   or global decl named IDENTIFIER (or an SSA_NAME for such a decl),
-   returning its value, or svalue_id::null if none are found.  */
-
-svalue_id
-root_region::get_value_by_name (tree identifier,
-				const region_model &model) const
-{
-  if (stack_region *stack = get_stack_region (&model))
-    {
-      svalue_id sid = stack->get_value_by_name (identifier, model);
-      if (!sid.null_p ())
-	return sid;
-    }
-  if (map_region *globals = get_globals_region (&model))
-    {
-      svalue_id sid = globals->get_value_by_name (identifier, model);
-      if (!sid.null_p ())
-	return sid;
-    }
-  return svalue_id::null ();
-}
-
-/* class symbolic_region : public map_region.  */
-
-/* symbolic_region's copy ctor.  */
-
-symbolic_region::symbolic_region (const symbolic_region &other)
-: region (other),
-  m_possibly_null (other.m_possibly_null)
-{
-}
-
-/* Compare the fields of this symbolic_region with OTHER, returning true
-   if they are equal.
-   For use by region::operator==.  */
-
-bool
-symbolic_region::compare_fields (const symbolic_region &other) const
-{
-  return m_possibly_null == other.m_possibly_null;
-}
-
-/* Implementation of region::clone vfunc for symbolic_region.  */
-
-region *
-symbolic_region::clone () const
-{
-  return new symbolic_region (*this);
-}
-
-/* Implementation of region::walk_for_canonicalization vfunc for
-   symbolic_region.  */
-
-void
-symbolic_region::walk_for_canonicalization (canonicalization *) const
-{
-  /* Empty.  */
-}
-
-/* Implementation of region::print_fields vfunc for symbolic_region.  */
-
-void
-symbolic_region::print_fields (const region_model &model,
-			       region_id this_rid,
-			       pretty_printer *pp) const
-{
-  region::print_fields (model, this_rid, pp);
-  pp_printf (pp, ", possibly_null: %s", m_possibly_null ? "true" : "false");
-}
-
-/* class region_model.  */
-
-/* region_model's default ctor.  */
-
-region_model::region_model ()
-{
-  m_root_rid = add_region (new root_region ());
-  m_constraints = new impl_constraint_manager (this);
-  // TODO
-}
-
-/* region_model's copy ctor.  */
-
-region_model::region_model (const region_model &other)
-: m_svalues (other.m_svalues.length ()),
-  m_regions (other.m_regions.length ()),
-  m_root_rid (other.m_root_rid)
-{
-  /* Clone the svalues and regions.  */
-  int i;
-
-  svalue *svalue;
-  FOR_EACH_VEC_ELT (other.m_svalues, i, svalue)
-    m_svalues.quick_push (svalue->clone ());
-
-  region *region;
-  FOR_EACH_VEC_ELT (other.m_regions, i, region)
-    m_regions.quick_push (region->clone ());
-
-  m_constraints = other.m_constraints->clone (this);
-}
-
-/* region_model's dtor.  */
-
-region_model::~region_model ()
-{
-  delete m_constraints;
-}
-
-/* region_model's assignment operator.  */
-
-region_model &
-region_model::operator= (const region_model &other)
-{
-  unsigned i;
-  svalue *svalue;
-  region *region;
-
-  /* Delete existing content.  */
-  FOR_EACH_VEC_ELT (m_svalues, i, svalue)
-    delete svalue;
-  m_svalues.truncate (0);
-
-  FOR_EACH_VEC_ELT (m_regions, i, region)
-    delete region;
-  m_regions.truncate (0);
-
-  delete m_constraints;
-
-  /* Clone the svalues and regions.  */
-  m_svalues.reserve (other.m_svalues.length (), true);
-  FOR_EACH_VEC_ELT (other.m_svalues, i, svalue)
-    m_svalues.quick_push (svalue->clone ());
-
-  m_regions.reserve (other.m_regions.length (), true);
-  FOR_EACH_VEC_ELT (other.m_regions, i, region)
-    m_regions.quick_push (region->clone ());
-
-  m_root_rid = other.m_root_rid;
-
-  m_constraints = other.m_constraints->clone (this);
-
-  return *this;
-}
-
-/* Equality operator for region_model.
-
-   Amongst other things this directly compares the svalue and region
-   vectors and so for this to be meaningful both this and OTHER should
-   have been canonicalized.  */
-
-bool
-region_model::operator== (const region_model &other) const
-{
-  if (m_root_rid != other.m_root_rid)
-    return false;
-
-  if (m_svalues.length () != other.m_svalues.length ())
-    return false;
-
-  if (m_regions.length () != other.m_regions.length ())
-    return false;
-
-  if (*m_constraints != *other.m_constraints)
-    return false;
-
-  unsigned i;
-  svalue *svalue;
-  FOR_EACH_VEC_ELT (other.m_svalues, i, svalue)
-    if (!(*m_svalues[i] == *other.m_svalues[i]))
-      return false;
-
-  region *region;
-  FOR_EACH_VEC_ELT (other.m_regions, i, region)
-    if (!(*m_regions[i] == *other.m_regions[i]))
-      return false;
-
-  gcc_checking_assert (hash () == other.hash ());
-
-  return true;
-}
-
-/* Generate a hash value for this region_model.  */
-
-hashval_t
-region_model::hash () const
-{
-  hashval_t result = 0;
-  int i;
-
-  svalue *svalue;
-  FOR_EACH_VEC_ELT (m_svalues, i, svalue)
-    result ^= svalue->hash ();
-
-  region *region;
-  FOR_EACH_VEC_ELT (m_regions, i, region)
-    result ^= region->hash ();
-
-  result ^= m_constraints->hash ();
-
-  return result;
-}
-
-/* Print an all-on-one-line representation of this region_model to PP,
-   which must support %E for trees.  */
-
-void
-region_model::print (pretty_printer *pp) const
-{
-  int i;
-
-  pp_string (pp, "svalues: [");
-  svalue *svalue;
-  FOR_EACH_VEC_ELT (m_svalues, i, svalue)
-    {
-      if (i > 0)
-	pp_string (pp, ", ");
-      print_svalue (svalue_id::from_int (i), pp);
-    }
-
-  pp_string (pp, "], regions: [");
-
-  region *region;
-  FOR_EACH_VEC_ELT (m_regions, i, region)
-    {
-      if (i > 0)
-	pp_string (pp, ", ");
-      region->print (*this, region_id::from_int (i), pp);
-    }
-
-  pp_string (pp, "], constraints: ");
-
-  m_constraints->print (pp);
-}
-
-/* Print the svalue with id SID to PP.  */
-
-void
-region_model::print_svalue (svalue_id sid, pretty_printer *pp) const
-{
-  get_svalue (sid)->print (*this, sid, pp);
-}
-
-/* Dump a .dot representation of this region_model to PP, showing
-   the values and the hierarchy of regions.  */
-
-void
-region_model::dump_dot_to_pp (pretty_printer *pp) const
-{
-  graphviz_out gv (pp);
-
-  pp_string (pp, "digraph \"");
-  pp_write_text_to_stream (pp);
-  pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
-  pp_string (pp, "\" {\n");
-
-  gv.indent ();
-
-  pp_string (pp, "overlap=false;\n");
-  pp_string (pp, "compound=true;\n");
-
-  int i;
-
-  svalue *svalue;
-  FOR_EACH_VEC_ELT (m_svalues, i, svalue)
-    svalue->dump_dot_to_pp (*this, svalue_id::from_int (i), pp);
-
-  region *region;
-  FOR_EACH_VEC_ELT (m_regions, i, region)
-    region->dump_dot_to_pp (*this, region_id::from_int (i), pp);
-
-  /* TODO: constraints.  */
-
-  /* Terminate "digraph" */
-  gv.outdent ();
-  pp_string (pp, "}");
-  pp_newline (pp);
-}
-
-/* Dump a .dot representation of this region_model to FP.  */
-
-void
-region_model::dump_dot_to_file (FILE *fp) const
-{
-  pretty_printer pp;
-  pp_format_decoder (&pp) = default_tree_printer;
-  pp.buffer->stream = fp;
-  dump_dot_to_pp (&pp);
-  pp_flush (&pp);
-}
-
-/* Dump a .dot representation of this region_model to PATH.  */
-
-void
-region_model::dump_dot (const char *path) const
-{
-  FILE *fp = fopen (path, "w");
-  dump_dot_to_file (fp);
-  fclose (fp);
-}
-
-/* Dump a multiline representation of this model to PP, showing the
-   region hierarchy, the svalues, and any constraints.
-
-   If SUMMARIZE is true, show only the most pertinent information,
-   in a form that attempts to be less verbose.
-   Otherwise, show all information.  */
-
-void
-region_model::dump_to_pp (pretty_printer *pp, bool summarize) const
-{
-  if (summarize)
-    {
-      auto_vec<path_var> rep_path_vars;
-
-      unsigned i;
-      region *reg;
-      FOR_EACH_VEC_ELT (m_regions, i, reg)
-	{
-	  region_id rid = region_id::from_int (i);
-	  path_var pv = get_representative_path_var (rid);
-	  if (pv.m_tree)
-	    rep_path_vars.safe_push (pv);
-	}
-      bool is_first = true;
-
-      /* Work with a copy in case the get_lvalue calls change anything
-	 (they shouldn't).  */
-      region_model copy (*this);
-      copy.dump_summary_of_rep_path_vars (pp, &rep_path_vars, &is_first);
-
-      equiv_class *ec;
-      FOR_EACH_VEC_ELT (m_constraints->m_equiv_classes, i, ec)
-	{
-	  for (unsigned j = 0; j < ec->m_vars.length (); j++)
-	    {
-	      svalue_id lhs_sid = ec->m_vars[j];
-	      tree lhs_tree = get_representative_tree (lhs_sid);
-	      if (lhs_tree == NULL_TREE)
-		continue;
-	      for (unsigned k = j + 1; k < ec->m_vars.length (); k++)
-		{
-		  svalue_id rhs_sid = ec->m_vars[k];
-		  tree rhs_tree = get_representative_tree (rhs_sid);
-		  if (rhs_tree
-		      && !(CONSTANT_CLASS_P (lhs_tree)
-			   && CONSTANT_CLASS_P (rhs_tree)))
-		    {
-		      dump_separator (pp, &is_first);
-		      dump_tree (pp, lhs_tree);
-		      pp_string (pp, " == ");
-		      dump_tree (pp, rhs_tree);
-		    }
-		}
-	    }
-	}
-
-      constraint *c;
-      FOR_EACH_VEC_ELT (m_constraints->m_constraints, i, c)
-	{
-	  const equiv_class &lhs = c->m_lhs.get_obj (*m_constraints);
-	  const equiv_class &rhs = c->m_rhs.get_obj (*m_constraints);
-	  svalue_id lhs_sid = lhs.get_representative ();
-	  svalue_id rhs_sid = rhs.get_representative ();
-	  tree lhs_tree = get_representative_tree (lhs_sid);
-	  tree rhs_tree = get_representative_tree (rhs_sid);
-	  if (lhs_tree && rhs_tree
-	      && !(CONSTANT_CLASS_P (lhs_tree) && CONSTANT_CLASS_P (rhs_tree)))
-	    {
-	      dump_separator (pp, &is_first);
-	      dump_tree (pp, lhs_tree);
-	      pp_printf (pp, " %s ", constraint_op_code (c->m_op));
-	      dump_tree (pp, rhs_tree);
-	   }
-	}
-
-      return;
-    }
-
-  get_region (m_root_rid)->dump_to_pp (*this, m_root_rid, pp, "", true);
-
-  pp_string (pp, "svalues:");
-  pp_newline (pp);
-  int i;
-  svalue *svalue;
-  FOR_EACH_VEC_ELT (m_svalues, i, svalue)
-    {
-      pp_string (pp, "  ");
-      svalue_id sid = svalue_id::from_int (i);
-      print_svalue (sid, pp);
-      pp_newline (pp);
-    }
-
-  pp_string (pp, "constraint manager:");
-  pp_newline (pp);
-  m_constraints->dump_to_pp (pp);
-}
-
-/* Dump a multiline representation of this model to FILE.  */
-
-void
-region_model::dump (FILE *fp, bool summarize) const
-{
-  pretty_printer pp;
-  pp_format_decoder (&pp) = default_tree_printer;
-  pp_show_color (&pp) = pp_show_color (global_dc->printer);
-  pp.buffer->stream = fp;
-  dump_to_pp (&pp, summarize);
-  pp_flush (&pp);
-}
-
-/* Dump a multiline representation of this model to stderr.  */
-
-DEBUG_FUNCTION void
-region_model::dump (bool summarize) const
-{
-  dump (stderr, summarize);
-}
-
-/* Dump RMODEL fully to stderr (i.e. without summarization).  */
-
-DEBUG_FUNCTION void
-region_model::debug () const
-{
-  dump (false);
-}
-
-/* Dump VEC to PP, in the form "{VEC elements}: LABEL".  */
-
-static void
-dump_vec_of_tree (pretty_printer *pp,
-		  bool *is_first,
-		  const auto_vec<tree> &vec,
-		  const char *label)
-{
-  if (vec.length () == 0)
-    return;
-
-  dump_separator (pp, is_first);
-  pp_printf (pp, "{");
-  unsigned i;
-  tree key;
-  FOR_EACH_VEC_ELT (vec, i, key)
-    {
-      if (i > 0)
-	pp_string (pp, ", ");
-      dump_tree (pp, key);
-    }
-  pp_printf (pp, "}: %s", label);
-}
-
-/* Dump all *REP_PATH_VARS to PP in compact form, updating *IS_FIRST.
-   Subroutine of region_model::dump_to_pp.  */
-
-void
-region_model::dump_summary_of_rep_path_vars (pretty_printer *pp,
-					     auto_vec<path_var> *rep_path_vars,
-					     bool *is_first)
-{
-  /* Print pointers, constants, and poisoned values that aren't "uninit";
-     gather keys for unknown and uninit values.  */
-  unsigned i;
-  path_var *pv;
-  auto_vec<tree> unknown_trees;
-  FOR_EACH_VEC_ELT (*rep_path_vars, i, pv)
-    {
-      if (TREE_CODE (pv->m_tree) == STRING_CST)
-	continue;
-      tentative_region_model_context ctxt;
-      region_id child_rid = get_lvalue (*pv, &ctxt);
-      if (ctxt.had_errors_p ())
-	continue;
-      region *child_region = get_region (child_rid);
-      if (!child_region)
-	continue;
-      svalue_id sid = child_region->get_value_direct ();
-      if (sid.null_p ())
-	continue;
-      svalue *sval = get_svalue (sid);
-      switch (sval->get_kind ())
-	{
-	default:
-	  gcc_unreachable ();
-	case SK_REGION:
-	  {
-	    region_svalue *region_sval = as_a <region_svalue *> (sval);
-	    region_id pointee_rid = region_sval->get_pointee ();
-	    gcc_assert (!pointee_rid.null_p ());
-	    tree pointee = get_representative_path_var (pointee_rid).m_tree;
-	    dump_separator (pp, is_first);
-	    dump_tree (pp, pv->m_tree);
-	    pp_string (pp, ": ");
-	    pp_character (pp, '&');
-	    if (pointee)
-	      dump_tree (pp, pointee);
-	    else
-	      pointee_rid.print (pp);
-	  }
-	  break;
-	case SK_CONSTANT:
-	  dump_separator (pp, is_first);
-	  dump_tree (pp, pv->m_tree);
-	  pp_string (pp, ": ");
-	  dump_tree (pp, sval->dyn_cast_constant_svalue ()->get_constant ());
-	  break;
-	case SK_UNKNOWN:
-	  unknown_trees.safe_push (pv->m_tree);
-	  break;
-	case SK_POISONED:
-	  {
-	    poisoned_svalue *poisoned_sval = as_a <poisoned_svalue *> (sval);
-	    enum poison_kind pkind = poisoned_sval->get_poison_kind ();
-	    dump_separator (pp, is_first);
-	    dump_tree (pp, pv->m_tree);
-	    pp_printf (pp, ": %s", poison_kind_to_str (pkind));
-	  }
-	  break;
-	case SK_SETJMP:
-	  dump_separator (pp, is_first);
-	  pp_printf (pp, "setjmp: EN: %i",
-		     sval->dyn_cast_setjmp_svalue ()->get_enode_index ());
-	  break;
-	}
-    }
-
-  /* Print unknown and uninitialized values in consolidated form.  */
-  dump_vec_of_tree (pp, is_first, unknown_trees, "unknown");
-}
-
-/* Assert that this object is valid.  */
-
-void
-region_model::validate () const
-{
-  /* Skip this in a release build.  */
-#if !CHECKING_P
-  return;
-#endif
-
-  m_constraints->validate ();
-
-  unsigned i;
-  region *r;
-  FOR_EACH_VEC_ELT (m_regions, i, r)
-    r->validate (*this);
-
-  // TODO: anything else?
-}
-
-/* Global data for use by svalue_id_cmp_by_constant_svalue.  */
-
-static region_model *svalue_id_cmp_by_constant_svalue_model = NULL;
-
-/* Comparator for use by region_model::canonicalize.  */
-
-static int
-svalue_id_cmp_by_constant_svalue (const void *p1, const void *p2)
-{
-  const svalue_id *sid1 = (const svalue_id *)p1;
-  const svalue_id *sid2 = (const svalue_id *)p2;
-  gcc_assert (!sid1->null_p ());
-  gcc_assert (!sid2->null_p ());
-  gcc_assert (svalue_id_cmp_by_constant_svalue_model);
-  const svalue &sval1
-    = *svalue_id_cmp_by_constant_svalue_model->get_svalue (*sid1);
-  const svalue &sval2
-    = *svalue_id_cmp_by_constant_svalue_model->get_svalue (*sid2);
-  gcc_assert (sval1.get_kind () == SK_CONSTANT);
-  gcc_assert (sval2.get_kind () == SK_CONSTANT);
-
-  tree cst1 = ((const constant_svalue &)sval1).get_constant ();
-  tree cst2 = ((const constant_svalue &)sval2).get_constant ();
-  return tree_cmp (cst1, cst2);
-}
-
-/* Reorder the regions and svalues into a deterministic "canonical" order,
-   to maximize the chance of equality.
-   If non-NULL, notify CTXT about the svalue id remapping.  */
-
-void
-region_model::canonicalize (region_model_context *ctxt)
-{
-  /* Walk all regions and values in a deterministic order, visiting
-     rids and sids, generating a rid and sid map.  */
-  canonicalization c (*this);
-
-  /* (1): Walk all svalues, putting constants first, sorting the constants
-     (thus imposing an ordering on any constants that are purely referenced
-     by constraints).
-     Ignore other svalues for now.  */
-  {
-    unsigned i;
-    auto_vec<svalue_id> sids;
-    svalue *sval;
-    FOR_EACH_VEC_ELT (m_svalues, i, sval)
-      {
-	if (sval->get_kind () == SK_CONSTANT)
-	  sids.safe_push (svalue_id::from_int (i));
-      }
-    svalue_id_cmp_by_constant_svalue_model = this;
-    sids.qsort (svalue_id_cmp_by_constant_svalue);
-    svalue_id_cmp_by_constant_svalue_model = NULL;
-    svalue_id *sid;
-    FOR_EACH_VEC_ELT (sids, i, sid)
-      c.walk_sid (*sid);
-  }
-
-  /* (2): Walk all regions (and thus their values) in a deterministic
-     order.  */
-  c.walk_rid (m_root_rid);
-
-  /* (3): Ensure we've visited everything, as we don't want to purge
-     at this stage.  Anything we visit for the first time here has
-     arbitrary order.  */
-  {
-    unsigned i;
-    region *region;
-    FOR_EACH_VEC_ELT (m_regions, i, region)
-      c.walk_rid (region_id::from_int (i));
-    svalue *sval;
-    FOR_EACH_VEC_ELT (m_svalues, i, sval)
-      c.walk_sid (svalue_id::from_int (i));
-  }
-
-  /* (4): We now have a reordering of the regions and values.
-     Apply it.  */
-  remap_svalue_ids (c.m_sid_map);
-  remap_region_ids (c.m_rid_map);
-  if (ctxt)
-    ctxt->remap_svalue_ids (c.m_sid_map);
-
-  /* (5): Canonicalize the constraint_manager (it has already had its
-     svalue_ids remapped above).  This makes use of the new svalue_id
-     values, and so must happen last.  */
-  m_constraints->canonicalize (get_num_svalues ());
-
-  validate ();
-}
-
-/* Return true if this region_model is in canonical form.  */
-
-bool
-region_model::canonicalized_p () const
-{
-  region_model copy (*this);
-  copy.canonicalize (NULL);
-  return *this == copy;
-}
-
-/* A subclass of pending_diagnostic for complaining about uses of
-   poisoned values.  */
-
-class poisoned_value_diagnostic
-: public pending_diagnostic_subclass<poisoned_value_diagnostic>
-{
-public:
-  poisoned_value_diagnostic (tree expr, enum poison_kind pkind)
-  : m_expr (expr), m_pkind (pkind)
-  {}
-
-  const char *get_kind () const FINAL OVERRIDE { return "poisoned_value_diagnostic"; }
-
-  bool operator== (const poisoned_value_diagnostic &other) const
-  {
-    return m_expr == other.m_expr;
-  }
-
-  bool emit (rich_location *rich_loc) FINAL OVERRIDE
-  {
-    switch (m_pkind)
-      {
-      default:
-	gcc_unreachable ();
-      case POISON_KIND_FREED:
-	{
-	  diagnostic_metadata m;
-	  m.add_cwe (416); /* "CWE-416: Use After Free".  */
-	  return warning_meta (rich_loc, m,
-			       OPT_Wanalyzer_use_after_free,
-			       "use after %<free%> of %qE",
-			       m_expr);
-	}
-	break;
-      case POISON_KIND_POPPED_STACK:
-	{
-	  /* TODO: which CWE?  */
-	  return warning_at (rich_loc,
-			     OPT_Wanalyzer_use_of_pointer_in_stale_stack_frame,
-			     "use of pointer %qE within stale stack frame",
-			     m_expr);
-	}
-	break;
-      }
-  }
-
-  label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE
-  {
-    switch (m_pkind)
-      {
-      default:
-	gcc_unreachable ();
-      case POISON_KIND_FREED:
-	return ev.formatted_print ("use after %<free%> of %qE here",
-				   m_expr);
-      case POISON_KIND_POPPED_STACK:
-	return ev.formatted_print
-	  ("use of pointer %qE within stale stack frame here",
-	   m_expr);
-      }
-  }
-
-private:
-  tree m_expr;
-  enum poison_kind m_pkind;
-};
-
-/* Determine if EXPR is poisoned, and if so, queue a diagnostic to CTXT.  */
-
-void
-region_model::check_for_poison (tree expr, region_model_context *ctxt)
-{
-  if (!ctxt)
-    return;
-
-  // TODO: this is disabled for now (too many false positives)
-  return;
-
-  svalue_id expr_sid = get_rvalue (expr, ctxt);
-  gcc_assert (!expr_sid.null_p ());
-  svalue *expr_svalue = get_svalue (expr_sid);
-  gcc_assert (expr_svalue);
-  if (const poisoned_svalue *poisoned_sval
-	= expr_svalue->dyn_cast_poisoned_svalue ())
-    {
-      enum poison_kind pkind = poisoned_sval->get_poison_kind ();
-      ctxt->warn (new poisoned_value_diagnostic (expr, pkind));
-    }
-}
-
-/* Update this model for the ASSIGN stmt, using CTXT to report any
-   diagnostics.  */
-
-void
-region_model::on_assignment (const gassign *assign, region_model_context *ctxt)
-{
-  tree lhs = gimple_assign_lhs (assign);
-  tree rhs1 = gimple_assign_rhs1 (assign);
-
-  region_id lhs_rid = get_lvalue (lhs, ctxt);
-
-  /* Check for uses of poisoned values.  */
-  switch (get_gimple_rhs_class (gimple_expr_code (assign)))
-    {
-    case GIMPLE_INVALID_RHS:
-      gcc_unreachable ();
-      break;
-    case GIMPLE_TERNARY_RHS:
-      check_for_poison (gimple_assign_rhs3 (assign), ctxt);
-      /* Fallthru */
-    case GIMPLE_BINARY_RHS:
-      check_for_poison (gimple_assign_rhs2 (assign), ctxt);
-      /* Fallthru */
-    case GIMPLE_UNARY_RHS:
-    case GIMPLE_SINGLE_RHS:
-      check_for_poison (gimple_assign_rhs1 (assign), ctxt);
-    }
-
-  if (lhs_rid.null_p ())
-    return;
-  // TODO: issue a warning for this case
-
-  enum tree_code op = gimple_assign_rhs_code (assign);
-  switch (op)
-    {
-    default:
-      {
-	if (0)
-	  sorry_at (assign->location, "unhandled assignment op: %qs",
-		    get_tree_code_name (op));
-	set_to_new_unknown_value (lhs_rid, TREE_TYPE (lhs), ctxt);
-      }
-      break;
-
-    case BIT_FIELD_REF:
-      {
-	// TODO
-      }
-      break;
-
-    case CONSTRUCTOR:
-      {
-	/* e.g. "x ={v} {CLOBBER};"  */
-	// TODO
-      }
-      break;
-
-    case POINTER_PLUS_EXPR:
-      {
-	/* e.g. "_1 = a_10(D) + 12;" */
-	tree ptr = rhs1;
-	tree offset = gimple_assign_rhs2 (assign);
-
-	svalue_id ptr_sid = get_rvalue (ptr, ctxt);
-	svalue_id offset_sid = get_rvalue (offset, ctxt);
-	region_id element_rid
-	  = get_or_create_pointer_plus_expr (TREE_TYPE (TREE_TYPE (ptr)),
-					     ptr_sid, offset_sid,
-					     ctxt);
-	svalue_id element_ptr_sid
-	  = get_or_create_ptr_svalue (TREE_TYPE (ptr), element_rid);
-	set_value (lhs_rid, element_ptr_sid, ctxt);
-      }
-      break;
-
-    case POINTER_DIFF_EXPR:
-      {
-	/* e.g. "_1 = p_2(D) - q_3(D);".  */
-
-	/* TODO.  */
-
-	set_to_new_unknown_value (lhs_rid, TREE_TYPE (lhs), ctxt);
-      }
-      break;
-
-    case ADDR_EXPR:
-      {
-	/* LHS = &RHS;  */
-	svalue_id ptr_sid = get_rvalue (rhs1, ctxt);
-	set_value (lhs_rid, ptr_sid, ctxt);
-      }
-      break;
-
-    case MEM_REF:
-      {
-	region_id rhs_rid = get_lvalue (rhs1, ctxt);
-	svalue_id rhs_sid
-	  = get_region (rhs_rid)->get_value (*this, true, ctxt);
-	set_value (lhs_rid, rhs_sid, ctxt);
-      }
-      break;
-
-    case REAL_CST:
-    case INTEGER_CST:
-    case ARRAY_REF:
-      {
-	/* LHS = RHS;  */
-	svalue_id cst_sid = get_rvalue (rhs1, ctxt);
-	set_value (lhs_rid, cst_sid, ctxt);
-      }
-      break;
-
-    case FIX_TRUNC_EXPR:
-    case FLOAT_EXPR:
-    case NOP_EXPR:
-      // cast: TODO
-      // fall though for now
-    case SSA_NAME:
-    case VAR_DECL:
-    case PARM_DECL:
-      {
-	/* LHS = VAR;  */
-	region_id rhs_rid = get_lvalue (rhs1, ctxt);
-	copy_region (lhs_rid, rhs_rid, ctxt);
-      }
-      break;
-
-    case EQ_EXPR:
-    case GE_EXPR:
-    case LE_EXPR:
-    case NE_EXPR:
-    case GT_EXPR:
-    case LT_EXPR:
-      {
-	tree rhs2 = gimple_assign_rhs2 (assign);
-
-	// TODO: constraints between svalues
-	svalue_id rhs1_sid = get_rvalue (rhs1, ctxt);
-	svalue_id rhs2_sid = get_rvalue (rhs2, ctxt);
-
-	tristate t = eval_condition (rhs1_sid, op, rhs2_sid);
-	if (t.is_known ())
-	  set_value (lhs_rid,
-		     get_rvalue (t.is_true ()
-				 ? boolean_true_node
-				 : boolean_false_node,
-				 ctxt),
-		     ctxt);
-	else
-	  set_to_new_unknown_value (lhs_rid, TREE_TYPE (lhs), ctxt);
-      }
-      break;
-
-    case NEGATE_EXPR:
-    case BIT_NOT_EXPR:
-      {
-	// TODO: unary ops
-
-	// TODO: constant?
-
-	set_to_new_unknown_value (lhs_rid, TREE_TYPE (lhs), ctxt);
-      }
-      break;
-
-    case PLUS_EXPR:
-    case MINUS_EXPR:
-    case MULT_EXPR:
-    case TRUNC_DIV_EXPR:
-    case TRUNC_MOD_EXPR:
-    case LSHIFT_EXPR:
-    case RSHIFT_EXPR:
-    case BIT_IOR_EXPR:
-    case BIT_XOR_EXPR:
-    case BIT_AND_EXPR:
-    case MIN_EXPR:
-    case MAX_EXPR:
-      {
-	/* Binary ops.  */
-	tree rhs2 = gimple_assign_rhs2 (assign);
-
-	svalue_id rhs1_sid = get_rvalue (rhs1, ctxt);
-	svalue_id rhs2_sid = get_rvalue (rhs2, ctxt);
-
-	if (tree rhs1_cst = maybe_get_constant (rhs1_sid))
-	  if (tree rhs2_cst = maybe_get_constant (rhs2_sid))
-	    {
-	      tree result = fold_binary (op, TREE_TYPE (lhs),
-					 rhs1_cst, rhs2_cst);
-	      if (result && CONSTANT_CLASS_P (result))
-		{
-		  svalue_id result_sid
-		    = get_or_create_constant_svalue (result);
-		  set_value (lhs_rid, result_sid, ctxt);
-		  return;
-		}
-	    }
-	set_to_new_unknown_value (lhs_rid, TREE_TYPE (lhs), ctxt);
-      }
-      break;
-
-    case COMPONENT_REF:
-      {
-	/* LHS = op0.op1;  */
-	region_id child_rid = get_lvalue (rhs1, ctxt);
-	svalue_id child_sid
-	  = get_region (child_rid)->get_value (*this, true, ctxt);
-	set_value (lhs_rid, child_sid, ctxt);
-      }
-      break;
-    }
-}
-
-/* Update this model for the CALL stmt, using CTXT to report any
-   diagnostics - the first half.
-
-   Updates to the region_model that should be made *before* sm-states
-   are updated are done here; other updates to the region_model are done
-   in region_model::on_call_post.
-
-   Return true if the function call has unknown side effects (it wasn't
-   recognized and we don't have a body for it, or are unable to tell which
-   fndecl it is).  */
-
-bool
-region_model::on_call_pre (const gcall *call, region_model_context *ctxt)
-{
-  region_id lhs_rid;
-  tree lhs_type = NULL_TREE;
-  if (tree lhs = gimple_call_lhs (call))
-    {
-      lhs_rid = get_lvalue (lhs, ctxt);
-      lhs_type = TREE_TYPE (lhs);
-    }
-
-  /* Check for uses of poisoned values.
-     For now, special-case "free", to avoid warning about "use-after-free"
-     when "double free" would be more precise.  */
-  if (!is_special_named_call_p (call, "free", 1))
-    for (unsigned i = 0; i < gimple_call_num_args (call); i++)
-      check_for_poison (gimple_call_arg (call, i), ctxt);
-
-  bool unknown_side_effects = false;
-
-  if (tree callee_fndecl = get_fndecl_for_call (call, ctxt))
-    {
-      if (is_named_call_p (callee_fndecl, "malloc", call, 1))
-	{
-	  // TODO: capture size as a svalue?
-	  region_id new_rid = add_new_malloc_region ();
-	  if (!lhs_rid.null_p ())
-	    {
-	      svalue_id ptr_sid
-		= get_or_create_ptr_svalue (lhs_type, new_rid);
-	      set_value (lhs_rid, ptr_sid, ctxt);
-	    }
-	  return false;
-	}
-      else if (is_named_call_p (callee_fndecl, "__builtin_alloca", call, 1))
-	{
-	  region_id frame_rid = get_current_frame_id ();
-	  region_id new_rid
-	    = add_region (new symbolic_region (frame_rid, NULL_TREE, false));
-	  if (!lhs_rid.null_p ())
-	    {
-	      svalue_id ptr_sid
-		= get_or_create_ptr_svalue (lhs_type, new_rid);
-	      set_value (lhs_rid, ptr_sid, ctxt);
-	    }
-	  return false;
-	}
-      else if (gimple_call_builtin_p (call, BUILT_IN_EXPECT)
-	       || gimple_call_builtin_p (call, BUILT_IN_EXPECT_WITH_PROBABILITY)
-	       || gimple_call_internal_p (call, IFN_BUILTIN_EXPECT))
-	{
-	  /* __builtin_expect's return value is its initial argument.  */
-	  if (!lhs_rid.null_p ())
-	    {
-	      tree initial_arg = gimple_call_arg (call, 0);
-	      svalue_id sid = get_rvalue (initial_arg, ctxt);
-	      set_value (lhs_rid, sid, ctxt);
-	    }
-	  return false;
-	}
-      else if (is_named_call_p (callee_fndecl, "strlen", call, 1))
-	{
-	  region_id buf_rid = deref_rvalue (gimple_call_arg (call, 0), ctxt);
-	  svalue_id buf_sid
-	    = get_region (buf_rid)->get_value (*this, true, ctxt);
-	  if (tree cst_expr = maybe_get_constant (buf_sid))
-	    {
-	      if (TREE_CODE (cst_expr) == STRING_CST
-		  && !lhs_rid.null_p ())
-		{
-		  /* TREE_STRING_LENGTH is sizeof, not strlen.  */
-		  int sizeof_cst = TREE_STRING_LENGTH (cst_expr);
-		  int strlen_cst = sizeof_cst - 1;
-		  tree t_cst = build_int_cst (lhs_type, strlen_cst);
-		  svalue_id result_sid
-		    = get_or_create_constant_svalue (t_cst);
-		  set_value (lhs_rid, result_sid, ctxt);
-		  return false;
-		}
-	    }
-	  /* Otherwise an unknown value.  */
-	}
-      else if (is_named_call_p (callee_fndecl,
-				"__analyzer_dump_num_heap_regions", call, 0))
-	{
-	  /* Handle the builtin "__analyzer_dump_num_heap_regions" by emitting
-	     a warning (for use in DejaGnu tests).  */
-	  int num_heap_regions = 0;
-	  region_id heap_rid = get_root_region ()->ensure_heap_region (this);
-	  unsigned i;
-	  region *region;
-	  FOR_EACH_VEC_ELT (m_regions, i, region)
-	    if (region->get_parent () == heap_rid)
-	      num_heap_regions++;
-	  /* Use quotes to ensure the output isn't truncated.  */
-	  warning_at (call->location, 0,
-		      "num heap regions: %qi", num_heap_regions);
-	  return false;
-	}
-      else if (!fndecl_has_gimple_body_p (callee_fndecl)
-	       && !DECL_PURE_P (callee_fndecl))
-	unknown_side_effects = true;
-    }
-  else
-    unknown_side_effects = true;
-
-  /* Unknown return value.  */
-  if (!lhs_rid.null_p ())
-    set_to_new_unknown_value (lhs_rid, lhs_type, ctxt);
-
-  return unknown_side_effects;
-}
-
-/* Update this model for the CALL stmt, using CTXT to report any
-   diagnostics - the second half.
-
-   Updates to the region_model that should be made *after* sm-states
-   are updated are done here; other updates to the region_model are done
-   in region_model::on_call_pre.
-
-   If UNKNOWN_SIDE_EFFECTS is true, also call handle_unrecognized_call
-   to purge state.  */
-
-void
-region_model::on_call_post (const gcall *call,
-			    bool unknown_side_effects,
-			    region_model_context *ctxt)
-{
-  /* Update for "free" here, after sm-handling.
-
-     If the ptr points to an underlying heap region, delete the region,
-     poisoning pointers to it and regions within it.
-
-     We delay this until after sm-state has been updated so that the
-     sm-handling can transition all of the various casts of the pointer
-     to a "freed" state *before* we delete the related region here.
-
-     This has to be done here so that the sm-handling can use the fact
-     that they point to the same region to establish that they are equal
-     (in region_model::eval_condition_without_cm), and thus transition
-     all pointers to the region to the "freed" state together, regardless
-     of casts.  */
-  if (tree callee_fndecl = get_fndecl_for_call (call, ctxt))
-    if (is_named_call_p (callee_fndecl, "free", call, 1))
-      {
-	tree ptr = gimple_call_arg (call, 0);
-	svalue_id ptr_sid = get_rvalue (ptr, ctxt);
-	svalue *ptr_sval = get_svalue (ptr_sid);
-	if (region_svalue *ptr_to_region_sval
-	    = ptr_sval->dyn_cast_region_svalue ())
-	  {
-	    /* If the ptr points to an underlying heap region, delete it,
-	       poisoning pointers.  */
-	    region_id pointee_rid = ptr_to_region_sval->get_pointee ();
-	    region_id heap_rid = get_root_region ()->ensure_heap_region (this);
-	    if (!pointee_rid.null_p ()
-		&& get_region (pointee_rid)->get_parent () == heap_rid)
-	      {
-		purge_stats stats;
-		delete_region_and_descendents (pointee_rid,
-					       POISON_KIND_FREED,
-					       &stats, ctxt->get_logger ());
-		purge_unused_svalues (&stats, ctxt);
-		validate ();
-		// TODO: do anything with stats?
-	      }
-	  }
-	return;
-      }
-
-  if (unknown_side_effects)
-    handle_unrecognized_call (call, ctxt);
-}
-
-/* Helper class for region_model::handle_unrecognized_call, for keeping
-   track of all regions that are reachable, and, of those, which are
-   mutable.  */
-
-class reachable_regions
-{
-public:
-  reachable_regions (region_model *model)
-  : m_model (model), m_reachable_rids (), m_mutable_rids ()
-  {}
-
-  /* Lazily mark RID as being reachable, recursively adding regions
-     reachable from RID.  */
-  void add (region_id rid, bool is_mutable)
-  {
-    gcc_assert (!rid.null_p ());
-
-    unsigned idx = rid.as_int ();
-    /* Bail out if this region is already in the sets at the IS_MUTABLE
-       level of mutability.  */
-    if (!is_mutable && bitmap_bit_p (m_reachable_rids, idx))
-      return;
-    bitmap_set_bit (m_reachable_rids, idx);
-
-    if (is_mutable)
-      {
-	if (bitmap_bit_p (m_mutable_rids, idx))
-	  return;
-	else
-	  bitmap_set_bit (m_mutable_rids, idx);
-      }
-
-    /* If this region's value is a pointer, add the pointee.  */
-    region *reg = m_model->get_region (rid);
-    svalue_id sid = reg->get_value_direct ();
-    svalue *sval = m_model->get_svalue (sid);
-    if (sval)
-      if (region_svalue *ptr = sval->dyn_cast_region_svalue ())
-	{
-	  region_id pointee_rid = 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;
-	  add (pointee_rid, ptr_is_mutable);
-	}
-
-    /* Add descendents of this region.  */
-    region_id_set descendents (m_model);
-    m_model->get_descendents (rid, &descendents, region_id::null ());
-    for (unsigned i = 0; i < m_model->get_num_regions (); i++)
-      {
-	region_id iter_rid = region_id::from_int (i);
-	if (descendents.region_p (iter_rid))
-	  add (iter_rid, is_mutable);
-      }
-  }
-
-  bool mutable_p (region_id rid)
-  {
-    gcc_assert (!rid.null_p ());
-    return bitmap_bit_p (m_mutable_rids, rid.as_int ());
-  }
-
-private:
-  region_model *m_model;
-
-  /* The region ids already seen.  This has to be an auto_bitmap rather than
-     an auto_sbitmap as new regions can be created within the model during
-     the traversal.  */
-  auto_bitmap m_reachable_rids;
-
-  /* The region_ids that can be changed (accessed via non-const pointers).  */
-  auto_bitmap m_mutable_rids;
-};
-
-/* Handle a call CALL to a function with unknown behavior.
-
-   Traverse the regions in this model, determining what regions are
-   reachable from pointer arguments to CALL and from global variables,
-   recursively.
-
-   Set all reachable regions to new unknown values and purge sm-state
-   from their values, and from values that point to them.  */
-
-void
-region_model::handle_unrecognized_call (const gcall *call,
-					region_model_context *ctxt)
-{
-  tree fndecl = get_fndecl_for_call (call, ctxt);
-
-  reachable_regions reachable_regions (this);
-
-  /* Determine the reachable regions and their mutability.  */
-  {
-    /* Globals.  */
-    region_id globals_rid = get_globals_region_id ();
-    if (!globals_rid.null_p ())
-      reachable_regions.add (globals_rid, true);
-
-    /* Params that are pointers.  */
-    tree iter_param_types = NULL_TREE;
-    if (fndecl)
-      iter_param_types = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
-    for (unsigned arg_idx = 0; arg_idx < gimple_call_num_args (call); arg_idx++)
-      {
-	/* Track expected param type, where available.  */
-	tree param_type = NULL_TREE;
-	if (iter_param_types)
-	  {
-	    param_type = TREE_VALUE (iter_param_types);
-	    gcc_assert (param_type);
-	    iter_param_types = TREE_CHAIN (iter_param_types);
-	  }
-
-	tree parm = gimple_call_arg (call, arg_idx);
-	svalue_id parm_sid = get_rvalue (parm, ctxt);
-	svalue *parm_sval = get_svalue (parm_sid);
-	if (parm_sval)
-	  if (region_svalue *parm_ptr = parm_sval->dyn_cast_region_svalue ())
-	    {
-	      region_id pointee_rid = parm_ptr->get_pointee ();
-	      bool is_mutable = true;
-	      if (param_type
-		  && TREE_CODE (param_type) == POINTER_TYPE
-		  &&  TYPE_READONLY (TREE_TYPE (param_type)))
-		is_mutable = false;
-	      reachable_regions.add (pointee_rid, is_mutable);
-	    }
-	// FIXME: what about compound parms that contain ptrs?
-      }
-  }
-
-  /* OK: we now have all reachable regions.
-     Set them all to new unknown values.  */
-  for (unsigned i = 0; i < get_num_regions (); i++)
-    {
-      region_id iter_rid = region_id::from_int (i);
-      if (reachable_regions.mutable_p (iter_rid))
-	{
-	  region *reg = get_region (iter_rid);
-
-	  /* Purge any sm-state for any underlying svalue.  */
-	  svalue_id curr_sid = reg->get_value_direct ();
-	  if (!curr_sid.null_p ())
-	    ctxt->on_unknown_change (curr_sid);
-
-	  set_to_new_unknown_value (iter_rid,
-				    reg->get_type (),
-				    ctxt);
-	}
-    }
-
-  /* Purge sm-state for any remaining svalues that point to regions that
-     were reachable.  This helps suppress leak false-positives.
-
-     For example, if we had a malloc call that was cast to a "foo *" type,
-     we could have a temporary void * for the result of malloc which has its
-     own svalue, not reachable from the function call, but for which the
-     "foo *" svalue was reachable.  If we don't purge it, the temporary will
-     be reported as a leak.  */
-  int i;
-  svalue *svalue;
-  FOR_EACH_VEC_ELT (m_svalues, i, svalue)
-    if (region_svalue *ptr = svalue->dyn_cast_region_svalue ())
-      {
-	region_id pointee_rid = ptr->get_pointee ();
-	if (reachable_regions.mutable_p (pointee_rid))
-	  ctxt->on_unknown_change (svalue_id::from_int (i));
-      }
-
-  validate ();
-}
-
-/* Update this model for the RETURN_STMT, using CTXT to report any
-   diagnostics.  */
-
-void
-region_model::on_return (const greturn *return_stmt, region_model_context *ctxt)
-{
-  tree callee = get_current_function ()->decl;
-  tree lhs = DECL_RESULT (callee);
-  tree rhs = gimple_return_retval (return_stmt);
-
-  if (lhs && rhs)
-    copy_region (get_lvalue (lhs, ctxt), get_lvalue (rhs, ctxt), ctxt);
-}
-
-/* Update this model for a call and return of setjmp/sigsetjmp at CALL within
-   ENODE, using CTXT to report any diagnostics.
-
-   This is for the initial direct invocation of setjmp/sigsetjmp (which returns
-   0), as opposed to any second return due to longjmp/sigsetjmp.  */
-
-void
-region_model::on_setjmp (const gcall *call, const exploded_node *enode,
-			 region_model_context *ctxt)
-{
-  region_id buf_rid = deref_rvalue (gimple_call_arg (call, 0), ctxt);
-  region *buf = get_region (buf_rid);
-
-  /* Create a setjmp_svalue for this call and store it in BUF_RID's region.  */
-  if (buf)
-    {
-      setjmp_record r (enode, call);
-      svalue *sval = new setjmp_svalue (r, buf->get_type ());
-      svalue_id new_sid = add_svalue (sval);
-      set_value (buf_rid, new_sid, ctxt);
-    }
-
-  /* Direct calls to setjmp return 0.  */
-  if (tree lhs = gimple_call_lhs (call))
-    {
-      tree zero = build_int_cst (TREE_TYPE (lhs), 0);
-      svalue_id new_sid = get_or_create_constant_svalue (zero);
-      region_id lhs_rid = get_lvalue (lhs, ctxt);
-      set_value (lhs_rid, new_sid, ctxt);
-    }
-}
-
-/* Update this region_model for rewinding from a "longjmp" at LONGJMP_CALL
-   to a "setjmp" at SETJMP_CALL where the final stack depth should be
-   SETJMP_STACK_DEPTH.  Purge any stack frames, potentially reporting on
-   leaks to CTXT.  */
-
-void
-region_model::on_longjmp (const gcall *longjmp_call, const gcall *setjmp_call,
-			  int setjmp_stack_depth,
-			  region_model_context *ctxt)
-{
-  /* Evaluate the val, using the frame of the "longjmp".  */
-  tree fake_retval = gimple_call_arg (longjmp_call, 1);
-  svalue_id fake_retval_sid = get_rvalue (fake_retval, ctxt);
-
-  /* Pop any frames until we reach the stack depth of the function where
-     setjmp was called.  */
-  gcc_assert (get_stack_depth () >= setjmp_stack_depth);
-  while (get_stack_depth () > setjmp_stack_depth)
-    {
-      /* Don't purge unused svalues yet, as we're using fake_retval_sid.  */
-      pop_frame (region_id::null (), false, NULL, ctxt);
-    }
-
-  gcc_assert (get_stack_depth () == setjmp_stack_depth);
-
-  /* Assign to LHS of "setjmp" in new_state.  */
-  if (tree lhs = gimple_call_lhs (setjmp_call))
-    {
-      /* Passing 0 as the val to longjmp leads to setjmp returning 1.  */
-      tree t_zero = build_int_cst (TREE_TYPE (fake_retval), 0);
-      svalue_id zero_sid = get_or_create_constant_svalue (t_zero);
-      tristate eq_zero = eval_condition (fake_retval_sid, EQ_EXPR, zero_sid);
-      /* If we have 0, use 1.  */
-      if (eq_zero.is_true ())
-	{
-	  tree t_one = build_int_cst (TREE_TYPE (fake_retval), 1);
-	  svalue_id one_sid = get_or_create_constant_svalue (t_one);
-	  fake_retval_sid = one_sid;
-	}
-      else
-	{
-	  /* Otherwise note that the value is nonzero.  */
-	  m_constraints->add_constraint (fake_retval_sid, NE_EXPR, zero_sid);
-	}
-
-      region_id lhs_rid = get_lvalue (lhs, ctxt);
-      set_value (lhs_rid, fake_retval_sid, ctxt);
-    }
-
-  /* Now that we've assigned the fake_retval, we can purge the unused
-     svalues, which could detect leaks.  */
-  purge_unused_svalues (NULL, ctxt, NULL);
-  validate ();
-}
-
-/* Update this region_model for a phi stmt of the form
-     LHS = PHI <...RHS...>.
-   where RHS is for the appropriate edge.  */
-
-void
-region_model::handle_phi (const gphi *phi,
-			  tree lhs, tree rhs, bool is_back_edge,
-			  region_model_context *ctxt)
-{
-  /* For now, don't bother tracking the .MEM SSA names.  */
-  if (tree var = SSA_NAME_VAR (lhs))
-    if (TREE_CODE (var) == VAR_DECL)
-      if (VAR_DECL_IS_VIRTUAL_OPERAND (var))
-	return;
-
-  svalue_id rhs_sid = get_rvalue (rhs, ctxt);
-
-  if (is_back_edge && get_svalue (rhs_sid)->get_kind () != SK_UNKNOWN)
-    {
-      /* If we have a back edge, we probably have a loop.
-	 Use an unknown value, to avoid effectively unrolling the
-	 loop.
-	 To terminate, we need to avoid generating a series of
-	 models with an unbounded monotonically increasing number of
-	 redundant unknown values; hence we need to purge svalues
-	 before inserting the state into the exploded graph, to
-	 collect unused svalues.  */
-      set_to_new_unknown_value (get_lvalue (lhs, ctxt), TREE_TYPE (lhs), ctxt);
-    }
-  else
-    set_value (get_lvalue (lhs, ctxt), rhs_sid, ctxt);
-
-  if (ctxt)
-    ctxt->on_phi (phi, rhs);
-}
-
-/* Implementation of region_model::get_lvalue; the latter adds type-checking.
-
-   Get the id of the region for PV within this region_model,
-   emitting any diagnostics to CTXT.  */
-
-region_id
-region_model::get_lvalue_1 (path_var pv, region_model_context *ctxt)
-{
-  tree expr = pv.m_tree;
-
-  gcc_assert (expr);
-
-  switch (TREE_CODE (expr))
-    {
-    default:
-      return make_region_for_unexpected_tree_code (ctxt, expr,
-						   dump_location_t ());
-
-    case ARRAY_REF:
-      {
-	tree array = TREE_OPERAND (expr, 0);
-	tree index = TREE_OPERAND (expr, 1);
-#if 0
-	// TODO: operands 2 and 3, if present:
-	gcc_assert (TREE_OPERAND (expr, 2) == NULL_TREE);
-	gcc_assert (TREE_OPERAND (expr, 3) == NULL_TREE);
-#endif
-
-	region_id array_rid = get_lvalue (array, ctxt);
-	svalue_id index_sid = get_rvalue (index, ctxt);
-	region *base_array_reg = get_region (array_rid);
-	array_region *array_reg  = base_array_reg->dyn_cast_array_region ();
-	if (!array_reg)
-	  {
-	    /* Normally, array_rid ought to refer to an array_region, since
-	       array's type will be ARRAY_TYPE.  However, if we have an
-	       unexpected tree code for array, we could have a
-	       symbolic_region here.  If so, we're in error-handling. */
-	    gcc_assert (base_array_reg->get_type () == NULL_TREE);
-	    return make_region_for_unexpected_tree_code (ctxt, expr,
-							 dump_location_t ());
-	  }
-	return array_reg->get_element (this, array_rid, index_sid, ctxt);
-      }
-      break;
-
-    case BIT_FIELD_REF:
-      {
-	/* For now, create a view, as if a cast, ignoring the bit positions.  */
-	tree obj = TREE_OPERAND (expr, 0);
-	return get_or_create_view (get_lvalue (obj, ctxt), TREE_TYPE (expr),
-				   ctxt);
-      };
-      break;
-
-    case MEM_REF:
-      {
-	tree ptr = TREE_OPERAND (expr, 0);
-	tree offset = TREE_OPERAND (expr, 1);
-	svalue_id ptr_sid = get_rvalue (ptr, ctxt);
-	svalue_id offset_sid = get_rvalue (offset, ctxt);
-	return get_or_create_mem_ref (TREE_TYPE (expr), ptr_sid,
-				      offset_sid, ctxt);
-      }
-      break;
-
-    case VAR_DECL:
-      /* Handle globals.  */
-      if (is_global_var (expr))
-	{
-	  region_id globals_rid
-	    = get_root_region ()->ensure_globals_region (this);
-	  map_region *globals = get_region<map_region> (globals_rid);
-	  region_id var_rid = globals->get_or_create (this, globals_rid, expr,
-						      TREE_TYPE (expr), ctxt);
-	  return var_rid;
-	}
-
-      /* Fall through.  */
-
-    case SSA_NAME:
-    case PARM_DECL:
-    case RESULT_DECL:
-      {
-	gcc_assert (TREE_CODE (expr) == SSA_NAME
-		    || TREE_CODE (expr) == PARM_DECL
-		    || TREE_CODE (expr) == VAR_DECL
-		    || TREE_CODE (expr) == RESULT_DECL);
-
-	int stack_depth = pv.m_stack_depth;
-	stack_region *stack = get_root_region ()->get_stack_region (this);
-	gcc_assert (stack);
-	region_id frame_rid = stack->get_frame_rid (stack_depth);
-	frame_region *frame = get_region <frame_region> (frame_rid);
-	gcc_assert (frame);
-	region_id child_rid = frame->get_or_create (this, frame_rid, expr,
-						    TREE_TYPE (expr), ctxt);
-	return child_rid;
-      }
-
-    case COMPONENT_REF:
-      {
-	/* obj.field  */
-	tree obj = TREE_OPERAND (expr, 0);
-	tree field = TREE_OPERAND (expr, 1);
-	tree obj_type = TREE_TYPE (obj);
-	if (TREE_CODE (obj_type) != RECORD_TYPE
-	    && TREE_CODE (obj_type) != UNION_TYPE)
-	  return make_region_for_unexpected_tree_code (ctxt, obj_type,
-						       dump_location_t ());
-	region_id obj_rid = get_lvalue (obj, ctxt);
-	region_id struct_or_union_rid
-	  = get_or_create_view (obj_rid, TREE_TYPE (obj), ctxt);
-	return get_field_region (struct_or_union_rid, field, ctxt);
-      }
-      break;
-
-    case CONST_DECL:
-      {
-	tree cst_type = TREE_TYPE (expr);
-	region_id cst_rid = add_region_for_type (m_root_rid, cst_type, ctxt);
-	if (tree value = DECL_INITIAL (expr))
-	  {
-	    svalue_id sid = get_rvalue (value, ctxt);
-	    get_region (cst_rid)->set_value (*this, cst_rid, sid, ctxt);
-	  }
-	return cst_rid;
-      }
-      break;
-
-    case STRING_CST:
-      {
-	tree cst_type = TREE_TYPE (expr);
-	array_region *cst_region = new array_region (m_root_rid, cst_type);
-	region_id cst_rid = add_region (cst_region);
-	svalue_id cst_sid = get_or_create_constant_svalue (expr);
-	cst_region->set_value (*this, cst_rid, cst_sid, ctxt);
-	return cst_rid;
-      }
-      break;
-
-    case NOP_EXPR:
-    case VIEW_CONVERT_EXPR:
-      {
-	tree obj = TREE_OPERAND (expr, 0);
-	return get_or_create_view (get_lvalue (obj, ctxt), TREE_TYPE (expr),
-				   ctxt);
-      };
-      break;
-    }
-}
-
-/* If we see a tree code we don't know how to handle, rather than
-   ICE or generate bogus results, create a dummy region, and notify
-   CTXT so that it can mark the new state as being not properly
-   modelled.  The exploded graph can then stop exploring that path,
-   since any diagnostics we might issue will have questionable
-   validity.  */
-
-region_id
-region_model::make_region_for_unexpected_tree_code (region_model_context *ctxt,
-						    tree t,
-						    const dump_location_t &loc)
-{
-  gcc_assert (ctxt);
-  region_id new_rid
-    = add_region (new symbolic_region (m_root_rid, NULL_TREE, false));
-  ctxt->on_unexpected_tree_code (t, loc);
-  return new_rid;
-}
-
-/* Assert that SRC_TYPE can be converted to DST_TYPE as a no-op.  */
-
-static void
-assert_compat_types (tree src_type, tree dst_type)
-{
-  if (src_type && dst_type && !VOID_TYPE_P (dst_type))
-    gcc_checking_assert (useless_type_conversion_p (src_type, dst_type));
-}
-
-/* Get the id of the region for PV within this region_model,
-   emitting any diagnostics to CTXT.  */
-
-region_id
-region_model::get_lvalue (path_var pv, region_model_context *ctxt)
-{
-  if (pv.m_tree == NULL_TREE)
-    return region_id::null ();
-
-  region_id result_rid = get_lvalue_1 (pv, ctxt);
-  assert_compat_types (get_region (result_rid)->get_type (),
-		       TREE_TYPE (pv.m_tree));
-  return result_rid;
-}
-
-/* Get the region_id for EXPR within this region_model (assuming the most
-   recent stack frame if it's a local).  */
-
-region_id
-region_model::get_lvalue (tree expr, region_model_context *ctxt)
-{
-  return get_lvalue (path_var (expr, get_stack_depth () - 1), ctxt);
-}
-
-/* Implementation of region_model::get_rvalue; the latter adds type-checking.
-
-   Get the value of PV within this region_model,
-   emitting any diagnostics to CTXT.  */
-
-svalue_id
-region_model::get_rvalue_1 (path_var pv, region_model_context *ctxt)
-{
-  gcc_assert (pv.m_tree);
-
-  switch (TREE_CODE (pv.m_tree))
-    {
-    default:
-      {
-	svalue *unknown_sval = new unknown_svalue (TREE_TYPE (pv.m_tree));
-	return add_svalue (unknown_sval);
-      }
-      break;
-
-    case ADDR_EXPR:
-      {
-	/* "&EXPR".  */
-	tree expr = pv.m_tree;
-	tree op0 = TREE_OPERAND (expr, 0);
-	if (TREE_CODE (op0) == FUNCTION_DECL)
-	  return get_svalue_for_fndecl (TREE_TYPE (expr), op0, ctxt);
-	else if (TREE_CODE (op0) == LABEL_DECL)
-	  return get_svalue_for_label (TREE_TYPE (expr), op0, ctxt);
-	region_id expr_rid = get_lvalue (op0, ctxt);
-	return get_or_create_ptr_svalue (TREE_TYPE (expr), expr_rid);
-      }
-      break;
-
-    case ARRAY_REF:
-      {
-	region_id element_rid = get_lvalue (pv, ctxt);
-	return get_region (element_rid)->get_value (*this, true, ctxt);
-      }
-
-    case INTEGER_CST:
-    case REAL_CST:
-    case STRING_CST:
-      return get_or_create_constant_svalue (pv.m_tree);
-
-    case COMPONENT_REF:
-    case MEM_REF:
-    case SSA_NAME:
-    case VAR_DECL:
-    case PARM_DECL:
-    case RESULT_DECL:
-      {
-	region_id var_rid = get_lvalue (pv, ctxt);
-	return get_region (var_rid)->get_value (*this, true, ctxt);
-      }
-    }
-}
-
-/* Get the value of PV within this region_model,
-   emitting any diagnostics to CTXT.  */
-
-svalue_id
-region_model::get_rvalue (path_var pv, region_model_context *ctxt)
-{
-  if (pv.m_tree == NULL_TREE)
-    return svalue_id::null ();
-  svalue_id result_sid = get_rvalue_1 (pv, ctxt);
-
-  assert_compat_types (get_svalue (result_sid)->get_type (),
-		       TREE_TYPE (pv.m_tree));
-
-  return result_sid;
-}
-
-/* Get the value of EXPR within this region_model (assuming the most
-   recent stack frame if it's a local).  */
-
-svalue_id
-region_model::get_rvalue (tree expr, region_model_context *ctxt)
-{
-  return get_rvalue (path_var (expr, get_stack_depth () - 1), ctxt);
-}
-
-/* Return an svalue_id for a pointer to RID of type PTR_TYPE, reusing
-   existing pointer values if one is available.  */
-
-svalue_id
-region_model::get_or_create_ptr_svalue (tree ptr_type, region_id rid)
-{
-  /* Reuse existing region_svalue, if one of the right type is
-     available.  */
-  /* In theory we could stash a svalue_id in "region", but differing
-     pointer types muddles things.
-     For now, just do a linear search through all existing svalues.  */
-  int i;
-  svalue *svalue;
-  FOR_EACH_VEC_ELT (m_svalues, i, svalue)
-    if (region_svalue *ptr_svalue = svalue->dyn_cast_region_svalue ())
-      if (ptr_svalue->get_pointee () == rid
-	  && ptr_svalue->get_type () == ptr_type)
-	return svalue_id::from_int (i);
-
-  return add_svalue (new region_svalue (ptr_type, rid));
-}
-
-/* Return an svalue_id for a constant_svalue for CST_EXPR,
-   creating the constant_svalue if necessary.
-   The constant_svalue instances are reused, based on pointer equality
-   of trees  */
-
-svalue_id
-region_model::get_or_create_constant_svalue (tree cst_expr)
-{
-  gcc_assert (cst_expr);
-
-  /* Reuse one if it already exists.  */
-  // TODO: maybe store a map, rather than do linear search?
-  int i;
-  svalue *svalue;
-  FOR_EACH_VEC_ELT (m_svalues, i, svalue)
-    if (svalue->maybe_get_constant () == cst_expr)
-      return svalue_id::from_int (i);
-
-  svalue_id cst_sid = add_svalue (new constant_svalue (cst_expr));
-  return cst_sid;
-}
-
-/* Return an svalue_id for a region_svalue for FNDECL,
-   creating the function_region if necessary.  */
-
-svalue_id
-region_model::get_svalue_for_fndecl (tree ptr_type, tree fndecl,
-				     region_model_context *ctxt)
-{
-  gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
-  region_id function_rid = get_region_for_fndecl (fndecl, ctxt);
-  return get_or_create_ptr_svalue (ptr_type, function_rid);
-}
-
-/* Return a region_id for a function_region for FNDECL,
-   creating it if necessary.  */
-
-region_id
-region_model::get_region_for_fndecl (tree fndecl,
-				     region_model_context *ctxt)
-{
-  gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
-
-  region_id code_rid = get_root_region ()->ensure_code_region (this);
-  code_region *code = get_root_region ()->get_code_region (this);
-
-  return code->get_or_create (this, code_rid, fndecl, TREE_TYPE (fndecl),
-			      ctxt);
-}
-
-/* Return an svalue_id for a region_svalue for LABEL,
-   creating the label_region if necessary.  */
-
-svalue_id
-region_model::get_svalue_for_label (tree ptr_type, tree label,
-				    region_model_context *ctxt)
-{
-  gcc_assert (TREE_CODE (label) == LABEL_DECL);
-  region_id label_rid = get_region_for_label (label, ctxt);
-  return get_or_create_ptr_svalue (ptr_type, label_rid);
-}
-
-/* Return a region_id for a label_region for LABEL,
-   creating it if necessary.  */
-
-region_id
-region_model::get_region_for_label (tree label,
-				    region_model_context *ctxt)
-{
-  gcc_assert (TREE_CODE (label) == LABEL_DECL);
-
-  tree fndecl = DECL_CONTEXT (label);
-  gcc_assert (fndecl && TREE_CODE (fndecl) == FUNCTION_DECL);
-
-  region_id func_rid = get_region_for_fndecl (fndecl, ctxt);
-  function_region *func_reg = get_region <function_region> (func_rid);
-  return func_reg->get_or_create (this, func_rid, label, TREE_TYPE (label),
-				  ctxt);
-}
-
-/* Build a cast of SRC_EXPR to DST_TYPE, or return NULL_TREE.
-
-   Adapted from gcc::jit::playback::context::build_cast, which in turn is
-   adapted from
-     - c/c-typeck.c:build_c_cast
-     - c/c-convert.c: convert
-     - convert.h
-   Only some kinds of cast are currently supported here.  */
-
-static tree
-build_cast (tree dst_type, tree src_expr)
-{
-  tree result = targetm.convert_to_type (dst_type, src_expr);
-  if (result)
-    return result;
-  enum tree_code dst_code = TREE_CODE (dst_type);
-  switch (dst_code)
-    {
-    case INTEGER_TYPE:
-    case ENUMERAL_TYPE:
-      result = convert_to_integer (dst_type, src_expr);
-      goto maybe_fold;
-
-    case BOOLEAN_TYPE:
-      /* Compare with c_objc_common_truthvalue_conversion and
-	 c_common_truthvalue_conversion. */
-      /* For now, convert to: (src_expr != 0)  */
-      result = build2 (NE_EXPR, dst_type,
-		       src_expr,
-		       build_int_cst (TREE_TYPE (src_expr), 0));
-      goto maybe_fold;
-
-    case REAL_TYPE:
-      result = convert_to_real (dst_type, src_expr);
-      goto maybe_fold;
-
-    case POINTER_TYPE:
-      result = build1 (NOP_EXPR, dst_type, src_expr);
-      goto maybe_fold;
-
-    default:
-      return NULL_TREE;
-
-    maybe_fold:
-      if (TREE_CODE (result) != C_MAYBE_CONST_EXPR)
-	result = fold (result);
-      return result;
-    }
-}
-
-/* If the type of SID's underlying value is DST_TYPE, return SID.
-   Otherwise, attempt to create (or reuse) an svalue representing an access
-   of SID as a DST_TYPE and return that value's svalue_id.  */
-
-svalue_id
-region_model::maybe_cast_1 (tree dst_type, svalue_id sid)
-{
-  svalue *sval = get_svalue (sid);
-  tree src_type = sval->get_type ();
-  if (src_type == dst_type)
-    return sid;
-
-  if (POINTER_TYPE_P (dst_type)
-      || POINTER_TYPE_P (src_type))
-    {
-      /* Pointer to region.  */
-      if (region_svalue *ptr_sval = sval->dyn_cast_region_svalue ())
-	return get_or_create_ptr_svalue (dst_type, ptr_sval->get_pointee ());
-
-      /* Unknown pointer?   Get or create a new unknown pointer of the
-	 correct type, preserving the equality between the pointers.  */
-      if (sval->dyn_cast_unknown_svalue ())
-	{
-	  equiv_class &ec = m_constraints->get_equiv_class (sid);
-
-	  /* Look for an existing pointer of the correct type within the EC.  */
-	  int i;
-	  svalue_id *equiv_sid;
-	  FOR_EACH_VEC_ELT (ec.m_vars, i, equiv_sid)
-	    {
-	      svalue *equiv_val = get_svalue (*equiv_sid);
-	      if (equiv_val->get_type () == dst_type)
-		return *equiv_sid;
-	    }
-
-	  /* Otherwise, create a new unknown pointer of the correct type.  */
-	  svalue *unknown_sval = new unknown_svalue (dst_type);
-	  svalue_id new_ptr_sid = add_svalue (unknown_sval);
-	  m_constraints->add_constraint (sid, EQ_EXPR, new_ptr_sid);
-	  return new_ptr_sid;
-	}
-    }
-
-  /* Attempt to cast constants.  */
-  if (tree src_cst = sval->maybe_get_constant ())
-    {
-      if (tree dst = build_cast (dst_type, src_cst))
-	if (CONSTANT_CLASS_P (dst))
-	  return get_or_create_constant_svalue (dst);
-    }
-
-  /* Otherwise, return a new unknown value.  */
-  svalue *unknown_sval = new unknown_svalue (dst_type);
-  return add_svalue (unknown_sval);
-}
-
-/* If the type of SID's underlying value is DST_TYPE, return SID.
-   Otherwise, attempt to create (or reuse) an svalue representing an access
-   of SID as a DST_TYPE and return that value's svalue_id.
-
-   If the result != SID, then call CTXT's on_cast vfunc (if CTXT is non-NULL),
-   so that sm-state can be propagated from SID to the result.  */
-
-svalue_id
-region_model::maybe_cast (tree dst_type, svalue_id sid,
-			  region_model_context *ctxt)
-{
-  svalue_id result = maybe_cast_1 (dst_type, sid);
-  if (result != sid)
-    if (ctxt)
-      {
-	/* Notify ctxt about a cast, so any sm-state can be copied.  */
-	ctxt->on_cast (sid, result);
-      }
-  return result;
-}
-
-/* Ensure that the region for OBJ_RID has a child region for FIELD;
-   return the child region's region_id.  */
-
-region_id
-region_model::get_field_region (region_id struct_or_union_rid, tree field,
-				region_model_context *ctxt)
-{
-  struct_or_union_region *sou_reg
-    = get_region<struct_or_union_region> (struct_or_union_rid);
-
-  /* Inherit constness from parent type.  */
-  const int qual_mask = TYPE_QUAL_CONST;
-  int sou_quals = TYPE_QUALS (sou_reg->get_type ()) & qual_mask;
-  tree field_type = TREE_TYPE (field);
-  tree field_type_with_quals = build_qualified_type (field_type, sou_quals);
-
-  // TODO: maybe convert to a vfunc?
-  if (sou_reg->get_kind () == RK_UNION)
-    {
-      /* Union.
-	 Get a view of the union as a whole, with the type of the field.  */
-      region_id view_rid
-	= get_or_create_view (struct_or_union_rid, field_type_with_quals, ctxt);
-      return view_rid;
-    }
-  else
-    {
-      /* Struct.  */
-      region_id child_rid
-	= sou_reg->get_or_create (this, struct_or_union_rid, field,
-				  field_type_with_quals, ctxt);
-      return child_rid;
-    }
-}
-
-/* Get a region_id for referencing PTR_SID, creating a region if need be, and
-   potentially generating warnings via CTXT.  */
-
-region_id
-region_model::deref_rvalue (svalue_id ptr_sid, region_model_context *ctxt)
-{
-  gcc_assert (!ptr_sid.null_p ());
-  svalue *ptr_svalue = get_svalue (ptr_sid);
-  gcc_assert (ptr_svalue);
-
-  switch (ptr_svalue->get_kind ())
-    {
-    case SK_REGION:
-      {
-	region_svalue *region_sval = as_a <region_svalue *> (ptr_svalue);
-	return region_sval->get_pointee ();
-      }
-
-    case SK_CONSTANT:
-      goto create_symbolic_region;
-
-    case SK_POISONED:
-      {
-	if (ctxt)
-	  if (tree ptr = get_representative_tree (ptr_sid))
-	    {
-	      poisoned_svalue *poisoned_sval
-		= as_a <poisoned_svalue *> (ptr_svalue);
-	      enum poison_kind pkind = poisoned_sval->get_poison_kind ();
-	      ctxt->warn (new poisoned_value_diagnostic (ptr, pkind));
-	    }
-	goto create_symbolic_region;
-      }
-
-    case SK_UNKNOWN:
-      {
-      create_symbolic_region:
-	/* We need a symbolic_region to represent this unknown region.
-	   We don't know if it on the heap, stack, or a global,
-	   so use the root region as parent.  */
-	region_id new_rid
-	  = add_region (new symbolic_region (m_root_rid, NULL_TREE, false));
-
-	/* We need to write the region back into the pointer,
-	   or we'll get a new, different region each time.
-	   We do this by changing the meaning of ptr_sid, replacing
-	   the unknown value with the ptr to the new region.
-	   We replace the meaning of the ID rather than simply writing
-	   to PTR's lvalue since there could be several places sharing
-	   the same unknown ptr value.  */
-	svalue *ptr_val
-	  = new region_svalue (ptr_svalue->get_type (), new_rid);
-	replace_svalue (ptr_sid, ptr_val);
-
-	return new_rid;
-      }
-
-    case SK_SETJMP:
-      goto create_symbolic_region;
-    }
-
-  gcc_unreachable ();
-}
-
-/* Get a region_id for referencing PTR, creating a region if need be, and
-   potentially generating warnings via CTXT.  */
-
-region_id
-region_model::deref_rvalue (tree ptr, region_model_context *ctxt)
-{
-  svalue_id ptr_sid = get_rvalue (ptr, ctxt);
-  return deref_rvalue (ptr_sid, ctxt);
-}
-
-/* Set the value of the region given by LHS_RID to the value given
-   by RHS_SID.  */
-
-void
-region_model::set_value (region_id lhs_rid, svalue_id rhs_sid,
-			 region_model_context *ctxt)
-{
-  gcc_assert (!lhs_rid.null_p ());
-  gcc_assert (!rhs_sid.null_p ());
-  get_region (lhs_rid)->set_value (*this, lhs_rid, rhs_sid, ctxt);
-}
-
-/* Set the value of the region given by LHS to the value given
-   by RHS.  */
-
-void
-region_model::set_value (tree lhs, tree rhs, region_model_context *ctxt)
-{
-  region_id lhs_rid = get_lvalue (lhs, ctxt);
-  svalue_id rhs_sid = get_rvalue (rhs, ctxt);
-  gcc_assert (!lhs_rid.null_p ());
-  gcc_assert (!rhs_sid.null_p ());
-  set_value (lhs_rid, rhs_sid, ctxt);
-}
-
-/* Determine what is known about the condition "LHS_SID OP RHS_SID" within
-   this model.  */
-
-tristate
-region_model::eval_condition (svalue_id lhs_sid,
-			      enum tree_code op,
-			      svalue_id rhs_sid) const
-{
-  svalue *lhs = get_svalue (lhs_sid);
-  svalue *rhs = get_svalue (rhs_sid);
-
-  /* For now, make no attempt to capture constraints on floating-point
-     values.  */
-  if ((lhs->get_type () && FLOAT_TYPE_P (lhs->get_type ()))
-      || (rhs->get_type () && FLOAT_TYPE_P (rhs->get_type ())))
-    return tristate::unknown ();
-
-  tristate ts = eval_condition_without_cm (lhs_sid, op, rhs_sid);
-
-  if (ts.is_known ())
-    return ts;
-
-  /* Otherwise, try constraints.  */
-  return m_constraints->eval_condition (lhs_sid, op, rhs_sid);
-}
-
-/* Determine what is known about the condition "LHS_SID OP RHS_SID" within
-   this model, without resorting to the constraint_manager.
-
-   This is exposed so that impl_region_model_context::on_state_leak can
-   check for equality part-way through region_model::purge_unused_svalues
-   without risking creating new ECs.  */
-
-tristate
-region_model::eval_condition_without_cm (svalue_id lhs_sid,
-					 enum tree_code op,
-					 svalue_id rhs_sid) const
-{
-  svalue *lhs = get_svalue (lhs_sid);
-  svalue *rhs = get_svalue (rhs_sid);
-  gcc_assert (lhs);
-  gcc_assert (rhs);
-
-  /* See what we know based on the values.  */
-  if (lhs && rhs)
-    {
-      /* For now, make no attempt to capture constraints on floating-point
-	 values.  */
-      if ((lhs->get_type () && FLOAT_TYPE_P (lhs->get_type ()))
-	  || (rhs->get_type () && FLOAT_TYPE_P (rhs->get_type ())))
-	return tristate::unknown ();
-
-      if (lhs == rhs)
-	{
-	  /* If we have the same svalue, then we have equality
-	     (apart from NaN-handling).
-	     TODO: should this definitely be the case for poisoned values?  */
-	  switch (op)
-	    {
-	    case EQ_EXPR:
-	    case GE_EXPR:
-	    case LE_EXPR:
-	      return tristate::TS_TRUE;
-
-	    case NE_EXPR:
-	    case GT_EXPR:
-	    case LT_EXPR:
-	      return tristate::TS_FALSE;
-
-	    default:
-	      /* For other ops, use the logic below.  */
-	      break;
-	    }
-	}
-
-      /* If we have a pair of region_svalues, compare them.  */
-      if (region_svalue *lhs_ptr = lhs->dyn_cast_region_svalue ())
-	if (region_svalue *rhs_ptr = rhs->dyn_cast_region_svalue ())
-	  {
-	    tristate res = region_svalue::eval_condition (lhs_ptr, op, rhs_ptr);
-	    if (res.is_known ())
-	      return res;
-	    /* Otherwise, only known through constraints.  */
-	  }
-
-      /* If we have a pair of constants, compare them.  */
-      if (constant_svalue *cst_lhs = lhs->dyn_cast_constant_svalue ())
-	if (constant_svalue *cst_rhs = rhs->dyn_cast_constant_svalue ())
-	  return constant_svalue::eval_condition (cst_lhs, op, cst_rhs);
-
-      /* Handle comparison of a region_svalue against zero.  */
-      if (region_svalue *ptr = lhs->dyn_cast_region_svalue ())
-	if (constant_svalue *cst_rhs = rhs->dyn_cast_constant_svalue ())
-	  if (zerop (cst_rhs->get_constant ()))
-	    {
-	      /* A region_svalue is a non-NULL pointer, except in certain
-		 special cases (see the comment for region::non_null_p.  */
-	      region *pointee = get_region (ptr->get_pointee ());
-	      if (pointee->non_null_p (*this))
-		{
-		  switch (op)
-		    {
-		    default:
-		      gcc_unreachable ();
-
-		    case EQ_EXPR:
-		    case GE_EXPR:
-		    case LE_EXPR:
-		      return tristate::TS_FALSE;
-
-		    case NE_EXPR:
-		    case GT_EXPR:
-		    case LT_EXPR:
-		      return tristate::TS_TRUE;
-		    }
-		}
-	    }
-    }
-
-  return tristate::TS_UNKNOWN;
-}
-
-/* Attempt to add the constraint "LHS OP RHS" to this region_model.
-   If it is consistent with existing constraints, add it, and return true.
-   Return false if it contradicts existing constraints.
-   Use CTXT for reporting any diagnostics associated with the accesses.  */
-
-bool
-region_model::add_constraint (tree lhs, enum tree_code op, tree rhs,
-			      region_model_context *ctxt)
-{
-  /* For now, make no attempt to capture constraints on floating-point
-     values.  */
-  if (FLOAT_TYPE_P (TREE_TYPE (lhs)) || FLOAT_TYPE_P (TREE_TYPE (rhs)))
-    return true;
-
-  svalue_id lhs_sid = get_rvalue (lhs, ctxt);
-  svalue_id rhs_sid = get_rvalue (rhs, ctxt);
-
-  tristate t_cond = eval_condition (lhs_sid, op, rhs_sid);
-
-  /* If we already have the condition, do nothing.  */
-  if (t_cond.is_true ())
-    return true;
-
-  /* Reject a constraint that would contradict existing knowledge, as
-     unsatisfiable.  */
-  if (t_cond.is_false ())
-    return false;
-
-  /* Store the constraint.  */
-  m_constraints->add_constraint (lhs_sid, op, rhs_sid);
-
-  add_any_constraints_from_ssa_def_stmt (lhs, op, rhs, ctxt);
-
-  /* If we now know a symbolic_region is non-NULL, clear its
-     m_possibly_null.  */
-  if (zerop (rhs) && op == NE_EXPR)
-    if (region_svalue *ptr = get_svalue (lhs_sid)->dyn_cast_region_svalue ())
-      {
-	region *pointee = get_region (ptr->get_pointee ());
-	if (symbolic_region *sym_reg = pointee->dyn_cast_symbolic_region ())
-	  sym_reg->m_possibly_null = false;
-      }
-
-  /* Notify the context, if any.  This exists so that the state machines
-     in a program_state can be notified about the condition, and so can
-     set sm-state for e.g. unchecked->checked, both for cfg-edges, and
-     when synthesizing constraints as above.  */
-  if (ctxt)
-    ctxt->on_condition (lhs, op, rhs);
-
-  return true;
-}
-
-/* Subroutine of region_model::add_constraint for handling optimized
-   && and || conditionals.
-
-   If we have an SSA_NAME for a boolean compared against 0,
-   look at anything implied by the def stmt and call add_constraint
-   for it (which could recurse).
-
-   For example, if we have
-      _1 = p_6 == 0B;
-      _2 = p_8 == 0B
-      _3 = _1 | _2
-    and add the constraint
-      (_3 == 0),
-    then the def stmt for _3 implies that _1 and _2 are both false,
-    and hence we can add the constraints:
-      p_6 != 0B
-      p_8 != 0B.  */
-
-void
-region_model::add_any_constraints_from_ssa_def_stmt (tree lhs,
-						     enum tree_code op,
-						     tree rhs,
-						     region_model_context *ctxt)
-{
-  if (TREE_CODE (lhs) != SSA_NAME)
-    return;
-
-  if (!zerop (rhs))
-    return;
-
-  if (op != NE_EXPR && op != EQ_EXPR)
-    return;
-
-  gimple *def_stmt = SSA_NAME_DEF_STMT (lhs);
-  if (const gassign *assign = dyn_cast<gassign *> (def_stmt))
-    add_any_constraints_from_gassign (op, rhs, assign, ctxt);
-  else if (gcall *call = dyn_cast<gcall *> (def_stmt))
-    add_any_constraints_from_gcall (op, rhs, call, ctxt);
-}
-
-/* Add any constraints for an SSA_NAME defined by ASSIGN
-   where the result OP RHS.  */
-
-void
-region_model::add_any_constraints_from_gassign (enum tree_code op,
-						tree rhs,
-						const gassign *assign,
-						region_model_context *ctxt)
-{
-  /* We have either
-     - "LHS != false" (i.e. LHS is true), or
-     - "LHS == false" (i.e. LHS is false).  */
-  bool is_true = op == NE_EXPR;
-
-  enum tree_code rhs_code = gimple_assign_rhs_code (assign);
-
-  switch (rhs_code)
-    {
-    default:
-      break;
-
-    case NOP_EXPR:
-      {
-	add_constraint (gimple_assign_rhs1 (assign), op, rhs, ctxt);
-      }
-      break;
-
-    case BIT_AND_EXPR:
-      {
-	if (is_true)
-	  {
-	    /* ...and "LHS == (rhs1 & rhs2) i.e. "(rhs1 & rhs2)" is true
-	       then both rhs1 and rhs2 must be true.  */
-	    tree rhs1 = gimple_assign_rhs1 (assign);
-	    tree rhs2 = gimple_assign_rhs2 (assign);
-	    add_constraint (rhs1, NE_EXPR, boolean_false_node, ctxt);
-	    add_constraint (rhs2, NE_EXPR, boolean_false_node, ctxt);
-	  }
-      }
-      break;
-
-    case BIT_IOR_EXPR:
-      {
-	if (!is_true)
-	  {
-	    /* ...and "LHS == (rhs1 | rhs2)
-	       i.e. "(rhs1 | rhs2)" is false
-	       then both rhs1 and rhs2 must be false.  */
-	    tree rhs1 = gimple_assign_rhs1 (assign);
-	    tree rhs2 = gimple_assign_rhs2 (assign);
-	    add_constraint (rhs1, EQ_EXPR, boolean_false_node, ctxt);
-	    add_constraint (rhs2, EQ_EXPR, boolean_false_node, ctxt);
-	  }
-      }
-      break;
-
-    case EQ_EXPR:
-    case NE_EXPR:
-      {
-	/* ...and "LHS == (rhs1 OP rhs2)"
-	   then rhs1 OP rhs2 must have the same logical value as LHS.  */
-	tree rhs1 = gimple_assign_rhs1 (assign);
-	tree rhs2 = gimple_assign_rhs2 (assign);
-	if (!is_true)
-	  rhs_code
-	    = invert_tree_comparison (rhs_code, false /* honor_nans */);
-	add_constraint (rhs1, rhs_code, rhs2, ctxt);
-      }
-      break;
-    }
-}
-
-/* Add any constraints for an SSA_NAME defined by CALL
-   where the result OP RHS.  */
-
-void
-region_model::add_any_constraints_from_gcall (enum tree_code op,
-					      tree rhs,
-					      const gcall *call,
-					      region_model_context *ctxt)
-{
-  if (gimple_call_builtin_p (call, BUILT_IN_EXPECT)
-      || gimple_call_builtin_p (call, BUILT_IN_EXPECT_WITH_PROBABILITY)
-      || gimple_call_internal_p (call, IFN_BUILTIN_EXPECT))
-    {
-      /* __builtin_expect's return value is its initial argument.  */
-      add_constraint (gimple_call_arg (call, 0), op, rhs, ctxt);
-    }
-}
-
-/* Determine what is known about the condition "LHS OP RHS" within
-   this model.
-   Use CTXT for reporting any diagnostics associated with the accesses.  */
-
-tristate
-region_model::eval_condition (tree lhs,
-			      enum tree_code op,
-			      tree rhs,
-			      region_model_context *ctxt)
-{
-  /* For now, make no attempt to model constraints on floating-point
-     values.  */
-  if (FLOAT_TYPE_P (TREE_TYPE (lhs)) || FLOAT_TYPE_P (TREE_TYPE (rhs)))
-    return tristate::unknown ();
-
-  return eval_condition (get_rvalue (lhs, ctxt), op, get_rvalue (rhs, ctxt));
-}
-
-/* If SID is a constant value, return the underlying tree constant.
-   Otherwise, return NULL_TREE.  */
-
-tree
-region_model::maybe_get_constant (svalue_id sid) const
-{
-  gcc_assert (!sid.null_p ());
-  svalue *sval = get_svalue (sid);
-  return sval->maybe_get_constant ();
-}
-
-/* Create a new child region of the heap (creating the heap region if
-   necessary).
-   Return the region_id of the new child region.  */
-
-region_id
-region_model::add_new_malloc_region ()
-{
-  region_id heap_rid
-    = get_root_region ()->ensure_heap_region (this);
-  return add_region (new symbolic_region (heap_rid, NULL_TREE, true));
-}
-
-/* Attempt to return a tree that represents SID, or return NULL_TREE.  */
-
-tree
-region_model::get_representative_tree (svalue_id sid) const
-{
-  if (sid.null_p ())
-    return NULL_TREE;
-
-  /* Find the first region that stores the value (e.g. a local) and
-     generate a representative tree for it.  */
-  unsigned i;
-  region *region;
-  FOR_EACH_VEC_ELT (m_regions, i, region)
-    if (sid == region->get_value_direct ())
-      {
-	path_var pv = get_representative_path_var (region_id::from_int (i));
-	if (pv.m_tree)
-	  return pv.m_tree;
-      }
-
-  /* Handle string literals and various other pointers.  */
-  svalue *sval = get_svalue (sid);
-  if (region_svalue *ptr_sval = sval->dyn_cast_region_svalue ())
-    {
-      region_id rid = ptr_sval->get_pointee ();
-      path_var pv = get_representative_path_var (rid);
-      if (pv.m_tree)
-	return build1 (ADDR_EXPR,
-		       TREE_TYPE (sval->get_type ()),
-		       pv.m_tree);
-    }
-
-  return maybe_get_constant (sid);
-}
-
-/* Attempt to return a path_var that represents the region, or return
-   the NULL path_var.
-   For example, a region for a field of a local would be a path_var
-   wrapping a COMPONENT_REF.  */
-
-path_var
-region_model::get_representative_path_var (region_id rid) const
-{
-  region *reg = get_region (rid);
-  region *parent_reg = get_region (reg->get_parent ());
-  region_id stack_rid = get_stack_region_id ();
-  if (!stack_rid.null_p ())
-    if (parent_reg && parent_reg->get_parent () == stack_rid)
-      {
-	frame_region *parent_frame = (frame_region *)parent_reg;
-	tree t = parent_frame->get_tree_for_child_region (rid);
-	return path_var (t, parent_frame->get_depth ());
-    }
-  if (reg->get_parent () == get_globals_region_id ())
-    {
-      map_region *globals = get_root_region ()->get_globals_region (this);
-      if (globals)
-	return path_var (globals->get_tree_for_child_region (rid), -1);
-    }
-
-  /* Handle e.g. fields of a local by recursing.  */
-  region_id parent_rid = reg->get_parent ();
-  if (parent_reg)
-    {
-      if (reg->is_view_p ())
-	{
-	  path_var parent_pv = get_representative_path_var (parent_rid);
-	  if (parent_pv.m_tree && reg->get_type ())
-	    return path_var (build1 (NOP_EXPR,
-				     reg->get_type (),
-				     parent_pv.m_tree),
-			     parent_pv.m_stack_depth);
-	}
-
-      if (parent_reg->get_kind () == RK_STRUCT)
-	{
-	  map_region *parent_map_region = (map_region *)parent_reg;
-	  /* This can fail if we have a view, rather than a field.  */
-	  if (tree child_key
-		= parent_map_region->get_tree_for_child_region (rid))
-	    {
-	      path_var parent_pv = get_representative_path_var (parent_rid);
-	      if (parent_pv.m_tree && TREE_CODE (child_key) == FIELD_DECL)
-		return path_var (build3 (COMPONENT_REF,
-					 TREE_TYPE (child_key),
-					 parent_pv.m_tree, child_key,
-					 NULL_TREE),
-				 parent_pv.m_stack_depth);
-	    }
-	}
-
-      /* Handle elements within an array.  */
-      if (array_region *array_reg = parent_reg->dyn_cast_array_region ())
-      {
-	array_region::key_t key;
-	if (array_reg->get_key_for_child_region (rid, &key))
-	  {
-	    path_var parent_pv = get_representative_path_var (parent_rid);
-	    if (parent_pv.m_tree && reg->get_type ())
-	      {
-		tree index = array_reg->constant_from_key (key);
-		return path_var (build4 (ARRAY_REF,
-					 reg->get_type (),
-					 parent_pv.m_tree, index,
-					 NULL_TREE, NULL_TREE),
-				 parent_pv.m_stack_depth);
-	      }
-	  }
-      }
-    }
-
-  /* Handle string literals.  */
-  svalue_id sid = reg->get_value_direct ();
-  if (svalue *sval = get_svalue (sid))
-    if (tree cst = sval->maybe_get_constant ())
-      if (TREE_CODE (cst) == STRING_CST)
-	return path_var (cst, 0);
-
-  return path_var (NULL_TREE, 0);
-}
-
-/* Locate all regions that directly have value SID and append representative
-   path_var instances for them into *OUT.  */
-
-void
-region_model::get_path_vars_for_svalue (svalue_id sid, vec<path_var> *out) const
-{
-  unsigned i;
-  region *region;
-  FOR_EACH_VEC_ELT (m_regions, i, region)
-    if (sid == region->get_value_direct ())
-      {
-	path_var pv = get_representative_path_var (region_id::from_int (i));
-	if (pv.m_tree)
-	  out->safe_push (pv);
-      }
-}
-
-/* Set DST_RID value to be a new unknown value of type TYPE.  */
-
-svalue_id
-region_model::set_to_new_unknown_value (region_id dst_rid, tree type,
-					region_model_context *ctxt)
-{
-  gcc_assert (!dst_rid.null_p ());
-  svalue_id new_sid = add_svalue (new unknown_svalue (type));
-  set_value (dst_rid, new_sid, ctxt);
-
-  // TODO: presumably purge all child regions too (but do this in set_value?)
-
-  return new_sid;
-}
-
-/* Update this model for any phis in SNODE, assuming we came from
-   LAST_CFG_SUPEREDGE.  */
-
-void
-region_model::update_for_phis (const supernode *snode,
-			       const cfg_superedge *last_cfg_superedge,
-			       region_model_context *ctxt)
-{
-  gcc_assert (last_cfg_superedge);
-
-  for (gphi_iterator gpi = const_cast<supernode *>(snode)->start_phis ();
-       !gsi_end_p (gpi); gsi_next (&gpi))
-    {
-      gphi *phi = gpi.phi ();
-
-      tree src = last_cfg_superedge->get_phi_arg (phi);
-      tree lhs = gimple_phi_result (phi);
-
-      /* Update next_state based on phi.  */
-      bool is_back_edge = last_cfg_superedge->back_edge_p ();
-      handle_phi (phi, lhs, src, is_back_edge, ctxt);
-    }
-}
-
-/* Attempt to update this model for taking EDGE (where the last statement
-   was LAST_STMT), returning true if the edge can be taken, false
-   otherwise.
-
-   For CFG superedges where LAST_STMT is a conditional or a switch
-   statement, attempt to add the relevant conditions for EDGE to this
-   model, returning true if they are feasible, or false if they are
-   impossible.
-
-   For call superedges, push frame information and store arguments
-   into parameters.
-
-   For return superedges, pop frame information and store return
-   values into any lhs.
-
-   Rejection of call/return superedges happens elsewhere, in
-   program_point::on_edge (i.e. based on program point, rather
-   than program state).  */
-
-bool
-region_model::maybe_update_for_edge (const superedge &edge,
-				     const gimple *last_stmt,
-				     region_model_context *ctxt)
-{
-  /* Handle frame updates for interprocedural edges.  */
-  switch (edge.m_kind)
-    {
-    default:
-      break;
-
-    case SUPEREDGE_CALL:
-      {
-	const call_superedge *call_edge = as_a <const call_superedge *> (&edge);
-	update_for_call_superedge (*call_edge, ctxt);
-      }
-      break;
-
-    case SUPEREDGE_RETURN:
-      {
-	const return_superedge *return_edge
-	  = as_a <const return_superedge *> (&edge);
-	update_for_return_superedge (*return_edge, ctxt);
-      }
-      break;
-
-    case SUPEREDGE_INTRAPROCEDURAL_CALL:
-      {
-	const callgraph_superedge *cg_sedge
-	  = as_a <const callgraph_superedge *> (&edge);
-	update_for_call_summary (*cg_sedge, ctxt);
-      }
-      break;
-    }
-
-  if (last_stmt == NULL)
-    return true;
-
-  /* Apply any constraints for conditionals/switch statements.  */
-
-  if (const gcond *cond_stmt = dyn_cast <const gcond *> (last_stmt))
-    {
-      const cfg_superedge *cfg_sedge = as_a <const cfg_superedge *> (&edge);
-      return apply_constraints_for_gcond (*cfg_sedge, cond_stmt, ctxt);
-    }
-
-  if (const gswitch *switch_stmt = dyn_cast <const gswitch *> (last_stmt))
-    {
-      const switch_cfg_superedge *switch_sedge
-	= as_a <const switch_cfg_superedge *> (&edge);
-      return apply_constraints_for_gswitch (*switch_sedge, switch_stmt, ctxt);
-    }
-
-  return true;
-}
-
-/* Push a new frame_region on to the stack region.
-   Populate the frame_region with child regions for the function call's
-   parameters, using values from the arguments at the callsite in the
-   caller's frame.  */
-
-void
-region_model::update_for_call_superedge (const call_superedge &call_edge,
-					 region_model_context *ctxt)
-{
-  /* Build a vec of argument svalue_id, using the current top
-     frame for resolving tree expressions.  */
-  const gcall *call_stmt = call_edge.get_call_stmt ();
-  auto_vec<svalue_id> arg_sids (gimple_call_num_args (call_stmt));
-
-  for (unsigned i = 0; i < gimple_call_num_args (call_stmt); i++)
-    {
-      tree arg = gimple_call_arg (call_stmt, i);
-      arg_sids.quick_push (get_rvalue (arg, ctxt));
-    }
-
-  push_frame (call_edge.get_callee_function (), &arg_sids, ctxt);
-}
-
-/* Pop the top-most frame_region from the stack, and copy the return
-   region's values (if any) into the region for the lvalue of the LHS of
-   the call (if any).  */
-
-void
-region_model::update_for_return_superedge (const return_superedge &return_edge,
-					   region_model_context *ctxt)
-{
-  region_id stack_rid = get_stack_region_id ();
-  stack_region *stack = get_region <stack_region> (stack_rid);
-
-  /* Get the region for the result of the call, within the caller frame.  */
-  region_id result_dst_rid;
-  const gcall *call_stmt = return_edge.get_call_stmt ();
-  tree lhs = gimple_call_lhs (call_stmt);
-  if (lhs)
-    {
-      /* Normally we access the top-level frame, which is:
-	   path_var (expr, stack->get_num_frames () - 1)
-	 whereas here we need the caller frame, hence "- 2" here.  */
-      gcc_assert (stack->get_num_frames () >= 2);
-      result_dst_rid = get_lvalue (path_var (lhs, stack->get_num_frames () - 2),
-				   ctxt);
-    }
-
-  purge_stats stats;
-  stack->pop_frame (this, result_dst_rid, true, &stats, ctxt);
-  // TODO: do something with the stats?
-
-  if (!lhs)
-    {
-      /* This could be a leak; try purging again, but this time,
-	 don't special-case the result sids (as was done in pop_frame).  */
-      purge_unused_svalues (&stats, ctxt);
-    }
-}
-
-/* Update this region_model with a summary of the effect of calling
-   and returning from CG_SEDGE.
-
-   TODO: Currently this is extremely simplistic: we merely set the
-   return value to "unknown".  A proper implementation would e.g. update
-   sm-state, and presumably be reworked to support multiple outcomes.  */
-
-void
-region_model::update_for_call_summary (const callgraph_superedge &cg_sedge,
-				       region_model_context *ctxt)
-{
-  /* For now, set any return value to "unknown".  */
-  const gcall *call_stmt = cg_sedge.get_call_stmt ();
-  tree lhs = gimple_call_lhs (call_stmt);
-  if (lhs)
-    set_to_new_unknown_value (get_lvalue (lhs, ctxt), TREE_TYPE (lhs), ctxt);
-
-  // TODO: actually implement some kind of summary here
-}
-
-/* Given a true or false edge guarded by conditional statement COND_STMT,
-   determine appropriate constraints for the edge to be taken.
-
-   If they are feasible, add the constraints and return true.
-
-   Return false if the constraints contradict existing knowledge
-   (and so the edge should not be taken).  */
-
-bool
-region_model::apply_constraints_for_gcond (const cfg_superedge &sedge,
-					   const gcond *cond_stmt,
-					   region_model_context *ctxt)
-{
-  ::edge cfg_edge = sedge.get_cfg_edge ();
-  gcc_assert (cfg_edge != NULL);
-  gcc_assert (cfg_edge->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE));
-
-  enum tree_code op = gimple_cond_code (cond_stmt);
-  tree lhs = gimple_cond_lhs (cond_stmt);
-  tree rhs = gimple_cond_rhs (cond_stmt);
-  if (cfg_edge->flags & EDGE_FALSE_VALUE)
-    op = invert_tree_comparison (op, false /* honor_nans */);
-  return add_constraint (lhs, op, rhs, ctxt);
-}
-
-/* Given an EDGE guarded by SWITCH_STMT, determine appropriate constraints
-   for the edge to be taken.
-
-   If they are feasible, add the constraints and return true.
-
-   Return false if the constraints contradict existing knowledge
-   (and so the edge should not be taken).  */
-
-bool
-region_model::apply_constraints_for_gswitch (const switch_cfg_superedge &edge,
-					     const gswitch *switch_stmt,
-					     region_model_context *ctxt)
-{
-  tree index  = gimple_switch_index (switch_stmt);
-  tree case_label = edge.get_case_label ();
-  gcc_assert (TREE_CODE (case_label) == CASE_LABEL_EXPR);
-  tree lower_bound = CASE_LOW (case_label);
-  tree upper_bound = CASE_HIGH (case_label);
-  if (lower_bound)
-    {
-      if (upper_bound)
-	{
-	  /* Range.  */
-	  if (!add_constraint (index, GE_EXPR, lower_bound, ctxt))
-	    return false;
-	  return add_constraint (index, LE_EXPR, upper_bound, ctxt);
-	}
-      else
-	/* Single-value.  */
-	return add_constraint (index, EQ_EXPR, lower_bound, ctxt);
-    }
-  else
-    {
-      /* The default case.
-	 Add exclusions based on the other cases.  */
-      for (unsigned other_idx = 1;
-	   other_idx < gimple_switch_num_labels (switch_stmt);
-	   other_idx++)
-	{
-	  tree other_label = gimple_switch_label (switch_stmt,
-						  other_idx);
-	  tree other_lower_bound = CASE_LOW (other_label);
-	  tree other_upper_bound = CASE_HIGH (other_label);
-	  gcc_assert (other_lower_bound);
-	  if (other_upper_bound)
-	    {
-	      /* Exclude this range-valued case.
-		 For now, we just exclude the boundary values.
-		 TODO: exclude the values within the region.  */
-	      if (!add_constraint (index, NE_EXPR, other_lower_bound, ctxt))
-		return false;
-	      if (!add_constraint (index, NE_EXPR, other_upper_bound, ctxt))
-		return false;
-	    }
-	  else
-	    /* Exclude this single-valued case.  */
-	    if (!add_constraint (index, NE_EXPR, other_lower_bound, ctxt))
-	      return false;
-	}
-      return true;
-    }
-}
-
-/* Get the root_region within this model (guaranteed to be non-null).  */
-
-root_region *
-region_model::get_root_region () const
-{
-  return get_region<root_region> (m_root_rid);
-}
-
-/* Get the region_id of this model's stack region (if any).  */
-
-region_id
-region_model::get_stack_region_id () const
-{
-  return get_root_region ()->get_stack_region_id ();
-}
-
-/* Create a new frame_region for a call to FUN and push it onto
-   the stack.
-
-   If ARG_SIDS is non-NULL, use it to populate the parameters
-   in the new frame.
-   Otherwise, populate them with unknown values.
-
-   Return the region_id of the new frame_region.  */
-
-region_id
-region_model::push_frame (function *fun, vec<svalue_id> *arg_sids,
-			  region_model_context *ctxt)
-{
-  return get_root_region ()->push_frame (this, fun, arg_sids, ctxt);
-}
-
-/* Get the region_id of the top-most frame in this region_model's stack,
-   if any.  */
-
-region_id
-region_model::get_current_frame_id () const
-{
-  return get_root_region ()->get_current_frame_id (*this);
-}
-
-/* Get the function of the top-most frame in this region_model's stack.
-   There must be such a frame.  */
-
-function *
-region_model::get_current_function () const
-{
-  region_id frame_id = get_current_frame_id ();
-  frame_region *frame = get_region<frame_region> (frame_id);
-  return frame->get_function ();
-}
-
-/* Pop the topmost frame_region from this region_model's stack;
-   see the comment for stack_region::pop_frame.  */
-
-void
-region_model::pop_frame (region_id result_dst_rid,
-			 bool purge, purge_stats *out,
-			 region_model_context *ctxt)
-{
-  get_root_region ()->pop_frame (this, result_dst_rid, purge, out, ctxt);
-}
-
-/* Get the number of frames in this region_model's stack.  */
-
-int
-region_model::get_stack_depth () const
-{
-  stack_region *stack = get_root_region ()->get_stack_region (this);
-  if (stack)
-    return stack->get_num_frames ();
-  else
-    return 0;
-}
-
-/* Get the function * at DEPTH within the call stack.  */
-
-function *
-region_model::get_function_at_depth (unsigned depth) const
-{
-  stack_region *stack = get_root_region ()->get_stack_region (this);
-  gcc_assert (stack);
-  region_id frame_rid = stack->get_frame_rid (depth);
-  frame_region *frame = get_region <frame_region> (frame_rid);
-  return frame->get_function ();
-}
-
-/* Get the region_id of this model's globals region (if any).  */
-
-region_id
-region_model::get_globals_region_id () const
-{
-  return get_root_region ()->get_globals_region_id ();
-}
-
-/* Add SVAL to this model, taking ownership, and returning its new
-   svalue_id.  */
-
-svalue_id
-region_model::add_svalue (svalue *sval)
-{
-  gcc_assert (sval);
-  m_svalues.safe_push (sval);
-  return svalue_id::from_int (m_svalues.length () - 1);
-}
-
-/* Change the meaning of SID to be NEW_SVAL
-   (e.g. when deferencing an unknown pointer, the pointer
-   becomes a pointer to a symbolic region, so that all users
-   of the former unknown pointer are now effectively pointing
-   at the same region).  */
-
-void
-region_model::replace_svalue (svalue_id sid, svalue *new_sval)
-{
-  gcc_assert (!sid.null_p ());
-  int idx = sid.as_int ();
-
-  gcc_assert (m_svalues[idx]);
-  gcc_assert (m_svalues[idx]->get_type () == new_sval->get_type ());
-  delete m_svalues[idx];
-
-  m_svalues[idx] = new_sval;
-}
-
-/* Add region R to this model, taking ownership, and returning its new
-   region_id.  */
-
-region_id
-region_model::add_region (region *r)
-{
-  gcc_assert (r);
-  m_regions.safe_push (r);
-  return region_id::from_int (m_regions.length () - 1);
-}
-
-/* Return the svalue with id SVAL_ID, or NULL for a null id.  */
-
-svalue *
-region_model::get_svalue (svalue_id sval_id) const
-{
-  if (sval_id.null_p ())
-    return NULL;
-  return m_svalues[sval_id.as_int ()];
-}
-
-/* Return the region with id RID, or NULL for a null id.  */
-
-region *
-region_model::get_region (region_id rid) const
-{
-  if (rid.null_p ())
-    return NULL;
-  return m_regions[rid.as_int ()];
-}
-
-/* Make a region of an appropriate subclass for TYPE,
-   with parent PARENT_RID, or return NULL for types we don't yet know
-   how to handle.  */
-
-static region *
-make_region_for_type (region_id parent_rid, tree type)
-{
-  gcc_assert (TYPE_P (type));
-
-  if (INTEGRAL_TYPE_P (type)
-      || SCALAR_FLOAT_TYPE_P (type)
-      || POINTER_TYPE_P (type)
-      || TREE_CODE (type) == COMPLEX_TYPE
-      || TREE_CODE (type) == VECTOR_TYPE)
-    return new primitive_region (parent_rid, type);
-
-  if (TREE_CODE (type) == RECORD_TYPE)
-    return new struct_region (parent_rid, type);
-
-  if (TREE_CODE (type) == ARRAY_TYPE)
-    return new array_region (parent_rid, type);
-
-  if (TREE_CODE (type) == UNION_TYPE)
-    return new union_region (parent_rid, type);
-
-  if (FUNC_OR_METHOD_TYPE_P (type))
-    return new function_region (parent_rid, type);
-
-  /* If we have a void *, make a new symbolic region.  */
-  if (VOID_TYPE_P (type))
-    return new symbolic_region (parent_rid, type, false);
-
-  return NULL;
-}
-
-/* Add a region with type TYPE and parent PARENT_RID.  */
-
-region_id
-region_model::add_region_for_type (region_id parent_rid, tree type,
-				   region_model_context *ctxt)
-{
-  if (type)
-    {
-      gcc_assert (TYPE_P (type));
-
-      if (region *new_region = make_region_for_type (parent_rid, type))
-	return add_region (new_region);
-    }
-
-  /* If we can't handle TYPE, return a placeholder region, and stop
-     exploring this path.  */
-  return make_region_for_unexpected_tree_code (ctxt, type,
-					       dump_location_t ());
-}
-
-/* Helper class for region_model::purge_unused_svalues.  */
-
-class restrict_to_used_svalues : public purge_criteria
-{
-public:
-  restrict_to_used_svalues (const auto_sbitmap &used) : m_used (used) {}
-
-  bool should_purge_p (svalue_id sid) const FINAL OVERRIDE
-  {
-    gcc_assert (!sid.null_p ());
-    return !bitmap_bit_p (m_used, sid.as_int ());
-  }
-
-private:
-  const auto_sbitmap &m_used;
-};
-
-/* Remove unused svalues from this model, accumulating stats into STATS.
-   Unused svalues are deleted.  Doing so could reorder the svalues, and
-   thus change the meaning of svalue_ids.
-
-   If CTXT is non-NULL, then it is notified about svalue_id remappings,
-   and about svalue_ids that are about to be deleted.  This allows e.g.
-   for warning about resource leaks, for the case where the svalue
-   represents a resource handle in the user code (e.g. a FILE * or a malloc
-   buffer).
-
-   Amongst other things, removing unused svalues is important for ensuring
-   that the analysis of loops terminates.  Otherwise, we could generate a
-   succession of models with unreferenced "unknown" values, where the
-   number of redundant unknown values could grow without bounds, and each
-   such model would be treated as distinct.
-
-   If KNOWN_USED_SIDS is non-NULL, treat *KNOWN_USED_SIDS as used (this is for
-   handling values being returned from functions as their frame is popped,
-   since otherwise we'd have to simultaneously determine both the rvalue
-   of the return expr in the callee frame and the lvalue for the gcall's
-   assignment in the caller frame, and it seems cleaner to express all
-   lvalue and rvalue lookups implicitly relative to a "current" frame).
-   The svalue_ids in *KNOWN_USED_SIDS are not remapped and hence this
-   call makes it invalid.  */
-
-void
-region_model::purge_unused_svalues (purge_stats *stats,
-				    region_model_context *ctxt,
-				    svalue_id_set *known_used_sids)
-{
-  // TODO: might want to avoid a vfunc call just to do logging here:
-  logger *logger = ctxt ? ctxt->get_logger () : NULL;
-
-  LOG_SCOPE (logger);
-
-  auto_sbitmap used (m_svalues.length ());
-  bitmap_clear (used);
-
-  if (known_used_sids)
-    {
-      /* We can't use an sbitmap for known_used_sids as the number of
-	 svalues could have grown since it was created.  */
-      for (unsigned i = 0; i < get_num_svalues (); i++)
-	if (known_used_sids->svalue_p (svalue_id::from_int (i)))
-	  bitmap_set_bit (used, i);
-    }
-
-  /* Walk the regions, marking sids that are used.  */
-  unsigned i;
-  region *r;
-  FOR_EACH_VEC_ELT (m_regions, i, r)
-    {
-      svalue_id sid = r->get_value_direct ();
-      if (!sid.null_p ())
-	bitmap_set_bit (used, sid.as_int ());
-    }
-
-  /* Now purge any constraints involving svalues we don't care about.  */
-  restrict_to_used_svalues criterion (used);
-  m_constraints->purge (criterion, stats);
-
-  /* Mark any sids that are in constraints that survived.  */
-  {
-    equiv_class *ec;
-    FOR_EACH_VEC_ELT (m_constraints->m_equiv_classes, i, ec)
-      {
-	int j;
-	svalue_id *sid;
-	FOR_EACH_VEC_ELT (ec->m_vars, j, sid)
-	  {
-	    gcc_assert (!sid->null_p ());
-	    bitmap_set_bit (used, sid->as_int ());
-	  }
-      }
-  }
-
-  /* Build a mapping from old-sid to new-sid so that we can preserve
-     order of the used IDs and move all redundant ones to the end.
-     Iterate though svalue IDs, adding used ones to the front of
-     the new list, and unused ones to the back.  */
-  svalue_id_map map (m_svalues.length ());
-  int next_used_new_sid = 0;
-  int after_next_unused_new_sid = m_svalues.length ();
-  for (unsigned i = 0; i < m_svalues.length (); i++)
-    {
-      svalue_id src (svalue_id::from_int (i));
-      if (bitmap_bit_p (used, i))
-	{
-	  if (logger)
-	    logger->log ("sv%i is used", i);
-	  map.put (src, svalue_id::from_int (next_used_new_sid++));
-	}
-      else
-	{
-	  if (logger)
-	    logger->log ("sv%i is unused", i);
-	  map.put (src, svalue_id::from_int (--after_next_unused_new_sid));
-	}
-    }
-  /* The two insertion points should have met.  */
-  gcc_assert (next_used_new_sid == after_next_unused_new_sid);
-
-  /* Now walk the regions and the constraints, remapping sids,
-     so that all the redundant svalues are at the end.  */
-  remap_svalue_ids (map);
-
-  if (logger)
-    {
-      logger->start_log_line ();
-      logger->log_partial ("map: ");
-      map.dump_to_pp (logger->get_printer ());
-      logger->end_log_line ();
-    }
-
-  /* Notify any client about the remapping and pending deletion.
-     Potentially this could trigger leak warnings.  */
-  if (ctxt)
-    {
-      ctxt->remap_svalue_ids (map);
-      int num_client_items_purged
-	= ctxt->on_svalue_purge (svalue_id::from_int (next_used_new_sid), map);
-      if (stats)
-	stats->m_num_client_items += num_client_items_purged;
-    }
-
-  /* Drop the redundant svalues from the end of the vector.  */
-  while ((signed)m_svalues.length () > next_used_new_sid)
-    {
-      if (logger)
-	{
-	  svalue_id victim = svalue_id::from_int (m_svalues.length () - 1);
-	  logger->log ("deleting sv%i (was sv%i)",
-		       victim.as_int (),
-		       map.get_src_for_dst (victim).as_int ());
-	}
-      delete m_svalues.pop ();
-      if (stats)
-	stats->m_num_svalues++;
-    }
-
-  validate ();
-}
-
-/* Renumber the svalues within this model according to MAP.  */
-
-void
-region_model::remap_svalue_ids (const svalue_id_map &map)
-{
-  /* Update IDs within regions.  */
-  unsigned i;
-  region *r;
-  FOR_EACH_VEC_ELT (m_regions, i, r)
-    r->remap_svalue_ids (map);
-
-  /* Update IDs within ECs within constraints.  */
-  m_constraints->remap_svalue_ids (map);
-
-  /* Build a reordered svalues vector.  */
-  auto_vec<svalue *> new_svalues (m_svalues.length ());
-  for (unsigned i = 0; i < m_svalues.length (); i++)
-    {
-      svalue_id dst (svalue_id::from_int (i));
-      svalue_id src = map.get_src_for_dst (dst);
-      new_svalues.quick_push (get_svalue (src));
-    }
-
-  /* Copy over the reordered vec to m_svalues.  */
-  m_svalues.truncate (0);
-  gcc_assert (m_svalues.space (new_svalues.length ()));
-  svalue *sval;
-  FOR_EACH_VEC_ELT (new_svalues, i, sval)
-    m_svalues.quick_push (sval);
-}
-
-/* Renumber the regions within this model according to MAP.  */
-
-void
-region_model::remap_region_ids (const region_id_map &map)
-{
-  /* Update IDs within regions.  */
-  unsigned i;
-  region *r;
-  FOR_EACH_VEC_ELT (m_regions, i, r)
-    r->remap_region_ids (map);
-
-  /* Update IDs within svalues.  */
-  svalue *sval;
-  FOR_EACH_VEC_ELT (m_svalues, i, sval)
-    sval->remap_region_ids (map);
-
-  /* Build a reordered regions vector.  */
-  auto_vec<region *> new_regions (m_regions.length ());
-  for (unsigned i = 0; i < m_regions.length (); i++)
-    {
-      region_id dst (region_id::from_int (i));
-      region_id src = map.get_src_for_dst (dst);
-      new_regions.quick_push (get_region (src));
-    }
-
-  /* Copy over the reordered vec to m_regions.  */
-  m_regions.truncate (0);
-  gcc_assert (m_regions.space (new_regions.length ()));
-  FOR_EACH_VEC_ELT (new_regions, i, r)
-    m_regions.quick_push (r);
-}
-
-/* Delete all regions within SET_TO_PURGE, remapping region IDs for
-   other regions.  It's required that there are no uses of the
-   regions within the set (or the region IDs will become invalid).
-
-   Accumulate stats to STATS.  */
-
-void
-region_model::purge_regions (const region_id_set &set_to_purge,
-			     purge_stats *stats,
-			     logger *)
-{
-  /* Build a mapping from old-rid to new-rid so that we can preserve
-     order of the used IDs and move all redundant ones to the end.
-     Iterate though region IDs, adding used ones to the front of
-     the new list, and unused ones to the back.  */
-  region_id_map map (m_regions.length ());
-  int next_used_new_rid = 0;
-  int after_next_unused_new_rid = m_regions.length ();
-  for (unsigned i = 0; i < m_regions.length (); i++)
-    {
-      region_id src (region_id::from_int (i));
-      if (set_to_purge.region_p (src))
-	map.put (src, region_id::from_int (--after_next_unused_new_rid));
-      else
-	map.put (src, region_id::from_int (next_used_new_rid++));
-    }
-  /* The two insertion points should have met.  */
-  gcc_assert (next_used_new_rid == after_next_unused_new_rid);
-
-  /* Now walk the regions and svalues, remapping rids,
-     so that all the redundant regions are at the end.  */
-  remap_region_ids (map);
-
-  /* Drop the redundant regions from the end of the vector.  */
-  while ((signed)m_regions.length () > next_used_new_rid)
-    {
-      delete m_regions.pop ();
-      if (stats)
-	stats->m_num_regions++;
-    }
-}
-
-/* Populate *OUT with RID and all of its descendents.
-   If EXCLUDE_RID is non-null, then don't add it or its descendents.  */
-
-void
-region_model::get_descendents (region_id rid, region_id_set *out,
-			       region_id exclude_rid) const
-{
-  out->add_region (rid);
-
-  bool changed = true;
-  while (changed)
-    {
-      changed = false;
-      unsigned i;
-      region *r;
-      FOR_EACH_VEC_ELT (m_regions, i, r)
-	{
-	  region_id iter_rid = region_id::from_int (i);
-	  if (iter_rid == exclude_rid)
-	    continue;
-	  if (!out->region_p (iter_rid))
-	    {
-	      region_id parent_rid = r->get_parent ();
-	      if (!parent_rid.null_p ())
-		if (out->region_p (parent_rid))
-		  {
-		    out->add_region (iter_rid);
-		    changed = true;
-		  }
-	    }
-	}
-    }
-}
-
-/* Delete RID and all descendent regions.
-   Find any pointers to such regions; convert them to
-   poisoned values of kind PKIND.
-   Accumulate stats on purged entities into STATS.  */
-
-void
-region_model::delete_region_and_descendents (region_id rid,
-					     enum poison_kind pkind,
-					     purge_stats *stats,
-					     logger *logger)
-{
-  /* Find all child and descendent regions.  */
-  region_id_set descendents (this);
-  get_descendents (rid, &descendents, region_id::null ());
-
-  /* Find any pointers to such regions; convert to poisoned.  */
-  poison_any_pointers_to_bad_regions (descendents, pkind);
-
-  /* Delete all such regions.  */
-  purge_regions (descendents, stats, logger);
-}
-
-/* Find any pointers to regions within BAD_REGIONS; convert them to
-   poisoned values of kind PKIND.  */
-
-void
-region_model::poison_any_pointers_to_bad_regions (const region_id_set &
-						    bad_regions,
-						  enum poison_kind pkind)
-{
-  int i;
-  svalue *sval;
-  FOR_EACH_VEC_ELT (m_svalues, i, sval)
-    if (region_svalue *ptr_sval = sval->dyn_cast_region_svalue ())
-      {
-	region_id ptr_dst = ptr_sval->get_pointee ();
-	if (!ptr_dst.null_p ())
-	  if (bad_regions.region_p (ptr_dst))
-	    replace_svalue
-	      (svalue_id::from_int (i),
-	       new poisoned_svalue (pkind, sval->get_type ()));
-      }
-}
-
-/* Attempt to merge THIS with OTHER_MODEL, writing the result
-   to OUT_MODEL, and populating SID_MAPPING.  */
-
-bool
-region_model::can_merge_with_p (const region_model &other_model,
-				region_model *out_model,
-				svalue_id_merger_mapping *sid_mapping) const
-{
-  gcc_assert (m_root_rid == other_model.m_root_rid);
-  gcc_assert (m_root_rid.as_int () == 0);
-  gcc_assert (sid_mapping);
-  gcc_assert (out_model);
-
-  model_merger merger (this, &other_model, out_model, sid_mapping);
-
-  if (!root_region::can_merge_p (get_root_region (),
-				 other_model.get_root_region (),
-				 out_model->get_root_region (),
-				 &merger))
-    return false;
-
-  /* Merge constraints.  */
-  constraint_manager::merge (*m_constraints,
-			     *other_model.m_constraints,
-			     out_model->m_constraints,
-			     merger);
-
-  out_model->validate ();
-
-  /* The merged model should be simpler (or as simple) as the inputs.  */
-#if 0
-  gcc_assert (out_model->m_svalues.length () <= m_svalues.length ());
-  gcc_assert (out_model->m_svalues.length ()
-	      <= other_model.m_svalues.length ());
-#endif
-  gcc_assert (out_model->m_regions.length () <= m_regions.length ());
-  gcc_assert (out_model->m_regions.length ()
-	      <= other_model.m_regions.length ());
-  // TODO: same, for constraints
-
-  return true;
-}
-
-/* As above, but supply a placeholder svalue_id_merger_mapping
-   instance to be used and receive output.  For use in selftests.  */
-
-bool
-region_model::can_merge_with_p (const region_model &other_model,
-				region_model *out_model) const
-{
-  svalue_id_merger_mapping sid_mapping (*this, other_model);
-  return can_merge_with_p (other_model, out_model, &sid_mapping);
-}
-
-/* For debugging purposes: look for a region within this region_model
-   for a decl named NAME (or an SSA_NAME for such a decl),
-   returning its value, or svalue_id::null if none are found.  */
-
-svalue_id
-region_model::get_value_by_name (const char *name) const
-{
-  gcc_assert (name);
-  tree identifier = get_identifier (name);
-  return get_root_region ()->get_value_by_name (identifier, *this);
-}
-
-/* Generate or reuse an svalue_id within this model for an index
-   into an array of type PTR_TYPE, based on OFFSET_SID.  */
-
-svalue_id
-region_model::convert_byte_offset_to_array_index (tree ptr_type,
-						  svalue_id offset_sid)
-{
-  gcc_assert (POINTER_TYPE_P (ptr_type));
-
-  if (tree offset_cst = maybe_get_constant (offset_sid))
-    {
-      tree elem_type = TREE_TYPE (ptr_type);
-
-      /* Arithmetic on void-pointers is a GNU C extension, treating the size
-	 of a void as 1.
-	 https://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html  */
-      if (TREE_CODE (elem_type) == VOID_TYPE)
-	return offset_sid;
-
-      /* First, use int_size_in_bytes, to reject the case where we have an
-	 incomplete type, or a non-constant value.  */
-      HOST_WIDE_INT hwi_byte_size = int_size_in_bytes (elem_type);
-      if (hwi_byte_size > 0)
-	{
-	  /* Now call size_in_bytes to get the answer in tree form.  */
-	  tree byte_size = size_in_bytes (elem_type);
-	  gcc_assert (byte_size);
-	  /* Try to get a constant by dividing, ensuring that we're in a
-	     signed representation first.  */
-	  tree index
-	    = fold_binary (TRUNC_DIV_EXPR, ssizetype,
-			   fold_convert (ssizetype, offset_cst),
-			   fold_convert (ssizetype, byte_size));
-	  if (index && TREE_CODE (index) == INTEGER_CST)
-	    return get_or_create_constant_svalue (index);
-	}
-    }
-
-  /* Otherwise, we don't know the array index; generate a new unknown value.
-     TODO: do we need to capture the relationship between two unknown
-     values (the offset and the index)?  */
-  return add_svalue (new unknown_svalue (integer_type_node));
-}
-
-/* Get a region of type TYPE for PTR_SID[OFFSET_SID/sizeof (*PTR_SID)].
-
-   If OFFSET_SID is known to be zero, then dereference PTR_SID.
-   Otherwise, impose a view of "typeof(*PTR_SID)[]" on *PTR_SID,
-   and then get a view of type TYPE on the relevant array element.  */
-
-region_id
-region_model::get_or_create_mem_ref (tree type,
-				     svalue_id ptr_sid,
-				     svalue_id offset_sid,
-				     region_model_context *ctxt)
-{
-  svalue *ptr_sval = get_svalue (ptr_sid);
-  tree ptr_type = ptr_sval->get_type ();
-  gcc_assert (ptr_type);
-
-  region_id raw_rid = deref_rvalue (ptr_sid, ctxt);
-
-  svalue *offset_sval = get_svalue (offset_sid);
-  tree offset_type = offset_sval->get_type ();
-  gcc_assert (offset_type);
-
-  if (constant_svalue *cst_sval = offset_sval->dyn_cast_constant_svalue ())
-    {
-      if (zerop (cst_sval->get_constant ()))
-	{
-	  /* Handle the zero offset case.  */
-	  return get_or_create_view (raw_rid, type, ctxt);
-	}
-
-      /* If we're already within an array of the correct type,
-	 then we want to reuse that array, rather than starting
-	 a new view.
-	 If so, figure out our raw_rid's offset from its parent,
-	 if we can, and use that to offset OFFSET_SID, and create
-	 the element within the parent region.  */
-      region *raw_reg = get_region (raw_rid);
-      region_id parent_rid = raw_reg->get_parent ();
-      tree parent_type = get_region (parent_rid)->get_type ();
-      if (parent_type
-	  && TREE_CODE (parent_type) == ARRAY_TYPE)
-	{
-	  // TODO: check we have the correct parent type
-	  array_region *parent_array = get_region <array_region> (parent_rid);
-	  array_region::key_t key_for_raw_rid;
-	  if (parent_array->get_key_for_child_region (raw_rid,
-						      &key_for_raw_rid))
-	    {
-	      /* Convert from offset to index.  */
-	      svalue_id index_sid
-		= convert_byte_offset_to_array_index (ptr_type, offset_sid);
-	      if (tree index_cst
-		    = get_svalue (index_sid)->maybe_get_constant ())
-		{
-		  array_region::key_t index_offset
-		    = array_region::key_from_constant (index_cst);
-		  array_region::key_t index_rel_to_parent
-		    = key_for_raw_rid + index_offset;
-		  tree index_rel_to_parent_cst
-		    = wide_int_to_tree (integer_type_node,
-					index_rel_to_parent);
-		  svalue_id index_sid
-		    = get_or_create_constant_svalue (index_rel_to_parent_cst);
-
-		  /* Carry on, using the parent region and adjusted index.  */
-		  region_id element_rid
-		    = parent_array->get_element (this, raw_rid, index_sid,
-						 ctxt);
-		  return get_or_create_view (element_rid, type, ctxt);
-		}
-	    }
-	}
-    }
-
-  tree array_type = build_array_type (TREE_TYPE (ptr_type),
-				      integer_type_node);
-  region_id array_view_rid = get_or_create_view (raw_rid, array_type, ctxt);
-  array_region *array_reg = get_region <array_region> (array_view_rid);
-
-  svalue_id index_sid
-    = convert_byte_offset_to_array_index (ptr_type, offset_sid);
-
-  region_id element_rid
-    = array_reg->get_element (this, array_view_rid, index_sid, ctxt);
-
-  return get_or_create_view (element_rid, type, ctxt);
-}
-
-/* Get a region of type TYPE for PTR_SID + OFFSET_SID.
-
-   If OFFSET_SID is known to be zero, then dereference PTR_SID.
-   Otherwise, impose a view of "typeof(*PTR_SID)[]" on *PTR_SID,
-   and then get a view of type TYPE on the relevant array element.  */
-
-region_id
-region_model::get_or_create_pointer_plus_expr (tree type,
-					       svalue_id ptr_sid,
-					       svalue_id offset_in_bytes_sid,
-					       region_model_context *ctxt)
-{
-  return get_or_create_mem_ref (type,
-				ptr_sid,
-				offset_in_bytes_sid,
-				ctxt);
-}
-
-/* Get or create a view of type TYPE of the region with id RAW_ID.
-   Return the id of the view (or RAW_ID if it of the same type).  */
-
-region_id
-region_model::get_or_create_view (region_id raw_rid, tree type,
-				  region_model_context *ctxt)
-{
-  region *raw_region = get_region (raw_rid);
-
-  gcc_assert (TYPE_P (type));
-  if (type != raw_region->get_type ())
-    {
-      /* If the region already has a view of the requested type,
-	 reuse it.  */
-      region_id existing_view_rid = raw_region->get_view (type, this);
-      if (!existing_view_rid.null_p ())
-	return existing_view_rid;
-
-      /* Otherwise, make one (adding it to the region_model and
-	 to the viewed region).  */
-      region_id view_rid = add_region_for_type (raw_rid, type, ctxt);
-      raw_region->add_view (view_rid, this);
-      // TODO: something to signify that this is a "view"
-      return view_rid;
-    }
-
-  return raw_rid;
-}
-
-/* Attempt to get the fndecl used at CALL, if known, or NULL_TREE
-   otherwise.  */
-
-tree
-region_model::get_fndecl_for_call (const gcall *call,
-				   region_model_context *ctxt)
-{
-  tree fn_ptr = gimple_call_fn (call);
-  if (fn_ptr == NULL_TREE)
-    return NULL_TREE;
-  svalue_id fn_ptr_sid = get_rvalue (fn_ptr, ctxt);
-  svalue *fn_ptr_sval = get_svalue (fn_ptr_sid);
-  if (region_svalue *fn_ptr_ptr = fn_ptr_sval->dyn_cast_region_svalue ())
-    {
-      region_id fn_rid = fn_ptr_ptr->get_pointee ();
-      code_region *code = get_root_region ()->get_code_region (this);
-      if (code)
-	{
-	  tree fn_decl = code->get_tree_for_child_region (fn_rid);
-	  if (!fn_decl)
-	    return NULL_TREE;
-	  cgraph_node *node = cgraph_node::get (fn_decl);
-	  if (!node)
-	    return NULL_TREE;
-	  const cgraph_node *ultimate_node = node->ultimate_alias_target ();
-	  if (ultimate_node)
-	    return ultimate_node->decl;
-	}
-    }
-
-  return NULL_TREE;
-}
-
-/* struct model_merger.  */
-
-/* Dump a multiline representation of this merger to PP.  */
-
-void
-model_merger::dump_to_pp (pretty_printer *pp) const
-{
-  pp_string (pp, "model A:");
-  pp_newline (pp);
-  m_model_a->dump_to_pp (pp, false);
-  pp_newline (pp);
-
-  pp_string (pp, "model B:");
-  pp_newline (pp);
-  m_model_b->dump_to_pp (pp, false);
-  pp_newline (pp);
-
-  pp_string (pp, "merged model:");
-  pp_newline (pp);
-  m_merged_model->dump_to_pp (pp, false);
-  pp_newline (pp);
-
-  pp_string (pp, "region map: model A to merged model:");
-  pp_newline (pp);
-  m_map_regions_from_a_to_m.dump_to_pp (pp);
-  pp_newline (pp);
-
-  pp_string (pp, "region map: model B to merged model:");
-  pp_newline (pp);
-  m_map_regions_from_b_to_m.dump_to_pp (pp);
-  pp_newline (pp);
-
-  m_sid_mapping->dump_to_pp (pp);
-}
-
-/* Dump a multiline representation of this merger to FILE.  */
-
-void
-model_merger::dump (FILE *fp) const
-{
-  pretty_printer pp;
-  pp_format_decoder (&pp) = default_tree_printer;
-  pp_show_color (&pp) = pp_show_color (global_dc->printer);
-  pp.buffer->stream = fp;
-  dump_to_pp (&pp);
-  pp_flush (&pp);
-}
-
-/* Dump a multiline representation of this merger to stderr.  */
-
-DEBUG_FUNCTION void
-model_merger::dump () const
-{
-  dump (stderr);
-}
-
-/* Attempt to merge the svalues of SID_A and SID_B (from their
-   respective models), writing the id of the resulting svalue
-   into *MERGED_SID.
-   Return true if the merger is possible, false otherwise.  */
-
-bool
-model_merger::can_merge_values_p (svalue_id sid_a,
-				  svalue_id sid_b,
-				  svalue_id *merged_sid)
-{
-  gcc_assert (merged_sid);
-  svalue *sval_a = m_model_a->get_svalue (sid_a);
-  svalue *sval_b = m_model_b->get_svalue (sid_b);
-
-  /* If both are NULL, then the "values" are trivially mergeable.  */
-  if (!sval_a && !sval_b)
-    return true;
-
-  /* If one is NULL and the other non-NULL, then the "values"
-     are not mergeable.  */
-  if (!(sval_a && sval_b))
-    return false;
-
-  /* Have they both already been mapped to the same new svalue_id?
-     If so, use it.  */
-  svalue_id sid_a_in_m
-    = m_sid_mapping->m_map_from_a_to_m.get_dst_for_src (sid_a);
-  svalue_id sid_b_in_m
-    = m_sid_mapping->m_map_from_b_to_m.get_dst_for_src (sid_b);
-  if (!sid_a_in_m.null_p ()
-      && !sid_b_in_m.null_p ()
-      && sid_a_in_m == sid_b_in_m)
-    {
-      *merged_sid = sid_a_in_m;
-      return true;
-    }
-
-  tree type = sval_a->get_type ();
-  if (type == NULL_TREE)
-    type = sval_b->get_type ();
-
-  /* If the values have different kinds, or are both unknown,
-     then merge as "unknown".  */
-  if (sval_a->get_kind () != sval_b->get_kind ()
-      || sval_a->get_kind () == SK_UNKNOWN)
-    {
-      svalue *merged_sval = new unknown_svalue (type);
-      *merged_sid = m_merged_model->add_svalue (merged_sval);
-      record_svalues (sid_a, sid_b, *merged_sid);
-      return true;
-    }
-
-  gcc_assert (sval_a->get_kind () == sval_b->get_kind ());
-
-  switch (sval_a->get_kind ())
-    {
-    default:
-    case SK_UNKNOWN: /* SK_UNKNOWN handled above.  */
-       gcc_unreachable ();
-
-    case SK_REGION:
-      {
-	/* If we have two region pointers, then we can merge (possibly to
-	   "unknown").  */
-	const region_svalue &region_sval_a = *as_a <region_svalue *> (sval_a);
-	const region_svalue &region_sval_b = *as_a <region_svalue *> (sval_b);
-	region_svalue::merge_values (region_sval_a, region_sval_b,
-				     merged_sid, type,
-				     this);
-	record_svalues (sid_a, sid_b, *merged_sid);
-	return true;
-      }
-      break;
-    case SK_CONSTANT:
-      {
-	/* If we have two constants, then we can merge.  */
-	const constant_svalue &cst_sval_a = *as_a <constant_svalue *> (sval_a);
-	const constant_svalue &cst_sval_b = *as_a <constant_svalue *> (sval_b);
-	constant_svalue::merge_values (cst_sval_a, cst_sval_b,
-				       merged_sid, this);
-	record_svalues (sid_a, sid_b, *merged_sid);
-	return true;
-      }
-      break;
-
-    case SK_POISONED:
-    case SK_SETJMP:
-      return false;
-    }
-}
-
-/* Record that A_RID in model A and B_RID in model B
-   correspond to MERGED_RID in the merged model, so
-   that pointers can be accurately merged.  */
-
-void
-model_merger::record_regions (region_id a_rid,
-			      region_id b_rid,
-			      region_id merged_rid)
-{
-  m_map_regions_from_a_to_m.put (a_rid, merged_rid);
-  m_map_regions_from_b_to_m.put (b_rid, merged_rid);
-}
-
-/* Record that A_SID in model A and B_SID in model B
-   correspond to MERGED_SID in the merged model.  */
-
-void
-model_merger::record_svalues (svalue_id a_sid,
-			      svalue_id b_sid,
-			      svalue_id merged_sid)
-{
-  gcc_assert (m_sid_mapping);
-  m_sid_mapping->m_map_from_a_to_m.put (a_sid, merged_sid);
-  m_sid_mapping->m_map_from_b_to_m.put (b_sid, merged_sid);
-}
-
-/* struct svalue_id_merger_mapping.  */
-
-/* svalue_id_merger_mapping's ctor.  */
-
-svalue_id_merger_mapping::svalue_id_merger_mapping (const region_model &a,
-						    const region_model &b)
-: m_map_from_a_to_m (a.get_num_svalues ()),
-  m_map_from_b_to_m (b.get_num_svalues ())
-{
-}
-
-/* Dump a multiline representation of this to PP.  */
-
-void
-svalue_id_merger_mapping::dump_to_pp (pretty_printer *pp) const
-{
-  pp_string (pp, "svalue_id map: model A to merged model:");
-  pp_newline (pp);
-  m_map_from_a_to_m.dump_to_pp (pp);
-  pp_newline (pp);
-
-  pp_string (pp, "svalue_id map: model B to merged model:");
-  pp_newline (pp);
-  m_map_from_b_to_m.dump_to_pp (pp);
-  pp_newline (pp);
-}
-
-/* Dump a multiline representation of this to FILE.  */
-
-void
-svalue_id_merger_mapping::dump (FILE *fp) const
-{
-  pretty_printer pp;
-  pp_format_decoder (&pp) = default_tree_printer;
-  pp_show_color (&pp) = pp_show_color (global_dc->printer);
-  pp.buffer->stream = fp;
-  dump_to_pp (&pp);
-  pp_flush (&pp);
-}
-
-/* Dump a multiline representation of this to stderr.  */
-
-DEBUG_FUNCTION void
-svalue_id_merger_mapping::dump () const
-{
-  dump (stderr);
-}
-
-/* struct canonicalization.  */
-
-/* canonicalization's ctor.  */
-
-canonicalization::canonicalization (const region_model &model)
-: m_model (model),
-  m_rid_map (model.get_num_regions ()),
-  m_sid_map (model.get_num_svalues ()),
-  m_next_rid_int (0),
-  m_next_sid_int (0)
-{
-}
-
-/* If we've not seen RID yet, assign it a canonicalized region_id,
-   and walk the region's svalue and then the region.  */
-
-void
-canonicalization::walk_rid (region_id rid)
-{
-  /* Stop if we've already seen RID.  */
-  if (!m_rid_map.get_dst_for_src (rid).null_p ())
-    return;
-
-  region *region = m_model.get_region (rid);
-  if (region)
-    {
-      m_rid_map.put (rid, region_id::from_int (m_next_rid_int++));
-      walk_sid (region->get_value_direct ());
-      region->walk_for_canonicalization (this);
-    }
-}
-
-/* If we've not seen SID yet, assign it a canonicalized svalue_id,
-   and walk the svalue (and potentially regions e.g. for ptr values).  */
-
-void
-canonicalization::walk_sid (svalue_id sid)
-{
-  /* Stop if we've already seen SID.  */
-  if (!m_sid_map.get_dst_for_src (sid).null_p ())
-    return;
-
-  svalue *sval = m_model.get_svalue (sid);
-  if (sval)
-    {
-      m_sid_map.put (sid, svalue_id::from_int (m_next_sid_int++));
-      /* Potentially walk regions e.g. for ptrs.  */
-      sval->walk_for_canonicalization (this);
-    }
-}
-
-/* Dump a multiline representation of this to PP.  */
-
-void
-canonicalization::dump_to_pp (pretty_printer *pp) const
-{
-  pp_string (pp, "region_id map:");
-  pp_newline (pp);
-  m_rid_map.dump_to_pp (pp);
-  pp_newline (pp);
-
-  pp_string (pp, "svalue_id map:");
-  pp_newline (pp);
-  m_sid_map.dump_to_pp (pp);
-  pp_newline (pp);
-}
-
-/* Dump a multiline representation of this to FILE.  */
-
-void
-canonicalization::dump (FILE *fp) const
-{
-  pretty_printer pp;
-  pp_format_decoder (&pp) = default_tree_printer;
-  pp_show_color (&pp) = pp_show_color (global_dc->printer);
-  pp.buffer->stream = fp;
-  dump_to_pp (&pp);
-  pp_flush (&pp);
-}
-
-/* Dump a multiline representation of this to stderr.  */
-
-DEBUG_FUNCTION void
-canonicalization::dump () const
-{
-  dump (stderr);
-}
-
-} // namespace ana
-
-/* Update HSTATE with a hash of SID.  */
-
-void
-inchash::add (svalue_id sid, inchash::hash &hstate)
-{
-  hstate.add_int (sid.as_int ());
-}
-
-/* Update HSTATE with a hash of RID.  */
-
-void
-inchash::add (region_id rid, inchash::hash &hstate)
-{
-  hstate.add_int (rid.as_int ());
-}
-
-/* Dump RMODEL fully to stderr (i.e. without summarization).  */
-
-DEBUG_FUNCTION void
-debug (const region_model &rmodel)
-{
-  rmodel.dump (false);
-}
-
-namespace ana {
-
-#if CHECKING_P
-
-namespace selftest {
-
-/* Build a constant tree of the given type from STR.  */
-
-static tree
-build_real_cst_from_string (tree type, const char *str)
-{
-  REAL_VALUE_TYPE real;
-  real_from_string (&real, str);
-  return build_real (type, real);
-}
-
-/* Append various "interesting" constants to OUT (e.g. NaN).  */
-
-static void
-append_interesting_constants (auto_vec<tree> *out)
-{
-  out->safe_push (build_int_cst (integer_type_node, 0));
-  out->safe_push (build_int_cst (integer_type_node, 42));
-  out->safe_push (build_int_cst (unsigned_type_node, 0));
-  out->safe_push (build_int_cst (unsigned_type_node, 42));
-  out->safe_push (build_real_cst_from_string (float_type_node, "QNaN"));
-  out->safe_push (build_real_cst_from_string (float_type_node, "-QNaN"));
-  out->safe_push (build_real_cst_from_string (float_type_node, "SNaN"));
-  out->safe_push (build_real_cst_from_string (float_type_node, "-SNaN"));
-  out->safe_push (build_real_cst_from_string (float_type_node, "0.0"));
-  out->safe_push (build_real_cst_from_string (float_type_node, "-0.0"));
-  out->safe_push (build_real_cst_from_string (float_type_node, "Inf"));
-  out->safe_push (build_real_cst_from_string (float_type_node, "-Inf"));
-}
-
-/* Verify that tree_cmp is a well-behaved comparator for qsort, even
-   if the underlying constants aren't comparable.  */
-
-static void
-test_tree_cmp_on_constants ()
-{
-  auto_vec<tree> csts;
-  append_interesting_constants (&csts);
-
-  /* Try sorting every triple. */
-  const unsigned num = csts.length ();
-  for (unsigned i = 0; i < num; i++)
-    for (unsigned j = 0; j < num; j++)
-      for (unsigned k = 0; k < num; k++)
-	{
-	  auto_vec<tree> v (3);
-	  v.quick_push (csts[i]);
-	  v.quick_push (csts[j]);
-	  v.quick_push (csts[k]);
-	  v.qsort (tree_cmp);
-	}
-}
-
-/* Implementation detail of the ASSERT_CONDITION_* macros.  */
-
-void
-assert_condition (const location &loc,
-		  region_model &model,
-		  tree lhs, tree_code op, tree rhs,
-		  tristate expected)
-{
-  tristate actual = model.eval_condition (lhs, op, rhs, NULL);
-  ASSERT_EQ_AT (loc, actual, expected);
-}
-
-/* Implementation detail of ASSERT_DUMP_TREE_EQ.  */
-
-static void
-assert_dump_tree_eq (const location &loc, tree t, const char *expected)
-{
-  auto_fix_quotes sentinel;
-  pretty_printer pp;
-  pp_format_decoder (&pp) = default_tree_printer;
-  dump_tree (&pp, t);
-  ASSERT_STREQ_AT (loc, pp_formatted_text (&pp), expected);
-}
-
-/* Assert that dump_tree (T) is EXPECTED.  */
-
-#define ASSERT_DUMP_TREE_EQ(T, EXPECTED) \
-  SELFTEST_BEGIN_STMT							\
-  assert_dump_tree_eq ((SELFTEST_LOCATION), (T), (EXPECTED)); \
-  SELFTEST_END_STMT
-
-/* Implementation detail of ASSERT_DUMP_EQ.  */
-
-static void
-assert_dump_eq (const location &loc,
-		const region_model &model,
-		bool summarize,
-		const char *expected)
-{
-  auto_fix_quotes sentinel;
-  pretty_printer pp;
-  pp_format_decoder (&pp) = default_tree_printer;
-  model.dump_to_pp (&pp, summarize);
-  ASSERT_STREQ_AT (loc, pp_formatted_text (&pp), expected);
-}
-
-/* Assert that MODEL.dump_to_pp (SUMMARIZE) is EXPECTED.  */
-
-#define ASSERT_DUMP_EQ(MODEL, SUMMARIZE, EXPECTED) \
-  SELFTEST_BEGIN_STMT							\
-  assert_dump_eq ((SELFTEST_LOCATION), (MODEL), (SUMMARIZE), (EXPECTED)); \
-  SELFTEST_END_STMT
-
-/* Smoketest for region_model::dump_to_pp.  */
-
-static void
-test_dump ()
-{
-  region_model model;
-  model.get_root_region ()->ensure_stack_region (&model);
-  model.get_root_region ()->ensure_globals_region (&model);
-  model.get_root_region ()->ensure_heap_region (&model);
-
-  ASSERT_DUMP_EQ (model, false,
-		  "r0: {kind: `root', parent: null, sval: null}\n"
-		  "|-stack: r1: {kind: `stack', parent: r0, sval: null}\n"
-		  "|-globals: r2: {kind: `globals', parent: r0, sval: null, map: {}}\n"
-		  "`-heap: r3: {kind: `heap', parent: r0, sval: null}\n"
-		  "svalues:\n"
-		  "constraint manager:\n"
-		  "  equiv classes:\n"
-		  "  constraints:\n");
-  ASSERT_DUMP_EQ (model, true, "");
-}
-
-/* Helper function for selftests.  Create a struct or union type named NAME,
-   with the fields given by the FIELD_DECLS in FIELDS.
-   If IS_STRUCT is true create a RECORD_TYPE (aka a struct), otherwise
-   create a UNION_TYPE.  */
-
-static tree
-make_test_compound_type (const char *name, bool is_struct,
-			 const auto_vec<tree> *fields)
-{
-  tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
-  TYPE_NAME (t) = get_identifier (name);
-  TYPE_SIZE (t) = 0;
-
-  tree fieldlist = NULL;
-  int i;
-  tree field;
-  FOR_EACH_VEC_ELT (*fields, i, field)
-    {
-      gcc_assert (TREE_CODE (field) == FIELD_DECL);
-      DECL_CONTEXT (field) = t;
-      fieldlist = chainon (field, fieldlist);
-    }
-  fieldlist = nreverse (fieldlist);
-  TYPE_FIELDS (t) = fieldlist;
-
-  layout_type (t);
-  return t;
-}
-
-/* Selftest fixture for creating the type "struct coord {int x; int y; };".  */
-
-struct coord_test
-{
-  coord_test ()
-  {
-    auto_vec<tree> fields;
-    m_x_field = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
-			       get_identifier ("x"), integer_type_node);
-    fields.safe_push (m_x_field);
-    m_y_field = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
-			       get_identifier ("y"), integer_type_node);
-    fields.safe_push (m_y_field);
-    m_coord_type = make_test_compound_type ("coord", true, &fields);
-  }
-
-  tree m_x_field;
-  tree m_y_field;
-  tree m_coord_type;
-};
-
-/* Verify that dumps can show struct fields.  */
-
-static void
-test_dump_2 ()
-{
-  coord_test ct;
-
-  tree c = build_global_decl ("c", ct.m_coord_type);
-  tree c_x = build3 (COMPONENT_REF, TREE_TYPE (ct.m_x_field),
-		     c, ct.m_x_field, NULL_TREE);
-  tree c_y = build3 (COMPONENT_REF, TREE_TYPE (ct.m_y_field),
-		     c, ct.m_y_field, NULL_TREE);
-
-  tree int_17 = build_int_cst (integer_type_node, 17);
-  tree int_m3 = build_int_cst (integer_type_node, -3);
-
-  region_model model;
-  model.set_value (c_x, int_17, NULL);
-  model.set_value (c_y, int_m3, NULL);
-
-  /* Simplified dump.  */
-  ASSERT_DUMP_EQ (model, true, "c.x: 17, c.y: -3");
-
-  /* Full dump.  */
-  ASSERT_DUMP_EQ
-    (model, false,
-     "r0: {kind: `root', parent: null, sval: null}\n"
-     "`-globals: r1: {kind: `globals', parent: r0, sval: null, map: {`c': r2}}\n"
-     "  `-`c': r2: {kind: `struct', parent: r1, sval: null, type: `struct coord', map: {`x': r3, `y': r4}}\n"
-     "    |: type: `struct coord'\n"
-     "    |-`x': r3: {kind: `primitive', parent: r2, sval: sv0, type: `int'}\n"
-     "    |  |: sval: sv0: {type: `int', `17'}\n"
-     "    |  |: type: `int'\n"
-     "    `-`y': r4: {kind: `primitive', parent: r2, sval: sv1, type: `int'}\n"
-     "      |: sval: sv1: {type: `int', `-3'}\n"
-     "      |: type: `int'\n"
-     "svalues:\n"
-     "  sv0: {type: `int', `17'}\n"
-     "  sv1: {type: `int', `-3'}\n"
-     "constraint manager:\n"
-     "  equiv classes:\n"
-     "  constraints:\n");
-}
-
-/* Verify that dumps can show array elements.  */
-
-static void
-test_dump_3 ()
-{
-  tree tlen = size_int (10);
-  tree arr_type = build_array_type (char_type_node, build_index_type (tlen));
-
-  tree a = build_global_decl ("a", arr_type);
-
-  region_model model;
-  tree int_0 = build_int_cst (integer_type_node, 0);
-  tree a_0 = build4 (ARRAY_REF, char_type_node,
-		     a, int_0, NULL_TREE, NULL_TREE);
-  tree char_A = build_int_cst (char_type_node, 'A');
-  model.set_value (a_0, char_A, NULL);
-
-  /* Simplified dump.  */
-  ASSERT_DUMP_EQ (model, true, "a[0]: 65");
-
-  /* Full dump.  */
-  ASSERT_DUMP_EQ
-    (model, false,
-     "r0: {kind: `root', parent: null, sval: null}\n"
-     "`-globals: r1: {kind: `globals', parent: r0, sval: null, map: {`a': r2}}\n"
-     "  `-`a': r2: {kind: `array', parent: r1, sval: null, type: `char[11]', array: {[0]: r3}}\n"
-     "    |: type: `char[11]'\n"
-     "    `-[0]: r3: {kind: `primitive', parent: r2, sval: sv1, type: `char'}\n"
-     "      |: sval: sv1: {type: `char', `65'}\n"
-     "      |: type: `char'\n"
-     "svalues:\n"
-     "  sv0: {type: `int', `0'}\n"
-     "  sv1: {type: `char', `65'}\n"
-     "constraint manager:\n"
-     "  equiv classes:\n"
-     "  constraints:\n");
-}
-
-/* Verify that region_model::get_representative_tree works as expected.  */
-
-static void
-test_get_representative_tree ()
-{
-  /* STRING_CST.  */
-  {
-    tree string_cst = build_string (4, "foo");
-    region_model m;
-    svalue_id str_sid = m.get_rvalue (string_cst, NULL);
-    tree rep = m.get_representative_tree (str_sid);
-    ASSERT_EQ (rep, string_cst);
-  }
-
-  /* String literal.  */
-  {
-    tree string_cst_ptr = build_string_literal (4, "foo");
-    region_model m;
-    svalue_id str_sid = m.get_rvalue (string_cst_ptr, NULL);
-    tree rep = m.get_representative_tree (str_sid);
-    ASSERT_DUMP_TREE_EQ (rep, "&\"foo\"[0]");
-  }
-}
-
-/* Verify that calling region_model::get_rvalue repeatedly on the same
-   tree constant retrieves the same svalue_id.  */
-
-static void
-test_unique_constants ()
-{
-  tree int_0 = build_int_cst (integer_type_node, 0);
-  tree int_42 = build_int_cst (integer_type_node, 42);
-
-  test_region_model_context ctxt;
-  region_model model;
-  ASSERT_EQ (model.get_rvalue (int_0, &ctxt), model.get_rvalue (int_0, &ctxt));
-  ASSERT_EQ (model.get_rvalue (int_42, &ctxt),
-	     model.get_rvalue (int_42, &ctxt));
-  ASSERT_NE (model.get_rvalue (int_0, &ctxt), model.get_rvalue (int_42, &ctxt));
-  ASSERT_EQ (ctxt.get_num_diagnostics (), 0);
-}
-
-/* Check that operator== and hashing works as expected for the
-   various svalue subclasses.  */
-
-static void
-test_svalue_equality ()
-{
-  tree int_42 = build_int_cst (integer_type_node, 42);
-  tree int_0 = build_int_cst (integer_type_node, 0);
-
-  /* Create pairs instances of the various subclasses of svalue,
-     testing for hash and equality between (this, this) and
-     (this, other of same subclass). */
-  svalue *ptr_to_r0
-    = new region_svalue (ptr_type_node, region_id::from_int (0));
-  svalue *ptr_to_r1
-    = new region_svalue (ptr_type_node, region_id::from_int (1));
-
-  ASSERT_EQ (ptr_to_r0->hash (), ptr_to_r0->hash ());
-  ASSERT_EQ (*ptr_to_r0, *ptr_to_r0);
-
-  ASSERT_NE (ptr_to_r0->hash (), ptr_to_r1->hash ());
-  ASSERT_NE (*ptr_to_r0, *ptr_to_r1);
-
-  svalue *cst_int_42 = new constant_svalue (int_42);
-  svalue *cst_int_0 = new constant_svalue (int_0);
-
-  ASSERT_EQ (cst_int_42->hash (), cst_int_42->hash ());
-  ASSERT_EQ (*cst_int_42, *cst_int_42);
-
-  ASSERT_NE (cst_int_42->hash (), cst_int_0->hash ());
-  ASSERT_NE (*cst_int_42, *cst_int_0);
-
-  svalue *unknown_0 = new unknown_svalue (ptr_type_node);
-  svalue *unknown_1 = new unknown_svalue (ptr_type_node);
-  ASSERT_EQ (unknown_0->hash (), unknown_0->hash ());
-  ASSERT_EQ (*unknown_0, *unknown_0);
-  ASSERT_EQ (*unknown_1, *unknown_1);
-
-  /* Comparisons between different kinds of svalue.  */
-  ASSERT_NE (*ptr_to_r0, *cst_int_42);
-  ASSERT_NE (*ptr_to_r0, *unknown_0);
-  ASSERT_NE (*cst_int_42, *ptr_to_r0);
-  ASSERT_NE (*cst_int_42, *unknown_0);
-  ASSERT_NE (*unknown_0, *ptr_to_r0);
-  ASSERT_NE (*unknown_0, *cst_int_42);
-
-  delete ptr_to_r0;
-  delete ptr_to_r1;
-  delete cst_int_42;
-  delete cst_int_0;
-  delete unknown_0;
-  delete unknown_1;
-}
-
-/* Check that operator== and hashing works as expected for the
-   various region subclasses.  */
-
-static void
-test_region_equality ()
-{
-  region *r0
-    = new primitive_region (region_id::from_int (3), integer_type_node);
-  region *r1
-    = new primitive_region (region_id::from_int (4), integer_type_node);
-
-  ASSERT_EQ (*r0, *r0);
-  ASSERT_EQ (r0->hash (), r0->hash ());
-  ASSERT_NE (*r0, *r1);
-  ASSERT_NE (r0->hash (), r1->hash ());
-
-  delete r0;
-  delete r1;
-
-  // TODO: test coverage for the map within a map_region
-}
-
-/* A subclass of purge_criteria for selftests: purge all svalue_id instances.  */
-
-class purge_all_svalue_ids : public purge_criteria
-{
-public:
-  bool should_purge_p (svalue_id) const FINAL OVERRIDE
-  {
-    return true;
-  }
-};
-
-/* A subclass of purge_criteria: purge a specific svalue_id.  */
-
-class purge_one_svalue_id : public purge_criteria
-{
-public:
-  purge_one_svalue_id (svalue_id victim) : m_victim (victim) {}
-
-  purge_one_svalue_id (region_model model, tree expr)
-  : m_victim (model.get_rvalue (expr, NULL)) {}
-
-  bool should_purge_p (svalue_id sid) const FINAL OVERRIDE
-  {
-    return sid == m_victim;
-  }
-
-private:
-  svalue_id m_victim;
-};
-
-/* Check that constraint_manager::purge works for individual svalue_ids.  */
-
-static void
-test_purging_by_criteria ()
-{
-  tree int_42 = build_int_cst (integer_type_node, 42);
-  tree int_0 = build_int_cst (integer_type_node, 0);
-
-  tree x = build_global_decl ("x", integer_type_node);
-  tree y = build_global_decl ("y", integer_type_node);
-
-  {
-    region_model model0;
-    region_model model1;
-
-    ADD_SAT_CONSTRAINT (model1, x, EQ_EXPR, y);
-    ASSERT_NE (model0, model1);
-
-    purge_stats stats_for_px;
-    purge_one_svalue_id px (model1, x);
-    model1.get_constraints ()->purge (px, &stats_for_px);
-    ASSERT_EQ (stats_for_px.m_num_equiv_classes, 0);
-
-    purge_stats stats_for_py;
-    purge_one_svalue_id py (model1.get_rvalue (y, NULL));
-    model1.get_constraints ()->purge (py, &stats_for_py);
-    ASSERT_EQ (stats_for_py.m_num_equiv_classes, 1);
-
-    ASSERT_EQ (*model0.get_constraints (), *model1.get_constraints ());
-  }
-
-  {
-    region_model model0;
-    region_model model1;
-
-    ADD_SAT_CONSTRAINT (model1, x, EQ_EXPR, int_42);
-    ASSERT_NE (model0, model1);
-    ASSERT_CONDITION_TRUE (model1, x, EQ_EXPR, int_42);
-
-    purge_stats stats;
-    model1.get_constraints ()->purge (purge_one_svalue_id (model1, x), &stats);
-
-    ASSERT_CONDITION_UNKNOWN (model1, x, EQ_EXPR, int_42);
-  }
-
-  {
-    region_model model0;
-    region_model model1;
-
-    ADD_SAT_CONSTRAINT (model1, x, GE_EXPR, int_0);
-    ADD_SAT_CONSTRAINT (model1, x, LE_EXPR, int_42);
-    ASSERT_NE (model0, model1);
-
-    ASSERT_CONDITION_TRUE (model1, x, GE_EXPR, int_0);
-    ASSERT_CONDITION_TRUE (model1, x, LE_EXPR, int_42);
-
-    purge_stats stats;
-    model1.get_constraints ()->purge (purge_one_svalue_id (model1, x), &stats);
-
-    ASSERT_CONDITION_UNKNOWN (model1, x, GE_EXPR, int_0);
-    ASSERT_CONDITION_UNKNOWN (model1, x, LE_EXPR, int_42);
-  }
-
-  {
-    region_model model0;
-    region_model model1;
-
-    ADD_SAT_CONSTRAINT (model1, x, NE_EXPR, int_42);
-    ADD_SAT_CONSTRAINT (model1, y, NE_EXPR, int_0);
-    ASSERT_NE (model0, model1);
-    ASSERT_CONDITION_TRUE (model1, x, NE_EXPR, int_42);
-    ASSERT_CONDITION_TRUE (model1, y, NE_EXPR, int_0);
-
-    purge_stats stats;
-    model1.get_constraints ()->purge (purge_one_svalue_id (model1, x), &stats);
-    ASSERT_NE (model0, model1);
-
-    ASSERT_CONDITION_UNKNOWN (model1, x, NE_EXPR, int_42);
-    ASSERT_CONDITION_TRUE (model1, y, NE_EXPR, int_0);
-  }
-
-  {
-    region_model model0;
-    region_model model1;
-
-    ADD_SAT_CONSTRAINT (model1, x, NE_EXPR, int_42);
-    ADD_SAT_CONSTRAINT (model1, y, NE_EXPR, int_0);
-    ASSERT_NE (model0, model1);
-    ASSERT_CONDITION_TRUE (model1, x, NE_EXPR, int_42);
-    ASSERT_CONDITION_TRUE (model1, y, NE_EXPR, int_0);
-
-    purge_stats stats;
-    model1.get_constraints ()->purge (purge_all_svalue_ids (), &stats);
-    ASSERT_CONDITION_UNKNOWN (model1, x, NE_EXPR, int_42);
-    ASSERT_CONDITION_UNKNOWN (model1, y, NE_EXPR, int_0);
-  }
-
-}
-
-/* Test that region_model::purge_unused_svalues works as expected.  */
-
-static void
-test_purge_unused_svalues ()
-{
-  tree int_42 = build_int_cst (integer_type_node, 42);
-  tree int_0 = build_int_cst (integer_type_node, 0);
-  tree x = build_global_decl ("x", integer_type_node);
-  tree y = build_global_decl ("y", integer_type_node);
-
-  test_region_model_context ctxt;
-  region_model model;
-  model.set_to_new_unknown_value (model.get_lvalue (x, &ctxt), TREE_TYPE (x),
-				  &ctxt);
-  model.set_to_new_unknown_value (model.get_lvalue (x, &ctxt), TREE_TYPE (x),
-				  &ctxt);
-  model.set_to_new_unknown_value (model.get_lvalue (x, &ctxt), TREE_TYPE (x),
-				  &ctxt);
-  model.add_constraint (x, NE_EXPR, int_42, &ctxt);
-
-  model.set_value (model.get_lvalue (x, &ctxt),
-		   model.get_rvalue (int_42, &ctxt),
-		   &ctxt);
-  model.add_constraint (y, GT_EXPR, int_0, &ctxt);
-
-  /* The redundant unknown values should have been purged.  */
-  purge_stats purged;
-  model.purge_unused_svalues (&purged, NULL);
-  ASSERT_EQ (purged.m_num_svalues, 3);
-
-  /* and the redundant constraint on an old, unknown value for x should
-     have been purged.  */
-  ASSERT_EQ (purged.m_num_equiv_classes, 1);
-  ASSERT_EQ (purged.m_num_constraints, 1);
-  ASSERT_EQ (model.get_constraints ()->m_constraints.length (), 2);
-
-  /* ...but we should still have x == 42.  */
-  ASSERT_EQ (model.eval_condition (x, EQ_EXPR, int_42, &ctxt),
-	     tristate::TS_TRUE);
-
-  /* ...and we should still have the constraint on y.  */
-  ASSERT_EQ (model.eval_condition (y, GT_EXPR, int_0, &ctxt),
-	     tristate::TS_TRUE);
-
-  ASSERT_EQ (ctxt.get_num_diagnostics (), 0);
-}
-
-/* Verify that simple assignments work as expected.  */
-
-static void
-test_assignment ()
-{
-  tree int_0 = build_int_cst (integer_type_node, 0);
-  tree x = build_global_decl ("x", integer_type_node);
-  tree y = build_global_decl ("y", integer_type_node);
-
-  /* "x == 0", then use of y, then "y = 0;".  */
-  region_model model;
-  ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, int_0);
-  ASSERT_CONDITION_UNKNOWN (model, y, EQ_EXPR, int_0);
-  model.set_value (model.get_lvalue (y, NULL),
-		   model.get_rvalue (int_0, NULL),
-		   NULL);
-  ASSERT_CONDITION_TRUE (model, y, EQ_EXPR, int_0);
-  ASSERT_CONDITION_TRUE (model, y, EQ_EXPR, x);
-
-  ASSERT_DUMP_EQ (model, true, "y: 0, {x}: unknown, x == y");
-}
-
-/* Verify that compound assignments work as expected.  */
-
-static void
-test_compound_assignment ()
-{
-  coord_test ct;
-
-  tree c = build_global_decl ("c", ct.m_coord_type);
-  tree c_x = build3 (COMPONENT_REF, TREE_TYPE (ct.m_x_field),
-		     c, ct.m_x_field, NULL_TREE);
-  tree c_y = build3 (COMPONENT_REF, TREE_TYPE (ct.m_y_field),
-		     c, ct.m_y_field, NULL_TREE);
-  tree d = build_global_decl ("d", ct.m_coord_type);
-  tree d_x = build3 (COMPONENT_REF, TREE_TYPE (ct.m_x_field),
-		     d, ct.m_x_field, NULL_TREE);
-  tree d_y = build3 (COMPONENT_REF, TREE_TYPE (ct.m_y_field),
-		     d, ct.m_y_field, NULL_TREE);
-
-  tree int_17 = build_int_cst (integer_type_node, 17);
-  tree int_m3 = build_int_cst (integer_type_node, -3);
-
-  region_model model;
-  model.set_value (c_x, int_17, NULL);
-  model.set_value (c_y, int_m3, NULL);
-
-  ASSERT_DUMP_EQ (model, true, "c.x: 17, c.y: -3");
-
-  /* Copy c to d.  */
-  model.copy_region (model.get_lvalue (d, NULL), model.get_lvalue (c, NULL),
-		     NULL);
-  /* Check that the fields have the same svalues.  */
-  ASSERT_EQ (model.get_rvalue (c_x, NULL), model.get_rvalue (d_x, NULL));
-  ASSERT_EQ (model.get_rvalue (c_y, NULL), model.get_rvalue (d_y, NULL));
-}
-
-/* Verify the details of pushing and popping stack frames.  */
-
-static void
-test_stack_frames ()
-{
-  tree int_42 = build_int_cst (integer_type_node, 42);
-  tree int_10 = build_int_cst (integer_type_node, 10);
-  tree int_5 = build_int_cst (integer_type_node, 5);
-  tree int_0 = build_int_cst (integer_type_node, 0);
-
-  auto_vec <tree> param_types;
-  tree parent_fndecl = make_fndecl (integer_type_node,
-				    "parent_fn",
-				    param_types);
-  allocate_struct_function (parent_fndecl, true);
-
-  tree child_fndecl = make_fndecl (integer_type_node,
-				   "child_fn",
-				   param_types);
-  allocate_struct_function (child_fndecl, true);
-
-  /* "a" and "b" in the parent frame.  */
-  tree a = build_decl (UNKNOWN_LOCATION, PARM_DECL,
-		       get_identifier ("a"),
-		       integer_type_node);
-  tree b = build_decl (UNKNOWN_LOCATION, PARM_DECL,
-		       get_identifier ("b"),
-		       integer_type_node);
-  /* "x" and "y" in a child frame.  */
-  tree x = build_decl (UNKNOWN_LOCATION, PARM_DECL,
-		       get_identifier ("x"),
-		       integer_type_node);
-  tree y = build_decl (UNKNOWN_LOCATION, PARM_DECL,
-		       get_identifier ("y"),
-		       integer_type_node);
-
-  /* "p" global.  */
-  tree p = build_global_decl ("p", ptr_type_node);
-
-  /* "q" global.  */
-  tree q = build_global_decl ("q", ptr_type_node);
-
-  test_region_model_context ctxt;
-  region_model model;
-
-  /* Push stack frame for "parent_fn".  */
-  region_id parent_frame_rid
-    = model.push_frame (DECL_STRUCT_FUNCTION (parent_fndecl), NULL, &ctxt);
-  ASSERT_EQ (model.get_current_frame_id (), parent_frame_rid);
-  region_id a_in_parent_rid = model.get_lvalue (a, &ctxt);
-  model.set_value (a_in_parent_rid, model.get_rvalue (int_42, &ctxt), &ctxt);
-  model.set_to_new_unknown_value (model.get_lvalue (b, &ctxt),
-				  integer_type_node, &ctxt);
-  model.add_constraint (b, LT_EXPR, int_10, &ctxt);
-  ASSERT_EQ (model.eval_condition (b, LT_EXPR, int_10, &ctxt),
-	     tristate (tristate::TS_TRUE));
-
-  /* Push stack frame for "child_fn".  */
-  region_id child_frame_rid
-    = model.push_frame (DECL_STRUCT_FUNCTION (child_fndecl), NULL, &ctxt);
-  ASSERT_EQ (model.get_current_frame_id (), child_frame_rid);
-  region_id x_in_child_rid = model.get_lvalue (x, &ctxt);
-  model.set_value (x_in_child_rid, model.get_rvalue (int_0, &ctxt), &ctxt);
-  model.set_to_new_unknown_value (model.get_lvalue (y, &ctxt),
-				  integer_type_node, &ctxt);
-  model.add_constraint (y, NE_EXPR, int_5, &ctxt);
-  ASSERT_EQ (model.eval_condition (y, NE_EXPR, int_5, &ctxt),
-	     tristate (tristate::TS_TRUE));
-
-  /* Point a global pointer at a local in the child frame:  p = &x.  */
-  region_id p_in_globals_rid = model.get_lvalue (p, &ctxt);
-  model.set_value (p_in_globals_rid,
-		   model.get_or_create_ptr_svalue (ptr_type_node,
-						   x_in_child_rid),
-		   &ctxt);
-
-  /* Point another global pointer at p: q = &p.  */
-  region_id q_in_globals_rid = model.get_lvalue (q, &ctxt);
-  model.set_value (q_in_globals_rid,
-		   model.get_or_create_ptr_svalue (ptr_type_node,
-						   p_in_globals_rid),
-		   &ctxt);
-
-  /* Test get_descendents.  */
-  region_id_set descendents (&model);
-  model.get_descendents (child_frame_rid, &descendents, region_id::null ());
-  ASSERT_TRUE (descendents.region_p (child_frame_rid));
-  ASSERT_TRUE (descendents.region_p (x_in_child_rid));
-  ASSERT_FALSE (descendents.region_p (a_in_parent_rid));
-  ASSERT_EQ (descendents.num_regions (), 3);
-#if 0
-  auto_vec<region_id> test_vec;
-  for (region_id_set::iterator_t iter = descendents.begin ();
-       iter != descendents.end ();
-       ++iter)
-    test_vec.safe_push (*iter);
-  gcc_unreachable (); // TODO
-  //ASSERT_EQ ();
-#endif
-
-  ASSERT_DUMP_EQ (model, true,
-		  "a: 42, x: 0, p: &x, q: &p, {b, y}: unknown, b < 10, y != 5");
-
-  /* Pop the "child_fn" frame from the stack.  */
-  purge_stats purged;
-  model.pop_frame (region_id::null (), true, &purged, &ctxt);
-
-  /* We should have purged the unknown values for x and y. */
-  ASSERT_EQ (purged.m_num_svalues, 2);
-
-  /* We should have purged the frame region and the regions for x and y. */
-  ASSERT_EQ (purged.m_num_regions, 3);
-
-  /* We should have purged the constraint on y.  */
-  ASSERT_EQ (purged.m_num_equiv_classes, 1);
-  ASSERT_EQ (purged.m_num_constraints, 1);
-
-  /* Verify that p (which was pointing at the local "x" in the popped
-     frame) has been poisoned.  */
-  svalue *new_p_sval = model.get_svalue (model.get_rvalue (p, &ctxt));
-  ASSERT_EQ (new_p_sval->get_kind (), SK_POISONED);
-  ASSERT_EQ (new_p_sval->dyn_cast_poisoned_svalue ()->get_poison_kind (),
-	     POISON_KIND_POPPED_STACK);
-
-  /* Verify that q still points to p, in spite of the region
-     renumbering.  */
-  svalue *new_q_sval = model.get_svalue (model.get_rvalue (q, &ctxt));
-  ASSERT_EQ (new_q_sval->get_kind (), SK_REGION);
-  ASSERT_EQ (new_q_sval->dyn_cast_region_svalue ()->get_pointee (),
-	     model.get_lvalue (p, &ctxt));
-
-  /* Verify that top of stack has been updated.  */
-  ASSERT_EQ (model.get_current_frame_id (), parent_frame_rid);
-
-  /* Verify locals in parent frame.  */
-  /* Verify "a" still has its value.  */
-  svalue *new_a_sval = model.get_svalue (model.get_rvalue (a, &ctxt));
-  ASSERT_EQ (new_a_sval->get_kind (), SK_CONSTANT);
-  ASSERT_EQ (new_a_sval->dyn_cast_constant_svalue ()->get_constant (),
-	     int_42);
-  /* Verify "b" still has its constraint.  */
-  ASSERT_EQ (model.eval_condition (b, LT_EXPR, int_10, &ctxt),
-	     tristate (tristate::TS_TRUE));
-}
-
-/* Verify that get_representative_path_var works as expected, that
-   we can map from region ids to parms and back within a recursive call
-   stack.  */
-
-static void
-test_get_representative_path_var ()
-{
-  auto_vec <tree> param_types;
-  tree fndecl = make_fndecl (integer_type_node,
-			     "factorial",
-			     param_types);
-  allocate_struct_function (fndecl, true);
-
-  /* Parm "n".  */
-  tree n = build_decl (UNKNOWN_LOCATION, PARM_DECL,
-		       get_identifier ("n"),
-		       integer_type_node);
-
-  region_model model;
-
-  /* Push 5 stack frames for "factorial", each with a param  */
-  auto_vec<region_id> parm_rids;
-  auto_vec<svalue_id> parm_sids;
-  for (int depth = 0; depth < 5; depth++)
-    {
-      region_id frame_rid
-	= model.push_frame (DECL_STRUCT_FUNCTION (fndecl), NULL, NULL);
-      region_id rid_n = model.get_lvalue (path_var (n, depth), NULL);
-      parm_rids.safe_push (rid_n);
-
-      ASSERT_EQ (model.get_region (rid_n)->get_parent (), frame_rid);
-
-      svalue_id sid_n
-	= model.set_to_new_unknown_value (rid_n, integer_type_node, NULL);
-      parm_sids.safe_push (sid_n);
-    }
-
-  /* Verify that we can recognize that the regions are the parms,
-     at every depth.  */
-  for (int depth = 0; depth < 5; depth++)
-    {
-      ASSERT_EQ (model.get_representative_path_var (parm_rids[depth]),
-		 path_var (n, depth));
-      /* ...and that we can lookup lvalues for locals for all frames,
-	 not just the top.  */
-      ASSERT_EQ (model.get_lvalue (path_var (n, depth), NULL),
-		 parm_rids[depth]);
-      /* ...and that we can locate the svalues.  */
-      auto_vec<path_var> pvs;
-      model.get_path_vars_for_svalue (parm_sids[depth], &pvs);
-      ASSERT_EQ (pvs.length (), 1);
-      ASSERT_EQ (pvs[0], path_var (n, depth));
-    }
-}
-
-/* Verify that the core regions within a region_model are in a consistent
-   order after canonicalization.  */
-
-static void
-test_canonicalization_1 ()
-{
-  region_model model0;
-  model0.get_root_region ()->ensure_stack_region (&model0);
-  model0.get_root_region ()->ensure_globals_region (&model0);
-
-  region_model model1;
-  model1.get_root_region ()->ensure_globals_region (&model1);
-  model1.get_root_region ()->ensure_stack_region (&model1);
-
-  model0.canonicalize (NULL);
-  model1.canonicalize (NULL);
-  ASSERT_EQ (model0, model1);
-}
-
-/* Verify that region models for
-      x = 42; y = 113;
-   and
-      y = 113; x = 42;
-   are equal after canonicalization.  */
-
-static void
-test_canonicalization_2 ()
-{
-  tree int_42 = build_int_cst (integer_type_node, 42);
-  tree int_113 = build_int_cst (integer_type_node, 113);
-  tree x = build_global_decl ("x", integer_type_node);
-  tree y = build_global_decl ("y", integer_type_node);
-
-  region_model model0;
-  model0.set_value (model0.get_lvalue (x, NULL),
-		    model0.get_rvalue (int_42, NULL),
-		    NULL);
-  model0.set_value (model0.get_lvalue (y, NULL),
-		    model0.get_rvalue (int_113, NULL),
-		    NULL);
-
-  region_model model1;
-  model1.set_value (model1.get_lvalue (y, NULL),
-		    model1.get_rvalue (int_113, NULL),
-		    NULL);
-  model1.set_value (model1.get_lvalue (x, NULL),
-		    model1.get_rvalue (int_42, NULL),
-		    NULL);
-
-  model0.canonicalize (NULL);
-  model1.canonicalize (NULL);
-  ASSERT_EQ (model0, model1);
-}
-
-/* Verify that constraints for
-     x > 3 && y > 42
-   and
-     y > 42 && x > 3
-   are equal after canonicalization.  */
-
-static void
-test_canonicalization_3 ()
-{
-  tree int_3 = build_int_cst (integer_type_node, 3);
-  tree int_42 = build_int_cst (integer_type_node, 42);
-  tree x = build_global_decl ("x", integer_type_node);
-  tree y = build_global_decl ("y", integer_type_node);
-
-  region_model model0;
-  model0.add_constraint (x, GT_EXPR, int_3, NULL);
-  model0.add_constraint (y, GT_EXPR, int_42, NULL);
-
-  region_model model1;
-  model1.add_constraint (y, GT_EXPR, int_42, NULL);
-  model1.add_constraint (x, GT_EXPR, int_3, NULL);
-
-  model0.canonicalize (NULL);
-  model1.canonicalize (NULL);
-  ASSERT_EQ (model0, model1);
-}
-
-/* Verify that we can canonicalize a model containing NaN and other real
-   constants.  */
-
-static void
-test_canonicalization_4 ()
-{
-  auto_vec<tree> csts;
-  append_interesting_constants (&csts);
-
-  region_model model;
-
-  unsigned i;
-  tree cst;
-  FOR_EACH_VEC_ELT (csts, i, cst)
-    model.get_rvalue (cst, NULL);
-
-  model.canonicalize (NULL);
-}
-
-/* Assert that if we have two region_model instances
-   with values VAL_A and VAL_B for EXPR that they are
-   mergable.  Write the merged model to *OUT_MERGED_MODEL,
-   and the merged svalue ptr to *OUT_MERGED_SVALUE.
-   If VAL_A or VAL_B are NULL_TREE, don't populate EXPR
-   for that region_model.  */
-
-static void
-assert_region_models_merge (tree expr, tree val_a, tree val_b,
-			    region_model *out_merged_model,
-			    svalue **out_merged_svalue)
-{
-  test_region_model_context ctxt;
-  region_model model0;
-  region_model model1;
-  if (val_a)
-    model0.set_value (model0.get_lvalue (expr, &ctxt),
-		      model0.get_rvalue (val_a, &ctxt),
-		      &ctxt);
-  if (val_b)
-    model1.set_value (model1.get_lvalue (expr, &ctxt),
-		      model1.get_rvalue (val_b, &ctxt),
-		      &ctxt);
-
-  /* They should be mergeable.  */
-  ASSERT_TRUE (model0.can_merge_with_p (model1, out_merged_model));
-
-  svalue_id merged_svalue_sid = out_merged_model->get_rvalue (expr, &ctxt);
-  *out_merged_svalue = out_merged_model->get_svalue (merged_svalue_sid);
-}
-
-/* Verify that we can merge region_model instances.  */
-
-static void
-test_state_merging ()
-{
-  tree int_42 = build_int_cst (integer_type_node, 42);
-  tree int_113 = build_int_cst (integer_type_node, 113);
-  tree x = build_global_decl ("x", integer_type_node);
-  tree y = build_global_decl ("y", integer_type_node);
-  tree z = build_global_decl ("z", integer_type_node);
-  tree p = build_global_decl ("p", ptr_type_node);
-
-  tree addr_of_y = build1 (ADDR_EXPR, ptr_type_node, y);
-  tree addr_of_z = build1 (ADDR_EXPR, ptr_type_node, z);
-
-  auto_vec <tree> param_types;
-  tree test_fndecl = make_fndecl (integer_type_node, "test_fn", param_types);
-  allocate_struct_function (test_fndecl, true);
-
-  /* Param "a".  */
-  tree a = build_decl (UNKNOWN_LOCATION, PARM_DECL,
-		       get_identifier ("a"),
-		       integer_type_node);
-  tree addr_of_a = build1 (ADDR_EXPR, ptr_type_node, a);
-
-  /* Param "q", a pointer.  */
-  tree q = build_decl (UNKNOWN_LOCATION, PARM_DECL,
-		       get_identifier ("q"),
-		       ptr_type_node);
-
-  {
-    region_model model0;
-    region_model model1;
-    region_model merged;
-    /* Verify empty models can be merged.  */
-    ASSERT_TRUE (model0.can_merge_with_p (model1, &merged));
-    ASSERT_EQ (model0, merged);
-  }
-
-  /* Verify that we can merge two contradictory constraints on the
-     value for a global.  */
-  /* TODO: verify that the merged model doesn't have a value for
-     the global  */
-  {
-    region_model model0;
-    region_model model1;
-    region_model merged;
-    test_region_model_context ctxt;
-    model0.add_constraint (x, EQ_EXPR, int_42, &ctxt);
-    model1.add_constraint (x, EQ_EXPR, int_113, &ctxt);
-    ASSERT_TRUE (model0.can_merge_with_p (model1, &merged));
-    ASSERT_NE (model0, merged);
-    ASSERT_NE (model1, merged);
-  }
-
-  /* Verify handling of a PARM_DECL.  */
-  {
-    test_region_model_context ctxt;
-    region_model model0;
-    region_model model1;
-    ASSERT_EQ (model0.get_stack_depth (), 0);
-    model0.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, &ctxt);
-    ASSERT_EQ (model0.get_stack_depth (), 1);
-    ASSERT_EQ (model0.get_function_at_depth (0),
-	       DECL_STRUCT_FUNCTION (test_fndecl));
-    model1.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, &ctxt);
-
-    svalue_id sid_a
-      = model0.set_to_new_unknown_value (model0.get_lvalue (a, &ctxt),
-					 integer_type_node, &ctxt);
-    model1.set_to_new_unknown_value (model1.get_lvalue (a, &ctxt),
-				     integer_type_node, &ctxt);
-    ASSERT_EQ (model0, model1);
-
-    /* Check that get_value_by_name works for locals.  */
-    ASSERT_EQ (model0.get_value_by_name ("a"), sid_a);
-
-    /* They should be mergeable, and the result should be the same.  */
-    region_model merged;
-    ASSERT_TRUE (model0.can_merge_with_p (model1, &merged));
-    ASSERT_EQ (model0, merged);
-    /* In particular, there should be an unknown value for "a".  */
-    svalue *merged_a_sval = merged.get_svalue (merged.get_rvalue (a, &ctxt));
-    ASSERT_EQ (merged_a_sval->get_kind (), SK_UNKNOWN);
-  }
-
-  /* Verify handling of a global.  */
-  {
-    test_region_model_context ctxt;
-    region_model model0;
-    region_model model1;
-    svalue_id sid_x
-      = model0.set_to_new_unknown_value (model0.get_lvalue (x, &ctxt),
-					 integer_type_node, &ctxt);
-    model1.set_to_new_unknown_value (model1.get_lvalue (x, &ctxt),
-				     integer_type_node, &ctxt);
-    ASSERT_EQ (model0, model1);
-
-    /* Check that get_value_by_name works for globals.  */
-    ASSERT_EQ (model0.get_value_by_name ("x"), sid_x);
-
-    /* They should be mergeable, and the result should be the same.  */
-    region_model merged;
-    ASSERT_TRUE (model0.can_merge_with_p (model1, &merged));
-    ASSERT_EQ (model0, merged);
-    /* In particular, there should be an unknown value for "x".  */
-    svalue *merged_x_sval = merged.get_svalue (merged.get_rvalue (x, &ctxt));
-    ASSERT_EQ (merged_x_sval->get_kind (), SK_UNKNOWN);
-  }
-
-  /* Use global-handling to verify various combinations of values.  */
-
-  /* Two equal constant values.  */
-  {
-    region_model merged;
-    svalue *merged_x_sval;
-    assert_region_models_merge (x, int_42, int_42, &merged, &merged_x_sval);
-
-    /* In particular, there should be a constant value for "x".  */
-    ASSERT_EQ (merged_x_sval->get_kind (), SK_CONSTANT);
-    ASSERT_EQ (merged_x_sval->dyn_cast_constant_svalue ()->get_constant (),
-	       int_42);
-  }
-
-  /* Two non-equal constant values.  */
-  {
-    region_model merged;
-    svalue *merged_x_sval;
-    assert_region_models_merge (x, int_42, int_113, &merged, &merged_x_sval);
-
-    /* In particular, there should be an unknown value for "x".  */
-    ASSERT_EQ (merged_x_sval->get_kind (), SK_UNKNOWN);
-  }
-
-  /* Uninit and constant.  */
-  {
-    region_model merged;
-    svalue *merged_x_sval;
-    assert_region_models_merge (x, NULL_TREE, int_113, &merged, &merged_x_sval);
-
-    /* In particular, there should be an unknown value for "x".  */
-    ASSERT_EQ (merged_x_sval->get_kind (), SK_UNKNOWN);
-  }
-
-  /* Constant and uninit.  */
-  {
-    region_model merged;
-    svalue *merged_x_sval;
-    assert_region_models_merge (x, int_42, NULL_TREE, &merged, &merged_x_sval);
-
-    /* In particular, there should be an unknown value for "x".  */
-    ASSERT_EQ (merged_x_sval->get_kind (), SK_UNKNOWN);
-  }
-
-  /* Unknown and constant.  */
-  // TODO
-
-  /* Pointers: NULL and NULL.  */
-  // TODO
-
-  /* Pointers: NULL and non-NULL.  */
-  // TODO
-
-  /* Pointers: non-NULL and non-NULL: ptr to a local.  */
-  {
-    region_model model0;
-    model0.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
-    model0.set_to_new_unknown_value (model0.get_lvalue (a, NULL),
-				     integer_type_node, NULL);
-    model0.set_value (model0.get_lvalue (p, NULL),
-		      model0.get_rvalue (addr_of_a, NULL), NULL);
-
-    region_model model1 (model0);
-    ASSERT_EQ (model0, model1);
-
-    /* They should be mergeable, and the result should be the same.  */
-    region_model merged;
-    ASSERT_TRUE (model0.can_merge_with_p (model1, &merged));
-    ASSERT_EQ (model0, merged);
-  }
-
-  /* Pointers: non-NULL and non-NULL: ptr to a global.  */
-  {
-    region_model merged;
-    /* p == &y in both input models.  */
-    svalue *merged_p_sval;
-    assert_region_models_merge (p, addr_of_y, addr_of_y, &merged,
-				&merged_p_sval);
-
-    /* We should get p == &y in the merged model.  */
-    ASSERT_EQ (merged_p_sval->get_kind (), SK_REGION);
-    region_svalue *merged_p_ptr = merged_p_sval->dyn_cast_region_svalue ();
-    region_id merged_p_star_rid = merged_p_ptr->get_pointee ();
-    ASSERT_EQ (merged_p_star_rid, merged.get_lvalue (y, NULL));
-  }
-
-  /* Pointers: non-NULL ptrs to different globals: should be unknown.  */
-  {
-    region_model merged;
-    /* x == &y vs x == &z in the input models.  */
-    svalue *merged_x_sval;
-    assert_region_models_merge (x, addr_of_y, addr_of_z, &merged,
-				&merged_x_sval);
-
-    /* We should get x == unknown in the merged model.  */
-    ASSERT_EQ (merged_x_sval->get_kind (), SK_UNKNOWN);
-  }
-
-  /* Pointers: non-NULL and non-NULL: ptr to a heap region.  */
-  {
-    test_region_model_context ctxt;
-    region_model model0;
-    region_id new_rid = model0.add_new_malloc_region ();
-    svalue_id ptr_sid
-      = model0.get_or_create_ptr_svalue (ptr_type_node, new_rid);
-    model0.set_value (model0.get_lvalue (p, &ctxt),
-		      ptr_sid, &ctxt);
-    model0.canonicalize (&ctxt);
-
-    region_model model1 (model0);
-
-    ASSERT_EQ (model0, model1);
-
-    region_model merged;
-    ASSERT_TRUE (model0.can_merge_with_p (model1, &merged));
-
-    merged.canonicalize (&ctxt);
-
-    /* The merged model ought to be identical (after canonicalization,
-       at least).  */
-    ASSERT_EQ (model0, merged);
-  }
-
-  /* Two regions sharing the same unknown svalue should continue sharing
-     an unknown svalue after self-merger.  */
-  {
-    test_region_model_context ctxt;
-    region_model model0;
-    svalue_id sid
-      = model0.set_to_new_unknown_value (model0.get_lvalue (x, &ctxt),
-					 integer_type_node, &ctxt);
-    model0.set_value (model0.get_lvalue (y, &ctxt), sid, &ctxt);
-    region_model model1 (model0);
-
-    /* They should be mergeable, and the result should be the same.  */
-    region_model merged;
-    ASSERT_TRUE (model0.can_merge_with_p (model1, &merged));
-    ASSERT_EQ (model0, merged);
-
-    /* In particular, we should have x == y.  */
-    ASSERT_EQ (merged.eval_condition (x, EQ_EXPR, y, &ctxt),
-	       tristate (tristate::TS_TRUE));
-  }
-
-#if 0
-  {
-    region_model model0;
-    region_model model1;
-    test_region_model_context ctxt;
-    model0.add_constraint (x, EQ_EXPR, int_42, &ctxt);
-    model1.add_constraint (x, NE_EXPR, int_42, &ctxt);
-    ASSERT_TRUE (model0.can_merge_with_p (model1));
-  }
-
-  {
-    region_model model0;
-    region_model model1;
-    test_region_model_context ctxt;
-    model0.add_constraint (x, EQ_EXPR, int_42, &ctxt);
-    model1.add_constraint (x, NE_EXPR, int_42, &ctxt);
-    model1.add_constraint (x, EQ_EXPR, int_113, &ctxt);
-    ASSERT_TRUE (model0.can_merge_with_p (model1));
-  }
-#endif
-
-  // TODO: what can't we merge? need at least one such test
-
-  /* TODO: various things
-     - heap regions
-     - value merging:
-       - every combination, but in particular
-          - pairs of regions
-   */
-
-  /* Views.  */
-  {
-    test_region_model_context ctxt;
-    region_model model0;
-
-    region_id x_rid = model0.get_lvalue (x, &ctxt);
-    region_id x_as_ptr = model0.get_or_create_view (x_rid, ptr_type_node,
-						    &ctxt);
-    model0.set_value (x_as_ptr, model0.get_rvalue (addr_of_y, &ctxt), &ctxt);
-
-    region_model model1 (model0);
-    ASSERT_EQ (model1, model0);
-
-    /* They should be mergeable, and the result should be the same.  */
-    region_model merged;
-    ASSERT_TRUE (model0.can_merge_with_p (model1, &merged));
-  }
-
-  /* Verify that we can merge a model in which a local in an older stack
-     frame points to a local in a more recent stack frame.  */
-  {
-    region_model model0;
-    model0.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
-    region_id q_in_first_frame = model0.get_lvalue (q, NULL);
-
-    /* Push a second frame.  */
-    region_id rid_2nd_frame
-      = 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.  */
-    svalue_id sid_ptr = model0.get_rvalue (addr_of_a, NULL);
-    model0.set_value (q_in_first_frame, sid_ptr, NULL);
-
-    /* Verify that it's pointing at the newer frame.  */
-    region_id rid_pointee
-      = model0.get_svalue (sid_ptr)->dyn_cast_region_svalue ()->get_pointee ();
-    ASSERT_EQ (model0.get_region (rid_pointee)->get_parent (), rid_2nd_frame);
-
-    model0.canonicalize (NULL);
-
-    region_model model1 (model0);
-    ASSERT_EQ (model0, model1);
-
-    /* They should be mergeable, and the result should be the same
-       (after canonicalization, at least).  */
-    region_model merged;
-    ASSERT_TRUE (model0.can_merge_with_p (model1, &merged));
-    merged.canonicalize (NULL);
-    ASSERT_EQ (model0, merged);
-  }
-
-  /* Verify that we can merge a model in which a local points to a global.  */
-  {
-    region_model model0;
-    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);
-
-    model0.canonicalize (NULL);
-
-    region_model model1 (model0);
-    ASSERT_EQ (model0, model1);
-
-    /* They should be mergeable, and the result should be the same
-       (after canonicalization, at least).  */
-    region_model merged;
-    ASSERT_TRUE (model0.can_merge_with_p (model1, &merged));
-    merged.canonicalize (NULL);
-    ASSERT_EQ (model0, merged);
-  }
-}
-
-/* Verify that constraints are correctly merged when merging region_model
-   instances.  */
-
-static void
-test_constraint_merging ()
-{
-  tree int_0 = build_int_cst (integer_type_node, 0);
-  tree int_5 = build_int_cst (integer_type_node, 5);
-  tree x = build_global_decl ("x", integer_type_node);
-  tree y = build_global_decl ("y", integer_type_node);
-  tree z = build_global_decl ("z", integer_type_node);
-  tree n = build_global_decl ("n", integer_type_node);
-
-  test_region_model_context ctxt;
-
-  /* model0: 0 <= (x == y) < n.  */
-  region_model model0;
-  model0.set_to_new_unknown_value (model0.get_lvalue (x, &ctxt),
-				   integer_type_node, &ctxt);
-  model0.add_constraint (x, EQ_EXPR, y, &ctxt);
-  model0.add_constraint (x, GE_EXPR, int_0, NULL);
-  model0.add_constraint (x, LT_EXPR, n, NULL);
-
-  /* model1: z != 5 && (0 <= x < n).  */
-  region_model model1;
-  model1.set_to_new_unknown_value (model1.get_lvalue (x, &ctxt),
-				   integer_type_node, &ctxt);
-  model1.add_constraint (z, NE_EXPR, int_5, NULL);
-  model1.add_constraint (x, GE_EXPR, int_0, NULL);
-  model1.add_constraint (x, LT_EXPR, n, NULL);
-
-  /* They should be mergeable; the merged constraints should
-     be: (0 <= x < n).  */
-  region_model merged;
-  ASSERT_TRUE (model0.can_merge_with_p (model1, &merged));
-
-  ASSERT_EQ (merged.eval_condition (x, GE_EXPR, int_0, &ctxt),
-	     tristate (tristate::TS_TRUE));
-  ASSERT_EQ (merged.eval_condition (x, LT_EXPR, n, &ctxt),
-	     tristate (tristate::TS_TRUE));
-
-  ASSERT_EQ (merged.eval_condition (z, NE_EXPR, int_5, &ctxt),
-	     tristate (tristate::TS_UNKNOWN));
-  ASSERT_EQ (merged.eval_condition (x, LT_EXPR, y, &ctxt),
-	     tristate (tristate::TS_UNKNOWN));
-}
-
-/* Verify that if we mark a pointer to a malloc-ed region as non-NULL,
-   all cast pointers to that region are also known to be non-NULL.  */
-
-static void
-test_malloc_constraints ()
-{
-  region_model model;
-  tree p = build_global_decl ("p", ptr_type_node);
-  tree char_star = build_pointer_type (char_type_node);
-  tree q = build_global_decl ("q", char_star);
-  tree null_ptr = build_int_cst (ptr_type_node, 0);
-
-  region_id rid = model.add_new_malloc_region ();
-  svalue_id sid = model.get_or_create_ptr_svalue (ptr_type_node, rid);
-  model.set_value (model.get_lvalue (p, NULL), sid, NULL);
-  model.set_value (q, p, NULL);
-
-  /* We should have a symbolic_region with m_possibly_null: true.  */
-  region *pointee = model.get_region (rid);
-  symbolic_region *sym_reg = pointee->dyn_cast_symbolic_region ();
-  ASSERT_NE (sym_reg, NULL);
-  ASSERT_TRUE (sym_reg->m_possibly_null);
-
-  ASSERT_CONDITION_UNKNOWN (model, p, NE_EXPR, null_ptr);
-  ASSERT_CONDITION_UNKNOWN (model, p, EQ_EXPR, null_ptr);
-  ASSERT_CONDITION_UNKNOWN (model, q, NE_EXPR, null_ptr);
-  ASSERT_CONDITION_UNKNOWN (model, q, EQ_EXPR, null_ptr);
-
-  model.add_constraint (p, NE_EXPR, null_ptr, NULL);
-
-  /* Adding the constraint should have cleared m_possibly_null.  */
-  ASSERT_FALSE (sym_reg->m_possibly_null);
-
-  ASSERT_CONDITION_TRUE (model, p, NE_EXPR, null_ptr);
-  ASSERT_CONDITION_FALSE (model, p, EQ_EXPR, null_ptr);
-  ASSERT_CONDITION_TRUE (model, q, NE_EXPR, null_ptr);
-  ASSERT_CONDITION_FALSE (model, q, EQ_EXPR, null_ptr);
-}
 
 /* Run all of the selftests within this file.  */
 
 void
 analyzer_region_model_cc_tests ()
 {
-  test_tree_cmp_on_constants ();
-  test_dump ();
-  test_dump_2 ();
-  test_dump_3 ();
-  test_get_representative_tree ();
-  test_unique_constants ();
-  test_svalue_equality ();
-  test_region_equality ();
-  test_purging_by_criteria ();
-  test_purge_unused_svalues ();
-  test_assignment ();
-  test_compound_assignment ();
-  test_stack_frames ();
-  test_get_representative_path_var ();
-  test_canonicalization_1 ();
-  test_canonicalization_2 ();
-  test_canonicalization_3 ();
-  test_canonicalization_4 ();
-  test_state_merging ();
-  test_constraint_merging ();
-  test_malloc_constraints ();
 }
 
 } // namespace selftest
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index 313376d0e6d..d0ab2c12829 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -36,82 +36,6 @@ namespace inchash
 
 namespace ana {
 
-/* A region_model is effectively a graph of regions and symbolic values.
-   We store per-model IDs rather than pointers to make it easier to clone
-   and to compare graphs.  */
-
-/* An ID for an svalue within a region_model.  Internally, this is an index
-   into a vector of svalue * within the region_model.  */
-
-class svalue_id
-{
-public:
-  static svalue_id null () { return svalue_id (-1); }
-
-  svalue_id () : m_idx (-1) {}
-
-  bool operator== (const svalue_id &other) const
-  {
-    return m_idx == other.m_idx;
-  }
-
-  bool operator!= (const svalue_id &other) const
-  {
-    return m_idx != other.m_idx;
-  }
-
-  bool null_p () const { return m_idx == -1; }
-
-  static svalue_id from_int (int idx) { return svalue_id (idx); }
-  int as_int () const { return m_idx; }
-
-  void print (pretty_printer *pp) const;
-  void dump_node_name_to_pp (pretty_printer *pp) const;
-
-  void validate (const region_model &model) const;
-
-private:
-  svalue_id (int idx) : m_idx (idx) {}
-
-  int m_idx;
-};
-
-/* An ID for a region within a region_model.  Internally, this is an index
-   into a vector of region * within the region_model.  */
-
-class region_id
-{
-public:
-  static region_id null () { return region_id (-1); }
-
-  region_id () : m_idx (-1) {}
-
-  bool operator== (const region_id &other) const
-  {
-    return m_idx == other.m_idx;
-  }
-
-  bool operator!= (const region_id &other) const
-  {
-    return m_idx != other.m_idx;
-  }
-
-  bool null_p () const { return m_idx == -1; }
-
-  static region_id from_int (int idx) { return region_id (idx); }
-  int as_int () const { return m_idx; }
-
-  void print (pretty_printer *pp) const;
-  void dump_node_name_to_pp (pretty_printer *pp) const;
-
-  void validate (const region_model &model) const;
-
-private:
-  region_id (int idx) : m_idx (idx) {}
-
-  int m_idx;
-};
-
 /* A class for renumbering IDs within a region_model, mapping old IDs
    to new IDs (e.g. when removing one or more elements, thus needing to
    renumber).  */
@@ -134,9 +58,6 @@ class id_map
   auto_vec<T> m_dst_to_src;
 };
 
-typedef id_map<svalue_id> svalue_id_map;
-typedef id_map<region_id> region_id_map;
-
 /* class id_map.  */
 
 /* id_map's ctor, which populates the map with dummy null values.  */
@@ -262,9 +183,6 @@ class one_way_id_map
   auto_vec<T> m_src_to_dst;
 };
 
-typedef one_way_id_map<svalue_id> one_way_svalue_id_map;
-typedef one_way_id_map<region_id> one_way_region_id_map;
-
 /* class one_way_id_map.  */
 
 /* one_way_id_map's ctor, which populates the map with dummy null values.  */
@@ -340,59 +258,6 @@ one_way_id_map<T>::update (T *id) const
   *id = get_dst_for_src (*id);
 }
 
-/* A set of region_ids within a region_model.  */
-
-class region_id_set
-{
-public:
-  region_id_set (const region_model *model);
-
-  void add_region (region_id rid)
-  {
-    if (!rid.null_p ())
-      bitmap_set_bit (m_bitmap, rid.as_int ());
-  }
-
-  bool region_p (region_id rid) const
-  {
-    gcc_assert (!rid.null_p ());
-    return bitmap_bit_p (const_cast <auto_sbitmap &> (m_bitmap),
-			 rid.as_int ());
-  }
-
-  unsigned int num_regions ()
-  {
-    return bitmap_count_bits (m_bitmap);
-  }
-
-private:
-  auto_sbitmap m_bitmap;
-};
-
-/* A set of svalue_ids within a region_model.  */
-
-class svalue_id_set
-{
-public:
-  svalue_id_set ();
-
-  void add_svalue (svalue_id sid)
-  {
-    if (!sid.null_p ())
-      bitmap_set_bit (m_bitmap, sid.as_int ());
-  }
-
-  bool svalue_p (svalue_id sid) const
-  {
-    gcc_assert (!sid.null_p ());
-    return bitmap_bit_p (const_cast <auto_bitmap &> (m_bitmap),
-			 sid.as_int ());
-  }
-
-private:
-  auto_bitmap m_bitmap;
-};
-
 /* Various operations delete information from a region_model.
 
    This struct tracks how many of each kind of entity were purged (e.g.
@@ -415,1707 +280,8 @@ struct purge_stats
   int m_num_client_items;
 };
 
-/* An enum for discriminating between the different concrete subclasses
-   of svalue.  */
-
-enum svalue_kind
-{
-  SK_REGION,
-  SK_CONSTANT,
-  SK_UNKNOWN,
-  SK_POISONED,
-  SK_SETJMP
-};
-
-/* svalue and its subclasses.
-
-   The class hierarchy looks like this (using indentation to show
-   inheritance, and with svalue_kinds shown for the concrete subclasses):
-
-   svalue
-     region_svalue (SK_REGION)
-     constant_svalue (SK_CONSTANT)
-     unknown_svalue (SK_UNKNOWN)
-     poisoned_svalue (SK_POISONED)
-     setjmp_svalue (SK_SETJMP).  */
-
-/* An abstract base class representing a value held by a region of memory.  */
-
-class svalue
-{
-public:
-  virtual ~svalue () {}
-
-  bool operator== (const svalue &other) const;
-  bool operator!= (const svalue &other) const { return !(*this == other); }
-
-  virtual svalue *clone () const = 0;
-
-  tree get_type () const { return m_type; }
-
-  virtual enum svalue_kind get_kind () const = 0;
-
-  hashval_t hash () const;
-
-  void print (const region_model &model,
-	      svalue_id this_sid,
-	      pretty_printer *pp) const;
-
-  virtual void dump_dot_to_pp (const region_model &model,
-			       svalue_id this_sid,
-			       pretty_printer *pp) const;
-
-  virtual region_svalue *dyn_cast_region_svalue () { return NULL; }
-  virtual constant_svalue *dyn_cast_constant_svalue () { return NULL; }
-  virtual const constant_svalue *dyn_cast_constant_svalue () const
-  { return NULL; }
-  virtual poisoned_svalue *dyn_cast_poisoned_svalue () { return NULL; }
-  virtual unknown_svalue *dyn_cast_unknown_svalue () { return NULL; }
-  virtual setjmp_svalue *dyn_cast_setjmp_svalue () { return NULL; }
-
-  virtual void remap_region_ids (const region_id_map &map);
-
-  virtual void walk_for_canonicalization (canonicalization *c) const;
-
-  virtual svalue_id get_child_sid (region *parent, region *child,
-				   region_model &model,
-				   region_model_context *ctxt);
-
-  tree maybe_get_constant () const;
-
- protected:
-  svalue (tree type) : m_type (type) {}
-
-  virtual void add_to_hash (inchash::hash &hstate) const = 0;
-
- private:
-  virtual void print_details (const region_model &model,
-			      svalue_id this_sid,
-			      pretty_printer *pp) const = 0;
-  tree m_type;
-};
-
-/* Concrete subclass of svalue representing a pointer value that points to
-   a known region  */
-
-class region_svalue : public svalue
-{
-public:
-  region_svalue (tree type, region_id rid) : svalue (type), m_rid (rid)
-  {
-    /* Should we support NULL ptrs here?  */
-    gcc_assert (!rid.null_p ());
-  }
-
-  bool compare_fields (const region_svalue &other) const;
-
-  svalue *clone () const FINAL OVERRIDE
-  { return new region_svalue (get_type (), m_rid); }
-
-  enum svalue_kind get_kind () const FINAL OVERRIDE { return SK_REGION; }
-
-  void dump_dot_to_pp (const region_model &model,
-		       svalue_id this_sid,
-		       pretty_printer *pp) const
-    FINAL OVERRIDE;
-
-  region_svalue *dyn_cast_region_svalue () FINAL OVERRIDE { return this; }
-
-  region_id get_pointee () const { return m_rid; }
-
-  void remap_region_ids (const region_id_map &map) FINAL OVERRIDE;
-
-  static void merge_values (const region_svalue &region_sval_a,
-			    const region_svalue &region_sval_b,
-			    svalue_id *merged_sid,
-			    tree type,
-			    model_merger *merger);
-
-  void walk_for_canonicalization (canonicalization *c) const FINAL OVERRIDE;
-
-  static tristate eval_condition (region_svalue *lhs_ptr,
-				  enum tree_code op,
-				  region_svalue *rhs_ptr);
-
-  void add_to_hash (inchash::hash &hstate) const FINAL OVERRIDE;
-
- private:
-  void print_details (const region_model &model,
-		      svalue_id this_sid,
-		      pretty_printer *pp) const
-    FINAL OVERRIDE;
-
-  region_id m_rid;
-};
-
-} // namespace ana
-
-template <>
-template <>
-inline bool
-is_a_helper <region_svalue *>::test (svalue *sval)
-{
-  return sval->get_kind () == SK_REGION;
-}
-
-namespace ana {
-
-/* Concrete subclass of svalue representing a specific constant value.  */
-
-class constant_svalue : public svalue
-{
-public:
-  constant_svalue (tree cst_expr)
-  : svalue (TREE_TYPE (cst_expr)), m_cst_expr (cst_expr)
-  {
-    gcc_assert (cst_expr);
-    gcc_assert (CONSTANT_CLASS_P (cst_expr));
-  }
-
-  bool compare_fields (const constant_svalue &other) const;
-
-  svalue *clone () const FINAL OVERRIDE
-  { return new constant_svalue (m_cst_expr); }
-
-  enum svalue_kind get_kind () const FINAL OVERRIDE { return SK_CONSTANT; }
-
-  void add_to_hash (inchash::hash &hstate) const FINAL OVERRIDE;
-
-  constant_svalue *dyn_cast_constant_svalue () FINAL OVERRIDE { return this; }
-  const constant_svalue *dyn_cast_constant_svalue () const FINAL OVERRIDE
-  { return this; }
-
-  tree get_constant () const { return m_cst_expr; }
-
-  static void merge_values (const constant_svalue &cst_sval_a,
-			    const constant_svalue &cst_sval_b,
-			    svalue_id *merged_sid,
-			    model_merger *merger);
-
-  static tristate eval_condition (constant_svalue *lhs,
-				  enum tree_code op,
-				  constant_svalue *rhs);
-
-  svalue_id get_child_sid (region *parent, region *child,
-			   region_model &model,
-			   region_model_context *ctxt) FINAL OVERRIDE;
-
- private:
-  void print_details (const region_model &model,
-		      svalue_id this_sid,
-		      pretty_printer *pp) const
-    FINAL OVERRIDE;
-
-  tree m_cst_expr;
-};
-
 } // namespace ana
 
-template <>
-template <>
-inline bool
-is_a_helper <constant_svalue *>::test (svalue *sval)
-{
-  return sval->get_kind () == SK_CONSTANT;
-}
-
-namespace ana {
-
-/* Concrete subclass of svalue representing a unique but unknown value.
-   Comparisons of variables that share the same unknown value are known
-   to be equal, even if we don't know what the value is.  */
-
-class unknown_svalue : public svalue
-{
-public:
-  unknown_svalue (tree type)
-  : svalue (type)
-  {}
-
-  bool compare_fields (const unknown_svalue &other) const;
-
-  svalue *clone () const FINAL OVERRIDE
-  { return new unknown_svalue (get_type ()); }
-
-  enum svalue_kind get_kind () const FINAL OVERRIDE { return SK_UNKNOWN; }
-
-  void add_to_hash (inchash::hash &hstate) const FINAL OVERRIDE;
-
-  unknown_svalue *dyn_cast_unknown_svalue () FINAL OVERRIDE { return this; }
-
- private:
-  void print_details (const region_model &model,
-		      svalue_id this_sid,
-		      pretty_printer *pp) const
-    FINAL OVERRIDE;
-};
-
-/* Concrete subclass of svalue representing a value that should not
-   be used (e.g. uninitialized memory, freed memory).  */
-
-class poisoned_svalue : public svalue
-{
-public:
-  poisoned_svalue (enum poison_kind kind, tree type)
-  : svalue (type), m_kind (kind) {}
-
-  bool compare_fields (const poisoned_svalue &other) const;
-
-  svalue *clone () const FINAL OVERRIDE
-  { return new poisoned_svalue (m_kind, get_type ()); }
-
-  enum svalue_kind get_kind () const FINAL OVERRIDE { return SK_POISONED; }
-
-  void add_to_hash (inchash::hash &hstate) const FINAL OVERRIDE;
-
-  poisoned_svalue *dyn_cast_poisoned_svalue () FINAL OVERRIDE { return this; }
-
-  enum poison_kind get_poison_kind () const { return m_kind; }
-
- private:
-  void print_details (const region_model &model,
-		      svalue_id this_sid,
-		      pretty_printer *pp) const
-    FINAL OVERRIDE;
-
-  enum poison_kind m_kind;
-};
-
-} // namespace ana
-
-template <>
-template <>
-inline bool
-is_a_helper <poisoned_svalue *>::test (svalue *sval)
-{
-  return sval->get_kind () == SK_POISONED;
-}
-
-namespace ana {
-
-/* Concrete subclass of svalue representing buffers for setjmp/sigsetjmp,
-   so that longjmp/siglongjmp can potentially "return" to an entirely
-   different function.  */
-
-class setjmp_svalue : public svalue
-{
-public:
-  setjmp_svalue (const setjmp_record &setjmp_record,
-		 tree type)
-  : svalue (type), m_setjmp_record (setjmp_record)
-  {}
-
-  bool compare_fields (const setjmp_svalue &other) const;
-
-  svalue *clone () const FINAL OVERRIDE
-  { return new setjmp_svalue (m_setjmp_record, get_type ()); }
-
-  enum svalue_kind get_kind () const FINAL OVERRIDE { return SK_SETJMP; }
-
-  void add_to_hash (inchash::hash &hstate) const FINAL OVERRIDE;
-
-  setjmp_svalue *dyn_cast_setjmp_svalue () FINAL OVERRIDE { return this; }
-
-  int get_enode_index () const;
-
-  const setjmp_record &get_setjmp_record () const { return m_setjmp_record; }
-
- private:
-  void print_details (const region_model &model,
-		      svalue_id this_sid,
-		      pretty_printer *pp) const
-    FINAL OVERRIDE;
-
-  setjmp_record m_setjmp_record;
-};
-
-/* An enum for discriminating between the different concrete subclasses
-   of region.  */
-
-enum region_kind
-{
-  RK_PRIMITIVE,
-  RK_STRUCT,
-  RK_UNION,
-  RK_FRAME,
-  RK_GLOBALS,
-  RK_CODE,
-  RK_FUNCTION,
-  RK_ARRAY,
-  RK_STACK,
-  RK_HEAP,
-  RK_ROOT,
-  RK_SYMBOLIC
-};
-
-extern const char *region_kind_to_str (enum region_kind);
-
-/* Region and its subclasses.
-
-   The class hierarchy looks like this (using indentation to show
-   inheritance, and with region_kinds shown for the concrete subclasses):
-
-   region
-     primitive_region (RK_PRIMITIVE)
-     map_region
-       struct_or_union_region
-         struct_region (RK_STRUCT)
-         union_region (RK_UNION)
-       scope_region
-         frame_region (RK_FRAME)
-         globals_region (RK_GLOBALS)
-       code_region (RK_CODE)
-       function_region (RK_FUNCTION)
-     array_region (RK_ARRAY)
-     stack_region (RK_STACK)
-     heap_region (RK_HEAP)
-     root_region (RK_ROOT)
-     label_region (RK_FUNCTION)
-     symbolic_region (RK_SYMBOLIC).  */
-
-/* Abstract base class representing a chunk of memory.
-
-   Regions form a tree-like hierarchy, with a root region at the base,
-   with memory space regions within it, representing the stack and
-   globals, with frames within the stack, and regions for variables
-   within the frames and the "globals" region.  Regions for structs
-   can have subregions for fields.
-
-   A region can optionally have a value, or inherit its value from
-   the first ancestor with a value.  For example, the stack region
-   has a "uninitialized" poison value which is inherited by all
-   descendent regions that don't themselves have a value.  */
-
-class region
-{
-public:
-  virtual ~region () {}
-
-  bool operator== (const region &other) const;
-  bool operator!= (const region &other) const { return !(*this == other); }
-
-  virtual region *clone () const = 0;
-
-  virtual enum region_kind get_kind () const = 0;
-  virtual map_region *dyn_cast_map_region () { return NULL; }
-  virtual array_region *dyn_cast_array_region () { return NULL; }
-  virtual symbolic_region *dyn_cast_symbolic_region () { return NULL; }
-  virtual const symbolic_region *dyn_cast_symbolic_region () const { return NULL; }
-
-  region_id get_parent () const { return m_parent_rid; }
-  region *get_parent_region (const region_model &model) const;
-
-  void set_value (region_model &model, region_id this_rid, svalue_id rhs_sid,
-		  region_model_context *ctxt);
-  svalue_id get_value (region_model &model, bool non_null,
-		       region_model_context *ctxt);
-  svalue_id get_value_direct () const { return m_sval_id; }
-
-  svalue_id get_inherited_child_sid (region *child,
-				     region_model &model,
-				     region_model_context *ctxt);
-
-  tree get_type () const { return m_type; }
-
-  hashval_t hash () const;
-
-  void print (const region_model &model,
-	      region_id this_rid,
-	      pretty_printer *pp) const;
-
-  virtual void dump_dot_to_pp (const region_model &model,
-			       region_id this_rid,
-			       pretty_printer *pp) const;
-
-  void dump_to_pp (const region_model &model,
-		   region_id this_rid,
-		   pretty_printer *pp,
-		   const char *prefix,
-		   bool is_last_child) const;
-  virtual void dump_child_label (const region_model &model,
-				 region_id this_rid,
-				 region_id child_rid,
-				 pretty_printer *pp) const;
-
-  void remap_svalue_ids (const svalue_id_map &map);
-  virtual void remap_region_ids (const region_id_map &map);
-
-  virtual void walk_for_canonicalization (canonicalization *c) const = 0;
-
-  void add_view (region_id view_rid, region_model *model);
-  region_id get_view (tree type, region_model *model) const;
-  region_id get_active_view () const { return m_active_view_rid; }
-  bool is_view_p () const { return m_is_view; }
-
-  virtual void validate (const region_model &model) const;
-
-  bool non_null_p (const region_model &model) const;
-
- protected:
-  region (region_id parent_rid, svalue_id sval_id, tree type);
-  region (const region &other);
-
-  virtual void add_to_hash (inchash::hash &hstate) const;
-  virtual void print_fields (const region_model &model,
-			     region_id this_rid,
-			     pretty_printer *pp) const;
-
- private:
-  void become_active_view (region_model &model, region_id this_rid);
-  void deactivate_any_active_view (region_model &model);
-  void deactivate_view (region_model &model, region_id this_view_rid);
-
-  region_id m_parent_rid;
-  svalue_id m_sval_id;
-  tree m_type;
-  /* Child regions that are "views" (one per type).  */
-  auto_vec<region_id> m_view_rids;
-
-  bool m_is_view;
-  region_id m_active_view_rid;
-};
-
-} // namespace ana
-
-template <>
-template <>
-inline bool
-is_a_helper <region *>::test (region *)
-{
-  return true;
-}
-
-namespace ana {
-
-/* Concrete region subclass for storing "primitive" types (integral types,
-   pointers, etc).  */
-
-class primitive_region : public region
-{
-public:
-  primitive_region (region_id parent_rid, tree type)
-  : region (parent_rid, svalue_id::null (), type)
-  {}
-
-  region *clone () const FINAL OVERRIDE;
-
-  enum region_kind get_kind () const FINAL OVERRIDE { return RK_PRIMITIVE; }
-
-  void walk_for_canonicalization (canonicalization *c) const FINAL OVERRIDE;
-};
-
-/* A region that has children identified by tree keys.
-   For example a stack frame has subregions per local, and a region
-   for a struct has subregions per field.  */
-
-class map_region : public region
-{
-public:
-  typedef ordered_hash_map<tree, region_id> map_t;
-  typedef map_t::iterator iterator_t;
-
-  map_region (region_id parent_rid, tree type)
-  : region (parent_rid, svalue_id::null (), type)
-  {}
-  map_region (const map_region &other);
-
-  map_region *dyn_cast_map_region () FINAL OVERRIDE { return this; }
-
-  void dump_dot_to_pp (const region_model &model,
-		       region_id this_rid,
-		       pretty_printer *pp) const
-    FINAL OVERRIDE;
-
-  void dump_child_label (const region_model &model,
-			 region_id this_rid,
-			 region_id child_rid,
-			 pretty_printer *pp) const
-    FINAL OVERRIDE;
-
-  region_id get_or_create (region_model *model,
-			   region_id this_rid,
-			   tree expr, tree type,
-			   region_model_context *ctxt);
-  void unbind (tree expr);
-  region_id *get (tree expr);
-
-  void remap_region_ids (const region_id_map &map) FINAL OVERRIDE;
-
-  tree get_tree_for_child_region (region_id child_rid) const;
-
-  tree get_tree_for_child_region (region *child,
-				  const region_model &model) const;
-
-  static bool can_merge_p (const map_region *map_region_a,
-			   const map_region *map_region_b,
-			   map_region *merged_map_region,
-			   region_id merged_rid,
-			   model_merger *merger);
-
-  void walk_for_canonicalization (canonicalization *c) const FINAL OVERRIDE;
-
-  virtual bool valid_key_p (tree key) const = 0;
-
-  svalue_id get_value_by_name (tree identifier,
-			       const region_model &model) const;
-
-  iterator_t begin () { return m_map.begin (); }
-  iterator_t end () { return m_map.end (); }
-  size_t elements () const { return m_map.elements (); }
-
- protected:
-  bool compare_fields (const map_region &other) const;
-  void add_to_hash (inchash::hash &hstate) const OVERRIDE;
-  void print_fields (const region_model &model,
-		     region_id this_rid,
-		     pretty_printer *pp) const
-    OVERRIDE;
-  void validate (const region_model &model) const FINAL OVERRIDE;
-
- private:
-  /* Mapping from tree to child region.  */
-  map_t m_map;
-};
-
-} // namespace ana
-
-template <>
-template <>
-inline bool
-is_a_helper <map_region *>::test (region *reg)
-{
-  return (reg->dyn_cast_map_region () != NULL);
-}
-
-namespace ana {
-
-/* Abstract subclass representing a region with fields
-   (either a struct or a union).  */
-
-class struct_or_union_region : public map_region
-{
-public:
-  bool valid_key_p (tree key) const FINAL OVERRIDE;
-
- protected:
-  struct_or_union_region (region_id parent_rid, tree type)
-  : map_region (parent_rid, type)
-  {}
-
-  bool compare_fields (const struct_or_union_region &other) const;
-};
-
-} // namespace ana
-
-template <>
-template <>
-inline bool
-is_a_helper <struct_or_union_region *>::test (region *reg)
-{
-  return (reg->get_kind () == RK_STRUCT
-	  || reg->get_kind () == RK_UNION);
-}
-
-namespace ana {
-
-/* Concrete region subclass.  A map_region representing a struct, using
-   FIELD_DECLs for its keys.  */
-
-class struct_region : public struct_or_union_region
-{
-public:
-  struct_region (region_id parent_rid, tree type)
-  : struct_or_union_region (parent_rid, type)
-  {
-    gcc_assert (TREE_CODE (type) == RECORD_TYPE);
-  }
-
-  region *clone () const FINAL OVERRIDE;
-
-  enum region_kind get_kind () const FINAL OVERRIDE { return RK_STRUCT; }
-
-  bool compare_fields (const struct_region &other) const;
-};
-
-} // namespace ana
-
-template <>
-template <>
-inline bool
-is_a_helper <struct_region *>::test (region *reg)
-{
-  return reg->get_kind () == RK_STRUCT;
-}
-
-namespace ana {
-
-/* Concrete region subclass.  A map_region representing a union, using
-   FIELD_DECLs for its keys.  */
-
-class union_region : public struct_or_union_region
-{
-public:
-  union_region (region_id parent_rid, tree type)
-  : struct_or_union_region (parent_rid, type)
-  {
-    gcc_assert (TREE_CODE (type) == UNION_TYPE);
-  }
-
-  region *clone () const FINAL OVERRIDE;
-
-  enum region_kind get_kind () const FINAL OVERRIDE { return RK_UNION; }
-
-  bool compare_fields (const union_region &other) const;
-};
-
-} // namespace ana
-
-template <>
-template <>
-inline bool
-is_a_helper <union_region *>::test (region *reg)
-{
-  return reg->get_kind () == RK_UNION;
-}
-
-namespace ana {
-
-/* Abstract map_region subclass for accessing decls, used as a base class
-   for function frames and for the globals region.  */
-
-class scope_region : public map_region
-{
- public:
-
- protected:
-  scope_region (region_id parent_rid)
-  : map_region (parent_rid, NULL_TREE)
-  {}
-
-  scope_region (const scope_region &other)
-  : map_region (other)
-  {
-  }
-
-  bool compare_fields (const scope_region &other) const;
-};
-
-/* Concrete region subclass, representing a function frame on the stack,
-   to contain the locals.  */
-
-class frame_region : public scope_region
-{
-public:
-  frame_region (region_id parent_rid, function *fun, int depth)
-  : scope_region (parent_rid), m_fun (fun), m_depth (depth)
-  {}
-
-  frame_region (const frame_region &other)
-  : scope_region (other), m_fun (other.m_fun), m_depth (other.m_depth)
-  {
-  }
-
-  /* region vfuncs.  */
-  region *clone () const FINAL OVERRIDE;
-  enum region_kind get_kind () const FINAL OVERRIDE { return RK_FRAME; }
-  void print_fields (const region_model &model,
-		     region_id this_rid,
-		     pretty_printer *pp) const
-    FINAL OVERRIDE;
-  void add_to_hash (inchash::hash &hstate) const FINAL OVERRIDE;
-
-  /* map_region vfuncs.  */
-  bool valid_key_p (tree key) const FINAL OVERRIDE;
-
-  /* Accessors.  */
-  function *get_function () const { return m_fun; }
-  int get_depth () const { return m_depth; }
-
-  bool compare_fields (const frame_region &other) const;
-
- private:
-  function *m_fun;
-  int m_depth;
-};
-
-} // namespace ana
-
-template <>
-template <>
-inline bool
-is_a_helper <frame_region *>::test (region *reg)
-{
-  return reg->get_kind () == RK_FRAME;
-}
-
-namespace ana {
-
-/* Concrete region subclass, to hold global variables (data and bss).  */
-
-class globals_region : public scope_region
-{
- public:
-  globals_region (region_id parent_rid)
-  : scope_region (parent_rid)
-  {}
-
-  globals_region (const globals_region &other)
-  : scope_region (other)
-  {
-  }
-
-  /* region vfuncs.  */
-  region *clone () const FINAL OVERRIDE;
-  enum region_kind get_kind () const FINAL OVERRIDE { return RK_GLOBALS; }
-
-  /* map_region vfuncs.  */
-  bool valid_key_p (tree key) const FINAL OVERRIDE;
-
-  bool compare_fields (const globals_region &other) const;
-};
-
-} // namespace ana
-
-template <>
-template <>
-inline bool
-is_a_helper <globals_region *>::test (region *reg)
-{
-  return reg->get_kind () == RK_GLOBALS;
-}
-
-namespace ana {
-
-/* Concrete region subclass.  A map_region representing the code, using
-   FUNCTION_DECLs for its keys.  */
-
-class code_region : public map_region
-{
-public:
-  code_region (region_id parent_rid)
-  : map_region (parent_rid, NULL_TREE)
-  {}
-  code_region (const code_region &other)
-  : map_region (other)
-  {}
-
-  /* region vfuncs.  */
-  region *clone () const FINAL OVERRIDE;
-  enum region_kind get_kind () const FINAL OVERRIDE { return RK_CODE; }
-
-  /* map_region vfunc.  */
-  bool valid_key_p (tree key) const FINAL OVERRIDE;
-
-  region_id get_element (region_model *model,
-			 region_id this_rid,
-			 svalue_id index_sid,
-			 region_model_context *ctxt);
-
-  bool compare_fields (const code_region &other) const;
-};
-
-} // namespace ana
-
-template <>
-template <>
-inline bool
-is_a_helper <code_region *>::test (region *reg)
-{
-  return reg->get_kind () == RK_CODE;
-}
-
-namespace ana {
-
-/* Concrete region subclass.  A map_region representing the code for
-   a particular function, using LABEL_DECLs for its keys.  */
-
-class function_region : public map_region
-{
-public:
-  function_region (region_id parent_rid, tree type)
-  : map_region (parent_rid, type)
-  {
-    gcc_assert (FUNC_OR_METHOD_TYPE_P (type));
-  }
-  function_region (const function_region &other)
-  : map_region (other)
-  {}
-
-  /* region vfuncs.  */
-  region *clone () const FINAL OVERRIDE;
-  enum region_kind get_kind () const FINAL OVERRIDE { return RK_FUNCTION; }
-
-  /* map_region vfunc.  */
-  bool valid_key_p (tree key) const FINAL OVERRIDE;
-
-  region_id get_element (region_model *model,
-			 region_id this_rid,
-			 svalue_id index_sid,
-			 region_model_context *ctxt);
-
-  bool compare_fields (const function_region &other) const;
-};
-
-} // namespace ana
-
-template <>
-template <>
-inline bool
-is_a_helper <function_region *>::test (region *reg)
-{
-  return reg->get_kind () == RK_FUNCTION;
-}
-
-namespace ana {
-
-/* Concrete region subclass representing an array (or an array-like view
-   of a parent region of memory.
-   This can't be a map_region as we can't use trees as the keys: there's
-   no guarantee about the uniqueness of an INTEGER_CST.  */
-
-class array_region : public region
-{
-public:
-#if 0
-  wide_int m_test;
-
-  typedef wide_int key_t;
-  typedef int_hash <wide_int, -1, -2> hash_t;
-  typedef ordered_hash_map<hash_t, region_id> map_t;
-#else
-  typedef int key_t;
-  typedef int_hash <int, -1, -2> int_hash_t;
-  typedef ordered_hash_map<int_hash_t, region_id> map_t;
-#endif
-  typedef map_t::iterator iterator_t;
-
-  array_region (region_id parent_rid, tree type)
-  : region (parent_rid, svalue_id::null (), type)
-  {
-    gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
-  }
-  array_region (const array_region &other);
-
-  void dump_dot_to_pp (const region_model &model,
-		       region_id this_rid,
-		       pretty_printer *pp) const
-    FINAL OVERRIDE;
-
-  void dump_child_label (const region_model &model,
-			 region_id this_rid,
-			 region_id child_rid,
-			 pretty_printer *pp) const
-    FINAL OVERRIDE;
-
-  /* region vfuncs.  */
-  region *clone () const FINAL OVERRIDE;
-  enum region_kind get_kind () const FINAL OVERRIDE { return RK_ARRAY; }
-  array_region *dyn_cast_array_region () { return this; }
-
-  region_id get_element (region_model *model,
-			 region_id this_rid,
-			 svalue_id index_sid,
-			 region_model_context *ctxt);
-
-  bool compare_fields (const array_region &other) const;
-
-  static bool can_merge_p (const array_region *array_region_a,
-			   const array_region *array_region_b,
-			   array_region *merged_array_region,
-			   region_id merged_rid,
-			   model_merger *merger);
-
-  void walk_for_canonicalization (canonicalization *c) const FINAL OVERRIDE;
-
-  iterator_t begin () { return m_map.begin (); }
-  iterator_t end () { return m_map.end (); }
-  size_t elements () const { return m_map.elements (); }
-
-  region_id get_or_create (region_model *model,
-			   region_id this_rid,
-			   key_t key, tree type,
-			   region_model_context *ctxt);
-//  void unbind (int expr);
-  region_id *get (key_t key);
-
-  void remap_region_ids (const region_id_map &map) FINAL OVERRIDE;
-
-  bool get_key_for_child_region (region_id child_rid,
-				 key_t *out) const;
-
-#if 0
-  bool get_key_for_child_region (region *child,
-				 const region_model &model,
-				 key_t *out) const;
-#endif
-
-  void add_to_hash (inchash::hash &hstate) const OVERRIDE;
-  void print_fields (const region_model &model,
-		     region_id this_rid,
-		     pretty_printer *pp) const
-    OVERRIDE;
-  void validate (const region_model &model) const FINAL OVERRIDE;
-
-  static key_t key_from_constant (tree cst);
-  tree constant_from_key (key_t key);
-
- private:
-  static int key_cmp (const void *, const void *);
-
-  /* Mapping from tree to child region.  */
-  map_t m_map;
-};
-
-} // namespace ana
-
-template <>
-template <>
-inline bool
-is_a_helper <array_region *>::test (region *reg)
-{
-  return reg->get_kind () == RK_ARRAY;
-}
-
-namespace ana {
-
-/* Concrete region subclass representing a stack, containing all stack
-   frames, and implicitly providing a POISON_KIND_UNINIT value to all
-   child regions by default.  */
-
-class stack_region : public region
-{
-public:
-  stack_region (region_id parent_rid, svalue_id sval_id)
-  : region (parent_rid, sval_id, NULL_TREE)
-  {}
-
-  stack_region (const stack_region &other);
-
-  bool compare_fields (const stack_region &other) const;
-
-  region *clone () const FINAL OVERRIDE;
-
-  enum region_kind get_kind () const FINAL OVERRIDE { return RK_STACK; }
-
-  void dump_child_label (const region_model &model,
-			 region_id this_rid,
-			 region_id child_rid,
-			 pretty_printer *pp) const
-    FINAL OVERRIDE;
-
-  void push_frame (region_id frame_rid);
-  region_id get_current_frame_id () const;
-  void pop_frame (region_model *model, region_id result_dst_rid,
-		  bool purge, purge_stats *stats,
-		  region_model_context *ctxt);
-
-  void remap_region_ids (const region_id_map &map) FINAL OVERRIDE;
-
-  unsigned get_num_frames () const { return m_frame_rids.length (); }
-  region_id get_frame_rid (unsigned i) const { return m_frame_rids[i]; }
-
-  static bool can_merge_p (const stack_region *stack_region_a,
-			   const stack_region *stack_region_b,
-			   model_merger *merger);
-
-  void walk_for_canonicalization (canonicalization *c) const FINAL OVERRIDE;
-
-  svalue_id get_value_by_name (tree identifier,
-			       const region_model &model) const;
-
-  void validate (const region_model &model) const FINAL OVERRIDE;
-
- private:
-  void add_to_hash (inchash::hash &hstate) const FINAL OVERRIDE;
-  void print_fields (const region_model &model,
-		     region_id this_rid,
-		     pretty_printer *pp) const
-    FINAL OVERRIDE;
-
-  auto_vec<region_id> m_frame_rids;
-};
-
-} // namespace ana
-
-template <>
-template <>
-inline bool
-is_a_helper <stack_region *>::test (region *reg)
-{
-  return reg->get_kind () == RK_STACK;
-}
-
-namespace ana {
-
-/* Concrete region subclass: a region within which regions can be
-   dynamically allocated.  */
-
-class heap_region : public region
-{
-public:
-  heap_region (region_id parent_rid, svalue_id sval_id)
-  : region (parent_rid, sval_id, NULL_TREE)
-  {}
-  heap_region (const heap_region &other);
-
-  bool compare_fields (const heap_region &other) const;
-
-  region *clone () const FINAL OVERRIDE;
-
-  enum region_kind get_kind () const FINAL OVERRIDE { return RK_HEAP; }
-
-  static bool can_merge_p (const heap_region *heap_a, region_id heap_a_rid,
-			   const heap_region *heap_b, region_id heap_b_rid,
-			   heap_region *merged_heap, region_id merged_heap_rid,
-			   model_merger *merger);
-
-  void walk_for_canonicalization (canonicalization *c) const FINAL OVERRIDE;
-
-};
-
-} // namespace ana
-
-template <>
-template <>
-inline bool
-is_a_helper <heap_region *>::test (region *reg)
-{
-  return reg->get_kind () == RK_HEAP;
-}
-
-namespace ana {
-
-/* Concrete region subclass.  The root region, containing all regions
-   (either directly, or as descendents).
-   Unique within a region_model.  */
-
-class root_region : public region
-{
-public:
-  root_region ();
-  root_region (const root_region &other);
-
-  bool compare_fields (const root_region &other) const;
-
-  region *clone () const FINAL OVERRIDE;
-
-  enum region_kind get_kind () const FINAL OVERRIDE { return RK_ROOT; }
-
-  void dump_child_label (const region_model &model,
-			 region_id this_rid,
-			 region_id child_rid,
-			 pretty_printer *pp) const
-    FINAL OVERRIDE;
-
-  region_id push_frame (region_model *model, function *fun,
-			vec<svalue_id> *arg_sids,
-			region_model_context *ctxt);
-  region_id get_current_frame_id (const region_model &model) const;
-  void pop_frame (region_model *model, region_id result_dst_rid,
-		  bool purge, purge_stats *stats,
-		  region_model_context *ctxt);
-
-  region_id ensure_stack_region (region_model *model);
-  region_id get_stack_region_id () const { return m_stack_rid; }
-  stack_region *get_stack_region (const region_model *model) const;
-
-  region_id ensure_globals_region (region_model *model);
-  region_id get_globals_region_id () const { return m_globals_rid; }
-  globals_region *get_globals_region (const region_model *model) const;
-
-  region_id ensure_code_region (region_model *model);
-  code_region *get_code_region (const region_model *model) const;
-
-  region_id ensure_heap_region (region_model *model);
-  heap_region *get_heap_region (const region_model *model) const;
-
-  void remap_region_ids (const region_id_map &map) FINAL OVERRIDE;
-
-  static bool can_merge_p (const root_region *root_region_a,
-			   const root_region *root_region_b,
-			   root_region *merged_root_region,
-			   model_merger *merger);
-
-  void walk_for_canonicalization (canonicalization *c) const FINAL OVERRIDE;
-
-  svalue_id get_value_by_name (tree identifier,
-			       const region_model &model) const;
-
-  void validate (const region_model &model) const FINAL OVERRIDE;
-
-private:
-  void add_to_hash (inchash::hash &hstate) const FINAL OVERRIDE;
-  void print_fields (const region_model &model,
-		     region_id this_rid,
-		     pretty_printer *pp) const
-    FINAL OVERRIDE;
-
-  region_id m_stack_rid;
-  region_id m_globals_rid;
-  region_id m_code_rid;
-  region_id m_heap_rid;
-};
-
-} // namespace ana
-
-template <>
-template <>
-inline bool
-is_a_helper <root_region *>::test (region *reg)
-{
-  return reg->get_kind () == RK_ROOT;
-}
-
-namespace ana {
-
-/* Concrete region subclass: a region to use when dereferencing an unknown
-   pointer.  */
-
-class symbolic_region : public region
-{
-public:
-  symbolic_region (region_id parent_rid, tree type, bool possibly_null)
-  : region (parent_rid, svalue_id::null (), type),
-    m_possibly_null (possibly_null)
-  {}
-  symbolic_region (const symbolic_region &other);
-
-  const symbolic_region *dyn_cast_symbolic_region () const FINAL OVERRIDE
-  { return this; }
-  symbolic_region *dyn_cast_symbolic_region () FINAL OVERRIDE
-  { return this; }
-
-  bool compare_fields (const symbolic_region &other) const;
-
-  region *clone () const FINAL OVERRIDE;
-
-  enum region_kind get_kind () const FINAL OVERRIDE { return RK_SYMBOLIC; }
-
-  void walk_for_canonicalization (canonicalization *c) const FINAL OVERRIDE;
-
-  void print_fields (const region_model &model,
-		     region_id this_rid,
-		     pretty_printer *pp) const FINAL OVERRIDE;
-
-  bool m_possibly_null;
-};
-
-/* A region_model encapsulates a representation of the state of memory, with
-   a tree of regions, along with their associated values.
-   The representation is graph-like because values can be pointers to
-   regions.
-   It also stores a constraint_manager, capturing relationships between
-   the values.  */
-
-class region_model
-{
- public:
-  region_model ();
-  region_model (const region_model &other);
-  ~region_model ();
-
-#if 0//__cplusplus >= 201103
-  region_model (region_model &&other);
-#endif
-
-  region_model &operator= (const region_model &other);
-
-  bool operator== (const region_model &other) const;
-  bool operator!= (const region_model &other) const
-  {
-    return !(*this == other);
-  }
-
-  hashval_t hash () const;
-
-  void print (pretty_printer *pp) const;
-
-  void print_svalue (svalue_id sid, pretty_printer *pp) const;
-
-  void dump_dot_to_pp (pretty_printer *pp) const;
-  void dump_dot_to_file (FILE *fp) const;
-  void dump_dot (const char *path) const;
-
-  void dump_to_pp (pretty_printer *pp, bool summarize) const;
-  void dump (FILE *fp, bool summarize) const;
-  void dump (bool summarize) const;
-
-  void debug () const;
-
-  void validate () const;
-
-  void canonicalize (region_model_context *ctxt);
-  bool canonicalized_p () const;
-
-  void check_for_poison (tree expr, region_model_context *ctxt);
-  void on_assignment (const gassign *stmt, region_model_context *ctxt);
-  bool on_call_pre (const gcall *stmt, region_model_context *ctxt);
-  void on_call_post (const gcall *stmt,
-		     bool unknown_side_effects,
-		     region_model_context *ctxt);
-  void handle_unrecognized_call (const gcall *call,
-				 region_model_context *ctxt);
-  void on_return (const greturn *stmt, region_model_context *ctxt);
-  void on_setjmp (const gcall *stmt, const exploded_node *enode,
-		  region_model_context *ctxt);
-  void on_longjmp (const gcall *longjmp_call, const gcall *setjmp_call,
-		   int setjmp_stack_depth, region_model_context *ctxt);
-
-  void update_for_phis (const supernode *snode,
-			const cfg_superedge *last_cfg_superedge,
-			region_model_context *ctxt);
-
-  void handle_phi (const gphi *phi,
-		   tree lhs, tree rhs, bool is_back_edge,
-		   region_model_context *ctxt);
-
-  bool maybe_update_for_edge (const superedge &edge,
-			      const gimple *last_stmt,
-			      region_model_context *ctxt);
-
-  region_id get_root_rid () const { return m_root_rid; }
-  root_region *get_root_region () const;
-
-  region_id get_stack_region_id () const;
-  region_id push_frame (function *fun, vec<svalue_id> *arg_sids,
-			region_model_context *ctxt);
-  region_id get_current_frame_id () const;
-  function * get_current_function () const;
-  void pop_frame (region_id result_dst_rid,
-		  bool purge, purge_stats *stats,
-		  region_model_context *ctxt);
-  int get_stack_depth () const;
-  function *get_function_at_depth (unsigned depth) const;
-
-  region_id get_globals_region_id () const;
-
-  svalue_id add_svalue (svalue *sval);
-  void replace_svalue (svalue_id sid, svalue *new_sval);
-
-  region_id add_region (region *r);
-
-  region_id add_region_for_type (region_id parent_rid, tree type,
-				 region_model_context *ctxt);
-
-  svalue *get_svalue (svalue_id sval_id) const;
-  region *get_region (region_id rid) const;
-
-  template <typename Subclass>
-  Subclass *get_region (region_id rid) const
-  {
-    region *result = get_region (rid);
-    if (result)
-      gcc_assert (is_a<Subclass *> (result));
-    return (Subclass *)result;
-  }
-
-  region_id get_lvalue (path_var pv, region_model_context *ctxt);
-  region_id get_lvalue (tree expr, region_model_context *ctxt);
-  svalue_id get_rvalue (path_var pv, region_model_context *ctxt);
-  svalue_id get_rvalue (tree expr, region_model_context *ctxt);
-
-  svalue_id get_or_create_ptr_svalue (tree ptr_type, region_id id);
-  svalue_id get_or_create_constant_svalue (tree cst_expr);
-  svalue_id get_svalue_for_fndecl (tree ptr_type, tree fndecl,
-				   region_model_context *ctxt);
-  svalue_id get_svalue_for_label (tree ptr_type, tree label,
-				  region_model_context *ctxt);
-
-  region_id get_region_for_fndecl (tree fndecl, region_model_context *ctxt);
-  region_id get_region_for_label (tree label, region_model_context *ctxt);
-
-  svalue_id maybe_cast (tree type, svalue_id sid, region_model_context *ctxt);
-  svalue_id maybe_cast_1 (tree type, svalue_id sid);
-
-  region_id get_field_region (region_id rid, tree field,
-			      region_model_context *ctxt);
-
-  region_id deref_rvalue (svalue_id ptr_sid, region_model_context *ctxt);
-  region_id deref_rvalue (tree ptr, region_model_context *ctxt);
-
-  void set_value (region_id lhs_rid, svalue_id rhs_sid,
-		  region_model_context *ctxt);
-  void set_value (tree lhs, tree rhs, region_model_context *ctxt);
-  svalue_id set_to_new_unknown_value (region_id dst_rid, tree type,
-				      region_model_context *ctxt);
-
-  void copy_region (region_id dst_rid, region_id src_rid,
-		    region_model_context *ctxt);
-
-  tristate eval_condition (svalue_id lhs,
-			   enum tree_code op,
-			   svalue_id rhs) const;
-  tristate eval_condition_without_cm (svalue_id lhs,
-				      enum tree_code op,
-				      svalue_id rhs) const;
-  tristate eval_condition (tree lhs,
-			   enum tree_code op,
-			   tree rhs,
-			   region_model_context *ctxt);
-  bool add_constraint (tree lhs, enum tree_code op, tree rhs,
-		       region_model_context *ctxt);
-
-  tree maybe_get_constant (svalue_id sid) const;
-
-  region_id add_new_malloc_region ();
-
-  tree get_representative_tree (svalue_id sid) const;
-  path_var get_representative_path_var (region_id rid) const;
-  void get_path_vars_for_svalue (svalue_id sid, vec<path_var> *out) const;
-
-  void purge_unused_svalues (purge_stats *out,
-			     region_model_context *ctxt,
-			     svalue_id_set *known_used_sids = NULL);
-  void remap_svalue_ids (const svalue_id_map &map);
-  void remap_region_ids (const region_id_map &map);
-
-  void purge_regions (const region_id_set &set,
-		      purge_stats *stats,
-		      logger *logger);
-
-  unsigned get_num_svalues () const { return m_svalues.length (); }
-  unsigned get_num_regions () const { return m_regions.length (); }
-
-  /* For selftests.  */
-  constraint_manager *get_constraints ()
-  {
-    return m_constraints;
-  }
-
-  void get_descendents (region_id rid, region_id_set *out,
-			region_id exclude_rid) const;
-
-  void delete_region_and_descendents (region_id rid,
-				      enum poison_kind pkind,
-				      purge_stats *stats,
-				      logger *logger);
-
-  bool can_merge_with_p (const region_model &other_model,
-			 region_model *out_model,
-			 svalue_id_merger_mapping *out) const;
-  bool can_merge_with_p (const region_model &other_model,
-			 region_model *out_model) const;
-
-  svalue_id get_value_by_name (const char *name) const;
-
-  svalue_id convert_byte_offset_to_array_index (tree ptr_type,
-						svalue_id offset_sid);
-
-  region_id get_or_create_mem_ref (tree type,
-				   svalue_id ptr_sid,
-				   svalue_id offset_sid,
-				   region_model_context *ctxt);
-  region_id get_or_create_pointer_plus_expr (tree type,
-					     svalue_id ptr_sid,
-					     svalue_id offset_sid,
-					     region_model_context *ctxt);
-  region_id get_or_create_view (region_id raw_rid, tree type,
-				region_model_context *ctxt);
-
-  tree get_fndecl_for_call (const gcall *call,
-			    region_model_context *ctxt);
-
- private:
-  region_id get_lvalue_1 (path_var pv, region_model_context *ctxt);
-  svalue_id get_rvalue_1 (path_var pv, region_model_context *ctxt);
-
-  void copy_struct_region (region_id dst_rid, struct_region *dst_reg,
-			   struct_region *src_reg, region_model_context *ctxt);
-  void copy_union_region (region_id dst_rid, union_region *src_reg,
-			  region_model_context *ctxt);
-  void copy_array_region (region_id dst_rid, array_region *dst_reg,
-			  array_region *src_reg, region_model_context *ctxt);
-
-  region_id make_region_for_unexpected_tree_code (region_model_context *ctxt,
-						  tree t,
-						  const dump_location_t &loc);
-
-  void add_any_constraints_from_ssa_def_stmt (tree lhs,
-					      enum tree_code op,
-					      tree rhs,
-					      region_model_context *ctxt);
-  void add_any_constraints_from_gassign (enum tree_code op,
-					 tree rhs,
-					 const gassign *assign,
-					 region_model_context *ctxt);
-  void add_any_constraints_from_gcall (enum tree_code op,
-				       tree rhs,
-				       const gcall *call,
-				       region_model_context *ctxt);
-
-  void update_for_call_superedge (const call_superedge &call_edge,
-				  region_model_context *ctxt);
-  void update_for_return_superedge (const return_superedge &return_edge,
-				    region_model_context *ctxt);
-  void update_for_call_summary (const callgraph_superedge &cg_sedge,
-				region_model_context *ctxt);
-  bool apply_constraints_for_gcond (const cfg_superedge &edge,
-				    const gcond *cond_stmt,
-				    region_model_context *ctxt);
-  bool apply_constraints_for_gswitch (const switch_cfg_superedge &edge,
-				      const gswitch *switch_stmt,
-				      region_model_context *ctxt);
-
-  void poison_any_pointers_to_bad_regions (const region_id_set &bad_regions,
-					   enum poison_kind pkind);
-
-  void dump_summary_of_rep_path_vars (pretty_printer *pp,
-				      auto_vec<path_var> *rep_path_vars,
-				      bool *is_first);
-
-  auto_delete_vec<svalue> m_svalues;
-  auto_delete_vec<region> m_regions;
-  region_id m_root_rid;
-  constraint_manager *m_constraints; // TODO: embed, rather than dynalloc?
-};
-
-/* Some region_model activity could lead to warnings (e.g. attempts to use an
-   uninitialized value).  This abstract base class encapsulates an interface
-   for the region model to use when emitting such warnings.
-
-   It also provides an interface for being notified about svalue_ids being
-   remapped, and being deleted.
-
-   Having this as an abstract base class allows us to support the various
-   operations needed by program_state in the analyzer within region_model,
-   whilst keeping them somewhat modularized.  */
-
-class region_model_context
-{
- public:
-  virtual void warn (pending_diagnostic *d) = 0;
-
-  /* Hook for clients that store svalue_id instances, so that they
-     can remap their IDs when the underlying region_model renumbers
-     the IDs.  */
-  virtual void remap_svalue_ids (const svalue_id_map &map) = 0;
-
-#if 0
-  /* Return true if if's OK to purge SID when simplifying state.
-     Subclasses can return false for values that have sm state,
-     to avoid generating "leak" false positives.  */
-  virtual bool can_purge_p (svalue_id sid) = 0;
-#endif
-
-  /* Hook for clients to be notified when a range of SIDs have
-     been purged, so that they can purge state relating to those
-     values (and potentially emit warnings about leaks).
-     All SIDs from FIRST_PURGED_SID numerically upwards are being
-     purged.
-     The return values is a count of how many items of data the client
-     has purged (potentially for use in selftests).
-     MAP has already been applied to the IDs, but is provided in case
-     the client needs to figure out the old IDs.  */
-  virtual int on_svalue_purge (svalue_id first_purged_sid,
-			       const svalue_id_map &map) = 0;
-
-  virtual logger *get_logger () = 0;
-
-  /* Hook for clients to be notified when CHILD_SID is created
-     from PARENT_SID, when "inheriting" a value for a region from a
-     parent region.
-     This exists so that state machines that inherit state can
-     propagate the state from parent to child.  */
-  virtual void on_inherited_svalue (svalue_id parent_sid,
-				    svalue_id child_sid) = 0;
-
-  /* Hook for clients to be notified when DST_SID is created
-     (or reused) as a cast from SRC_SID.
-     This exists so that state machines can propagate the state
-     from SRC_SID to DST_SID.  */
-  virtual void on_cast (svalue_id src_sid,
-			svalue_id dst_sid) = 0;
-
-  /* Hook for clients to be notified when the condition
-     "LHS OP RHS" is added to the region model.
-     This exists so that state machines can detect tests on edges,
-     and use them to trigger sm-state transitions (e.g. transitions due
-     to ptrs becoming known to be NULL or non-NULL, rather than just
-     "unchecked") */
-  virtual void on_condition (tree lhs, enum tree_code op, tree rhs) = 0;
-
-  /* Hooks for clients to be notified when an unknown change happens
-     to SID (in response to a call to an unknown function).  */
-  virtual void on_unknown_change (svalue_id sid) = 0;
-
-  /* Hooks for clients to be notified when a phi node is handled,
-     where RHS is the pertinent argument.  */
-  virtual void on_phi (const gphi *phi, tree rhs) = 0;
-
-  /* Hooks for clients to be notified when the region model doesn't
-     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;
-};
-
-/* A "do nothing" subclass of region_model_context.  */
-
-class noop_region_model_context : public region_model_context
-{
-public:
-  void warn (pending_diagnostic *) OVERRIDE {}
-  void remap_svalue_ids (const svalue_id_map &) OVERRIDE {}
-  int on_svalue_purge (svalue_id, const svalue_id_map &) OVERRIDE
-  {
-    return 0;
-  }
-  logger *get_logger () OVERRIDE { return NULL; }
-  void on_inherited_svalue (svalue_id parent_sid ATTRIBUTE_UNUSED,
-			    svalue_id child_sid  ATTRIBUTE_UNUSED)
-    OVERRIDE
-  {
-  }
-  void on_cast (svalue_id src_sid ATTRIBUTE_UNUSED,
-		svalue_id dst_sid ATTRIBUTE_UNUSED) OVERRIDE
-  {
-  }
-  void on_condition (tree lhs ATTRIBUTE_UNUSED,
-		     enum tree_code op ATTRIBUTE_UNUSED,
-		     tree rhs ATTRIBUTE_UNUSED) OVERRIDE
-  {
-  }
-  void on_unknown_change (svalue_id sid ATTRIBUTE_UNUSED) OVERRIDE
-  {
-  }
-  void on_phi (const gphi *phi ATTRIBUTE_UNUSED,
-	       tree rhs ATTRIBUTE_UNUSED) OVERRIDE
-  {
-  }
-  void on_unexpected_tree_code (tree, const dump_location_t &) OVERRIDE {}
-};
-
-/* A subclass of region_model_context for determining if operations fail
-   e.g. "can we generate a region for the lvalue of EXPR?".  */
-
-class tentative_region_model_context : public noop_region_model_context
-{
-public:
-  tentative_region_model_context () : m_num_unexpected_codes (0) {}
-
-  void on_unexpected_tree_code (tree, const dump_location_t &)
-    FINAL OVERRIDE
-  {
-    m_num_unexpected_codes++;
-  }
-
-  bool had_errors_p () const { return m_num_unexpected_codes > 0; }
-
-private:
-  int m_num_unexpected_codes;
-};
-
-/* A bundle of data for use when attempting to merge two region_model
-   instances to make a third.  */
-
-struct model_merger
-{
-  model_merger (const region_model *model_a,
-		const region_model *model_b,
-		region_model *merged_model,
-		svalue_id_merger_mapping *sid_mapping)
-  : m_model_a (model_a), m_model_b (model_b),
-    m_merged_model (merged_model),
-    m_map_regions_from_a_to_m (model_a->get_num_regions ()),
-    m_map_regions_from_b_to_m (model_b->get_num_regions ()),
-    m_sid_mapping (sid_mapping)
-  {
-    gcc_assert (sid_mapping);
-  }
-
-  void dump_to_pp (pretty_printer *pp) const;
-  void dump (FILE *fp) const;
-  void dump () const;
-
-  template <typename Subclass>
-  Subclass *get_region_a (region_id rid_a) const
-  {
-    return m_model_a->get_region <Subclass> (rid_a);
-  }
-
-  template <typename Subclass>
-  Subclass *get_region_b (region_id rid_b) const
-  {
-    return m_model_b->get_region <Subclass> (rid_b);
-  }
-
-  bool can_merge_values_p (svalue_id sid_a,
-			   svalue_id sid_b,
-			   svalue_id *merged_sid);
-
-  void record_regions (region_id a_rid,
-		       region_id b_rid,
-		       region_id merged_rid);
-
-  void record_svalues (svalue_id a_sid,
-		       svalue_id b_sid,
-		       svalue_id merged_sid);
-
-  const region_model *m_model_a;
-  const region_model *m_model_b;
-  region_model *m_merged_model;
-
-  one_way_region_id_map m_map_regions_from_a_to_m;
-  one_way_region_id_map m_map_regions_from_b_to_m;
-  svalue_id_merger_mapping *m_sid_mapping;
-};
-
-/* A bundle of data that can be optionally generated during merger of two
-   region_models that describes how svalue_ids in each of the two inputs
-   are mapped to svalue_ids in the merged output.
-
-   For use when merging sm-states within program_state.  */
-
-struct svalue_id_merger_mapping
-{
-  svalue_id_merger_mapping (const region_model &a,
-			    const region_model &b);
-
-  void dump_to_pp (pretty_printer *pp) const;
-  void dump (FILE *fp) const;
-  void dump () const;
-
-  one_way_svalue_id_map m_map_from_a_to_m;
-  one_way_svalue_id_map m_map_from_b_to_m;
-};
-
-/* A bundle of data used when canonicalizing a region_model so that the
-   order of regions and svalues is in a predictable order (thus increasing
-   the chance of two region_models being equal).
-
-   This object is used to keep track of a recursive traversal across the
-   svalues and regions within the model, made in a deterministic order,
-   assigning new ids the first time each region or svalue is
-   encountered.  */
-
-struct canonicalization
-{
-  canonicalization (const region_model &model);
-  void walk_rid (region_id rid);
-  void walk_sid (svalue_id sid);
-
-  void dump_to_pp (pretty_printer *pp) const;
-  void dump (FILE *fp) const;
-  void dump () const;
-
-  const region_model &m_model;
-  /* Maps from existing IDs to new IDs.  */
-  region_id_map m_rid_map;
-  svalue_id_map m_sid_map;
-  /* The next IDs to hand out.  */
-  int m_next_rid_int;
-  int m_next_sid_int;
-};
-
-} // namespace ana
-
-namespace inchash
-{
-  extern void add (svalue_id sid, hash &hstate);
-  extern void add (region_id rid, hash &hstate);
-} // namespace inchash
-
-extern void debug (const region_model &rmodel);
-
 namespace ana {
 
 #if CHECKING_P
@@ -2124,31 +290,6 @@ namespace selftest {
 
 using namespace ::selftest;
 
-/* An implementation of region_model_context for use in selftests, which
-   stores any pending_diagnostic instances passed to it.  */
-
-class test_region_model_context : public noop_region_model_context
-{
-public:
-  void warn (pending_diagnostic *d) FINAL OVERRIDE
-  {
-    m_diagnostics.safe_push (d);
-  }
-
-  unsigned get_num_diagnostics () const { return m_diagnostics.length (); }
-
-  void on_unexpected_tree_code (tree t, const dump_location_t &)
-    FINAL OVERRIDE
-  {
-    internal_error ("unhandled tree code: %qs",
-		    t ? get_tree_code_name (TREE_CODE (t)) : "(null)");
-  }
-
-private:
-  /* Implicitly delete any diagnostics in the dtor.  */
-  auto_delete_vec<pending_diagnostic> m_diagnostics;
-};
-
 /* Attempt to add the constraint (LHS OP RHS) to MODEL.
    Verify that MODEL remains satisfiable.  */
 
@@ -2167,13 +308,6 @@ private:
     ASSERT_FALSE (sat);				\
   SELFTEST_END_STMT
 
-/* Implementation detail of the ASSERT_CONDITION_* macros.  */
-
-void assert_condition (const location &loc,
-		       region_model &model,
-		       tree lhs, tree_code op, tree rhs,
-		       tristate expected);
-
 /* Assert that REGION_MODEL evaluates the condition "LHS OP RHS"
    as "true".  */
 
diff --git a/gcc/analyzer/sm-signal.cc b/gcc/analyzer/sm-signal.cc
index f2a7911603f..fd9a5a13fb6 100644
--- a/gcc/analyzer/sm-signal.cc
+++ b/gcc/analyzer/sm-signal.cc
@@ -200,19 +200,6 @@ signal_state_machine::signal_state_machine (logger *logger)
   m_stop = add_state ("stop");
 }
 
-/* Update MODEL for edges that simulate HANDLER_FUN being called as
-   an signal-handler in response to a signal.  */
-
-static void
-update_model_for_signal_handler (region_model *model,
-				 function *handler_fun)
-{
-  gcc_assert (model);
-  /* Purge all state within MODEL.  */
-  *model = region_model ();
-  model->push_frame (handler_fun, NULL, NULL);
-}
-
 /* Update MODEL for edges that simulate HANDLER_FUN being called as
    an signal-handler in response to a signal.  */
 
@@ -236,12 +223,6 @@ public:
     pp_string (pp, "signal delivered");
   }
 
-  void update_model (region_model *model,
-		     const exploded_edge &eedge) FINAL OVERRIDE
-  {
-    update_model_for_signal_handler (model, eedge.m_dest->get_function ());
-  }
-
   void update_model2 (region_model2 *model,
 		      const exploded_edge &eedge) FINAL OVERRIDE
   {
@@ -285,23 +266,16 @@ public:
 					    handler_fun);
 
     program_state state_entering_handler (eg->get_ext_state ());
-    if (state_entering_handler.m_region_model)
-      update_model_for_signal_handler (state_entering_handler.m_region_model,
-				       handler_fun);
-    if (state_entering_handler.m_region_model2)
-      update_model2_for_signal_handler (state_entering_handler.m_region_model2,
-					handler_fun);
-    state_entering_handler.m_checker_states[sm_idx]->set_global_state
-      (m_sm.m_in_signal_handler);
+    update_model2_for_signal_handler (state_entering_handler.m_region_model2,
+				      handler_fun);
     state_entering_handler.m_checker_states2[sm_idx]->set_global_state
       (m_sm.m_in_signal_handler);
 
     exploded_node *dst_enode = eg->get_or_create_node (entering_handler,
 						       state_entering_handler,
-						       src_enode,
-						       NULL);
+						       src_enode);
     if (dst_enode)
-      eg->add_edge (src_enode, dst_enode, NULL, state_change (),
+      eg->add_edge (src_enode, dst_enode, NULL, /*state_change (),*/
 		    new signal_delivery_edge_info_t ());
   }
 
-- 
2.26.2

