re PR c++/78551 (Internal compiler error with constexpr initialization of union)
authorNathan Sidwell <nathan@acm.org>
Thu, 8 Dec 2016 18:34:04 +0000 (18:34 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Thu, 8 Dec 2016 18:34:04 +0000 (18:34 +0000)
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.

From-SVN: r243448

gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp1y/pr78551.C [new file with mode: 0644]

index e32516450511db13bc9fa2aec06304b9347f2ead..4b203b2a79408df4703434b6bc707f5fb3bd96d4 100644 (file)
@@ -1,3 +1,11 @@
+2016-12-08  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.
+
 2016-12-08  Jakub Jelinek  <jakub@redhat.com>
 
        P0003R5 - removal of dynamic exception specification from C++17
index f93dd4713c0c3903834183c226f40197312f8385..aedd004210238d590f6fe8901810286116e127a6 100644 (file)
@@ -2149,6 +2149,27 @@ diag_array_subscript (const constexpr_ctx *ctx, tree array, tree index)
     }
 }
 
+/* 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 constexpr_ctx *ctx, tree t,
        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 constexpr_ctx *ctx, tree t,
          *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);
index 7e6b6d021b97ec272809da60f25d36972caa9d3f..6342b9d91de2fe52a0ce9cae7cedd53f2d8640f6 100644 (file)
@@ -1,3 +1,8 @@
+2016-12-08  Nathan Sidwell  <nathan@acm.org>
+
+       PR c++/78551
+       * g++.dg/cpp1y/pr78551.C: New.
+
 2016-12-08  Pierre-Marie de Rodat  <derodat@adacore.com>
 
        PR debug/78112
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr78551.C b/gcc/testsuite/g++.dg/cpp1y/pr78551.C
new file mode 100644 (file)
index 0000000..a549fff
--- /dev/null
@@ -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', "");