From 96295b8d920bfbbb713382e5670a32fa44b27f94 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 4 Jun 2020 11:40:14 -0400
Subject: [PATCH 198/315] FIXME: use get_subregions_for_binding

---
 gcc/analyzer/region-model2.cc                 | 65 +++++++++++++++----
 gcc/analyzer/store2.cc                        | 19 ++++++
 gcc/testsuite/gcc.dg/analyzer/data-model-13.c |  3 +-
 gcc/testsuite/gcc.dg/analyzer/dot-output.c    |  3 +-
 gcc/testsuite/gcc.dg/analyzer/loop-3.c        |  6 +-
 5 files changed, 78 insertions(+), 18 deletions(-)

diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc
index 3fcdb62bf2f..3ca6d0bfeac 100644
--- a/gcc/analyzer/region-model2.cc
+++ b/gcc/analyzer/region-model2.cc
@@ -1109,13 +1109,20 @@ region2::get_subregions_for_binding (region_model2_manager *mgr,
       break;
     case UNION_TYPE:
       {
-	gcc_unreachable (); // TODO
+	for (tree field = TYPE_FIELDS (get_type ()); field != NULL_TREE;
+	     field = DECL_CHAIN (field))
+	  {
+	    const region2 *subregion = mgr->get_field_region (this, field);
+	    subregion->get_subregions_for_binding (mgr,
+						   relative_bit_offset,
+						   size_in_bits,
+						   type,
+						   out);
+	  }
       }
       break;
     default:
-      {
-	gcc_unreachable (); // TODO
-      }
+      /* Do nothing FIXME.  */
       break;
     }
 }
@@ -3035,6 +3042,7 @@ region_model2_manager::maybe_fold_binop (tree type, enum tree_code op,
     {
     default:
       break;
+    case POINTER_PLUS_EXPR:
     case PLUS_EXPR:
       /* (VAL + 0) -> VAL.  */
       if (cst1 && zerop (cst1) && type == arg0->get_type ())
@@ -3094,6 +3102,19 @@ region_model2_manager::maybe_fold_binop (tree type, enum tree_code op,
 	   get_or_create_binop (type, op,
 				binop->get_arg1 (), arg1));
 
+  /* FIXME.  pointer_plus_expr on pointer_plus_expr...
+     associative_tree_code is false for POINTER_PLUS_EXPR.  */
+  /* e.g. in data-model-1.c: test_42c.  */
+  if (cst1 && op == POINTER_PLUS_EXPR)
+    if (const binop_svalue2 *binop = arg0->dyn_cast_binop_svalue2 ())
+      if (binop->get_op () == POINTER_PLUS_EXPR)
+	if (tree cst01 = binop->get_arg1 ()->maybe_get_constant ())
+	  if (TREE_TYPE (cst01) == TREE_TYPE (cst1))
+	    return get_or_create_binop
+	      (type, op, binop->get_arg0 (),
+	       get_or_create_binop (type, op,
+				    binop->get_arg1 (), arg1));
+
   // TODO
 
   return NULL;
@@ -8180,11 +8201,8 @@ test_get_representative_tree ()
 			 a, int_3, NULL_TREE, NULL_TREE);
       const region2 *a_3_reg = model.get_lvalue (a_3, &ctxt);
       model.set_value (a_3_reg, &test_sval, &ctxt);
-#if 0
       tree rep = model.get_representative_tree (&test_sval);
-      // TODO: this currently ICEs
       ASSERT_DUMP_TREE_EQ (rep, "a[3]");
-#endif
     }
 
     /* Value of a[0].  */
@@ -8197,16 +8215,41 @@ test_get_representative_tree ()
       const region2 *a_0_reg = model.get_lvalue (a_0, &ctxt);
       model.set_value (a_0_reg, &test_sval, &ctxt);
       tree rep = model.get_representative_tree (&test_sval);
-#if 0
-      // TODO: this currently gets just "a", rather than "a[0]":
       ASSERT_DUMP_TREE_EQ (rep, "a[0]");
-#endif
     }
   }
 
   /* Value of a field within a struct.  */
   {
-    // TODO: initial vs non-initial
+    coord_test2 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);
+
+    test_region_model2_context ctxt;
+
+    /* Value of initial field.  */
+    {
+      region_model2 m (&mgr);
+      const region2 *c_x_reg = m.get_lvalue (c_x, &ctxt);
+      placeholder_svalue2 test_sval_x (integer_type_node, "test x val");
+      m.set_value (c_x_reg, &test_sval_x, &ctxt);
+      tree rep = m.get_representative_tree (&test_sval_x);
+      ASSERT_DUMP_TREE_EQ (rep, "c.x");
+    }
+
+    /* Value of non-initial field.  */
+    {
+      region_model2 m (&mgr);
+      const region2 *c_y_reg = m.get_lvalue (c_y, &ctxt);
+      placeholder_svalue2 test_sval_y (integer_type_node, "test y val");
+      m.set_value (c_y_reg, &test_sval_y, &ctxt);
+      tree rep = m.get_representative_tree (&test_sval_y);
+      ASSERT_DUMP_TREE_EQ (rep, "c.y");
+    }
   }
 
   /* Value of a field within a union.  */
