From 45b6259486e4a1201c630186338e0845ffeab2f5 Mon Sep 17 00:00:00 2001
From: Richard Biener <rguenther@suse.de>
Date: Fri, 4 Apr 2014 11:52:35 +0000
Subject: [PATCH] re PR middle-end/60746 (ICE segfault in gimple-expr.c:314)

2014-04-04  Richard Biener  <rguenther@suse.de>

	PR ipa/60746
	* tree-ssanames.c (make_ssa_name_fn): Fix assert.
	* gimple.c (gimple_set_bb): Avoid ICEing for NULL cfun for
	non-GIMPLE_LABELs.
	* gimplify.h (gimple_add_tmp_var_fn): Declare.
	* gimplify.c (gimple_add_tmp_var_fn): New function.
	* gimple-expr.h (create_tmp_reg_fn): Declare.
	* gimple-expr.c (create_tmp_reg_fn): New function.
	* gimple-low.c (record_vars_into): Don't change cfun.
	* cgraph.c (cgraph_redirect_edge_call_stmt_to_callee): Fix
	code generation without cfun.

	* g++.dg/torture/pr60746.C: New testcase.

From-SVN: r209079
---
 gcc/ChangeLog                          | 14 ++++++++++++++
 gcc/cgraph.c                           | 13 +++++++------
 gcc/gimple-expr.c                      | 18 ++++++++++++++++++
 gcc/gimple-expr.h                      |  1 +
 gcc/gimple-low.c                       | 10 +---------
 gcc/gimple.c                           |  5 ++++-
 gcc/gimplify.c                         | 19 +++++++++++++++++++
 gcc/gimplify.h                         |  1 +
 gcc/testsuite/ChangeLog                |  5 +++++
 gcc/testsuite/g++.dg/torture/pr60746.C | 23 +++++++++++++++++++++++
 gcc/tree-ssanames.c                    |  2 +-
 11 files changed, 94 insertions(+), 17 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/torture/pr60746.C

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5a25f784dd79..4dc3a9ea7f71 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,17 @@
+2014-04-04  Richard Biener  <rguenther@suse.de>
+
+	PR ipa/60746
+	* tree-ssanames.c (make_ssa_name_fn): Fix assert.
+	* gimple.c (gimple_set_bb): Avoid ICEing for NULL cfun for
+	non-GIMPLE_LABELs.
+	* gimplify.h (gimple_add_tmp_var_fn): Declare.
+	* gimplify.c (gimple_add_tmp_var_fn): New function.
+	* gimple-expr.h (create_tmp_reg_fn): Declare.
+	* gimple-expr.c (create_tmp_reg_fn): New function.
+	* gimple-low.c (record_vars_into): Don't change cfun.
+	* cgraph.c (cgraph_redirect_edge_call_stmt_to_callee): Fix
+	code generation without cfun.
+
 2014-04-04  Thomas Schwinge  <thomas@codesourcery.com>
 
 	PR bootstrap/60719
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index dcab9848307e..281ad6326b51 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -1479,13 +1479,14 @@ cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *e)
     {
       if (TREE_CODE (lhs) == SSA_NAME)
 	{
+	  tree var = create_tmp_reg_fn (DECL_STRUCT_FUNCTION (e->caller->decl),
+					TREE_TYPE (lhs), NULL);
+	  var = get_or_create_ssa_default_def
+		  (DECL_STRUCT_FUNCTION (e->caller->decl), var);
+	  gimple set_stmt = gimple_build_assign (lhs, var);
           gsi = gsi_for_stmt (new_stmt);
-
-	  tree var = create_tmp_var (TREE_TYPE (lhs), NULL);
-	  tree def = get_or_create_ssa_default_def
-		      (DECL_STRUCT_FUNCTION (e->caller->decl), var);
-	  gimple set_stmt = gimple_build_assign (lhs, def);
-	  gsi_insert_before (&gsi, set_stmt, GSI_SAME_STMT);
+	  gsi_insert_before_without_update (&gsi, set_stmt, GSI_SAME_STMT);
+	  update_stmt_fn (DECL_STRUCT_FUNCTION (e->caller->decl), set_stmt);
 	}
       gimple_call_set_lhs (new_stmt, NULL_TREE);
       update_stmt_fn (DECL_STRUCT_FUNCTION (e->caller->decl), new_stmt);
diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c
index 2c4da474eff7..da663d6fb799 100644
--- a/gcc/gimple-expr.c
+++ b/gcc/gimple-expr.c
@@ -527,6 +527,24 @@ create_tmp_reg (tree type, const char *prefix)
   return tmp;
 }
 
+/* Create a new temporary variable declaration of type TYPE by calling
+   create_tmp_var and if TYPE is a vector or a complex number, mark the new
+   temporary as gimple register.  */
+
+tree
+create_tmp_reg_fn (struct function *fn, tree type, const char *prefix)
+{
+  tree tmp;
+
+  tmp = create_tmp_var_raw (type, prefix);
+  gimple_add_tmp_var_fn (fn, tmp);
+  if (TREE_CODE (type) == COMPLEX_TYPE
+      || TREE_CODE (type) == VECTOR_TYPE)
+    DECL_GIMPLE_REG_P (tmp) = 1;
+
+  return tmp;
+}
+
 
 /* ----- Expression related -----  */
 
