diff mbox

C++ PATCHes to build_vec_init for c++/61994

Message ID 53E2D8E8.9060000@redhat.com
State New
Headers show

Commit Message

Jason Merrill Aug. 7, 2014, 1:39 a.m. UTC
The first patch is a simple fix for the testcase in 61994: if we build 
an INIT_EXPR, it should have array type, not pointer type.

But looking at that bug, I noticed a wrong-code bug as well: in cases 
like the testcase in 61994 where all the initializers are constant, we 
were failing to initialize trailing elements (with no explicit 
initializer) in cases where value-initialization is different from 
zero-initialization.  Oops.  So the second patch fixes that.

Tested x86_64-pc-linux-gnu, applying to trunk.
diff mbox

Patch

commit f1e0c6432cef81f723a74436b9a3d716dcc739eb
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Aug 6 17:00:25 2014 -0400

    	* init.c (build_vec_init): Fix constant initialization of
    	trailing elements.
    	(build_value_init_noctor): Call maybe_constant_init.
    	* semantics.c (maybe_constant_init): Seee through EXPR_STMT and
    	conversion to void.

diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 777e0a9..f0ca9b9 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -419,12 +419,18 @@  build_value_init_noctor (tree type, tsubst_flags_t complain)
 		 over TYPE_FIELDs will result in correct initialization of
 		 all of the subobjects.  */
 	      value = build_value_init (ftype, complain);
+	      value = maybe_constant_init (value);
 
 	      if (value == error_mark_node)
 		return error_mark_node;
 
-	      if (value)
-		CONSTRUCTOR_APPEND_ELT(v, field, value);
+	      CONSTRUCTOR_APPEND_ELT(v, field, value);
+
+	      /* We shouldn't have gotten here for anything that would need
+		 non-trivial initialization, and gimplify_init_ctor_preeval
+		 would need to be fixed to allow it.  */
+	      gcc_assert (TREE_CODE (value) != TARGET_EXPR
+			  && TREE_CODE (value) != AGGR_INIT_EXPR);
 	    }
 
 	  /* Build a constructor to contain the zero- initializations.  */
@@ -462,20 +468,18 @@  build_value_init_noctor (tree type, tsubst_flags_t complain)
 	    ce.index = build2 (RANGE_EXPR, sizetype, size_zero_node, max_index);
 
 	  ce.value = build_value_init (TREE_TYPE (type), complain);
-	  if (ce.value)
-	    {
-	      if (ce.value == error_mark_node)
-		return error_mark_node;
+	  ce.value = maybe_constant_init (ce.value);
+	  if (ce.value == error_mark_node)
+	    return error_mark_node;
 
-	      vec_alloc (v, 1);
-	      v->quick_push (ce);
+	  vec_alloc (v, 1);
+	  v->quick_push (ce);
 
-	      /* We shouldn't have gotten here for anything that would need
-		 non-trivial initialization, and gimplify_init_ctor_preeval
-		 would need to be fixed to allow it.  */
-	      gcc_assert (TREE_CODE (ce.value) != TARGET_EXPR
-			  && TREE_CODE (ce.value) != AGGR_INIT_EXPR);
-	    }
+	  /* We shouldn't have gotten here for anything that would need
+	     non-trivial initialization, and gimplify_init_ctor_preeval
+	     would need to be fixed to allow it.  */
+	  gcc_assert (TREE_CODE (ce.value) != TARGET_EXPR
+		      && TREE_CODE (ce.value) != AGGR_INIT_EXPR);
 	}
 
       /* Build a constructor to contain the initializations.  */
