]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR c++/78551 (Internal compiler error with constexpr initialization of union)
authorNathan Sidwell <nathan@acm.org>
Thu, 8 Dec 2016 19:27:32 +0000 (19:27 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Thu, 8 Dec 2016 19:27:32 +0000 (19:27 +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: r243457

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

index 86ba3309874382b6c337b7ad7d2baa9543ce3ccd..0fbbe2118bae13439d68224ad85b59b07b52c4ff 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-08-05  Nathan Sidwell  <nathan@acm.org>
 
        PR c++/68724
index 50e2338a13fbc10c683e2a44e95b2b73bfa92c99..e558e69066ae1cbcc4f5dad77599280747805036 100644 (file)
@@ -1829,6 +1829,27 @@ find_array_ctor_elt (tree ary, tree dindex, bool insert = false)
 }
 
 
+/* 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.  */
 
@@ -1913,16 +1934,8 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
 
   if (TREE_CODE (ary) == CONSTRUCTOR)
     return (*CONSTRUCTOR_ELTS (ary))[i].value;
-  else if (elem_nchars == 1)
-    return 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)));
-      return native_interpret_expr (type, (const unsigned char *)
-                                         TREE_STRING_POINTER (ary)
-                                         + i * elem_nchars, elem_nchars);
-    }
+    return extract_string_elt (ary, elem_nchars, i);
   /* Don't VERIFY_CONSTANT here.  */
 }
 
@@ -2838,6 +2851,34 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
          *valp = build_constructor (type, NULL);
          CONSTRUCTOR_NO_IMPLICIT_ZERO (*valp) = true;
        }
+      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;
+       }
 
       enum tree_code code = TREE_CODE (type);
       type = refs->pop();
index f602468145459e379f4e4e491b6118f57cc64358..c560323c275f46b853ace2a0b5940b59269aae12 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-07  Thomas Preud'homme  <thomas.preudhomme@arm.com>
 
        Backport from mainline
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', "");