From 9ef4089815fd31632557216012bd1b4d70c1cf41 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 15 May 2020 15:54:06 -0400
Subject: [PATCH 140/377] FIXME: get test_12d to work (field extraction after a
 struct copy)

---
 gcc/analyzer/region-model2.cc                | 22 ++++++++++++--
 gcc/analyzer/region-model2.h                 |  3 +-
 gcc/analyzer/store2.cc                       | 32 ++++++++++++++------
 gcc/analyzer/store2.h                        |  5 +--
 gcc/testsuite/gcc.dg/analyzer/data-model-1.c | 11 ++-----
 5 files changed, 47 insertions(+), 26 deletions(-)

diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc
index 17c8f9a5739..3abc494fb82 100644
--- a/gcc/analyzer/region-model2.cc
+++ b/gcc/analyzer/region-model2.cc
@@ -2871,6 +2871,23 @@ region_model2_manager::maybe_fold_sub_svalue2 (tree type,
 	      return get_or_create_cast (type, char_sval);
 	}
 
+  /* SUB(INIT(r)).FIELD -> INIT(r.FIELD)
+     i.e.
+     Subvalue(InitialValue(R1), FieldRegion(R2, F))
+       -> InitialValue(FieldRegion(R1, F)).  */
+  if (const initial_svalue2 *init_sval
+        = parent_svalue2->dyn_cast_initial_svalue2 ())
+    {
+      if (const field_region2 *field_reg = subregion->dyn_cast_field_region2 ())
+	{
+	  const region2 *field_reg_new
+	    = get_field_region (init_sval->get_region (),
+				field_reg->get_field ());
+	  return get_or_create_initial_value (field_reg_new);
+	}
+    }
+  // TODO: etc similar for element_region
+
   return NULL;
 }
 
@@ -2955,8 +2972,7 @@ region_model2_manager::get_region_for_global (tree expr,
 /* FIXME.  */
 
 const region2 *
-region_model2_manager::get_field_region (const region2 *parent, tree field,
-					 region_model2_context */*ctxt*/)
+region_model2_manager::get_field_region (const region2 *parent, tree field)
 {
   // FIXME: should only alloc_region_id if consolidation fails
   region2 *field_reg = new field_region2 (alloc_region_id (), parent, field);
@@ -4930,7 +4946,7 @@ region_model2::get_lvalue_1 (path_var pv,
 						       dump_location_t ());
 #endif
 	const region2 *obj_reg = get_lvalue (obj, ctxt);
-	return m_mgr->get_field_region (obj_reg, field, ctxt);
+	return m_mgr->get_field_region (obj_reg, field);
       }
       break;
 #if 0
diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h
index 0aee4001d7e..47943b79da2 100644
--- a/gcc/analyzer/region-model2.h
+++ b/gcc/analyzer/region-model2.h
@@ -1579,8 +1579,7 @@ public:
 					     region_model2_context *ctxt);
   const decl_region2 *get_region_for_global (tree expr,
 					     region_model2_context *ctxt);