@@ -3412,7 +3416,6 @@  build_vec_init (tree base, tree maxindex, tree init,
   tree try_block = NULL_TREE;
   int num_initialized_elts = 0;
   bool is_global;
-  tree const_init = NULL_TREE;
   tree obase = base;
   bool xvalue = false;
   bool errors = false;
@@ -3545,6 +3548,19 @@  build_vec_init (tree base, tree maxindex, tree init,
       try_block = begin_try_block ();
     }
 
+  /* Should we try to create a constant initializer?  */
+  bool try_const = (TREE_CODE (atype) == ARRAY_TYPE
+		    && TREE_CONSTANT (maxindex)
+		    && init && TREE_CODE (init) == CONSTRUCTOR
+		    && (literal_type_p (inner_elt_type)
+			|| TYPE_HAS_CONSTEXPR_CTOR (inner_elt_type)));
+  vec<constructor_elt, va_gc> *const_vec = NULL;
+  bool saw_non_const = false;
+  /* If we're initializing a static array, we want to do static
+     initialization of any elements with constant initializers even if
+     some are non-constant.  */
+  bool do_static_init = (DECL_P (obase) && TREE_STATIC (obase));
+
   bool empty_list = false;
   if (init && BRACE_ENCLOSED_INITIALIZER_P (init)
       && CONSTRUCTOR_NELTS (init) == 0)
@@ -3559,21 +3575,9 @@  build_vec_init (tree base, tree maxindex, tree init,
 	 brace-enclosed initializers.  */
       unsigned HOST_WIDE_INT idx;
       tree field, elt;
-      /* Should we try to create a constant initializer?  */
-      bool try_const = (TREE_CODE (atype) == ARRAY_TYPE
-			&& TREE_CONSTANT (maxindex)
-			&& (literal_type_p (inner_elt_type)
-			    || TYPE_HAS_CONSTEXPR_CTOR (inner_elt_type)));
       /* If the constructor already has the array type, it's been through
 	 digest_init, so we shouldn't try to do anything more.  */
       bool digested = same_type_p (atype, TREE_TYPE (init));
-      bool saw_non_const = false;
-      bool saw_const = false;
-      /* If we're initializing a static array, we want to do static
-	 initialization of any elements with constant initializers even if
-	 some are non-constant.  */
-      bool do_static_init = (DECL_P (obase) && TREE_STATIC (obase));
-      vec<constructor_elt, va_gc> *new_vec;
       from_array = 0;
 
       if (length_check)
@@ -3589,9 +3593,7 @@  build_vec_init (tree base, tree maxindex, tree init,
 	}
 
       if (try_const)
-	vec_alloc (new_vec, CONSTRUCTOR_NELTS (init));
-      else
-	new_vec = NULL;
+	vec_alloc (const_vec, CONSTRUCTOR_NELTS (init));
 
       FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), idx, field, elt)
 	{
@@ -3612,21 +3614,14 @@  build_vec_init (tree base, tree maxindex, tree init,
 	    errors = true;
 	  if (try_const)
 	    {
-	      tree e = one_init;
-	      if (TREE_CODE (e) == EXPR_STMT)
-		e = TREE_OPERAND (e, 0);
-	      if (TREE_CODE (e) == CONVERT_EXPR
-		  && VOID_TYPE_P (TREE_TYPE (e)))
-		e = TREE_OPERAND (e, 0);
-	      e = maybe_constant_init (e);
+	      tree e = maybe_constant_init (one_init);
 	      if (reduced_constant_expression_p (e))
 		{
-		  CONSTRUCTOR_APPEND_ELT (new_vec, field, e);
+		  CONSTRUCTOR_APPEND_ELT (const_vec, field, e);
 		  if (do_static_init)
 		    one_init = NULL_TREE;
 		  else
 		    one_init = build2 (INIT_EXPR, type, baseref, e);
-		  saw_const = true;
 		}
 	      else
 		{
@@ -3635,7 +3630,7 @@  build_vec_init (tree base, tree maxindex, tree init,
 		      tree value = build_zero_init (TREE_TYPE (e), NULL_TREE,
 						    true);
 		      if (value)
-			CONSTRUCTOR_APPEND_ELT (new_vec, field, value);
+			CONSTRUCTOR_APPEND_ELT (const_vec, field, value);
 		    }
 		  saw_non_const = true;
 		}
@@ -3659,16 +3654,6 @@  build_vec_init (tree base, tree maxindex, tree init,
 	    finish_expr_stmt (one_init);
 	}
 
-      if (try_const)
-	{
-	  if (!saw_non_const)
-	    const_init = build_constructor (atype, new_vec);
-	  else if (do_static_init && saw_const)
-	    DECL_INITIAL (obase) = build_constructor (atype, new_vec);
-	  else
-	    vec_free (new_vec);
-	}
-
       /* Any elements without explicit initializers get T{}.  */
       empty_list = true;
     }
@@ -3793,8 +3778,38 @@  build_vec_init (tree base, tree maxindex, tree init,
       if (elt_init == error_mark_node)
 	errors = true;
 
+      if (try_const)
+	{
+	  tree e = maybe_constant_init (elt_init);
+	  if (reduced_constant_expression_p (e))
+	    {
+	      if (initializer_zerop (e))
+		/* Don't fill the CONSTRUCTOR with zeros.  */
+		e = NULL_TREE;
+	      if (do_static_init)
+		elt_init = NULL_TREE;
+	    }
+	  else
+	    {
+	      saw_non_const = true;
+	      if (do_static_init)
+		e = build_zero_init (TREE_TYPE (e), NULL_TREE, true);
+	    }
+
+	  if (e)
+	    {
+	      int max = tree_to_shwi (maxindex)+1;
+	      for (; num_initialized_elts < max; ++num_initialized_elts)
+		{
+		  tree field = size_int (num_initialized_elts);
+		  CONSTRUCTOR_APPEND_ELT (const_vec, field, e);
+		}
+	    }
+	}
+
       current_stmt_tree ()->stmts_are_full_exprs_p = 1;
-      finish_expr_stmt (elt_init);
+      if (elt_init)
+	finish_expr_stmt (elt_init);
       current_stmt_tree ()->stmts_are_full_exprs_p = 0;
 
       finish_expr_stmt (cp_build_unary_op (PREINCREMENT_EXPR, base, 0,
@@ -3844,8 +3859,19 @@  build_vec_init (tree base, tree maxindex, tree init,
 
   if (errors)
     return error_mark_node;
-  if (const_init)
-    return build2 (INIT_EXPR, atype, obase, const_init);
+
+  if (try_const)
+    {
+      if (!saw_non_const)
+	{
+	  tree const_init = build_constructor (atype, const_vec);
+	  return build2 (INIT_EXPR, atype, obase, const_init);
+	}
+      else if (do_static_init && !vec_safe_is_empty (const_vec))
+	DECL_INITIAL (obase) = build_constructor (atype, const_vec);
+      else
+	vec_free (const_vec);
+    }
 
   /* Now make the result have the correct type.  */
   if (TREE_CODE (atype) == ARRAY_TYPE)
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 859550b..536ea5c 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -9976,6 +9976,11 @@  maybe_constant_value (tree t)
 tree
 maybe_constant_init (tree t)
 {
+  if (TREE_CODE (t) == EXPR_STMT)
+    t = TREE_OPERAND (t, 0);
+  if (TREE_CODE (t) == CONVERT_EXPR
+      && VOID_TYPE_P (TREE_TYPE (t)))
+    t = TREE_OPERAND (t, 0);
   t = maybe_constant_value (t);
   if (TREE_CODE (t) == TARGET_EXPR)
     {
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array8.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array8.C
new file mode 100644
index 0000000..f4aae4f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array8.C
@@ -0,0 +1,22 @@ 
+// { dg-do run { target c++11 } }
+
+struct A { int i,j; };
+
+struct X {
+  A a = {1,1};
+};
+
+constexpr X table[2][2] = {{ {} }};
+
+#define SA(X) static_assert(X,#X)
+SA(table[1][1].a.i == 1);
+
+extern "C" void abort();
+
+const int *p = &table[1][1].a.j;
+
+int main()
+{
+  if (*p != 1)
+    abort();
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array9.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array9.C
new file mode 100644
index 0000000..20ec255
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array9.C
@@ -0,0 +1,22 @@ 
+// { dg-do run { target c++11 } }
+
+struct A { int i,j; };
+
+struct X {
+  A a = {0,0};
+};
+
+constexpr X table[2][2] = {{ {} }};
+
+#define SA(X) static_assert(X,#X)
+SA(table[1][1].a.i == 0);
+
+extern "C" void abort();
+
+const int *p = &table[1][1].a.j;
+
+int main()
+{
+  if (*p != 0)
+    abort();
+}