From 6f2d1f226a83e953b1d57a5d76632e697c72ccbf Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 28 Apr 2020 17:19:45 -0400
Subject: [PATCH 085/293] FIXME: eliminate map_region2 in favor of a new
 space_region2; add dyn_cast

---
 gcc/analyzer/analyzer.h       |   1 -
 gcc/analyzer/region-model2.cc | 377 +---------------------------------
 gcc/analyzer/region-model2.h  | 158 +++-----------
 3 files changed, 40 insertions(+), 496 deletions(-)

diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h
index d3968ed3322..ee416f0e347 100644
--- a/gcc/analyzer/analyzer.h
+++ b/gcc/analyzer/analyzer.h
@@ -62,7 +62,6 @@ class svalue2;
   class setjmp_svalue2;
   class initial_svalue2;
 class region2;
-  class map_region2;
   class function_region2;
   class symbolic_region2;
   class element_region2;
diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc
index 23fe704e34e..1c4155f05ee 100644
--- a/gcc/analyzer/region-model2.cc
+++ b/gcc/analyzer/region-model2.cc
@@ -1694,235 +1694,6 @@ region2::non_null_p (const region_model2 &model) const
   return true;
 }
 
-/* class map_region2 : public region2.  */
-
-/* Compare the fields of this map_region2 with OTHER, returning true
-   if they are equal.
-   For use by region2::operator==.  */
-#if 0
-bool
-map_region2::compare_fields (const map_region2 &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;
-      region2_id e = (*iter).second;
-      region2_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;
-}
-#endif
-
-/* Implementation of region2::print_fields vfunc for map_region2.  */
-#if 0
-void
-map_region2::print_fields (const region_model2 &model,
-			  region2_id this_reg,
-			  pretty_printer *pp) const
-{
-  region2::print_fields (model, this_reg, 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;
-      region2_id child_reg = (*iter).second;
-      dump_quoted_tree (pp, expr);
-      pp_string (pp, ": ");
-      child_reg.print (pp);
-    }
-  pp_string (pp, "}");
-}
-#endif
-
-/* Implementation of region2::validate vfunc for map_region2.  */
-#if 0
-void
-map_region2::validate (const region_model2 &model) const
-{
-  region2::validate (model);
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      region2_id child_reg = (*iter).second;
-      child_reg.validate (model);
-    }
-}
-#endif
-
-/* Implementation of region2::dump_dot_to_pp vfunc for map_region2.  */
-#if 0
-void
-map_region2::dump_dot_to_pp (const region_model2 &model,
-			    region2_id this_reg,
-			    pretty_printer *pp) const
-{
-  region2::dump_dot_to_pp (model, this_reg, 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;
-      region2_id child_reg = (*iter).second;
-
-      pp_printf (pp, "rid_label_%i [label=\"", child_reg.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_reg.as_int ());
-      pp_string (pp, " -> ");
-      child_reg.dump_node_name_to_pp (pp);
-      pp_string (pp, ";");
-      pp_newline (pp);
-    }
-}
-#endif
-
-/* Implementation of region2::dump_child_label vfunc for map_region2.  */
-#if 0
-void
-map_region2::dump_child_label (const region_model2 &model,
-			      region2_id this_reg,
-			      region2_id child_reg,
-			      pretty_printer *pp) const
-{
-  region2::dump_child_label (model, this_reg, child_reg, pp);
-
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end ();
-       ++iter)
-    {
-      if (child_reg == (*iter).second)
-	{
-	  tree key = (*iter).first;
-	  dump_quoted_tree (pp, key);
-	  pp_string (pp, ": ");
-	}
-    }
-}
-#endif
-
-/* Look for a child region2 for KEY within this map_region2.
-   If it doesn't already exist, create a child map_region2, using TYPE for
-   its type.
-   Return the region2_id of the child (whether pre-existing, or
-   newly-created).
-   Notify CTXT if we don't know how to handle TYPE.  */
-#if 0
-region2 *
-map_region2::get_or_create (region_model2 *model,
-			   tree key,
-			   tree type,
-			   region_model2_context *ctxt)
-{
-  gcc_assert (key);
-  gcc_assert (valid_key_p (key));
-  region2 **slot = m_map.get (key);
-  if (slot)
-    return *slot;
-  region2 *child_reg = model->add_region_for_type (type, ctxt);
-  m_map.put (key, child_reg);
-  return child_reg;
-}
-#endif
-
-#if 0
-/* Get the region2_id for the child region2 for KEY within this
-   MAP_REGION2, or NULL if there is no such child region2.  */
-
-region2_id *
-map_region2::get (tree key)
-{
-  gcc_assert (key);
-  gcc_assert (valid_key_p (key));
-  region2_id *slot = m_map.get (key);
-  return slot;
-}
-#endif
-
-/* Implementation of region2::add_to_hash vfunc for map_region2.  */
-#if 0
-void
-map_region2::add_to_hash (inchash::hash &hstate) const
-{
-  region2::add_to_hash (hstate);
-  // TODO
-}
-#endif
-
-/* Remove the binding of KEY to its child region2 (but not the
-   child region2 itself).
-   For use when purging unneeded SSA names.  */
-#if 0
-void
-map_region2::unbind (tree key)
-{
-  gcc_assert (key);
-  gcc_assert (valid_key_p (key));
-  m_map.remove (key);
-}
-#endif
-
-/* Look for a child region2 with id CHILD_REG within this map_region2.
-   If one is found, return its tree key, otherwise return NULL_TREE.  */
-#if 0
-tree
-map_region2::get_tree_for_child_region2 (region2_id child_reg) 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;
-      region2_id r = (*iter).second;
-      if (r == child_reg)
-	return key;
-    }
-
-  return NULL_TREE;
-}
-
-/* Look for a child region2 CHILD within this map_region2.
-   If one is found, return its tree key, otherwise return NULL_TREE.  */
-
-tree
-map_region2::get_tree_for_child_region2 (region2 *child,
-				       const region_model2 &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;
-      region2_id r = (*iter).second;
-      if (model.get_region2 (r) == child)
-	return key;
-    }
-
-  return NULL_TREE;
-}
-#endif
-
 /* Comparator for trees to impose a deterministic ordering on
    T1 and T2.  */
 
