From 23f1f679141bbb4720ca195cb758605dc017b7fd Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Mon, 6 Apr 2020 14:05:44 -0400 Subject: [PATCH] c++: Fix usage of CONSTRUCTOR_PLACEHOLDER_BOUNDARY inside array initializers [PR90996] This PR reports that ever since the introduction of the CONSTRUCTOR_PLACEHOLDER_BOUNDARY flag, we are sometimes failing to resolve PLACEHOLDER_EXPRs inside array initializers that refer to some inner constructor. In the testcase in the PR, we have as the initializer for "S c[];" the following {{.a=(int &) &_ZGR1c_, .b={*(&)->a}}} where CONSTRUCTOR_PLACEHOLDER_BOUNDARY is set on the middle constructor. When calling replace_placeholders from store_init_value, we pass the entire initializer to it, and as a result we fail to resolve the PLACEHOLDER_EXPR within due to the CONSTRUCTOR_PLACEHOLDER_BOUNDARY flag on the middle constructor blocking replace_placeholders_r from reaching it. To fix this, we could perhaps either call replace_placeholders in more places, or we could change where we set CONSTRUCTOR_PLACEHOLDER_BOUNDARY. This patch takes this latter approach -- when building up an array initializer, we now bubble any CONSTRUCTOR_PLACEHOLDER_BOUNDARY flag from the element initializers up to the array initializer so that the boundary doesn't later impede us when we call replace_placeholders from store_init_value. Besides fixing the kind of code like in the testcase, this shouldn't cause any other differences in PLACEHOLDER_EXPR resolution because we don't create or use PLACEHOLDER_EXPRs of array type in the frontend, as far as I can tell. gcc/cp/ChangeLog: PR c++/90996 * tree.c (replace_placeholders): Look through all handled components, not just COMPONENT_REFs. * typeck2.c (process_init_constructor_array): Propagate CONSTRUCTOR_PLACEHOLDER_BOUNDARY up from each element initializer to the array initializer. gcc/testsuite/ChangeLog: PR c++/90996 * g++.dg/cpp1y/pr90996.C: New test. --- gcc/cp/ChangeLog | 9 +++++++++ gcc/cp/tree.c | 2 +- gcc/cp/typeck2.c | 18 ++++++++++++++++++ gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/g++.dg/cpp1y/pr90996.C | 17 +++++++++++++++++ 5 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr90996.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 4452796f2fa..67bee239253 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2020-04-07 Patrick Palka + + PR c++/90996 + * tree.c (replace_placeholders): Look through all handled components, + not just COMPONENT_REFs. + * typeck2.c (process_init_constructor_array): Propagate + CONSTRUCTOR_PLACEHOLDER_BOUNDARY up from each element initializer to + the array initializer. + 2020-04-07 Jakub Jelinek PR c++/94512 diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 5eb0dcd717a..d1192b7e094 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -3247,7 +3247,7 @@ replace_placeholders (tree exp, tree obj, bool *seen_p /*= NULL*/) /* If the object isn't a (member of a) class, do nothing. */ tree op0 = obj; - while (TREE_CODE (op0) == COMPONENT_REF) + while (handled_component_p (op0)) op0 = TREE_OPERAND (op0, 0); if (!CLASS_TYPE_P (strip_array_types (TREE_TYPE (op0)))) return exp; diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index cf1cb5ace66..56fd9bafa7e 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1488,6 +1488,17 @@ process_init_constructor_array (tree type, tree init, int nested, int flags, = massage_init_elt (TREE_TYPE (type), ce->value, nested, flags, complain); + if (TREE_CODE (ce->value) == CONSTRUCTOR + && CONSTRUCTOR_PLACEHOLDER_BOUNDARY (ce->value)) + { + /* Shift CONSTRUCTOR_PLACEHOLDER_BOUNDARY from the element initializer + up to the array initializer, so that the call to + replace_placeholders from store_init_value can resolve any + PLACEHOLDER_EXPRs inside this element initializer. */ + CONSTRUCTOR_PLACEHOLDER_BOUNDARY (ce->value) = 0; + CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1; + } + gcc_checking_assert (ce->value == error_mark_node || (same_type_ignoring_top_level_qualifiers_p @@ -1516,6 +1527,13 @@ process_init_constructor_array (tree type, tree init, int nested, int flags, /* The default zero-initialization is fine for us; don't add anything to the CONSTRUCTOR. */ next = NULL_TREE; + else if (TREE_CODE (next) == CONSTRUCTOR + && CONSTRUCTOR_PLACEHOLDER_BOUNDARY (next)) + { + /* As above. */ + CONSTRUCTOR_PLACEHOLDER_BOUNDARY (next) = 0; + CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1; + } } else if (!zero_init_p (TREE_TYPE (type))) next = build_zero_init (TREE_TYPE (type), diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index af475d42de4..982f0b144d6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2020-04-07 Patrick Palka + + PR c++/90996 + * g++.dg/cpp1y/pr90996.C: New test. + 2020-04-07 Jakub Jelinek PR target/94509 diff --git a/gcc/testsuite/g++.dg/cpp1y/pr90996.C b/gcc/testsuite/g++.dg/cpp1y/pr90996.C new file mode 100644 index 00000000000..780cbb4e3ac --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr90996.C @@ -0,0 +1,17 @@ +// PR c++/90996 +// { dg-do compile { target c++14 } } + +struct S +{ + int &&a = 2; + int b[1] {a}; +}; + +S c[2][2] {{{5}}}; + +struct T +{ + S c[2][2] {{{7}}}; +}; + +T d {}; -- 2.30.2