From d6b46fca8d1b3d1621dafc7ceaaa0d3d148a4f5d Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Thu, 8 Dec 2016 18:34:04 +0000 Subject: [PATCH] re PR c++/78551 (Internal compiler error with constexpr initialization of union) 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 | 8 ++++ gcc/cp/constexpr.c | 61 ++++++++++++++++++++++++---- gcc/testsuite/ChangeLog | 5 +++ gcc/testsuite/g++.dg/cpp1y/pr78551.C | 32 +++++++++++++++ 4 files changed, 97 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr78551.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index e3251645051..4b203b2a794 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2016-12-08 Nathan Sidwell + + 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 P0003R5 - removal of dynamic exception specification from C++17 diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index f93dd4713c0..aedd0042102 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -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); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7e6b6d021b9..6342b9d91de 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2016-12-08 Nathan Sidwell + + PR c++/78551 + * g++.dg/cpp1y/pr78551.C: New. + 2016-12-08 Pierre-Marie de Rodat 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 index 00000000000..a549fff4fef --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr78551.C @@ -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', ""); -- 2.30.2