@@ -2028,115 +1799,7 @@ tree_cmp (const void *p1, const void *p2)
   return tree_cmp (t1, t2);
 }
 
-/* Attempt to merge MAP_REGION2_A and MAP_REGION2_B into MERGED_MAP_REGION2,
-   which has region2_id MERGED_REG, using MERGER.
-   Return true if the merger is possible, false otherwise.  */
-#if 0
-bool
-map_region2::can_merge_p (const map_region2 *map_region2_a,
-			 const map_region2 *map_region2_b,
-			 map_region2 *merged_map_region2,
-			 region2_id merged_reg,
-			 model_merger *merger)
-{
-  for (map_t::iterator iter = map_region2_a->m_map.begin ();
-       iter != map_region2_a->m_map.end ();
-       ++iter)
-    {
-      tree key_a = (*iter).first;
-      region2_id rid_a = (*iter).second;
-
-      if (const region2_id *slot_b
-	  = const_cast<map_region2 *>(map_region2_b)->m_map.get (key_a))
-	{
-	  region2_id rid_b = *slot_b;
-
-	  region2 *child_region2_a = merger->get_region2_a <region2> (rid_a);
-	  region2 *child_region2_b = merger->get_region2_b <region2> (rid_b);
-
-	  gcc_assert (child_region2_a->get_type ()
-		      == child_region2_b->get_type ());
-
-	  gcc_assert (child_region2_a->get_kind ()
-		      == child_region2_b->get_kind ());
-
-	  region2_id child_merged_reg
-	    = merged_map_region2->get_or_create (merger->m_merged_model,
-						merged_reg,
-						key_a,
-						child_region2_a->get_type (),
-						NULL);
-
-	  region2 *child_merged_region2
-	    = merger->m_merged_model->get_region2 (child_merged_reg);
-
-	  /* Consider values.  */
-	  svalue2_id child_a_sval = child_region2_a->get_value_direct ();
-	  svalue2_id child_b_sval = child_region2_b->get_value_direct ();
-	  svalue2_id child_merged_sval;
-	  if (!merger->can_merge_values_p (child_a_sval, child_b_sval,
-					   &child_merged_sval))
-	    return false;
-	  if (!child_merged_sval.null_p ())
-	    child_merged_region2->set_value (*merger->m_merged_model,
-					    child_merged_reg,
-					    child_merged_sval,
-					    NULL);
-
-	  if (map_region2 *map_region2_a = child_region2_a->dyn_cast_map_region2 ())
-	    {
-	      /* Recurse.  */
-	      if (!can_merge_p (map_region2_a,
-				as_a <map_region2 *> (child_region2_b),
-				as_a <map_region2 *> (child_merged_region2),
-				child_merged_reg,
-				merger))
-		return false;
-	    }
-
-	}
-      else
-	{
-	  /* TODO: region2 is present in A, but absent in B.  */
-	}
-    }
-
-  /* TODO: check for keys in B that aren't in A.  */
-
-  return true;
-}
-#endif
-
-/* For debugging purposes: look for a child region2 for a decl named
-   IDENTIFIER (or an SSA_NAME for such a decl), returning its value,
-   or svalue2_id::null if none are found.  */
-#if 0
-svalue2_id
-map_region2::get_value_by_name (tree identifier,
-			       const region_model2 &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)
-	  {
-	    region2_id rid = (*iter).second;
-	    region2 *region2 = model.get_region2 (rid);
-	    return region2->get_value (const_cast<region_model2 &>(model),
-				      false, NULL);
-	  }
-    }
-  return svalue2_id::null ();
-}
-#endif
-
-/* class frame_region2 : public map_region2.  */
+/* class frame_region2 : public space_region2.  */
 
 frame_region2::~frame_region2 ()
 {
@@ -2177,18 +1840,6 @@ frame_region2::compare_fields (const frame_region2 &other) const
   return true;
 }
 
