On Thu, Mar 23, 2017 at 05:09:58PM -0400, Jason Merrill wrote:
> On Thu, Mar 23, 2017 at 4:34 PM, Marek Polacek <pola...@redhat.com> wrote:
> > On Tue, Mar 14, 2017 at 02:34:30PM -0400, Jason Merrill wrote:
> >> On Tue, Mar 14, 2017 at 2:33 PM, Jason Merrill <ja...@redhat.com> wrote:
> >> > On Tue, Mar 7, 2017 at 12:10 PM, Marek Polacek <pola...@redhat.com> 
> >> > wrote:
> >> >> In this testcase we have
> >> >> C c = bar (X{1});
> >> >> which store_init_value sees as
> >> >> c = TARGET_EXPR <D.2332, bar (TARGET_EXPR <D.2298, {.i=1, 
> >> >> .n=(&<PLACEHOLDER_EXPR struct X>)->i}>)>
> >> >> i.e. we're initializing "c" with a TARGET_EXPR.  We call 
> >> >> replace_placeholders
> >> >> that walks the whole tree to substitute the placeholders.  Eventually 
> >> >> we find
> >> >> the nested <PLACEHOLDER_EXPR struct X> but that's for another object, 
> >> >> so we
> >> >> crash.  Seems that we shouldn't have stepped into the second 
> >> >> TARGET_EXPR at
> >> >> all; it has nothing to with "c", it's bar's argument.
> >> >>
> >> >> It occurred to me that we shouldn't step into CALL_EXPRs and leave the
> >> >> placeholders in function arguments to cp_gimplify_init_expr which calls
> >> >> replace_placeholders for constructors.  Not sure if it's enough to 
> >> >> handle
> >> >> CALL_EXPRs like this, anything else?
> >> >
> >> > Hmm, we might have a DMI containing a call with an argument referring
> >> > to *this, i.e.
> >> >
> >> > struct A
> >> > {
> >> >   int i;
> >> >   int j = frob (this->i);
> >> > };
> >> >
> >> > The TARGET_EXPR seems like a more likely barrier, but even there we
> >> > could have something like
> >> >
> >> > struct A { int i; };
> >> > struct B
> >> > {
> >> >   int i;
> >> >   A a = A{this->i};
> >> > };
> >> >
> >> > I think we need replace_placeholders to keep a stack of objects, so
> >> > that when we see a TARGET_EXPR we add it to the stack and therefore
> >> > can properly replace a PLACEHOLDER_EXPR of its type.
> >>
> >> Or actually, avoid replacing such a PLACEHOLDER_EXPR, but rather leave
> >> it for later when we lower the TARGET_EXPR.
> >
> > Sorry, I don't really follow.  I have a patch that puts TARGET_EXPRs on
> > a stack, but I don't know how that helps.  E.g. with nsdmi-aggr3.C
> > we have
> > B b = TARGET_EXPR <D1, {.a = TARGET_EXPR <D2, (struct A *) 
> > &<PLACEHOLDER_EXPR struct B>>}>
> > so when we get to that PLACEHOLDER_EXPR, on the stack there's
> > TARGET_EXPR with type struct A
> > TARGET_EXPR with type struct B
> > so the type of the PLACEHOLDER_EXPR doesn't match the type of the current
> > TARGET_EXPR, but we still want to replace it in this case.
> >
> > So -- could you expand a bit on what you had in mind, please?
> 
> So then when we see a placeholder, we walk the stack to find the
> object of the matching type.
> 
> But if the object we find was collected from walking through a
> TARGET_EXPR, we should leave the PLACEHOLDER_EXPR alone, so that it
> can be replaced later with the actual target of the initialization.

Unfortunately, I still don't understand; guess I'll have to drop this PR.

With this we put TARGET_EXPRs on a stack, and then when we find a
PLACEHOLDER_EXPR we walk the stack to find a TARGET_EXPR of the same type as
the PLACEHOLDER_EXPR.  There are three simplified examples I've been playing
with:

  B b = T_E <D1, {.a = T_E <D2, ... &<P_E struct B>>}>

  - here we should replace the P_E; on the stack there are two
    TARGET_EXPRs of types B and A

  C c = T_E <D1, bar (T_E <D2, &<P_E struct X>>)>

  - here we shouldn't replace the P_E; on the stack there are two
    TARGET_EXPRs of types X and C

  B b = T_E <D1, {.a = {.b = &<P_E struct B>}}>

  - here we should replace the P_E; on the stack there's one TARGET_EXPR
    of type B