diff --git a/gcc/gimple-expr.h b/gcc/gimple-expr.h
index ed8e338beca0..3b6cda8441b1 100644
--- a/gcc/gimple-expr.h
+++ b/gcc/gimple-expr.h
@@ -33,6 +33,7 @@ extern tree create_tmp_var_name (const char *);
 extern tree create_tmp_var_raw (tree, const char *);
 extern tree create_tmp_var (tree, const char *);
 extern tree create_tmp_reg (tree, const char *);
+extern tree create_tmp_reg_fn (struct function *, tree, const char *);
 
 
 extern void extract_ops_from_tree_1 (tree, enum tree_code *, tree *, tree *,
diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c
index 80fd786fddeb..da3fb9fb35eb 100644
--- a/gcc/gimple-low.c
+++ b/gcc/gimple-low.c
@@ -841,11 +841,6 @@ lower_builtin_posix_memalign (gimple_stmt_iterator *gsi)
 void
 record_vars_into (tree vars, tree fn)
 {
-  bool change_cfun = fn != current_function_decl;
-
-  if (change_cfun)
-    push_cfun (DECL_STRUCT_FUNCTION (fn));
-
   for (; vars; vars = DECL_CHAIN (vars))
     {
       tree var = vars;
@@ -860,11 +855,8 @@ record_vars_into (tree vars, tree fn)
 	continue;
 
       /* Record the variable.  */
-      add_local_decl (cfun, var);
+      add_local_decl (DECL_STRUCT_FUNCTION (fn), var);
     }
-
-  if (change_cfun)
-    pop_cfun ();
 }
 
 
diff --git a/gcc/gimple.c b/gcc/gimple.c
index e9851ca386a2..2a278e41e9df 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -1464,9 +1464,12 @@ gimple_set_bb (gimple stmt, basic_block bb)
 {
   stmt->bb = bb;
 
+  if (gimple_code (stmt) != GIMPLE_LABEL)
+    return;
+
   /* If the statement is a label, add the label to block-to-labels map
      so that we can speed up edge creation for GIMPLE_GOTOs.  */
-  if (cfun->cfg && gimple_code (stmt) == GIMPLE_LABEL)
+  if (cfun->cfg)
     {
       tree t;
       int uid;
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index ad2178dd914c..744178420ab7 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -626,6 +626,25 @@ force_constant_size (tree var)
 
 /* Push the temporary variable TMP into the current binding.  */
 
+void
+gimple_add_tmp_var_fn (struct function *fn, tree tmp)
+{
+  gcc_assert (!DECL_CHAIN (tmp) && !DECL_SEEN_IN_BIND_EXPR_P (tmp));
+
+  /* Later processing assumes that the object size is constant, which might
+     not be true at this point.  Force the use of a constant upper bound in
+     this case.  */
+  if (!tree_fits_uhwi_p (DECL_SIZE_UNIT (tmp)))
+    force_constant_size (tmp);
+
+  DECL_CONTEXT (tmp) = fn->decl;
+  DECL_SEEN_IN_BIND_EXPR_P (tmp) = 1;
+
+  record_vars_into (tmp, fn->decl);
+}
+
+/* Push the temporary variable TMP into the current binding.  */
+
 void
 gimple_add_tmp_var (tree tmp)
 {
diff --git a/gcc/gimplify.h b/gcc/gimplify.h
index 6bc0057c30e9..47e72130add6 100644
--- a/gcc/gimplify.h
+++ b/gcc/gimplify.h
@@ -60,6 +60,7 @@ extern tree get_formal_tmp_var (tree, gimple_seq *);
 extern tree get_initialized_tmp_var (tree, gimple_seq *, gimple_seq *);
 extern void declare_vars (tree, gimple, bool);
 extern void gimple_add_tmp_var (tree);
+extern void gimple_add_tmp_var_fn (struct function *, tree);
 extern tree unshare_expr (tree);
 extern tree unshare_expr_without_location (tree);
 extern tree voidify_wrapper_expr (tree, tree);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 0446485dfb88..3c64a2bf96b8 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2014-04-04  Richard Biener  <rguenther@suse.de>
+
+	PR ipa/60746
+	* g++.dg/torture/pr60746.C: New testcase.
+
 2014-04-04  Fabien Chêne  <fabien@gcc.gnu.org>
 
 	* g++.old-deja/g++.robertl/eb121.C: Adjust.
diff --git a/gcc/testsuite/g++.dg/torture/pr60746.C b/gcc/testsuite/g++.dg/torture/pr60746.C
new file mode 100644
index 000000000000..7ce6ebe6bc0d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr60746.C
@@ -0,0 +1,23 @@
+// { dg-do compile }
+
+class One
+{
+public:
+  virtual unsigned long getSize () const;
+};
+
+class Two
+{
+  virtual int run ();
+};
+
+int
+Two::run ()
+{
+  One list_arry[5][2];
+  int orig = 0;
+  if (list_arry[3][orig].getSize () > 0
+      || list_arry[4][orig].getSize () > 0)
+    {
+    }
+}
diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c
index 2fc822081c8d..2b535a1fef0e 100644
--- a/gcc/tree-ssanames.c
+++ b/gcc/tree-ssanames.c
@@ -144,7 +144,7 @@ make_ssa_name_fn (struct function *fn, tree var, gimple stmt)
 
       /* The node was cleared out when we put it on the free list, so
 	 there is no need to do so again here.  */
-      gcc_assert (ssa_name (SSA_NAME_VERSION (t)) == NULL);
+      gcc_assert ((*SSANAMES (fn))[SSA_NAME_VERSION (t)] == NULL);
       (*SSANAMES (fn))[SSA_NAME_VERSION (t)] = t;
     }
   else
-- 
GitLab