diff mbox

C++ PATCH for c++/67104 (wrong handling of array and constexpr)

Message ID 55D22A06.10507@redhat.com
State New
Headers show

Commit Message

Jason Merrill Aug. 17, 2015, 6:37 p.m. UTC
On 08/12/2015 01:32 PM, Jason Merrill wrote:
> cxx_eval_array_reference was assuming that the CONSTRUCTOR for an array
> has one entry per array element, in order.  But
> cxx_eval_store_expression doesn't try to create such a CONSTRUCTOR, and
> other places use RANGE_EXPRs, so we need to be prepared to handle these
> cases.

Thinking more about this, I noticed that fold uses binary search for 
ARRAY_REF and we could do the same here.  But for that to work we need 
cxx_eval_store_expression to keep the CONSTRUCTOR sorted.  The first 
patch implements this.

The second patch fixes the error for referring to an uninitialized 
element of an array in the initializer for another element.

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

Patch

commit 6a4d118d9ae128791a4f043cc1e079c82bad6fb8
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Aug 12 17:54:04 2015 +0100

    	* constexpr.c (cxx_eval_store_expression): Don't set
    	CONSTRUCTOR_NO_IMPLICIT_ZERO if we have an enclosing CONSTRUCTOR
    	without it.
    	(cxx_eval_array_reference): Check it.

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 81afb47..2aef631 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1741,6 +1741,18 @@  cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
     {
       if (tree_int_cst_lt (index, array_type_nelts_top (TREE_TYPE (ary))))
 	{
+	  if (TREE_CODE (ary) == CONSTRUCTOR
+	      && CONSTRUCTOR_NO_IMPLICIT_ZERO (ary))
+	    {
+	      /* 'ary' is part of the aggregate initializer we're currently
+		 building; if there's no initializer for this element yet,
+		 that's an error. */
+	      if (!ctx->quiet)
+		error ("accessing uninitialized array element");
+	      *non_constant_p = true;
+	      return t;
+	    }
+
 	  /* If it's within the array bounds but doesn't have an explicit
 	     initializer, it's value-initialized.  */
 	  tree val = build_value_init (elem_type, tf_warning_or_error);
@@ -2683,13 +2695,17 @@  cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
       return t;
     }
   type = TREE_TYPE (object);
+  bool no_zero_init = true;
   while (!refs->is_empty())
     {
       if (*valp == NULL_TREE)
 	{
 	  *valp = build_constructor (type, NULL);
-	  CONSTRUCTOR_NO_IMPLICIT_ZERO (*valp) = true;
+	  CONSTRUCTOR_NO_IMPLICIT_ZERO (*valp) = no_zero_init;
 	}
+      /* If the value of object is already zero-initialized, any new ctors for
+	 subobjects will also be zero-initialized.  */
+      no_zero_init = CONSTRUCTOR_NO_IMPLICIT_ZERO (*valp);
 
       constructor_elt ce;
       type = refs->pop();
@@ -2717,7 +2733,7 @@  cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
       new_ctx.ctor = build_constructor (type, NULL);
       if (*valp == NULL_TREE)
 	*valp = new_ctx.ctor;
-      CONSTRUCTOR_NO_IMPLICIT_ZERO (new_ctx.ctor) = true;
+      CONSTRUCTOR_NO_IMPLICIT_ZERO (new_ctx.ctor) = no_zero_init;
       new_ctx.object = target;
     }
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array12.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array12.C
new file mode 100644
index 0000000..347ee54
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array12.C
@@ -0,0 +1,8 @@ 
+// { dg-do compile { target c++11 } }
+
+struct A { int ar[3]; };
+int main()
+{
+  constexpr A a1 = { 0, a1.ar[0] };
+  constexpr A a2 = { a2.ar[0] };	// { dg-error "uninitialized" }
+}