diff mbox series

[committed] analyzer: fix ICE on RANGE_EXPR in CONSTRUCTORs [PR96763]

Message ID 20200831201137.10691-1-dmalcolm@redhat.com
State New
Headers show
Series [committed] analyzer: fix ICE on RANGE_EXPR in CONSTRUCTORs [PR96763] | expand

Commit Message

David Malcolm Aug. 31, 2020, 8:11 p.m. UTC
Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
Pushed to master as r11-2953-g0d1b4edc5fff834e8f924b20dd021ded7a21d2d2.

gcc/analyzer/ChangeLog:
	PR analyzer/96763
	* store.cc (binding_map::apply_ctor_to_region): Handle RANGE_EXPR
	by calling a new binding_map::apply_ctor_val_to_range subroutine.
	Split out the existing non-CONSTRUCTOR-handling code to a new
	apply_ctor_pair_to_child_region subroutine.
	(binding_map::apply_ctor_val_to_range): New.
	(binding_map::apply_ctor_pair_to_child_region): New, split out
	from binding_map::apply_ctor_to_region as noted above.
	* store.h (binding_map::apply_ctor_val_to_range): New decl.
	(binding_map::apply_ctor_pair_to_child_region): New decl.

gcc/testsuite/ChangeLog:
	PR analyzer/96763
	* g++.dg/analyzer/pr96763.C: New test.
---
 gcc/analyzer/store.cc                   | 129 +++++++++++++++++-------
 gcc/analyzer/store.h                    |   8 ++
 gcc/testsuite/g++.dg/analyzer/pr96763.C |  13 +++
 3 files changed, 115 insertions(+), 35 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/analyzer/pr96763.C
diff mbox series

Patch

diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc
index 14f7c00bde6..8890a69a6f8 100644
--- a/gcc/analyzer/store.cc
+++ b/gcc/analyzer/store.cc
@@ -419,43 +419,102 @@  binding_map::apply_ctor_to_region (const region *parent_reg, tree ctor,
     {
       if (!index)
 	index = build_int_cst (integer_type_node, ix);
-      const region *child_reg
-	= get_subregion_within_ctor (parent_reg, index, mgr);
-      if (TREE_CODE (val) == CONSTRUCTOR)
-	apply_ctor_to_region (child_reg, val, mgr);
-      else
+      else if (TREE_CODE (index) == RANGE_EXPR)
 	{
-	  const svalue *sval = get_svalue_for_ctor_val (val, mgr);
-	  const binding_key *k
-	    = binding_key::make (mgr->get_store_manager (), child_reg,
-				 BK_direct);
-	  /* Handle the case where we have an unknown size for child_reg
-	     (e.g. due to it being a trailing field with incomplete array
-	     type.  */
-	  if (!k->concrete_p ())
-	    {
-	      /* Assume that sval has a well-defined size for this case.  */
-	      tree sval_type = sval->get_type ();
-	      gcc_assert (sval_type);
-	      HOST_WIDE_INT sval_byte_size = int_size_in_bytes (sval_type);
-	      gcc_assert (sval_byte_size != -1);
-	      bit_size_t sval_bit_size = sval_byte_size * BITS_PER_UNIT;
-	      /* Get offset of child relative to base region.  */
-	      region_offset child_base_offset = child_reg->get_offset ();
-	      gcc_assert (!child_base_offset.symbolic_p ());
-	      /* Convert to an offset relative to the parent region.  */
-	      region_offset parent_base_offset = parent_reg->get_offset ();
-	      gcc_assert (!parent_base_offset.symbolic_p ());
-	      bit_offset_t child_parent_offset
-		= (child_base_offset.get_bit_offset ()
-		   - parent_base_offset.get_bit_offset ());
-	      /* Create a concrete key for the child within the parent.  */
-	      k = mgr->get_store_manager ()->get_concrete_binding
-		(child_parent_offset, sval_bit_size, BK_direct);
-	    }
-	  gcc_assert (k->concrete_p ());
-	  put (k, sval);
+	  tree min_index = TREE_OPERAND (index, 0);
+	  tree max_index = TREE_OPERAND (index, 1);
+	  apply_ctor_val_to_range (parent_reg, mgr, min_index, max_index, val);
+	  continue;
+	}
+      apply_ctor_pair_to_child_region (parent_reg, mgr, index, val);
+    }
+}
+
+/* Bind the value VAL into the range of elements within PARENT_REF
+   from MIN_INDEX to MAX_INDEX (including endpoints).
+   For use in handling RANGE_EXPR within a CONSTRUCTOR.  */
+
+void
+binding_map::apply_ctor_val_to_range (const region *parent_reg,
+				      region_model_manager *mgr,
+				      tree min_index, tree max_index,
+				      tree val)
+{
+  gcc_assert (TREE_CODE (min_index) == INTEGER_CST);
+  gcc_assert (TREE_CODE (max_index) == INTEGER_CST);
+
+  /* Generate a binding key for the range.  */
+  const region *min_element
+    = get_subregion_within_ctor (parent_reg, min_index, mgr);
+  const region *max_element
+    = get_subregion_within_ctor (parent_reg, max_index, mgr);
+  region_offset min_offset = min_element->get_offset ();
+  bit_offset_t start_bit_offset = min_offset.get_bit_offset ();
+  store_manager *smgr = mgr->get_store_manager ();
+  const binding_key *max_element_key
+    = binding_key::make (smgr, max_element, BK_direct);
+  gcc_assert (max_element_key->concrete_p ());
+  const concrete_binding *max_element_ckey
+    = max_element_key->dyn_cast_concrete_binding ();
+  bit_size_t range_size_in_bits
+    = max_element_ckey->get_next_bit_offset () - start_bit_offset;
+  const concrete_binding *range_key
+    = smgr->get_concrete_binding (start_bit_offset, range_size_in_bits,
+				  BK_direct);
+  gcc_assert (range_key->concrete_p ());
+
+  /* Get the value.  */
+  gcc_assert (TREE_CODE (val) != CONSTRUCTOR);
+  const svalue *sval = get_svalue_for_ctor_val (val, mgr);
+
+  /* Bind the value to the range.  */
+  put (range_key, sval);
+}
+
+/* Bind the value VAL into INDEX within PARENT_REF.
+   For use in handling a pair of entries within a CONSTRUCTOR.  */
+
+void
+binding_map::apply_ctor_pair_to_child_region (const region *parent_reg,
+					      region_model_manager *mgr,
+					      tree index, tree val)
+{
+  const region *child_reg
+    = get_subregion_within_ctor (parent_reg, index, mgr);
+  if (TREE_CODE (val) == CONSTRUCTOR)
+    apply_ctor_to_region (child_reg, val, mgr);
+  else
+    {
+      const svalue *sval = get_svalue_for_ctor_val (val, mgr);
+      const binding_key *k
+	= binding_key::make (mgr->get_store_manager (), child_reg,
+			     BK_direct);
+      /* Handle the case where we have an unknown size for child_reg
+	 (e.g. due to it being a trailing field with incomplete array
+	 type.  */
+      if (!k->concrete_p ())
+	{
+	  /* Assume that sval has a well-defined size for this case.  */
+	  tree sval_type = sval->get_type ();
+	  gcc_assert (sval_type);
+	  HOST_WIDE_INT sval_byte_size = int_size_in_bytes (sval_type);
+	  gcc_assert (sval_byte_size != -1);
+	  bit_size_t sval_bit_size = sval_byte_size * BITS_PER_UNIT;
+	  /* Get offset of child relative to base region.  */
+	  region_offset child_base_offset = child_reg->get_offset ();
+	  gcc_assert (!child_base_offset.symbolic_p ());
+	  /* Convert to an offset relative to the parent region.  */
+	  region_offset parent_base_offset = parent_reg->get_offset ();
+	  gcc_assert (!parent_base_offset.symbolic_p ());
+	  bit_offset_t child_parent_offset
+	    = (child_base_offset.get_bit_offset ()
+	       - parent_base_offset.get_bit_offset ());
+	  /* Create a concrete key for the child within the parent.  */
+	  k = mgr->get_store_manager ()->get_concrete_binding
+	    (child_parent_offset, sval_bit_size, BK_direct);
 	}
+      gcc_assert (k->concrete_p ());
+      put (k, sval);
     }
 }
 
diff --git a/gcc/analyzer/store.h b/gcc/analyzer/store.h
index 636a9547f2c..0ac93179dc6 100644
--- a/gcc/analyzer/store.h
+++ b/gcc/analyzer/store.h
@@ -344,6 +344,14 @@  public:
 			     region_model_manager *mgr);
 
 private:
+  void apply_ctor_val_to_range (const region *parent_reg,
+				region_model_manager *mgr,
+				tree min_index, tree max_index,
+				tree val);
+  void apply_ctor_pair_to_child_region (const region *parent_reg,
+					region_model_manager *mgr,
+					tree index, tree val);
+
   map_t m_map;
 };
 
diff --git a/gcc/testsuite/g++.dg/analyzer/pr96763.C b/gcc/testsuite/g++.dg/analyzer/pr96763.C
new file mode 100644
index 00000000000..1b29e30a8f8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/pr96763.C
@@ -0,0 +1,13 @@ 
+// { dg-do compile { target c++11 } }
+
+struct c0;
+
+struct md {
+  int c0::*jj[2];
+};
+
+void
+n0 ()
+{
+  md{};
+}