2016-12-07 Nathan Sidwell <nathan@acm.org>
PR c++/78551
* constexpr.c (extract_string_elt): New. Broken out of ...
(cxx_eval_array_reference): ... here. Call it.
(cxx_eval_store_expression): Convert init by STRING_CST into
CONSTRUCTOR, if needed.
PR c++/78551
* g++.dg/cpp1y/pr78551.C: New.
===================================================================
@@ -2149,6 +2149,27 @@ diag_array_subscript (const constexpr_ct
}
}
+/* Extract element INDEX consisting of CHARS_PER_ELT chars from
+ STRING_CST STRING. */
+
+static tree
+extract_string_elt (tree string, unsigned chars_per_elt, unsigned index)
+{
+ tree type = cv_unqualified (TREE_TYPE (TREE_TYPE (string)));
+ tree r;
+
+ if (chars_per_elt == 1)
+ r = build_int_cst (type, TREE_STRING_POINTER (string)[index]);
+ else
+ {
+ const unsigned char *ptr
+ = ((const unsigned char *)TREE_STRING_POINTER (string)
+ + index * chars_per_elt);
+ r = native_interpret_expr (type, ptr, chars_per_elt);
+ }
+ return r;
+}
+
/* Subroutine of cxx_eval_constant_expression.
Attempt to reduce a reference to an array slot. */
@@ -2244,16 +2265,9 @@ cxx_eval_array_reference (const constexp
r = (*CONSTRUCTOR_ELTS (ary))[i].value;
else if (TREE_CODE (ary) == VECTOR_CST)
r = VECTOR_CST_ELT (ary, i);
- else if (elem_nchars == 1)
- r = build_int_cst (cv_unqualified (TREE_TYPE (TREE_TYPE (ary))),
- TREE_STRING_POINTER (ary)[i]);
else
- {
- tree type = cv_unqualified (TREE_TYPE (TREE_TYPE (ary)));
- r = native_interpret_expr (type, (const unsigned char *)
- TREE_STRING_POINTER (ary)
- + i * elem_nchars, elem_nchars);
- }
+ r = extract_string_elt (ary, elem_nchars, i);
+
if (r)
/* Don't VERIFY_CONSTANT here. */
return r;
@@ -3326,6 +3340,35 @@ cxx_eval_store_expression (const constex
*valp = build_constructor (type, NULL);
CONSTRUCTOR_NO_IMPLICIT_ZERO (*valp) = no_zero_init;
}
+ else if (TREE_CODE (*valp) == STRING_CST)
+ {
+ /* An array was initialized with a string constant, and now
+ we're writing into one of its elements. Explode the
+ single initialization into a set of element
+ initializations. */
+ gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
+
+ tree string = *valp;
+ tree elt_type = TREE_TYPE (type);
+ unsigned chars_per_elt = (TYPE_PRECISION (elt_type)
+ / TYPE_PRECISION (char_type_node));
+ unsigned num_elts = TREE_STRING_LENGTH (string) / chars_per_elt;
+ tree ary_ctor = build_constructor (type, NULL);
+
+ vec_safe_reserve (CONSTRUCTOR_ELTS (ary_ctor), num_elts);
+ for (unsigned ix = 0; ix != num_elts; ix++)
+ {
+ constructor_elt elt =
+ {
+ build_int_cst (size_type_node, ix),
+ extract_string_elt (string, chars_per_elt, ix)
+ };
+ CONSTRUCTOR_ELTS (ary_ctor)->quick_push (elt);
+ }
+
+ *valp = ary_ctor;
+ }
+
/* 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);
===================================================================
@@ -0,0 +1,32 @@
+// { dg-do compile { target c++14 } }
+
+// PR c++/78551 ICE in constexpr evaluation overwriting array
+// intialized by string constant.
+
+constexpr char Foo (char x, int ix)
+{
+ char d[4] = "012";
+ d[0] = x;
+ return d[ix];
+}
+
+static const char a = Foo ('a', 1);
+static const char b = Foo ('a', 0);
+
+static_assert (a == '1', "");
+static_assert (b == 'a', "");
+
+struct A {
+ union {
+ long s;
+ char d[4];
+ };
+ constexpr A (char x)
+ : d("012")
+ { d[0] = x; }
+};
+
+static constexpr A c{'a'};
+
+static_assert (c.d[0] == 'a', "");
+static_assert (c.d[1] == '1', "");