diff --git a/gcc/analyzer/store2.cc b/gcc/analyzer/store2.cc
index 685993b2de2..3afe1a40b64 100644
--- a/gcc/analyzer/store2.cc
+++ b/gcc/analyzer/store2.cc
@@ -704,6 +704,24 @@ binding_cluster2::get_representative_path_vars (const region_model2 *model,
 	  if (const concrete_binding2 *ckey
 		= key->dyn_cast_concrete_binding2 ())
 	    {
+#if 1
+	      auto_vec <const region2 *> subregions;
+	      base_reg->get_subregions_for_binding
+		(model->get_manager (),
+		 ckey->get_start_bit_offset (),
+		 ckey->get_size_in_bits (),
+		 sval->get_type (),
+		 &subregions);
+	      unsigned i;
+	      const region2 *subregion;
+	      FOR_EACH_VEC_ELT (subregions, i, subregion)
+		{
+		  if (path_var pv
+		      = model->get_representative_path_var (subregion,
+							    visited))
+		    out_pvs->safe_push (pv);
+		}
+#else
 	      // FIXME: support fields etc
 	      // TODO: check size as well
 	      if (ckey->get_start_bit_offset () == 0)
@@ -716,6 +734,7 @@ binding_cluster2::get_representative_path_vars (const region_model2 *model,
 		}
 	      else
 		gcc_unreachable ();
+#endif
 	    }
 	  else
 	    {
diff --git a/gcc/testsuite/gcc.dg/analyzer/data-model-13.c b/gcc/testsuite/gcc.dg/analyzer/data-model-13.c
index 69be534144d..31c1896b0c2 100644
--- a/gcc/testsuite/gcc.dg/analyzer/data-model-13.c
+++ b/gcc/testsuite/gcc.dg/analyzer/data-model-13.c
@@ -14,6 +14,5 @@ void test_1 (void)
 void test_2 (void)
 {
   global_union.ptr_val = malloc (1024); /* { dg-message "allocated here" } */
-  global_union.int_val = 0; /* { dg-warning "leak of 'global_union' " } */
+  global_union.int_val = 0; /* { dg-warning "leak of 'global_union.ptr_val' " } */
 } 
-/* TODO: 'global_union.ptr_val' would be better than just 'global_union'.  */
diff --git a/gcc/testsuite/gcc.dg/analyzer/dot-output.c b/gcc/testsuite/gcc.dg/analyzer/dot-output.c
index 7b69c626f4e..ff418b156c0 100644
--- a/gcc/testsuite/gcc.dg/analyzer/dot-output.c
+++ b/gcc/testsuite/gcc.dg/analyzer/dot-output.c
@@ -18,8 +18,7 @@ int *test (int *buf, int n, int *out)
   
   /* A loop, to ensure we have phi nodes.  */
   for (i = 0; i < n; i++)
-    result[i] = buf[i] + i; /* { dg-warning "possibly-NULL" "" { xfail *-*-* } } */
-  /* TODO(xfail): why isn't the warning appearing? */
+    result[i] = buf[i] + i; /* { dg-warning "possibly-NULL" } */
 
   /* Example of a "'" (to test quoting).  */
   *out = some_call (i, 'a');
diff --git a/gcc/testsuite/gcc.dg/analyzer/loop-3.c b/gcc/testsuite/gcc.dg/analyzer/loop-3.c
index 1d01771d7cb..191b4d8dc85 100644
--- a/gcc/testsuite/gcc.dg/analyzer/loop-3.c
+++ b/gcc/testsuite/gcc.dg/analyzer/loop-3.c
@@ -6,9 +6,9 @@ void test(int c)
   char *buffer = (char*)malloc(256);
 
   for (i=0; i<255; i++) {
-    buffer[i] = c; /* { dg-warning "use after 'free' of 'buffer'" } */
-		   /* BUG: the malloc could have failed
-		      TODO: the checker doesn't yet pick up on this, perhaps
+    buffer[i] = c; /* { dg-warning "use after 'free' of 'buffer'" "use after free" } */
+                   /* { dg-warning "possibly-NULL 'buffer'" "deref of unchecked" { target *-*-* } .-1 } */
+		   /* TODO: fix up; keeping these lines to avoid fouling my result diffs
 		      due to the pointer arithmetic not picking up on the
 		      state */
     free(buffer); /* { dg-warning "double-'free' of 'buffer'" } */
-- 
2.26.2