In each case we find a TARGET_EXPR of the type of the PLACEHOLDER_EXPR, but I
don't see how to decide which PLACEHOLDER_EXPR we should let slide.  Sorry for
being dense...

diff --git gcc/cp/tree.c gcc/cp/tree.c
index 2757af6..2439a00 100644
--- gcc/cp/tree.c
+++ gcc/cp/tree.c
@@ -2741,8 +2741,12 @@ build_ctor_subob_ref (tree index, tree type, tree obj)
 
 struct replace_placeholders_t
 {
-  tree obj;        /* The object to be substituted for a PLACEHOLDER_EXPR.  */
-  bool seen;       /* Whether we've encountered a PLACEHOLDER_EXPR.  */
+  /* The object to be substituted for a PLACEHOLDER_EXPR.  */
+  tree obj;
+  /* Whether we've encountered a PLACEHOLDER_EXPR.  */
+  bool seen;
+  /* A stack of TARGET_EXPRs we've found ourselves in.  */
+  vec<tree> target_expr_stack;
 };
 
 /* Like substitute_placeholder_in_expr, but handle C++ tree codes and
@@ -2762,14 +2766,35 @@ replace_placeholders_r (tree* t, int* walk_subtrees, 
void* data_)
 
   switch (TREE_CODE (*t))
     {
+    case TARGET_EXPR:
+      d->target_expr_stack.safe_push (*t);
+      cp_walk_tree (&TARGET_EXPR_INITIAL (*t), replace_placeholders_r, data_,
+                   NULL);
+      d->target_expr_stack.pop ();
+      *walk_subtrees = 0;
+      break;
+
     case PLACEHOLDER_EXPR:
       {
-       tree x = obj;
-       for (; !(same_type_ignoring_top_level_qualifiers_p
-                (TREE_TYPE (*t), TREE_TYPE (x)));
-            x = TREE_OPERAND (x, 0))
-         gcc_assert (TREE_CODE (x) == COMPONENT_REF);
-       *t = x;
+       bool skip_it = false;
+       unsigned ix;
+       tree targ;
+       /* Walk the stack to find the object of the matching type.  */
+       FOR_EACH_VEC_ELT_REVERSE (d->target_expr_stack, ix, targ)
+         if (same_type_ignoring_top_level_qualifiers_p
+             (TREE_TYPE (*t), TREE_TYPE (targ)))
+           {
+             // ...
+           }
+       if (!skip_it)
+         {
+           tree x = obj;
+           for (; !(same_type_ignoring_top_level_qualifiers_p
+                    (TREE_TYPE (*t), TREE_TYPE (x)));
+                x = TREE_OPERAND (x, 0))
+             gcc_assert (TREE_CODE (x) == COMPONENT_REF);
+           *t = x;
+         }
        *walk_subtrees = false;
        d->seen = true;
       }
@@ -2813,14 +2838,23 @@ replace_placeholders_r (tree* t, int* walk_subtrees, 
void* data_)
   return NULL_TREE;
 }
 
+/* Replace PLACEHOLDER_EXPRs in EXP with object OBJ.  */
+
 tree
 replace_placeholders (tree exp, tree obj, bool *seen_p)
 {
   tree *tp = &exp;
-  replace_placeholders_t data = { obj, false };
+  replace_placeholders_t data;
+  data.obj = obj;
+  data.seen = false;
+  data.target_expr_stack.create (0);
   if (TREE_CODE (exp) == TARGET_EXPR)
-    tp = &TARGET_EXPR_INITIAL (exp);
+    {
+      tp = &TARGET_EXPR_INITIAL (exp);
+      data.target_expr_stack.safe_push (exp);
+    }
   cp_walk_tree (tp, replace_placeholders_r, &data, NULL);
+  data.target_expr_stack.release ();
   if (seen_p)
     *seen_p = data.seen;
   return exp;

        Marek

Reply via email to