c++: Fix usage of CONSTRUCTOR_PLACEHOLDER_BOUNDARY inside array initializers [PR90996]
authorPatrick Palka <ppalka@redhat.com>
Mon, 6 Apr 2020 18:05:44 +0000 (14:05 -0400)
committerPatrick Palka <ppalka@redhat.com>
Tue, 7 Apr 2020 13:04:30 +0000 (09:04 -0400)
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={*(&<PLACEHOLDER_EXPR struct S>)->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
gcc/cp/tree.c
gcc/cp/typeck2.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp1y/pr90996.C [new file with mode: 0644]

index 4452796f2fa7e800ebd02e86801d57f70dde043d..67bee23925378baafadc04d2623c11dca3ec9a97 100644 (file)
@@ -1,3 +1,12 @@
+2020-04-07  Patrick Palka  <ppalka@redhat.com>
+
+       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  <jakub@redhat.com>
 
        PR c++/94512
index 5eb0dcd717addb77612a893a482860b3d2347495..d1192b7e094b00f02ed1485429043eb48af0d51e 100644 (file)
@@ -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;
index cf1cb5ace665be84c55ffdc8645de16484994824..56fd9bafa7e568d21edb7f6a35cd82066397c321 100644 (file)
@@ -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),
index af475d42de459f2380cfaf361bc2a6027fbf207d..982f0b144d6eec33daa42bef44eb104c7d8d9a21 100644 (file)
@@ -1,3 +1,8 @@
+2020-04-07  Patrick Palka  <ppalka@redhat.com>
+
+       PR c++/90996
+       * g++.dg/cpp1y/pr90996.C: New test.
+
 2020-04-07  Jakub Jelinek  <jakub@redhat.com>
 
        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 (file)
index 0000000..780cbb4
--- /dev/null
@@ -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 {};