-  const region2 *get_field_region (const region2 *parent, tree field,
-				   region_model2_context *ctxt);
+  const region2 *get_field_region (const region2 *parent, tree field);
   const region2 *get_element_region (const region2 *parent,
 				     tree element_type,
 				     const svalue2 *index,
diff --git a/gcc/analyzer/store2.cc b/gcc/analyzer/store2.cc
index c588edc40f9..a8d3973644f 100644
--- a/gcc/analyzer/store2.cc
+++ b/gcc/analyzer/store2.cc
@@ -409,21 +409,21 @@ binding_cluster2::get_binding (store2_manager *mgr,
 /* FIXME.  */
 
 const svalue2 *
-binding_cluster2::get_default_binding_recursive (store2_manager *mgr,
-						 const region2 *reg) const
+binding_cluster2::get_binding_recursive (store2_manager *mgr,
+					 const region2 *reg,
+					 enum binding_kind kind) const
 {
-  if (const svalue2 *default_sval
-      = get_binding (mgr, reg, BK_default))
-    return default_sval;
+  if (const svalue2 *sval = get_binding (mgr, reg, kind))
+    return sval;
   if (reg != m_base_region)
     if (const region2 *parent_reg = reg->get_parent_region ())
-      if (const svalue2 *parent_default_sval
-	  = get_default_binding_recursive (mgr, parent_reg))
+      if (const svalue2 *parent_sval
+	  = get_binding_recursive (mgr, parent_reg, kind))
 	{
 	  /* Extract child svalue from parent svalue.  */
 	  region_model2_manager *rmm_mgr = mgr->get_svalue2_manager ();
 	  return rmm_mgr->get_or_create_sub_svalue2 (reg->get_type (),
-						     parent_default_sval, reg);
+						     parent_sval, reg);
 	}
   return NULL;
 }
@@ -434,10 +434,22 @@ const svalue2 *
 binding_cluster2::get_any_binding (store2_manager *mgr,
 				   const region2 *reg) const
 {
+  /* FIXME:  I'm not quite sure how this should work.
+     This looks recursively for matches for a "direct" binding,
+     then for a "default" binding.
+     Doing so gets data-model-1.c: test_12d to work, where we
+     can extract the initial_value of a different struct, then
+     get a field of it.
+     But when should bindings be default, and when should they be direct?
+     The code uses "default" for things that are typically a parent
+     region, and "direct" elsewhere.  */
   if (const svalue2 *direct_sval
-      = get_binding (mgr, reg, BK_direct))
+      = get_binding_recursive (mgr, reg, BK_direct))
     return direct_sval;
-  return get_default_binding_recursive (mgr, reg);
+  if (const svalue2 *default_sval
+      = get_binding_recursive (mgr, reg, BK_default))
+    return default_sval;
+  return NULL;
 }
 
 /* Populate OUT with all bindings within this cluster that overlap REG.  */
diff --git a/gcc/analyzer/store2.h b/gcc/analyzer/store2.h
index 43d148318b6..216f2da9254 100644
--- a/gcc/analyzer/store2.h
+++ b/gcc/analyzer/store2.h
@@ -205,8 +205,9 @@ public:
 
   const svalue2 *get_binding (store2_manager *mgr, const region2 *reg,
 			      binding_kind kind) const;
-  const svalue2 *get_default_binding_recursive (store2_manager *mgr,
-						const region2 *reg) const;
+  const svalue2 *get_binding_recursive (store2_manager *mgr,
+					const region2 *reg,
+					enum binding_kind kind) const;
   const svalue2 *get_any_binding (store2_manager *mgr,
 				  const region2 *reg) const;
 
diff --git a/gcc/testsuite/gcc.dg/analyzer/data-model-1.c b/gcc/testsuite/gcc.dg/analyzer/data-model-1.c
index 47423c3d742..c368ba20e25 100644
--- a/gcc/testsuite/gcc.dg/analyzer/data-model-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/data-model-1.c
@@ -179,15 +179,8 @@ int test_12d (struct coord c)
 {
   struct coord d;
   d = c;
-  __analyzer_eval (d.x == c.x); /* { dg-warning "TRUE" "desired" { xfail *-*-* } } */
-  /* { dg-warning "UNKNOWN" "actual" { target *-*-* } .-1 } */
-  /* TODO(xfail): c and d share the same unknown value of type "coord", but
-     attempts to access the fields lead to different unknown values.  */
-
-  __analyzer_eval (d.y == c.y); /* { dg-warning "TRUE" "desired" { xfail *-*-* } } */
-  /* { dg-warning "UNKNOWN" "actual" { target *-*-* } .-1 } */
-  // TODO(xfail): likewise
-
+  __analyzer_eval (d.x == c.x); /* { dg-warning "TRUE" } */
+  __analyzer_eval (d.y == c.y); /* { dg-warning "TRUE" } */
   __analyzer_eval (d.x == d.y); /* { dg-warning "UNKNOWN" } */
   /* d and c share an unknown value of type "struct coord".
      But d.x and d.y should be different unknown values (although they inherit
-- 
2.26.2

