diff mbox series

[committed] analyzer: fix ICE on casting float to pointer [PR96764]

Message ID 20200831201038.10434-1-dmalcolm@redhat.com
State New
Headers show
Series [committed] analyzer: fix ICE on casting float to pointer [PR96764] | expand

Commit Message

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

gcc/analyzer/ChangeLog:
	PR analyzer/96764
	* region-model-manager.cc
	(region_model_manager::maybe_fold_unaryop): Handle VIEW_CONVERT_EXPR.
	(region_model_manager::get_or_create_cast): Move logic for
	real->integer casting to...
	(get_code_for_cast): ...this new function, and add logic for
	real->non-integer casts.
	(region_model_manager::maybe_fold_sub_svalue): Handle
	VIEW_CONVERT_EXPR.
	* region-model.cc
	(region_model::add_any_constraints_from_gassign): Likewise.
	* svalue.cc (svalue::maybe_undo_cast): Likewise.
	(unaryop_svalue::dump_to_pp): Likewise.

gcc/testsuite/ChangeLog:
	PR analyzer/96764
	* gcc.dg/analyzer/pr96764.c: New test.
---
 gcc/analyzer/region-model-manager.cc    | 35 ++++++++++++++++++++-----
 gcc/analyzer/region-model.cc            |  1 +
 gcc/analyzer/svalue.cc                  | 13 +++++----
 gcc/testsuite/gcc.dg/analyzer/pr96764.c |  6 +++++
 4 files changed, 44 insertions(+), 11 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/pr96764.c
diff mbox series

Patch

diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc
index 9bfb0812998..da8fa01077b 100644
--- a/gcc/analyzer/region-model-manager.cc
+++ b/gcc/analyzer/region-model-manager.cc
@@ -324,6 +324,7 @@  region_model_manager::maybe_fold_unaryop (tree type, enum tree_code op,
   switch (op)
     {
     default: break;
+    case VIEW_CONVERT_EXPR:
     case NOP_EXPR:
       {
 	/* Handle redundant casts.  */
@@ -390,6 +391,30 @@  region_model_manager::get_or_create_unaryop (tree type, enum tree_code op,
   return unaryop_sval;
 }
 
+/* Get a tree code for a cast to DST_TYPE from SRC_TYPE.
+   Use NOP_EXPR if possible (e.g. to help fold_unary convert casts
+   of 0 to (T*) to simple pointer constants), but use FIX_TRUNC_EXPR
+   and VIEW_CONVERT_EXPR for cases that fold_unary would otherwise crash
+   on.  */
+
+static enum tree_code
+get_code_for_cast (tree dst_type, tree src_type)
+{
+  gcc_assert (dst_type);
+  if (!src_type)
+    return NOP_EXPR;
+
+  if (TREE_CODE (src_type) == REAL_TYPE)
+    {
+      if (TREE_CODE (dst_type) == INTEGER_TYPE)
+	return FIX_TRUNC_EXPR;
+      else
+	return VIEW_CONVERT_EXPR;
+    }
+
+  return NOP_EXPR;
+}
+
 /* Return the svalue * for a cast of ARG to type TYPE, creating it
    if necessary.  */
 
@@ -397,11 +422,8 @@  const svalue *
 region_model_manager::get_or_create_cast (tree type, const svalue *arg)
 {
   gcc_assert (type);
-  if (arg->get_type ())
-    if (TREE_CODE (type) == INTEGER_TYPE
-	&& TREE_CODE (arg->get_type ()) == REAL_TYPE)
-      return get_or_create_unaryop (type, FIX_TRUNC_EXPR, arg);
-  return get_or_create_unaryop (type, NOP_EXPR, arg);
+  enum tree_code op = get_code_for_cast (type, arg->get_type ());
+  return get_or_create_unaryop (type, op, arg);
 }
 
 /* Subroutine of region_model_manager::get_or_create_binop.
@@ -561,7 +583,8 @@  region_model_manager::maybe_fold_sub_svalue (tree type,
   if (const unaryop_svalue *unary
       = parent_svalue->dyn_cast_unaryop_svalue ())
     {
-      if (unary->get_op () == NOP_EXPR)
+      if (unary->get_op () == NOP_EXPR
+	  || unary->get_op () == VIEW_CONVERT_EXPR)
 	if (tree cst = unary->get_arg ()->maybe_get_constant ())
 	  if (zerop (cst))
 	    {
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 02bbfa54781..1f794dacc13 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -1764,6 +1764,7 @@  region_model::add_any_constraints_from_gassign (enum tree_code op,
       break;
 
     case NOP_EXPR:
+    case VIEW_CONVERT_EXPR:
       {
 	add_constraint (gimple_assign_rhs1 (assign), op, rhs, ctxt);
       }
diff --git a/gcc/analyzer/svalue.cc b/gcc/analyzer/svalue.cc
index a1c6241a0ba..fcab578674e 100644
--- a/gcc/analyzer/svalue.cc
+++ b/gcc/analyzer/svalue.cc
@@ -128,16 +128,19 @@  svalue::maybe_get_constant () const
     return NULL_TREE;
 }
 
-/* If this svalue is a cast (i.e a unaryop NOP_EXPR), return the underlying
-   svalue.
+/* If this svalue is a cast (i.e a unaryop NOP_EXPR or VIEW_CONVERT_EXPR),
+   return the underlying svalue.
    Otherwise return NULL.  */
 
 const svalue *
 svalue::maybe_undo_cast () const
 {
   if (const unaryop_svalue *unaryop_sval = dyn_cast_unaryop_svalue ())
-    if (unaryop_sval->get_op () == NOP_EXPR)
-      return unaryop_sval->get_arg ();
+    {
+      enum tree_code op = unaryop_sval->get_op ();
+      if (op == NOP_EXPR || op == VIEW_CONVERT_EXPR)
+	return unaryop_sval->get_arg ();
+    }
   return NULL;
 }
 
@@ -566,7 +569,7 @@  unaryop_svalue::dump_to_pp (pretty_printer *pp, bool simple) const
 {
   if (simple)
     {
-      if (m_op == NOP_EXPR)
+      if (m_op == VIEW_CONVERT_EXPR || m_op == NOP_EXPR)
 	{
 	  pp_string (pp, "CAST(");
 	  dump_tree (pp, get_type ());
diff --git a/gcc/testsuite/gcc.dg/analyzer/pr96764.c b/gcc/testsuite/gcc.dg/analyzer/pr96764.c
new file mode 100644
index 00000000000..70b25d3ab81
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/pr96764.c
@@ -0,0 +1,6 @@ 
+void
+ar (int *hd)
+{
+  int **zv = &hd;
+  *(double *) zv = 0.0;
+}