-/* Implementation of map_region2::valid_key_p vfunc for frame_region2.  */
-
-bool
-frame_region2::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 region2::print_fields vfunc for frame_region2.  */
 #if 0
 void
@@ -2216,6 +1867,12 @@ frame_region2::get_region_for_local (region_model2_manager *mgr,
 				     tree expr,
 				     region_model2_context */*ctxt*/)
 {
+  // TODO: could also check that VAR_DECLs are locals
+  gcc_assert (TREE_CODE (expr) == PARM_DECL
+	      || TREE_CODE (expr) == VAR_DECL
+	      || TREE_CODE (expr) == SSA_NAME
+	      || TREE_CODE (expr) == RESULT_DECL);
+
   if (region2 **slot = m_locals.get (expr))
     return *slot;
   decl_region2 *reg
@@ -2224,7 +1881,7 @@ frame_region2::get_region_for_local (region_model2_manager *mgr,
   return reg;
 }
 
-/* class globals_region2 : public scope_region2.  */
+/* class globals_region2 : public space_region2.  */
 
 /* Compare the fields of this globals_region2 with OTHER, returning true
    if they are equal.
@@ -2246,14 +1903,6 @@ globals_region2::dump_to_pp (pretty_printer *pp, bool simple) const
     pp_string (pp, "globals");
 }
 
-/* Implementation of map_region2::valid_key_p vfunc for globals_region2.  */
-
-bool
-globals_region2::valid_key_p (tree key) const
-{
-  return TREE_CODE (key) == VAR_DECL;
-}
-
 /* class code_region2 : public map_region2.  */
 
 /* Compare the fields of this code_region2 with OTHER, returning true
@@ -2267,14 +1916,6 @@ code_region2::compare_fields (const code_region2 &other) const
 }
 #endif
 
-/* Implementation of map_region2::valid_key_p vfunc for code_region2.  */
-
-bool
-code_region2::valid_key_p (tree key) const
-{
-  return TREE_CODE (key) == FUNCTION_DECL;
-}
-
 /* FIXME.  */
 
 void
@@ -2318,11 +1959,13 @@ function_region2::dump_to_pp (pretty_printer *pp, bool simple) const
 
 /* Implementation of map_region2::valid_key_p vfunc for function_region2.  */
 
+#if 0
 bool
 function_region2::valid_key_p (tree key) const
 {
   return TREE_CODE (key) == LABEL_DECL;
 }
+#endif
 
 /* class stack_region2 : public region2.  */
 
diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h
index e4fc3395cf9..9d8d4fd8fb4 100644
--- a/gcc/analyzer/region-model2.h
+++ b/gcc/analyzer/region-model2.h
@@ -741,15 +741,14 @@ namespace ana {
    than a struct_region.
 
    region
-     map_region
-       scope_region
-         frame_region (RK_FRAME)
-         globals_region (RK_GLOBALS)
+     space_region
+       frame_region (RK_FRAME)
+       globals_region (RK_GLOBALS)
        code_region (RK_CODE)
-       function_region (RK_FUNCTION)
-     stack_region (RK_STACK)
-     heap_region (RK_HEAP)
-     root_region (RK_ROOT)
+       stack_region (RK_STACK)
+       heap_region (RK_HEAP)
+       root_region (RK_ROOT)
+     function_region (RK_FUNCTION)
      label_region (RK_LABEL)
      symbolic_region (RK_SYMBOLIC)
      field_region2 (RK_FIELD)
@@ -810,10 +809,10 @@ public:
   static int cmp_ids (const region2 *reg1, const region2 *reg2);
 
   virtual enum kind get_kind () const = 0;
-  virtual map_region2 *dyn_cast_map_region2 () { return NULL; }
   virtual function_region2 *dyn_cast_function_region2 () { return NULL; }
   virtual symbolic_region2 *dyn_cast_symbolic_region2 () { return NULL; }
   virtual const symbolic_region2 *dyn_cast_symbolic_region2 () const { return NULL; }
+  virtual field_region2 *dyn_cast_field_region2 () { return NULL; }
   virtual element_region2 *dyn_cast_element_region2 () { return NULL; }
   virtual offset_region2 *dyn_cast_offset_region2 () { return NULL; }
   virtual string_region2 *dyn_cast_string_region2 () { return NULL; }
@@ -909,106 +908,18 @@ is_a_helper <region2 *>::test (region2 *)
 
 namespace ana {
 
-/* A region2 that has children identified by tree keys.
-   For example a stack frame has subregion2s per local, and a region2
-   for a struct has subregion2s per field.  */
+/* Abstract subclass of region2, for regions that represent an untyped
+   space within memory, such as the stack or the heap.  */
 
-class map_region2 : public region2
+class space_region2 : public region2
 {
-public:
-  typedef ordered_hash_map<tree, region2 *> map_t;
-  typedef map_t::iterator iterator_t;
-
-  map_region2 (unsigned id, region2 *parent, tree type)
-  : region2 (id, parent, type)
-  {}
-  map_region2 (const map_region2 &other);
-
-  map_region2 *dyn_cast_map_region2 () FINAL OVERRIDE { return this; }
-
-#if 0
-  void dump_dot_to_pp (const region_model2 &model,
-		       pretty_printer *pp) const
-    FINAL OVERRIDE;
-  void dump_child_label (const region_model2 &model,
-			 region2 *child,
-			 pretty_printer *pp) const
-    FINAL OVERRIDE;
-#endif
-
-#if 0
-  region2_id get_or_create (region_model2 *model,
-			   tree expr, tree type,
-			   region_model2_context *ctxt);
-  void unbind (tree expr);
-  region2_id *get (tree expr);
-#endif
-
-#if 0
-  tree get_tree_for_child_region2 (region2_id child_rid) const;
-
-  tree get_tree_for_child_region2 (region2 *child,
-				  const region_model2 &model) const;
-
-  static bool can_merge_p (const map_region2 *map_region2_a,
-			   const map_region2 *map_region2_b,
-			   map_region2 *merged_map_region2,
-			   region2_id merged_rid,
-			   model_merger *merger);
-#endif
-  virtual bool valid_key_p (tree key) const = 0;
-
-#if 0
-  svalue2_id get_value_by_name (tree identifier,
-			       const region_model2 &model) const;
-#endif
-
-  iterator_t begin () { return m_map.begin (); }
-  iterator_t end () { return m_map.end (); }
-  size_t elements () const { return m_map.elements (); }
-
- protected:
-#if 0
-  void add_to_hash (inchash::hash &hstate) const OVERRIDE;
-  void print_fields (const region_model2 &model,
-		     pretty_printer *pp) const
-    OVERRIDE;
-  void validate (const region_model2 &model) const FINAL OVERRIDE;
-#endif
-
- private:
-  /* Mapping from tree to child region2.  */
-  map_t m_map;
-};
-
-} // namespace ana
-
-template <>
-template <>
-inline bool
-is_a_helper <map_region2 *>::test (region2 *reg)
-{
-  return (reg->dyn_cast_map_region2 () != NULL);
-}
-
-namespace ana {
-
-/* Abstract map_region2 subclass for accessing decls, used as a base class
-   for function frames and for the globals region2.  */
-
-class scope_region2 : public map_region2
-{
- public:
-
- protected:
-  scope_region2 (unsigned id, region2 *parent)
-    : map_region2 (id, parent, NULL_TREE)
+protected:
+  space_region2 (unsigned id, region2 *parent)
+  : region2 (id, parent, NULL_TREE)
   {}
-
-  bool compare_fields (const scope_region2 &other) const;
 };
 
-/* Concrete region2 subclass, representing a function frame on the stack,
+/* Concrete space_region2 subclass, representing a function frame on the stack,
    to contain the locals.
    The parent is the stack region; there's also a hierarchy of call-stack
    prefixes expressed via m_calling_frame.
@@ -1020,12 +931,13 @@ class scope_region2 : public map_region2
    where the parent region for each of the frames is the "stack" region.
    The index is the count of frames earlier than this in the stack.  */
 
-class frame_region2 : public scope_region2
+class frame_region2 : public space_region2
 {
 public:
-  frame_region2 (unsigned id, region2 *parent, frame_region2 *calling_frame,
+  frame_region2 (unsigned id, region2 *parent,
+		 frame_region2 *calling_frame,
 		 function *fun, int index)
-  : scope_region2 (id, parent), m_calling_frame (calling_frame),
+  : space_region2 (id, parent), m_calling_frame (calling_frame),
     m_fun (fun), m_index (index)
   {}
   ~frame_region2 ();
@@ -1039,8 +951,6 @@ public:
     FINAL OVERRIDE;
   void add_to_hash (inchash::hash &hstate) const FINAL OVERRIDE;
 #endif
-  /* map_region2 vfuncs.  */
-  bool valid_key_p (tree key) const FINAL OVERRIDE;
 
   /* Accessors.  */
   frame_region2 *get_calling_frame () const { return m_calling_frame; }
@@ -1060,7 +970,6 @@ public:
   int m_index;
   typedef hash_map<tree, region2 *> map_t;
   map_t m_locals;
-  // TODO: make this not be a map_region2 anymore?
   /* TODO: do we want a distinction between params (assumed initialized)
      vs temporaries?  */
 };
@@ -1077,13 +986,13 @@ is_a_helper <frame_region2 *>::test (region2 *reg)
 
 namespace ana {
 
-/* Concrete region2 subclass, to hold global variables (data and bss).  */
+/* Concrete space_region2 subclass, to hold global variables (data and bss).  */
 
-class globals_region2 : public scope_region2
+class globals_region2 : public space_region2
 {
  public:
   globals_region2 (unsigned id, region2 *parent)
-  : scope_region2 (id, parent)
+  : space_region2 (id, parent)
   {}
 
   /* region2 vfuncs.  */
@@ -1093,9 +1002,6 @@ class globals_region2 : public scope_region2
   enum kind get_kind () const FINAL OVERRIDE { return RK_GLOBALS; }
   void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE;
 
-  /* map_region2 vfuncs.  */
-  bool valid_key_p (tree key) const FINAL OVERRIDE;
-
   bool compare_fields (const globals_region2 &other) const;
 };
 
@@ -1114,20 +1020,17 @@ namespace ana {
 /* Concrete region2 subclass.  A map_region2 representing the code, using
    FUNCTION_DECLs for its keys.  */
 
-class code_region2 : public map_region2
+class code_region2 : public space_region2
 {
 public:
   code_region2 (unsigned id, region2 *parent)
-  : map_region2 (id, parent, NULL_TREE)
+  : space_region2 (id, parent)
   {}
 
   /* region2 vfuncs.  */
   void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE;
   enum kind get_kind () const FINAL OVERRIDE { return RK_CODE; }
 
-  /* map_region2 vfunc.  */
-  bool valid_key_p (tree key) const FINAL OVERRIDE;
-
   region2 *get_element (region_model2 *model,
 			svalue2 *index,
 			region_model2_context *ctxt);
@@ -1147,14 +1050,15 @@ is_a_helper <code_region2 *>::test (region2 *reg)
 
 namespace ana {
 
-/* Concrete region2 subclass.  A map_region2 representing the code for
+// FIXME:
+/* Concrete region2 subclass.  A region2 representing the code for
    a particular function, using LABEL_DECLs for its keys.  */
 
-class function_region2 : public map_region2
+class function_region2 : public region2
 {
 public:
-  function_region2 (unsigned id, region2 *parent, tree fndecl)
-  : map_region2 (id, parent, TREE_TYPE (fndecl)), m_fndecl (fndecl)
+  function_region2 (unsigned id, code_region2 *parent, tree fndecl)
+  : region2 (id, parent, TREE_TYPE (fndecl)), m_fndecl (fndecl)
   {
     gcc_assert (FUNC_OR_METHOD_TYPE_P (TREE_TYPE (fndecl)));
   }
@@ -1166,9 +1070,6 @@ public:
 
   tree get_fndecl () const { return m_fndecl; }
 
-  /* map_region2 vfunc.  */
-  bool valid_key_p (tree key) const FINAL OVERRIDE;
-
   region2 *get_element (region_model2 *model,
 			svalue2 *index_sid,
 			region_model2_context *ctxt);
@@ -1443,6 +1344,7 @@ public:
   enum region2::kind get_kind () const FINAL OVERRIDE { return RK_FIELD; }
 
   void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE;
+  field_region2 *dyn_cast_field_region2 () FINAL OVERRIDE { return this; }
 
   tree get_field () const { return m_field; }
 
-- 
2.26.2

